From 2195ad5ae8d795d99bd45bc2eba7edb5f25cd1d8 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Sat, 15 Dec 2018 21:35:18 +0100 Subject: [PATCH 001/304] Added boss bars to siege and assault --- .../movecraft/commands/AssaultCommand.java | 8 +++ .../movecraft/commands/SiegeCommand.java | 5 ++ .../movecraft/listener/BlockListener.java | 1 + .../listener/WorldEditInteractListener.java | 1 + .../movecraft/sign/RepairSign.java | 1 + .../movecraft/utils/ChatUtils.java | 8 +++ .../movecraft/warfare/assault/Assault.java | 17 ++++++ .../warfare/assault/AssaultBarTask.java | 49 +++++++++++++++++ .../warfare/assault/AssaultTask.java | 55 +++++++++++++++++-- .../warfare/assault/AssaultUtils.java | 4 +- .../movecraft/warfare/siege/Siege.java | 11 ++++ .../movecraft/warfare/siege/SiegeManager.java | 1 + .../warfare/siege/SiegePreparationTask.java | 18 +++++- .../warfare/siege/SiegeProgressTask.java | 26 +++++++-- modules/api/pom.xml | 12 ++++ .../movecraft/craft/CraftType.java | 33 +++++++++++ 16 files changed, 235 insertions(+), 15 deletions(-) create mode 100644 modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/assault/AssaultBarTask.java diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/AssaultCommand.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/AssaultCommand.java index 51b96499e..dbc4012a3 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/AssaultCommand.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/AssaultCommand.java @@ -12,10 +12,15 @@ import net.countercraft.movecraft.config.Settings; import net.countercraft.movecraft.localisation.I18nSupport; import net.countercraft.movecraft.warfare.assault.Assault; +import net.countercraft.movecraft.warfare.assault.AssaultBarTask; import net.countercraft.movecraft.warfare.assault.AssaultUtils; import net.countercraft.movecraft.warfare.siege.Siege; import org.bukkit.*; import org.bukkit.block.Block; +import org.bukkit.boss.BarColor; +import org.bukkit.boss.BarFlag; +import org.bukkit.boss.BarStyle; +import org.bukkit.boss.BossBar; import org.bukkit.command.Command; import org.bukkit.command.CommandExecutor; import org.bukkit.command.CommandSender; @@ -181,6 +186,7 @@ public boolean onCommand(CommandSender commandSender, Command command, String s, for (Player p : Bukkit.getOnlinePlayers()) { p.playSound(p.getLocation(), Sound.ENTITY_WITHER_DEATH, 1, (float) 0.25); } + new AssaultBarTask(Movecraft.getInstance() ,args[0] ,System.currentTimeMillis()).runTaskTimer(Movecraft.getInstance(), 0, 20); final String taskAssaultName = args[0]; final Player taskPlayer = player; final World taskWorld = player.getWorld(); @@ -191,6 +197,7 @@ public boolean onCommand(CommandSender commandSender, Command command, String s, new BukkitRunnable() { @Override public void run() { + //progressBar.setVisible(false); Bukkit.getServer().broadcastMessage(String.format("The Assault of %s has commenced! The assault leader is %s. Destroy the enemy region!" , taskAssaultName, taskPlayer.getDisplayName())); for (Player p : Bukkit.getOnlinePlayers()) { @@ -201,6 +208,7 @@ public void run() { tRegion.setFlag(DefaultFlag.TNT, StateFlag.State.ALLOW); } }.runTaskLater(Movecraft.getInstance(), (20 * Settings.AssaultDelay)); + return true; diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/SiegeCommand.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/SiegeCommand.java index 78c000628..509ec0bed 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/SiegeCommand.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/SiegeCommand.java @@ -14,6 +14,9 @@ import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.Sound; +import org.bukkit.boss.BarColor; +import org.bukkit.boss.BarFlag; +import org.bukkit.boss.BarStyle; import org.bukkit.command.Command; import org.bukkit.command.CommandExecutor; import org.bukkit.command.CommandSender; @@ -176,6 +179,8 @@ private boolean beginCommand(CommandSender commandSender){ } Movecraft.getInstance().getLogger().log(Level.INFO, String.format("Siege: %s commenced by %s for a cost of %d", siege.getName(), player.getName(), cost)); Movecraft.getInstance().getEconomy().withdrawPlayer(player, cost); + siege.setProgressBar(Bukkit.createBossBar(siege.getName(), BarColor.BLUE, BarStyle.SOLID, BarFlag.DARKEN_SKY)); + siege.getProgressBar().setVisible(true); siege.setPlayerUUID(player.getUniqueId()); siege.setStartTime((int)System.currentTimeMillis()); siege.setStage(SiegeStage.PREPERATION); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/BlockListener.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/BlockListener.java index 1dca1c4a0..7e21d9948 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/BlockListener.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/BlockListener.java @@ -406,6 +406,7 @@ public void run() { if (Math.round(p.getLocation().getBlockX() / 1000.0) == Math.round(floc.getBlockX() / 1000.0) && Math.round(p.getLocation().getBlockZ() / 1000.0) == Math.round(floc.getBlockZ() / 1000.0)) { p.sendMessage("Damages: " + fdamages); + } } } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/WorldEditInteractListener.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/WorldEditInteractListener.java index 5706abf24..cc6114eba 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/WorldEditInteractListener.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/WorldEditInteractListener.java @@ -250,6 +250,7 @@ public void WEOnPlayerInteract(PlayerInteractEvent event) { baseBlock = new BaseBlock(bukkitBlock.getTypeId(), bukkitBlock.getData()); } try{ + //TODO: Bug fix cuboidClipboard.setBlock(offsetLocation, baseBlock); }catch (Exception e){ Movecraft.getInstance().getLogger().warning("Factory save failed, this is typically caused by FAWE"); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RepairSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RepairSign.java index a3e5db7e1..3ab7d3435 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RepairSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RepairSign.java @@ -3,4 +3,5 @@ import org.bukkit.event.Listener; public class RepairSign implements Listener{ + } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/ChatUtils.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/ChatUtils.java index 3a666fefc..0c6672055 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/ChatUtils.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/ChatUtils.java @@ -4,4 +4,12 @@ public class ChatUtils { public static final String MOVECRAFT_COMMAND_PREFIX = ChatColor.GOLD + "[" + ChatColor.WHITE + "Movecraft" + ChatColor.GOLD + "] " + ChatColor.RESET; + + public static String timeFromMilliSeconds(long timeInMillisec){ + long hour = (timeInMillisec / 1000) / 3600; + long minute = (timeInMillisec / 1000) / 60 - hour * 60; + long second = (timeInMillisec / 1000) - minute * 60; + String time = String.format("%d:%d:%d", hour, minute, second); + return time; + } } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/assault/Assault.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/assault/Assault.java index d2896bf27..d15f581d8 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/assault/Assault.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/assault/Assault.java @@ -1,7 +1,12 @@ package net.countercraft.movecraft.warfare.assault; import com.sk89q.worldedit.Vector; +import org.bukkit.Bukkit; import org.bukkit.World; +import org.bukkit.boss.BarColor; +import org.bukkit.boss.BarFlag; +import org.bukkit.boss.BarStyle; +import org.bukkit.boss.BossBar; import org.bukkit.entity.Player; import java.util.UUID; @@ -19,6 +24,8 @@ public class Assault { private final World world; private final Vector minPos, maxPos; private AtomicBoolean running = new AtomicBoolean(true); + private BossBar progressBar; + private BossBar damageBar; public Assault(String regionName, Player starter, World world, long startTime, long maxDamages, Vector minPos, Vector maxPos) { this.regionName = regionName; @@ -28,6 +35,8 @@ public Assault(String regionName, Player starter, World world, long startTime, l this.maxDamages = maxDamages; this.minPos = minPos; this.maxPos = maxPos; + progressBar = Bukkit.createBossBar(this.getRegionName() + " passed time", BarColor.RED, BarStyle.SOLID, BarFlag.DARKEN_SKY); + damageBar = Bukkit.createBossBar(this.getRegionName() + " damages", BarColor.WHITE, BarStyle.SOLID, BarFlag.DARKEN_SKY); } public Vector getMaxPos() { @@ -70,4 +79,12 @@ public String getRegionName() { public AtomicBoolean getRunning() { return running; } + + public BossBar getDamageBar() { + return damageBar; + } + + public BossBar getProgressBar() { + return progressBar; + } } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/assault/AssaultBarTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/assault/AssaultBarTask.java new file mode 100644 index 000000000..1485661ce --- /dev/null +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/assault/AssaultBarTask.java @@ -0,0 +1,49 @@ +package net.countercraft.movecraft.warfare.assault; + +import net.countercraft.movecraft.config.Settings; +import org.bukkit.Bukkit; +import org.bukkit.boss.BarColor; +import org.bukkit.boss.BarFlag; +import org.bukkit.boss.BarStyle; +import org.bukkit.boss.BossBar; +import org.bukkit.entity.Player; +import org.bukkit.plugin.Plugin; +import org.bukkit.scheduler.BukkitRunnable; + + +public class AssaultBarTask extends BukkitRunnable { + private static boolean assaultInPreparation = false; + private static long startTime; + private static Plugin movecraft; + private static BossBar prepBar; + private static String assaultName; + public AssaultBarTask(Plugin movecraft,String assaultName, long startTime){ + this.assaultInPreparation = true; + this.startTime = startTime; + this.movecraft = movecraft; + this.assaultName = assaultName; + this.prepBar = Bukkit.createBossBar(assaultName, BarColor.BLUE, BarStyle.SOLID, BarFlag.DARKEN_SKY); + this.prepBar.setProgress(0.0); + } + + @Override + public void run() { + long timePassed = (System.currentTimeMillis() - startTime) / 1000; + assaultInPreparation = timePassed <= Settings.AssaultDelay; + double progress = (double) timePassed / (double) Settings.AssaultDelay; + for (Player p : Bukkit.getOnlinePlayers()){ + prepBar.addPlayer(p); + } + //Bukkit.broadcastMessage(String.valueOf(startTime) + ", " + String.valueOf(System.currentTimeMillis()) + ", " + String.valueOf(progress) + ", " + String.valueOf(timePassed)); + if (assaultInPreparation){ + prepBar.setVisible(true); + if (progress >= 0.0 && progress <= 1.0){ + prepBar.setProgress(progress); + + } + } else { + prepBar.setVisible(false); + this.cancel(); + } + } +} diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/assault/AssaultTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/assault/AssaultTask.java index 63d79d470..9f209e91f 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/assault/AssaultTask.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/assault/AssaultTask.java @@ -6,14 +6,16 @@ import net.countercraft.movecraft.Movecraft; import net.countercraft.movecraft.config.Settings; import net.countercraft.movecraft.listener.WorldEditInteractListener; -import org.bukkit.Bukkit; -import org.bukkit.ChatColor; -import org.bukkit.Material; -import org.bukkit.OfflinePlayer; -import org.bukkit.World; +import net.countercraft.movecraft.utils.ChatUtils; +import org.bukkit.*; +import org.bukkit.block.Block; import org.bukkit.block.Sign; +import org.bukkit.boss.BarColor; +import org.bukkit.entity.Player; import org.bukkit.scheduler.BukkitRunnable; +import org.bukkit.util.Vector; +import java.text.DecimalFormat; import java.util.UUID; public class AssaultTask extends BukkitRunnable { @@ -29,7 +31,48 @@ public void run() { //in-case the server is lagging and a new assault task is started at the exact time on ends if (!assault.getRunning().get()) return; + + //track assault progress in progress and damage bars + assault.getDamageBar().setVisible(true); + assault.getProgressBar().setVisible(true); + double dmgProgress = (double) assault.getDamages() / (double) assault.getMaxDamages(); + double timeProgress = (double) ((System.currentTimeMillis() - assault.getStartTime()) / 1000)/ (double) Settings.AssaultDuration; + //Bukkit.broadcastMessage(String.format("Damage: %d, Max damage: %d, Start time: %d, passed time: %d", assault.getDamages(), assault.getMaxDamages(), assault.getStartTime(), System.currentTimeMillis())); + Location aLoc = assault.getWorld().getBlockAt(assault.getMinPos().getBlockX() + assault.getMaxPos().getBlockX() / 2, assault.getMinPos().getBlockY() + assault.getMaxPos().getBlockY() / 2, assault.getMinPos().getBlockZ() + assault.getMaxPos().getBlockZ() / 2).getLocation(); + for (Player p : Bukkit.getOnlinePlayers()){ + assault.getProgressBar().addPlayer(p); + if (p.getLocation().getX() - aLoc.getX() <= 1500.0 && p.getLocation().getX() - aLoc.getX() >= -1500.0 && + p.getLocation().getZ() - aLoc.getZ() <= 1500.0 && p.getLocation().getZ() - aLoc.getZ() >= -1500.0){ + assault.getDamageBar().addPlayer(p); + } else { + assault.getDamageBar().removePlayer(p); + } + } + + if (assault.getDamages() >= assault.getMaxDamages() / 10 * 9){ //When 9/10 of Max damages is inflicted, set progress bar green + assault.getProgressBar().setColor(BarColor.GREEN); + } else if (assault.getDamages() >= assault.getMaxDamages() / 2){ //When half of the max damages is inflicted, set progress bar yellow + assault.getProgressBar().setColor(BarColor.YELLOW); + } else { //Otherwise, keep it red + assault.getProgressBar().setColor(BarColor.RED); + } + + if (dmgProgress >= 0.0 && dmgProgress <= 1.0){ + assault.getDamageBar().setProgress(dmgProgress); + } + if (timeProgress >= 0.0 && timeProgress <= 1.0){ + assault.getProgressBar().setProgress(timeProgress); + } + long timeLeft = Settings.AssaultDuration * 1000 - (System.currentTimeMillis() - assault.getStartTime()); + int hours = (int) (timeLeft / 1000) / 3600; + int minutes = (int) (timeLeft / 1000) / 60 - hours * 60; + int seconds = (int) (timeLeft / 1000) - minutes * 60; + DecimalFormat df = new DecimalFormat("00"); + assault.getDamageBar().setTitle(String.format("%s damages: %d", assault.getRegionName(),assault.getDamages())); + assault.getProgressBar().setTitle(assault.getRegionName() + " time left: " + df.format(hours) + ":" + df.format(minutes) + ":" + df.format(seconds)); if (assault.getDamages() >= assault.getMaxDamages()) { + assault.getDamageBar().setVisible(false); + assault.getProgressBar().setVisible(false); // assault was successful assault.getRunning().set(false); World w = assault.getWorld(); @@ -91,6 +134,8 @@ public void run() { } else { // assault was not successful if (System.currentTimeMillis() - assault.getStartTime() > Settings.AssaultDuration * 1000) { + assault.getDamageBar().setVisible(false); + assault.getProgressBar().setVisible(false); // assault has failed to reach damage cap within required time assault.getRunning().set(false); Bukkit.getServer().broadcastMessage(String.format("The assault of %s has failed!", assault.getRegionName())); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/assault/AssaultUtils.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/assault/AssaultUtils.java index 89f860e39..4bcbfc847 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/assault/AssaultUtils.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/assault/AssaultUtils.java @@ -5,6 +5,7 @@ import net.countercraft.movecraft.config.Settings; import org.bukkit.Bukkit; import org.bukkit.OfflinePlayer; +import org.bukkit.boss.BossBar; import java.util.HashSet; import java.util.UUID; @@ -24,6 +25,7 @@ public static boolean areDefendersOnline(ProtectedRegion tRegion) { return numOnline >= Settings.AssaultRequiredDefendersOnline; } + public static double getCostToAssault(ProtectedRegion tRegion) { HashSet players = new HashSet<>(); players.addAll(tRegion.getMembers().getUniqueIds()); @@ -53,6 +55,6 @@ public static double getMaxDamages(ProtectedRegion tRegion) { else total += Movecraft.getInstance().getEconomy().getBalance(offP); } - return total * Settings.AssaultDamagesCapPercent / 100.0; + return total * (Settings.AssaultDamagesCapPercent / 100.0); } } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/siege/Siege.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/siege/Siege.java index 7284997f0..3a1abf950 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/siege/Siege.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/siege/Siege.java @@ -1,5 +1,6 @@ package net.countercraft.movecraft.warfare.siege; +import org.bukkit.boss.BossBar; import org.jetbrains.annotations.NotNull; import java.util.List; @@ -16,6 +17,7 @@ public class Siege { private long lastPayout; private final boolean doubleCostPerOwnedSiegeRegion; private UUID playerUUID; + private BossBar progressBar; public Siege(@NotNull String name, @NotNull String captureRegion, @NotNull String attackRegion, int scheduleStart, int scheduleEnd, int delayBeforeStart, int duration, int dayOfWeek, int dailyIncome, int cost, boolean doubleCostPerOwnedSiegeRegion, @NotNull List craftsToWin, @NotNull List commandsOnStart, @NotNull List commandsOnWin, @NotNull List commandsOnLose) { this.commandsOnWin = commandsOnWin; @@ -37,6 +39,7 @@ public Siege(@NotNull String name, @NotNull String captureRegion, @NotNull Strin lastUpdate = 0; stage = new AtomicReference<>(); stage.set(SiegeStage.INACTIVE); + progressBar = null; } @NotNull @@ -145,4 +148,12 @@ public void setLastUpdate(int lastUpdate) { public boolean isDoubleCostPerOwnedSiegeRegion() { return doubleCostPerOwnedSiegeRegion; } + + public BossBar getProgressBar(){ + return progressBar; + } + + public void setProgressBar(BossBar progressBar){ + this.progressBar = progressBar; + } } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/siege/SiegeManager.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/siege/SiegeManager.java index efbb92a46..74fec8112 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/siege/SiegeManager.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/siege/SiegeManager.java @@ -24,6 +24,7 @@ public void run() { } else if (siege.getStage().get() == SiegeStage.PREPERATION) { new SiegePreparationTask(siege).runTask(movecraft); } + } } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/siege/SiegePreparationTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/siege/SiegePreparationTask.java index 7182f568f..39eb2d9f2 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/siege/SiegePreparationTask.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/siege/SiegePreparationTask.java @@ -4,8 +4,9 @@ import org.bukkit.Sound; import org.bukkit.entity.Player; -public class SiegePreparationTask extends SiegeTask { +import java.util.UUID; +public class SiegePreparationTask extends SiegeTask { public SiegePreparationTask(Siege siege) { super(siege); @@ -18,17 +19,28 @@ public void run() { if (timePassedinSeconds >= siege.getDelayBeforeStart()){ siege.setStage(SiegeStage.IN_PROGRESS); } + double progress = (double) timePassedinSeconds / (double) siege.getDelayBeforeStart(); + if (progress <= 1.0) { + siege.getProgressBar().setProgress(progress); + } + //Bukkit.getServer().broadcastMessage(String.valueOf(progress) + ", " + String.valueOf(timePassedinSeconds) + ", " + String.valueOf(siege.getDuration())); + for (Player p : Bukkit.getOnlinePlayers()){ + siege.getProgressBar().addPlayer(p); + } if ((siege.getDelayBeforeStart() - timePassed/1000) % 60 != 0 || timePassed < 3000){ return; } int timeLeft = siege.getDelayBeforeStart() - (timePassed/1000); - broadcastSiegePreparation(Bukkit.getPlayer(siege.getPlayerUUID()), siege.getName(), (int) timeLeft); + broadcastSiegePreparation(siege.getPlayerUUID(), siege.getName(), (int) timeLeft); } - private void broadcastSiegePreparation(Player player, String siegeName, int timeLeft){ + private void broadcastSiegePreparation(UUID playerUUID, String siegeName, int timeLeft){ String playerName = "An offline siege leader"; + Player player = Bukkit.getPlayer(playerUUID); if (player != null){ playerName = player.getDisplayName(); + } else { + playerName = Bukkit.getOfflinePlayer(playerUUID).getName(); } Bukkit.getServer().broadcastMessage(String.format("%s is preparing to siege %s! All players wishing to participate in the defense should head there immediately! Siege will begin in %d minutes", playerName, siegeName, timeLeft / 60)); for (Player p : Bukkit.getOnlinePlayers()) { diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/siege/SiegeProgressTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/siege/SiegeProgressTask.java index 1ee3c6c9d..bfbf15428 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/siege/SiegeProgressTask.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/siege/SiegeProgressTask.java @@ -8,10 +8,9 @@ import net.countercraft.movecraft.craft.CraftManager; import org.bukkit.Bukkit; import org.bukkit.Sound; +import org.bukkit.boss.BarColor; import org.bukkit.entity.Player; -import java.util.concurrent.atomic.AtomicReference; - public class SiegeProgressTask extends SiegeTask { public SiegeProgressTask(Siege siege) { @@ -20,9 +19,8 @@ public SiegeProgressTask(Siege siege) { //every 180 seconds = 3600 ticks public void run() { - if ((siege.getDuration() - ((System.currentTimeMillis() - siege.getStartTime()) / 1000)) % 60 != 0) { - return; - } + + Player siegeLeader = Movecraft.getInstance().getServer().getPlayer(siege.getPlayerUUID()); Craft siegeCraft = CraftManager.getInstance().getCraftByPlayer(siegeLeader); boolean siegeLeaderShipInRegion = false, siegeLeaderPilotingShip; @@ -45,8 +43,23 @@ public void run() { siegeLeaderShipInRegion = Movecraft.getInstance().getWorldGuardPlugin().getRegionManager(siegeLeader.getWorld()).getRegion(siege.getAttackRegion()).contains(midX, midY, midZ); } - int timeLeft = (siege.getDuration() - (((int)System.currentTimeMillis() - siege.getStartTime())/1000)); + + + double progress = (double) ((((int)System.currentTimeMillis() - siege.getStartTime())/1000) - siege.getDelayBeforeStart()) / (double) (siege.getDuration() - siege.getDelayBeforeStart()); + if (progress <= 1.0 && progress >= 0.0) { //Make sure progress is between 0.0 and 1.0 when it is registered to the progressbar + siege.getProgressBar().setProgress(progress); + } + if (siegeLeaderShipInRegion){ + siege.getProgressBar().setColor(BarColor.GREEN); + } else { + siege.getProgressBar().setColor(BarColor.RED); + } + if ((siege.getDuration() - ((System.currentTimeMillis() - siege.getStartTime()) / 1000)) % 60 != 0) { + return; + } + int timeLeft = (siege.getDuration() - (((int)System.currentTimeMillis() - siege.getStartTime())/1000)); + Bukkit.getPlayer(siege.getPlayerUUID()).sendMessage(String.valueOf(timeLeft)); if (timeLeft > 10) { if (siegeLeaderShipInRegion) { Bukkit.getServer().broadcastMessage(String.format( @@ -89,6 +102,7 @@ public void run() { .replaceAll("%l", siegeLeader.toString())); } } + siege.getProgressBar().setVisible(false); siege.setStage(SiegeStage.INACTIVE); } for (Player p : Bukkit.getOnlinePlayers()){ diff --git a/modules/api/pom.xml b/modules/api/pom.xml index 5e1bb189e..73eeb20e1 100644 --- a/modules/api/pom.xml +++ b/modules/api/pom.xml @@ -7,6 +7,13 @@ http://github.com/apdevteam/Movecraft API + + + sk89q-repo + http://maven.sk89q.com/repo/ + + + UTF-8 5.2.0 @@ -23,6 +30,11 @@ + + com.sk89q + worldedit + LATEST + org.spigotmc spigot diff --git a/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java b/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java index 49f512bc3..b5a696bc5 100644 --- a/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java +++ b/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java @@ -18,7 +18,10 @@ package net.countercraft.movecraft.craft; import net.countercraft.movecraft.MovecraftLocation; +import org.bukkit.Bukkit; import org.bukkit.Material; +import org.bukkit.World; +import org.bukkit.block.Block; import org.jetbrains.annotations.NotNull; import org.yaml.snakeyaml.Yaml; @@ -82,7 +85,9 @@ final public class CraftType { private final float collisionExplosion; @NotNull private final String craftName; @NotNull private final int[] allowedBlocks; + //@NotNull private final Map> allowedBlocks; @NotNull private final int[] forbiddenBlocks; + //@NotNull private final Map> forbiddenBlocks; @NotNull private final String[] forbiddenSignStrings; @NotNull private final Map, List> flyBlocks; @NotNull private final Map, List> moveBlocks; @@ -462,6 +467,34 @@ private int[] blockIDListFromObject(Object obj) { output[i] = returnList.get(i); return output; } + private Map> materialMapFromObject(Object obj){ + HashMap> returnMap = new HashMap<>(); + HashMap objMap = (HashMap) obj; + + for (Object o : objMap.keySet()){ + Block block; + Material type; + if (o instanceof Integer){ + Integer id = (Integer) o; + type = Material.getMaterial(id); + } else if (o instanceof String){ + String str = (String) o; + type = Material.getMaterial(str); + } else { + type = (Material) o; + } + ArrayList objList = (ArrayList) objMap.get(o); + ArrayList dataList = new ArrayList<>(); + for (Object dataObj : objList){ + if (dataObj instanceof Integer){ + Integer data = (Integer) dataObj; + dataList.add(data); + } + } + returnMap.put(type,dataList); + } + return returnMap; + } private String[] stringListFromObject(Object obj) { ArrayList returnList = new ArrayList<>(); From b597044b8049d9840dc95058cd8610810863006d Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Sat, 5 Jan 2019 17:14:19 +0100 Subject: [PATCH 002/304] New repair system, phased out numerical block IDs and 1.13 update --- modules/Movecraft/pom.xml | 26 + .../net/countercraft/movecraft/Movecraft.java | 88 ++- .../movecraft/async/AsyncManager.java | 67 +- .../async/detection/DetectionTask.java | 227 ++++-- .../async/detection/DetectionTaskData.java | 13 +- .../async/rotation/RotationTask.java | 25 +- .../async/translation/TranslationTask.java | 70 +- .../movecraft/commands/AssaultCommand.java | 46 +- .../movecraft/craft/CraftManager.java | 35 +- .../factions/FactionsCompatManager.java | 21 + .../movecraft/listener/BlockListener.java | 127 +-- .../movecraft/listener/InteractListener.java | 24 +- .../movecraft/listener/PlayerListener.java | 33 +- .../listener/WorldEditInteractListener.java | 728 ------------------ .../mapUpdater/update/BlockCreateCommand.java | 48 +- .../mapUpdater/update/CraftRotateCommand.java | 33 +- .../update/CraftTranslateCommand.java | 43 +- .../update/WorldEditUpdateCommand.java | 200 ++++- .../movecraft/repair/RepairUtils.java | 68 ++ .../sign/AntiAircraftDirectorSign.java | 4 +- .../movecraft/sign/AscendSign.java | 6 +- .../movecraft/sign/CannonDirectorSign.java | 4 +- .../movecraft/sign/ContactsSign.java | 4 +- .../movecraft/sign/CraftSign.java | 3 +- .../countercraft/movecraft/sign/CrewSign.java | 16 +- .../movecraft/sign/CruiseSign.java | 5 +- .../movecraft/sign/DescendSign.java | 6 +- .../countercraft/movecraft/sign/HelmSign.java | 4 +- .../countercraft/movecraft/sign/MoveSign.java | 4 +- .../countercraft/movecraft/sign/NameSign.java | 16 +- .../movecraft/sign/RelativeMoveSign.java | 4 +- .../movecraft/sign/ReleaseSign.java | 4 +- .../movecraft/sign/RemoteSign.java | 6 +- .../movecraft/sign/RepairSign.java | 257 +++++++ .../movecraft/sign/SpeedSign.java | 4 +- .../movecraft/sign/StatusSign.java | 52 +- .../movecraft/sign/SubcraftRotateSign.java | 4 +- .../movecraft/sign/TeleportSign.java | 4 +- .../movecraft/warfare/assault/Assault.java | 2 +- .../warfare/assault/AssaultTask.java | 8 +- .../warfare/assault/AssaultUtils.java | 106 ++- .../Movecraft/src/main/resources/plugin.yml | 3 +- .../src/main/resources/types/BigAirship.craft | 354 ++++++--- .../main/resources/types/BigSubAirship.craft | 356 ++++++--- .../main/resources/types/LaunchTorpedo.craft | 6 +- .../src/main/resources/types/Ship.craft | 310 +++++--- .../src/main/resources/types/SubAirship.craft | 350 ++++++--- .../src/main/resources/types/Submarine.craft | 319 +++++--- .../src/main/resources/types/Turret.craft | 282 ++++--- .../src/main/resources/types/airship.craft | 348 ++++++--- .../src/main/resources/types/airskiff.craft | 290 +++++-- .../src/main/resources/types/elevator.craft | 292 ++++--- .../resources/types/legacy/BigAirship.craft | 167 ++++ .../types/legacy/BigSubAirship.craft | 170 ++++ .../types/legacy/LaunchTorpedo.craft | 30 + .../main/resources/types/legacy/Ship.craft | 143 ++++ .../resources/types/legacy/SubAirship.craft | 169 ++++ .../resources/types/legacy/Submarine.craft | 147 ++++ .../main/resources/types/legacy/Turret.craft | 140 ++++ .../main/resources/types/legacy/airship.craft | 166 ++++ .../resources/types/legacy/airskiff.craft | 126 +++ .../resources/types/legacy/elevator.craft | 100 +++ modules/api/pom.xml | 1 + .../movecraft/MovecraftRepair.java | 29 + .../movecraft/config/ConfigManager.java | 31 +- .../movecraft/config/Settings.java | 19 +- .../countercraft/movecraft/craft/Craft.java | 3 +- .../movecraft/craft/CraftType.java | 290 +++++-- modules/v1_10_R1/pom.xml | 17 +- .../compat/v1_10_R1/IMovecraftRepair.java | 477 ++++++++++++ modules/v1_11_R1/pom.xml | 17 +- .../compat/v1_11_R1/IMovecraftRepair.java | 477 ++++++++++++ modules/v1_12_R1/pom.xml | 13 +- modules/v1_13_R2/pom.xml | 79 ++ .../compat/v1_13_R2/IMovecraftRepair.java | 131 ++++ pom.xml | 97 +-- 76 files changed, 6132 insertions(+), 2262 deletions(-) create mode 100644 modules/Movecraft/src/main/java/net/countercraft/movecraft/factions/FactionsCompatManager.java delete mode 100644 modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/WorldEditInteractListener.java create mode 100644 modules/Movecraft/src/main/java/net/countercraft/movecraft/repair/RepairUtils.java create mode 100644 modules/Movecraft/src/main/resources/types/legacy/BigAirship.craft create mode 100644 modules/Movecraft/src/main/resources/types/legacy/BigSubAirship.craft create mode 100644 modules/Movecraft/src/main/resources/types/legacy/LaunchTorpedo.craft create mode 100644 modules/Movecraft/src/main/resources/types/legacy/Ship.craft create mode 100644 modules/Movecraft/src/main/resources/types/legacy/SubAirship.craft create mode 100644 modules/Movecraft/src/main/resources/types/legacy/Submarine.craft create mode 100644 modules/Movecraft/src/main/resources/types/legacy/Turret.craft create mode 100644 modules/Movecraft/src/main/resources/types/legacy/airship.craft create mode 100644 modules/Movecraft/src/main/resources/types/legacy/airskiff.craft create mode 100644 modules/Movecraft/src/main/resources/types/legacy/elevator.craft create mode 100644 modules/api/src/main/java/net/countercraft/movecraft/MovecraftRepair.java create mode 100644 modules/v1_10_R1/src/main/java/net/countercraft/movecraft/compat/v1_10_R1/IMovecraftRepair.java create mode 100644 modules/v1_11_R1/src/main/java/net/countercraft/movecraft/compat/v1_11_R1/IMovecraftRepair.java create mode 100644 modules/v1_13_R2/pom.xml create mode 100644 modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/IMovecraftRepair.java diff --git a/modules/Movecraft/pom.xml b/modules/Movecraft/pom.xml index 1189bb682..88cf9644b 100644 --- a/modules/Movecraft/pom.xml +++ b/modules/Movecraft/pom.xml @@ -35,6 +35,12 @@ + + net.countercraft + movecraft-v1_13_R2 + v1_13_R2 + jar + net.countercraft movecraft-v1_10_R1 @@ -53,6 +59,7 @@ v1_12_R1 jar + net.countercraft movecraft-api @@ -69,6 +76,11 @@ worldedit LATEST + + com.sk89q.worldedit + worldedit-bukkit + 7.0.0-SNAPSHOT + at.pavlov Cannons @@ -115,6 +127,20 @@ system ${project.basedir}/../../libs/WGCustomFlags.jar + + com.massivecraft + Factions + LATEST + system + ${project.basedir}/../../libs/Factions.jar + + + com.massivecraft + MassiveCore + LATEST + system + ${project.basedir}/../../libs/MassiveCore.jar + org.jetbrains annotations-java5 diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java index 9636b2db4..2cdac94f6 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java @@ -19,6 +19,7 @@ import at.pavlov.cannons.Cannons; import com.earth2me.essentials.Essentials; +import com.massivecraft.factions.Factions; import com.mewin.WGCustomFlags.WGCustomFlagsPlugin; import com.palmergames.bukkit.towny.Towny; import com.sk89q.worldedit.bukkit.WorldEditPlugin; @@ -31,9 +32,9 @@ import net.countercraft.movecraft.listener.BlockListener; import net.countercraft.movecraft.listener.InteractListener; import net.countercraft.movecraft.listener.PlayerListener; -import net.countercraft.movecraft.listener.WorldEditInteractListener; import net.countercraft.movecraft.localisation.I18nSupport; import net.countercraft.movecraft.mapUpdater.MapUpdateManager; +import net.countercraft.movecraft.repair.RepairManager; import net.countercraft.movecraft.sign.*; import net.countercraft.movecraft.utils.TownyUtils; import net.countercraft.movecraft.utils.WGCustomFlagsUtils; @@ -43,7 +44,6 @@ import net.countercraft.movecraft.worldguard.WorldGuardCompatManager; import net.milkbowl.vault.economy.Economy; import org.bukkit.Material; -import org.bukkit.World; import org.bukkit.plugin.Plugin; import org.bukkit.plugin.RegisteredServiceProvider; import org.bukkit.plugin.java.JavaPlugin; @@ -70,6 +70,7 @@ public class Movecraft extends JavaPlugin { private static Cannons cannonsPlugin = null; private static Towny townyPlugin = null; private static Essentials essentialsPlugin = null; + private static Factions factionsPlugin; /*public HashMap blockFadeTimeMap = new HashMap<>(); public HashMap blockFadeTypeMap = new HashMap<>(); public HashMap blockFadeWaterMap = new HashMap<>(); @@ -77,11 +78,13 @@ public class Movecraft extends JavaPlugin { private Logger logger; private boolean shuttingDown; private WorldHandler worldHandler; + private MovecraftRepair movecraftRepair; private AsyncManager asyncManager; private AssaultManager assaultManager; private SiegeManager siegeManager; + private RepairManager repairManager; public static synchronized Movecraft getInstance() { return instance; @@ -109,10 +112,10 @@ public void onEnable() { Settings.Debug = getConfig().getBoolean("Debug", false); Settings.DisableSpillProtection = getConfig().getBoolean("DisableSpillProtection", false); // if the PilotTool is specified in the config.yml file, use it - if (getConfig().getInt("PilotTool") != 0) { + if (getConfig().getString("PilotTool") != null || getConfig().getString("PilotTool") != "") { logger.log(Level.INFO, "Recognized PilotTool setting of: " - + getConfig().getInt("PilotTool")); - Settings.PilotTool = getConfig().getInt("PilotTool"); + + getConfig().getString("PilotTool")); + Settings.PilotTool = Material.getMaterial(getConfig().getString("PilotTool")); } else { logger.log(Level.INFO, "No PilotTool setting, using default of 280"); } @@ -131,6 +134,14 @@ public void onEnable() { //Switch to interfaces String packageName = this.getServer().getClass().getPackage().getName(); String version = packageName.substring(packageName.lastIndexOf('.') + 1); + String[] parts = version.split("_"); + Integer versionNumber = Integer.valueOf(parts[1]); + //Check if the server is 1.12 and lower or 1.13 anf higher + if (versionNumber <= 12){ + Settings.IsLegacy = true; + } else { + Settings.IsLegacy = false; + } try { final Class clazz = Class.forName("net.countercraft.movecraft.compat." + version + ".IWorldHandler"); // Check if we have a NMSHandler class at that location. @@ -143,8 +154,9 @@ public void onEnable() { this.setEnabled(false); return; } - this.getLogger().info("Loading support for " + version); + this.getLogger().info("Loading support for " + version); + this.getLogger().info("isLegacy: " + Settings.IsLegacy); Settings.SinkCheckTicks = getConfig().getDouble("SinkCheckTicks", 100.0); Settings.TracerRateTicks = getConfig().getDouble("TracerRateTicks", 5.0); @@ -164,7 +176,7 @@ public void onEnable() { Map temp = getConfig().getConfigurationSection("DurabilityOverride").getValues(false); Settings.DurabilityOverride = new HashMap<>(); for (String str : temp.keySet()) { - Settings.DurabilityOverride.put(Integer.parseInt(str), (Integer) temp.get(str)); + Settings.DurabilityOverride.put(Material.getMaterial(str), (Integer) temp.get(str)); } } @@ -176,17 +188,23 @@ public void onEnable() { Settings.AssaultCostPercent = getConfig().getDouble("AssaultCostPercent", 0.25); Settings.AssaultDamagesPerBlock = getConfig().getInt("AssaultDamagesPerBlock", 15); Settings.AssaultRequiredDefendersOnline = getConfig().getInt("AssaultRequiredDefendersOnline", 3); - Settings.AssaultDestroyableBlocks = new HashSet<>(getConfig().getIntegerList("AssaultDestroyableBlocks")); - Settings.DisableShadowBlocks = new HashSet<>(getConfig().getIntegerList("DisableShadowBlocks")); //REMOVE FOR PUBLIC VERSION - + List assaultDestroyableBlocks = getConfig().getStringList("AssaultDestroyableBlocks"); + for (String matStr : assaultDestroyableBlocks){ + Settings.AssaultDestroyableBlocks.add(Material.getMaterial(matStr)); + } + List disableShadowBlocks = getConfig().getStringList("DisableShadowBlocks"); + for (String typ : disableShadowBlocks){ + Settings.DisableShadowBlocks.add(Material.getMaterial(typ)); + } + Settings.RepairMaxPercent = getConfig().getDouble("RepairMaxPercent", 50.0); Settings.SiegeEnable = getConfig().getBoolean("SiegeEnable", false); if (!Settings.CompatibilityMode) { - for (int typ : Settings.DisableShadowBlocks) { - worldHandler.disableShadow(Material.getMaterial(typ)); + for (Material typ : Settings.DisableShadowBlocks) { + worldHandler.disableShadow(typ); } } //load up WorldGuard if it's present @@ -213,9 +231,24 @@ public void onEnable() { } else { logger.log(Level.INFO, "Found a compatible version of WorldEdit. Enabling WorldEdit integration"); Settings.RepairTicksPerBlock = getConfig().getInt("RepairTicksPerBlock", 0); + //Test if a compatible MovecraftRepair is present + try { + final Class clazz = Class.forName("net.countercraft.movecraft.compat." + version + ".IMovecraftRepair"); + //Check if we have a Repair class at that location + if (MovecraftRepair.class.isAssignableFrom(clazz)){ + this.movecraftRepair = (MovecraftRepair) clazz.getConstructor().newInstance(); + } + } catch (final Exception e){ + e.printStackTrace(); + this.getLogger().severe("Could not find a compatible repair class. Disabling repair function"); + Settings.RepairTicksPerBlock = 0; + } } worldEditPlugin = (WorldEditPlugin) wEPlugin; + + + // next is Cannons Plugin plug = getServer().getPluginManager().getPlugin("Cannons"); if (plug != null && plug instanceof Cannons) { @@ -247,6 +280,7 @@ public void onEnable() { } } } + //Towny Plugin tempTownyPlugin = getServer().getPluginManager().getPlugin("Towny"); if (tempTownyPlugin != null && tempTownyPlugin instanceof Towny) { logger.log(Level.INFO, "Found a compatible version of Towny. Enabling Towny integration."); @@ -260,7 +294,7 @@ public void onEnable() { } else { logger.log(Level.INFO, "Movecraft did not find a compatible version of Towny. Disabling Towny integration."); } - + //Essentials Plugin tempEssentialsPlugin = getServer().getPluginManager().getPlugin("Essentials"); if (tempEssentialsPlugin != null) { if (tempEssentialsPlugin.getDescription().getName().equalsIgnoreCase("essentials")) { @@ -275,7 +309,17 @@ public void onEnable() { if (essentialsPlugin == null) { logger.log(Level.INFO, "Movecraft did not find a compatible version of Essentials. Disabling Essentials integration."); } - + //Factions + Plugin tempFactionsPlugin = getServer().getPluginManager().getPlugin("Factions"); + if (tempFactionsPlugin != null){ + if (tempFactionsPlugin instanceof Factions){ + factionsPlugin = (Factions) tempFactionsPlugin; + logger.info("Movecraft found a compatible version of Factions. Enabling Factions integration."); + } + } + if (factionsPlugin == null){ + logger.info("Movecraft did not find a compatible version of Factions. Disabling Factions integration"); + } // and now Vault if (getServer().getPluginManager().getPlugin("Vault") != null) { RegisteredServiceProvider rsp = getServer().getServicesManager().getRegistration(Economy.class); @@ -363,12 +407,15 @@ public void onEnable() { } siegeManager.runTaskTimerAsynchronously(this, 0, 20); + } CraftManager.initialize(); getServer().getPluginManager().registerEvents(new InteractListener(), this); if (worldEditPlugin != null) { - getServer().getPluginManager().registerEvents(new WorldEditInteractListener(), this); + //getServer().getPluginManager().registerEvents(new WorldEditInteractListener(), this); + repairManager = new RepairManager(this); + repairManager.runTaskTimerAsynchronously(this, 0,1); } this.getCommand("movecraft").setExecutor(new MovecraftCommand()); this.getCommand("release").setExecutor(new ReleaseCommand()); @@ -400,10 +447,11 @@ public void onEnable() { getServer().getPluginManager().registerEvents(new MoveSign(), this); getServer().getPluginManager().registerEvents(new NameSign(), this); getServer().getPluginManager().registerEvents(new PilotSign(), this); + getServer().getPluginManager().registerEvents(new RegionDamagedSign(), this); getServer().getPluginManager().registerEvents(new RelativeMoveSign(), this); getServer().getPluginManager().registerEvents(new ReleaseSign(), this); getServer().getPluginManager().registerEvents(new RemoteSign(), this); - //getServer().getPluginManager().registerEvents(new RepairSign(), this); + getServer().getPluginManager().registerEvents(new RepairSign(), this); getServer().getPluginManager().registerEvents(new SpeedSign(), this); getServer().getPluginManager().registerEvents(new StatusSign(), this); getServer().getPluginManager().registerEvents(new SubcraftRotateSign(), this); @@ -464,5 +512,13 @@ public WorldHandler getWorldHandler(){ public AsyncManager getAsyncManager(){return asyncManager;} + public MovecraftRepair getMovecraftRepair() {return movecraftRepair;} + + public RepairManager getRepairManager() { + return repairManager; + } + public Factions getFactionsPlugin(){ + return factionsPlugin; + } } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java index dd2f0969f..ff1a38cf3 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java @@ -18,7 +18,6 @@ package net.countercraft.movecraft.async; import at.pavlov.cannons.cannon.Cannon; -import com.google.common.collect.Iterators; import com.google.common.collect.Lists; import net.countercraft.movecraft.Movecraft; import net.countercraft.movecraft.MovecraftLocation; @@ -33,9 +32,9 @@ import net.countercraft.movecraft.events.CraftDetectEvent; import net.countercraft.movecraft.localisation.I18nSupport; import net.countercraft.movecraft.mapUpdater.MapUpdateManager; -import net.countercraft.movecraft.mapUpdater.update.UpdateCommand; import net.countercraft.movecraft.utils.CollectionUtils; import net.countercraft.movecraft.utils.HashHitBox; +import net.countercraft.movecraft.utils.LegacyUtils; import org.bukkit.*; import org.bukkit.block.Block; import org.bukkit.entity.Player; @@ -66,24 +65,33 @@ public class AsyncManager extends BukkitRunnable { public AsyncManager() { transparent = new HashSet<>(); + //These materials exists in both 1.12 and 1.13 APIs transparent.add(Material.AIR); transparent.add(Material.GLASS); - transparent.add(Material.THIN_GLASS); - transparent.add(Material.STAINED_GLASS); - transparent.add(Material.STAINED_GLASS_PANE); - transparent.add(Material.IRON_FENCE); transparent.add(Material.REDSTONE_WIRE); transparent.add(Material.IRON_TRAPDOOR); - transparent.add(Material.TRAP_DOOR); transparent.add(Material.NETHER_BRICK_STAIRS); transparent.add(Material.LEVER); transparent.add(Material.STONE_BUTTON); - transparent.add(Material.WOOD_BUTTON); - transparent.add(Material.STEP); - transparent.add(Material.SMOOTH_STAIRS); transparent.add(Material.SIGN); - transparent.add(Material.SIGN_POST); transparent.add(Material.WALL_SIGN); + if (Settings.IsLegacy){ + transparent.add(LegacyUtils.THIN_GLASS); + transparent.add(LegacyUtils.STAINED_GLASS); + transparent.add(LegacyUtils.STAINED_GLASS_PANE); + transparent.add(LegacyUtils.IRON_FENCE); + transparent.add(LegacyUtils.TRAP_DOOR); + transparent.add(LegacyUtils.WOOD_BUTTON); + transparent.add(LegacyUtils.STEP); + transparent.add(LegacyUtils.SMOOTH_STAIRS); + transparent.add(LegacyUtils.SIGN_POST); + } else { + transparent.add(Material.GLASS_PANE); + transparent.add(Material.BLACK_STAINED_GLASS_PANE); + transparent.add(Material.WHITE_STAINED_GLASS_PANE); + transparent.add(Material.GRAY_STAINED_GLASS_PANE); + transparent.add(Material.GREEN_STAINED_GLASS_PANE); + } } /* public static AsyncManager getInstance() { @@ -452,40 +460,39 @@ private void detectSinking(){ final World w = pcraft.getW(); int totalNonAirBlocks = 0; int totalNonAirWaterBlocks = 0; - HashMap, Integer> foundFlyBlocks = new HashMap<>(); - HashMap, Integer> foundMoveBlocks = new HashMap<>(); + HashMap>, Integer> foundFlyBlocks = new HashMap<>(); + HashMap>, Integer> foundMoveBlocks = new HashMap<>(); // go through each block in the blocklist, and // if its in the FlyBlocks, total up the number // of them for (MovecraftLocation l : pcraft.getHitBox()) { - int blockID = w.getBlockAt(l.getX(), l.getY(), l.getZ()).getTypeId(); - int dataID = (int) w.getBlockAt(l.getX(), l.getY(), l.getZ()).getData(); - int shiftedID = (blockID << 4) + dataID + 10000; - for (List flyBlockDef : pcraft.getType().getFlyBlocks().keySet()) { - if (flyBlockDef.contains(blockID) || flyBlockDef.contains(shiftedID)) { + Material blockType = w.getBlockAt(l.getX(), l.getY(), l.getZ()).getType(); + byte dataID = w.getBlockAt(l.getX(), l.getY(), l.getZ()).getData(); + for (Map> flyBlockDef : pcraft.getType().getFlyBlocks().keySet()) { + if ((flyBlockDef.containsKey(blockType) && flyBlockDef.get(blockType).isEmpty())|| (flyBlockDef.containsKey(blockType) && flyBlockDef.get(blockType).contains(dataID))) { foundFlyBlocks.merge(flyBlockDef, 1, (a, b) -> a + b); } } - for (List moveBlockDef : pcraft.getType().getMoveBlocks().keySet()) { - if (moveBlockDef.contains(blockID) || moveBlockDef.contains(shiftedID)) { + for (Map> moveBlockDef : pcraft.getType().getMoveBlocks().keySet()) { + if ((moveBlockDef.containsKey(blockType) && moveBlockDef.get(blockType).isEmpty())|| (moveBlockDef.containsKey(blockType) && moveBlockDef.get(blockType).contains(dataID))) { foundMoveBlocks.merge(moveBlockDef, 1, (a, b) -> a + b); } } - if (blockID != 0) { + if (blockType != Material.AIR) { totalNonAirBlocks++; } - if (blockID != 0 && blockID != 8 && blockID != 9) { + if (blockType != Material.AIR && blockType != Material.WATER && blockType != LegacyUtils.STATIONARY_WATER) { totalNonAirWaterBlocks++; } } - // now see if any of the resulting percentagesit + // now see if any of the resulting percentages // are below the threshold specified in // SinkPercent boolean isSinking = false; - for (List i : pcraft.getType().getFlyBlocks().keySet()) { + for (Map> i : pcraft.getType().getFlyBlocks().keySet()) { int numfound = 0; if (foundFlyBlocks.get(i) != null) { numfound = foundFlyBlocks.get(i); @@ -498,7 +505,7 @@ private void detectSinking(){ } } - for (List i : pcraft.getType().getMoveBlocks().keySet()) { + for (Map> i : pcraft.getType().getMoveBlocks().keySet()) { int numfound = 0; if (foundMoveBlocks.get(i) != null) { numfound = foundMoveBlocks.get(i); @@ -510,7 +517,7 @@ private void detectSinking(){ pcraft.setDisabled(true); if (pcraft.getNotificationPlayer() != null) { Location loc = pcraft.getNotificationPlayer().getLocation(); - pcraft.getW().playSound(loc, Sound.ENTITY_IRONGOLEM_DEATH, 5.0f, 5.0f); + pcraft.getW().playSound(loc, Settings.IsLegacy ? LegacyUtils.ENITIY_IRONGOLEM_DEATH : Sound.ENTITY_IRON_GOLEM_DEATH , 5.0f, 5.0f); } } } @@ -608,7 +615,7 @@ private void processTracers() { new BukkitRunnable() { @Override public void run() { - fp.sendBlockChange(loc, 30, (byte) 0); + fp.sendBlockChange(loc, Settings.IsLegacy ? LegacyUtils.WEB :Material.COBWEB, (byte) 0); } }.runTaskLater(Movecraft.getInstance(), 5); // then remove it @@ -618,7 +625,7 @@ public void run() { // fp.sendBlockChange(loc, // fw.getBlockAt(loc).getType(), // fw.getBlockAt(loc).getData()); - fp.sendBlockChange(loc, 0, (byte) 0); + fp.sendBlockChange(loc, Material.AIR, (byte) 0); } }.runTaskLater(Movecraft.getInstance(), 160); } @@ -664,7 +671,7 @@ private void processFireballs() { boolean inRange = (distX < 50) && (distY < 50) && (distZ < 50); if ((c.getAADirector() != null) && inRange) { p = c.getAADirector(); - if (p.getItemInHand().getTypeId() == Settings.PilotTool) { + if (p.getItemInHand().getType() == Settings.PilotTool) { Vector fv = fireball.getVelocity(); double speed = fv.length(); // store the speed to add it back in later, since all the values we will be using are "normalized", IE: have a speed of 1 fv = fv.normalize(); // you normalize it for comparison with the new direction to see if we are trying to steer too far @@ -774,7 +781,7 @@ private void processTNTContactExplosives() { boolean inRange = (distX < 100) && (distY < 100) && (distZ < 100); if ((c.getCannonDirector() != null) && inRange) { Player p = c.getCannonDirector(); - if (p.getInventory().getItemInMainHand().getTypeId() == Settings.PilotTool) { + if (p.getInventory().getItemInMainHand().getType() == Settings.PilotTool) { Vector tv = tnt.getVelocity(); double speed = tv.length(); // store the speed to add it back in later, since all the values we will be using are "normalized", IE: have a speed of 1 tv = tv.normalize(); // you normalize it for comparison with the new direction to see if we are trying to steer too far diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/detection/DetectionTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/detection/DetectionTask.java index 7b97b4976..ee2135144 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/detection/DetectionTask.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/detection/DetectionTask.java @@ -18,12 +18,13 @@ package net.countercraft.movecraft.async.detection; -import net.countercraft.movecraft.Movecraft; import net.countercraft.movecraft.MovecraftLocation; import net.countercraft.movecraft.async.AsyncTask; +import net.countercraft.movecraft.config.Settings; import net.countercraft.movecraft.craft.Craft; import net.countercraft.movecraft.localisation.I18nSupport; import net.countercraft.movecraft.utils.*; +import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.World; @@ -40,14 +41,14 @@ public class DetectionTask extends AsyncTask { private final Stack blockStack = new Stack<>(); private final HashHitBox blockList = new HashHitBox(); private final HashSet visited = new HashSet<>(); - private final HashMap, Integer> blockTypeCount = new HashMap<>(); + private final HashMap>, Integer> blockTypeCount = new HashMap>, Integer>(); private final DetectionTaskData data; private final World world; private int maxX; private int maxY; private int maxZ; private int minY; - private Map, List> dFlyBlocks; + private Map>, List> dFlyBlocks; private int foundDynamicFlyBlock = 0; public DetectionTask(Craft c, MovecraftLocation startLocation, Player player) { @@ -62,9 +63,8 @@ public DetectionTask(Craft c, MovecraftLocation startLocation, Player player) { @Override public void execute() { - Map, List> flyBlocks = getCraft().getType().getFlyBlocks(); + Map>, List> flyBlocks = getCraft().getType().getFlyBlocks(); dFlyBlocks = flyBlocks; - blockStack.push(startLocation); do { detectSurrounding(blockStack.pop()); @@ -76,8 +76,8 @@ public void execute() { int totalBlocks = blockList.size(); double ratio = (double) foundDynamicFlyBlock / totalBlocks; double foundMinimum = 0.0; - for (List i : flyBlocks.keySet()) { - if (i.contains(getCraft().getType().getDynamicFlyBlock())) + for (Map> i : flyBlocks.keySet()) { + if (i.containsKey(getCraft().getType().getDynamicFlyBlock())) foundMinimum = flyBlocks.get(i).get(0); } ratio = ratio - (foundMinimum / 100.0); @@ -99,19 +99,21 @@ private void detectBlock(int x, int y, int z) { if (notVisited(workingLocation, visited)) { + Material testType = null; int testID = 0; int testData = 0; try { testData = data.getWorld().getBlockAt(x, y, z).getData(); - testID = data.getWorld().getBlockTypeIdAt(x, y, z); + testType = data.getWorld().getBlockAt(x, y, z).getType(); + } catch (Exception e) { fail(String.format(I18nSupport.getInternationalisedString("Detection - Craft too large"), maxSize)); } - if ((testID == 8) || (testID == 9)) { + if ((testType == Material.WATER) || (testType == LegacyUtils.STATIONARY_WATER)) { data.setWaterContact(true); } - if (testID == 63 || testID == 68) { + if (testType == (Settings.IsLegacy ? LegacyUtils.SIGN_POST : Material.SIGN) || testType == Material.WALL_SIGN) { BlockState state = data.getWorld().getBlockAt(x, y, z).getState(); if (state instanceof Sign) { Sign s = (Sign) state; @@ -138,22 +140,22 @@ private void detectBlock(int x, int y, int z) { } } } - if (isForbiddenBlock(testID, testData)) { + if (isForbiddenBlock(testType, testData)) { fail(I18nSupport.getInternationalisedString("Detection - Forbidden block found")); - } else if (isAllowedBlock(testID, testData)) { + } else if (isAllowedBlock(testType, testData)) { // check for double chests - if (testID == 54) { + if (testType == Material.CHEST) { boolean foundDoubleChest = false; - if (data.getWorld().getBlockTypeIdAt(x - 1, y, z) == 54) { + if (data.getWorld().getBlockAt(x - 1, y, z).getType() == Material.CHEST) { foundDoubleChest = true; } - if (data.getWorld().getBlockTypeIdAt(x + 1, y, z) == 54) { + if (data.getWorld().getBlockAt(x + 1, y, z).getType() == Material.CHEST) { foundDoubleChest = true; } - if (data.getWorld().getBlockTypeIdAt(x, y, z - 1) == 54) { + if (data.getWorld().getBlockAt(x, y, z - 1).getType() == Material.CHEST) { foundDoubleChest = true; } - if (data.getWorld().getBlockTypeIdAt(x, y, z + 1) == 54) { + if (data.getWorld().getBlockAt(x, y, z + 1).getType() == Material.CHEST) { foundDoubleChest = true; } if (foundDoubleChest) { @@ -162,18 +164,18 @@ private void detectBlock(int x, int y, int z) { } } // check for double trapped chests - if (testID == 146) { + if (testType == Material.TRAPPED_CHEST) { boolean foundDoubleChest = false; - if (data.getWorld().getBlockTypeIdAt(x - 1, y, z) == 146) { + if (data.getWorld().getBlockAt(x - 1, y, z).getType() == Material.TRAPPED_CHEST) { foundDoubleChest = true; } - if (data.getWorld().getBlockTypeIdAt(x + 1, y, z) == 146) { + if (data.getWorld().getBlockAt(x + 1, y, z).getType() == Material.TRAPPED_CHEST) { foundDoubleChest = true; } - if (data.getWorld().getBlockTypeIdAt(x, y, z - 1) == 146) { + if (data.getWorld().getBlockAt(x, y, z - 1).getType() == Material.TRAPPED_CHEST) { foundDoubleChest = true; } - if (data.getWorld().getBlockTypeIdAt(x, y, z + 1) == 146) { + if (data.getWorld().getBlockAt(x, y, z + 1).getType() == Material.TRAPPED_CHEST) { foundDoubleChest = true; } if (foundDoubleChest) { @@ -192,18 +194,19 @@ private void detectBlock(int x, int y, int z) { if (p != null) { addToBlockList(workingLocation); - Integer blockID = testID; - Integer dataID = testData; + Material blockType = testType; + int blockID = testID; + int dataID = testData; Integer shiftedID = (blockID << 4) + dataID + 10000; - for (List flyBlockDef : dFlyBlocks.keySet()) { - if (flyBlockDef.contains(blockID) || flyBlockDef.contains(shiftedID)) { + for (Map> flyBlockDef : dFlyBlocks.keySet()) { + if ((flyBlockDef.containsKey(blockType) && flyBlockDef.get(blockType).isEmpty()) || (flyBlockDef.containsKey(blockType) && flyBlockDef.get(blockType).contains(dataID))) { addToBlockCount(flyBlockDef); } else { addToBlockCount(null); } } if (getCraft().getType().getDynamicFlyBlockSpeedFactor() != 0.0) { - if (blockID == getCraft().getType().getDynamicFlyBlock()) { + if (blockType == getCraft().getType().getDynamicFlyBlock()) { foundDynamicFlyBlock++; } } @@ -220,21 +223,38 @@ private void detectBlock(int x, int y, int z) { } } - private boolean isAllowedBlock(int test, int testData) { + private boolean isAllowedBlock(Material test, int testData) { - for (int i : data.getAllowedBlocks()) { - if ((i == test) || (i == (test << 4) + testData + 10000)) { + if (data.getAllowedBlocks().containsKey(test)){ + if (!data.getAllowedBlocks().get(test).isEmpty()){ + if (data.getAllowedBlocks().get(test).contains(testData)){ + return true; + } else { + return false; + } + } else { return true; } } + /* + for (Material type : data.getAllowedBlocks().keySet()) { + if ((type == test) || (type == test && data.getAllowedBlocks().get(test).contains(testData))) { + return true; + } + }*/ return false; } - private boolean isForbiddenBlock(int test, int testData) { - - for (int i : data.getForbiddenBlocks()) { - if ((i == test) || (i == (test << 4) + testData + 10000)) { + private boolean isForbiddenBlock(Material test, int testData) { + if (data.getForbiddenBlocks().containsKey(test)){ + if (!data.getForbiddenBlocks().get(test).isEmpty()){ + if (data.getForbiddenBlocks().get(test).contains(testData)){ + return true; + } else { + return false; + } + } else { return true; } } @@ -274,7 +294,7 @@ private void addToDetectionStack(MovecraftLocation l) { blockStack.push(l); } - private void addToBlockCount(List id) { + private void addToBlockCount(Map> id) { Integer count = blockTypeCount.get(id); if (count == null) { @@ -370,8 +390,8 @@ private MovecraftLocation[] finaliseBlockList(HashSet blockSe return finalList.toArray(new MovecraftLocation[1]); } - private boolean confirmStructureRequirements(Map, List> flyBlocks, - Map, Integer> countData) { + private boolean confirmStructureRequirements(Map>, List> flyBlocks, + HashMap>, Integer> countData) { if (getCraft().getType().getRequireWaterContact()) { if (!data.getWaterContact()) { fail(I18nSupport @@ -379,9 +399,8 @@ private boolean confirmStructureRequirements(Map, List> fl return false; } } - for (List i : flyBlocks.keySet()) { + for (Map> i : flyBlocks.keySet()) { Integer numberOfBlocks = countData.get(i); - if (numberOfBlocks == null) { numberOfBlocks = 0; } @@ -391,65 +410,103 @@ private boolean confirmStructureRequirements(Map, List> fl Double maxPercentage = flyBlocks.get(i).get(1); if (minPercentage < 10000.0) { if (blockPercentage < minPercentage) { - if (i.get(0) < 10000) { - fail(String.format( - I18nSupport.getInternationalisedString("Not enough flyblock") + ": %s %.2f%% < %.2f%%", - Material.getMaterial(i.get(0)).name().toLowerCase().replace("_", " "), blockPercentage, - minPercentage)); - return false; - } else { - fail(String.format( - I18nSupport.getInternationalisedString("Not enough flyblock") + ": %s %.2f%% < %.2f%%", - Material.getMaterial((i.get(0) - 10000) >> 4).name().toLowerCase().replace("_", " "), - blockPercentage, minPercentage)); - return false; + if (i != null) { + if (i.get(0) != null) { + if (i.get(0).isEmpty() || i.get(0) == null) { + fail(String.format( + I18nSupport.getInternationalisedString("Not enough flyblock") + ": %s %.2f%% < %.2f%%", + i.keySet().iterator().next().name().toLowerCase().replace("_", " "), blockPercentage, + minPercentage)); + return false; + } else { + fail(String.format( + I18nSupport.getInternationalisedString("Not enough flyblock") + ": %s %.2f%% < %.2f%%", + i.keySet().iterator().next().name().toLowerCase().replace("_", " "), + blockPercentage, minPercentage)); + return false; + } + } else { + fail(String.format( + I18nSupport.getInternationalisedString("Not enough flyblock") + ": %s %.2f%% < %.2f%%", + i.keySet().iterator().next().name().toLowerCase().replace("_", " "), blockPercentage, + minPercentage)); + return false; + } } } } else { if (numberOfBlocks < flyBlocks.get(i).get(0) - 10000.0) { - if (i.get(0) < 10000) { - fail(String.format( - I18nSupport.getInternationalisedString("Not enough flyblock") + ": %s %d < %d", - Material.getMaterial(i.get(0)).name().toLowerCase().replace("_", " "), numberOfBlocks, - flyBlocks.get(i).get(0).intValue() - 10000)); - return false; - } else { - fail(String.format( - I18nSupport.getInternationalisedString("Not enough flyblock") + ": %s %d < %d", - Material.getMaterial((i.get(0) - 10000) >> 4).name().toLowerCase().replace("_", " "), - numberOfBlocks, flyBlocks.get(i).get(0).intValue() - 10000)); - return false; + if (i != null) { + if (i.get(0) != null) { + if (i.get(0).isEmpty() || i.get(0) == null) { + fail(String.format( + I18nSupport.getInternationalisedString("Not enough flyblock") + ": %s %d < %d", + i.keySet().iterator().next().name().toLowerCase().replace("_", " "), numberOfBlocks, + flyBlocks.get(i).get(0).intValue() - 10000)); + return false; + } else { + fail(String.format( + I18nSupport.getInternationalisedString("Not enough flyblock") + ": %s %d < %d", + i.keySet().iterator().next().name().toLowerCase().replace("_", " "), + numberOfBlocks, flyBlocks.get(i).get(0).intValue() - 10000)); + return false; + } + } else { + fail(String.format(I18nSupport.getInternationalisedString("Not enough flyblock") + ": %s %d > %d", + i.keySet().iterator().next().name().toLowerCase().replace("_", " "), numberOfBlocks, + flyBlocks.get(i).get(1).intValue() - 10000)); + return false; + } } } } if (maxPercentage < 10000.0) { if (blockPercentage > maxPercentage) { - if (i.get(0) < 10000) { - fail(String.format( - I18nSupport.getInternationalisedString("Too much flyblock") + ": %s %.2f%% > %.2f%%", - Material.getMaterial(i.get(0)).name().toLowerCase().replace("_", " "), blockPercentage, - maxPercentage)); - return false; - } else { - fail(String.format( - I18nSupport.getInternationalisedString("Too much flyblock") + ": %s %.2f%% > %.2f%%", - Material.getMaterial((i.get(0) - 10000) >> 4).name().toLowerCase().replace("_", " "), - blockPercentage, maxPercentage)); - return false; + if (i != null) { + if (i.get(0) != null) { + if (i.get(0).isEmpty() || i.get(0) == null) { + fail(String.format( + I18nSupport.getInternationalisedString("Too much flyblock") + ": %s %.2f%% > %.2f%%", + i.keySet().iterator().next().name().toLowerCase().replace("_", " "), blockPercentage, + maxPercentage)); + return false; + } else { + fail(String.format( + I18nSupport.getInternationalisedString("Too much flyblock") + ": %s %.2f%% > %.2f%%", + i.keySet().iterator().next().name().toLowerCase().replace("_", " "), + blockPercentage, maxPercentage)); + return false; + } + } else { + fail(String.format( + I18nSupport.getInternationalisedString("Too much flyblock") + ": %s %.2f%% > %.2f%%", + i.keySet().iterator().next().name().toLowerCase().replace("_", " "), + blockPercentage, maxPercentage)); + return false; + } } } } else { if (numberOfBlocks > flyBlocks.get(i).get(1) - 10000.0) { - if (i.get(0) < 10000) { - fail(String.format(I18nSupport.getInternationalisedString("Too much flyblock") + ": %s %d > %d", - Material.getMaterial(i.get(0)).name().toLowerCase().replace("_", " "), numberOfBlocks, - flyBlocks.get(i).get(1).intValue() - 10000)); - return false; - } else { - fail(String.format(I18nSupport.getInternationalisedString("Too much flyblock") + ": %s %d > %d", - Material.getMaterial((i.get(0) - 10000) >> 4).name().toLowerCase().replace("_", " "), - numberOfBlocks, flyBlocks.get(i).get(1).intValue() - 10000)); - return false; + if (i != null) { + if (i.get(0) != null) { + if (i.get(0).isEmpty()) { + fail(String.format(I18nSupport.getInternationalisedString("Too much flyblock") + ": %s %d > %d", + i.keySet().iterator().next().name().toLowerCase().replace("_", " "), numberOfBlocks, + flyBlocks.get(i).get(1).intValue() - 10000)); + return false; + } else { + fail(String.format(I18nSupport.getInternationalisedString("Too much flyblock") + ": %s %d > %d", + i.keySet().iterator().next().name().toLowerCase().replace("_", " "), + numberOfBlocks, flyBlocks.get(i).get(1).intValue() - 10000)); + return false; + } + } else { + fail(String.format(I18nSupport.getInternationalisedString("Too much flyblock") + ": %s %d > %d", + i.keySet().iterator().next().name().toLowerCase().replace("_", " "), numberOfBlocks, + flyBlocks.get(i).get(1).intValue() - 10000)); + return false; + } } } } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/detection/DetectionTaskData.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/detection/DetectionTaskData.java index 32ae4ac3b..88613478d 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/detection/DetectionTaskData.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/detection/DetectionTaskData.java @@ -19,9 +19,13 @@ import net.countercraft.movecraft.utils.HashHitBox; import net.countercraft.movecraft.utils.HitBox; +import org.bukkit.Material; import org.bukkit.World; import org.bukkit.entity.Player; +import java.util.List; +import java.util.Map; + @Deprecated public class DetectionTaskData { public Double dynamicFlyBlockSpeedMultiplier; @@ -33,10 +37,11 @@ public class DetectionTaskData { private Player player; private Player notificationPlayer; private int minX, minZ; - private int[] allowedBlocks, forbiddenBlocks; + private Map> allowedBlocks; + private Map> forbiddenBlocks; private String[] forbiddenSignStrings; - public DetectionTaskData(World w, Player player, Player notificationPlayer, int[] allowedBlocks, int[] forbiddenBlocks, String[] forbiddenSignStrings) { + public DetectionTaskData(World w, Player player, Player notificationPlayer, Map> allowedBlocks, Map> forbiddenBlocks, String[] forbiddenSignStrings) { this.w = w; this.player = player; this.notificationPlayer = notificationPlayer; @@ -49,11 +54,11 @@ public DetectionTaskData(World w, Player player, Player notificationPlayer, int[ public DetectionTaskData() { } - public int[] getAllowedBlocks() { + public Map> getAllowedBlocks() { return allowedBlocks; } - public int[] getForbiddenBlocks() { + public Map> getForbiddenBlocks() { return forbiddenBlocks; } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/rotation/RotationTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/rotation/RotationTask.java index 86f372d5f..6166140cd 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/rotation/RotationTask.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/rotation/RotationTask.java @@ -106,9 +106,9 @@ protected void execute() { Block fuelHolder = null; for (MovecraftLocation bTest : oldHitBox) { Block b = getCraft().getW().getBlockAt(bTest.getX(), bTest.getY(), bTest.getZ()); - if (b.getTypeId() == 61) { + if (b.getType() == Material.FURNACE) { InventoryHolder inventoryHolder = (InventoryHolder) b.getState(); - if (inventoryHolder.getInventory().contains(263) || inventoryHolder.getInventory().contains(173)) { + if ((!Settings.IsLegacy ? (inventoryHolder.getInventory().contains(Material.COAL) || inventoryHolder.getInventory().contains(Material.CHARCOAL)) : (inventoryHolder.getInventory().contains(Material.COAL)) || inventoryHolder.getInventory().contains(Material.COAL_BLOCK))) { fuelHolder = b; } } @@ -118,8 +118,8 @@ protected void execute() { failMessage = I18nSupport.getInternationalisedString("Translation - Failed Craft out of fuel"); } else { InventoryHolder inventoryHolder = (InventoryHolder) fuelHolder.getState(); - if (inventoryHolder.getInventory().contains(263)) { - ItemStack iStack = inventoryHolder.getInventory().getItem(inventoryHolder.getInventory().first(263)); + if (inventoryHolder.getInventory().contains(Material.COAL)) { + ItemStack iStack = inventoryHolder.getInventory().getItem(inventoryHolder.getInventory().first(Material.COAL)); int amount = iStack.getAmount(); if (amount == 1) { inventoryHolder.getInventory().remove(iStack); @@ -127,8 +127,8 @@ protected void execute() { iStack.setAmount(amount - 1); } getCraft().setBurningFuel(getCraft().getBurningFuel() + 7.0); - } else { - ItemStack iStack = inventoryHolder.getInventory().getItem(inventoryHolder.getInventory().first(173)); + } else if (inventoryHolder.getInventory().contains(Material.COAL_BLOCK)){ + ItemStack iStack = inventoryHolder.getInventory().getItem(inventoryHolder.getInventory().first(Material.COAL_BLOCK)); int amount = iStack.getAmount(); if (amount == 1) { inventoryHolder.getInventory().remove(iStack); @@ -137,6 +137,15 @@ protected void execute() { } getCraft().setBurningFuel(getCraft().getBurningFuel() + 79.0); + } else { + ItemStack iStack = inventoryHolder.getInventory().getItem(inventoryHolder.getInventory().first(Material.CHARCOAL)); + int amount = iStack.getAmount(); + if (amount == 1) { + inventoryHolder.getInventory().remove(iStack); + } else { + iStack.setAmount(amount - 1); + } + getCraft().setBurningFuel(getCraft().getBurningFuel() + 7.0); } } } else { @@ -178,10 +187,10 @@ protected void execute() { } //TODO: ADD TOWNY - + //TODO: ADD FACTIONS //isTownyBlock(plugLoc,craftPilot); Material newMaterial = newLocation.toBukkit(w).getBlock().getType(); - if ((newMaterial == Material.AIR) || (newMaterial == Material.PISTON_EXTENSION) || craft.getType().getPassthroughBlocks().contains(newMaterial)) { + if ((newMaterial == Material.AIR) || (newMaterial == LegacyUtils.PISTON_EXTENSION) || craft.getType().getPassthroughBlocks().contains(newMaterial)) { //getCraft().getPhaseBlocks().put(newLocation, newMaterial); continue; } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java index 18af4783c..844fc5d35 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java @@ -3,6 +3,7 @@ import net.countercraft.movecraft.Movecraft; import net.countercraft.movecraft.MovecraftLocation; import net.countercraft.movecraft.async.AsyncTask; +import net.countercraft.movecraft.config.Settings; import net.countercraft.movecraft.craft.Craft; import net.countercraft.movecraft.craft.CraftManager; import net.countercraft.movecraft.events.CraftTranslateEvent; @@ -10,6 +11,7 @@ import net.countercraft.movecraft.mapUpdater.update.*; import net.countercraft.movecraft.utils.HashHitBox; import net.countercraft.movecraft.utils.HitBox; +import net.countercraft.movecraft.utils.LegacyUtils; import net.countercraft.movecraft.utils.MutableHitBox; import org.bukkit.Bukkit; import org.bukkit.Location; @@ -29,7 +31,10 @@ import java.util.concurrent.ThreadLocalRandom; public class TranslationTask extends AsyncTask { - private static final int[] FALL_THROUGH_BLOCKS = {0, 8, 9, 10, 11, 31, 37, 38, 39, 40, 50, 51, 55, 59, 63, 65, 68, 69, 70, 72, 75, 76, 77, 78, 83, 85, 93, 94, 111, 141, 142, 143, 171}; + private static final Material[] FALL_THROUGH_BLOCKS = {Material.AIR, Material.WATER, LegacyUtils.STATIONARY_WATER, Material.LAVA, LegacyUtils.STATIONARY_LAVA, LegacyUtils.LONG_GRASS, LegacyUtils.YELLOW_FLOWER, LegacyUtils.RED_ROSE, + Material.BROWN_MUSHROOM, Material.RED_MUSHROOM, Material.TORCH, Material.FIRE, Material.REDSTONE_WIRE, LegacyUtils.CROPS, LegacyUtils.SIGN_POST, Material.LADDER, Material.WALL_SIGN, Material.LEVER, LegacyUtils.STONE_PLATE, LegacyUtils.REDSTONE_TORCH_ON, LegacyUtils.REDSTONE_TORCH_OFF, Material.STONE_BUTTON, + Material.SNOW, LegacyUtils.SUGAR_CANE_BLOCK, LegacyUtils.FENCE, LegacyUtils.DIODE_BLOCK_OFF, LegacyUtils.DIODE_BLOCK_ON, LegacyUtils.WATER_LILY, Material.CARROT, Material.POTATO, LegacyUtils.WOOD_BUTTON, LegacyUtils.CARPET}; + //private static final int[] FALL_THROUGH_BLOCKS = {0, 8, 9, 10, 11, 31, 37, 38, 39, 40, 50, 51, 55, 59, 63, 65, 68, 69, 70, 72, 75, 76, 77, 78, 83, 85, 93, 94, 111, 141, 142, 143, 171}; private int dx, dy, dz; private HashHitBox newHitBox, oldHitBox; @@ -65,7 +70,7 @@ protected void execute() { int testY = minY; while (testY > 0){ testY -= 1; - if (craft.getW().getBlockTypeIdAt(middle.getX(),testY,middle.getZ()) != 0) + if (craft.getW().getBlockAt(middle.getX(),testY,middle.getZ()).getType() != Material.AIR || !Settings.IsLegacy &&(craft.getW().getBlockAt(middle.getX(),testY,middle.getZ()).getType() != Material.CAVE_AIR || craft.getW().getBlockAt(middle.getX(),testY,middle.getZ()).getType() != Material.VOID_AIR)) break; } if (minY - testY > craft.getType().getMaxHeightAboveGround()) { @@ -109,11 +114,28 @@ protected void execute() { return; } + if (Movecraft.getInstance().getWorldGuardPlugin() != null ){ + + } + + if (Movecraft.getInstance().getFactionsPlugin() != null){ + + } + + if (Movecraft.getInstance().getTownyPlugin() != null){ + + } + boolean blockObstructed; if (craft.getSinking()) { - blockObstructed = !(Arrays.binarySearch(FALL_THROUGH_BLOCKS, testMaterial.getId()) >= 0); + blockObstructed = !(Arrays.binarySearch(FALL_THROUGH_BLOCKS, testMaterial) >= 0); } else { - blockObstructed = !craft.getType().getPassthroughBlocks().contains(testMaterial) && !testMaterial.equals(Material.AIR); + if (Settings.IsLegacy) { + blockObstructed = !craft.getType().getPassthroughBlocks().contains(testMaterial) && !testMaterial.equals(Material.AIR); + } else { //1.13 has more than just one air type + blockObstructed = !craft.getType().getPassthroughBlocks().contains(testMaterial) && !testMaterial.equals(Material.AIR) || + !testMaterial.equals(Material.CAVE_AIR) || !testMaterial.equals(Material.VOID_AIR); + } } boolean ignoreBlock = false; @@ -249,7 +271,7 @@ private void fail(String message) { craft.getW().playSound(location, Sound.BLOCK_ANVIL_LAND, 1.0f, 0.25f); //craft.setCurTickCooldown(craft.getType().getCruiseTickCooldown()); } else { - craft.getW().playSound(location, Sound.ENTITY_IRONGOLEM_DEATH, 5.0f, 5.0f); + craft.getW().playSound(location, Settings.IsLegacy ? Sound.ENTITY_IRON_GOLEM_DEATH : LegacyUtils.ENITIY_IRONGOLEM_DEATH, 5.0f, 5.0f); //craft.setCurTickCooldown(craft.getType().getCruiseTickCooldown()); } } @@ -287,13 +309,24 @@ private void captureYield(List harvestedBlocks) { for (MovecraftLocation harvestedBlock : harvestedBlocks) { Block block = craft.getW().getBlockAt(harvestedBlock.getX(), harvestedBlock.getY(), harvestedBlock.getZ()); List drops = new ArrayList<>(block.getDrops()); - //generate seed drops - if (block.getType() == Material.CROPS) { - Random rand = new Random(); - int amount = rand.nextInt(4); - if (amount > 0) { - ItemStack seeds = new ItemStack(Material.SEEDS, amount); - drops.add(seeds); + if (Settings.IsLegacy) { + //generate seed drops + if (block.getType() == LegacyUtils.CROPS) { + Random rand = new Random(); + int amount = rand.nextInt(4); + if (amount > 0) { + ItemStack seeds = new ItemStack(LegacyUtils.SEEDS, amount); + drops.add(seeds); + } + } + } else { + if (block.getType() == Material.WHEAT){ + Random rand = new Random(); + int amount = rand.nextInt(4); + if (amount > 0){ + ItemStack seeds = new ItemStack(Material.WHEAT_SEEDS, amount); + drops.add(seeds); + } } } //get contents of inventories before deposting @@ -358,9 +391,12 @@ private boolean checkFuel(){ Block fuelHolder = null; for (MovecraftLocation bTest : oldHitBox) { Block b = craft.getW().getBlockAt(bTest.getX(), bTest.getY(), bTest.getZ()); - if (b.getTypeId() == 61) { + if (b.getType() == Material.FURNACE) { InventoryHolder inventoryHolder = (InventoryHolder) b.getState(); - if (inventoryHolder.getInventory().contains(263) || inventoryHolder.getInventory().contains(173)) { + if ((!Settings.IsLegacy ? (inventoryHolder.getInventory().contains(Material.COAL) || + inventoryHolder.getInventory().contains(Material.CHARCOAL)) + : (inventoryHolder.getInventory().contains(Material.COAL)) || + inventoryHolder.getInventory().contains(Material.COAL_BLOCK))) { fuelHolder = b; } } @@ -370,8 +406,8 @@ private boolean checkFuel(){ return false; } InventoryHolder inventoryHolder = (InventoryHolder) fuelHolder.getState(); - if (inventoryHolder.getInventory().contains(263)) { - ItemStack iStack = inventoryHolder.getInventory().getItem(inventoryHolder.getInventory().first(263)); + if (inventoryHolder.getInventory().contains(Material.COAL)) { + ItemStack iStack = inventoryHolder.getInventory().getItem(inventoryHolder.getInventory().first(Material.COAL)); int amount = iStack.getAmount(); if (amount == 1) { inventoryHolder.getInventory().remove(iStack); @@ -380,7 +416,7 @@ private boolean checkFuel(){ } craft.setBurningFuel(craft.getBurningFuel() + 7.0); } else { - ItemStack iStack = inventoryHolder.getInventory().getItem(inventoryHolder.getInventory().first(173)); + ItemStack iStack = inventoryHolder.getInventory().getItem(inventoryHolder.getInventory().first(Material.COAL_BLOCK)); int amount = iStack.getAmount(); if (amount == 1) { inventoryHolder.getInventory().remove(iStack); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/AssaultCommand.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/AssaultCommand.java index dbc4012a3..53323a034 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/AssaultCommand.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/AssaultCommand.java @@ -4,11 +4,13 @@ import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.blocks.BaseBlock; import com.sk89q.worldedit.bukkit.selections.CuboidSelection; +import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard; import com.sk89q.worldguard.LocalPlayer; import com.sk89q.worldguard.protection.flags.DefaultFlag; import com.sk89q.worldguard.protection.flags.StateFlag; import com.sk89q.worldguard.protection.regions.ProtectedRegion; import net.countercraft.movecraft.Movecraft; +import net.countercraft.movecraft.MovecraftRepair; import net.countercraft.movecraft.config.Settings; import net.countercraft.movecraft.localisation.I18nSupport; import net.countercraft.movecraft.warfare.assault.Assault; @@ -17,10 +19,6 @@ import net.countercraft.movecraft.warfare.siege.Siege; import org.bukkit.*; import org.bukkit.block.Block; -import org.bukkit.boss.BarColor; -import org.bukkit.boss.BarFlag; -import org.bukkit.boss.BarStyle; -import org.bukkit.boss.BossBar; import org.bukkit.command.Command; import org.bukkit.command.CommandExecutor; import org.bukkit.command.CommandSender; @@ -130,10 +128,10 @@ public boolean onCommand(CommandSender commandSender, Command command, String s, repairStateName += ".schematic"; file = new File(repairStateName); - Vector min = new Vector(aRegion.getMinimumPoint().getBlockX(), aRegion.getMinimumPoint().getBlockY(), aRegion.getMinimumPoint().getBlockZ()); - Vector max = new Vector(aRegion.getMaximumPoint().getBlockX(), aRegion.getMaximumPoint().getBlockY(), aRegion.getMaximumPoint().getBlockZ()); + org.bukkit.util.Vector min = new org.bukkit.util.Vector(aRegion.getMinimumPoint().getBlockX(), aRegion.getMinimumPoint().getBlockY(), aRegion.getMinimumPoint().getBlockZ()); + org.bukkit.util.Vector max = new org.bukkit.util.Vector(aRegion.getMaximumPoint().getBlockX(), aRegion.getMaximumPoint().getBlockY(), aRegion.getMaximumPoint().getBlockZ()); - if (max.subtract(min).getBlockX() > 256) { + /*if (max.subtract(min).getBlockX() > 256) { if (min.getBlockX() < player.getLocation().getBlockX() - 128) { min = min.setX(player.getLocation().getBlockX() - 128); } @@ -148,32 +146,10 @@ public boolean onCommand(CommandSender commandSender, Command command, String s, if (max.getBlockZ() > player.getLocation().getBlockZ() + 128) { max = max.setZ(player.getLocation().getBlockZ() + 128); } - } - - CuboidClipboard clipboard = new CuboidClipboard(max.subtract(min).add(Vector.ONE), min); - CuboidSelection selection = new CuboidSelection(player.getWorld(), min, max); - - for (int x = 0; x < selection.getWidth(); ++x) { - for (int y = 0; y < selection.getHeight(); ++y) { - for (int z = 0; z < selection.getLength(); ++z) { - Vector vector = new Vector(x, y, z); - int bx = selection.getMinimumPoint().getBlockX() + x; - int by = selection.getMinimumPoint().getBlockY() + y; - int bz = selection.getMinimumPoint().getBlockZ() + z; - Block block = player.getWorld().getBlockAt(bx, by, bz); - if (!player.getWorld().isChunkLoaded(bx >> 4, bz >> 4)) - player.getWorld().loadChunk(bx >> 4, bz >> 4); - BaseBlock baseBlock = new BaseBlock(block.getTypeId(), block.getData()); - - clipboard.setBlock(vector, baseBlock); - } - } - } - try { - clipboard.saveSchematic(file); - } catch (Exception e) { - player.sendMessage(MOVECRAFT_COMMAND_PREFIX + I18nSupport.getInternationalisedString("Could not save file")); - e.printStackTrace(); + }*/ + MovecraftRepair movecraftRepair = Movecraft.getInstance().getMovecraftRepair(); + if (!movecraftRepair.saveRegionRepairState(Movecraft.getInstance(), ((Player) commandSender).getWorld(),min, max, aRegion.getId().replaceAll("´\\s+", "_"))){ + player.sendMessage(I18nSupport.getInternationalisedString("Could not save file")); return true; } // } else { @@ -191,8 +167,8 @@ public boolean onCommand(CommandSender commandSender, Command command, String s, final Player taskPlayer = player; final World taskWorld = player.getWorld(); final Long taskMaxDamages = (long) AssaultUtils.getMaxDamages(aRegion); - final Vector taskMin = min; - final Vector taskMax = max; + final org.bukkit.util.Vector taskMin = min; + final org.bukkit.util.Vector taskMax = max; //TODO: Make async new BukkitRunnable() { @Override diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/CraftManager.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/CraftManager.java index 691595bd8..e10306a90 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/CraftManager.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/CraftManager.java @@ -18,7 +18,9 @@ package net.countercraft.movecraft.craft; import net.countercraft.movecraft.Movecraft; +import net.countercraft.movecraft.config.Settings; import net.countercraft.movecraft.localisation.I18nSupport; +import org.bukkit.Material; import org.bukkit.World; import org.bukkit.entity.Player; import org.bukkit.scheduler.BukkitRunnable; @@ -61,16 +63,29 @@ private Set loadCraftTypes(){ File craftsFile = new File(Movecraft.getInstance().getDataFolder().getAbsolutePath() + "/types"); if (craftsFile.mkdirs()) { - Movecraft.getInstance().saveResource("types/airship.craft", false); - Movecraft.getInstance().saveResource("types/airskiff.craft", false); - Movecraft.getInstance().saveResource("types/BigAirship.craft", false); - Movecraft.getInstance().saveResource("types/BigSubAirship.craft", false); - Movecraft.getInstance().saveResource("types/elevator.craft", false); - Movecraft.getInstance().saveResource("types/LaunchTorpedo.craft", false); - Movecraft.getInstance().saveResource("types/Ship.craft", false); - Movecraft.getInstance().saveResource("types/SubAirship.craft", false); - Movecraft.getInstance().saveResource("types/Submarine.craft", false); - Movecraft.getInstance().saveResource("types/Turret.craft", false); + if (Settings.IsLegacy) { //save legacy craft files if server version is 1.12.2 or below + Movecraft.getInstance().saveResource("types/legacy/airship.craft", false); + Movecraft.getInstance().saveResource("types/legacy/airskiff.craft", false); + Movecraft.getInstance().saveResource("types/legacy/BigAirship.craft", false); + Movecraft.getInstance().saveResource("types/legacy/BigSubAirship.craft", false); + Movecraft.getInstance().saveResource("types/legacy/elevator.craft", false); + Movecraft.getInstance().saveResource("types/legacy/LaunchTorpedo.craft", false); + Movecraft.getInstance().saveResource("types/legacy/Ship.craft", false); + Movecraft.getInstance().saveResource("types/legacy/SubAirship.craft", false); + Movecraft.getInstance().saveResource("types/legacy/Submarine.craft", false); + Movecraft.getInstance().saveResource("types/legacy/Turret.craft", false); + } else { //if 1.13 and higher, save 1.13 files + Movecraft.getInstance().saveResource("types/airship.craft", false); + Movecraft.getInstance().saveResource("types/airskiff.craft", false); + Movecraft.getInstance().saveResource("types/BigAirship.craft", false); + Movecraft.getInstance().saveResource("types/BigSubAirship.craft", false); + Movecraft.getInstance().saveResource("types/elevator.craft", false); + Movecraft.getInstance().saveResource("types/LaunchTorpedo.craft", false); + Movecraft.getInstance().saveResource("types/Ship.craft", false); + Movecraft.getInstance().saveResource("types/SubAirship.craft", false); + Movecraft.getInstance().saveResource("types/Submarine.craft", false); + Movecraft.getInstance().saveResource("types/Turret.craft", false); + } } Set craftTypes = new HashSet<>(); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/factions/FactionsCompatManager.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/factions/FactionsCompatManager.java new file mode 100644 index 000000000..92af8331a --- /dev/null +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/factions/FactionsCompatManager.java @@ -0,0 +1,21 @@ +package net.countercraft.movecraft.factions; + +import com.massivecraft.factions.Factions; +import com.massivecraft.factions.entity.MPlayer; +import net.countercraft.movecraft.Movecraft; +import net.countercraft.movecraft.events.CraftTranslateEvent; +import org.bukkit.entity.Player; +import org.bukkit.event.Listener; + +public class FactionsCompatManager implements Listener { + + public void onCraftTranslate(CraftTranslateEvent event){ + if (Movecraft.getInstance().getFactionsPlugin() == null){ + return; + } + Factions factions = Movecraft.getInstance().getFactionsPlugin(); + Player player = event.getCraft().getNotificationPlayer(); + MPlayer mPlayer = MPlayer.get(player); + + } +} diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/BlockListener.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/BlockListener.java index 7e21d9948..bbb5fe25f 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/BlockListener.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/BlockListener.java @@ -21,6 +21,7 @@ import com.sk89q.worldguard.protection.ApplicableRegionSet; import com.sk89q.worldguard.protection.flags.DefaultFlag; import net.countercraft.movecraft.Movecraft; +import net.countercraft.movecraft.utils.LegacyUtils; import net.countercraft.movecraft.utils.MathUtils; import net.countercraft.movecraft.MovecraftLocation; import net.countercraft.movecraft.craft.Craft; @@ -28,6 +29,7 @@ import net.countercraft.movecraft.craft.CraftManager; import net.countercraft.movecraft.localisation.I18nSupport; import net.countercraft.movecraft.warfare.assault.Assault; +import net.countercraft.movecraft.warfare.assault.AssaultUtils; import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.Location; @@ -65,13 +67,13 @@ public class BlockListener implements Listener { - final int[] fragileBlocks = new int[]{26, 34, 50, 55, 63, 64, 65, 68, 69, 70, 71, 72, 75, 76, 77, 93, 94, 96, 131, 132, 143, 147, 148, 149, 150, 151, 171, 323, 324, 330, 331, 356, 404}; - private long lastDamagesUpdate = 0; + + @EventHandler public void onBlockPlace(final BlockPlaceEvent e) { if (!Settings.RestrictSiBsToRegions || - e.getBlockPlaced().getTypeId() != 54 || + e.getBlockPlaced().getType() != Material.CHEST || !e.getItemInHand().hasItemMeta() || !e.getItemInHand().getItemMeta().hasLore()) { return; @@ -164,8 +166,9 @@ public void onRedstoneEvent(BlockRedstoneEvent event) { for (Craft tcraft : CraftManager.getInstance().getCraftsInWorld(block.getWorld())) { MovecraftLocation mloc = new MovecraftLocation(block.getX(), block.getY(), block.getZ()); if (MathUtils.locIsNearCraftFast(tcraft, mloc) && - tcraft.getCruising() && (block.getTypeId() == 29 || - block.getTypeId() == 33 || block.getTypeId() == 23 && + tcraft.getCruising() && (block.getType() == LegacyUtils.PISTON_STICKY_BASE || + block.getType() == LegacyUtils.PISTON_BASE || block.getType() == Material.DISPENSER || block.getType() == Material.PISTON || + block.getType() == Material.STICKY_PISTON && !tcraft.isNotProcessing())) { event.setNewCurrent(event.getOldCurrent()); // don't allow piston movement on cruising crafts return; @@ -213,27 +216,33 @@ public void onPhysics(BlockPhysicsEvent event) { Block block = event.getBlock(); - final int[] fragileBlocks = new int[]{26, 34, 50, 55, 63, 64, 65, 68, 69, 70, 71, 72, 75, 76, 77, 93, 94, 96, 131, 132, 143, 147, 148, 149, 150, 151, 171, 193, 194, 195, 196, 197}; + final Material[] legacyFragileBlocks = new Material[]{LegacyUtils.BED_BLOCK, LegacyUtils.PISTON_EXTENSION, Material.TORCH, Material.REDSTONE_WIRE, LegacyUtils.SIGN_POST, LegacyUtils.WOOD_DOOR, Material.LADDER, Material.WALL_SIGN, Material.LEVER, LegacyUtils.STONE_PLATE, LegacyUtils.IRON_DOOR_BLOCK, LegacyUtils.WOOD_PLATE, LegacyUtils.REDSTONE_TORCH_OFF, LegacyUtils.REDSTONE_TORCH_ON, Material.STONE_BUTTON, LegacyUtils.DIODE_BLOCK_OFF, LegacyUtils.DIODE_BLOCK_ON, LegacyUtils.TRAP_DOOR, Material.TRIPWIRE_HOOK, + Material.TRIPWIRE, LegacyUtils.WOOD_BUTTON, LegacyUtils.GOLD_PLATE, LegacyUtils.IRON_PLATE, LegacyUtils.REDSTONE_COMPARATOR_OFF, LegacyUtils.REDSTONE_COMPARATOR_ON, Material.DAYLIGHT_DETECTOR, LegacyUtils.CARPET, LegacyUtils.DAYLIGHT_DETECTOR_INVERTED, Material.SPRUCE_DOOR, Material.BIRCH_DOOR, Material.JUNGLE_DOOR, Material.ACACIA_DOOR, Material.DARK_OAK_DOOR}; CraftManager.getInstance().getCraftsInWorld(block.getWorld()); for (Craft tcraft : CraftManager.getInstance().getCraftsInWorld(block.getWorld())) { MovecraftLocation mloc = new MovecraftLocation(block.getX(), block.getY(), block.getZ()); if (!MathUtils.locIsNearCraftFast(tcraft, mloc)) { continue; } - if (Arrays.binarySearch(fragileBlocks, block.getTypeId()) >= 0) { - MaterialData m = block.getState().getData(); - BlockFace face = BlockFace.DOWN; - boolean faceAlwaysDown = false; - if (block.getTypeId() == 149 || block.getTypeId() == 150 || block.getTypeId() == 93 || block.getTypeId() == 94) - faceAlwaysDown = true; - if (m instanceof Attachable && !faceAlwaysDown) { - face = ((Attachable) m).getAttachedFace(); - } - if (!event.getBlock().getRelative(face).getType().isSolid()) { + + if (Settings.IsLegacy) { + if (Arrays.binarySearch(legacyFragileBlocks, block.getType()) >= 0) { + MaterialData m = block.getState().getData(); + BlockFace face = BlockFace.DOWN; + boolean faceAlwaysDown = false; + if (block.getType() == LegacyUtils.REDSTONE_COMPARATOR_ON || block.getType() == LegacyUtils.REDSTONE_COMPARATOR_OFF || block.getType() == LegacyUtils.DIODE_BLOCK_ON|| block.getType() == LegacyUtils.DIODE_BLOCK_OFF) + faceAlwaysDown = true; + if (m instanceof Attachable && !faceAlwaysDown) { + face = ((Attachable) m).getAttachedFace(); + } + if (!event.getBlock().getRelative(face).getType().isSolid()) { // if(event.getEventName().equals("BlockPhysicsEvent")) { - event.setCancelled(true); - return; + event.setCancelled(true); + return; + } } + } else { + } } } @@ -306,11 +315,11 @@ public void explodeEvent(EntityExplodeEvent e) { } if (Settings.DurabilityOverride != null) { - e.blockList().removeIf(b -> Settings.DurabilityOverride.containsKey(b.getTypeId()) && + e.blockList().removeIf(b -> Settings.DurabilityOverride.containsKey(b.getType()) && (new Random(b.getX() + b.getY() + b.getZ() + (System.currentTimeMillis() >> 12))) - .nextInt(100) < Settings.DurabilityOverride.get(b.getTypeId())); + .nextInt(100) < Settings.DurabilityOverride.get(b.getType())); } - processAssault(e); + AssaultUtils.processAssault(e); if (e.getEntity() == null) return; for (Player p : e.getEntity().getWorld().getPlayers()) { @@ -330,91 +339,27 @@ public void explodeEvent(EntityExplodeEvent e) { new BukkitRunnable() { @Override public void run() { - fp.sendBlockChange(loc, 89, (byte) 0); + fp.sendBlockChange(loc, Material.GLOWSTONE, (byte) 0); } }.runTaskLater(Movecraft.getInstance(), 5); // then remove it new BukkitRunnable() { @Override public void run() { - fp.sendBlockChange(loc, 0, (byte) 0); + fp.sendBlockChange(loc, Material.AIR, (byte) 0); } }.runTaskLater(Movecraft.getInstance(), 160); } } } - } - //TODO: move to Warfare plugin - private void processAssault(EntityExplodeEvent e){ - List assaults = Movecraft.getInstance().getAssaultManager() != null ? Movecraft.getInstance().getAssaultManager().getAssaults() : null; - if (assaults == null || assaults.size() == 0) { - return; - } - WorldGuardPlugin worldGuard = Movecraft.getInstance().getWorldGuardPlugin(); - for (final Assault assault : assaults) { - Iterator i = e.blockList().iterator(); - while (i.hasNext()) { - Block b = i.next(); - if (b.getWorld() != assault.getWorld()) - continue; - ApplicableRegionSet regions = worldGuard.getRegionManager(b.getWorld()).getApplicableRegions(b.getLocation()); - boolean isInAssaultRegion = false; - for (com.sk89q.worldguard.protection.regions.ProtectedRegion tregion : regions.getRegions()) { - if (assault.getRegionName().equals(tregion.getId())) { - isInAssaultRegion = true; - } - } - if (!isInAssaultRegion) - continue; - // first see if it is outside the destroyable area - com.sk89q.worldedit.Vector min = assault.getMinPos(); - com.sk89q.worldedit.Vector max = assault.getMaxPos(); - - if (b.getLocation().getBlockX() < min.getBlockX() || - b.getLocation().getBlockX() > max.getBlockX() || - b.getLocation().getBlockZ() < min.getBlockZ() || - b.getLocation().getBlockZ() > max.getBlockZ() || - !Settings.AssaultDestroyableBlocks.contains(b.getTypeId()) || - Arrays.binarySearch(fragileBlocks, b.getRelative(BlockFace.SOUTH).getTypeId()) >= 0 || - Arrays.binarySearch(fragileBlocks, b.getRelative(BlockFace.DOWN).getTypeId()) >= 0 || - Arrays.binarySearch(fragileBlocks, b.getRelative(BlockFace.UP).getTypeId()) >= 0 || - Arrays.binarySearch(fragileBlocks, b.getRelative(BlockFace.EAST).getTypeId()) >= 0 || - Arrays.binarySearch(fragileBlocks, b.getRelative(BlockFace.WEST).getTypeId()) >= 0 || - Arrays.binarySearch(fragileBlocks, b.getRelative(BlockFace.NORTH).getTypeId()) >= 0) { - i.remove(); - } - - - // whether or not you actually destroyed the block, add to damages - long damages = assault.getDamages() + Settings.AssaultDamagesPerBlock; - //if (damages < assault.getMaxDamages()) { - assault.setDamages(damages); - //} + for (Block b : e.blockList()){ + if (b.getType() == Material.WALL_SIGN || b.getType() == (Settings.IsLegacy ? LegacyUtils.SIGN_POST : Material.SIGN)){ + Sign sign = (Sign) b.getState(); + if (sign.getLine(0).equals(ChatColor.RED + "REGION DAMAGED!")){ - // notify nearby players of the damages, do this 1 second later so all damages from this volley will be included - if (System.currentTimeMillis() < lastDamagesUpdate + 4000) { - continue; } - final Location floc = b.getLocation(); - final World fworld = b.getWorld(); - new BukkitRunnable() { - @Override - public void run() { - long fdamages = assault.getDamages(); - for (Player p : fworld.getPlayers()) { - if (Math.round(p.getLocation().getBlockX() / 1000.0) == Math.round(floc.getBlockX() / 1000.0) && - Math.round(p.getLocation().getBlockZ() / 1000.0) == Math.round(floc.getBlockZ() / 1000.0)) { - p.sendMessage("Damages: " + fdamages); - - } - } - } - }.runTaskLater(Movecraft.getInstance(), 20); - lastDamagesUpdate = System.currentTimeMillis(); - } } - } } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/InteractListener.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/InteractListener.java index d7d163b65..a1d19b3cc 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/InteractListener.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/InteractListener.java @@ -17,6 +17,7 @@ package net.countercraft.movecraft.listener; +import net.countercraft.movecraft.utils.LegacyUtils; import net.countercraft.movecraft.utils.MathUtils; import net.countercraft.movecraft.craft.Craft; import net.countercraft.movecraft.config.Settings; @@ -28,27 +29,38 @@ import org.bukkit.event.Listener; import org.bukkit.event.block.Action; import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.material.Button; +import java.util.Arrays; import java.util.HashMap; import java.util.Map; public final class InteractListener implements Listener { private static final Map timeMap = new HashMap<>(); - + final Material[] buttons = !Settings.IsLegacy ? new Material[] {Material.STONE_BUTTON, Material.BIRCH_BUTTON, Material.ACACIA_BUTTON, Material.DARK_OAK_BUTTON, Material.JUNGLE_BUTTON, Material.OAK_BUTTON, Material.SPRUCE_BUTTON}: new Material[]{}; @EventHandler public final void onPlayerInteract(PlayerInteractEvent event) { if (event.getAction() != Action.RIGHT_CLICK_BLOCK && event.getAction() != Action.LEFT_CLICK_BLOCK) { return; } Material m = event.getClickedBlock().getType(); - if (!m.equals(Material.WOOD_BUTTON) && !m.equals(Material.STONE_BUTTON)) { + if (Settings.IsLegacy ? (!m.equals(LegacyUtils.WOOD_BUTTON) && !m.equals(Material.STONE_BUTTON)) : Arrays.binarySearch(buttons, m) < 0) { return; } if (event.getAction() != Action.LEFT_CLICK_BLOCK) { return; } // if they left click a button which is pressed, unpress it - if (event.getClickedBlock().getData() >= 8) { - event.getClickedBlock().setData((byte) (event.getClickedBlock().getData() - 8)); + if (Settings.IsLegacy) { + if (event.getClickedBlock().getData() >= 8) { + LegacyUtils.setData(event.getClickedBlock(), (byte) (event.getClickedBlock().getData() - 8)); + } + } else { + if (event.getClickedBlock().getState() instanceof Button){ + Button button = (Button) event.getClickedBlock().getState(); + if (button.isPowered()){ + button.setPowered(false); + } + } } } @@ -69,7 +81,7 @@ public void onPlayerInteractStick(PlayerInteractEvent event) { if (event.getAction() == Action.RIGHT_CLICK_AIR || event.getAction() == Action.RIGHT_CLICK_BLOCK) { Craft craft = CraftManager.getInstance().getCraftByPlayer(event.getPlayer()); - if (event.getItem() == null || event.getItem().getTypeId() != Settings.PilotTool) { + if (event.getItem() == null || event.getItem().getType() != Settings.PilotTool) { return; } event.setCancelled(true); @@ -136,7 +148,7 @@ public void onPlayerInteractStick(PlayerInteractEvent event) { return; } if (event.getAction() == Action.LEFT_CLICK_AIR || event.getAction() == Action.LEFT_CLICK_BLOCK) { - if (event.getItem() == null || event.getItem().getTypeId() != Settings.PilotTool) { + if (event.getItem() == null || event.getItem().getType() != Settings.PilotTool) { return; } Craft craft = CraftManager.getInstance().getCraftByPlayer(event.getPlayer()); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/PlayerListener.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/PlayerListener.java index 77881ecc7..9c030ecab 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/PlayerListener.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/PlayerListener.java @@ -17,6 +17,8 @@ package net.countercraft.movecraft.listener; +import net.countercraft.movecraft.Movecraft; +import net.countercraft.movecraft.repair.Repair; import net.countercraft.movecraft.utils.HitBox; import net.countercraft.movecraft.utils.MathUtils; import net.countercraft.movecraft.MovecraftLocation; @@ -28,6 +30,7 @@ import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; import org.bukkit.event.entity.EntityDamageByEntityEvent; +import org.bukkit.event.player.PlayerJoinEvent; import org.bukkit.event.player.PlayerMoveEvent; import org.bukkit.event.player.PlayerQuitEvent; @@ -47,7 +50,7 @@ private String checkCraftBorders(Craft craft) { z = block.getZ(); MovecraftLocation test = new MovecraftLocation(x, y, z); if (!craft.getHitBox().contains(test)) - if ((Arrays.binarySearch(craft.getType().getAllowedBlocks(), craft.getW().getBlockTypeIdAt(x, y, z)) >= 0) || (Arrays.binarySearch(craft.getType().getAllowedBlocks(), (craft.getW().getBlockTypeIdAt(x, y, z) << 4) + craft.getW().getBlockAt(x, y, z).getData() + 10000) >= 0)) { + if (craft.getType().getAllowedBlocks().containsKey(craft.getW().getBlockAt(x, y, z).getType()) || craft.getType().getAllowedBlocks().get(craft.getW().getBlockAt(x, y, z).getType()).contains(craft.getW().getBlockAt(x, y, z).getData())) { ret = "@ " + x + "," + y + "," + z; } x = block.getX() - 1; @@ -55,7 +58,7 @@ private String checkCraftBorders(Craft craft) { z = block.getZ(); test = new MovecraftLocation(x, y, z); if (!craftBlocks.contains(test)) - if ((Arrays.binarySearch(craft.getType().getAllowedBlocks(), craft.getW().getBlockTypeIdAt(x, y, z)) >= 0) || (Arrays.binarySearch(craft.getType().getAllowedBlocks(), (craft.getW().getBlockTypeIdAt(x, y, z) << 4) + craft.getW().getBlockAt(x, y, z).getData() + 10000) >= 0)) { + if (craft.getType().getAllowedBlocks().containsKey(craft.getW().getBlockAt(x, y, z).getType()) || craft.getType().getAllowedBlocks().get(craft.getW().getBlockAt(x, y, z).getType()).contains(craft.getW().getBlockAt(x, y, z).getData())) { ret = "@ " + x + "," + y + "," + z; } x = block.getX(); @@ -63,7 +66,7 @@ private String checkCraftBorders(Craft craft) { z = block.getZ(); test = new MovecraftLocation(x, y, z); if (!craftBlocks.contains(test)) - if ((Arrays.binarySearch(craft.getType().getAllowedBlocks(), craft.getW().getBlockTypeIdAt(x, y, z)) >= 0) || (Arrays.binarySearch(craft.getType().getAllowedBlocks(), (craft.getW().getBlockTypeIdAt(x, y, z) << 4) + craft.getW().getBlockAt(x, y, z).getData() + 10000) >= 0)) { + if (craft.getType().getAllowedBlocks().containsKey(craft.getW().getBlockAt(x, y, z).getType()) || craft.getType().getAllowedBlocks().get(craft.getW().getBlockAt(x, y, z).getType()).contains(craft.getW().getBlockAt(x, y, z).getData())) { ret = "@ " + x + "," + y + "," + z; } x = block.getX(); @@ -71,7 +74,7 @@ private String checkCraftBorders(Craft craft) { z = block.getZ(); test = new MovecraftLocation(x, y, z); if (!craftBlocks.contains(test)) - if ((Arrays.binarySearch(craft.getType().getAllowedBlocks(), craft.getW().getBlockTypeIdAt(x, y, z)) >= 0) || (Arrays.binarySearch(craft.getType().getAllowedBlocks(), (craft.getW().getBlockTypeIdAt(x, y, z) << 4) + craft.getW().getBlockAt(x, y, z).getData() + 10000) >= 0)) { + if (craft.getType().getAllowedBlocks().containsKey(craft.getW().getBlockAt(x, y, z).getType()) || craft.getType().getAllowedBlocks().get(craft.getW().getBlockAt(x, y, z).getType()).contains(craft.getW().getBlockAt(x, y, z).getData())) { ret = "@ " + x + "," + y + "," + z; } x = block.getX(); @@ -79,7 +82,7 @@ private String checkCraftBorders(Craft craft) { z = block.getZ() + 1; test = new MovecraftLocation(x, y, z); if (!craftBlocks.contains(test)) - if ((Arrays.binarySearch(craft.getType().getAllowedBlocks(), craft.getW().getBlockTypeIdAt(x, y, z)) >= 0) || (Arrays.binarySearch(craft.getType().getAllowedBlocks(), (craft.getW().getBlockTypeIdAt(x, y, z) << 4) + craft.getW().getBlockAt(x, y, z).getData() + 10000) >= 0)) { + if (craft.getType().getAllowedBlocks().containsKey(craft.getW().getBlockAt(x, y, z).getType()) || craft.getType().getAllowedBlocks().get(craft.getW().getBlockAt(x, y, z).getType()).contains(craft.getW().getBlockAt(x, y, z).getData())) { ret = "@ " + x + "," + y + "," + z; } x = block.getX(); @@ -87,7 +90,7 @@ private String checkCraftBorders(Craft craft) { z = block.getZ() + 1; test = new MovecraftLocation(x, y, z); if (!craftBlocks.contains(test)) - if ((Arrays.binarySearch(craft.getType().getAllowedBlocks(), craft.getW().getBlockTypeIdAt(x, y, z)) >= 0) || (Arrays.binarySearch(craft.getType().getAllowedBlocks(), (craft.getW().getBlockTypeIdAt(x, y, z) << 4) + craft.getW().getBlockAt(x, y, z).getData() + 10000) >= 0)) { + if (craft.getType().getAllowedBlocks().containsKey(craft.getW().getBlockAt(x, y, z).getType()) || craft.getType().getAllowedBlocks().get(craft.getW().getBlockAt(x, y, z).getType()).contains(craft.getW().getBlockAt(x, y, z).getData())) { ret = "@ " + x + "," + y + "," + z; } x = block.getX() + 1; @@ -95,7 +98,7 @@ private String checkCraftBorders(Craft craft) { z = block.getZ(); test = new MovecraftLocation(x, y, z); if (!craftBlocks.contains(test)) - if ((Arrays.binarySearch(craft.getType().getAllowedBlocks(), craft.getW().getBlockTypeIdAt(x, y, z)) >= 0) || (Arrays.binarySearch(craft.getType().getAllowedBlocks(), (craft.getW().getBlockTypeIdAt(x, y, z) << 4) + craft.getW().getBlockAt(x, y, z).getData() + 10000) >= 0)) { + if (craft.getType().getAllowedBlocks().containsKey(craft.getW().getBlockAt(x, y, z).getType()) || craft.getType().getAllowedBlocks().get(craft.getW().getBlockAt(x, y, z).getType()).contains(craft.getW().getBlockAt(x, y, z).getData())) { ret = "@ " + x + "," + y + "," + z; } x = block.getX() + 1; @@ -103,7 +106,7 @@ private String checkCraftBorders(Craft craft) { z = block.getZ(); test = new MovecraftLocation(x, y, z); if (!craftBlocks.contains(test)) - if ((Arrays.binarySearch(craft.getType().getAllowedBlocks(), craft.getW().getBlockTypeIdAt(x, y, z)) >= 0) || (Arrays.binarySearch(craft.getType().getAllowedBlocks(), (craft.getW().getBlockTypeIdAt(x, y, z) << 4) + craft.getW().getBlockAt(x, y, z).getData() + 10000) >= 0)) { + if (craft.getType().getAllowedBlocks().containsKey(craft.getW().getBlockAt(x, y, z).getType()) || craft.getType().getAllowedBlocks().get(craft.getW().getBlockAt(x, y, z).getType()).contains(craft.getW().getBlockAt(x, y, z).getData())) { ret = "@ " + x + "," + y + "," + z; } x = block.getX() - 1; @@ -111,7 +114,7 @@ private String checkCraftBorders(Craft craft) { z = block.getZ(); test = new MovecraftLocation(x, y, z); if (!craftBlocks.contains(test)) - if ((Arrays.binarySearch(craft.getType().getAllowedBlocks(), craft.getW().getBlockTypeIdAt(x, y, z)) >= 0) || (Arrays.binarySearch(craft.getType().getAllowedBlocks(), (craft.getW().getBlockTypeIdAt(x, y, z) << 4) + craft.getW().getBlockAt(x, y, z).getData() + 10000) >= 0)) { + if (craft.getType().getAllowedBlocks().containsKey(craft.getW().getBlockAt(x, y, z).getType()) || craft.getType().getAllowedBlocks().get(craft.getW().getBlockAt(x, y, z).getType()).contains(craft.getW().getBlockAt(x, y, z).getData())) { ret = "@ " + x + "," + y + "," + z; } x = block.getX() - 1; @@ -119,7 +122,7 @@ private String checkCraftBorders(Craft craft) { z = block.getZ(); test = new MovecraftLocation(x, y, z); if (!craftBlocks.contains(test)) - if ((Arrays.binarySearch(craft.getType().getAllowedBlocks(), craft.getW().getBlockTypeIdAt(x, y, z)) >= 0) || (Arrays.binarySearch(craft.getType().getAllowedBlocks(), (craft.getW().getBlockTypeIdAt(x, y, z) << 4) + craft.getW().getBlockAt(x, y, z).getData() + 10000) >= 0)) { + if (craft.getType().getAllowedBlocks().containsKey(craft.getW().getBlockAt(x, y, z).getType()) || craft.getType().getAllowedBlocks().get(craft.getW().getBlockAt(x, y, z).getType()).contains(craft.getW().getBlockAt(x, y, z).getData())) { ret = "@ " + x + "," + y + "," + z; } x = block.getX(); @@ -127,7 +130,7 @@ private String checkCraftBorders(Craft craft) { z = block.getZ() + 1; test = new MovecraftLocation(x, y, z); if (!craftBlocks.contains(test)) - if ((Arrays.binarySearch(craft.getType().getAllowedBlocks(), craft.getW().getBlockTypeIdAt(x, y, z)) >= 0) || (Arrays.binarySearch(craft.getType().getAllowedBlocks(), (craft.getW().getBlockTypeIdAt(x, y, z) << 4) + craft.getW().getBlockAt(x, y, z).getData() + 10000) >= 0)) { + if (craft.getType().getAllowedBlocks().containsKey(craft.getW().getBlockAt(x, y, z).getType()) || craft.getType().getAllowedBlocks().get(craft.getW().getBlockAt(x, y, z).getType()).contains(craft.getW().getBlockAt(x, y, z).getData())) { ret = "@ " + x + "," + y + "," + z; } x = block.getX(); @@ -135,7 +138,7 @@ private String checkCraftBorders(Craft craft) { z = block.getZ() + 1; test = new MovecraftLocation(x, y, z); if (!craftBlocks.contains(test)) - if ((Arrays.binarySearch(craft.getType().getAllowedBlocks(), craft.getW().getBlockTypeIdAt(x, y, z)) >= 0) || (Arrays.binarySearch(craft.getType().getAllowedBlocks(), (craft.getW().getBlockTypeIdAt(x, y, z) << 4) + craft.getW().getBlockAt(x, y, z).getData() + 10000) >= 0)) { + if (craft.getType().getAllowedBlocks().containsKey(craft.getW().getBlockAt(x, y, z).getType()) || craft.getType().getAllowedBlocks().get(craft.getW().getBlockAt(x, y, z).getType()).contains(craft.getW().getBlockAt(x, y, z).getData())) { ret = "@ " + x + "," + y + "," + z; } x = block.getX(); @@ -143,7 +146,7 @@ private String checkCraftBorders(Craft craft) { z = block.getZ() - 1; test = new MovecraftLocation(x, y, z); if (!craftBlocks.contains(test)) - if ((Arrays.binarySearch(craft.getType().getAllowedBlocks(), craft.getW().getBlockTypeIdAt(x, y, z)) >= 0) || (Arrays.binarySearch(craft.getType().getAllowedBlocks(), (craft.getW().getBlockTypeIdAt(x, y, z) << 4) + craft.getW().getBlockAt(x, y, z).getData() + 10000) >= 0)) { + if (craft.getType().getAllowedBlocks().containsKey(craft.getW().getBlockAt(x, y, z).getType()) || craft.getType().getAllowedBlocks().get(craft.getW().getBlockAt(x, y, z).getType()).contains(craft.getW().getBlockAt(x, y, z).getData())) { ret = "@ " + x + "," + y + "," + z; } x = block.getX(); @@ -151,7 +154,7 @@ private String checkCraftBorders(Craft craft) { z = block.getZ() - 1; test = new MovecraftLocation(x, y, z); if (!craftBlocks.contains(test)) - if ((Arrays.binarySearch(craft.getType().getAllowedBlocks(), craft.getW().getBlockTypeIdAt(x, y, z)) >= 0) || (Arrays.binarySearch(craft.getType().getAllowedBlocks(), (craft.getW().getBlockTypeIdAt(x, y, z) << 4) + craft.getW().getBlockAt(x, y, z).getData() + 10000) >= 0)) { + if (craft.getType().getAllowedBlocks().containsKey(craft.getW().getBlockAt(x, y, z).getType()) || craft.getType().getAllowedBlocks().get(craft.getW().getBlockAt(x, y, z).getType()).contains(craft.getW().getBlockAt(x, y, z).getData())) { ret = "@ " + x + "," + y + "," + z; } } @@ -163,6 +166,8 @@ public void onPLayerLogout(PlayerQuitEvent e) { CraftManager.getInstance().removeCraftByPlayer(e.getPlayer()); } + + @EventHandler public void onPlayerDeath(EntityDamageByEntityEvent e) { // changed to death so when you shoot up an airship and hit the pilot, it still sinks if (e instanceof Player) { diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/WorldEditInteractListener.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/WorldEditInteractListener.java deleted file mode 100644 index cc6114eba..000000000 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/WorldEditInteractListener.java +++ /dev/null @@ -1,728 +0,0 @@ -/* - * This file is part of Movecraft. - * - * Movecraft is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Movecraft is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Movecraft. If not, see . - */ - -package net.countercraft.movecraft.listener; - -import com.sk89q.jnbt.StringTag; -import com.sk89q.jnbt.Tag; -import com.sk89q.worldedit.CuboidClipboard; -import com.sk89q.worldedit.LocalWorld; -import com.sk89q.worldedit.Vector; -import com.sk89q.worldedit.blocks.BaseBlock; -import com.sk89q.worldedit.blocks.BaseItemStack; -import com.sk89q.worldedit.blocks.DispenserBlock; -import com.sk89q.worldedit.blocks.SignBlock; -import com.sk89q.worldedit.bukkit.BukkitUtil; -import com.sk89q.worldedit.data.DataException; -import com.sk89q.worldedit.schematic.SchematicFormat; -import com.sk89q.worldguard.protection.regions.ProtectedRegion; -import net.countercraft.movecraft.Movecraft; -import net.countercraft.movecraft.MovecraftLocation; -import net.countercraft.movecraft.config.Settings; -import net.countercraft.movecraft.craft.Craft; -import net.countercraft.movecraft.craft.CraftManager; -import net.countercraft.movecraft.localisation.I18nSupport; -import net.countercraft.movecraft.mapUpdater.MapUpdateManager; -import net.countercraft.movecraft.mapUpdater.update.UpdateCommand; -import net.countercraft.movecraft.mapUpdater.update.WorldEditUpdateCommand; -import net.countercraft.movecraft.utils.HashHitBox; -import org.bukkit.*; -import org.bukkit.block.Block; -import org.bukkit.block.BlockState; -import org.bukkit.block.Dispenser; -import org.bukkit.block.Sign; -import org.bukkit.entity.Player; -import org.bukkit.event.EventHandler; -import org.bukkit.event.Listener; -import org.bukkit.event.block.Action; -import org.bukkit.event.player.PlayerInteractEvent; -import org.bukkit.inventory.InventoryHolder; -import org.bukkit.inventory.ItemStack; -import org.bukkit.scheduler.BukkitRunnable; - -import java.io.File; -import java.io.IOException; -import java.util.*; - -//import com.sk89q.worldedit.blocks.BaseBlock; -//import com.sk89q.worldedit.world.DataException; - -public class WorldEditInteractListener implements Listener { - private static final Map timeMap = new HashMap<>(); - private static final Map repairRightClickTimeMap = new HashMap<>(); - - public boolean repairRegion(World w, String regionName) { - if (w == null || regionName == null) - return false; - String repairStateName = Movecraft.getInstance().getDataFolder().getAbsolutePath() + "/RegionRepairStates"; - repairStateName += "/"; - repairStateName += regionName.replaceAll("\\s+", "_"); - repairStateName += ".schematic"; - File file = new File(repairStateName); - if (!file.exists()) { - return false; - } - SchematicFormat sf = SchematicFormat.getFormat(file); - CuboidClipboard cc; - try { - cc = sf.load(file); - } catch (DataException | IOException e) { - e.printStackTrace(); - return false; - } - int minx = cc.getOrigin().getBlockX(); - int miny = cc.getOrigin().getBlockY(); - int minz = cc.getOrigin().getBlockZ(); - int maxx = minx + cc.getWidth(); - int maxy = miny + cc.getHeight(); - int maxz = minz + cc.getLength(); - for (int x = minx; x < maxx; x++) { - for (int y = miny; y < maxy; y++) { - for (int z = minz; z < maxz; z++) { - Vector ccloc = new Vector(x - minx, y - miny, z - minz); - BaseBlock bb = cc.getBlock(ccloc); - if (!bb.isAir()) { // most blocks will be air, quickly move on to the next. This loop will run 16 million times, needs to be fast - if (Settings.AssaultDestroyableBlocks.contains(bb.getId())) { - if (!w.getChunkAt(x >> 4, z >> 4).isLoaded()) - w.loadChunk(x >> 4, z >> 4); - if (w.getBlockAt(x, y, z).isEmpty() || w.getBlockAt(x, y, z).isLiquid()) { - MovecraftLocation moveloc = new MovecraftLocation(x, y, z); - WorldEditUpdateCommand updateCommand = new WorldEditUpdateCommand(bb, w, moveloc, Material.getMaterial(bb.getType()), (byte) bb.getData()); - MapUpdateManager.getInstance().scheduleUpdate(updateCommand); - } - } - } - } - } - } - - return true; - } - - @EventHandler - public void WEOnPlayerInteract(PlayerInteractEvent event) { - - if (event.getAction() == Action.RIGHT_CLICK_BLOCK || event.getAction() == Action.LEFT_CLICK_BLOCK) { - Material m = event.getClickedBlock().getType(); - if (m.equals(Material.SIGN_POST) || m.equals(Material.WALL_SIGN)) { - Sign sign = (Sign) event.getClickedBlock().getState(); - String signText = ChatColor.stripColor(sign.getLine(0)); - - if (signText == null) { - return; - } - } - } - if (event.getAction() == Action.RIGHT_CLICK_BLOCK) { - Material m = event.getClickedBlock().getType(); - if (m.equals(Material.SIGN_POST) || m.equals(Material.WALL_SIGN)) { - WEOnSignRightClick(event); - } - return; - } - if (event.getAction() != Action.LEFT_CLICK_BLOCK) { - return; - } - Material m = event.getClickedBlock().getType(); - if (!m.equals(Material.SIGN_POST) && !m.equals(Material.WALL_SIGN)) { - return; - } - if (event.getClickedBlock() == null) { - return; - } - Sign sign = (Sign) event.getClickedBlock().getState(); - String signText = ChatColor.stripColor(sign.getLine(0)); - - if (signText == null) { - return; - } - - if (!ChatColor.stripColor(sign.getLine(0)).equalsIgnoreCase("Repair:")) { - return; - } // left click the Repair sign, and it saves the state - if (Settings.RepairTicksPerBlock == 0) { - event.getPlayer().sendMessage(I18nSupport.getInternationalisedString("Repair functionality is disabled or WorldEdit was not detected")); - return; - } - Craft pCraft = CraftManager.getInstance().getCraftByPlayer(event.getPlayer()); - if (pCraft == null) { - event.getPlayer().sendMessage(I18nSupport.getInternationalisedString("You must be piloting a craft")); - return; - } - - String repairStateName = Movecraft.getInstance().getDataFolder().getAbsolutePath() + "/RepairStates"; - File file = new File(repairStateName); - if (!file.exists()) { - file.mkdirs(); - } - repairStateName += "/"; - repairStateName += event.getPlayer().getName(); - repairStateName += sign.getLine(1).replaceAll("\\s+", "_"); - repairStateName += ".schematic"; - file = new File(repairStateName); - - HashHitBox hitBox = pCraft.getHitBox(); - Vector size = new Vector(hitBox.getXLength(), (hitBox.getYLength()) + 1, hitBox.getZLength()); - Vector origin = new Vector(sign.getX(), sign.getY(), sign.getZ()); - Vector offset = new Vector(hitBox.getMinX() - sign.getX(), hitBox.getMinY() - sign.getY(), hitBox.getMinZ() - sign.getZ()); - CuboidClipboard cuboidClipboard = new CuboidClipboard(size, origin, offset); - final int[] ignoredBlocks = new int[]{64, 140, 144, 176, 177}; // BLOCKS THAT CAN'T BE PARTIALLY RECONSTRUCTED - - for (MovecraftLocation location : hitBox) { - Vector offsetLocation = new Vector(location.getX() - hitBox.getMinX(), location.getY() - hitBox.getMinY(), location.getZ() - hitBox.getMinZ()); - Block bukkitBlock = sign.getWorld().getBlockAt(location.getX(), location.getY(), location.getZ()); - if (Arrays.binarySearch(ignoredBlocks, bukkitBlock.getTypeId()) >= 0) { - continue; - } - BaseBlock baseBlock; - BlockState state = bukkitBlock.getState(); - if (state instanceof Sign) { - Sign s = (Sign) state; - baseBlock = new SignBlock(bukkitBlock.getTypeId(), bukkitBlock.getData(), s.getLines()); - } else if (state instanceof Dispenser) { - LocalWorld lw = BukkitUtil.getLocalWorld(event.getPlayer().getWorld()); - Vector vectorPos = new Vector(location.getX(), location.getY(), location.getZ()); - baseBlock = lw.getBlock(vectorPos); - DispenserBlock dispBlock = new DispenserBlock(baseBlock.getData()); - BaseItemStack[] bItemStack = new BaseItemStack[9]; - int numTNT = 0; - int numFireballs = 0; - int numWater = 0; - InventoryHolder inventoryHolder = (InventoryHolder) state; - if (inventoryHolder.getInventory().contains(46)) { - HashMap foundItems = inventoryHolder.getInventory().all(46); - // count how many were in the chest - for (ItemStack istack : foundItems.values()) { - numTNT += istack.getAmount(); - } - } - if (inventoryHolder.getInventory().contains(385)) { - HashMap foundItems = inventoryHolder.getInventory().all(385); - // count how many were in the chest - for (ItemStack istack : foundItems.values()) { - numFireballs += istack.getAmount(); - } - } - if (inventoryHolder.getInventory().contains(326)) { - HashMap foundItems = inventoryHolder.getInventory().all(326); - // count how many were in the chest - for (ItemStack istack : foundItems.values()) { - numWater += istack.getAmount(); - } - } - int index = 0; - while (numTNT > 64) { - bItemStack[index] = new BaseItemStack(46, 64); - index++; - numTNT -= 64; - } - if (numTNT > 0) - bItemStack[index] = new BaseItemStack(46, numTNT); - while (numFireballs > 64) { - bItemStack[index] = new BaseItemStack(385, 64); - index++; - numFireballs -= 64; - } - if (numFireballs > 0) - bItemStack[index] = new BaseItemStack(385, numFireballs); - while (numWater > 0) { - bItemStack[index] = new BaseItemStack(326, 1); - index++; - numWater--; - } - dispBlock.setItems(bItemStack); - baseBlock = dispBlock; - } else { - baseBlock = new BaseBlock(bukkitBlock.getTypeId(), bukkitBlock.getData()); - } - try{ - //TODO: Bug fix - cuboidClipboard.setBlock(offsetLocation, baseBlock); - }catch (Exception e){ - Movecraft.getInstance().getLogger().warning("Factory save failed, this is typically caused by FAWE"); - event.getPlayer().sendMessage(I18nSupport.getInternationalisedString("Could not save file")); - e.printStackTrace(); - return; - } - } - try { - cuboidClipboard.saveSchematic(file); - } catch (Exception e) { - event.getPlayer().sendMessage(I18nSupport.getInternationalisedString("Could not save file")); - e.printStackTrace(); - return; - } - event.getPlayer().sendMessage(I18nSupport.getInternationalisedString("State saved")); - event.setCancelled(true); - } - - private void WEOnSignRightClick(PlayerInteractEvent event) { - Sign sign = (Sign) event.getClickedBlock().getState(); - String signText = ChatColor.stripColor(sign.getLine(0)); - - if (signText == null) { - return; - } - - // don't process commands if this is a pilot tool click - if (event.getItem() != null && event.getItem().getTypeId() == Settings.PilotTool) { - Craft c = CraftManager.getInstance().getCraftByPlayer(event.getPlayer()); - if (c != null) - return; - } - if (sign.getLine(0).equalsIgnoreCase(ChatColor.RED + "REGION DAMAGED!")) { - String regionName = sign.getLine(1).substring(7); - Long damages = Long.parseLong(sign.getLine(2).substring(7)); - String[] owners = sign.getLine(3).substring(6).split(","); - if (Movecraft.getInstance().getEconomy().has(event.getPlayer(), damages)) { - Movecraft.getInstance().getEconomy().withdrawPlayer(event.getPlayer(), damages); - } else { - event.getPlayer().sendMessage(I18nSupport.getInternationalisedString("You do not have enough money")); - return; - } - event.getPlayer().sendMessage(I18nSupport.getInternationalisedString("Repairing region")); - if (!repairRegion(event.getClickedBlock().getWorld(), regionName)) { - Bukkit.getServer().broadcastMessage(String.format("REPAIR OF %s FAILED, CONTACT AN ADMIN", regionName)); - } - ProtectedRegion aRegion = Movecraft.getInstance().getWorldGuardPlugin().getRegionManager(event.getClickedBlock().getWorld()).getRegion(regionName); - for (String ownerName : owners) { - if (ownerName.length() > 16) { - aRegion.getOwners().addPlayer(UUID.fromString(ownerName)); - } else { - - if (Bukkit.getPlayer(ownerName) != null){//Cannot add names directly as bug will allow free assaults - aRegion.getOwners().addPlayer(Bukkit.getPlayer(ownerName).getUniqueId()); - } else { - aRegion.getOwners().addPlayer(Bukkit.getOfflinePlayer(ownerName).getUniqueId()); - } - //aRegion.getOwners().addPlayer(ownerName); - - } - //event.getPlayer().sendMessage(ownerName); - } - int beaconX = sign.getX() - 2; - int beaconY = sign.getY() - 3; - int beaconZ = sign.getZ() - 1; - for (int x = beaconX; x < beaconX + 5; x++) { - for (int y = beaconY; y < beaconY + 4; y++) { - for (int z = beaconZ; z < beaconZ + 5; z++) { - event.getClickedBlock().getWorld().getBlockAt(x, y, z).setType(Material.AIR); - } - } - } - return; - } - if (!ChatColor.stripColor(sign.getLine(0)).equalsIgnoreCase("Repair:")) { - return; - } - if (Settings.RepairTicksPerBlock == 0) { - event.getPlayer().sendMessage(I18nSupport.getInternationalisedString("Repair functionality is disabled or WorldEdit was not detected")); - return; - } - Craft pCraft = CraftManager.getInstance().getCraftByPlayer(event.getPlayer()); - if (pCraft == null) { - event.getPlayer().sendMessage(I18nSupport.getInternationalisedString("You must be piloting a craft")); - return; - } - if (!event.getPlayer().hasPermission("movecraft." + pCraft.getType().getCraftName() + ".repair")) { - event.getPlayer().sendMessage(I18nSupport.getInternationalisedString("Insufficient Permissions")); - return; - } - // load up the repair state - - String repairStateName = Movecraft.getInstance().getDataFolder().getAbsolutePath() + "/RepairStates"; - repairStateName += "/"; - repairStateName += event.getPlayer().getName(); - repairStateName += sign.getLine(1).replaceAll("\\s+", "_"); - repairStateName += ".schematic"; - File file = new File(repairStateName); - if (!file.exists()) { - event.getPlayer().sendMessage(I18nSupport.getInternationalisedString("REPAIR STATE NOT FOUND")); - return; - } - SchematicFormat sf = SchematicFormat.getFormat(file); - CuboidClipboard cc; - try { - cc = sf.load(file); - } catch (DataException | IOException e) { - event.getPlayer().sendMessage(I18nSupport.getInternationalisedString("REPAIR STATE NOT FOUND")); - e.printStackTrace(); - return; - } - - // calculate how many and where the blocks need to be replaced - Location worldLoc = new Location(sign.getWorld(), sign.getX(), sign.getY(), sign.getZ()); - int numdiffblocks = 0; - HashMap numMissingItems = new HashMap<>(); // block type, number missing - HashSet locMissingBlocks = new HashSet<>(); - for (int x = 0; x < cc.getWidth(); x++) { - for (int y = 0; y < cc.getHeight(); y++) { - for (int z = 0; z < cc.getLength(); z++) { - Vector ccLoc = new Vector(x, y, z); - worldLoc.setX(sign.getX() + cc.getOffset().getBlockX() + x); - worldLoc.setY(sign.getY() + cc.getOffset().getBlockY() + y); - worldLoc.setZ(sign.getZ() + cc.getOffset().getBlockZ() + z); - boolean isImportant = true; - if (!pCraft.getType().blockedByWater()) - if (cc.getBlock(ccLoc).getId() == 8 || cc.getBlock(ccLoc).getId() == 9) - isImportant = false; - if (cc.getBlock(ccLoc).getId() == 0) - isImportant = false; - if (isImportant && worldLoc.getWorld().getBlockAt(worldLoc).getTypeId() != cc.getBlock(ccLoc).getId()) { - numdiffblocks++; - int itemToConsume = cc.getBlock(ccLoc).getId(); - int qtyToConsume = 1; - //some blocks aren't represented by items with the same number as the block - if (itemToConsume == 63 || itemToConsume == 68) // signs - itemToConsume = 323; - if (itemToConsume == 93 || itemToConsume == 94) // repeaters - itemToConsume = 356; - if (itemToConsume == 149 || itemToConsume == 150) // comparators - itemToConsume = 404; - if (itemToConsume == 55) // redstone - itemToConsume = 331; - if (itemToConsume == 118) // cauldron - itemToConsume = 380; - if (itemToConsume == 124) // lit redstone lamp - itemToConsume = 123; - if (itemToConsume == 75) // lit redstone torch - itemToConsume = 76; - if (itemToConsume == 8 || itemToConsume == 9) { // don't require water to be in the chest - itemToConsume = 0; - qtyToConsume = 0; - } - if (itemToConsume == 10 || itemToConsume == 11) { // don't require lava either, yeah you could exploit this for free lava, so make sure you set a price per block - itemToConsume = 0; - qtyToConsume = 0; - } - if (itemToConsume == 26 || itemToConsume == 34 || itemToConsume == 71 || itemToConsume == 193 || itemToConsume == 194 || itemToConsume == 195 || itemToConsume == 196 || itemToConsume == 197) { // don't require doors, beds - itemToConsume = 0; - qtyToConsume = 0; - } - if (itemToConsume == 23) { // for dispensers, count the fireballs and tnt - BaseBlock bb = cc.getBlock(ccLoc); - DispenserBlock dispBlock = new DispenserBlock(bb.getData()); - if(bb.getNbtData() != null && bb.getNbtData().getValue()!=null) { - Tag t = bb.getNbtData().getValue().get("id"); - if (t instanceof StringTag && ((StringTag) t).getValue().equals("Trap")) { - dispBlock.setNbtData(bb.getNbtData()); - } - } - int numFireCharges = 0; - int numTNT = 0; - int numWater = 0; - for (BaseItemStack bi : dispBlock.getItems()) { - if (bi != null) { - if (bi.getType() == 46) - numTNT += bi.getAmount(); - if (bi.getType() == 385) - numFireCharges += bi.getAmount(); - if (bi.getType() == 326) - numWater += bi.getAmount(); - } - } - if (numFireCharges > 0) { - if (!numMissingItems.containsKey(385)) { - numMissingItems.put(385, numFireCharges); - } else { - Integer num = numMissingItems.get(385); - num += numFireCharges; - numMissingItems.put(385, num); - } - } - if (numTNT > 0) { - if (!numMissingItems.containsKey(46)) { - numMissingItems.put(46, numTNT); - } else { - Integer num = numMissingItems.get(46); - num += numTNT; - numMissingItems.put(46, num); - } - } - if (numWater > 0) { - if (!numMissingItems.containsKey(326)) { - numMissingItems.put(326, numWater); - } else { - Integer num = numMissingItems.get(326); - num += numWater; - numMissingItems.put(46, num); - } - } - } - if (itemToConsume == 43) { // for double slabs, require 2 slabs - itemToConsume = 44; - qtyToConsume = 2; - } - if (itemToConsume == 125) { // for double wood slabs, require 2 wood slabs - itemToConsume = 126; - qtyToConsume = 2; - } - if (itemToConsume == 181) { // for double red sandstone slabs, require 2 red sandstone slabs - itemToConsume = 182; - qtyToConsume = 2; - } - - if (itemToConsume != 0) { - if (!numMissingItems.containsKey(itemToConsume)) { - numMissingItems.put(itemToConsume, qtyToConsume); - } else { - Integer num = numMissingItems.get(itemToConsume); - num += qtyToConsume; - numMissingItems.put(itemToConsume, num); - } - } - locMissingBlocks.add(ccLoc); - } - if ((worldLoc.getWorld().getBlockAt(worldLoc).getTypeId() == 23) && (cc.getBlock(ccLoc).getId() == 23)) { // check to see if ammo is missing from intact dispensers - BaseBlock bb = cc.getBlock(ccLoc); - DispenserBlock dispBlock = new DispenserBlock(bb.getData()); - if(bb.getNbtData() != null && bb.getNbtData().getValue()!=null) { - Tag t = bb.getNbtData().getValue().get("id"); - if (t instanceof StringTag && ((StringTag) t).getValue().equals("Trap")) { - dispBlock.setNbtData(bb.getNbtData()); - } - } - int numFireCharges = 0; - int numTNT = 0; - int numWater = 0; - boolean needsReplace = false; - for (BaseItemStack bi : dispBlock.getItems()) { - if (bi != null) { - if (bi.getType() == 46) - numTNT += bi.getAmount(); - if (bi.getType() == 385) - numFireCharges += bi.getAmount(); - if (bi.getType() == 326) - numWater += bi.getAmount(); - } - } - Dispenser disp = (Dispenser) worldLoc.getWorld().getBlockAt(worldLoc).getState(); - for (ItemStack di : disp.getInventory().getContents()) { - if (di != null) { - if (di.getTypeId() == 46) - numTNT -= di.getAmount(); - if (di.getTypeId() == 385) - numFireCharges -= di.getAmount(); - if (di.getTypeId() == 326) - numWater -= di.getAmount(); - } - } - if (numFireCharges > 0) { - if (!numMissingItems.containsKey(385)) { - numMissingItems.put(385, numFireCharges); - } else { - Integer num = numMissingItems.get(385); - num += numFireCharges; - numMissingItems.put(385, num); - } - needsReplace = true; - } - if (numTNT > 0) { - if (!numMissingItems.containsKey(46)) { - numMissingItems.put(46, numTNT); - } else { - Integer num = numMissingItems.get(46); - num += numTNT; - numMissingItems.put(46, num); - } - needsReplace = true; - } - if (numWater > 0) { - if (!numMissingItems.containsKey(326)) { - numMissingItems.put(326, numWater); - } else { - Integer num = numMissingItems.get(326); - num += numWater; - numMissingItems.put(46, num); - } - needsReplace = true; - } - if (needsReplace) { - numdiffblocks++; - locMissingBlocks.add(ccLoc); - } - } - } - } - } - - // if this is the second click in the last 5 seconds, start the repair, otherwise give them the info on the repair - boolean secondClick = false; - Long time = repairRightClickTimeMap.get(event.getPlayer()); - if (time != null) { - long ticksElapsed = (System.currentTimeMillis() - time) / 50; - if (ticksElapsed < 100) { - secondClick = true; - } - } - if (secondClick) { - // check all the chests for materials for the repair - HashMap> chestsToTakeFrom = new HashMap<>(); // typeid, list of chest inventories - boolean enoughMaterial = true; - for (Integer typeID : numMissingItems.keySet()) { - int remainingQty = numMissingItems.get(typeID); - ArrayList chests = new ArrayList<>(); - for (MovecraftLocation loc : pCraft.getHitBox()) { - Block b = pCraft.getW().getBlockAt(loc.getX(), loc.getY(), loc.getZ()); - if ((b.getTypeId() == 54) || (b.getTypeId() == 146)) { - InventoryHolder inventoryHolder = (InventoryHolder) b.getState(); - if (inventoryHolder.getInventory().contains(typeID) && remainingQty > 0) { - HashMap foundItems = inventoryHolder.getInventory().all(typeID); - // count how many were in the chest - int numfound = 0; - for (ItemStack istack : foundItems.values()) { - numfound += istack.getAmount(); - } - remainingQty -= numfound; - chests.add(inventoryHolder); - } - } - } - if (remainingQty > 0) { - event.getPlayer().sendMessage(String.format(I18nSupport.getInternationalisedString("Need more of material") + ": %s - %d", Material.getMaterial(typeID).name().toLowerCase().replace("_", " "), remainingQty)); - enoughMaterial = false; - } else { - chestsToTakeFrom.put(typeID, chests); - } - } - if (Movecraft.getInstance().getEconomy() != null && enoughMaterial) { - double moneyCost = numdiffblocks * Settings.RepairMoneyPerBlock; - if (Movecraft.getInstance().getEconomy().has(event.getPlayer(), moneyCost)) { - Movecraft.getInstance().getEconomy().withdrawPlayer(event.getPlayer(), moneyCost); - } else { - event.getPlayer().sendMessage(I18nSupport.getInternationalisedString("You do not have enough money")); - enoughMaterial = false; - } - } - if (enoughMaterial) { - // we know we have enough materials to make the repairs, so remove the materials from the chests - for (Integer typeID : numMissingItems.keySet()) { - int remainingQty = numMissingItems.get(typeID); - for (InventoryHolder inventoryHolder : chestsToTakeFrom.get(typeID)) { - HashMap foundItems = inventoryHolder.getInventory().all(typeID); - for (ItemStack istack : foundItems.values()) { - if (istack.getAmount() <= remainingQty) { - remainingQty -= istack.getAmount(); - inventoryHolder.getInventory().removeItem(istack); - } else { - istack.setAmount(istack.getAmount() - remainingQty); - remainingQty = 0; - } - } - - } - } - double Cost = numdiffblocks * Settings.RepairMoneyPerBlock; - Bukkit.getLogger().info(event.getPlayer().toString() + " has begun a repair with the cost of " + String.valueOf(Cost)); - final LinkedList updateCommands = new LinkedList<>(); - for (Vector ccloc : locMissingBlocks) { - BaseBlock bb = cc.getBlock(ccloc); - if (bb.getId() == 68 || bb.getId() == 63) { // I don't know why this is necessary. I'm pretty sure WE should be loading signs as signblocks, but it doesn't seem to - SignBlock sb = new SignBlock(bb.getId(), bb.getData()); - sb.setNbtData(bb.getNbtData()); - String[] textLines = sb.getText(); - for (int i = 0; i < textLines.length; i++) { - String str = textLines[i]; - if (str.length() >= 11) - str = str.substring(9); - str = str.replaceAll("\"", ""); - str = str.replace("\\\\", "\\"); - str = str.replaceAll("}", ""); - textLines[i] = str; - } - if (textLines[0].equals("\\ || /")) { - textLines[1] = "== =="; - textLines[2] = "/ || \\"; - textLines[3] = ""; - } - sb.setText(textLines); - bb = sb; - } - MovecraftLocation moveloc = new MovecraftLocation(sign.getX() + cc.getOffset().getBlockX() + ccloc.getBlockX(), sign.getY() + cc.getOffset().getBlockY() + ccloc.getBlockY(), sign.getZ() + cc.getOffset().getBlockZ() + ccloc.getBlockZ()); - WorldEditUpdateCommand updateCom = new WorldEditUpdateCommand(bb, sign.getLocation().getWorld(), moveloc, Material.getMaterial(bb.getType()), (byte) bb.getData()); - updateCommands.add(updateCom); - } - if (updateCommands.size() > 0) { - int durationInTicks = numdiffblocks * Settings.RepairTicksPerBlock; - - // send out status updates every minute - for (int ticsFromStart = 0; ticsFromStart < durationInTicks; ticsFromStart += 1200) { - final Player fp = event.getPlayer(); - final int fTics = ticsFromStart / 20; - final int fDur = durationInTicks / 20; - new BukkitRunnable() { - @Override - public void run() { - fp.sendMessage(String.format(I18nSupport.getInternationalisedString("Repairs underway") + ": %d / %d", fTics, fDur)); - } - }.runTaskLater(Movecraft.getInstance(), (ticsFromStart)); - - } - - // keep craft piloted during the repair process so player can not move it - CraftManager.getInstance().removePlayerFromCraft(pCraft); - final Craft releaseCraft = pCraft; - final Player fp = event.getPlayer(); - new BukkitRunnable() { - @Override - public void run() { - CraftManager.getInstance().removeCraft(releaseCraft); - fp.sendMessage(I18nSupport.getInternationalisedString("Repairs complete. You may now pilot the craft")); - } - }.runTaskLater(Movecraft.getInstance(), (durationInTicks + 20)); - - //do the actual repair - new BukkitRunnable() { - @Override - public void run() { - if (updateCommands.isEmpty()) { - Movecraft.getInstance().getLogger().info("Repair complete"); - this.cancel(); - return; - } - MapUpdateManager.getInstance().scheduleUpdate(updateCommands.pop()); - } - }.runTaskTimer(Movecraft.getInstance(), 0, Settings.RepairTicksPerBlock); - - } - } - - } else { - // if this is the first time they have clicked the sign, show the summary of repair costs and requirements - event.getPlayer().sendMessage(String.format(I18nSupport.getInternationalisedString("Total damaged blocks") + ": %d", numdiffblocks)); - float percent = (numdiffblocks * 100) / pCraft.getOrigBlockCount(); - event.getPlayer().sendMessage(String.format(I18nSupport.getInternationalisedString("Percentage of craft") + ": %.2f%%", percent)); - if (percent > 50) { - event.getPlayer().sendMessage(I18nSupport.getInternationalisedString("This craft is too damaged and can not be repaired")); - return; - } - if (numdiffblocks != 0) { - event.getPlayer().sendMessage(I18nSupport.getInternationalisedString("SUPPLIES NEEDED")); - for (Integer blockTypeInteger : numMissingItems.keySet()) { - event.getPlayer().sendMessage(String.format("%s : %d", Material.getMaterial(blockTypeInteger).name().toLowerCase().replace("_", " "), numMissingItems.get(blockTypeInteger))); - } - int durationInSeconds = numdiffblocks * Settings.RepairTicksPerBlock / 20; - event.getPlayer().sendMessage(String.format(I18nSupport.getInternationalisedString("Seconds to complete repair") + ": %d", durationInSeconds)); - int moneyCost = (int) (numdiffblocks * Settings.RepairMoneyPerBlock); - event.getPlayer().sendMessage(String.format(I18nSupport.getInternationalisedString("Money to complete repair") + ": %d", moneyCost)); - repairRightClickTimeMap.put(event.getPlayer(), System.currentTimeMillis()); - } - } - - } - -} diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/BlockCreateCommand.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/BlockCreateCommand.java index 34429849a..c42d88d3f 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/BlockCreateCommand.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/BlockCreateCommand.java @@ -2,10 +2,14 @@ import net.countercraft.movecraft.Movecraft; import net.countercraft.movecraft.MovecraftLocation; +import net.countercraft.movecraft.config.Settings; import net.countercraft.movecraft.craft.Craft; +import net.countercraft.movecraft.utils.LegacyUtils; import org.bukkit.Material; import org.bukkit.World; import org.bukkit.block.Block; +import org.bukkit.block.BlockState; +import org.bukkit.block.data.BlockData; import org.jetbrains.annotations.NotNull; import java.util.Objects; @@ -17,12 +21,14 @@ public class BlockCreateCommand extends UpdateCommand { final private Material type; final private byte dataID; final private World world; + final BlockData bData; public BlockCreateCommand(@NotNull MovecraftLocation newBlockLocation, @NotNull Material type, byte dataID, @NotNull Craft craft) { this.newBlockLocation = newBlockLocation; this.type = type; this.dataID = dataID; this.world = craft.getW(); + bData = null; } public BlockCreateCommand(@NotNull World world, @NotNull MovecraftLocation newBlockLocation, @NotNull Material type, byte dataID) { @@ -30,6 +36,7 @@ public BlockCreateCommand(@NotNull World world, @NotNull MovecraftLocation newBl this.type = type; this.dataID = dataID; this.world = world; + bData = null; } public BlockCreateCommand(@NotNull World world, @NotNull MovecraftLocation newBlockLocation, @NotNull Material type) { @@ -37,6 +44,15 @@ public BlockCreateCommand(@NotNull World world, @NotNull MovecraftLocation newBl this.type = type; this.dataID = (byte)0; this.world = world; + bData = null; + } + + public BlockCreateCommand(@NotNull World world, @NotNull MovecraftLocation newBlockLocation, @NotNull Material type, @NotNull BlockData bData){ + this.world = world; + this.newBlockLocation = newBlockLocation; + this.type = type; + this.dataID = 0; + this.bData = bData; } @@ -50,18 +66,28 @@ public void doUpdate() { newBlockLocation.toBukkit(world).getBlock().getState().update(false, false); //Do comperator stuff - - if (type == Material.REDSTONE_COMPARATOR_OFF) { // for some reason comparators are flakey, have to do it twice sometimes - //Block b = updateWorld.getBlockAt(newBlockLocation.getX(), newBlockLocation.getY(), newBlockLocation.getZ()); - Block b = newBlockLocation.toBukkit(world).getBlock(); - if (b.getType() != Material.REDSTONE_COMPARATOR_OFF) { - b.setTypeIdAndData(type.getId(), dataID, false); + if (Settings.IsLegacy) { + if (type == LegacyUtils.REDSTONE_COMPARATOR_OFF) { // for some reason comparators are flakey, have to do it twice sometimes + //Block b = updateWorld.getBlockAt(newBlockLocation.getX(), newBlockLocation.getY(), newBlockLocation.getZ()); + Block b = newBlockLocation.toBukkit(world).getBlock(); + if (b.getType() != LegacyUtils.REDSTONE_COMPARATOR_OFF) { + LegacyUtils.setTypeIdAndData(b, type.getId(), dataID, false); + //b.setTypeIdAndData(type.getId(), dataID, false); + } } - } - if (type == Material.REDSTONE_COMPARATOR) { // for some reason comparators are flakey, have to do it twice sometimes - Block b = newBlockLocation.toBukkit(world).getBlock(); - if (b.getType() != Material.REDSTONE_COMPARATOR) { - b.setTypeIdAndData(type.getId(), dataID, false); + if (type == LegacyUtils.REDSTONE_COMPARATOR) { // for some reason comparators are flakey, have to do it twice sometimes + Block b = newBlockLocation.toBukkit(world).getBlock(); + if (b.getType() != LegacyUtils.REDSTONE_COMPARATOR) { + LegacyUtils.setTypeIdAndData(b, type.getId(), dataID, false); + } + } + } else { + if (type == Material.COMPARATOR){ + Block b = newBlockLocation.toBukkit(world).getBlock(); + if (b.getType() != Material.COMPARATOR){ + b.setType(type, false); + b.setBlockData(bData, false); + } } } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftRotateCommand.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftRotateCommand.java index ed9e6fc07..74433d008 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftRotateCommand.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftRotateCommand.java @@ -45,12 +45,31 @@ public void doUpdate() { long time = System.nanoTime(); final Set passthroughBlocks = new HashSet<>(craft.getType().getPassthroughBlocks()); if(craft.getSinking()){ - passthroughBlocks.add(Material.STATIONARY_WATER); + passthroughBlocks.add(Material.WATER); - passthroughBlocks.add(Material.LEAVES); - passthroughBlocks.add(Material.LEAVES_2); - passthroughBlocks.add(Material.LONG_GRASS); - passthroughBlocks.add(Material.DOUBLE_PLANT); + if (Settings.IsLegacy){ //use pre-1.13 values if running on 1.12.2 or lower + passthroughBlocks.add(LegacyUtils.STATIONARY_WATER); + passthroughBlocks.add(LegacyUtils.LEAVES); + passthroughBlocks.add(LegacyUtils.LEAVES_2); + passthroughBlocks.add(LegacyUtils.LONG_GRASS); + passthroughBlocks.add(LegacyUtils.DOUBLE_PLANT); + } else {//otherwise, use 1.13+ types + //Leaves + passthroughBlocks.add(Material.ACACIA_LEAVES); + passthroughBlocks.add(Material.BIRCH_LEAVES); + passthroughBlocks.add(Material.DARK_OAK_LEAVES); + passthroughBlocks.add(Material.JUNGLE_LEAVES); + passthroughBlocks.add(Material.OAK_LEAVES); + passthroughBlocks.add(Material.SPRUCE_LEAVES); + //Grass + passthroughBlocks.add(Material.GRASS); + //Double plants + passthroughBlocks.add(Material.ROSE_BUSH); + passthroughBlocks.add(Material.SUNFLOWER); + passthroughBlocks.add(Material.LILAC); + passthroughBlocks.add(Material.PEONY); + + } } if (!passthroughBlocks.isEmpty()) { MutableHitBox originalLocations = new HashHitBox(); @@ -131,7 +150,7 @@ public void doUpdate() { //trigger sign events for (MovecraftLocation location : craft.getHitBox()) { Block block = location.toBukkit(craft.getW()).getBlock(); - if (block.getType() == Material.WALL_SIGN || block.getType() == Material.SIGN_POST) { + if (block.getType() == Material.WALL_SIGN || block.getType() == (Settings.IsLegacy ? LegacyUtils.SIGN_POST : Material.SIGN)) { Sign sign = (Sign) block.getState(); Bukkit.getServer().getPluginManager().callEvent(new SignTranslateEvent(block, craft, sign.getLines())); sign.update(); @@ -167,7 +186,7 @@ public void doUpdate() { //trigger sign events for (MovecraftLocation location : craft.getHitBox()) { Block block = location.toBukkit(craft.getW()).getBlock(); - if (block.getType() == Material.WALL_SIGN || block.getType() == Material.SIGN_POST) { + if (block.getType() == Material.WALL_SIGN || block.getType() == (Settings.IsLegacy ? LegacyUtils.SIGN_POST : Material.SIGN)) { Sign sign = (Sign) block.getState(); Bukkit.getServer().getPluginManager().callEvent(new SignTranslateEvent(block, craft, sign.getLines())); sign.update(); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftTranslateCommand.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftTranslateCommand.java index 4e8f7984e..21fd0d52b 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftTranslateCommand.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftTranslateCommand.java @@ -8,11 +8,7 @@ import net.countercraft.movecraft.craft.Craft; import net.countercraft.movecraft.craft.CraftManager; import net.countercraft.movecraft.events.SignTranslateEvent; -import net.countercraft.movecraft.utils.CollectionUtils; -import net.countercraft.movecraft.utils.HashHitBox; -import net.countercraft.movecraft.utils.HitBox; -import net.countercraft.movecraft.utils.MutableHitBox; -import net.countercraft.movecraft.utils.SolidHitBox; +import net.countercraft.movecraft.utils.*; import org.bukkit.Bukkit; import org.bukkit.Material; import org.bukkit.block.Block; @@ -47,12 +43,33 @@ public void doUpdate() { long time = System.nanoTime(); final Set passthroughBlocks = new HashSet<>(craft.getType().getPassthroughBlocks()); if(craft.getSinking()){ - passthroughBlocks.add(Material.STATIONARY_WATER); - passthroughBlocks.add(Material.WATER); - passthroughBlocks.add(Material.LEAVES); - passthroughBlocks.add(Material.LEAVES_2); - passthroughBlocks.add(Material.LONG_GRASS); - passthroughBlocks.add(Material.DOUBLE_PLANT); + + + passthroughBlocks.add(Material.WATER);//Same in the 1.13 API, but other values are different + if (Settings.IsLegacy){ //use pre-1.13 values if running on 1.12.2 or lower + passthroughBlocks.add(LegacyUtils.STATIONARY_WATER); + passthroughBlocks.add(LegacyUtils.LEAVES); + passthroughBlocks.add(LegacyUtils.LEAVES_2); + passthroughBlocks.add(LegacyUtils.LONG_GRASS); + passthroughBlocks.add(LegacyUtils.DOUBLE_PLANT); + } else {//otherwise, use 1.13+ types + //Leaves + passthroughBlocks.add(Material.ACACIA_LEAVES); + passthroughBlocks.add(Material.BIRCH_LEAVES); + passthroughBlocks.add(Material.DARK_OAK_LEAVES); + passthroughBlocks.add(Material.JUNGLE_LEAVES); + passthroughBlocks.add(Material.OAK_LEAVES); + passthroughBlocks.add(Material.SPRUCE_LEAVES); + //Grass + passthroughBlocks.add(Material.GRASS); + //Double plants + passthroughBlocks.add(Material.ROSE_BUSH); + passthroughBlocks.add(Material.SUNFLOWER); + passthroughBlocks.add(Material.LILAC); + passthroughBlocks.add(Material.PEONY); + + } + } if(passthroughBlocks.isEmpty()){ //translate the craft @@ -60,7 +77,7 @@ public void doUpdate() { //trigger sign events for(MovecraftLocation location : craft.getHitBox()){ Block block = location.toBukkit(craft.getW()).getBlock(); - if(block.getType() == Material.WALL_SIGN || block.getType() == Material.SIGN_POST){ + if(block.getType() == Material.WALL_SIGN || block.getType() == (Settings.IsLegacy ? LegacyUtils.SIGN_POST : Material.SIGN)){ Sign sign = (Sign) block.getState(); Bukkit.getServer().getPluginManager().callEvent(new SignTranslateEvent(block, craft, sign.getLines())); sign.update(); @@ -143,7 +160,7 @@ public void doUpdate() { //trigger sign events for (MovecraftLocation location : craft.getHitBox()) { Block block = location.toBukkit(craft.getW()).getBlock(); - if (block.getType() == Material.WALL_SIGN || block.getType() == Material.SIGN_POST) { + if (block.getType() == Material.WALL_SIGN || block.getType() == (Settings.IsLegacy ? LegacyUtils.SIGN_POST : Material.SIGN)) { Sign sign = (Sign) block.getState(); Bukkit.getServer().getPluginManager().callEvent(new SignTranslateEvent(block, craft, sign.getLines())); sign.update(); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/WorldEditUpdateCommand.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/WorldEditUpdateCommand.java index 7f3bc1903..243323efc 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/WorldEditUpdateCommand.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/WorldEditUpdateCommand.java @@ -1,78 +1,198 @@ package net.countercraft.movecraft.mapUpdater.update; +import com.sk89q.jnbt.CompoundTag; +import com.sk89q.jnbt.ListTag; +import com.sk89q.jnbt.Tag; import com.sk89q.worldedit.blocks.BaseBlock; -import com.sk89q.worldedit.blocks.BaseItemStack; -import com.sk89q.worldedit.blocks.DispenserBlock; -import com.sk89q.worldedit.blocks.SignBlock; +import com.sk89q.worldedit.blocks.BlockMaterial; +import com.sk89q.worldedit.blocks.BlockType; +import com.sk89q.worldedit.world.block.BlockStateHolder; import net.countercraft.movecraft.MovecraftLocation; +import net.countercraft.movecraft.config.Settings; +import net.countercraft.movecraft.utils.LegacyUtils; +import org.bukkit.Bukkit; import org.bukkit.Material; import org.bukkit.World; import org.bukkit.block.BlockState; import org.bukkit.block.Dispenser; +import org.bukkit.block.Furnace; import org.bukkit.block.Sign; +import org.bukkit.block.data.BlockData; import org.bukkit.inventory.ItemStack; public class WorldEditUpdateCommand extends UpdateCommand { private final BaseBlock worldEditBaseBlock; + private final com.sk89q.worldedit.world.block.BlockState worldEditBlockState; private World world; private MovecraftLocation location; private Material type; private byte data; + private BlockData bData; public WorldEditUpdateCommand(BaseBlock worldEditBaseBlock, World world, MovecraftLocation location, Material type, byte data) { this.worldEditBaseBlock = worldEditBaseBlock; + worldEditBlockState = null; this.world = world; this.location = location; this.type = type; this.data = data; } + //1.13 constructor + public WorldEditUpdateCommand(com.sk89q.worldedit.world.block.BlockState worldEditBlockState, World world, MovecraftLocation location, Material type, BlockData bData){ + worldEditBaseBlock = null; + this.worldEditBlockState = worldEditBlockState; + this.world = world; + this.location = location; + this.type = type; + this.bData = bData; + } @Override public void doUpdate() { world.getBlockAt(location.getX(), location.getY(), location.getZ()).setType(type); - world.getBlockAt(location.getX(), location.getY(), location.getZ()).setData(data); - // put inventory into dispensers if its a repair - if (type == Material.DISPENSER) { - DispenserBlock dispBlock = new DispenserBlock(worldEditBaseBlock.getData()); - dispBlock.setNbtData(worldEditBaseBlock.getNbtData()); - int numFireCharges = 0; - int numTNT = 0; - int numWater = 0; - for (BaseItemStack bi : dispBlock.getItems()) { - if (bi != null) { - if (bi.getType() == 46) - numTNT += bi.getAmount(); - if (bi.getType() == 385) - numFireCharges += bi.getAmount(); - if (bi.getType() == 326) - numWater += bi.getAmount(); + if (Settings.IsLegacy) { + LegacyUtils.setData(world.getBlockAt(location.getX(), location.getY(), location.getZ()), data); + + // put inventory into dispensers if its a repair + if (type == Material.DISPENSER) { + //DispenserBlock dispBlock = new DispenserBlock(worldEditBaseBlock.getData()); + //dispBlock.setNbtData(worldEditBaseBlock.getNbtData()); + Tag t = worldEditBaseBlock.getNbtData().getValue().get("Items"); + ListTag lt = null; + if (t instanceof ListTag) { + lt = (ListTag) t; } + int numFireCharges = 0; + int numTNT = 0; + int numWater = 0; + if (lt != null) { + for (Tag entryTag : lt.getValue()) { + if (entryTag instanceof CompoundTag) { + CompoundTag cTag = (CompoundTag) entryTag; + if (cTag.toString().contains("minecraft:tnt")) { + numTNT += cTag.getByte("Count"); + } + if (cTag.toString().contains("minecraft:fire_charge")) { + numFireCharges += cTag.getByte("Count"); + } + if (cTag.toString().contains("minecraft:water_bucket")) { + numWater += cTag.getByte("Count"); + } + } + } + } + Dispenser disp = (Dispenser) world.getBlockAt(location.getX(), location.getY(), location.getZ()).getState(); + if (numFireCharges > 0) { + ItemStack fireItems = new ItemStack(LegacyUtils.FIREBALL, numFireCharges); + disp.getInventory().addItem(fireItems); + } + if (numTNT > 0) { + ItemStack TNTItems = new ItemStack(Material.TNT, numTNT); + disp.getInventory().addItem(TNTItems); + } + if (numWater > 0) { + ItemStack WaterItems = new ItemStack(Material.WATER_BUCKET, numWater); + disp.getInventory().addItem(WaterItems); + } + + } - Dispenser disp = (Dispenser) world.getBlockAt(location.getX(), location.getY(), location.getZ()).getState(); - if (numFireCharges > 0) { - ItemStack fireItems = new ItemStack(Material.FIREBALL, numFireCharges); - disp.getInventory().addItem(fireItems); - } - if (numTNT > 0) { - ItemStack TNTItems = new ItemStack(Material.TNT, numTNT); - disp.getInventory().addItem(TNTItems); + if (worldEditBaseBlock.getType() == 63 || worldEditBaseBlock.getType() == 68) { + BlockState state = world.getBlockAt(location.getX(), location.getY(), location.getZ()).getState(); + if (state instanceof Sign) { + Sign s = (Sign) state; + CompoundTag nbtData = worldEditBaseBlock.getNbtData(); + //first line + String firstLine = nbtData.getString("Text1"); + firstLine = firstLine.substring(2); + if (firstLine.substring(0, 5).equalsIgnoreCase("extra")){ + firstLine = firstLine.substring(17); + String[] parts = firstLine.split("\""); + firstLine = parts[0]; + } else { + firstLine = ""; + } + //second line + String secondLine = nbtData.getString("Text2"); + secondLine = secondLine.substring(2); + if (secondLine.substring(0, 5).equalsIgnoreCase("extra")){ + secondLine = secondLine.substring(17); + String[] parts = secondLine.split("\""); + secondLine = parts[0]; + } else { + secondLine = ""; + } + //third line + String thirdLine = nbtData.getString("Text3"); + thirdLine = thirdLine.substring(2); + if (thirdLine.substring(0, 5).equalsIgnoreCase("extra")){ + thirdLine = thirdLine.substring(17); + String[] parts = thirdLine.split("\""); + thirdLine = parts[0]; + } else { + thirdLine = ""; + } + //fourth line + String fourthLine = nbtData.getString("Text4"); + fourthLine = fourthLine.substring(2); + if (fourthLine.substring(0, 5).equalsIgnoreCase("extra")){ + fourthLine = fourthLine.substring(17); + String[] parts = fourthLine.split("\""); + fourthLine = parts[0]; + } else { + fourthLine = ""; + } + String[] lines = new String[4]; + if (firstLine.equalsIgnoreCase("\\\\ || /")){ + firstLine = "\\ || /"; + secondLine = "== =="; + thirdLine = "/ || \\"; + } + lines[0] = firstLine; + lines[1] = secondLine; + lines[2] = thirdLine; + lines[3] = fourthLine; + for (int line = 0; line < lines.length; line++) { + s.setLine(line, lines[line]); + } + s.update(false, false); + } } - if (numWater > 0) { - ItemStack WaterItems = new ItemStack(Material.WATER_BUCKET, numWater); - disp.getInventory().addItem(WaterItems); + } else { + world.getBlockAt(location.getX(), location.getY(), location.getZ()).setBlockData(bData); + if (type == Material.DISPENSER){ + } + } - if (worldEditBaseBlock instanceof SignBlock) { - BlockState state = world.getBlockAt(location.getX(), location.getY(), location.getZ()).getState(); - if (state instanceof Sign) { - Sign s = (Sign) state; - SignBlock signBlock = (SignBlock) worldEditBaseBlock; - for (int line = 0; line < signBlock.getText().length; line++) { - s.setLine(line, signBlock.getText()[line]); + + //might have issues due to repair order + /*if (type == Material.FURNACE){ + Tag t = worldEditBaseBlock.getNbtData().getValue().get("Items"); + ListTag lt = null; + if (t instanceof ListTag){ + lt = (ListTag) t; + } + int numCoal = 0; + int numCharCoal = 0; + int numCoalBlock = 0; + if (lt != null) { + for (Tag entryTag : lt.getValue()) { + if (entryTag instanceof CompoundTag){ + CompoundTag cTag = (CompoundTag) entryTag; + if (cTag.toString().contains("minecraft:coal")){ + numCoal += cTag.getByte("Count"); + } + if (cTag.toString().contains("minecraft:fire_charge")){ + numCharCoal += cTag.getByte("Count"); + } + if (cTag.toString().contains("minecraft:water_bucket")){ + numCoalBlock += cTag.getByte("Count"); + } + } } - s.update(false, false); } - } - //might have issues due to repair order + Furnace furnace = (Furnace) world.getBlockAt(location.getX(),location.getY(),location.getZ()).getState(); + }*/ } } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/repair/RepairUtils.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/repair/RepairUtils.java new file mode 100644 index 000000000..77b65848c --- /dev/null +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/repair/RepairUtils.java @@ -0,0 +1,68 @@ +package net.countercraft.movecraft.repair; + +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.blocks.BaseBlock; +import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard; +import com.sk89q.worldedit.extent.clipboard.Clipboard; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.world.block.BlockState; +import net.countercraft.movecraft.Movecraft; +import net.countercraft.movecraft.MovecraftLocation; +import net.countercraft.movecraft.MovecraftRepair; +import net.countercraft.movecraft.config.Settings; +import net.countercraft.movecraft.mapUpdater.MapUpdateManager; +import net.countercraft.movecraft.mapUpdater.update.WorldEditUpdateCommand; +import net.countercraft.movecraft.utils.LegacyUtils; +import org.bukkit.Material; +import org.bukkit.World; +import org.bukkit.event.player.PlayerInteractEvent; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +public class RepairUtils { + + + public static boolean repairRegion(String regionName, World world){ + MovecraftRepair movecraftRepair = Movecraft.getInstance().getMovecraftRepair(); + Clipboard clipboard = movecraftRepair.loadRegionRepairStateClipboard(Movecraft.getInstance(), regionName, world); + if (clipboard == null){ + return false; + } + int minX = clipboard.getMinimumPoint().getBlockX(); + int minY = clipboard.getMinimumPoint().getBlockY(); + int minZ = clipboard.getMinimumPoint().getBlockZ(); + int maxX = clipboard.getMaximumPoint().getBlockX(); + int maxY = clipboard.getMaximumPoint().getBlockY(); + int maxZ = clipboard.getMaximumPoint().getBlockZ(); + + for (int x = minX; x <= maxX; x++){ + for (int y = minY; y <= maxY; y++){ + for (int z = minZ; z <= maxZ; z++){ + if (Settings.IsLegacy){ + Vector pos = new Vector(x,y,z); + BaseBlock bb = clipboard.getBlock(pos); + if (bb.isAir()){ + continue; + } + if (Settings.AssaultDestroyableBlocks.contains(LegacyUtils.getMaterial(bb.getId()))){ + if (!world.getChunkAt(x >> 4, z >> 4).isLoaded()) + world.loadChunk(x >> 4, z >> 4); + if (world.getBlockAt(x, y, z).isEmpty() || world.getBlockAt(x, y, z).isLiquid()) { + MovecraftLocation moveloc = new MovecraftLocation(x, y, z); + WorldEditUpdateCommand updateCommand = new WorldEditUpdateCommand(bb, world, moveloc, LegacyUtils.getMaterial(bb.getType()), (byte) bb.getData()); + MapUpdateManager.getInstance().scheduleUpdate(updateCommand); + } + } + } else { + BlockVector3 pos = BlockVector3.at(x,y,z); + BlockArrayClipboard bac = (BlockArrayClipboard) clipboard; + } + } + } + } + return true; + } + + +} diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/AntiAircraftDirectorSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/AntiAircraftDirectorSign.java index 1b2042393..dd7c0ae36 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/AntiAircraftDirectorSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/AntiAircraftDirectorSign.java @@ -1,6 +1,8 @@ package net.countercraft.movecraft.sign; +import net.countercraft.movecraft.config.Settings; import net.countercraft.movecraft.craft.Craft; +import net.countercraft.movecraft.utils.LegacyUtils; import net.countercraft.movecraft.utils.MathUtils; import net.countercraft.movecraft.craft.CraftManager; import net.countercraft.movecraft.localisation.I18nSupport; @@ -22,7 +24,7 @@ public final void onSignClick(PlayerInteractEvent event) { return; } Block block = event.getClickedBlock(); - if (block.getType() != Material.SIGN_POST && block.getType() != Material.WALL_SIGN){ + if (block.getType() != (Settings.IsLegacy ? LegacyUtils.SIGN_POST : Material.SIGN) && block.getType() != Material.WALL_SIGN){ return; } Sign sign = (Sign) event.getClickedBlock().getState(); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/AscendSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/AscendSign.java index d8dfb61c4..7c981b969 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/AscendSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/AscendSign.java @@ -1,10 +1,12 @@ package net.countercraft.movecraft.sign; import net.countercraft.movecraft.MovecraftLocation; +import net.countercraft.movecraft.config.Settings; import net.countercraft.movecraft.craft.Craft; import net.countercraft.movecraft.craft.CraftManager; import net.countercraft.movecraft.events.CraftDetectEvent; import net.countercraft.movecraft.events.CraftPilotEvent; +import net.countercraft.movecraft.utils.LegacyUtils; import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.Material; @@ -23,7 +25,7 @@ public void onCraftDetect(CraftDetectEvent event){ World world = event.getCraft().getW(); for(MovecraftLocation location: event.getCraft().getHitBox()){ Block block = location.toBukkit(world).getBlock(); - if(block.getType() == Material.WALL_SIGN || block.getType() == Material.SIGN_POST){ + if(block.getType() == Material.WALL_SIGN || block.getType() == (Settings.IsLegacy ? LegacyUtils.SIGN_POST : Material.SIGN)){ Sign sign = (Sign) block.getState(); if (ChatColor.stripColor(sign.getLine(0)).equalsIgnoreCase("Ascend: ON")) { sign.setLine(0, "Ascend: OFF"); @@ -40,7 +42,7 @@ public void onSignClickEvent(PlayerInteractEvent event){ return; } Block block = event.getClickedBlock(); - if (block.getType() != Material.SIGN_POST && block.getType() != Material.WALL_SIGN){ + if (block.getType() != (Settings.IsLegacy ? LegacyUtils.SIGN_POST : Material.SIGN) && block.getType() != Material.WALL_SIGN){ return; } Sign sign = (Sign) event.getClickedBlock().getState(); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CannonDirectorSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CannonDirectorSign.java index cb2eae768..0a3857e7f 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CannonDirectorSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CannonDirectorSign.java @@ -1,6 +1,8 @@ package net.countercraft.movecraft.sign; +import net.countercraft.movecraft.config.Settings; import net.countercraft.movecraft.craft.Craft; +import net.countercraft.movecraft.utils.LegacyUtils; import net.countercraft.movecraft.utils.MathUtils; import net.countercraft.movecraft.craft.CraftManager; import net.countercraft.movecraft.localisation.I18nSupport; @@ -22,7 +24,7 @@ public final void onSignClick(PlayerInteractEvent event) { return; } Block block = event.getClickedBlock(); - if (block.getType() != Material.SIGN_POST && block.getType() != Material.WALL_SIGN) { + if (block.getType() != (Settings.IsLegacy ? LegacyUtils.SIGN_POST : Material.SIGN) && block.getType() != Material.WALL_SIGN) { return; } Sign sign = (Sign) event.getClickedBlock().getState(); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/ContactsSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/ContactsSign.java index f73e28ab3..2c5f22c90 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/ContactsSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/ContactsSign.java @@ -1,10 +1,12 @@ package net.countercraft.movecraft.sign; import net.countercraft.movecraft.MovecraftLocation; +import net.countercraft.movecraft.config.Settings; import net.countercraft.movecraft.craft.Craft; import net.countercraft.movecraft.events.CraftDetectEvent; import net.countercraft.movecraft.events.SignTranslateEvent; import net.countercraft.movecraft.craft.CraftManager; +import net.countercraft.movecraft.utils.LegacyUtils; import org.bukkit.ChatColor; import org.bukkit.Material; import org.bukkit.World; @@ -20,7 +22,7 @@ public void onCraftDetect(CraftDetectEvent event){ World world = event.getCraft().getW(); for(MovecraftLocation location: event.getCraft().getHitBox()){ Block block = location.toBukkit(world).getBlock(); - if(block.getType() == Material.WALL_SIGN || block.getType() == Material.SIGN_POST){ + if(block.getType() == Material.WALL_SIGN || block.getType() == (Settings.IsLegacy ? LegacyUtils.SIGN_POST : Material.SIGN)){ Sign sign = (Sign) block.getState(); if (ChatColor.stripColor(sign.getLine(0)).equalsIgnoreCase("Contacts:")) { sign.setLine(1, ""); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CraftSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CraftSign.java index 905db228c..6cbe5ab8e 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CraftSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CraftSign.java @@ -8,6 +8,7 @@ import net.countercraft.movecraft.craft.CraftManager; import net.countercraft.movecraft.craft.ICraft; import net.countercraft.movecraft.localisation.I18nSupport; +import net.countercraft.movecraft.utils.LegacyUtils; import org.bukkit.ChatColor; import org.bukkit.Location; import org.bukkit.Material; @@ -43,7 +44,7 @@ public final void onSignClick(PlayerInteractEvent event) { return; } Block block = event.getClickedBlock(); - if (block.getType() != Material.SIGN_POST && block.getType() != Material.WALL_SIGN) { + if (block.getType() != (Settings.IsLegacy ? LegacyUtils.SIGN_POST : Material.SIGN) && block.getType() != Material.WALL_SIGN) { return; } Sign sign = (Sign) event.getClickedBlock().getState(); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CrewSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CrewSign.java index 85e7be8c9..fde7913ed 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CrewSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CrewSign.java @@ -8,6 +8,7 @@ import net.countercraft.movecraft.events.CraftDetectEvent; import net.countercraft.movecraft.events.SignTranslateEvent; import net.countercraft.movecraft.config.Settings; +import net.countercraft.movecraft.utils.LegacyUtils; import org.bukkit.*; import org.bukkit.block.Block; import org.bukkit.block.Sign; @@ -20,8 +21,15 @@ import org.bukkit.event.player.PlayerInteractEvent; import org.bukkit.event.player.PlayerRespawnEvent; -public class CrewSign implements Listener { +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +public class CrewSign implements Listener { + //As of 1.13, each bed color have their own values + final Material[] beds = !Settings.IsLegacy ? new Material[]{Material.CYAN_BED, Material.BLACK_BED, Material.BLUE_BED, + Material.BROWN_BED, Material.GRAY_BED, Material.GREEN_BED, Material.LIGHT_BLUE_BED, Material.LIGHT_GRAY_BED, Material.LIME_BED, Material.MAGENTA_BED, + Material.ORANGE_BED, Material.PINK_BED, Material.PURPLE_BED, Material.RED_BED, Material.WHITE_BED, Material.YELLOW_BED} : null; @EventHandler public final void onSignChange(SignChangeEvent event) { if (!event.getLine(0).equalsIgnoreCase("Crew:")) { @@ -43,7 +51,7 @@ public final void onSignTranslate(SignTranslateEvent event) { return; } Location location = event.getBlock().getLocation().subtract(0,1,0); - if (!craft.getW().getBlockAt(location).getType().equals(Material.BED_BLOCK)) { + if (Settings.IsLegacy ? !craft.getW().getBlockAt(location).getType().equals(LegacyUtils.BED_BLOCK) : Arrays.binarySearch(beds, craft.getW().getBlockAt(location).getType()) < 0) { return; } craft.getCrewSigns().put(crewPlayer.getUniqueId(), location); @@ -62,7 +70,7 @@ public final void onSignRightClick(PlayerInteractEvent event) { if (!sign.getLine(0).equalsIgnoreCase("Crew:")) { return; } - if (!sign.getBlock().getRelative(0,-1,0).getType().equals(Material.BED_BLOCK)) { + if (Settings.IsLegacy ? !sign.getBlock().getRelative(0,-1,0).getType().equals(LegacyUtils.BED_BLOCK) : Arrays.binarySearch(beds, sign.getBlock().getRelative(0,-1,0).getType()) < 0) { player.sendMessage("You need to have a bed below your crew sign"); return; } @@ -103,7 +111,7 @@ public void onCraftDetect(CraftDetectEvent event){ World world = event.getCraft().getW(); for(MovecraftLocation location: event.getCraft().getHitBox()){ Block block = location.toBukkit(world).getBlock(); - if (block.getType() != Material.WALL_SIGN && block.getType() != Material.SIGN_POST) { + if (block.getType() != Material.WALL_SIGN && block.getType() != (Settings.IsLegacy ? LegacyUtils.SIGN_POST : Material.SIGN)) { continue; } Sign sign = (Sign) block.getState(); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CruiseSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CruiseSign.java index 31d5d4044..73c539dc8 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CruiseSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CruiseSign.java @@ -6,6 +6,7 @@ import net.countercraft.movecraft.craft.CraftManager; import net.countercraft.movecraft.events.CraftDetectEvent; import net.countercraft.movecraft.localisation.I18nSupport; +import net.countercraft.movecraft.utils.LegacyUtils; import org.bukkit.ChatColor; import org.bukkit.Material; import org.bukkit.World; @@ -26,7 +27,7 @@ public void onCraftDetect(CraftDetectEvent event){ World world = event.getCraft().getW(); for(MovecraftLocation location: event.getCraft().getHitBox()){ Block block = location.toBukkit(world).getBlock(); - if(block.getType() == Material.WALL_SIGN || block.getType() == Material.SIGN_POST){ + if(block.getType() == Material.WALL_SIGN || block.getType() == (Settings.IsLegacy ? LegacyUtils.SIGN_POST : Material.SIGN)){ Sign sign = (Sign) block.getState(); if (ChatColor.stripColor(sign.getLine(0)).equalsIgnoreCase("Cruise: ON")) { sign.setLine(0, "Cruise: OFF"); @@ -42,7 +43,7 @@ public final void onSignClick(PlayerInteractEvent event) { return; } Block block = event.getClickedBlock(); - if (block.getType() != Material.SIGN_POST && block.getType() != Material.WALL_SIGN) { + if (block.getType() != (Settings.IsLegacy ? LegacyUtils.SIGN_POST : Material.SIGN) && block.getType() != Material.WALL_SIGN) { return; } Sign sign = (Sign) event.getClickedBlock().getState(); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/DescendSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/DescendSign.java index 32c48fb3f..e4ae30a80 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/DescendSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/DescendSign.java @@ -1,9 +1,11 @@ package net.countercraft.movecraft.sign; import net.countercraft.movecraft.MovecraftLocation; +import net.countercraft.movecraft.config.Settings; import net.countercraft.movecraft.craft.Craft; import net.countercraft.movecraft.craft.CraftManager; import net.countercraft.movecraft.events.CraftDetectEvent; +import net.countercraft.movecraft.utils.LegacyUtils; import org.bukkit.ChatColor; import org.bukkit.Material; import org.bukkit.World; @@ -21,7 +23,7 @@ public void onCraftDetect(CraftDetectEvent event){ World world = event.getCraft().getW(); for(MovecraftLocation location: event.getCraft().getHitBox()){ Block block = location.toBukkit(world).getBlock(); - if(block.getType() == Material.WALL_SIGN || block.getType() == Material.SIGN_POST){ + if(block.getType() == Material.WALL_SIGN || block.getType() == (Settings.IsLegacy ? LegacyUtils.SIGN_POST : Material.SIGN)){ Sign sign = (Sign) block.getState(); if (ChatColor.stripColor(sign.getLine(0)).equalsIgnoreCase("Descend: ON")) { sign.setLine(0, "Descend: OFF"); @@ -37,7 +39,7 @@ public final void onSignClick(PlayerInteractEvent event) { return; } Block block = event.getClickedBlock(); - if (block.getType() != Material.SIGN_POST && block.getType() != Material.WALL_SIGN) { + if (block.getType() != (Settings.IsLegacy ? LegacyUtils.SIGN_POST : Material.SIGN) && block.getType() != Material.WALL_SIGN) { return; } Sign sign = (Sign) event.getClickedBlock().getState(); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/HelmSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/HelmSign.java index f9c53b0df..0913ba4e7 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/HelmSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/HelmSign.java @@ -1,7 +1,9 @@ package net.countercraft.movecraft.sign; import net.countercraft.movecraft.Rotation; +import net.countercraft.movecraft.config.Settings; import net.countercraft.movecraft.craft.Craft; +import net.countercraft.movecraft.utils.LegacyUtils; import net.countercraft.movecraft.utils.MathUtils; import net.countercraft.movecraft.craft.CraftManager; import net.countercraft.movecraft.localisation.I18nSupport; @@ -38,7 +40,7 @@ public final void onSignClick(PlayerInteractEvent event) { return; } Block block = event.getClickedBlock(); - if (block.getType() != Material.SIGN_POST && block.getType() != Material.WALL_SIGN) { + if (block.getType() != (Settings.IsLegacy ? LegacyUtils.SIGN_POST : Material.SIGN) && block.getType() != Material.WALL_SIGN) { return; } Sign sign = (Sign) event.getClickedBlock().getState(); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/MoveSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/MoveSign.java index b068a8da7..971ee57b8 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/MoveSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/MoveSign.java @@ -1,7 +1,9 @@ package net.countercraft.movecraft.sign; +import net.countercraft.movecraft.config.Settings; import net.countercraft.movecraft.craft.CraftManager; import net.countercraft.movecraft.localisation.I18nSupport; +import net.countercraft.movecraft.utils.LegacyUtils; import org.bukkit.ChatColor; import org.bukkit.Material; import org.bukkit.block.Block; @@ -20,7 +22,7 @@ public final void onSignClick(PlayerInteractEvent event) { return; } Block block = event.getClickedBlock(); - if (block.getType() != Material.SIGN_POST && block.getType() != Material.WALL_SIGN) { + if (block.getType() != (Settings.IsLegacy ? LegacyUtils.SIGN_POST : Material.SIGN) && block.getType() != Material.WALL_SIGN) { return; } Sign sign = (Sign) event.getClickedBlock().getState(); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/NameSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/NameSign.java index 31ef8520f..692859193 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/NameSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/NameSign.java @@ -5,6 +5,7 @@ import net.countercraft.movecraft.craft.Craft; import net.countercraft.movecraft.events.CraftDetectEvent; import net.countercraft.movecraft.utils.ChatUtils; +import net.countercraft.movecraft.utils.LegacyUtils; import org.bukkit.Material; import org.bukkit.World; import org.bukkit.block.Block; @@ -22,7 +23,7 @@ public void onCraftDetect(@NotNull CraftDetectEvent event){ World w = c.getW(); for (MovecraftLocation location : event.getCraft().getHitBox()){ Block b = location.toBukkit(w).getBlock(); - if (b.getType() == Material.SIGN_POST || b.getType() == Material.WALL_SIGN){ + if (b.getType() == (Settings.IsLegacy ? LegacyUtils.SIGN_POST : Material.SIGN) || b.getType() == Material.WALL_SIGN){ Sign s = (Sign) b.getState(); String name = ""; if (s.getLine(0).equalsIgnoreCase(HEADER)){ @@ -43,12 +44,13 @@ public void onCraftDetect(@NotNull CraftDetectEvent event){ } @EventHandler public void onSignChange(SignChangeEvent event){ - if (event.getLine(0).equalsIgnoreCase(HEADER)){ - if (Settings.RequireNamePerm && !event.getPlayer().hasPermission("movecraft.name")){ - event.getPlayer().sendMessage(ChatUtils.MOVECRAFT_COMMAND_PREFIX + "Insufficient permissions"); - event.setCancelled(true); - return; - } + if (!event.getLine(0).equalsIgnoreCase(HEADER)){ + return; + } + if (Settings.RequireNamePerm && !event.getPlayer().hasPermission("movecraft.name")){ + event.getPlayer().sendMessage(ChatUtils.MOVECRAFT_COMMAND_PREFIX + "Insufficient permissions"); + event.setCancelled(true); + return; } } } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RelativeMoveSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RelativeMoveSign.java index f608389e2..33dca6688 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RelativeMoveSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RelativeMoveSign.java @@ -1,7 +1,9 @@ package net.countercraft.movecraft.sign; +import net.countercraft.movecraft.config.Settings; import net.countercraft.movecraft.craft.CraftManager; import net.countercraft.movecraft.localisation.I18nSupport; +import net.countercraft.movecraft.utils.LegacyUtils; import org.bukkit.ChatColor; import org.bukkit.Material; import org.bukkit.block.Block; @@ -20,7 +22,7 @@ public final void onSignClick(PlayerInteractEvent event) { return; } Block block = event.getClickedBlock(); - if (block.getType() != Material.SIGN_POST && block.getType() != Material.WALL_SIGN) { + if (block.getType() != (Settings.IsLegacy ? LegacyUtils.SIGN_POST : Material.SIGN) && block.getType() != Material.WALL_SIGN) { return; } Sign sign = (Sign) event.getClickedBlock().getState(); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/ReleaseSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/ReleaseSign.java index b1ef8d914..a30fe54a1 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/ReleaseSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/ReleaseSign.java @@ -1,7 +1,9 @@ package net.countercraft.movecraft.sign; +import net.countercraft.movecraft.config.Settings; import net.countercraft.movecraft.craft.Craft; import net.countercraft.movecraft.craft.CraftManager; +import net.countercraft.movecraft.utils.LegacyUtils; import org.bukkit.ChatColor; import org.bukkit.Material; import org.bukkit.block.Block; @@ -20,7 +22,7 @@ public final void onSignClick(PlayerInteractEvent event) { return; } Block block = event.getClickedBlock(); - if (block.getType() != Material.SIGN_POST && block.getType() != Material.WALL_SIGN) { + if (block.getType() != (Settings.IsLegacy ? LegacyUtils.SIGN_POST : Material.SIGN) && block.getType() != Material.WALL_SIGN) { return; } Sign sign = (Sign) event.getClickedBlock().getState(); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RemoteSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RemoteSign.java index 4fe3c8f3f..3580ccb8b 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RemoteSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RemoteSign.java @@ -1,5 +1,7 @@ package net.countercraft.movecraft.sign; +import net.countercraft.movecraft.config.Settings; +import net.countercraft.movecraft.utils.LegacyUtils; import net.countercraft.movecraft.utils.MathUtils; import net.countercraft.movecraft.MovecraftLocation; import net.countercraft.movecraft.craft.Craft; @@ -25,7 +27,7 @@ public final void onSignClick(PlayerInteractEvent event) { return; } Block block = event.getClickedBlock(); - if (block.getType() != Material.SIGN_POST && block.getType() != Material.WALL_SIGN) { + if (block.getType() != (Settings.IsLegacy ? LegacyUtils.SIGN_POST : Material.SIGN) && block.getType() != Material.WALL_SIGN) { return; } Sign sign = (Sign) event.getClickedBlock().getState(); @@ -63,7 +65,7 @@ public final void onSignClick(PlayerInteractEvent event) { LinkedList foundLocations = new LinkedList(); for (MovecraftLocation tloc : foundCraft.getHitBox()) { Block tb = event.getClickedBlock().getWorld().getBlockAt(tloc.getX(), tloc.getY(), tloc.getZ()); - if (!tb.getType().equals(Material.SIGN_POST) && !tb.getType().equals(Material.WALL_SIGN)) { + if (!tb.getType().equals((Settings.IsLegacy ? LegacyUtils.SIGN_POST : Material.SIGN)) && !tb.getType().equals(Material.WALL_SIGN)) { continue; } Sign ts = (Sign) tb.getState(); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RepairSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RepairSign.java index 3ab7d3435..1590ff436 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RepairSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RepairSign.java @@ -1,7 +1,264 @@ package net.countercraft.movecraft.sign; +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.blocks.BaseBlock; +import com.sk89q.worldedit.extent.clipboard.Clipboard; +import com.sk89q.worldedit.world.block.BlockStateHolder; +import net.countercraft.movecraft.Movecraft; +import net.countercraft.movecraft.MovecraftLocation; +import net.countercraft.movecraft.MovecraftRepair; +import net.countercraft.movecraft.config.Settings; +import net.countercraft.movecraft.craft.Craft; +import net.countercraft.movecraft.craft.CraftManager; +import net.countercraft.movecraft.localisation.I18nSupport; +import net.countercraft.movecraft.mapUpdater.update.UpdateCommand; +import net.countercraft.movecraft.mapUpdater.update.WorldEditUpdateCommand; +import net.countercraft.movecraft.repair.Repair; +import net.countercraft.movecraft.repair.RepairManager; +import net.countercraft.movecraft.utils.LegacyUtils; +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.Material; +import org.bukkit.World; +import org.bukkit.block.Block; +import org.bukkit.block.Sign; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; +import org.bukkit.event.block.Action; +import org.bukkit.event.block.SignChangeEvent; +import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.inventory.InventoryHolder; +import org.bukkit.inventory.ItemStack; + +import java.util.*; public class RepairSign implements Listener{ + private String HEADER = "Repair:"; + private HashMap playerInteractTimeMap = new HashMap<>();//Players must be assigned by the UUID, or NullPointerExceptions are thrown + private final Material[] fragileBlocks = new Material[]{ Material.TORCH, Material.LADDER, Material.WALL_SIGN, Material.LEVER, Material.STONE_BUTTON, LegacyUtils.TRAP_DOOR, Material.TRIPWIRE_HOOK, LegacyUtils.WOOD_BUTTON, Material.IRON_TRAPDOOR, }; + //final int[] fragileBlocks = new int[]{ 171, 323, 324, 330, 331, 356, 404}; + + @EventHandler + public void onSignChange(SignChangeEvent event){ + if (!event.getLine(0).equalsIgnoreCase(HEADER)){ + return; + } + if (event.getLine(1).isEmpty()){ + event.getPlayer().sendMessage("You must specify a repair state name on second line"); + event.setCancelled(true); + return; + } + } + + @EventHandler + public void onSignClick(PlayerInteractEvent event){ + String firstLine = ""; + if (event.getAction() == Action.RIGHT_CLICK_BLOCK || event.getAction() == Action.LEFT_CLICK_BLOCK) { + Material m = event.getClickedBlock().getType(); + if (m.equals((Settings.IsLegacy ? LegacyUtils.SIGN_POST : Material.SIGN)) || m.equals(Material.WALL_SIGN)) { + Sign sign = (Sign) event.getClickedBlock().getState(); + String signText = ChatColor.stripColor(sign.getLine(0)); + + if (signText == null) { + return; + } + } + } + if (event.getAction() == Action.RIGHT_CLICK_BLOCK) { + Material m = event.getClickedBlock().getType(); + if (m.equals((Settings.IsLegacy ? LegacyUtils.SIGN_POST : Material.SIGN)) || m.equals(Material.WALL_SIGN)) { + + signRightClick(event); + } + return; + } + if (event.getAction() == Action.LEFT_CLICK_BLOCK) { + Material m = event.getClickedBlock().getType(); + if (m == (Settings.IsLegacy ? LegacyUtils.SIGN_POST : Material.SIGN) || m == Material.WALL_SIGN) { + + signLeftClick(event); + + } + } + } + // + private void signLeftClick(PlayerInteractEvent event){ + + Sign sign = (Sign) event.getClickedBlock().getState(); + if (!sign.getLine(0).equalsIgnoreCase(HEADER) || sign.getLine(0) == null){ + return; + } + String repairName = event.getPlayer().getName(); + repairName += "_"; + repairName += sign.getLine(1); + if (Settings.RepairTicksPerBlock == 0) { + event.getPlayer().sendMessage(I18nSupport.getInternationalisedString("Repair functionality is disabled or WorldEdit was not detected")); + return; + } + Craft pCraft = CraftManager.getInstance().getCraftByPlayer(event.getPlayer()); + if (pCraft == null) { + event.getPlayer().sendMessage(I18nSupport.getInternationalisedString("You must be piloting a craft")); + return; + } + MovecraftRepair movecraftRepair = Movecraft.getInstance().getMovecraftRepair(); + movecraftRepair.saveCraftRepairState(pCraft, sign, Movecraft.getInstance(), repairName); + event.setCancelled(true); + + } + private void signRightClick(PlayerInteractEvent event){ + Sign sign = (Sign) event.getClickedBlock().getState(); + World world = sign.getWorld(); + Player p = event.getPlayer(); + Craft pCraft = CraftManager.getInstance().getCraftByPlayer(p); + if (!sign.getLine(0).equalsIgnoreCase(HEADER)){ + return; + } + if (pCraft == null){ + event.getPlayer().sendMessage(I18nSupport.getInternationalisedString("You must be piloting a craft")); + return; + } + if (Settings.RepairTicksPerBlock == 0) { + event.getPlayer().sendMessage(I18nSupport.getInternationalisedString("Repair functionality is disabled or WorldEdit was not detected")); + return; + } + String repairName = event.getPlayer().getName(); + repairName += "_"; + repairName += sign.getLine(1); + MovecraftRepair movecraftRepair = Movecraft.getInstance().getMovecraftRepair(); + Clipboard clipboard = movecraftRepair.loadCraftRepairStateClipboard(Movecraft.getInstance(), sign, repairName, world); + + + if (clipboard == null){ + p.sendMessage(I18nSupport.getInternationalisedString("REPAIR STATE NOT FOUND")); + return; + } else { //if clipboard is not null + long numDifferentBlocks = movecraftRepair.getNumDiffBlocks(repairName); + boolean secondClick = false; + if (!playerInteractTimeMap.isEmpty()) { + if (System.currentTimeMillis() - playerInteractTimeMap.get(p.getUniqueId()) < 5000) { + secondClick = true; + } + } + HashMap numMissingItems = movecraftRepair.getMissingBlocks(repairName); + HashSet locMissingBlocks = movecraftRepair.getMissingBlockLocations(repairName); + int totalSize = locMissingBlocks.size() + pCraft.getHitBox().size(); + + if (secondClick){ + // check all the chests for materials for the repair + HashMap> chestsToTakeFrom = new HashMap<>(); // typeid, list of chest inventories + boolean enoughMaterial = true; + for (Material type : numMissingItems.keySet()) { + long longRemQty = Math.round(numMissingItems.get(type)); + int remainingQty = (int) longRemQty; + ArrayList chests = new ArrayList<>(); + for (MovecraftLocation loc : pCraft.getHitBox()) { + Block b = pCraft.getW().getBlockAt(loc.getX(), loc.getY(), loc.getZ()); + if ((b.getType() == Material.CHEST) || (b.getType() == Material.TRAPPED_CHEST)) { + InventoryHolder inventoryHolder = (InventoryHolder) b.getState(); + if (inventoryHolder.getInventory().contains(type) && remainingQty > 0) { + HashMap foundItems = inventoryHolder.getInventory().all(type); + // count how many were in the chest + int numfound = 0; + for (ItemStack istack : foundItems.values()) { + numfound += istack.getAmount(); + } + remainingQty -= numfound; + chests.add(inventoryHolder); + } + } + } + if (remainingQty > 0) { + event.getPlayer().sendMessage(String.format(I18nSupport.getInternationalisedString("Need more of material") + ": %s - %d", type.name().toLowerCase().replace("_", " "), remainingQty)); + enoughMaterial = false; + } else { + chestsToTakeFrom.put(type, chests); + } + } + if (Movecraft.getInstance().getEconomy() != null && enoughMaterial) { + double moneyCost = numDifferentBlocks * Settings.RepairMoneyPerBlock; + if (Movecraft.getInstance().getEconomy().has(event.getPlayer(), moneyCost)) { + Movecraft.getInstance().getEconomy().withdrawPlayer(event.getPlayer(), moneyCost); + } else { + event.getPlayer().sendMessage(I18nSupport.getInternationalisedString("You do not have enough money")); + enoughMaterial = false; + } + } + if (enoughMaterial) { + // we know we have enough materials to make the repairs, so remove the materials from the chests + for (Material type : numMissingItems.keySet()) { + int remainingQty = (int) Math.round(numMissingItems.get(type)); + for (InventoryHolder inventoryHolder : chestsToTakeFrom.get(type)) { + HashMap foundItems = inventoryHolder.getInventory().all(type); + for (ItemStack istack : foundItems.values()) { + if (istack.getAmount() <= remainingQty) { + remainingQty -= istack.getAmount(); + inventoryHolder.getInventory().removeItem(istack); + } else { + istack.setAmount(istack.getAmount() - remainingQty); + remainingQty = 0; + } + } + + } + } + + double Cost = numDifferentBlocks * Settings.RepairMoneyPerBlock; + Bukkit.getLogger().info(event.getPlayer().getName() + " has begun a repair with the cost of " + String.valueOf(Cost)); + final LinkedList updateCommands = new LinkedList<>(); + final LinkedList updateCommandsFragileBlocks = new LinkedList<>(); + final Vector distToOffset = movecraftRepair.getDistanceFromSignToLowestPoint(clipboard, sign.getLine(1)); + final Vector offsetFromSign = new Vector(sign.getLocation().getBlockX() - distToOffset.getBlockX(), sign.getLocation().getBlockY() - distToOffset.getBlockY(), sign.getLocation().getBlockZ() - distToOffset.getBlockZ()); + final Vector distance = new Vector(offsetFromSign.getBlockX() - clipboard.getMinimumPoint().getBlockX(), offsetFromSign.getBlockY() - clipboard.getMinimumPoint().getBlockY(), offsetFromSign.getBlockZ() - clipboard.getMinimumPoint().getBlockZ()); + final TreeSet sortedLocMissingBlocks = new TreeSet<>(locMissingBlocks); + for (Vector cLoc : sortedLocMissingBlocks){ + + MovecraftLocation moveLoc = new MovecraftLocation(cLoc.getBlockX() + distance.getBlockX(), cLoc.getBlockY() + distance.getBlockY(), cLoc.getBlockZ() + distance.getBlockZ()); + //To avoid any issues during the repair, keep certain blocks in different linked lists + if (Settings.IsLegacy) { + BaseBlock baseBlock = clipboard.getBlock(cLoc); + if (Arrays.binarySearch(fragileBlocks, LegacyUtils.getMaterial(baseBlock.getType())) >= 0) { + WorldEditUpdateCommand updateCommand = new WorldEditUpdateCommand(baseBlock, sign.getWorld(), moveLoc, LegacyUtils.getMaterial(baseBlock.getType()), (byte) baseBlock.getData()); + updateCommandsFragileBlocks.add(updateCommand); + } else { + WorldEditUpdateCommand updateCommand = new WorldEditUpdateCommand(baseBlock, sign.getWorld(), moveLoc, LegacyUtils.getMaterial(baseBlock.getType()), (byte) baseBlock.getData()); + updateCommands.add(updateCommand); + } + } else { + BlockStateHolder bsHolder; + + } + + } + if (updateCommands.size() > 0) { + final Craft releaseCraft = pCraft; + CraftManager.getInstance().removePlayerFromCraft(pCraft); + RepairManager repairManager = Movecraft.getInstance().getRepairManager(); + repairManager.getRepairs().add(new Repair(sign.getLine(1), releaseCraft, updateCommands, updateCommandsFragileBlocks, p.getUniqueId(), numDifferentBlocks, sign.getLocation())); + } + + } + } else { + float percent = ((float) numDifferentBlocks / (float) totalSize) * 100; + p.sendMessage(I18nSupport.getInternationalisedString("Total damaged blocks") + ": " + numDifferentBlocks); + p.sendMessage(I18nSupport.getInternationalisedString("Percentage of craft") + ": " + percent); + if (percent > Settings.RepairMaxPercent){ + p.sendMessage(I18nSupport.getInternationalisedString("This craft is too damaged and can not be repaired")); + return; + } + if (numDifferentBlocks != 0) { + event.getPlayer().sendMessage(I18nSupport.getInternationalisedString("SUPPLIES NEEDED")); + for (Material blockType : numMissingItems.keySet()) { + event.getPlayer().sendMessage(String.format("%s : %d", blockType.name().toLowerCase().replace("_", " "), Math.round(numMissingItems.get(blockType)))); + } + long durationInSeconds = numDifferentBlocks * Settings.RepairTicksPerBlock / 20; + event.getPlayer().sendMessage(String.format(I18nSupport.getInternationalisedString("Seconds to complete repair") + ": %d", durationInSeconds)); + int moneyCost = (int) (numDifferentBlocks * Settings.RepairMoneyPerBlock); + event.getPlayer().sendMessage(String.format(I18nSupport.getInternationalisedString("Money to complete repair") + ": %d", moneyCost)); + playerInteractTimeMap.put(event.getPlayer().getUniqueId(), System.currentTimeMillis()); + } + } + } + } } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/SpeedSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/SpeedSign.java index cb1248a56..3d5f16361 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/SpeedSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/SpeedSign.java @@ -1,9 +1,11 @@ package net.countercraft.movecraft.sign; import net.countercraft.movecraft.MovecraftLocation; +import net.countercraft.movecraft.config.Settings; import net.countercraft.movecraft.craft.Craft; import net.countercraft.movecraft.events.CraftDetectEvent; import net.countercraft.movecraft.events.SignTranslateEvent; +import net.countercraft.movecraft.utils.LegacyUtils; import org.bukkit.ChatColor; import org.bukkit.Material; import org.bukkit.World; @@ -18,7 +20,7 @@ public void onCraftDetect(CraftDetectEvent event){ World world = event.getCraft().getW(); for(MovecraftLocation location: event.getCraft().getHitBox()){ Block block = location.toBukkit(world).getBlock(); - if(block.getType() == Material.WALL_SIGN || block.getType() == Material.SIGN_POST){ + if(block.getType() == Material.WALL_SIGN || block.getType() == (Settings.IsLegacy ? LegacyUtils.SIGN_POST : Material.SIGN)){ Sign sign = (Sign) block.getState(); if (ChatColor.stripColor(sign.getLine(0)).equalsIgnoreCase("Speed:")) { sign.setLine(1, "0 m/s"); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/StatusSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/StatusSign.java index 03e31b229..cddcb1b80 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/StatusSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/StatusSign.java @@ -1,9 +1,11 @@ package net.countercraft.movecraft.sign; import net.countercraft.movecraft.MovecraftLocation; +import net.countercraft.movecraft.config.Settings; import net.countercraft.movecraft.craft.Craft; import net.countercraft.movecraft.events.CraftDetectEvent; import net.countercraft.movecraft.events.SignTranslateEvent; +import net.countercraft.movecraft.utils.LegacyUtils; import org.bukkit.ChatColor; import org.bukkit.Material; import org.bukkit.World; @@ -26,7 +28,7 @@ public void onCraftDetect(CraftDetectEvent event){ World world = event.getCraft().getW(); for(MovecraftLocation location: event.getCraft().getHitBox()){ Block block = location.toBukkit(world).getBlock(); - if(block.getType() == Material.WALL_SIGN || block.getType() == Material.SIGN_POST){ + if(block.getType() == Material.WALL_SIGN || block.getType() == (Settings.IsLegacy ? LegacyUtils.SIGN_POST : Material.SIGN)){ Sign sign = (Sign) block.getState(); if (ChatColor.stripColor(sign.getLine(0)).equalsIgnoreCase("Status:")) { sign.setLine(1, ""); @@ -46,54 +48,56 @@ public final void onSignTranslate(SignTranslateEvent event) { } int fuel=0; int totalBlocks=0; - Map foundBlocks = new HashMap<>(); + Map foundBlocks = new HashMap<>(); for (MovecraftLocation ml : craft.getHitBox()) { - Integer blockID = craft.getW().getBlockAt(ml.getX(), ml.getY(), ml.getZ()).getTypeId(); + Material blockType = craft.getW().getBlockAt(ml.getX(), ml.getY(), ml.getZ()).getType(); - if (foundBlocks.containsKey(blockID)) { - Integer count = foundBlocks.get(blockID); + if (foundBlocks.containsKey(blockType)) { + Integer count = foundBlocks.get(blockType); if (count == null) { - foundBlocks.put(blockID, 1); + foundBlocks.put(blockType, 1); } else { - foundBlocks.put(blockID, count + 1); + foundBlocks.put(blockType, count + 1); } } else { - foundBlocks.put(blockID, 1); + foundBlocks.put(blockType, 1); } - if (blockID == 61) { + if (blockType == Material.FURNACE) { InventoryHolder inventoryHolder = (InventoryHolder) craft.getW().getBlockAt(ml.getX(), ml.getY(), ml.getZ()).getState(); - if (inventoryHolder.getInventory().contains(263) - || inventoryHolder.getInventory().contains(173)) { + if (inventoryHolder.getInventory().contains(Material.COAL) + || inventoryHolder.getInventory().contains(Material.COAL_BLOCK) + || inventoryHolder.getInventory().contains(Material.CHARCOAL)) { ItemStack[] istack=inventoryHolder.getInventory().getContents(); for(ItemStack i : istack) { if(i!=null) { - if(i.getTypeId()==263) { + if(i.getType()== Material.COAL || i.getType() == Material.CHARCOAL) { fuel+=i.getAmount()*8; } - if(i.getTypeId()==173) { + if(i.getType()==Material.COAL_BLOCK) { fuel+=i.getAmount()*80; } } } } } - if (blockID != 0) { + if (blockType != Material.AIR || blockType != Material.CAVE_AIR || blockType != Material.VOID_AIR) { totalBlocks++; } } int signLine=1; int signColumn=0; - for(List alFlyBlockID : craft.getType().getFlyBlocks().keySet()) { - int flyBlockID=alFlyBlockID.get(0); - Double minimum=craft.getType().getFlyBlocks().get(alFlyBlockID).get(0); - if(foundBlocks.containsKey(flyBlockID) && minimum>0) { // if it has a minimum, it should be considered for sinking consideration - int amount=foundBlocks.get(flyBlockID); + for(Map> alFlyBlock : craft.getType().getFlyBlocks().keySet()) { + Material flyBlock = alFlyBlock.keySet().iterator().next(); + Double minimum=craft.getType().getFlyBlocks().get(alFlyBlock).get(0); + if(foundBlocks.containsKey(flyBlock) && minimum>0) { // if it has a minimum, it should be considered for sinking consideration + int amount=foundBlocks.get(flyBlock); Double percentPresent=(double) (amount*100/totalBlocks); + /* int deshiftedID=flyBlockID; if(deshiftedID>10000) { deshiftedID=(deshiftedID-10000)>>4; - } + }*/ String signText=""; if(percentPresent>minimum*1.04) { signText+= ChatColor.GREEN; @@ -102,12 +106,12 @@ public final void onSignTranslate(SignTranslateEvent event) { } else { signText+=ChatColor.RED; } - if(deshiftedID==152) { + if(flyBlock == Material.REDSTONE_BLOCK) { signText+="R"; - } else if(deshiftedID==42) { + } else if(flyBlock == Material.IRON_BLOCK) { signText+="I"; } else { - signText+= Material.getMaterial(deshiftedID).toString().charAt(0); + signText+= flyBlock.toString().charAt(0); } signText+=" "; @@ -118,7 +122,7 @@ public final void onSignTranslate(SignTranslateEvent event) { if(signColumn==0) { event.setLine(signLine,signText); signColumn++; - } else if(signLine<3) { + } else if(signLine < 3) { String existingLine=event.getLine(signLine); existingLine+=signText; event.setLine(signLine, existingLine); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/SubcraftRotateSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/SubcraftRotateSign.java index a9a8782df..e33ad8b9f 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/SubcraftRotateSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/SubcraftRotateSign.java @@ -3,6 +3,7 @@ import net.countercraft.movecraft.Movecraft; import net.countercraft.movecraft.MovecraftLocation; import net.countercraft.movecraft.Rotation; +import net.countercraft.movecraft.config.Settings; import net.countercraft.movecraft.craft.Craft; import net.countercraft.movecraft.craft.CraftManager; import net.countercraft.movecraft.craft.CraftType; @@ -11,6 +12,7 @@ import net.countercraft.movecraft.events.CraftReleaseEvent; import net.countercraft.movecraft.events.CraftRotateEvent; import net.countercraft.movecraft.localisation.I18nSupport; +import net.countercraft.movecraft.utils.LegacyUtils; import net.countercraft.movecraft.utils.MathUtils; import org.bukkit.ChatColor; import org.bukkit.Location; @@ -40,7 +42,7 @@ public final void onSignClick(PlayerInteractEvent event) { return; } Block block = event.getClickedBlock(); - if (block.getType() != Material.SIGN_POST && block.getType() != Material.WALL_SIGN) { + if (block.getType() != (Settings.IsLegacy ? LegacyUtils.SIGN_POST : Material.SIGN) && block.getType() != Material.WALL_SIGN) { return; } Sign sign = (Sign) event.getClickedBlock().getState(); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/TeleportSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/TeleportSign.java index 31fa2001f..e725f6529 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/TeleportSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/TeleportSign.java @@ -1,7 +1,9 @@ package net.countercraft.movecraft.sign; +import net.countercraft.movecraft.config.Settings; import net.countercraft.movecraft.craft.CraftManager; import net.countercraft.movecraft.localisation.I18nSupport; +import net.countercraft.movecraft.utils.LegacyUtils; import org.bukkit.ChatColor; import org.bukkit.Material; import org.bukkit.block.Block; @@ -19,7 +21,7 @@ public final void onSignClick(PlayerInteractEvent event) { return; } Block block = event.getClickedBlock(); - if (block.getType() != Material.SIGN_POST && block.getType() != Material.WALL_SIGN) { + if (block.getType() != (Settings.IsLegacy ? LegacyUtils.SIGN_POST : Material.SIGN) && block.getType() != Material.WALL_SIGN) { return; } Sign sign = (Sign) event.getClickedBlock().getState(); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/assault/Assault.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/assault/Assault.java index d15f581d8..3deb0f55a 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/assault/Assault.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/assault/Assault.java @@ -1,6 +1,6 @@ package net.countercraft.movecraft.warfare.assault; -import com.sk89q.worldedit.Vector; +import org.bukkit.util.Vector; import org.bukkit.Bukkit; import org.bukkit.World; import org.bukkit.boss.BarColor; diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/assault/AssaultTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/assault/AssaultTask.java index 9f209e91f..aee2233bb 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/assault/AssaultTask.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/assault/AssaultTask.java @@ -5,15 +5,12 @@ import com.sk89q.worldguard.protection.regions.ProtectedRegion; import net.countercraft.movecraft.Movecraft; import net.countercraft.movecraft.config.Settings; -import net.countercraft.movecraft.listener.WorldEditInteractListener; -import net.countercraft.movecraft.utils.ChatUtils; +import net.countercraft.movecraft.repair.RepairUtils; import org.bukkit.*; -import org.bukkit.block.Block; import org.bukkit.block.Sign; import org.bukkit.boss.BarColor; import org.bukkit.entity.Player; import org.bukkit.scheduler.BukkitRunnable; -import org.bukkit.util.Vector; import java.text.DecimalFormat; import java.util.UUID; @@ -143,7 +140,7 @@ public void run() { assert tRegion != null; tRegion.setFlag(DefaultFlag.TNT, StateFlag.State.DENY); // repair the damages that have occurred so far - if (!new WorldEditInteractListener().repairRegion(assault.getWorld(), assault.getRegionName())) { + if (!RepairUtils.repairRegion(assault.getRegionName(), assault.getWorld())) { Bukkit.getServer().broadcastMessage(String.format("REPAIR OF %s FAILED, CONTACT AN ADMIN", assault.getRegionName().toUpperCase())); } } @@ -154,6 +151,7 @@ public void run() { private static String getRegionOwnerList(ProtectedRegion tRegion) { + StringBuilder output = new StringBuilder(); if (tRegion == null) return ""; diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/assault/AssaultUtils.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/assault/AssaultUtils.java index 4bcbfc847..a22e010a7 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/assault/AssaultUtils.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/assault/AssaultUtils.java @@ -1,17 +1,41 @@ package net.countercraft.movecraft.warfare.assault; +import com.sk89q.worldguard.bukkit.WorldGuardPlugin; +import com.sk89q.worldguard.protection.ApplicableRegionSet; import com.sk89q.worldguard.protection.regions.ProtectedRegion; import net.countercraft.movecraft.Movecraft; import net.countercraft.movecraft.config.Settings; -import org.bukkit.Bukkit; -import org.bukkit.OfflinePlayer; +import net.countercraft.movecraft.utils.LegacyUtils; +import org.bukkit.*; +import org.bukkit.block.Block; +import org.bukkit.block.BlockFace; import org.bukkit.boss.BossBar; +import org.bukkit.entity.Player; +import org.bukkit.event.entity.EntityExplodeEvent; +import org.bukkit.scheduler.BukkitRunnable; -import java.util.HashSet; -import java.util.UUID; +import java.util.*; public class AssaultUtils { - + private static long lastDamagesUpdate = 0; + final static Material[] fragileBlocks = Settings.IsLegacy ? new Material[]{LegacyUtils.BED_BLOCK, LegacyUtils.PISTON_EXTENSION, Material.TORCH, Material.REDSTONE_WIRE, LegacyUtils.SIGN_POST, LegacyUtils.WOOD_DOOR, Material.LADDER, Material.WALL_SIGN, Material.LEVER, LegacyUtils.STONE_PLATE, LegacyUtils.IRON_DOOR_BLOCK, LegacyUtils.WOOD_PLATE, LegacyUtils.REDSTONE_TORCH_OFF, LegacyUtils.REDSTONE_TORCH_ON, Material.STONE_BUTTON, LegacyUtils.DIODE_BLOCK_OFF, LegacyUtils.DIODE_BLOCK_ON, LegacyUtils.TRAP_DOOR, Material.TRIPWIRE_HOOK, + Material.TRIPWIRE, LegacyUtils.WOOD_BUTTON, LegacyUtils.GOLD_PLATE, LegacyUtils.IRON_PLATE, LegacyUtils.REDSTONE_COMPARATOR_OFF, LegacyUtils.REDSTONE_COMPARATOR_ON, Material.DAYLIGHT_DETECTOR, LegacyUtils.CARPET, LegacyUtils.DAYLIGHT_DETECTOR_INVERTED, Material.SPRUCE_DOOR, Material.BIRCH_DOOR, Material.JUNGLE_DOOR, Material.ACACIA_DOOR, Material.DARK_OAK_DOOR} + : + new Material[] + //Beds + {Material.CYAN_BED, Material.BLACK_BED, Material.BLUE_BED, + Material.BROWN_BED, Material.GRAY_BED, Material.GREEN_BED, Material.LIGHT_BLUE_BED, Material.LIGHT_GRAY_BED, Material.LIME_BED, Material.MAGENTA_BED, + Material.ORANGE_BED, Material.PINK_BED, Material.PURPLE_BED, Material.RED_BED, Material.WHITE_BED, Material.YELLOW_BED, + //Redstone components + Material.REDSTONE_WIRE, Material.REPEATER, Material.COMPARATOR, Material.REDSTONE_TORCH, Material.REDSTONE_WALL_TORCH, Material.TRIPWIRE_HOOK, + //Pressure plates + Material.STONE_PRESSURE_PLATE, Material.ACACIA_PRESSURE_PLATE, Material.BIRCH_PRESSURE_PLATE, Material.DARK_OAK_PRESSURE_PLATE, Material.HEAVY_WEIGHTED_PRESSURE_PLATE, Material.LIGHT_WEIGHTED_PRESSURE_PLATE, Material.JUNGLE_PRESSURE_PLATE, Material.OAK_PRESSURE_PLATE, Material.SPRUCE_PRESSURE_PLATE, + //Buttons + Material.STONE_BUTTON, Material.BIRCH_BUTTON, Material.ACACIA_BUTTON, Material.DARK_OAK_BUTTON, Material.JUNGLE_BUTTON, Material.OAK_BUTTON, Material.SPRUCE_BUTTON, + //Doors + Material.SPRUCE_DOOR, Material.BIRCH_DOOR, Material.JUNGLE_DOOR, Material.ACACIA_DOOR, Material.DARK_OAK_DOOR, Material.OAK_DOOR, Material.IRON_DOOR, + //Trapdoors + Material.IRON_TRAPDOOR, Material.ACACIA_TRAPDOOR, Material.BIRCH_TRAPDOOR}; public static boolean areDefendersOnline(ProtectedRegion tRegion) { HashSet players = new HashSet<>(); players.addAll(tRegion.getMembers().getUniqueIds()); @@ -57,4 +81,76 @@ public static double getMaxDamages(ProtectedRegion tRegion) { } return total * (Settings.AssaultDamagesCapPercent / 100.0); } + + public static void processAssault(EntityExplodeEvent e){ + List assaults = Movecraft.getInstance().getAssaultManager() != null ? Movecraft.getInstance().getAssaultManager().getAssaults() : null; + if (assaults == null || assaults.size() == 0) { + return; + } + WorldGuardPlugin worldGuard = Movecraft.getInstance().getWorldGuardPlugin(); + for (final Assault assault : assaults) { + Iterator i = e.blockList().iterator(); + while (i.hasNext()) { + Block b = i.next(); + if (b.getWorld() != assault.getWorld()) + continue; + ApplicableRegionSet regions = worldGuard.getRegionManager(b.getWorld()).getApplicableRegions(b.getLocation()); + boolean isInAssaultRegion = false; + for (com.sk89q.worldguard.protection.regions.ProtectedRegion tregion : regions.getRegions()) { + if (assault.getRegionName().equals(tregion.getId())) { + isInAssaultRegion = true; + } + } + if (!isInAssaultRegion) + continue; + // first see if it is outside the destroyable area + org.bukkit.util.Vector min = assault.getMinPos(); + org.bukkit.util.Vector max = assault.getMaxPos(); + + if (b.getLocation().getBlockX() < min.getBlockX() || + b.getLocation().getBlockX() > max.getBlockX() || + b.getLocation().getBlockZ() < min.getBlockZ() || + b.getLocation().getBlockZ() > max.getBlockZ() || + !Settings.AssaultDestroyableBlocks.contains(b.getType()) || + Arrays.binarySearch(fragileBlocks, b.getRelative(BlockFace.SOUTH).getType()) >= 0 || + Arrays.binarySearch(fragileBlocks, b.getRelative(BlockFace.DOWN).getType()) >= 0 || + Arrays.binarySearch(fragileBlocks, b.getRelative(BlockFace.UP).getType()) >= 0 || + Arrays.binarySearch(fragileBlocks, b.getRelative(BlockFace.EAST).getType()) >= 0 || + Arrays.binarySearch(fragileBlocks, b.getRelative(BlockFace.WEST).getType()) >= 0 || + Arrays.binarySearch(fragileBlocks, b.getRelative(BlockFace.NORTH).getType()) >= 0 ) { + i.remove(); + } + + + // whether or not you actually destroyed the block, add to damages + long damages = assault.getDamages() + Settings.AssaultDamagesPerBlock; + //if (damages < assault.getMaxDamages()) { + assault.setDamages(damages); + //} + + // notify nearby players of the damages, do this 1 second later so all damages from this volley will be included + if (System.currentTimeMillis() < lastDamagesUpdate + 4000) { + continue; + } + final Location floc = b.getLocation(); + final World fworld = b.getWorld(); + new BukkitRunnable() { + @Override + public void run() { + long fdamages = assault.getDamages(); + for (Player p : fworld.getPlayers()) { + if (Math.round(p.getLocation().getBlockX() / 1000.0) == Math.round(floc.getBlockX() / 1000.0) && + Math.round(p.getLocation().getBlockZ() / 1000.0) == Math.round(floc.getBlockZ() / 1000.0)) { + p.sendMessage("Damages: " + fdamages); + + } + } + } + }.runTaskLater(Movecraft.getInstance(), 20); + lastDamagesUpdate = System.currentTimeMillis(); + + } + } + + } } diff --git a/modules/Movecraft/src/main/resources/plugin.yml b/modules/Movecraft/src/main/resources/plugin.yml index 4f48e16be..408f5470b 100644 --- a/modules/Movecraft/src/main/resources/plugin.yml +++ b/modules/Movecraft/src/main/resources/plugin.yml @@ -1,6 +1,7 @@ name: Movecraft -softdepend: [WorldGuard, WorldEdit, Cannons, Vault ,Essentials, WGCustomFlags, Towny] +softdepend: [WorldGuard, WorldEdit, FastAsyncWorldEdit, Cannons, Vault ,Essentials, WGCustomFlags, Towny] version: ${project.version} +api-version: 1.13 #version: ${env.BUILD_NUMBER} description: The original flight and movement plugin for minecraft. author: BaccaYarro diff --git a/modules/Movecraft/src/main/resources/types/BigAirship.craft b/modules/Movecraft/src/main/resources/types/BigAirship.craft index 79bc179a8..34b029b58 100644 --- a/modules/Movecraft/src/main/resources/types/BigAirship.craft +++ b/modules/Movecraft/src/main/resources/types/BigAirship.craft @@ -1,123 +1,227 @@ name: BigAirship maxSize: 20000 minSize: 10000 -allowedBlocks: - - 5 - - 8 - - 9 - - 10 - - 11 - - 17 - - 20 - - 22 - - 23 - - 25 - - 26 - - 29 - - 33 - - 34 - - 35 - - 41 - - 42 - - 43 - - 44 - - 47 - - 49 - - 50 - - 51 - - 53 - - 54 - - 55 - - 57 - - 58 - - 61 - - 62 - - 63 - - 64 - - 65 - - 68 - - 69 - - 70 - - 71 - - 72 - - 75 - - 76 - - 77 - - 82 - - 85 - - 87 - - 89 - - 92 - - 93 - - 94 - - 95 - - 96 - - 98 - - 101 - - 102 - - 107 - - 109 - - 112 - - 113 - - 114 - - 116 - - 117 - - 118 - - 121 - - 122 - - 123 - - 124 - - 125 - - 126 - - 130 - - 131 - - 133 - - 134 - - 135 - - 136 - - 138 - - 139 - - 140 - - 143 - - 144 - - 145 - - 146 - - 147 - - 148 - - 149 - - 150 - - 151 - - 152 - - 154 - - 155 - - 156 - - 157 - - 159 - - 160 - - 171 - - 172 - - 173 - - 165 - - 167 - - 183 - - 184 - - 185 - - 186 - - 187 - - 188 - - 189 - - 190 - - 191 - - 192 - - 193 - - 194 - - 195 - - 196 - - 197 - - 206 +allowedBlocks: + #beds + - WHITE_BED + - ORANGE_BED + - MAGENTA_BED + - LIGHT_BLUE_BED + - YELLOW_BED + - LIME_BED + - PINK_BED + - GRAY_BED + - LIGHT_BED + - CYAN_BED + - PURPLE_BED + - BLUE_BED + - BROWN_BED + - GREEN_BED + - RED_BED + - BLACK_BED + #buttons + - ACACIA_BUTTON + - BIRCH_BUTTON + - DARK_OAK_BUTTON + - JUNGLE_BUTTON + - OAK_BUTTON + - SPRUCE_BUTTON + - STONE_BUTTON + #doors + - ACACIA_DOOR + - BIRCH_DOOR + - DARK_OAK_DOOR + - IRON_DOOR + - JUNGLE_DOOR + - OAK_DOOR + - SPRUCE_DOOR + #fences + - ACACIA_FENCE + - BIRCH_FENCE + - DARK_OAK_FENCE + - JUNGLE_FENCE + - OAK_FENCE + - SPRUCE_FENCE + #fence gates + - ACACIA_FENCE_GATE + - BIRCH_FENCE_GATE + - DARK_OAK_FENCE_GATE + - JUNGLE_FENCE_GATE + - OAK_FENCE_GATE + - SPRUCE_FENCE_GATE + #glass + - GLASS + - WHITE_STAINED_GLASS + - ORANGE_STAINED_GLASS + - MAGENTA_STAINED_GLASS + - LIGHT_BLUE_STAINED_GLASS + - YELLOW_STAINED_GLASS + - LIME_STAINED_GLASS + - PINK_STAINED_GLASS + - GRAY_STAINED_GLASS + - LIGHT_GRAY_STAINED_GLASS + - CYAN_STAINED_GLASS + - PURPLE_STAINED_GLASS + - BLUE_STAINED_GLASS + - BROWN_STAINED_GLASS + - GREEN_STAINED_GLASS + - RED_STAINED_GLASS + - BLACK_STAINED_GLASS + #glass pane + - GLASS_PANE + - WHITE_STAINED_GLASS_PANE + - ORANGE_STAINED_GLASS_PANE + - MAGENTA_STAINED_GLASS_PANE + - LIGHT_BLUE_STAINED_GLASS_PANE + - YELLOW_STAINED_GLASS_PANE + - LIME_STAINED_GLASS_PANE + - PINK_STAINED_GLASS_PANE + - GRAY_STAINED_GLASS_PANE + - LIGHT_GRAY_STAINED_GLASS_PANE + - CYAN_STAINED_GLASS_PANE + - PURPLE_STAINED_GLASS_PANE + - BLUE_STAINED_GLASS_PANE + - BROWN_STAINED_GLASS_PANE + - GREEN_STAINED_GLASS_PANE + - RED_STAINED_GLASS_PANE + - BLACK_STAINED_GLASS_PANE + #interior + - BOOKSHELF + - BREWING_STAND + - CAULDRON + - IRON_BARS + - SIGN + - TORCH + - WALL_SIGN + - WALL_TORCH + #liquids + - LAVA + - WATER + #logs + - BIRCH_LOG + - JUNGLE_LOG + - OAK_LOG + - SPRUCE_LOG + - STRIPPED_BIRCH_LOG + - STRIPPED_JUNGLE_LOG + - STRIPPED_OAK_LOG + - STRIPPED_SPRUCE_LOG + #planks + - ACACIA_PLANKS + - BIRCH_PLANKS + - DARK_OAK_PLANKS + - JUNGLE_PLANKS + - OAK_PLANKS + - SPRUCE_PLANKS + #pressure plates + - ACACIA_PRESSURE_PLATE + - BIRCH_PRESSURE_PLATE + - DARK_OAK_PRESSURE_PLATE + - HEAVY_WEIGHTED_PRESSURE_PLATE + - JUNGLE_PRESSURE_PLATE + - LIGHT_WEIGHTED_PRESSURE_PLATE + - OAK_PRESSURE_PLATE + - SPRUCE_PRESSURE_PLATE + #redstone + - COMPARATOR + - NOTE_BLOCK + - PISTON + - PISTON_HEAD + - REDSTONE_BLOCK + - REDSTONE_WIRE + - REPEATER + - REDSTONE_TORCH + - REDSTONE_WALL_TORCH + - STICKY_PISTON + - TRIPWIRE_HOOK + #slabs + - ACACIA_SLAB + - BIRCH_SLAB + - BRICK_SLAB + - COBBLESTONE_SLAB + - DARK_OAK_SLAB + - DARK_PRISMARINE + - JUNGLE_SLAB + - NETHER_BRICK_SLAB + - OAK_SLAB + - PETRIFIED_OAK_SLAB + - PRISMARINE_SLAB + - PRISMARINE_BRICK_SLAB + - RED_SANDSTONE_SLAB + - QUARTZ_SLAB + - SPRUCE_SLAB + - STONE_SLAB + #stairs + - BIRCH_STAIRS + - JUNGLE_STAIRS + - OAK_STAIRS + - SMOOTH_STAIRS + - SPRUCE_STAIRS + #storage + - CHEST + - DISPENSER + - DROPPER + - HOPPER + - TRAPPED_CHEST + #terracotta + - TERRACOTTA + - WHITE_TERRACOTTA + - ORANGE_TERRACOTTA + - MAGENTA_TERRACOTTA + - LIGHT_BLUE_TERRACOTTA + - YELLOW_TERRACOTTA + - LIME_TERRACOTTA + - PINK_TERRACOTTA + - GRAY_TERRACOTTA + - LIGHT_TERRACOTTA + - CYAN_TERRACOTTA + - PURPLE_TERRACOTTA + - BLUE_TERRACOTTA + - BROWN_TERRACOTTA + - GREEN_TERRACOTTA + - RED_TERRACOTTA + - BLACK_TERRACOTTA + #trapdoors + - ACACIA_TRAPDOOR + - BIRCH_TRAPDOOR + - DARK_OAK_TRAPDOOR + - JUNGLE_TRAPDOOR + - OAK_TRAPDOOR + - SPRUCE_TRAPDOOR + #weapon blocks + - COAL_BLOCK + #wood + - ACACIA_WOOD + - BIRCH_WOOD + - DARK_OAK_WOOD + - OAK_WOOD + - SPRUCE_WOOD + - STRIPPED_ACACIA_WOOD + - STRIPPED_BIRCH_WOOD + - STRIPPED_DARK_OAK_WOOD + - STRIPPED_OAK_WOOD + - STRIPPED_SPRUCE_WOOD + #wool + - WHITE_WOOL + - ORANGE_WOOL + - MAGENTA_WOOL + - LIGHT_BLUE_WOOL + - YELLOW_WOOL + - LIME_WOOL + - PINK_WOOL + - GRAY_WOOL + - LIGHT_GRAY_WOOL + - CYAN_WOOL + - PURPLE_WOOL + - BLUE_WOOL + - BROWN_WOOL + - GREEN_WOOL + - RED_WOOL + - BLACK_WOOL forbiddenBlocks: - - 34 + - PISTON_HEAD + canCruise: true rotateAtMidpoint: true @@ -139,28 +243,28 @@ tryNudge: false canStaticMove: true maxStaticMove: 2 moveblocks: - 152: # redstone represents engines + REDSTONE_BLOCK: # redstone represents engines - 1.0 - 100.0 flyblocks: - 35: #wool represents lift + [WHITE_WOOL, ORANGE_WOOL, MAGENTA_WOOL,LIGHT_BLUE_WOOL,YELLOW_WOOL,LIME_WOOL,PINK_WOOL,GRAY_WOOL,LIGHT_GRAY_WOOL,CYAN_WOOL,PURPLE_WOOL,BLUE_WOOL,BROWN_WOOL, GREEN_WOOL, RED_WOOL, BLACK_WOOL]: #wool represents lift - 50.0 - 100.0 - [54,146]: # limit chests to make big airships important for merchant missions + [CHEST,TRAPPED_CHEST]: # limit chests to make big airships important for merchant missions - 0.0 - - N50 - [23,154]: # dispensers and hoppers can be used for inventory too, so limit them as well + - 1.0 + [DISPENSER,DROPPER,HOPPER]: # dispensers and hoppers can be used for inventory too, so limit them as well - 0.0 - 2.0 - 61: # Furnaces for cargo? really guys? + FURNACE: # Furnaces for cargo? really guys? - 0.0 - - N75 - 145: # anvils are OP armor, so limit it + - N50 + ANVIL: # anvils are OP armor, so limit it - 0.0 - 1.0 - 49: # so is obsidian + OBSIDIAN: # so is obsidian - 0.0 - 1.0 - 8: # so is water + WATER: # so is water - 0.0 - 1.0 diff --git a/modules/Movecraft/src/main/resources/types/BigSubAirship.craft b/modules/Movecraft/src/main/resources/types/BigSubAirship.craft index 3eab02401..d25ff6e98 100644 --- a/modules/Movecraft/src/main/resources/types/BigSubAirship.craft +++ b/modules/Movecraft/src/main/resources/types/BigSubAirship.craft @@ -1,122 +1,226 @@ name: BigSubAirship maxSize: 20000 minSize: 10000 -allowedBlocks: - - 5 - - 10 - - 11 - - 17 - - 20 - - 22 - - 23 - - 25 - - 26 - - 29 - - 33 - - 34 - - 35 - - 41 - - 42 - - 43 - - 44 - - 47 - - 50 - - 51 - - 53 - - 54 - - 55 - - 57 - - 58 - - 61 - - 62 - - 63 - - 64 - - 65 - - 68 - - 69 - - 70 - - 71 - - 72 - - 75 - - 76 - - 77 - - 82 - - 85 - - 87 - - 89 - - 92 - - 93 - - 94 - - 95 - - 96 - - 98 - - 101 - - 102 - - 107 - - 109 - - 112 - - 113 - - 114 - - 116 - - 117 - - 118 - - 121 - - 122 - - 123 - - 124 - - 125 - - 126 - - 130 - - 131 - - 133 - - 134 - - 135 - - 136 - - 138 - - 139 - - 140 - - 143 - - 144 - - 145 - - 146 - - 147 - - 148 - - 149 - - 150 - - 151 - - 152 - - 154 - - 155 - - 156 - - 157 - - 158 - - 159 - - 160 - - 165 - - 171 - - 172 - - 173 - - 165 - - 167 - - 183 - - 184 - - 185 - - 186 - - 187 - - 188 - - 189 - - 190 - - 191 - - 192 - - 193 - - 194 - - 195 - - 196 - - 197 - - 206 +allowedBlocks: + #beds + - WHITE_BED + - ORANGE_BED + - MAGENTA_BED + - LIGHT_BLUE_BED + - YELLOW_BED + - LIME_BED + - PINK_BED + - GRAY_BED + - LIGHT_BED + - CYAN_BED + - PURPLE_BED + - BLUE_BED + - BROWN_BED + - GREEN_BED + - RED_BED + - BLACK_BED + #buttons + - ACACIA_BUTTON + - BIRCH_BUTTON + - DARK_OAK_BUTTON + - JUNGLE_BUTTON + - OAK_BUTTON + - SPRUCE_BUTTON + - STONE_BUTTON + #doors + - ACACIA_DOOR + - BIRCH_DOOR + - DARK_OAK_DOOR + - IRON_DOOR + - JUNGLE_DOOR + - OAK_DOOR + - SPRUCE_DOOR + #fences + - ACACIA_FENCE + - BIRCH_FENCE + - DARK_OAK_FENCE + - JUNGLE_FENCE + - OAK_FENCE + - SPRUCE_FENCE + #fence gates + - ACACIA_FENCE_GATE + - BIRCH_FENCE_GATE + - DARK_OAK_FENCE_GATE + - JUNGLE_FENCE_GATE + - OAK_FENCE_GATE + - SPRUCE_FENCE_GATE + #glass + - GLASS + - WHITE_STAINED_GLASS + - ORANGE_STAINED_GLASS + - MAGENTA_STAINED_GLASS + - LIGHT_BLUE_STAINED_GLASS + - YELLOW_STAINED_GLASS + - LIME_STAINED_GLASS + - PINK_STAINED_GLASS + - GRAY_STAINED_GLASS + - LIGHT_GRAY_STAINED_GLASS + - CYAN_STAINED_GLASS + - PURPLE_STAINED_GLASS + - BLUE_STAINED_GLASS + - BROWN_STAINED_GLASS + - GREEN_STAINED_GLASS + - RED_STAINED_GLASS + - BLACK_STAINED_GLASS + #glass pane + - GLASS_PANE + - WHITE_STAINED_GLASS_PANE + - ORANGE_STAINED_GLASS_PANE + - MAGENTA_STAINED_GLASS_PANE + - LIGHT_BLUE_STAINED_GLASS_PANE + - YELLOW_STAINED_GLASS_PANE + - LIME_STAINED_GLASS_PANE + - PINK_STAINED_GLASS_PANE + - GRAY_STAINED_GLASS_PANE + - LIGHT_GRAY_STAINED_GLASS_PANE + - CYAN_STAINED_GLASS_PANE + - PURPLE_STAINED_GLASS_PANE + - BLUE_STAINED_GLASS_PANE + - BROWN_STAINED_GLASS_PANE + - GREEN_STAINED_GLASS_PANE + - RED_STAINED_GLASS_PANE + - BLACK_STAINED_GLASS_PANE + #interior + - BOOKSHELF + - BREWING_STAND + - CAULDRON + - IRON_BARS + - SIGN + - TORCH + - WALL_SIGN + - WALL_TORCH + #liquids + - LAVA + - WATER + #logs + - BIRCH_LOG + - JUNGLE_LOG + - OAK_LOG + - SPRUCE_LOG + - STRIPPED_BIRCH_LOG + - STRIPPED_JUNGLE_LOG + - STRIPPED_OAK_LOG + - STRIPPED_SPRUCE_LOG + #planks + - ACACIA_PLANKS + - BIRCH_PLANKS + - DARK_OAK_PLANKS + - JUNGLE_PLANKS + - OAK_PLANKS + - SPRUCE_PLANKS + #pressure plates + - ACACIA_PRESSURE_PLATE + - BIRCH_PRESSURE_PLATE + - DARK_OAK_PRESSURE_PLATE + - HEAVY_WEIGHTED_PRESSURE_PLATE + - JUNGLE_PRESSURE_PLATE + - LIGHT_WEIGHTED_PRESSURE_PLATE + - OAK_PRESSURE_PLATE + - SPRUCE_PRESSURE_PLATE + #redstone + - COMPARATOR + - NOTE_BLOCK + - PISTON + - PISTON_HEAD + - REDSTONE_BLOCK + - REDSTONE_WIRE + - REPEATER + - REDSTONE_TORCH + - REDSTONE_WALL_TORCH + - STICKY_PISTON + - TRIPWIRE_HOOK + #slabs + - ACACIA_SLAB + - BIRCH_SLAB + - BRICK_SLAB + - COBBLESTONE_SLAB + - DARK_OAK_SLAB + - DARK_PRISMARINE + - JUNGLE_SLAB + - NETHER_BRICK_SLAB + - OAK_SLAB + - PETRIFIED_OAK_SLAB + - PRISMARINE_SLAB + - PRISMARINE_BRICK_SLAB + - RED_SANDSTONE_SLAB + - QUARTZ_SLAB + - SPRUCE_SLAB + - STONE_SLAB + #stairs + - BIRCH_STAIRS + - JUNGLE_STAIRS + - OAK_STAIRS + - SMOOTH_STAIRS + - SPRUCE_STAIRS + #storage + - CHEST + - DISPENSER + - DROPPER + - HOPPER + - TRAPPED_CHEST + #terracotta + - TERRACOTTA + - WHITE_TERRACOTTA + - ORANGE_TERRACOTTA + - MAGENTA_TERRACOTTA + - LIGHT_BLUE_TERRACOTTA + - YELLOW_TERRACOTTA + - LIME_TERRACOTTA + - PINK_TERRACOTTA + - GRAY_TERRACOTTA + - LIGHT_TERRACOTTA + - CYAN_TERRACOTTA + - PURPLE_TERRACOTTA + - BLUE_TERRACOTTA + - BROWN_TERRACOTTA + - GREEN_TERRACOTTA + - RED_TERRACOTTA + - BLACK_TERRACOTTA + #trapdoors + - ACACIA_TRAPDOOR + - BIRCH_TRAPDOOR + - DARK_OAK_TRAPDOOR + - JUNGLE_TRAPDOOR + - OAK_TRAPDOOR + - SPRUCE_TRAPDOOR + #weapon blocks + - COAL_BLOCK + #wood + - ACACIA_WOOD + - BIRCH_WOOD + - DARK_OAK_WOOD + - OAK_WOOD + - SPRUCE_WOOD + - STRIPPED_ACACIA_WOOD + - STRIPPED_BIRCH_WOOD + - STRIPPED_DARK_OAK_WOOD + - STRIPPED_OAK_WOOD + - STRIPPED_SPRUCE_WOOD + #wool + - WHITE_WOOL + - ORANGE_WOOL + - MAGENTA_WOOL + - LIGHT_BLUE_WOOL + - YELLOW_WOOL + - LIME_WOOL + - PINK_WOOL + - GRAY_WOOL + - LIGHT_GRAY_WOOL + - CYAN_WOOL + - PURPLE_WOOL + - BLUE_WOOL + - BROWN_WOOL + - GREEN_WOOL + - RED_WOOL + - BLACK_WOOL forbiddenBlocks: - - 34 + - PISTON_HEAD canCruise: true rotateAtMidpoint: true @@ -138,31 +242,31 @@ sinkPercent: 99.0 overallSinkPercent: 60.0 halfSpeedUnderwater: true moveblocks: - 152: # redstone represents engines + REDSTONE_BLOCK: # redstone represents engines - 1.0 - 100.0 flyblocks: - 42: # iron represents ballast tanks + IRON_BLOCK: # iron represents ballast tanks - 10.0 - 100.0 - 35: # wool represents lift + [WHITE_WOOL, ORANGE_WOOL, MAGENTA_WOOL,LIGHT_BLUE_WOOL,YELLOW_WOOL,LIME_WOOL,PINK_WOOL,GRAY_WOOL,LIGHT_GRAY_WOOL,CYAN_WOOL,PURPLE_WOOL,BLUE_WOOL,BROWN_WOOL, GREEN_WOOL, RED_WOOL, BLACK_WOOL]: #wool represents lift - 50.0 - 100.0 - [54,146]: # limit chests to make big airships important for merchant missions + [CHEST,TRAPPED_CHEST]: # limit chests to make big airships important for merchant missions - 0.0 - - N50 - [23,154]: # dispensers and hoppers can be used for inventory too, so limit them as well + - 1.0 + [DISPENSER,DROPPER,HOPPER]: # dispensers and hoppers can be used for inventory too, so limit them as well - 0.0 - - 3.0 - 61: # Furnaces for cargo? really guys? + - 2.0 + FURNACE: # Furnaces for cargo? really guys? - 0.0 - - N75 - 145: # anvils are OP armor, so limit it + - N50 + ANVIL: # anvils are OP armor, so limit it - 0.0 - 1.0 - 49: # so is obsidian + OBSIDIAN: # so is obsidian - 0.0 - 1.0 - 8: # so is water + WATER: # so is water - 0.0 - 1.0 diff --git a/modules/Movecraft/src/main/resources/types/LaunchTorpedo.craft b/modules/Movecraft/src/main/resources/types/LaunchTorpedo.craft index 9fcb8a195..ace8eb4b7 100644 --- a/modules/Movecraft/src/main/resources/types/LaunchTorpedo.craft +++ b/modules/Movecraft/src/main/resources/types/LaunchTorpedo.craft @@ -2,10 +2,10 @@ name: LaunchTorpedo maxSize: 7 minSize: 1 allowedBlocks: - - 173 + - COAL_BLOCK forbiddenBlocks: - - 7 + - BEDROCK canCruise: true cruiseOnPilot: true @@ -25,6 +25,6 @@ tryNudge: false sinkPercent: 99.0 overallSinkPercent: 99.0 flyblocks: - 173: + COAL_BLOCK: - 10.0 - 100.0 diff --git a/modules/Movecraft/src/main/resources/types/Ship.craft b/modules/Movecraft/src/main/resources/types/Ship.craft index bae7628cf..2533840bf 100644 --- a/modules/Movecraft/src/main/resources/types/Ship.craft +++ b/modules/Movecraft/src/main/resources/types/Ship.craft @@ -1,100 +1,226 @@ name: Ship maxSize: 100000 minSize: 10 -allowedBlocks: - - 5 - - 10 - - 11 - - 17 - - 20 - - 23 - - 25 - - 26 - - 29 - - 33 - - 34 - - 35 - - 41 - - 42 - - 43 - - 44 - - 47 - - 49 - - 50 - - 53 - - 54 - - 55 - - 57 - - 58 - - 61 - - 62 - - 63 - - 64 - - 65 - - 68 - - 69 - - 70 - - 71 - - 72 - - 75 - - 76 - - 77 - - 82 - - 85 - - 87 - - 89 - - 92 - - 93 - - 94 - - 95 - - 96 - - 98 - - 101 - - 102 - - 107 - - 109 - - 112 - - 113 - - 114 - - 116 - - 117 - - 118 - - 122 - - 123 - - 124 - - 125 - - 126 - - 130 - - 131 - - 133 - - 134 - - 135 - - 136 - - 138 - - 139 - - 140 - - 143 - - 144 - - 145 - - 146 - - 147 - - 148 - - 149 - - 150 - - 151 - - 152 - - 154 - - 155 - - 156 - - 157 - - 158 - - 159 - - 171 - - 172 - - 173 +allowedBlocks: + #beds + - WHITE_BED + - ORANGE_BED + - MAGENTA_BED + - LIGHT_BLUE_BED + - YELLOW_BED + - LIME_BED + - PINK_BED + - GRAY_BED + - LIGHT_BED + - CYAN_BED + - PURPLE_BED + - BLUE_BED + - BROWN_BED + - GREEN_BED + - RED_BED + - BLACK_BED + #buttons + - ACACIA_BUTTON + - BIRCH_BUTTON + - DARK_OAK_BUTTON + - JUNGLE_BUTTON + - OAK_BUTTON + - SPRUCE_BUTTON + - STONE_BUTTON + #doors + - ACACIA_DOOR + - BIRCH_DOOR + - DARK_OAK_DOOR + - IRON_DOOR + - JUNGLE_DOOR + - OAK_DOOR + - SPRUCE_DOOR + #fences + - ACACIA_FENCE + - BIRCH_FENCE + - DARK_OAK_FENCE + - JUNGLE_FENCE + - OAK_FENCE + - SPRUCE_FENCE + #fence gates + - ACACIA_FENCE_GATE + - BIRCH_FENCE_GATE + - DARK_OAK_FENCE_GATE + - JUNGLE_FENCE_GATE + - OAK_FENCE_GATE + - SPRUCE_FENCE_GATE + #glass + - GLASS + - WHITE_STAINED_GLASS + - ORANGE_STAINED_GLASS + - MAGENTA_STAINED_GLASS + - LIGHT_BLUE_STAINED_GLASS + - YELLOW_STAINED_GLASS + - LIME_STAINED_GLASS + - PINK_STAINED_GLASS + - GRAY_STAINED_GLASS + - LIGHT_GRAY_STAINED_GLASS + - CYAN_STAINED_GLASS + - PURPLE_STAINED_GLASS + - BLUE_STAINED_GLASS + - BROWN_STAINED_GLASS + - GREEN_STAINED_GLASS + - RED_STAINED_GLASS + - BLACK_STAINED_GLASS + #glass pane + - GLASS_PANE + - WHITE_STAINED_GLASS_PANE + - ORANGE_STAINED_GLASS_PANE + - MAGENTA_STAINED_GLASS_PANE + - LIGHT_BLUE_STAINED_GLASS_PANE + - YELLOW_STAINED_GLASS_PANE + - LIME_STAINED_GLASS_PANE + - PINK_STAINED_GLASS_PANE + - GRAY_STAINED_GLASS_PANE + - LIGHT_GRAY_STAINED_GLASS_PANE + - CYAN_STAINED_GLASS_PANE + - PURPLE_STAINED_GLASS_PANE + - BLUE_STAINED_GLASS_PANE + - BROWN_STAINED_GLASS_PANE + - GREEN_STAINED_GLASS_PANE + - RED_STAINED_GLASS_PANE + - BLACK_STAINED_GLASS_PANE + #interior + - BOOKSHELF + - BREWING_STAND + - CAULDRON + - IRON_BARS + - SIGN + - TORCH + - WALL_SIGN + - WALL_TORCH + #liquids + - LAVA + - WATER + #logs + - BIRCH_LOG + - JUNGLE_LOG + - OAK_LOG + - SPRUCE_LOG + - STRIPPED_BIRCH_LOG + - STRIPPED_JUNGLE_LOG + - STRIPPED_OAK_LOG + - STRIPPED_SPRUCE_LOG + #planks + - ACACIA_PLANKS + - BIRCH_PLANKS + - DARK_OAK_PLANKS + - JUNGLE_PLANKS + - OAK_PLANKS + - SPRUCE_PLANKS + #pressure plates + - ACACIA_PRESSURE_PLATE + - BIRCH_PRESSURE_PLATE + - DARK_OAK_PRESSURE_PLATE + - HEAVY_WEIGHTED_PRESSURE_PLATE + - JUNGLE_PRESSURE_PLATE + - LIGHT_WEIGHTED_PRESSURE_PLATE + - OAK_PRESSURE_PLATE + - SPRUCE_PRESSURE_PLATE + #redstone + - COMPARATOR + - NOTE_BLOCK + - PISTON + - PISTON_HEAD + - REDSTONE_BLOCK + - REDSTONE_WIRE + - REPEATER + - REDSTONE_TORCH + - REDSTONE_WALL_TORCH + - STICKY_PISTON + - TRIPWIRE_HOOK + #slabs + - ACACIA_SLAB + - BIRCH_SLAB + - BRICK_SLAB + - COBBLESTONE_SLAB + - DARK_OAK_SLAB + - DARK_PRISMARINE + - JUNGLE_SLAB + - NETHER_BRICK_SLAB + - OAK_SLAB + - PETRIFIED_OAK_SLAB + - PRISMARINE_SLAB + - PRISMARINE_BRICK_SLAB + - RED_SANDSTONE_SLAB + - QUARTZ_SLAB + - SPRUCE_SLAB + - STONE_SLAB + #stairs + - BIRCH_STAIRS + - JUNGLE_STAIRS + - OAK_STAIRS + - SMOOTH_STAIRS + - SPRUCE_STAIRS + #storage + - CHEST + - DISPENSER + - DROPPER + - HOPPER + - TRAPPED_CHEST + #terracotta + - TERRACOTTA + - WHITE_TERRACOTTA + - ORANGE_TERRACOTTA + - MAGENTA_TERRACOTTA + - LIGHT_BLUE_TERRACOTTA + - YELLOW_TERRACOTTA + - LIME_TERRACOTTA + - PINK_TERRACOTTA + - GRAY_TERRACOTTA + - LIGHT_TERRACOTTA + - CYAN_TERRACOTTA + - PURPLE_TERRACOTTA + - BLUE_TERRACOTTA + - BROWN_TERRACOTTA + - GREEN_TERRACOTTA + - RED_TERRACOTTA + - BLACK_TERRACOTTA + #trapdoors + - ACACIA_TRAPDOOR + - BIRCH_TRAPDOOR + - DARK_OAK_TRAPDOOR + - JUNGLE_TRAPDOOR + - OAK_TRAPDOOR + - SPRUCE_TRAPDOOR + #weapon blocks + - COAL_BLOCK + #wood + - ACACIA_WOOD + - BIRCH_WOOD + - DARK_OAK_WOOD + - OAK_WOOD + - SPRUCE_WOOD + - STRIPPED_ACACIA_WOOD + - STRIPPED_BIRCH_WOOD + - STRIPPED_DARK_OAK_WOOD + - STRIPPED_OAK_WOOD + - STRIPPED_SPRUCE_WOOD + #wool + - WHITE_WOOL + - ORANGE_WOOL + - MAGENTA_WOOL + - LIGHT_BLUE_WOOL + - YELLOW_WOOL + - LIME_WOOL + - PINK_WOOL + - GRAY_WOOL + - LIGHT_GRAY_WOOL + - CYAN_WOOL + - PURPLE_WOOL + - BLUE_WOOL + - BROWN_WOOL + - GREEN_WOOL + - RED_WOOL + - BLACK_WOOL forbiddenBlocks: - - 7 + - PISTON_HEAD canCruise: true cruiseSkipBlocks: 4 diff --git a/modules/Movecraft/src/main/resources/types/SubAirship.craft b/modules/Movecraft/src/main/resources/types/SubAirship.craft index 0e6e07756..2b008d39e 100644 --- a/modules/Movecraft/src/main/resources/types/SubAirship.craft +++ b/modules/Movecraft/src/main/resources/types/SubAirship.craft @@ -1,122 +1,226 @@ name: SubAirship maxSize: 5000 minSize: 1000 -allowedBlocks: - - 5 - - 10 - - 11 - - 17 - - 20 - - 22 - - 23 - - 25 - - 26 - - 29 - - 33 - - 34 - - 35 - - 41 - - 42 - - 43 - - 44 - - 47 - - 50 - - 51 - - 53 - - 54 - - 55 - - 57 - - 58 - - 61 - - 62 - - 63 - - 64 - - 65 - - 68 - - 69 - - 70 - - 71 - - 72 - - 75 - - 76 - - 77 - - 82 - - 85 - - 87 - - 89 - - 92 - - 93 - - 94 - - 95 - - 96 - - 98 - - 101 - - 102 - - 107 - - 109 - - 112 - - 113 - - 114 - - 116 - - 117 - - 118 - - 121 - - 122 - - 123 - - 124 - - 125 - - 126 - - 130 - - 131 - - 133 - - 134 - - 135 - - 136 - - 138 - - 139 - - 140 - - 143 - - 144 - - 145 - - 146 - - 147 - - 148 - - 149 - - 150 - - 151 - - 152 - - 154 - - 155 - - 156 - - 157 - - 158 - - 159 - - 160 - - 165 - - 171 - - 172 - - 173 - - 165 - - 167 - - 183 - - 184 - - 185 - - 186 - - 187 - - 188 - - 189 - - 190 - - 191 - - 192 - - 193 - - 194 - - 195 - - 196 - - 197 - - 206 +allowedBlocks: + #beds + - WHITE_BED + - ORANGE_BED + - MAGENTA_BED + - LIGHT_BLUE_BED + - YELLOW_BED + - LIME_BED + - PINK_BED + - GRAY_BED + - LIGHT_BED + - CYAN_BED + - PURPLE_BED + - BLUE_BED + - BROWN_BED + - GREEN_BED + - RED_BED + - BLACK_BED + #buttons + - ACACIA_BUTTON + - BIRCH_BUTTON + - DARK_OAK_BUTTON + - JUNGLE_BUTTON + - OAK_BUTTON + - SPRUCE_BUTTON + - STONE_BUTTON + #doors + - ACACIA_DOOR + - BIRCH_DOOR + - DARK_OAK_DOOR + - IRON_DOOR + - JUNGLE_DOOR + - OAK_DOOR + - SPRUCE_DOOR + #fences + - ACACIA_FENCE + - BIRCH_FENCE + - DARK_OAK_FENCE + - JUNGLE_FENCE + - OAK_FENCE + - SPRUCE_FENCE + #fence gates + - ACACIA_FENCE_GATE + - BIRCH_FENCE_GATE + - DARK_OAK_FENCE_GATE + - JUNGLE_FENCE_GATE + - OAK_FENCE_GATE + - SPRUCE_FENCE_GATE + #glass + - GLASS + - WHITE_STAINED_GLASS + - ORANGE_STAINED_GLASS + - MAGENTA_STAINED_GLASS + - LIGHT_BLUE_STAINED_GLASS + - YELLOW_STAINED_GLASS + - LIME_STAINED_GLASS + - PINK_STAINED_GLASS + - GRAY_STAINED_GLASS + - LIGHT_GRAY_STAINED_GLASS + - CYAN_STAINED_GLASS + - PURPLE_STAINED_GLASS + - BLUE_STAINED_GLASS + - BROWN_STAINED_GLASS + - GREEN_STAINED_GLASS + - RED_STAINED_GLASS + - BLACK_STAINED_GLASS + #glass pane + - GLASS_PANE + - WHITE_STAINED_GLASS_PANE + - ORANGE_STAINED_GLASS_PANE + - MAGENTA_STAINED_GLASS_PANE + - LIGHT_BLUE_STAINED_GLASS_PANE + - YELLOW_STAINED_GLASS_PANE + - LIME_STAINED_GLASS_PANE + - PINK_STAINED_GLASS_PANE + - GRAY_STAINED_GLASS_PANE + - LIGHT_GRAY_STAINED_GLASS_PANE + - CYAN_STAINED_GLASS_PANE + - PURPLE_STAINED_GLASS_PANE + - BLUE_STAINED_GLASS_PANE + - BROWN_STAINED_GLASS_PANE + - GREEN_STAINED_GLASS_PANE + - RED_STAINED_GLASS_PANE + - BLACK_STAINED_GLASS_PANE + #interior + - BOOKSHELF + - BREWING_STAND + - CAULDRON + - IRON_BARS + - SIGN + - TORCH + - WALL_SIGN + - WALL_TORCH + #liquids + - LAVA + - WATER + #logs + - BIRCH_LOG + - JUNGLE_LOG + - OAK_LOG + - SPRUCE_LOG + - STRIPPED_BIRCH_LOG + - STRIPPED_JUNGLE_LOG + - STRIPPED_OAK_LOG + - STRIPPED_SPRUCE_LOG + #planks + - ACACIA_PLANKS + - BIRCH_PLANKS + - DARK_OAK_PLANKS + - JUNGLE_PLANKS + - OAK_PLANKS + - SPRUCE_PLANKS + #pressure plates + - ACACIA_PRESSURE_PLATE + - BIRCH_PRESSURE_PLATE + - DARK_OAK_PRESSURE_PLATE + - HEAVY_WEIGHTED_PRESSURE_PLATE + - JUNGLE_PRESSURE_PLATE + - LIGHT_WEIGHTED_PRESSURE_PLATE + - OAK_PRESSURE_PLATE + - SPRUCE_PRESSURE_PLATE + #redstone + - COMPARATOR + - NOTE_BLOCK + - PISTON + - PISTON_HEAD + - REDSTONE_BLOCK + - REDSTONE_WIRE + - REPEATER + - REDSTONE_TORCH + - REDSTONE_WALL_TORCH + - STICKY_PISTON + - TRIPWIRE_HOOK + #slabs + - ACACIA_SLAB + - BIRCH_SLAB + - BRICK_SLAB + - COBBLESTONE_SLAB + - DARK_OAK_SLAB + - DARK_PRISMARINE + - JUNGLE_SLAB + - NETHER_BRICK_SLAB + - OAK_SLAB + - PETRIFIED_OAK_SLAB + - PRISMARINE_SLAB + - PRISMARINE_BRICK_SLAB + - RED_SANDSTONE_SLAB + - QUARTZ_SLAB + - SPRUCE_SLAB + - STONE_SLAB + #stairs + - BIRCH_STAIRS + - JUNGLE_STAIRS + - OAK_STAIRS + - SMOOTH_STAIRS + - SPRUCE_STAIRS + #storage + - CHEST + - DISPENSER + - DROPPER + - HOPPER + - TRAPPED_CHEST + #terracotta + - TERRACOTTA + - WHITE_TERRACOTTA + - ORANGE_TERRACOTTA + - MAGENTA_TERRACOTTA + - LIGHT_BLUE_TERRACOTTA + - YELLOW_TERRACOTTA + - LIME_TERRACOTTA + - PINK_TERRACOTTA + - GRAY_TERRACOTTA + - LIGHT_TERRACOTTA + - CYAN_TERRACOTTA + - PURPLE_TERRACOTTA + - BLUE_TERRACOTTA + - BROWN_TERRACOTTA + - GREEN_TERRACOTTA + - RED_TERRACOTTA + - BLACK_TERRACOTTA + #trapdoors + - ACACIA_TRAPDOOR + - BIRCH_TRAPDOOR + - DARK_OAK_TRAPDOOR + - JUNGLE_TRAPDOOR + - OAK_TRAPDOOR + - SPRUCE_TRAPDOOR + #weapon blocks + - COAL_BLOCK + #wood + - ACACIA_WOOD + - BIRCH_WOOD + - DARK_OAK_WOOD + - OAK_WOOD + - SPRUCE_WOOD + - STRIPPED_ACACIA_WOOD + - STRIPPED_BIRCH_WOOD + - STRIPPED_DARK_OAK_WOOD + - STRIPPED_OAK_WOOD + - STRIPPED_SPRUCE_WOOD + #wool + - WHITE_WOOL + - ORANGE_WOOL + - MAGENTA_WOOL + - LIGHT_BLUE_WOOL + - YELLOW_WOOL + - LIME_WOOL + - PINK_WOOL + - GRAY_WOOL + - LIGHT_GRAY_WOOL + - CYAN_WOOL + - PURPLE_WOOL + - BLUE_WOOL + - BROWN_WOOL + - GREEN_WOOL + - RED_WOOL + - BLACK_WOOL forbiddenBlocks: - - 34 + - PISTON_HEAD canCruise: true rotateAtMidpoint: true @@ -141,28 +245,28 @@ moveblocks: - 1.0 - 100.0 flyblocks: - 42: # iron represents ballast tanks + IRON_BLOCK: # iron represents ballast tanks - 10.0 - 100.0 - 35: # wool represents lift + [WHITE_WOOL, ORANGE_WOOL, MAGENTA_WOOL,LIGHT_BLUE_WOOL,YELLOW_WOOL,LIME_WOOL,PINK_WOOL,GRAY_WOOL,LIGHT_GRAY_WOOL,CYAN_WOOL,PURPLE_WOOL,BLUE_WOOL,BROWN_WOOL, GREEN_WOOL, RED_WOOL, BLACK_WOOL]: #wool represents lift - 50.0 - 100.0 - [54,146]: # limit chests to make big airships important for merchant missions + [CHEST,TRAPPED_CHEST]: # limit chests to make big airships important for merchant missions - 0.0 - 1.0 - [23,154]: # dispensers can be used for inventory too, so limit them as well + [DISPENSER,DROPPER,HOPPER]: # dispensers and hoppers can be used for inventory too, so limit them as well - 0.0 - 2.0 - 61: # Furnaces for cargo? really guys? + FURNACE: # Furnaces for cargo? really guys? - 0.0 - N50 - - 145: # anvils are OP armor, so limit it + ANVIL: # anvils are OP armor, so limit it - 0.0 - 1.0 - 49: # so is obsidian + OBSIDIAN: # so is obsidian - 0.0 - 1.0 - 8: # so is water + WATER: # so is water - 0.0 - 1.0 + diff --git a/modules/Movecraft/src/main/resources/types/Submarine.craft b/modules/Movecraft/src/main/resources/types/Submarine.craft index 82a0766cc..6047c661f 100644 --- a/modules/Movecraft/src/main/resources/types/Submarine.craft +++ b/modules/Movecraft/src/main/resources/types/Submarine.craft @@ -1,100 +1,227 @@ name: Submarine maxSize: 100000 minSize: 10 -allowedBlocks: - - 5 - - 10 - - 11 - - 17 - - 20 - - 23 - - 25 - - 26 - - 29 - - 33 - - 34 - - 35 - - 41 - - 42 - - 43 - - 44 - - 47 - - 49 - - 50 - - 53 - - 54 - - 55 - - 57 - - 58 - - 61 - - 62 - - 63 - - 64 - - 65 - - 68 - - 69 - - 70 - - 71 - - 72 - - 75 - - 76 - - 77 - - 82 - - 85 - - 87 - - 89 - - 92 - - 93 - - 94 - - 95 - - 96 - - 101 - - 102 - - 107 - - 109 - - 112 - - 113 - - 114 - - 116 - - 117 - - 118 - - 122 - - 123 - - 124 - - 125 - - 126 - - 130 - - 131 - - 133 - - 134 - - 135 - - 136 - - 138 - - 139 - - 140 - - 143 - - 144 - - 145 - - 146 - - 147 - - 148 - - 149 - - 150 - - 151 - - 152 - - 154 - - 155 - - 156 - - 157 - - 158 - - 159 - - 163 - - 171 - - 172 - - 173 +allowedBlocks: + #beds + - WHITE_BED + - ORANGE_BED + - MAGENTA_BED + - LIGHT_BLUE_BED + - YELLOW_BED + - LIME_BED + - PINK_BED + - GRAY_BED + - LIGHT_BED + - CYAN_BED + - PURPLE_BED + - BLUE_BED + - BROWN_BED + - GREEN_BED + - RED_BED + - BLACK_BED + #buttons + - ACACIA_BUTTON + - BIRCH_BUTTON + - DARK_OAK_BUTTON + - JUNGLE_BUTTON + - OAK_BUTTON + - SPRUCE_BUTTON + - STONE_BUTTON + #doors + - ACACIA_DOOR + - BIRCH_DOOR + - DARK_OAK_DOOR + - IRON_DOOR + - JUNGLE_DOOR + - OAK_DOOR + - SPRUCE_DOOR + #fences + - ACACIA_FENCE + - BIRCH_FENCE + - DARK_OAK_FENCE + - JUNGLE_FENCE + - OAK_FENCE + - SPRUCE_FENCE + #fence gates + - ACACIA_FENCE_GATE + - BIRCH_FENCE_GATE + - DARK_OAK_FENCE_GATE + - JUNGLE_FENCE_GATE + - OAK_FENCE_GATE + - SPRUCE_FENCE_GATE + #glass + - GLASS + - WHITE_STAINED_GLASS + - ORANGE_STAINED_GLASS + - MAGENTA_STAINED_GLASS + - LIGHT_BLUE_STAINED_GLASS + - YELLOW_STAINED_GLASS + - LIME_STAINED_GLASS + - PINK_STAINED_GLASS + - GRAY_STAINED_GLASS + - LIGHT_GRAY_STAINED_GLASS + - CYAN_STAINED_GLASS + - PURPLE_STAINED_GLASS + - BLUE_STAINED_GLASS + - BROWN_STAINED_GLASS + - GREEN_STAINED_GLASS + - RED_STAINED_GLASS + - BLACK_STAINED_GLASS + #glass pane + - GLASS_PANE + - WHITE_STAINED_GLASS_PANE + - ORANGE_STAINED_GLASS_PANE + - MAGENTA_STAINED_GLASS_PANE + - LIGHT_BLUE_STAINED_GLASS_PANE + - YELLOW_STAINED_GLASS_PANE + - LIME_STAINED_GLASS_PANE + - PINK_STAINED_GLASS_PANE + - GRAY_STAINED_GLASS_PANE + - LIGHT_GRAY_STAINED_GLASS_PANE + - CYAN_STAINED_GLASS_PANE + - PURPLE_STAINED_GLASS_PANE + - BLUE_STAINED_GLASS_PANE + - BROWN_STAINED_GLASS_PANE + - GREEN_STAINED_GLASS_PANE + - RED_STAINED_GLASS_PANE + - BLACK_STAINED_GLASS_PANE + #interior + - BOOKSHELF + - BREWING_STAND + - CAULDRON + - IRON_BARS + - SIGN + - TORCH + - WALL_SIGN + - WALL_TORCH + #liquids + - LAVA + - WATER + #logs + - BIRCH_LOG + - JUNGLE_LOG + - OAK_LOG + - SPRUCE_LOG + - STRIPPED_BIRCH_LOG + - STRIPPED_JUNGLE_LOG + - STRIPPED_OAK_LOG + - STRIPPED_SPRUCE_LOG + #planks + - ACACIA_PLANKS + - BIRCH_PLANKS + - DARK_OAK_PLANKS + - JUNGLE_PLANKS + - OAK_PLANKS + - SPRUCE_PLANKS + #pressure plates + - ACACIA_PRESSURE_PLATE + - BIRCH_PRESSURE_PLATE + - DARK_OAK_PRESSURE_PLATE + - HEAVY_WEIGHTED_PRESSURE_PLATE + - JUNGLE_PRESSURE_PLATE + - LIGHT_WEIGHTED_PRESSURE_PLATE + - OAK_PRESSURE_PLATE + - SPRUCE_PRESSURE_PLATE + #redstone + - COMPARATOR + - NOTE_BLOCK + - PISTON + - PISTON_HEAD + - REDSTONE_BLOCK + - REDSTONE_WIRE + - REPEATER + - REDSTONE_TORCH + - REDSTONE_WALL_TORCH + - STICKY_PISTON + - TRIPWIRE_HOOK + #slabs + - ACACIA_SLAB + - BIRCH_SLAB + - BRICK_SLAB + - COBBLESTONE_SLAB + - DARK_OAK_SLAB + - DARK_PRISMARINE + - JUNGLE_SLAB + - NETHER_BRICK_SLAB + - OAK_SLAB + - PETRIFIED_OAK_SLAB + - PRISMARINE_SLAB + - PRISMARINE_BRICK_SLAB + - RED_SANDSTONE_SLAB + - QUARTZ_SLAB + - SPRUCE_SLAB + - STONE_SLAB + #stairs + - BIRCH_STAIRS + - JUNGLE_STAIRS + - OAK_STAIRS + - SMOOTH_STAIRS + - SPRUCE_STAIRS + #storage + - CHEST + - DISPENSER + - DROPPER + - HOPPER + - TRAPPED_CHEST + #terracotta + - TERRACOTTA + - WHITE_TERRACOTTA + - ORANGE_TERRACOTTA + - MAGENTA_TERRACOTTA + - LIGHT_BLUE_TERRACOTTA + - YELLOW_TERRACOTTA + - LIME_TERRACOTTA + - PINK_TERRACOTTA + - GRAY_TERRACOTTA + - LIGHT_TERRACOTTA + - CYAN_TERRACOTTA + - PURPLE_TERRACOTTA + - BLUE_TERRACOTTA + - BROWN_TERRACOTTA + - GREEN_TERRACOTTA + - RED_TERRACOTTA + - BLACK_TERRACOTTA + #trapdoors + - ACACIA_TRAPDOOR + - BIRCH_TRAPDOOR + - DARK_OAK_TRAPDOOR + - JUNGLE_TRAPDOOR + - OAK_TRAPDOOR + - SPRUCE_TRAPDOOR + #weapon blocks + - COAL_BLOCK + #wood + - ACACIA_WOOD + - BIRCH_WOOD + - DARK_OAK_WOOD + - OAK_WOOD + - SPRUCE_WOOD + - STRIPPED_ACACIA_WOOD + - STRIPPED_BIRCH_WOOD + - STRIPPED_DARK_OAK_WOOD + - STRIPPED_OAK_WOOD + - STRIPPED_SPRUCE_WOOD + #wool + - WHITE_WOOL + - ORANGE_WOOL + - MAGENTA_WOOL + - LIGHT_BLUE_WOOL + - YELLOW_WOOL + - LIME_WOOL + - PINK_WOOL + - GRAY_WOOL + - LIGHT_GRAY_WOOL + - CYAN_WOOL + - PURPLE_WOOL + - BLUE_WOOL + - BROWN_WOOL + - GREEN_WOOL + - RED_WOOL + - BLACK_WOOL forbiddenBlocks: - - 7 + - BEDROCK + canCruise: true cruiseSkipBlocks: 4 @@ -109,15 +236,15 @@ allowVerticalMovement: true fuelBurnRate: 1.0 tryNudge: false flyblocks: - 5: + [ACACIA_PLANKS, BIRCH_PLANKS, DARK_OAK_PLANKS, JUNGLE_PLANKS, OAK_PLANKS, SPRUCE_PLANKS]: - 25.0 - 100.0 - 145: # anvils are OP armor, so limit it + ANVIL: # anvils are OP armor, so limit it - 0.0 - 1.0 - 49: # so is obsidian + OBSIDIAN: # so is obsidian - 0.0 - 1.0 - 42: + IRON_BLOCK: - 15.0 - 100.0 \ No newline at end of file diff --git a/modules/Movecraft/src/main/resources/types/Turret.craft b/modules/Movecraft/src/main/resources/types/Turret.craft index 7cc4c305e..15cc0d687 100644 --- a/modules/Movecraft/src/main/resources/types/Turret.craft +++ b/modules/Movecraft/src/main/resources/types/Turret.craft @@ -1,100 +1,196 @@ name: Turret maxSize: 1000 minSize: 1 -allowedBlocks: - - 8 - - 9 - - 10 - - 11 - - 17 - - 20 - - 23 - - 25 - - 26 - - 29 - - 33 - - "35:8" - - 41 - - 43 - - 44 - - 47 - - 50 - - 52 - - 53 - - 54 - - 55 - - 57 - - 58 - - 61 - - 62 - - 63 - - 64 - - 65 - - 68 - - 69 - - 70 - - 71 - - 72 - - 77 - - 85 - - 89 - - 92 - - 93 - - 94 - - 95 - - 96 - - 101 - - 102 - - 107 - - 113 - - 114 - - 117 - - 118 - - 123 - - 124 - - 125 - - 126 - - 130 - - 131 - - 133 - - 134 - - 135 - - 117 - - 118 - - 123 - - 124 - - 125 - - 126 - - 130 - - 131 - - 133 - - 134 - - 135 - - 136 - - 138 - - 140 - - 143 - - 144 - - 145 - - 146 - - 147 - - 148 - - 149 - - 150 - - 151 - - 152 - - 154 - - 157 - - 158 - - "159:7" - - "159:8" - - "159:15" - - 165 - - 171 - - 206 +allowedBlocks: + #beds + - WHITE_BED + - ORANGE_BED + - MAGENTA_BED + - LIGHT_BLUE_BED + - YELLOW_BED + - LIME_BED + - PINK_BED + - GRAY_BED + - LIGHT_BED + - CYAN_BED + - PURPLE_BED + - BLUE_BED + - BROWN_BED + - GREEN_BED + - RED_BED + - BLACK_BED + #buttons + - ACACIA_BUTTON + - BIRCH_BUTTON + - DARK_OAK_BUTTON + - JUNGLE_BUTTON + - OAK_BUTTON + - SPRUCE_BUTTON + - STONE_BUTTON + #doors + - ACACIA_DOOR + - BIRCH_DOOR + - DARK_OAK_DOOR + - IRON_DOOR + - JUNGLE_DOOR + - OAK_DOOR + - SPRUCE_DOOR + #fences + - ACACIA_FENCE + - BIRCH_FENCE + - DARK_OAK_FENCE + - JUNGLE_FENCE + - OAK_FENCE + - SPRUCE_FENCE + #fence gates + - ACACIA_FENCE_GATE + - BIRCH_FENCE_GATE + - DARK_OAK_FENCE_GATE + - JUNGLE_FENCE_GATE + - OAK_FENCE_GATE + - SPRUCE_FENCE_GATE + #glass + - GLASS + - WHITE_STAINED_GLASS + - ORANGE_STAINED_GLASS + - MAGENTA_STAINED_GLASS + - LIGHT_BLUE_STAINED_GLASS + - YELLOW_STAINED_GLASS + - LIME_STAINED_GLASS + - PINK_STAINED_GLASS + - GRAY_STAINED_GLASS + - LIGHT_GRAY_STAINED_GLASS + - CYAN_STAINED_GLASS + - PURPLE_STAINED_GLASS + - BLUE_STAINED_GLASS + - BROWN_STAINED_GLASS + - GREEN_STAINED_GLASS + - RED_STAINED_GLASS + - BLACK_STAINED_GLASS + #glass pane + - GLASS_PANE + - WHITE_STAINED_GLASS_PANE + - ORANGE_STAINED_GLASS_PANE + - MAGENTA_STAINED_GLASS_PANE + - LIGHT_BLUE_STAINED_GLASS_PANE + - YELLOW_STAINED_GLASS_PANE + - LIME_STAINED_GLASS_PANE + - PINK_STAINED_GLASS_PANE + - GRAY_STAINED_GLASS_PANE + - LIGHT_GRAY_STAINED_GLASS_PANE + - CYAN_STAINED_GLASS_PANE + - PURPLE_STAINED_GLASS_PANE + - BLUE_STAINED_GLASS_PANE + - BROWN_STAINED_GLASS_PANE + - GREEN_STAINED_GLASS_PANE + - RED_STAINED_GLASS_PANE + - BLACK_STAINED_GLASS_PANE + #interior + - BOOKSHELF + - BREWING_STAND + - CAULDRON + - IRON_BARS + - SIGN + - TORCH + - WALL_SIGN + - WALL_TORCH + #liquids + - LAVA + - WATER + #logs + - BIRCH_LOG + - JUNGLE_LOG + - OAK_LOG + - SPRUCE_LOG + - STRIPPED_BIRCH_LOG + - STRIPPED_JUNGLE_LOG + - STRIPPED_OAK_LOG + - STRIPPED_SPRUCE_LOG + #planks + - ACACIA_PLANKS + - BIRCH_PLANKS + - DARK_OAK_PLANKS + - JUNGLE_PLANKS + - OAK_PLANKS + - SPRUCE_PLANKS + #pressure plates + - ACACIA_PRESSURE_PLATE + - BIRCH_PRESSURE_PLATE + - DARK_OAK_PRESSURE_PLATE + - HEAVY_WEIGHTED_PRESSURE_PLATE + - JUNGLE_PRESSURE_PLATE + - LIGHT_WEIGHTED_PRESSURE_PLATE + - OAK_PRESSURE_PLATE + - SPRUCE_PRESSURE_PLATE + #redstone + - COMPARATOR + - NOTE_BLOCK + - PISTON + - PISTON_HEAD + - REDSTONE_BLOCK + - REDSTONE_WIRE + - REPEATER + - STICKY_PISTON + - TRIPWIRE_HOOK + #slabs + - ACACIA_SLAB + - BIRCH_SLAB + - BRICK_SLAB + - COBBLESTONE_SLAB + - DARK_OAK_SLAB + - DARK_PRISMARINE + - JUNGLE_SLAB + - NETHER_BRICK_SLAB + - OAK_SLAB + - PETRIFIED_OAK_SLAB + - PRISMARINE_SLAB + - PRISMARINE_BRICK_SLAB + - RED_SANDSTONE_SLAB + - QUARTZ_SLAB + - SPRUCE_SLAB + - STONE_SLAB + #stairs + - BIRCH_STAIRS + - JUNGLE_STAIRS + - OAK_STAIRS + - SMOOTH_STAIRS + - SPRUCE_STAIRS + #storage + - CHEST + - DISPENSER + - DROPPER + - HOPPER + - TRAPPED_CHEST + #terracotta + - GRAY_TERRACOTTA + - LIGHT_GRAY_TERRACOTTA + - BLACK_TERRACOTTA + #trapdoors + - ACACIA_TRAPDOOR + - BIRCH_TRAPDOOR + - DARK_OAK_TRAPDOOR + - JUNGLE_TRAPDOOR + - OAK_TRAPDOOR + - SPRUCE_TRAPDOOR + #weapon blocks + - COAL_BLOCK + #wood + - ACACIA_WOOD + - BIRCH_WOOD + - DARK_OAK_WOOD + - OAK_WOOD + - SPRUCE_WOOD + - STRIPPED_ACACIA_WOOD + - STRIPPED_BIRCH_WOOD + - STRIPPED_DARK_OAK_WOOD + - STRIPPED_OAK_WOOD + - STRIPPED_SPRUCE_WOOD + #wool + - LIGHT_GRAY_WOOL forbiddenBlocks: - - 7 + - PISTON_HEAD + canFly: true canCruise: false @@ -109,6 +205,6 @@ speed: 1.0 tryNudge: false sinkPercent: 99.0 flyblocks: - 35: + LIGHT_GRAY_WOOL: - 0.0 - 100.0 diff --git a/modules/Movecraft/src/main/resources/types/airship.craft b/modules/Movecraft/src/main/resources/types/airship.craft index 32df1def2..2fbca116a 100644 --- a/modules/Movecraft/src/main/resources/types/airship.craft +++ b/modules/Movecraft/src/main/resources/types/airship.craft @@ -1,124 +1,226 @@ name: Airship maxSize: 5000 minSize: 1000 -allowedBlocks: - - 5 - - 8 - - 9 - - 10 - - 11 - - 17 - - 20 - - 22 - - 23 - - 25 - - 26 - - 29 - - 33 - - 34 - - 35 - - 41 - - 42 - - 43 - - 44 - - 47 - - 50 - - 51 - - 53 - - 54 - - 55 - - 57 - - 58 - - 61 - - 62 - - 63 - - 64 - - 65 - - 68 - - 69 - - 70 - - 71 - - 72 - - 75 - - 76 - - 77 - - 82 - - 85 - - 87 - - 89 - - 92 - - 93 - - 94 - - 95 - - 96 - - 98 - - 101 - - 102 - - 107 - - 109 - - 112 - - 113 - - 114 - - 116 - - 117 - - 118 - - 121 - - 122 - - 123 - - 124 - - 125 - - 126 - - 130 - - 131 - - 133 - - 134 - - 135 - - 136 - - 138 - - 139 - - 140 - - 143 - - 144 - - 145 - - 146 - - 147 - - 148 - - 149 - - 150 - - 151 - - 152 - - 154 - - 155 - - 156 - - 157 - - 158 - - 159 - - 160 - - 165 - - 171 - - 172 - - 173 - - 165 - - 167 - - 183 - - 184 - - 185 - - 186 - - 187 - - 188 - - 189 - - 190 - - 191 - - 192 - - 193 - - 194 - - 195 - - 196 - - 197 - - 206 +allowedBlocks: + #beds + - WHITE_BED + - ORANGE_BED + - MAGENTA_BED + - LIGHT_BLUE_BED + - YELLOW_BED + - LIME_BED + - PINK_BED + - GRAY_BED + - LIGHT_BED + - CYAN_BED + - PURPLE_BED + - BLUE_BED + - BROWN_BED + - GREEN_BED + - RED_BED + - BLACK_BED + #buttons + - ACACIA_BUTTON + - BIRCH_BUTTON + - DARK_OAK_BUTTON + - JUNGLE_BUTTON + - OAK_BUTTON + - SPRUCE_BUTTON + - STONE_BUTTON + #doors + - ACACIA_DOOR + - BIRCH_DOOR + - DARK_OAK_DOOR + - IRON_DOOR + - JUNGLE_DOOR + - OAK_DOOR + - SPRUCE_DOOR + #fences + - ACACIA_FENCE + - BIRCH_FENCE + - DARK_OAK_FENCE + - JUNGLE_FENCE + - OAK_FENCE + - SPRUCE_FENCE + #fence gates + - ACACIA_FENCE_GATE + - BIRCH_FENCE_GATE + - DARK_OAK_FENCE_GATE + - JUNGLE_FENCE_GATE + - OAK_FENCE_GATE + - SPRUCE_FENCE_GATE + #glass + - GLASS + - WHITE_STAINED_GLASS + - ORANGE_STAINED_GLASS + - MAGENTA_STAINED_GLASS + - LIGHT_BLUE_STAINED_GLASS + - YELLOW_STAINED_GLASS + - LIME_STAINED_GLASS + - PINK_STAINED_GLASS + - GRAY_STAINED_GLASS + - LIGHT_GRAY_STAINED_GLASS + - CYAN_STAINED_GLASS + - PURPLE_STAINED_GLASS + - BLUE_STAINED_GLASS + - BROWN_STAINED_GLASS + - GREEN_STAINED_GLASS + - RED_STAINED_GLASS + - BLACK_STAINED_GLASS + #glass pane + - GLASS_PANE + - WHITE_STAINED_GLASS_PANE + - ORANGE_STAINED_GLASS_PANE + - MAGENTA_STAINED_GLASS_PANE + - LIGHT_BLUE_STAINED_GLASS_PANE + - YELLOW_STAINED_GLASS_PANE + - LIME_STAINED_GLASS_PANE + - PINK_STAINED_GLASS_PANE + - GRAY_STAINED_GLASS_PANE + - LIGHT_GRAY_STAINED_GLASS_PANE + - CYAN_STAINED_GLASS_PANE + - PURPLE_STAINED_GLASS_PANE + - BLUE_STAINED_GLASS_PANE + - BROWN_STAINED_GLASS_PANE + - GREEN_STAINED_GLASS_PANE + - RED_STAINED_GLASS_PANE + - BLACK_STAINED_GLASS_PANE + #interior + - BOOKSHELF + - BREWING_STAND + - CAULDRON + - IRON_BARS + - SIGN + - TORCH + - WALL_SIGN + - WALL_TORCH + #liquids + - LAVA + - WATER + #logs + - BIRCH_LOG + - JUNGLE_LOG + - OAK_LOG + - SPRUCE_LOG + - STRIPPED_BIRCH_LOG + - STRIPPED_JUNGLE_LOG + - STRIPPED_OAK_LOG + - STRIPPED_SPRUCE_LOG + #planks + - ACACIA_PLANKS + - BIRCH_PLANKS + - DARK_OAK_PLANKS + - JUNGLE_PLANKS + - OAK_PLANKS + - SPRUCE_PLANKS + #pressure plates + - ACACIA_PRESSURE_PLATE + - BIRCH_PRESSURE_PLATE + - DARK_OAK_PRESSURE_PLATE + - HEAVY_WEIGHTED_PRESSURE_PLATE + - JUNGLE_PRESSURE_PLATE + - LIGHT_WEIGHTED_PRESSURE_PLATE + - OAK_PRESSURE_PLATE + - SPRUCE_PRESSURE_PLATE + #redstone + - COMPARATOR + - NOTE_BLOCK + - PISTON + - PISTON_HEAD + - REDSTONE_BLOCK + - REDSTONE_WIRE + - REPEATER + - REDSTONE_TORCH + - REDSTONE_WALL_TORCH + - STICKY_PISTON + - TRIPWIRE_HOOK + #slabs + - ACACIA_SLAB + - BIRCH_SLAB + - BRICK_SLAB + - COBBLESTONE_SLAB + - DARK_OAK_SLAB + - DARK_PRISMARINE + - JUNGLE_SLAB + - NETHER_BRICK_SLAB + - OAK_SLAB + - PETRIFIED_OAK_SLAB + - PRISMARINE_SLAB + - PRISMARINE_BRICK_SLAB + - RED_SANDSTONE_SLAB + - QUARTZ_SLAB + - SPRUCE_SLAB + - STONE_SLAB + #stairs + - BIRCH_STAIRS + - JUNGLE_STAIRS + - OAK_STAIRS + - SMOOTH_STAIRS + - SPRUCE_STAIRS + #storage + - CHEST + - DISPENSER + - DROPPER + - HOPPER + - TRAPPED_CHEST + #terracotta + - TERRACOTTA + - WHITE_TERRACOTTA + - ORANGE_TERRACOTTA + - MAGENTA_TERRACOTTA + - LIGHT_BLUE_TERRACOTTA + - YELLOW_TERRACOTTA + - LIME_TERRACOTTA + - PINK_TERRACOTTA + - GRAY_TERRACOTTA + - LIGHT_TERRACOTTA + - CYAN_TERRACOTTA + - PURPLE_TERRACOTTA + - BLUE_TERRACOTTA + - BROWN_TERRACOTTA + - GREEN_TERRACOTTA + - RED_TERRACOTTA + - BLACK_TERRACOTTA + #trapdoors + - ACACIA_TRAPDOOR + - BIRCH_TRAPDOOR + - DARK_OAK_TRAPDOOR + - JUNGLE_TRAPDOOR + - OAK_TRAPDOOR + - SPRUCE_TRAPDOOR + #weapon blocks + - COAL_BLOCK + #wood + - ACACIA_WOOD + - BIRCH_WOOD + - DARK_OAK_WOOD + - OAK_WOOD + - SPRUCE_WOOD + - STRIPPED_ACACIA_WOOD + - STRIPPED_BIRCH_WOOD + - STRIPPED_DARK_OAK_WOOD + - STRIPPED_OAK_WOOD + - STRIPPED_SPRUCE_WOOD + #wool + - WHITE_WOOL + - ORANGE_WOOL + - MAGENTA_WOOL + - LIGHT_BLUE_WOOL + - YELLOW_WOOL + - LIME_WOOL + - PINK_WOOL + - GRAY_WOOL + - LIGHT_GRAY_WOOL + - CYAN_WOOL + - PURPLE_WOOL + - BLUE_WOOL + - BROWN_WOOL + - GREEN_WOOL + - RED_WOOL + - BLACK_WOOL forbiddenBlocks: - - 34 + - PISTON_HEAD canCruise: true rotateAtMidpoint: true @@ -143,24 +245,24 @@ moveblocks: - 1.0 - 100.0 flyblocks: - 35: #wool represents lift + [WHITE_WOOL, ORANGE_WOOL, MAGENTA_WOOL,LIGHT_BLUE_WOOL,YELLOW_WOOL,LIME_WOOL,PINK_WOOL,GRAY_WOOL,LIGHT_GRAY_WOOL,CYAN_WOOL,PURPLE_WOOL,BLUE_WOOL,BROWN_WOOL, GREEN_WOOL, RED_WOOL, BLACK_WOOL]: #wool represents lift - 50.0 - 100.0 - [54,146]: # limit chests to make big airships important for merchant missions + [CHEST,TRAPPED_CHEST]: # limit chests to make big airships important for merchant missions - 0.0 - 1.0 - [23,154,158]: # dispensers and hoppers can be used for inventory too, so limit them as well + [DISPENSER,DROPPER,HOPPER]: # dispensers and hoppers can be used for inventory too, so limit them as well - 0.0 - 2.0 - 61: # Furnaces for cargo? really guys? + FURNACE: # Furnaces for cargo? really guys? - 0.0 - N50 - 145: # anvils are OP armor, so limit it + ANVIL: # anvils are OP armor, so limit it - 0.0 - 1.0 - 49: # so is obsidian + OBSIDIAN: # so is obsidian - 0.0 - 1.0 - 8: # so is water + WATER: # so is water - 0.0 - 1.0 diff --git a/modules/Movecraft/src/main/resources/types/airskiff.craft b/modules/Movecraft/src/main/resources/types/airskiff.craft index 1857f2b10..f364ed910 100644 --- a/modules/Movecraft/src/main/resources/types/airskiff.craft +++ b/modules/Movecraft/src/main/resources/types/airskiff.craft @@ -1,84 +1,208 @@ name: Airskiff maxSize: 80 minSize: 10 -allowedBlocks: - - 5 - - 8 - - 9 - - 10 - - 11 - - 17 - - 20 # - - 23 # - - 25 # - - 26 # - - 29 # - - 33 # - - 35 - - 41 # - - 43 # - - 44 # - - 47 # - - 50 # - - 52 - - 53 - - 54 # - - 55 - - 57 # - - 58 # - - 61 # - - 62 # - - 63 # - - 64 # - - 65 # - - 68 # - - 69 # - - 72 - - 75 # - - 76 # - - 77 # - - 85 - - 92 - - 93 - - 94 - - 95 # - - 96 # - - 101 # - - 102 # - - 107 - - 113 # - - 117 - - 118 # - - 123 # - - 124 # - - 125 - - 126 - - 130 # - - 131 # - - 133 # - - 134 - - 135 - - 136 - - 138 - - 140 - - 143 # - - 144 # - - 145 - - 146 # - - 147 - - 148 - - 149 - - 150 - - 151 - - 152 # - - 154 # - - 157 - - 165 # - - 171 - - 173 +allowedBlocks: + #beds + - WHITE_BED + - ORANGE_BED + - MAGENTA_BED + - LIGHT_BLUE_BED + - YELLOW_BED + - LIME_BED + - PINK_BED + - GRAY_BED + - LIGHT_BED + - CYAN_BED + - PURPLE_BED + - BLUE_BED + - BROWN_BED + - GREEN_BED + - RED_BED + - BLACK_BED + #buttons + - ACACIA_BUTTON + - BIRCH_BUTTON + - DARK_OAK_BUTTON + - JUNGLE_BUTTON + - OAK_BUTTON + - SPRUCE_BUTTON + - STONE_BUTTON + #doors + - ACACIA_DOOR + - BIRCH_DOOR + - DARK_OAK_DOOR + - IRON_DOOR + - JUNGLE_DOOR + - OAK_DOOR + - SPRUCE_DOOR + #fences + - ACACIA_FENCE + - BIRCH_FENCE + - DARK_OAK_FENCE + - JUNGLE_FENCE + - OAK_FENCE + - SPRUCE_FENCE + #fence gates + - ACACIA_FENCE_GATE + - BIRCH_FENCE_GATE + - DARK_OAK_FENCE_GATE + - JUNGLE_FENCE_GATE + - OAK_FENCE_GATE + - SPRUCE_FENCE_GATE + #glass + - GLASS + - WHITE_STAINED_GLASS + - ORANGE_STAINED_GLASS + - MAGENTA_STAINED_GLASS + - LIGHT_BLUE_STAINED_GLASS + - YELLOW_STAINED_GLASS + - LIME_STAINED_GLASS + - PINK_STAINED_GLASS + - GRAY_STAINED_GLASS + - LIGHT_GRAY_STAINED_GLASS + - CYAN_STAINED_GLASS + - PURPLE_STAINED_GLASS + - BLUE_STAINED_GLASS + - BROWN_STAINED_GLASS + - GREEN_STAINED_GLASS + - RED_STAINED_GLASS + - BLACK_STAINED_GLASS + #glass pane + - GLASS_PANE + - WHITE_STAINED_GLASS_PANE + - ORANGE_STAINED_GLASS_PANE + - MAGENTA_STAINED_GLASS_PANE + - LIGHT_BLUE_STAINED_GLASS_PANE + - YELLOW_STAINED_GLASS_PANE + - LIME_STAINED_GLASS_PANE + - PINK_STAINED_GLASS_PANE + - GRAY_STAINED_GLASS_PANE + - LIGHT_GRAY_STAINED_GLASS_PANE + - CYAN_STAINED_GLASS_PANE + - PURPLE_STAINED_GLASS_PANE + - BLUE_STAINED_GLASS_PANE + - BROWN_STAINED_GLASS_PANE + - GREEN_STAINED_GLASS_PANE + - RED_STAINED_GLASS_PANE + - BLACK_STAINED_GLASS_PANE + #interior + - BOOKSHELF + - BREWING_STAND + - CAULDRON + - IRON_BARS + - SIGN + - TORCH + - WALL_SIGN + - WALL_TORCH + #liquids + - LAVA + - WATER + #logs + - BIRCH_LOG + - JUNGLE_LOG + - OAK_LOG + - SPRUCE_LOG + - STRIPPED_BIRCH_LOG + - STRIPPED_JUNGLE_LOG + - STRIPPED_OAK_LOG + - STRIPPED_SPRUCE_LOG + #planks + - ACACIA_PLANKS + - BIRCH_PLANKS + - DARK_OAK_PLANKS + - JUNGLE_PLANKS + - OAK_PLANKS + - SPRUCE_PLANKS + #pressure plates + - ACACIA_PRESSURE_PLATE + - BIRCH_PRESSURE_PLATE + - DARK_OAK_PRESSURE_PLATE + - HEAVY_WEIGHTED_PRESSURE_PLATE + - JUNGLE_PRESSURE_PLATE + - LIGHT_WEIGHTED_PRESSURE_PLATE + - OAK_PRESSURE_PLATE + - SPRUCE_PRESSURE_PLATE + #redstone + - COMPARATOR + - NOTE_BLOCK + - PISTON + - PISTON_HEAD + - REDSTONE_BLOCK + - REDSTONE_WIRE + - REPEATER + - REDSTONE_TORCH + - REDSTONE_WALL_TORCH + - STICKY_PISTON + - TRIPWIRE_HOOK + #slabs + - ACACIA_SLAB + - BIRCH_SLAB + - BRICK_SLAB + - COBBLESTONE_SLAB + - DARK_OAK_SLAB + - DARK_PRISMARINE + - JUNGLE_SLAB + - NETHER_BRICK_SLAB + - OAK_SLAB + - PETRIFIED_OAK_SLAB + - PRISMARINE_SLAB + - PRISMARINE_BRICK_SLAB + - RED_SANDSTONE_SLAB + - QUARTZ_SLAB + - SPRUCE_SLAB + - STONE_SLAB + #stairs + - BIRCH_STAIRS + - JUNGLE_STAIRS + - OAK_STAIRS + - SMOOTH_STAIRS + - SPRUCE_STAIRS + #storage + - CHEST + - DISPENSER + - DROPPER + - HOPPER + - TRAPPED_CHEST + #trapdoors + - ACACIA_TRAPDOOR + - BIRCH_TRAPDOOR + - DARK_OAK_TRAPDOOR + - JUNGLE_TRAPDOOR + - OAK_TRAPDOOR + - SPRUCE_TRAPDOOR + #weapon blocks + - COAL_BLOCK + #wood + - ACACIA_WOOD + - BIRCH_WOOD + - DARK_OAK_WOOD + - OAK_WOOD + - SPRUCE_WOOD + - STRIPPED_ACACIA_WOOD + - STRIPPED_BIRCH_WOOD + - STRIPPED_DARK_OAK_WOOD + - STRIPPED_OAK_WOOD + - STRIPPED_SPRUCE_WOOD + #wool + - WHITE_WOOL + - ORANGE_WOOL + - MAGENTA_WOOL + - LIGHT_BLUE_WOOL + - YELLOW_WOOL + - LIME_WOOL + - PINK_WOOL + - GRAY_WOOL + - LIGHT_GRAY_WOOL + - CYAN_WOOL + - PURPLE_WOOL + - BLUE_WOOL + - BROWN_WOOL + - GREEN_WOOL + - RED_WOOL + - BLACK_WOOL forbiddenBlocks: - - 34 + - PISTON_HEAD canFly: true rotateAtMidpoint: true @@ -102,24 +226,24 @@ speed: 3.0 tryNudge: false sinkPercent: 99.0 flyblocks: - 35: #wool represents lift + [WHITE_WOOL, ORANGE_WOOL, MAGENTA_WOOL,LIGHT_BLUE_WOOL,YELLOW_WOOL,LIME_WOOL,PINK_WOOL,GRAY_WOOL,LIGHT_GRAY_WOOL,CYAN_WOOL,PURPLE_WOOL,BLUE_WOOL,BROWN_WOOL, GREEN_WOOL, RED_WOOL, BLACK_WOOL]: #wool represents lift - 50.0 - 100.0 - [54,146]: # limit chests to make big airships important for merchant missions + [CHEST,TRAPPED_CHEST]: # limit chests to make big airships important for merchant missions - 0.0 - N2 - [23,154]: # dispensers and hoppers can be used for inventory too, so limit them as well + [DISPENSER,HOPPER]: # dispensers and hoppers can be used for inventory too, so limit them as well - 0.0 - 6.0 - 152: # redstone represents engines + REDSTONE_BLOCK: # redstone represents engines - 8.0 - 100.0 - 145: # anvils are OP armor, so limit it + ANVIL: # anvils are OP armor, so limit it - 0.0 - 1.0 - 49: # so is obsidian + OBSIDIAN: # so is obsidian - 0.0 - 1.0 - 8: # so is water + WATER: # so is water - 0.0 - 1.0 diff --git a/modules/Movecraft/src/main/resources/types/elevator.craft b/modules/Movecraft/src/main/resources/types/elevator.craft index a9f3e2dfc..8ebe8d222 100644 --- a/modules/Movecraft/src/main/resources/types/elevator.craft +++ b/modules/Movecraft/src/main/resources/types/elevator.craft @@ -1,98 +1,208 @@ name: elevator maxSize: 1000 minSize: 10 -allowedBlocks: - - 5 - - 8 - - 9 - - 10 - - 11 - - 17 - - 20 - - 23 - - 25 - - 26 - - 29 - - 33 - - 35 - - 41 - - 43 - - 44 - - 47 - - 50 - - 52 - - 53 - - 54 - - 55 - - 57 - - 58 - - 61 - - 62 - - 63 - - 64 - - 65 - - 68 - - 69 - - 72 - - 75 - - 76 - - 77 - - 85 - - 92 - - 93 - - 94 - - 95 - - 96 - - 101 - - 102 - - 107 - - 112 - - 113 - - 114 - - 117 - - 118 - - 123 - - 124 - - 125 - - 126 - - 130 - - 131 - - 133 - - 134 - - 135 - - 117 - - 118 - - 123 - - 124 - - 125 - - 126 - - 130 - - 131 - - 133 - - 134 - - 135 - - 136 - - 138 - - 140 - - 143 - - 144 - - 145 - - 146 - - 147 - - 148 - - 149 - - 150 - - 151 - - 152 - - 154 - - 157 - - 158 - - 165 - - 171 - - 173 +allowedBlocks: + #beds + - WHITE_BED + - ORANGE_BED + - MAGENTA_BED + - LIGHT_BLUE_BED + - YELLOW_BED + - LIME_BED + - PINK_BED + - GRAY_BED + - LIGHT_BED + - CYAN_BED + - PURPLE_BED + - BLUE_BED + - BROWN_BED + - GREEN_BED + - RED_BED + - BLACK_BED + #buttons + - ACACIA_BUTTON + - BIRCH_BUTTON + - DARK_OAK_BUTTON + - JUNGLE_BUTTON + - OAK_BUTTON + - SPRUCE_BUTTON + - STONE_BUTTON + #doors + - ACACIA_DOOR + - BIRCH_DOOR + - DARK_OAK_DOOR + - IRON_DOOR + - JUNGLE_DOOR + - OAK_DOOR + - SPRUCE_DOOR + #fences + - ACACIA_FENCE + - BIRCH_FENCE + - DARK_OAK_FENCE + - JUNGLE_FENCE + - OAK_FENCE + - SPRUCE_FENCE + #fence gates + - ACACIA_FENCE_GATE + - BIRCH_FENCE_GATE + - DARK_OAK_FENCE_GATE + - JUNGLE_FENCE_GATE + - OAK_FENCE_GATE + - SPRUCE_FENCE_GATE + #glass + - GLASS + - WHITE_STAINED_GLASS + - ORANGE_STAINED_GLASS + - MAGENTA_STAINED_GLASS + - LIGHT_BLUE_STAINED_GLASS + - YELLOW_STAINED_GLASS + - LIME_STAINED_GLASS + - PINK_STAINED_GLASS + - GRAY_STAINED_GLASS + - LIGHT_GRAY_STAINED_GLASS + - CYAN_STAINED_GLASS + - PURPLE_STAINED_GLASS + - BLUE_STAINED_GLASS + - BROWN_STAINED_GLASS + - GREEN_STAINED_GLASS + - RED_STAINED_GLASS + - BLACK_STAINED_GLASS + #glass pane + - GLASS_PANE + - WHITE_STAINED_GLASS_PANE + - ORANGE_STAINED_GLASS_PANE + - MAGENTA_STAINED_GLASS_PANE + - LIGHT_BLUE_STAINED_GLASS_PANE + - YELLOW_STAINED_GLASS_PANE + - LIME_STAINED_GLASS_PANE + - PINK_STAINED_GLASS_PANE + - GRAY_STAINED_GLASS_PANE + - LIGHT_GRAY_STAINED_GLASS_PANE + - CYAN_STAINED_GLASS_PANE + - PURPLE_STAINED_GLASS_PANE + - BLUE_STAINED_GLASS_PANE + - BROWN_STAINED_GLASS_PANE + - GREEN_STAINED_GLASS_PANE + - RED_STAINED_GLASS_PANE + - BLACK_STAINED_GLASS_PANE + #interior + - BOOKSHELF + - BREWING_STAND + - CAULDRON + - IRON_BARS + - SIGN + - TORCH + - WALL_SIGN + - WALL_TORCH + #liquids + - LAVA + - WATER + #logs + - BIRCH_LOG + - JUNGLE_LOG + - OAK_LOG + - SPRUCE_LOG + - STRIPPED_BIRCH_LOG + - STRIPPED_JUNGLE_LOG + - STRIPPED_OAK_LOG + - STRIPPED_SPRUCE_LOG + #planks + - ACACIA_PLANKS + - BIRCH_PLANKS + - DARK_OAK_PLANKS + - JUNGLE_PLANKS + - OAK_PLANKS + - SPRUCE_PLANKS + #pressure plates + - ACACIA_PRESSURE_PLATE + - BIRCH_PRESSURE_PLATE + - DARK_OAK_PRESSURE_PLATE + - HEAVY_WEIGHTED_PRESSURE_PLATE + - JUNGLE_PRESSURE_PLATE + - LIGHT_WEIGHTED_PRESSURE_PLATE + - OAK_PRESSURE_PLATE + - SPRUCE_PRESSURE_PLATE + #redstone + - COMPARATOR + - NOTE_BLOCK + - PISTON + - PISTON_HEAD + - REDSTONE_BLOCK + - REDSTONE_WIRE + - REPEATER + - REDSTONE_TORCH + - REDSTONE_WALL_TORCH + - STICKY_PISTON + - TRIPWIRE_HOOK + #slabs + - ACACIA_SLAB + - BIRCH_SLAB + - BRICK_SLAB + - COBBLESTONE_SLAB + - DARK_OAK_SLAB + - DARK_PRISMARINE + - JUNGLE_SLAB + - NETHER_BRICK_SLAB + - OAK_SLAB + - PETRIFIED_OAK_SLAB + - PRISMARINE_SLAB + - PRISMARINE_BRICK_SLAB + - RED_SANDSTONE_SLAB + - QUARTZ_SLAB + - SPRUCE_SLAB + - STONE_SLAB + #stairs + - BIRCH_STAIRS + - JUNGLE_STAIRS + - OAK_STAIRS + - SMOOTH_STAIRS + - SPRUCE_STAIRS + #storage + - CHEST + - DISPENSER + - DROPPER + - HOPPER + - TRAPPED_CHEST + #trapdoors + - ACACIA_TRAPDOOR + - BIRCH_TRAPDOOR + - DARK_OAK_TRAPDOOR + - JUNGLE_TRAPDOOR + - OAK_TRAPDOOR + - SPRUCE_TRAPDOOR + #weapon blocks + - COAL_BLOCK + #wood + - ACACIA_WOOD + - BIRCH_WOOD + - DARK_OAK_WOOD + - OAK_WOOD + - SPRUCE_WOOD + - STRIPPED_ACACIA_WOOD + - STRIPPED_BIRCH_WOOD + - STRIPPED_DARK_OAK_WOOD + - STRIPPED_OAK_WOOD + - STRIPPED_SPRUCE_WOOD + #wool + - WHITE_WOOL + - ORANGE_WOOL + - MAGENTA_WOOL + - LIGHT_BLUE_WOOL + - YELLOW_WOOL + - LIME_WOOL + - PINK_WOOL + - GRAY_WOOL + - LIGHT_GRAY_WOOL + - CYAN_WOOL + - PURPLE_WOOL + - BLUE_WOOL + - BROWN_WOOL + - GREEN_WOOL + - RED_WOOL + - BLACK_WOOL forbiddenBlocks: - - 7 + - PISTON_HEAD canFly: true canCruise: false @@ -108,6 +218,6 @@ speed: 1.0 tryNudge: false sinkPercent: 99.0 flyblocks: - 35: + [WHITE_WOOL, ORANGE_WOOL, MAGENTA_WOOL,LIGHT_BLUE_WOOL,YELLOW_WOOL,LIME_WOOL,PINK_WOOL,GRAY_WOOL,LIGHT_GRAY_WOOL,CYAN_WOOL,PURPLE_WOOL,BLUE_WOOL,BROWN_WOOL, GREEN_WOOL, RED_WOOL, BLACK_WOOL]: #wool represents lift - 0.0 - 100.0 \ No newline at end of file diff --git a/modules/Movecraft/src/main/resources/types/legacy/BigAirship.craft b/modules/Movecraft/src/main/resources/types/legacy/BigAirship.craft new file mode 100644 index 000000000..b74bec32b --- /dev/null +++ b/modules/Movecraft/src/main/resources/types/legacy/BigAirship.craft @@ -0,0 +1,167 @@ +name: BigAirship +maxSize: 20000 +minSize: 10000 +allowedBlocks: + WOOD: + STATIONARY_WATER: + WATER: + STATIONARY_LAVA: + LAVA: + LOG: + GLASS: + LAPIS_BLOCK: + DISPENSER: + NOTE_BLOCK: + BED_BLOCK: + PISTON_STICKY_BASE: + PISTON_BASE: + PISTON_EXTENSION: + WOOL: + GOLD_BLOCK: + IRON_BLOCK: + DOUBLE_STEP: + STEP: + BOOKSHELF: + TORCH: + FIRE: + WOOD_STAIRS: + CHEST: + REDSTONE_WIRE: + DIAMOND_BLOCK: + WORKBENCH: + FURNACE: + BURNING_FURNACE: + SIGN_POST: + WOOD_DOOR: + LADDER: + WALL_SIGN: + LEVER: + STONE_PLATE: + IRON_DOOR: + WOOD_PLATE: + REDSTONE_TORCH_ON: + REDSTONE_TORCH_OFF: + STONE_BUTTON: + CLAY: + FENCE: + NETHERRACK: + GLOWSTONE: + CAKE_BLOCK: + DIODE_BLOCK_OFF: + DIODE_BLOCK_ON: + STAINED_GLASS: + TRAP_DOOR: + SMOOTH_BRICK: + IRON_FENCE: + THIN_GLASS: + FENCE_GATE: + SMOOTH_STAIRS: + NETHER_BRICK: + NETHER_FENCE: + NETHER_BRICK_STAIRS: + ENCHANTMENT_TABLE: + BREWING_STAND: + CAULDRON: + ENDER_STONE: + DRAGON_EGG: + REDSTONE_LAMP_ON: + REDSTONE_LAMP_OFF: + WOOD_DOUBLE_STEP: + WOOD_STEP: + ENDER_CHEST: + TRIPWIRE_HOOK: + EMERALD_BLOCK: + SPRUCE_WOOD_STAIRS: + BIRCH_WOOD_STAIRS: + JUNGLE_WOOD_STAIRS: + BEACON: + COBBLE_WALL: + FLOWER_POT: + WOOD_BUTTON: + SKULL: + ANVIL: + TRAPPED_CHEST: + GOLD_PLATE: + IRON_PLATE: + REDSTONE_COMPARATOR_OFF: + REDSTONE_COMPARATOR_ON: + DAYLIGHT_SENSOR: + REDSTONE_BLOCK: + HOPPER: + QUARTZ_BLOCK: + QUARTZ_STAIRS: + ACTIVATOR_RAIL: + DROPPER: + STAINED_CLAY: + STAINED_GLASS_PANE: + SLIME_BLOCK: + CARPET: + HARD_CLAY: + COAL_BLOCK: + IRON_TRAPDOOR: + DAYLIGHT_SENSOR_INVERTED: + SPRUCE_FENCE_GATE: + BIRCH_FENCE_GATE: + JUNGLE_FENCE_GATE: + DARK_OAK_FENCE_GATE: + ACACIA_FENCE_GATE: + SPRUCE_FENCE: + BIRCH_FENCE: + JUNGLE_FENCE: + ACACIA_FENCE: + DARK_OAK_FENCE: + SPRUCE_DOOR: + BIRCH_DOOR: + JUNGLE_DOOR: + ACACIA_DOOR: + DARK_OAK_DOOR: + END_BRICKS: + +forbiddenBlocks: + PISTON_EXTENSION: + +canCruise: true +rotateAtMidpoint: true +blockRemoteRotate: true +canFly: true +maxHeightLimit: 110 +maxHeightAboveGround: 50 +vertCruiseSkipBlocks: 1 +collisionExplosion: 0.0 +speed: 0.3 +detectionMultiplier: 10.0 +underwaterDetectionMultiplier: 1.0 +cruiseSkipBlocks: 4 +cruiseSpeed: 0.3 +fuelBurnRate: 4.0 +sinkPercent: 99.0 +overallSinkPercent: 60.0 +tryNudge: false +canStaticMove: true +maxStaticMove: 2 +moveblocks: + REDSTONNE_BLOCK: # redstone represents engines + - 1.0 + - 100.0 +flyblocks: + WOOL: #wool represents lift + - 50.0 + - 100.0 + [CHEST, TRAPPED_CHEST]: # limit chests to make big airships important for merchant missions + - 0.0 + - 1.0 + [DISPENSER, DROPPER, HOPPER]: # dispensers and hoppers can be used for inventory too, so limit them as well + - 0.0 + - 2.0 + FURNACE: # Furnaces for cargo? really guys? + - 0.0 + - N50 + ANVIL: # anvils are OP armor, so limit it + - 0.0 + - 1.0 + OBSIDIAN: # so is obsidian + - 0.0 + - 1.0 + STATIONARY_WATER: # so is water + - 0.0 + - 1.0 diff --git a/modules/Movecraft/src/main/resources/types/legacy/BigSubAirship.craft b/modules/Movecraft/src/main/resources/types/legacy/BigSubAirship.craft new file mode 100644 index 000000000..258fe1b8e --- /dev/null +++ b/modules/Movecraft/src/main/resources/types/legacy/BigSubAirship.craft @@ -0,0 +1,170 @@ +name: BigSubAirship +maxSize: 20000 +minSize: 10000 +allowedBlocks: + WOOD: + STATIONARY_WATER: + WATER: + STATIONARY_LAVA: + LAVA: + LOG: + GLASS: + LAPIS_BLOCK: + DISPENSER: + NOTE_BLOCK: + BED_BLOCK: + PISTON_STICKY_BASE: + PISTON_BASE: + PISTON_EXTENSION: + WOOL: + GOLD_BLOCK: + IRON_BLOCK: + DOUBLE_STEP: + STEP: + BOOKSHELF: + TORCH: + FIRE: + WOOD_STAIRS: + CHEST: + REDSTONE_WIRE: + DIAMOND_BLOCK: + WORKBENCH: + FURNACE: + BURNING_FURNACE: + SIGN_POST: + WOOD_DOOR: + LADDER: + WALL_SIGN: + LEVER: + STONE_PLATE: + IRON_DOOR: + WOOD_PLATE: + REDSTONE_TORCH_ON: + REDSTONE_TORCH_OFF: + STONE_BUTTON: + CLAY: + FENCE: + NETHERRACK: + GLOWSTONE: + CAKE_BLOCK: + DIODE_BLOCK_OFF: + DIODE_BLOCK_ON: + STAINED_GLASS: + TRAP_DOOR: + SMOOTH_BRICK: + IRON_FENCE: + THIN_GLASS: + FENCE_GATE: + SMOOTH_STAIRS: + NETHER_BRICK: + NETHER_FENCE: + NETHER_BRICK_STAIRS: + ENCHANTMENT_TABLE: + BREWING_STAND: + CAULDRON: + ENDER_STONE: + DRAGON_EGG: + REDSTONE_LAMP_ON: + REDSTONE_LAMP_OFF: + WOOD_DOUBLE_STEP: + WOOD_STEP: + ENDER_CHEST: + TRIPWIRE_HOOK: + EMERALD_BLOCK: + SPRUCE_WOOD_STAIRS: + BIRCH_WOOD_STAIRS: + JUNGLE_WOOD_STAIRS: + BEACON: + COBBLE_WALL: + FLOWER_POT: + WOOD_BUTTON: + SKULL: + ANVIL: + TRAPPED_CHEST: + GOLD_PLATE: + IRON_PLATE: + REDSTONE_COMPARATOR_OFF: + REDSTONE_COMPARATOR_ON: + DAYLIGHT_SENSOR: + REDSTONE_BLOCK: + HOPPER: + QUARTZ_BLOCK: + QUARTZ_STAIRS: + ACTIVATOR_RAIL: + DROPPER: + STAINED_CLAY: + STAINED_GLASS_PANE: + SLIME_BLOCK: + CARPET: + HARD_CLAY: + COAL_BLOCK: + IRON_TRAPDOOR: + DAYLIGHT_SENSOR_INVERTED: + SPRUCE_FENCE_GATE: + BIRCH_FENCE_GATE: + JUNGLE_FENCE_GATE: + DARK_OAK_FENCE_GATE: + ACACIA_FENCE_GATE: + SPRUCE_FENCE: + BIRCH_FENCE: + JUNGLE_FENCE: + ACACIA_FENCE: + DARK_OAK_FENCE: + SPRUCE_DOOR: + BIRCH_DOOR: + JUNGLE_DOOR: + ACACIA_DOOR: + DARK_OAK_DOOR: + END_BRICKS: + +forbiddenBlocks: + PISTON_EXTENSION: + +canCruise: true +rotateAtMidpoint: true +blockRemoteRotate: true +cruiseSkipBlocks: 4 +cruiseSpeed: 0.17 +canFly: false +minHeightLimit: 1 +maxHeightLimit: 110 +maxHeightAboveGround: 50 +vertCruiseSkipBlocks: 1 +detectionMultiplier: 10.0 +underwaterDetectionMultiplier: 1.0 +speed: 0.17 +collisionExplosion: 0.0 +fuelBurnRate: 4.0 +tryNudge: false +sinkPercent: 99.0 +overallSinkPercent: 60.0 +halfSpeedUnderwater: true +moveblocks: + REDSTONNE_BLOCK: # redstone represents engines + - 1.0 + - 100.0 +flyblocks: + IRON_BLOCK: # iron represents ballast tanks + - 10.0 + - 100.0 + WOOL: #wool represents lift + - 50.0 + - 100.0 + [CHEST, TRAPPED_CHEST]: # limit chests to make big airships important for merchant missions + - 0.0 + - 1.0 + [DISPENSER, DROPPER, HOPPER]: # dispensers and hoppers can be used for inventory too, so limit them as well + - 0.0 + - 2.0 + FURNACE: # Furnaces for cargo? really guys? + - 0.0 + - N50 + ANVIL: # anvils are OP armor, so limit it + - 0.0 + - 1.0 + OBSIDIAN: # so is obsidian + - 0.0 + - 1.0 + STATIONARY_WATER: # so is water + - 0.0 + - 1.0 diff --git a/modules/Movecraft/src/main/resources/types/legacy/LaunchTorpedo.craft b/modules/Movecraft/src/main/resources/types/legacy/LaunchTorpedo.craft new file mode 100644 index 000000000..0bd95152b --- /dev/null +++ b/modules/Movecraft/src/main/resources/types/legacy/LaunchTorpedo.craft @@ -0,0 +1,30 @@ +name: LaunchTorpedo +maxSize: 7 +minSize: 1 +allowedBlocks: + COAL_BLOCK: + +forbiddenBlocks: + BEDROCK: + +canCruise: true +cruiseOnPilot: true +focusedExplosion: true +mustBeSubcraft: true +cruiseSkipBlocks: 1 +canFly: false +minHeightLimit: 65 +maxHeightLimit: 65 +detectionMultiplier: 40.0 +underwaterDetectionMultiplier: 4.0 +collisionExplosion: 3.0 +explodeOnCrash: 3.0 +moveEntities: false +speed: 9.0 +tryNudge: false +sinkPercent: 99.0 +overallSinkPercent: 99.0 +flyblocks: + COAL_BLOCK: + - 10.0 + - 100.0 diff --git a/modules/Movecraft/src/main/resources/types/legacy/Ship.craft b/modules/Movecraft/src/main/resources/types/legacy/Ship.craft new file mode 100644 index 000000000..c9bc67f68 --- /dev/null +++ b/modules/Movecraft/src/main/resources/types/legacy/Ship.craft @@ -0,0 +1,143 @@ +name: Ship +maxSize: 100000 +minSize: 10 +allowedBlocks: + WOOD: + STATIONARY_WATER: + WATER: + STATIONARY_LAVA: + LAVA: + LOG: + GLASS: + LAPIS_BLOCK: + DISPENSER: + NOTE_BLOCK: + BED_BLOCK: + PISTON_STICKY_BASE: + PISTON_BASE: + PISTON_EXTENSION: + WOOL: + GOLD_BLOCK: + IRON_BLOCK: + DOUBLE_STEP: + STEP: + BOOKSHELF: + TORCH: + FIRE: + WOOD_STAIRS: + CHEST: + REDSTONE_WIRE: + DIAMOND_BLOCK: + WORKBENCH: + FURNACE: + BURNING_FURNACE: + SIGN_POST: + WOOD_DOOR: + LADDER: + WALL_SIGN: + LEVER: + STONE_PLATE: + IRON_DOOR: + WOOD_PLATE: + REDSTONE_TORCH_ON: + REDSTONE_TORCH_OFF: + STONE_BUTTON: + CLAY: + FENCE: + NETHERRACK: + GLOWSTONE: + CAKE_BLOCK: + DIODE_BLOCK_OFF: + DIODE_BLOCK_ON: + STAINED_GLASS: + TRAP_DOOR: + SMOOTH_BRICK: + IRON_FENCE: + THIN_GLASS: + FENCE_GATE: + SMOOTH_STAIRS: + NETHER_BRICK: + NETHER_FENCE: + NETHER_BRICK_STAIRS: + ENCHANTMENT_TABLE: + BREWING_STAND: + CAULDRON: + ENDER_STONE: + DRAGON_EGG: + REDSTONE_LAMP_ON: + REDSTONE_LAMP_OFF: + WOOD_DOUBLE_STEP: + WOOD_STEP: + ENDER_CHEST: + TRIPWIRE_HOOK: + EMERALD_BLOCK: + SPRUCE_WOOD_STAIRS: + BIRCH_WOOD_STAIRS: + JUNGLE_WOOD_STAIRS: + BEACON: + COBBLE_WALL: + FLOWER_POT: + WOOD_BUTTON: + SKULL: + ANVIL: + TRAPPED_CHEST: + GOLD_PLATE: + IRON_PLATE: + REDSTONE_COMPARATOR_OFF: + REDSTONE_COMPARATOR_ON: + DAYLIGHT_SENSOR: + REDSTONE_BLOCK: + HOPPER: + QUARTZ_BLOCK: + QUARTZ_STAIRS: + ACTIVATOR_RAIL: + DROPPER: + STAINED_CLAY: + STAINED_GLASS_PANE: + SLIME_BLOCK: + CARPET: + HARD_CLAY: + COAL_BLOCK: + IRON_TRAPDOOR: + DAYLIGHT_SENSOR_INVERTED: + SPRUCE_FENCE_GATE: + BIRCH_FENCE_GATE: + JUNGLE_FENCE_GATE: + DARK_OAK_FENCE_GATE: + ACACIA_FENCE_GATE: + SPRUCE_FENCE: + BIRCH_FENCE: + JUNGLE_FENCE: + ACACIA_FENCE: + DARK_OAK_FENCE: + SPRUCE_DOOR: + BIRCH_DOOR: + JUNGLE_DOOR: + ACACIA_DOOR: + DARK_OAK_DOOR: + END_BRICKS: + +forbiddenBlocks: + BEDROCK: + +canCruise: true +cruiseSkipBlocks: 4 +canFly: false +sinkPercent: 99.0 +overallSinkPercent: 60.0 +minHeightLimit: 50 +maxHeightLimit: 80 +requireWaterContact: true +allowVerticalMovement: false +speed: 0.5 +tryNudge: false +flyblocks: + WOOD: + - 25.0 + - 100.0 + ANVIL: # anvils are OP armor, so limit it + - 0.0 + - 1.0 + OBSIDIAN: # so is obsidian + - 0.0 + - 1.0 diff --git a/modules/Movecraft/src/main/resources/types/legacy/SubAirship.craft b/modules/Movecraft/src/main/resources/types/legacy/SubAirship.craft new file mode 100644 index 000000000..0983b3fbf --- /dev/null +++ b/modules/Movecraft/src/main/resources/types/legacy/SubAirship.craft @@ -0,0 +1,169 @@ +name: SubAirship +maxSize: 5000 +minSize: 1000 +allowedBlocks: + WOOD: + STATIONARY_WATER: + WATER: + STATIONARY_LAVA: + LAVA: + LOG: + GLASS: + LAPIS_BLOCK: + DISPENSER: + NOTE_BLOCK: + BED_BLOCK: + PISTON_STICKY_BASE: + PISTON_BASE: + PISTON_EXTENSION: + WOOL: + GOLD_BLOCK: + IRON_BLOCK: + DOUBLE_STEP: + STEP: + BOOKSHELF: + TORCH: + FIRE: + WOOD_STAIRS: + CHEST: + REDSTONE_WIRE: + DIAMOND_BLOCK: + WORKBENCH: + FURNACE: + BURNING_FURNACE: + SIGN_POST: + WOOD_DOOR: + LADDER: + WALL_SIGN: + LEVER: + STONE_PLATE: + IRON_DOOR: + WOOD_PLATE: + REDSTONE_TORCH_ON: + REDSTONE_TORCH_OFF: + STONE_BUTTON: + CLAY: + FENCE: + NETHERRACK: + GLOWSTONE: + CAKE_BLOCK: + DIODE_BLOCK_OFF: + DIODE_BLOCK_ON: + STAINED_GLASS: + TRAP_DOOR: + SMOOTH_BRICK: + IRON_FENCE: + THIN_GLASS: + FENCE_GATE: + SMOOTH_STAIRS: + NETHER_BRICK: + NETHER_FENCE: + NETHER_BRICK_STAIRS: + ENCHANTMENT_TABLE: + BREWING_STAND: + CAULDRON: + ENDER_STONE: + DRAGON_EGG: + REDSTONE_LAMP_ON: + REDSTONE_LAMP_OFF: + WOOD_DOUBLE_STEP: + WOOD_STEP: + ENDER_CHEST: + TRIPWIRE_HOOK: + EMERALD_BLOCK: + SPRUCE_WOOD_STAIRS: + BIRCH_WOOD_STAIRS: + JUNGLE_WOOD_STAIRS: + BEACON: + COBBLE_WALL: + FLOWER_POT: + WOOD_BUTTON: + SKULL: + ANVIL: + TRAPPED_CHEST: + GOLD_PLATE: + IRON_PLATE: + REDSTONE_COMPARATOR_OFF: + REDSTONE_COMPARATOR_ON: + DAYLIGHT_SENSOR: + REDSTONE_BLOCK: + HOPPER: + QUARTZ_BLOCK: + QUARTZ_STAIRS: + ACTIVATOR_RAIL: + DROPPER: + STAINED_CLAY: + STAINED_GLASS_PANE: + SLIME_BLOCK: + CARPET: + HARD_CLAY: + COAL_BLOCK: + IRON_TRAPDOOR: + DAYLIGHT_SENSOR_INVERTED: + SPRUCE_FENCE_GATE: + BIRCH_FENCE_GATE: + JUNGLE_FENCE_GATE: + DARK_OAK_FENCE_GATE: + ACACIA_FENCE_GATE: + SPRUCE_FENCE: + BIRCH_FENCE: + JUNGLE_FENCE: + ACACIA_FENCE: + DARK_OAK_FENCE: + SPRUCE_DOOR: + BIRCH_DOOR: + JUNGLE_DOOR: + ACACIA_DOOR: + DARK_OAK_DOOR: + END_BRICKS: + +forbiddenBlocks: + PISTON_EXTENSION: + +canCruise: true +rotateAtMidpoint: true +cruiseSkipBlocks: 4 +vertCruiseSkipBlocks: 1 +cruiseSpeed: 0.5 +canFly: false +minHeightLimit: 1 +maxHeightLimit: 135 +maxHeightAboveGround: 50 +speed: 1.0 +collisionExplosion: 0.0 +detectionMultiplier: 10.0 +underwaterDetectionMultiplier: 1.0 +fuelBurnRate: 2.0 +tryNudge: false +halfSpeedUnderwater: true +sinkPercent: 99.0 +overallSinkPercent: 60.0 +moveblocks: + REDSTONNE_BLOCK: # redstone represents engines + - 1.0 + - 100.0 +flyblocks: + IRON_BLOCK: # iron represents ballast tanks + - 10.0 + - 100.0 + WOOL: #wool represents lift + - 50.0 + - 100.0 + [CHEST, TRAPPED_CHEST]: # limit chests to make big airships important for merchant missions + - 0.0 + - 1.0 + [DISPENSER, DROPPER, HOPPER]: # dispensers and hoppers can be used for inventory too, so limit them as well + - 0.0 + - 2.0 + FURNACE: # Furnaces for cargo? really guys? + - 0.0 + - N50 + ANVIL: # anvils are OP armor, so limit it + - 0.0 + - 1.0 + OBSIDIAN: # so is obsidian + - 0.0 + - 1.0 + STATIONARY_WATER: # so is water + - 0.0 + - 1.0 diff --git a/modules/Movecraft/src/main/resources/types/legacy/Submarine.craft b/modules/Movecraft/src/main/resources/types/legacy/Submarine.craft new file mode 100644 index 000000000..750f3f943 --- /dev/null +++ b/modules/Movecraft/src/main/resources/types/legacy/Submarine.craft @@ -0,0 +1,147 @@ +name: Submarine +maxSize: 100000 +minSize: 10 +allowedBlocks: + WOOD: + STATIONARY_WATER: + WATER: + STATIONARY_LAVA: + LAVA: + LOG: + GLASS: + LAPIS_BLOCK: + DISPENSER: + NOTE_BLOCK: + BED_BLOCK: + PISTON_STICKY_BASE: + PISTON_BASE: + PISTON_EXTENSION: + WOOL: + GOLD_BLOCK: + IRON_BLOCK: + DOUBLE_STEP: + STEP: + BOOKSHELF: + TORCH: + FIRE: + WOOD_STAIRS: + CHEST: + REDSTONE_WIRE: + DIAMOND_BLOCK: + WORKBENCH: + FURNACE: + BURNING_FURNACE: + SIGN_POST: + WOOD_DOOR: + LADDER: + WALL_SIGN: + LEVER: + STONE_PLATE: + IRON_DOOR: + WOOD_PLATE: + REDSTONE_TORCH_ON: + REDSTONE_TORCH_OFF: + STONE_BUTTON: + CLAY: + FENCE: + NETHERRACK: + GLOWSTONE: + CAKE_BLOCK: + DIODE_BLOCK_OFF: + DIODE_BLOCK_ON: + STAINED_GLASS: + TRAP_DOOR: + SMOOTH_BRICK: + IRON_FENCE: + THIN_GLASS: + FENCE_GATE: + SMOOTH_STAIRS: + NETHER_BRICK: + NETHER_FENCE: + NETHER_BRICK_STAIRS: + ENCHANTMENT_TABLE: + BREWING_STAND: + CAULDRON: + ENDER_STONE: + DRAGON_EGG: + REDSTONE_LAMP_ON: + REDSTONE_LAMP_OFF: + WOOD_DOUBLE_STEP: + WOOD_STEP: + ENDER_CHEST: + TRIPWIRE_HOOK: + EMERALD_BLOCK: + SPRUCE_WOOD_STAIRS: + BIRCH_WOOD_STAIRS: + JUNGLE_WOOD_STAIRS: + BEACON: + COBBLE_WALL: + FLOWER_POT: + WOOD_BUTTON: + SKULL: + ANVIL: + TRAPPED_CHEST: + GOLD_PLATE: + IRON_PLATE: + REDSTONE_COMPARATOR_OFF: + REDSTONE_COMPARATOR_ON: + DAYLIGHT_SENSOR: + REDSTONE_BLOCK: + HOPPER: + QUARTZ_BLOCK: + QUARTZ_STAIRS: + ACTIVATOR_RAIL: + DROPPER: + STAINED_CLAY: + STAINED_GLASS_PANE: + SLIME_BLOCK: + CARPET: + HARD_CLAY: + COAL_BLOCK: + IRON_TRAPDOOR: + DAYLIGHT_SENSOR_INVERTED: + SPRUCE_FENCE_GATE: + BIRCH_FENCE_GATE: + JUNGLE_FENCE_GATE: + DARK_OAK_FENCE_GATE: + ACACIA_FENCE_GATE: + SPRUCE_FENCE: + BIRCH_FENCE: + JUNGLE_FENCE: + ACACIA_FENCE: + DARK_OAK_FENCE: + SPRUCE_DOOR: + BIRCH_DOOR: + JUNGLE_DOOR: + ACACIA_DOOR: + DARK_OAK_DOOR: + END_BRICKS: + +forbiddenBlocks: + PISTON_EXTENSION: + +canCruise: true +cruiseSkipBlocks: 4 +canFly: false +minHeightLimit: 10 +maxHeightLimit: 67 +sinkPercent: 99.0 +overallSinkPercent: 60.0 +speed: 0.5 +requireWaterContact: true +allowVerticalMovement: true +fuelBurnRate: 1.0 +tryNudge: false +flyblocks: + WOOD: + - 25.0 + - 100.0 + ANVIL: # anvils are OP armor, so limit it + - 0.0 + - 1.0 + OBSIDIAN: # so is obsidian + - 0.0 + - 1.0 + IRON_BLOCK: + - 15.0 + - 100.0 \ No newline at end of file diff --git a/modules/Movecraft/src/main/resources/types/legacy/Turret.craft b/modules/Movecraft/src/main/resources/types/legacy/Turret.craft new file mode 100644 index 000000000..bd1e37d55 --- /dev/null +++ b/modules/Movecraft/src/main/resources/types/legacy/Turret.craft @@ -0,0 +1,140 @@ +name: Turret +maxSize: 1000 +minSize: 1 +allowedBlocks: + WOOD: + STATIONARY_WATER: + WATER: + STATIONARY_LAVA: + LAVA: + LOG: + GLASS: + LAPIS_BLOCK: + DISPENSER: + NOTE_BLOCK: + BED_BLOCK: + PISTON_STICKY_BASE: + PISTON_BASE: + PISTON_EXTENSION: + WOOL: + - 8 + GOLD_BLOCK: + IRON_BLOCK: + DOUBLE_STEP: + STEP: + BOOKSHELF: + TORCH: + FIRE: + WOOD_STAIRS: + CHEST: + REDSTONE_WIRE: + DIAMOND_BLOCK: + WORKBENCH: + FURNACE: + BURNING_FURNACE: + SIGN_POST: + WOOD_DOOR: + LADDER: + WALL_SIGN: + LEVER: + STONE_PLATE: + IRON_DOOR: + WOOD_PLATE: + STONE_BUTTON: + CLAY: + FENCE: + NETHERRACK: + GLOWSTONE: + CAKE_BLOCK: + DIODE_BLOCK_OFF: + DIODE_BLOCK_ON: + STAINED_GLASS: + TRAP_DOOR: + SMOOTH_BRICK: + IRON_FENCE: + THIN_GLASS: + FENCE_GATE: + SMOOTH_STAIRS: + NETHER_BRICK: + NETHER_FENCE: + NETHER_BRICK_STAIRS: + ENCHANTMENT_TABLE: + BREWING_STAND: + CAULDRON: + ENDER_STONE: + DRAGON_EGG: + REDSTONE_LAMP_ON: + REDSTONE_LAMP_OFF: + WOOD_DOUBLE_STEP: + WOOD_STEP: + ENDER_CHEST: + TRIPWIRE_HOOK: + EMERALD_BLOCK: + SPRUCE_WOOD_STAIRS: + BIRCH_WOOD_STAIRS: + JUNGLE_WOOD_STAIRS: + BEACON: + COBBLE_WALL: + FLOWER_POT: + WOOD_BUTTON: + SKULL: + ANVIL: + TRAPPED_CHEST: + GOLD_PLATE: + IRON_PLATE: + REDSTONE_COMPARATOR_OFF: + REDSTONE_COMPARATOR_ON: + DAYLIGHT_SENSOR: + REDSTONE_BLOCK: + HOPPER: + QUARTZ_BLOCK: + QUARTZ_STAIRS: + ACTIVATOR_RAIL: + DROPPER: + STAINED_CLAY: + - 7 + - 8 + - 15 + STAINED_GLASS_PANE: + SLIME_BLOCK: + CARPET: + HARD_CLAY: + COAL_BLOCK: + IRON_TRAPDOOR: + DAYLIGHT_SENSOR_INVERTED: + SPRUCE_FENCE_GATE: + BIRCH_FENCE_GATE: + JUNGLE_FENCE_GATE: + DARK_OAK_FENCE_GATE: + ACACIA_FENCE_GATE: + SPRUCE_FENCE: + BIRCH_FENCE: + JUNGLE_FENCE: + ACACIA_FENCE: + DARK_OAK_FENCE: + SPRUCE_DOOR: + BIRCH_DOOR: + JUNGLE_DOOR: + ACACIA_DOOR: + DARK_OAK_DOOR: + END_BRICKS: + +forbiddenBlocks: + BEDROCK: + +canFly: true +canCruise: false +maxHeightLimit: 144 +collisionExplosion: 0.0 +explodeOnCrash: 2.0 +allowHorizontalMovement: false +allowVerticalMovement: false +allowCannonDirectorSign: true +allowAADirectorSign: true +speed: 1.0 +tryNudge: false +sinkPercent: 99.0 +flyblocks: + WOOL: + - 0.0 + - 100.0 diff --git a/modules/Movecraft/src/main/resources/types/legacy/airship.craft b/modules/Movecraft/src/main/resources/types/legacy/airship.craft new file mode 100644 index 000000000..7004d30d4 --- /dev/null +++ b/modules/Movecraft/src/main/resources/types/legacy/airship.craft @@ -0,0 +1,166 @@ +name: Airship +maxSize: 5000 +minSize: 1000 +allowedBlocks: + WOOD: + STATIONARY_WATER: + WATER: + STATIONARY_LAVA: + LAVA: + LOG: + GLASS: + LAPIS_BLOCK: + DISPENSER: + NOTE_BLOCK: + BED_BLOCK: + PISTON_STICKY_BASE: + PISTON_BASE: + PISTON_EXTENSION: + WOOL: + GOLD_BLOCK: + IRON_BLOCK: + DOUBLE_STEP: + STEP: + BOOKSHELF: + TORCH: + FIRE: + WOOD_STAIRS: + CHEST: + REDSTONE_WIRE: + DIAMOND_BLOCK: + WORKBENCH: + FURNACE: + BURNING_FURNACE: + SIGN_POST: + WOOD_DOOR: + LADDER: + WALL_SIGN: + LEVER: + STONE_PLATE: + IRON_DOOR: + WOOD_PLATE: + REDSTONE_TORCH_ON: + REDSTONE_TORCH_OFF: + STONE_BUTTON: + CLAY: + FENCE: + NETHERRACK: + GLOWSTONE: + CAKE_BLOCK: + DIODE_BLOCK_OFF: + DIODE_BLOCK_ON: + STAINED_GLASS: + TRAP_DOOR: + SMOOTH_BRICK: + IRON_FENCE: + THIN_GLASS: + FENCE_GATE: + SMOOTH_STAIRS: + NETHER_BRICK: + NETHER_FENCE: + NETHER_BRICK_STAIRS: + ENCHANTMENT_TABLE: + BREWING_STAND: + CAULDRON: + ENDER_STONE: + DRAGON_EGG: + REDSTONE_LAMP_ON: + REDSTONE_LAMP_OFF: + WOOD_DOUBLE_STEP: + WOOD_STEP: + ENDER_CHEST: + TRIPWIRE_HOOK: + EMERALD_BLOCK: + SPRUCE_WOOD_STAIRS: + BIRCH_WOOD_STAIRS: + JUNGLE_WOOD_STAIRS: + BEACON: + COBBLE_WALL: + FLOWER_POT: + WOOD_BUTTON: + SKULL: + ANVIL: + TRAPPED_CHEST: + GOLD_PLATE: + IRON_PLATE: + REDSTONE_COMPARATOR_OFF: + REDSTONE_COMPARATOR_ON: + DAYLIGHT_SENSOR: + REDSTONE_BLOCK: + HOPPER: + QUARTZ_BLOCK: + QUARTZ_STAIRS: + ACTIVATOR_RAIL: + DROPPER: + STAINED_CLAY: + STAINED_GLASS_PANE: + SLIME_BLOCK: + CARPET: + HARD_CLAY: + COAL_BLOCK: + IRON_TRAPDOOR: + DAYLIGHT_SENSOR_INVERTED: + SPRUCE_FENCE_GATE: + BIRCH_FENCE_GATE: + JUNGLE_FENCE_GATE: + DARK_OAK_FENCE_GATE: + ACACIA_FENCE_GATE: + SPRUCE_FENCE: + BIRCH_FENCE: + JUNGLE_FENCE: + ACACIA_FENCE: + DARK_OAK_FENCE: + SPRUCE_DOOR: + BIRCH_DOOR: + JUNGLE_DOOR: + ACACIA_DOOR: + DARK_OAK_DOOR: + END_BRICKS: + +forbiddenBlocks: + PISTON_EXTENSION: + +canCruise: true +rotateAtMidpoint: true +canFly: true +maxHeightLimit: 135 +maxHeightAboveGround: 50 +vertCruiseSkipBlocks: 1 +collisionExplosion: 0.0 +detectionMultiplier: 10.0 +underwaterDetectionMultiplier: 1.0 +speed: 1.0 +cruiseSkipBlocks: 4 +cruiseSpeed: 0.5 +fuelBurnRate: 2.0 +sinkPercent: 99.0 +overallSinkPercent: 60.0 +tryNudge: false +canStaticMove: true +maxStaticMove: 2 +moveblocks: + REDSTONNE_BLOCK: # redstone represents engines + - 1.0 + - 100.0 +flyblocks: + WOOL: #wool represents lift + - 50.0 + - 100.0 + [CHEST, TRAPPED_CHEST]: # limit chests to make big airships important for merchant missions + - 0.0 + - 1.0 + [DISPENSER, DROPPER, HOPPER]: # dispensers and hoppers can be used for inventory too, so limit them as well + - 0.0 + - 2.0 + FURNACE: # Furnaces for cargo? really guys? + - 0.0 + - N50 + ANVIL: # anvils are OP armor, so limit it + - 0.0 + - 1.0 + OBSIDIAN: # so is obsidian + - 0.0 + - 1.0 + STATIONARY_WATER: # so is water + - 0.0 + - 1.0 diff --git a/modules/Movecraft/src/main/resources/types/legacy/airskiff.craft b/modules/Movecraft/src/main/resources/types/legacy/airskiff.craft new file mode 100644 index 000000000..b329b2155 --- /dev/null +++ b/modules/Movecraft/src/main/resources/types/legacy/airskiff.craft @@ -0,0 +1,126 @@ +name: Airskiff +maxSize: 80 +minSize: 10 +allowedBlocks: + WOOD: + STATIONARY_WATER: + WATER: + STATIONARY_LAVA: + LAVA: + LOG: + GLASS: + DISPENSER: + NOTE_BLOCK: + BED_BLOCK: + PISTON_STICKY_BASE: + PISTON_BASE: + WOOL: + GOLD_BLOCK: + DOUBLE_STEP: + STEP: + BOOKSHELF: + TORCH: + MOB_SPAWNER: + WOOD_STAIRS: + CHEST: + REDSTONE_WIRE: + DIAMOND_BLOCK: + WORKBENCH: + FURNACE: + BURNING_FURNACE: + SIGN_POST: + WOOD_DOOR: + LADDER: + WALL_SIGN: + LEVER: + STONE_PLATE: + IRON_DOOR: + WOOD_PLATE: + REDSTONE_TORCH_ON: + REDSTONE_TORCH_OFF: + STONE_BUTTON: + FENCE: + CAKE_BLOCK: + DIODE_BLOCK_OFF: + DIODE_BLOCK_ON: + STAINED_GLASS: + TRAP_DOOR: + IRON_FENCE: + THIN_GLASS: + FENCE_GATE: + NETHER_FENCE: + BREWING_STAND: + CAULDRON: + REDSTONE_LAMP_ON: + REDSTONE_LAMP_OFF: + WOOD_DOUBLE_STEP: + WOOD_STEP: + ENDER_CHEST: + TRIPWIRE_HOOK: + EMERALD_BLOCK: + SPRUCE_WOOD_STAIRS: + BIRCH_WOOD_STAIRS: + JUNGLE_WOOD_STAIRS: + BEACON: + WOOD_BUTTON: + SKULL: + ANVIL: + TRAPPED_CHEST: + GOLD_PLATE: + IRON_PLATE: + REDSTONE_COMPARATOR_OFF: + REDSTONE_COMPARATOR_ON: + DAYLIGHT_SENSOR: + REDSTONE_BLOCK: + HOPPER: + ACTIVATOR_RAIL: + SLIME_BLOCK: + CARPET: + COAL_BLOCK: + +forbiddenBlocks: + PISTON_EXTENSION: + +canFly: true +rotateAtMidpoint: true +allowCannonDirectorSign: false +allowAADirectorSign: false +canCruise: true +cruiseSpeed: 1.5 +cruiseSkipBlocks: 1 +maxHeightLimit: 130 +maxHeightAboveGround: 46 +collisionExplosion: 0.0 +fuelBurnRate: 1.0 +explodeOnCrash: 2.0 +sinkSpeed: 3.0 +overallSinkPercent: 97.0 +detectionMultiplier: 20.0 +underwaterDetectionMultiplier: 2.0 +smokeOnSink: 1 +keepMovingOnSink: true +speed: 3.0 +tryNudge: false +sinkPercent: 99.0 +flyblocks: + WOOL: #wool represents lift + - 50.0 + - 100.0 + [CHEST, TRAPPED_CHEST]: # limit chests to make big airships important for merchant missions + - 0.0 + - N2 + [DISPENSER, HOPPER]: # dispensers and hoppers can be used for inventory too, so limit them as well + - 0.0 + - 6.0 + REDSTONE_BLOCK: # redstone represents engines + - 8.0 + - 100.0 + ANVIL: # anvils are OP armor, so limit it + - 0.0 + - 1.0 + OBSIDIAN: # so is obsidian + - 0.0 + - 1.0 + STATIONARY_WATER: # so is water + - 0.0 + - 1.0 diff --git a/modules/Movecraft/src/main/resources/types/legacy/elevator.craft b/modules/Movecraft/src/main/resources/types/legacy/elevator.craft new file mode 100644 index 000000000..0d3426acb --- /dev/null +++ b/modules/Movecraft/src/main/resources/types/legacy/elevator.craft @@ -0,0 +1,100 @@ +name: elevator +maxSize: 1000 +minSize: 10 +allowedBlocks: + WOOD: + STATIONARY_WATER: + WATER: + STATIONARY_LAVA: + LAVA: + LOG: + GLASS: + DISPENSER: + NOTE_BLOCK: + BED_BLOCK: + PISTON_STICKY_BASE: + PISTON_BASE: + WOOL: + GOLD_BLOCK: + DOUBLE_STEP: + STEP: + BOOKSHELF: + TORCH: + MOB_SPAWNER: + WOOD_STAIRS: + CHEST: + REDSTONE_WIRE: + DIAMOND_BLOCK: + WORKBENCH: + FURNACE: + BURNING_FURNACE: + SIGN_POST: + WOOD_DOOR: + LADDER: + WALL_SIGN: + LEVER: + STONE_PLATE: + IRON_DOOR: + WOOD_PLATE: + REDSTONE_TORCH_ON: + REDSTONE_TORCH_OFF: + STONE_BUTTON: + FENCE: + CAKE_BLOCK: + DIODE_BLOCK_OFF: + DIODE_BLOCK_ON: + STAINED_GLASS: + TRAP_DOOR: + IRON_FENCE: + THIN_GLASS: + FENCE_GATE: + NETHER_FENCE: + BREWING_STAND: + CAULDRON: + REDSTONE_LAMP_ON: + REDSTONE_LAMP_OFF: + WOOD_DOUBLE_STEP: + WOOD_STEP: + ENDER_CHEST: + TRIPWIRE_HOOK: + EMERALD_BLOCK: + SPRUCE_WOOD_STAIRS: + BIRCH_WOOD_STAIRS: + JUNGLE_WOOD_STAIRS: + BEACON: + WOOD_BUTTON: + SKULL: + ANVIL: + TRAPPED_CHEST: + GOLD_PLATE: + IRON_PLATE: + REDSTONE_COMPARATOR_OFF: + REDSTONE_COMPARATOR_ON: + DAYLIGHT_SENSOR: + REDSTONE_BLOCK: + HOPPER: + ACTIVATOR_RAIL: + SLIME_BLOCK: + CARPET: + COAL_BLOCK: + +forbiddenBlocks: + BEDROCK: + +canFly: true +canCruise: false +collisionExplosion: 0.0 +allowHorizontalMovement: false +canStaticMove: true +maxStaticMove: 2 +allowCannonDirectorSign: false +detectionMultiplier: 30.0 +underwaterDetectionMultiplier: 3.0 +allowAADirectorSign: false +speed: 1.0 +tryNudge: false +sinkPercent: 99.0 +flyblocks: + WOOL: + - 0.0 + - 100.0 \ No newline at end of file diff --git a/modules/api/pom.xml b/modules/api/pom.xml index 73eeb20e1..249c292f0 100644 --- a/modules/api/pom.xml +++ b/modules/api/pom.xml @@ -35,6 +35,7 @@ worldedit LATEST + org.spigotmc spigot diff --git a/modules/api/src/main/java/net/countercraft/movecraft/MovecraftRepair.java b/modules/api/src/main/java/net/countercraft/movecraft/MovecraftRepair.java new file mode 100644 index 000000000..96518fbc6 --- /dev/null +++ b/modules/api/src/main/java/net/countercraft/movecraft/MovecraftRepair.java @@ -0,0 +1,29 @@ +package net.countercraft.movecraft; + +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard; +import com.sk89q.worldedit.extent.clipboard.Clipboard; +import net.countercraft.movecraft.craft.Craft; +import org.bukkit.Material; +import org.bukkit.World; +import org.bukkit.block.Sign; +import org.bukkit.entity.Player; +import org.bukkit.plugin.Plugin; + +import java.io.File; +import java.util.HashMap; +import java.util.HashSet; + +public abstract class MovecraftRepair { + public abstract boolean saveCraftRepairState(Craft craft, Sign sign, Plugin plugin, String repairStateName); + public abstract boolean saveRegionRepairState(Plugin plugin, World world, org.bukkit.util.Vector minPos, org.bukkit.util.Vector maxPos, String regionName); + public abstract boolean repairRegion(World world, String regionName); + public abstract Clipboard loadCraftRepairStateClipboard(Plugin plugin, Sign sign, String repairStateName, World bukkitWorld); + public abstract Clipboard loadRegionRepairStateClipboard(Plugin plugin, String repairStateName, World bukkitWorld); + public abstract HashMap getMissingBlocks(String repairName); + public abstract HashSet getMissingBlockLocations(String repairName); + public abstract long getNumDiffBlocks(String repairName); + public abstract Vector getDistanceFromSignToLowestPoint(Clipboard clipboard, String repairName); + + +} diff --git a/modules/api/src/main/java/net/countercraft/movecraft/config/ConfigManager.java b/modules/api/src/main/java/net/countercraft/movecraft/config/ConfigManager.java index d920db274..8850469fa 100644 --- a/modules/api/src/main/java/net/countercraft/movecraft/config/ConfigManager.java +++ b/modules/api/src/main/java/net/countercraft/movecraft/config/ConfigManager.java @@ -17,6 +17,7 @@ package net.countercraft.movecraft.config; +import org.bukkit.Material; import org.bukkit.configuration.file.FileConfiguration; import java.util.ArrayList; @@ -31,7 +32,7 @@ public ConfigManager(FileConfiguration configFile) { public void loadConfig() { setupDefaults(); - Settings.DATA_BLOCKS = configFile.getIntegerList("dataBlocks"); + Settings.DATA_BLOCKS = (List) configFile.getList("dataBlocks"); Settings.THREAD_POOL_SIZE = configFile.getInt("ThreadPoolSize"); Settings.IGNORE_RESET = configFile.getBoolean("safeReload"); @@ -40,20 +41,20 @@ public void loadConfig() { private void setupDefaults() { configFile.addDefault("ThreadPoolSize", 5); configFile.addDefault("safeReload", false); - List dataBlockList = new ArrayList<>(); - dataBlockList.add(23); - dataBlockList.add(25); - dataBlockList.add(33); - dataBlockList.add(44); - dataBlockList.add(50); - dataBlockList.add(53); - dataBlockList.add(54); - dataBlockList.add(55); - dataBlockList.add(61); - dataBlockList.add(62); - dataBlockList.add(63); - dataBlockList.add(64); - dataBlockList.add(65); + List dataBlockList = new ArrayList<>(); + dataBlockList.add(Material.DISPENSER); + dataBlockList.add(Material.NOTE_BLOCK); + dataBlockList.add(Material.PISTON_BASE); + dataBlockList.add(Material.STEP); + dataBlockList.add(Material.TORCH); + dataBlockList.add(Material.WOOD_STAIRS); + dataBlockList.add(Material.CHEST); + dataBlockList.add(Material.REDSTONE_WIRE); + dataBlockList.add(Material.FURNACE); + dataBlockList.add(Material.BURNING_FURNACE); + dataBlockList.add(Material.SIGN_POST); + dataBlockList.add(Material.WOOD_DOOR); + dataBlockList.add(Material.LADDER); configFile.addDefault("dataBlocks", dataBlockList); configFile.options().copyDefaults(true); //Movecraft.getInstance().saveConfig(); diff --git a/modules/api/src/main/java/net/countercraft/movecraft/config/Settings.java b/modules/api/src/main/java/net/countercraft/movecraft/config/Settings.java index 46f03e66b..e569fb22d 100644 --- a/modules/api/src/main/java/net/countercraft/movecraft/config/Settings.java +++ b/modules/api/src/main/java/net/countercraft/movecraft/config/Settings.java @@ -18,6 +18,7 @@ package net.countercraft.movecraft.config; import net.countercraft.movecraft.utils.TownyWorldHeightLimits; +import org.bukkit.Material; import java.util.HashSet; import java.util.List; @@ -28,9 +29,9 @@ public class Settings { public static boolean IGNORE_RESET = false; public static boolean Debug = false; public static int THREAD_POOL_SIZE = 5; - public static List DATA_BLOCKS; + public static List DATA_BLOCKS; public static String LOCALE; - public static int PilotTool = 280; + public static Material PilotTool = Material.STICK; public static int SilhouetteViewDistance = 200; public static int SilhouetteBlockCount = 20; public static boolean CompatibilityMode = false; @@ -50,6 +51,7 @@ public class Settings { public static int FireballLifespan = 6; public static int RepairTicksPerBlock = 0; public static int BlockQueueChunkSize = 1000; + public static double RepairMaxPercent = 50.0; public static double RepairMoneyPerBlock = 0.0; public static boolean FireballPenetration = true; public static boolean AllowCrewSigns = true; @@ -60,9 +62,16 @@ public class Settings { public static boolean WGCustomFlagsUseSinkFlag = false; public static boolean TownyBlockMoveOnSwitchPerm = false; public static boolean TownyBlockSinkOnNoPVP = false; + public static boolean FactionsBlockMoveInSafezone = false; + public static boolean FactionsBlockMoveInWarzone = false; + public static boolean FactionsBlockMoveInAllyTerritory = false; + public static boolean FactionsBlockMoveInTruceTerritory = false; + public static boolean FactionsBlockMoveInEnemyTerritory = false; + public static boolean FactionsBlockSinkOnNoPVP = false; public static Map TownProtectionHeightLimits; - public static Map DurabilityOverride; + public static Map DurabilityOverride; public static boolean IsPaper = false; + public static boolean IsLegacy = true; //false if version is 1.13 or higher public static boolean AssaultEnable; public static double AssaultDamagesCapPercent; @@ -71,9 +80,9 @@ public class Settings { public static int AssaultDuration; public static int AssaultRequiredDefendersOnline; public static double AssaultCostPercent; - public static HashSet AssaultDestroyableBlocks; + public static HashSet AssaultDestroyableBlocks = new HashSet<>(); public static int AssaultDamagesPerBlock; - public static HashSet DisableShadowBlocks; + public static HashSet DisableShadowBlocks = new HashSet<>(); public static boolean SiegeEnable; } diff --git a/modules/api/src/main/java/net/countercraft/movecraft/craft/Craft.java b/modules/api/src/main/java/net/countercraft/movecraft/craft/Craft.java index 880154be6..4075cb6de 100644 --- a/modules/api/src/main/java/net/countercraft/movecraft/craft/Craft.java +++ b/modules/api/src/main/java/net/countercraft/movecraft/craft/Craft.java @@ -134,6 +134,7 @@ public boolean getCruising() { public void setCruising(boolean cruising) { if(notificationPlayer!=null){ + notificationPlayer.spigot().sendMessage(ChatMessageType.ACTION_BAR, new TextComponent("Cruising " + (cruising ? "enabled" : "disabled"))); } this.cruising = cruising; @@ -320,7 +321,7 @@ public int getTickCooldown() { return type.getTickCooldown()+(int)chestPenalty; if(type.getDynamicFlyBlockSpeedFactor()!=0){ double count = 0; - Material flyBlockMaterial = Material.getMaterial(type.getDynamicFlyBlock()); + Material flyBlockMaterial = type.getDynamicFlyBlock(); for(MovecraftLocation location : hitBox){ if(location.toBukkit(w).getBlock().getType()==flyBlockMaterial) count++; diff --git a/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java b/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java index b5a696bc5..30a027d92 100644 --- a/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java +++ b/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java @@ -17,10 +17,8 @@ package net.countercraft.movecraft.craft; -import net.countercraft.movecraft.MovecraftLocation; -import org.bukkit.Bukkit; +import net.countercraft.movecraft.config.Settings; import org.bukkit.Material; -import org.bukkit.World; import org.bukkit.block.Block; import org.jetbrains.annotations.NotNull; import org.yaml.snakeyaml.Yaml; @@ -72,7 +70,7 @@ final public class CraftType { private final int smokeOnSink; private final int tickCooldown; private final int hoverLimit; - private final int dynamicFlyBlock; + private final Material dynamicFlyBlock; private final double fuelBurnRate; private final double sinkPercent; private final double overallSinkPercent; @@ -84,13 +82,15 @@ final public class CraftType { private final float explodeOnCrash; private final float collisionExplosion; @NotNull private final String craftName; - @NotNull private final int[] allowedBlocks; + //@NotNull private final int[] allowedBlocks; + @NotNull private final Map> allowedBlocks; //@NotNull private final Map> allowedBlocks; - @NotNull private final int[] forbiddenBlocks; + //@NotNull private final int[] forbiddenBlocks; + @NotNull private final Map> forbiddenBlocks; //@NotNull private final Map> forbiddenBlocks; @NotNull private final String[] forbiddenSignStrings; - @NotNull private final Map, List> flyBlocks; - @NotNull private final Map, List> moveBlocks; + @NotNull private final Map>, List> flyBlocks; + @NotNull private final Map>, List> moveBlocks; @NotNull private final List harvestBlocks; @NotNull private final List harvesterBladeBlocks; @NotNull private final Set passthroughBlocks; @@ -110,10 +110,10 @@ public CraftType(File f) { maxSize = integerFromObject(data.get("maxSize")); minSize = integerFromObject(data.get("minSize")); // allowedBlocks = ((ArrayList ) data.get( "allowedBlocks" )).toArray( new Integer[1] ); - allowedBlocks = blockIDListFromObject(data.get("allowedBlocks")); - Arrays.sort(allowedBlocks); + allowedBlocks = materialMapFromObject(data.get("allowedBlocks")); + //Collections.sort(allowedBlocks); - forbiddenBlocks = blockIDListFromObject(data.get("forbiddenBlocks")); + forbiddenBlocks = materialMapFromObject(data.get("forbiddenBlocks")); forbiddenSignStrings = stringListFromObject(data.get("forbiddenSignStrings")); if (data.containsKey("canFly")) { blockedByWater = (Boolean) data.get("canFly"); @@ -139,9 +139,9 @@ public CraftType(File f) { cruiseTickCooldown = tickCooldown; } - flyBlocks = blockIDMapListFromObject(data.get("flyblocks")); + flyBlocks = materialMapListFromObject(data.get("flyblocks")); if (data.containsKey("moveblocks")) { - moveBlocks = blockIDMapListFromObject(data.get("moveblocks")); + moveBlocks = materialMapListFromObject(data.get("moveblocks")); } else { moveBlocks = new HashMap<>(); } @@ -421,9 +421,9 @@ public CraftType(File f) { dynamicFlyBlockSpeedFactor = 0d; } if (data.containsKey("dynamicFlyBlock")) { - dynamicFlyBlock = integerFromObject(data.get("dynamicFlyBlock")); + dynamicFlyBlock = materialFromObject(data.get("dynamicFlyBlock")); } else { - dynamicFlyBlock = 0; + dynamicFlyBlock = null; } chestPenalty = data.containsKey("chestPenalty") ? doubleFromObject(data.get("chestPenalty")) : 0d; } @@ -441,6 +441,14 @@ private Double doubleFromObject(Object obj) { } return (Double) obj; } + private Material materialFromObject(Object obj){ + if (obj instanceof Integer){ + return Material.getMaterial((Integer) obj); + } else { + return (Material) obj; + } + + } private int[] blockIDListFromObject(Object obj) { ArrayList returnList = new ArrayList<>(); @@ -469,29 +477,67 @@ private int[] blockIDListFromObject(Object obj) { } private Map> materialMapFromObject(Object obj){ HashMap> returnMap = new HashMap<>(); - HashMap objMap = (HashMap) obj; + if (obj instanceof ArrayList){ + for (Object o : (ArrayList) obj){ + if (o instanceof Integer){ + Integer id = (Integer) o; + Material type = Material.getMaterial(id); + returnMap.put(type, new ArrayList<>()); + } else if (o instanceof String){ + String string = (String) o; + if (string.contains(":")){ + String[] parts = string.split(":"); + Material type; + Integer data = Integer.valueOf(parts[1]); + if (parts[0].contains("0")||parts[0].contains("1")||parts[0].contains("2")||parts[0].contains("3")||parts[0].contains("4")||parts[0].contains("5")||parts[0].contains("6")||parts[0].contains("7")||parts[0].contains("8")||parts[0].contains("9")){ + Integer typeID = Integer.valueOf(parts[0]); + type = Material.getMaterial(typeID); - for (Object o : objMap.keySet()){ - Block block; - Material type; - if (o instanceof Integer){ - Integer id = (Integer) o; - type = Material.getMaterial(id); - } else if (o instanceof String){ - String str = (String) o; - type = Material.getMaterial(str); - } else { - type = (Material) o; + } else { + type = Material.getMaterial(parts[0]); + } + if (returnMap.containsKey(type)){ + returnMap.get(type).add(data); + } else { + returnMap.put(type, new ArrayList<>(data)); + } + } + } else { + Material type = (Material) o; + returnMap.put(type, new ArrayList<>()); + } } - ArrayList objList = (ArrayList) objMap.get(o); - ArrayList dataList = new ArrayList<>(); - for (Object dataObj : objList){ - if (dataObj instanceof Integer){ - Integer data = (Integer) dataObj; - dataList.add(data); + } else { + HashMap objMap = (HashMap) obj; + + for (Object o : objMap.keySet()) { + Block block; + Material type; + if (o instanceof Integer) { + Integer id = (Integer) o; + type = Material.getMaterial(id); + } else if (o instanceof String) { + String str = (String) o; + type = Material.getMaterial(str); + } else { + type = (Material) o; } + ArrayList objList = (ArrayList) objMap.get(o); + ArrayList dataList = new ArrayList<>(); + if (objList != null) { + for (Object dataObj : objList) { + if (dataObj instanceof String) { + String s = (String) dataObj; + Integer data = Integer.valueOf(s); + dataList.add(data); + } else { + Integer data = (Integer) dataObj; + dataList.add(data); + } + } + } + returnMap.put(type, dataList); } - returnMap.put(type,dataList); } return returnMap; } @@ -510,7 +556,143 @@ private String[] stringListFromObject(Object obj) { } return returnList.toArray(new String[1]); } + private Map>, List> materialMapListFromObject(Object obj){ + HashMap>, List> returnMap = new HashMap<>(); + HashMap objMap = (HashMap) obj; + for (Object i : objMap.keySet()) { + HashMap> materialMap = new HashMap<>(); + if (i instanceof ArrayList) { + for (Object o : (ArrayList) i) { + if (o instanceof Integer) { + Integer typeID = (Integer) o; + Material type = Material.getMaterial(typeID); + materialMap.put(type, new ArrayList<>()); + } else if (o instanceof String) { + String string = (String) o; + if (string.contains(":")) { + String[] parts = string.split(":"); + Material type; + Integer data = Integer.valueOf(parts[1]); + if (parts[0].contains("0") || parts[0].contains("1") || parts[0].contains("2") || parts[0].contains("3") || parts[0].contains("4") || parts[0].contains("5") || parts[0].contains("6") || parts[0].contains("7") || parts[0].contains("8") || parts[0].contains("9")) { + Integer typeID = Integer.valueOf(parts[0]); + type = Material.getMaterial(typeID); + + } else { + type = Material.getMaterial(parts[0]); + } + if (materialMap.containsKey(type)) { + List dataList = materialMap.get(type); + dataList.add(data); + materialMap.put(type, dataList); + } else { + List dataList = new ArrayList<>(); + dataList.add(data); + materialMap.put(type, dataList); + } + } else { + Material type; + if (string.contains("0") || string.contains("1") || string.contains("2") || string.contains("3") || string.contains("4") || string.contains("5") || string.contains("6") || string.contains("7") || string.contains("8") || string.contains("9")) { + Integer typeID = Integer.valueOf(string); + type = Material.getMaterial(typeID); + + } else { + type = Material.getMaterial(string); + } + materialMap.put(type, new ArrayList<>()); + } + } else { + Material type = (Material) o; + materialMap.put(type, new ArrayList<>()); + } + } + } else if (i instanceof Map) { + HashMap objMapKey = (HashMap) i; + for (Object o : objMapKey.keySet()) { + if (o instanceof Integer) { + Integer typeID = (Integer) o; + Material type = Material.getMaterial(typeID); + List dataList = (List) objMapKey.get(o); + materialMap.put(type, dataList); + } else { + Material type = (Material) o; + List dataList = (List) objMapKey.get(o); + materialMap.put(type, dataList); + } + } + } else if (i instanceof Integer) { + Integer typeID = (Integer) i; + Material type = Material.getMaterial(typeID); + materialMap.put(type, new ArrayList<>()); + } else if (i instanceof String) { + String string = (String) i; + if (string.contains(":")) { + String[] parts = string.split(":"); + Material type; + Integer data = Integer.valueOf(parts[1]); + if (parts[0].contains("0") || parts[0].contains("1") || parts[0].contains("2") || parts[0].contains("3") || parts[0].contains("4") || parts[0].contains("5") || parts[0].contains("6") || parts[0].contains("7") || parts[0].contains("8") || parts[0].contains("9")) { + Integer typeID = Integer.valueOf(parts[0]); + type = Material.getMaterial(typeID); + + } else { + type = Material.getMaterial(parts[0]); + } + if (materialMap.containsKey(type)) { + List dataList = materialMap.get(type); + dataList.add(data); + materialMap.put(type, dataList); + } else { + List dataList = new ArrayList<>(); + dataList.add(data); + materialMap.put(type, dataList); + } + } else { + Material type; + if (string.contains("0") || string.contains("1") || string.contains("2") || string.contains("3") || string.contains("4") || string.contains("5") || string.contains("6") || string.contains("7") || string.contains("8") || string.contains("9")) { + Integer typeID = Integer.valueOf(string); + type = Material.getMaterial(typeID); + + } else { + type = Material.getMaterial(string); + } + if (materialMap.containsKey(type)) { + List dataList = materialMap.get(type); + materialMap.put(type, dataList); + } else { + List dataList = new ArrayList<>(); + materialMap.put(type, dataList); + } + } + } else { + Material type = (Material) i; + materialMap.put(type, new ArrayList<>()); + } + + // then read in the limitation values, low and high + ArrayList objList = (ArrayList) objMap.get(i); + ArrayList limitList = new ArrayList<>(); + for (Object limitObj : objList) { + if (limitObj instanceof String) { + String str = (String) limitObj; + if (str.contains("N")) { // a # indicates a specific quantity, IE: #2 for exactly 2 of the block + String[] parts = str.split("N"); + Double val = Double.valueOf(parts[1]); + limitList.add(10000d + val); // limit greater than 10000 indicates an specific quantity (not a ratio) + } else { + Double val = Double.valueOf(str); + limitList.add(val); + } + } else if (limitObj instanceof Integer) { + Double ret = ((Integer) limitObj).doubleValue(); + limitList.add(ret); + } else { + limitList.add((Double) limitObj); + } + } + returnMap.put(materialMap, limitList); + } + return returnMap; + } private Map, List> blockIDMapListFromObject(Object obj) { HashMap, List> returnMap = new HashMap<>(); HashMap objMap = (HashMap) obj; @@ -556,21 +738,21 @@ private Map, List> blockIDMapListFromObject(Object obj) { ArrayList objList = (ArrayList) objMap.get(i); ArrayList limitList = new ArrayList<>(); for (Object limitObj : objList) { - if (limitObj instanceof String) { - String str = (String) limitObj; - if (str.contains("N")) { // a # indicates a specific quantity, IE: #2 for exactly 2 of the block - String[] parts = str.split("N"); - Double val = Double.valueOf(parts[1]); - limitList.add(10000d + val); // limit greater than 10000 indicates an specific quantity (not a ratio) - } else { - Double val = Double.valueOf(str); - limitList.add(val); - } - } else if (limitObj instanceof Integer) { - Double ret = ((Integer) limitObj).doubleValue(); - limitList.add(ret); - } else - limitList.add((Double) limitObj); + if (limitObj instanceof String) { + String str = (String) limitObj; + if (str.contains("N")) { // a # indicates a specific quantity, IE: #2 for exactly 2 of the block + String[] parts = str.split("N"); + Double val = Double.valueOf(parts[1]); + limitList.add(10000d + val); // limit greater than 10000 indicates an specific quantity (not a ratio) + } else { + Double val = Double.valueOf(str); + limitList.add(val); + } + } else if (limitObj instanceof Integer) { + Double ret = ((Integer) limitObj).doubleValue(); + limitList.add(ret); + } else + limitList.add((Double) limitObj); } returnMap.put(rowList, limitList); } @@ -590,11 +772,11 @@ public int getMinSize() { return minSize; } - public int[] getAllowedBlocks() { + public Map> getAllowedBlocks() { return allowedBlocks; } - public int[] getForbiddenBlocks() { + public Map> getForbiddenBlocks() { return forbiddenBlocks; } @@ -739,12 +921,12 @@ public boolean isTryNudge() { } @NotNull - public Map, List> getFlyBlocks() { + public Map>, List> getFlyBlocks() { return flyBlocks; } @NotNull - public Map, List> getMoveBlocks() { + public Map>, List> getMoveBlocks() { return moveBlocks; } @@ -806,7 +988,7 @@ public double getDynamicFlyBlockSpeedFactor() { return dynamicFlyBlockSpeedFactor; } - public int getDynamicFlyBlock() { + public Material getDynamicFlyBlock() { return dynamicFlyBlock; } diff --git a/modules/v1_10_R1/pom.xml b/modules/v1_10_R1/pom.xml index 4b11116a3..c9e49ebfb 100644 --- a/modules/v1_10_R1/pom.xml +++ b/modules/v1_10_R1/pom.xml @@ -10,7 +10,12 @@ UTF-8 - + + + sk89q-repo + http://maven.sk89q.com/repo/ + + net.countercraft movecraft-parent @@ -19,6 +24,16 @@ + + com.sk89q + worldedit + LATEST + + + com.sk89q + worldguard + 6.1.1-SNAPSHOT + org.bukkit craftbukkit diff --git a/modules/v1_10_R1/src/main/java/net/countercraft/movecraft/compat/v1_10_R1/IMovecraftRepair.java b/modules/v1_10_R1/src/main/java/net/countercraft/movecraft/compat/v1_10_R1/IMovecraftRepair.java new file mode 100644 index 000000000..bcd6ae614 --- /dev/null +++ b/modules/v1_10_R1/src/main/java/net/countercraft/movecraft/compat/v1_10_R1/IMovecraftRepair.java @@ -0,0 +1,477 @@ +package net.countercraft.movecraft.compat.v1_10_R1; + +import com.sk89q.jnbt.CompoundTag; +import com.sk89q.jnbt.ListTag; +import com.sk89q.jnbt.Tag; +import com.sk89q.worldedit.MaxChangedBlocksException; +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.blocks.BaseBlock; +import com.sk89q.worldedit.bukkit.BukkitWorld; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard; +import com.sk89q.worldedit.extent.clipboard.Clipboard; +import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormat; +import com.sk89q.worldedit.extent.clipboard.io.ClipboardWriter; +import com.sk89q.worldedit.function.mask.BlockMask; +import com.sk89q.worldedit.function.mask.ExistingBlockMask; +import com.sk89q.worldedit.function.operation.ForwardExtentCopy; +import com.sk89q.worldedit.function.operation.Operations; +import com.sk89q.worldedit.regions.CuboidRegion; +import com.sk89q.worldedit.world.registry.WorldData; +import net.countercraft.movecraft.MovecraftLocation; +import net.countercraft.movecraft.MovecraftRepair; +import net.countercraft.movecraft.config.Settings; +import net.countercraft.movecraft.craft.Craft; +import net.countercraft.movecraft.utils.HashHitBox; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.World; +import org.bukkit.block.Block; +import org.bukkit.block.Dispenser; +import org.bukkit.block.Sign; +import org.bukkit.inventory.ItemStack; +import org.bukkit.plugin.Plugin; + +import java.io.*; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Set; + +public class IMovecraftRepair extends MovecraftRepair { + private HashMap> locMissingBlocksMap = new HashMap<>(); + private HashMap numDiffBlocksMap = new HashMap<>(); + private HashMap> missingBlocksMap = new HashMap<>(); + + @Override + public boolean saveCraftRepairState (Craft craft, Sign sign, Plugin plugin, String s) { + HashHitBox hitBox = craft.getHitBox(); + File saveDirectory = new File(plugin.getDataFolder(), "CraftRepairStates"); + World world = craft.getW(); + com.sk89q.worldedit.world.World weWorld = new BukkitWorld(world); + WorldData worldData = weWorld.getWorldData(); + if (!saveDirectory.exists()){ + saveDirectory.mkdirs(); + } + Vector minPos = new Vector(hitBox.getMinX(), hitBox.getMinY(), hitBox.getMinZ()); + Vector maxPos = new Vector(hitBox.getMaxX(), hitBox.getMaxY(), hitBox.getMaxZ()); + CuboidRegion cRegion = new CuboidRegion(minPos, maxPos); + File repairStateFile = new File(saveDirectory, s + ".schematic"); + Set blockSet = baseBlocksFromCraft(craft); + try { + + BlockArrayClipboard clipboard = new BlockArrayClipboard(cRegion); + Extent source = WorldEdit.getInstance().getEditSessionFactory().getEditSession(weWorld, -1); + Extent destination = clipboard; + ForwardExtentCopy copy = new ForwardExtentCopy(source, cRegion, clipboard.getOrigin(), destination, minPos); + BlockMask mask = new BlockMask(source, blockSet); + copy.setSourceMask(mask); + Operations.completeLegacy(copy); + ClipboardWriter writer = ClipboardFormat.SCHEMATIC.getWriter(new FileOutputStream(repairStateFile, false)); + writer.write(clipboard, worldData); + writer.close(); + return true; + + } catch (MaxChangedBlocksException e) { + e.printStackTrace(); + return false; + } catch (IOException e) { + e.printStackTrace(); + return false; + } + + + } + + @Override + public boolean saveRegionRepairState(Plugin plugin, World world, org.bukkit.util.Vector minPos, org.bukkit.util.Vector maxPos, String s) { + File saveDirectory = new File(plugin.getDataFolder(), "CraftRepairStates"); + com.sk89q.worldedit.world.World weWorld = new BukkitWorld(world); + WorldData worldData = weWorld.getWorldData(); + Vector weMinPos = new Vector(minPos.getBlockX(), minPos.getBlockY(), minPos.getBlockZ()); + Vector weMaxPos = new Vector(maxPos.getBlockX(), maxPos.getBlockY(), maxPos.getBlockZ()); + if (!saveDirectory.exists()){ + saveDirectory.mkdirs(); + } + + CuboidRegion cRegion = new CuboidRegion(weMinPos, weMaxPos); + File repairStateFile = new File(saveDirectory, s + ".schematic"); + try { + + BlockArrayClipboard clipboard = new BlockArrayClipboard(cRegion); + Extent source = WorldEdit.getInstance().getEditSessionFactory().getEditSession(weWorld, -1); + Extent destination = clipboard; + ForwardExtentCopy copy = new ForwardExtentCopy(source, cRegion, clipboard.getOrigin(), destination, weMinPos); + ExistingBlockMask mask = new ExistingBlockMask(source); + copy.setSourceMask(mask); + Operations.completeLegacy(copy); + ClipboardWriter writer = ClipboardFormat.SCHEMATIC.getWriter(new FileOutputStream(repairStateFile, false)); + writer.write(clipboard, worldData); + writer.close(); + return true; + + } catch (MaxChangedBlocksException e) { + e.printStackTrace(); + return false; + } catch (IOException e) { + e.printStackTrace(); + return false; + } + } + + @Override + public boolean repairRegion(World world, String s) { + return false; + } + + @Override + public Clipboard loadCraftRepairStateClipboard(Plugin plugin, Sign sign, String repairStateFile, World world) { + File dataDirectory = new File(plugin.getDataFolder(), "CraftRepairStates"); + File file = new File(dataDirectory, repairStateFile + ".schematic"); // The schematic file + com.sk89q.worldedit.world.World weWorld = new BukkitWorld(world); + WorldData worldData = weWorld.getWorldData(); + Clipboard clipboard; + try { + clipboard = ClipboardFormat.SCHEMATIC.getReader(new FileInputStream(file)).read(worldData); + + } catch (FileNotFoundException e) { + e.printStackTrace(); + return null; + } catch (IOException e) { + e.printStackTrace(); + return null; + } + if (clipboard != null){ + long numDiffBlocks = 0; + HashMap missingBlocks = new HashMap<>(); + HashSet locMissingBlocks = new HashSet<>(); + Vector distMP = getDistanceFromSignToLowestPoint(clipboard, sign.getLine(1)); + Vector minPos = new Vector(sign.getLocation().getBlockX() - distMP.getBlockX(), sign.getLocation().getBlockY() - distMP.getBlockY(), sign.getLocation().getBlockZ() - distMP.getBlockZ()); + Vector distance = new Vector(minPos.getBlockX() - clipboard.getMinimumPoint().getBlockX(), minPos.getBlockY() - clipboard.getMinimumPoint().getBlockY(), minPos.getBlockZ() - clipboard.getMinimumPoint().getBlockZ()); + for (int x = clipboard.getMinimumPoint().getBlockX(); x <= clipboard.getMaximumPoint().getBlockX(); x++){ + for (int y = clipboard.getMinimumPoint().getBlockY(); y <= clipboard.getMaximumPoint().getBlockY(); y++){ + for (int z = clipboard.getMinimumPoint().getBlockZ(); z <= clipboard.getMaximumPoint().getBlockZ(); z++){ + Vector position = new Vector(x,y,z); + Location bukkitLoc = new Location(sign.getWorld(), x + distance.getBlockX(), y + distance.getBlockY(), z + distance.getBlockZ()); + BaseBlock block = clipboard.getBlock(position); + Block bukkitBlock = sign.getWorld().getBlockAt(bukkitLoc); + boolean isImportant = true; + if (block.getType() == 0){ + isImportant = false; + } + + if (isImportant && bukkitBlock.getTypeId() != block.getType()) { + int itemToConsume = block.getType(); + double qtyToConsume = 1.0; + numDiffBlocks++; + //some blocks aren't represented by items with the same number as the block + if (itemToConsume == 63 || itemToConsume == 68) // signs + itemToConsume = 323; + if (itemToConsume == 93 || itemToConsume == 94) // repeaters + itemToConsume = 356; + if (itemToConsume == 149 || itemToConsume == 150) // comparators + itemToConsume = 404; + if (itemToConsume == 55) // redstone + itemToConsume = 331; + if (itemToConsume == 118) // cauldron + itemToConsume = 380; + if (itemToConsume == 124) // lit redstone lamp + itemToConsume = 123; + if (itemToConsume == 75) // lit redstone torch + itemToConsume = 76; + if (itemToConsume == 8 || itemToConsume == 9) { // don't require water to be in the chest + itemToConsume = 0; + qtyToConsume = 0.0; + } + if (itemToConsume == 10 || itemToConsume == 11) { // don't require lava either, yeah you could exploit this for free lava, so make sure you set a price per block + itemToConsume = 0; + qtyToConsume = 0.0; + } + if (itemToConsume == 26) { //beds + itemToConsume = 355; + qtyToConsume = 0.5; + } + if (itemToConsume == 64) { //doors + itemToConsume = 324; //since doors and beds encompass two blocks, require only 0.5 block for each of the two blocks + qtyToConsume = 0.5; + } + if (itemToConsume == 71){ + itemToConsume = 330; + qtyToConsume = 0.5; + } + if (itemToConsume == 193){ + itemToConsume = 427; + qtyToConsume = 0.5; + } + if (itemToConsume == 194){ + itemToConsume = 428; + qtyToConsume = 0.5; + } + if (itemToConsume == 195){ + itemToConsume = 429; + qtyToConsume = 0.5; + } + if (itemToConsume == 196){ + itemToConsume = 430; + qtyToConsume = 0.5; + } + if (itemToConsume == 197) { + itemToConsume = 431; + qtyToConsume = 0.5; + } + if (itemToConsume == 23){ + Tag t = block.getNbtData().getValue().get("Items"); + ListTag lt = null; + if (t instanceof ListTag){ + lt = (ListTag) t; + } + int numTNT = 0; + int numFireCharges = 0; + int numWaterBuckets = 0; + if (lt != null) { + for (Tag entryTag : lt.getValue()) { + if (entryTag instanceof CompoundTag){ + CompoundTag cTag = (CompoundTag) entryTag; + if (cTag.toString().contains("minecraft:tnt")){ + numTNT += cTag.getByte("Count"); + } + if (cTag.toString().contains("minecraft:fire_charge")){ + numFireCharges += cTag.getByte("Count"); + } + if (cTag.toString().contains("minecraft:water_bucket")){ + numWaterBuckets += cTag.getByte("Count"); + } + } + } + } + + + if (numTNT > 0){ + if (!missingBlocks.containsKey(Material.TNT)){ + missingBlocks.put(Material.TNT, (double) numTNT); + } else { + Double num = missingBlocks.get(Material.TNT); + num += numTNT; + missingBlocks.put(Material.TNT, num); + } + } + if (numFireCharges > 0){ + if (!missingBlocks.containsKey(Material.FIREBALL)){ + missingBlocks.put(Material.FIREBALL, (double) numFireCharges); + } else { + Double num = missingBlocks.get(Material.FIREBALL); + num += numFireCharges; + missingBlocks.put(Material.FIREBALL, num); + + } + } + if (numWaterBuckets > 0){ + if (!missingBlocks.containsKey(Material.WATER_BUCKET)){ + missingBlocks.put(Material.WATER_BUCKET, (double) numWaterBuckets); + } else { + Double num = missingBlocks.get(Material.WATER_BUCKET); + num += numWaterBuckets; + missingBlocks.put(Material.WATER_BUCKET, num); + } + } + } + if (itemToConsume == 43) { // for double slabs, require 2 slabs + itemToConsume = 44; + qtyToConsume = 2; + } + if (itemToConsume == 125) { // for double wood slabs, require 2 wood slabs + itemToConsume = 126; + qtyToConsume = 2; + } + if (itemToConsume == 181) { // for double red sandstone slabs, require 2 red sandstone slabs + itemToConsume = 182; + qtyToConsume = 2; + } + if (itemToConsume != 0){ + if (!missingBlocks.containsKey(Material.getMaterial(itemToConsume))){ + missingBlocks.put(Material.getMaterial(itemToConsume), qtyToConsume); + } else { + Double num = missingBlocks.get(Material.getMaterial(itemToConsume)); + num += qtyToConsume; + missingBlocks.put(Material.getMaterial(itemToConsume), num); + } + locMissingBlocks.add(new Vector(x,y,z)); + } + } + if (bukkitBlock.getType() == Material.DISPENSER && block.getType() == 23){ + boolean needReplace = false; + Tag t = block.getNbtData().getValue().get("Items"); + ListTag lt = null; + if (t instanceof ListTag){ + lt = (ListTag) t; + } + int numTNT = 0; + int numFireCharges = 0; + int numWaterBuckets = 0; + if (lt != null) { + for (Tag entryTag : lt.getValue()) { + if (entryTag instanceof CompoundTag){ + CompoundTag cTag = (CompoundTag) entryTag; + if (cTag.toString().contains("minecraft:tnt")){ + numTNT += cTag.getByte("Count"); + } + if (cTag.toString().contains("minecraft:fire_charge")){ + numFireCharges += cTag.getByte("Count"); + } + if (cTag.toString().contains("minecraft:water_bucket")){ + numWaterBuckets += cTag.getByte("Count"); + } + } + } + } + Dispenser bukkitDispenser = (Dispenser) bukkitBlock.getState(); + //Bukkit.getLogger().info(String.format("TNT: %d, Fireballs: %d, Water buckets: %d", numTNT, numFireCharges, numWaterBuckets)); + for (ItemStack iStack : bukkitDispenser.getInventory().getContents()){ + if (iStack != null) { + if (iStack.getType() == Material.TNT) { + numTNT -= iStack.getAmount(); + } + if (iStack.getType() == Material.FIREBALL) { + numFireCharges -= iStack.getAmount(); + } + if (iStack.getType() == Material.WATER_BUCKET) { + numWaterBuckets -= iStack.getAmount(); + } + } + } + //Bukkit.getLogger().info(String.format("TNT: %d, Fireballs: %d, Water buckets: %d", numTNT, numFireCharges, numWaterBuckets)); + if (numTNT > 0){ + if (!missingBlocks.containsKey(Material.TNT)){ + missingBlocks.put(Material.TNT, (double) numTNT); + } else { + Double num = missingBlocks.get(Material.TNT); + num += numTNT; + missingBlocks.put(Material.TNT, num); + } + needReplace = true; + } + if (numFireCharges > 0){ + if (!missingBlocks.containsKey(Material.FIREBALL)){ + missingBlocks.put(Material.FIREBALL, (double) numFireCharges); + } else { + Double num = missingBlocks.get(Material.FIREBALL); + num += numFireCharges; + missingBlocks.put(Material.FIREBALL, num); + + } + needReplace = true; + } + if (numWaterBuckets > 0){ + if (!missingBlocks.containsKey(Material.WATER_BUCKET)){ + missingBlocks.put(Material.WATER_BUCKET, (double) numWaterBuckets); + } else { + Double num = missingBlocks.get(Material.WATER_BUCKET); + num += numWaterBuckets; + missingBlocks.put(Material.WATER_BUCKET, num); + } + needReplace = true; + } + if (needReplace){ + numDiffBlocks++; + locMissingBlocks.add(new Vector(x,y,z)); + } + } + } + } + } + locMissingBlocksMap.put(repairStateFile, locMissingBlocks); + missingBlocksMap.put(repairStateFile, missingBlocks); + numDiffBlocksMap.put(repairStateFile, numDiffBlocks); + } + return clipboard; + } + + @Override + public Clipboard loadRegionRepairStateClipboard(Plugin plugin, String s, World world) { + return null; + } + + @Override + public HashMap getMissingBlocks(String repairName) { + if (missingBlocksMap.get(repairName) == null){ + return null; + } + return missingBlocksMap.get(repairName); + } + + @Override + public HashSet getMissingBlockLocations(String repairName) { + return locMissingBlocksMap.get(repairName); + } + + @Override + public long getNumDiffBlocks(String s) { + return numDiffBlocksMap.get(s); + } + + @Override + public Vector getDistanceFromSignToLowestPoint(Clipboard clipboard, String repairName) { + Vector returnDistance = null; + for (int x = clipboard.getMinimumPoint().getBlockX(); x <= clipboard.getMaximumPoint().getBlockX(); x++) { + for (int y = clipboard.getMinimumPoint().getBlockY(); y <= clipboard.getMaximumPoint().getBlockY(); y++) { + for (int z = clipboard.getMinimumPoint().getBlockZ(); z <= clipboard.getMaximumPoint().getBlockZ(); z++) { + Vector pos = new Vector(x,y,z); + BaseBlock block = clipboard.getBlock(pos); + if (block.getType() == 68 || block.getType() == 63) { + String firstLine = block.getNbtData().getString("Text1"); + firstLine = firstLine.substring(2); + if (firstLine.substring(0, 5).equalsIgnoreCase("extra")){ + firstLine = firstLine.substring(17); + String[] parts = firstLine.split("\""); + firstLine = parts[0]; + } + String secondLine = block.getNbtData().getString("Text2"); + secondLine = secondLine.substring(2); + if (secondLine.substring(0, 5).equalsIgnoreCase("extra")){ + secondLine = secondLine.substring(17); + String[] parts = secondLine.split("\""); + secondLine = parts[0]; + } + if (firstLine.equalsIgnoreCase("Repair:")&& secondLine.contains(repairName)){ + returnDistance = new Vector(x - clipboard.getMinimumPoint().getBlockX(), y - clipboard.getMinimumPoint().getBlockY(), z - clipboard.getMinimumPoint().getBlockZ()); + } + } + } + } + } + return returnDistance; + } + + private Set baseBlocksFromCraft(Craft craft){ + HashSet returnSet = new HashSet<>(); + HashHitBox hitBox = craft.getHitBox(); + World w = craft.getW(); + for (MovecraftLocation location : hitBox){ + Integer id = w.getBlockTypeIdAt(location.getX(), location.getY(), location.getZ()); + Byte data = w.getBlockAt(location.getX(), location.getY(), location.getZ()).getData(); + returnSet.add(new BaseBlock(id, data)); + } + Bukkit.getLogger().info(returnSet.toString()); + return returnSet; + } + + private Set baseBlocksFromAssaultRegion(Vector minPos, Vector maxPos, World world){ + HashSet returnSet = new HashSet<>(); + for (int x = minPos.getBlockX(); x <= maxPos.getBlockX(); x++){ + for (int y = minPos.getBlockY(); y <= maxPos.getBlockY(); y++){ + for (int z = minPos.getBlockZ(); z <= maxPos.getBlockZ(); z++){ + int id = world.getBlockTypeIdAt(x,y,z); + byte data = world.getBlockAt(x,y,z).getData(); + //exclude air and blocks that are not destroyable during an assault + if (!Settings.AssaultDestroyableBlocks.contains(id) || id == 0){ + continue; + } + returnSet.add(new BaseBlock(id, data)); + } + } + } + + return returnSet; + } +} diff --git a/modules/v1_11_R1/pom.xml b/modules/v1_11_R1/pom.xml index 5ede4cbe2..4159a72e1 100644 --- a/modules/v1_11_R1/pom.xml +++ b/modules/v1_11_R1/pom.xml @@ -17,8 +17,23 @@ parent ../../ - + + + sk89q-repo + http://maven.sk89q.com/repo/ + + + + com.sk89q + worldedit + LATEST + + + com.sk89q + worldguard + 6.1.1-SNAPSHOT + org.bukkit craftbukkit diff --git a/modules/v1_11_R1/src/main/java/net/countercraft/movecraft/compat/v1_11_R1/IMovecraftRepair.java b/modules/v1_11_R1/src/main/java/net/countercraft/movecraft/compat/v1_11_R1/IMovecraftRepair.java new file mode 100644 index 000000000..cd0fa2a70 --- /dev/null +++ b/modules/v1_11_R1/src/main/java/net/countercraft/movecraft/compat/v1_11_R1/IMovecraftRepair.java @@ -0,0 +1,477 @@ +package net.countercraft.movecraft.compat.v1_11_R1; + +import com.sk89q.jnbt.CompoundTag; +import com.sk89q.jnbt.ListTag; +import com.sk89q.jnbt.Tag; +import com.sk89q.worldedit.MaxChangedBlocksException; +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.blocks.BaseBlock; +import com.sk89q.worldedit.bukkit.BukkitWorld; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard; +import com.sk89q.worldedit.extent.clipboard.Clipboard; +import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormat; +import com.sk89q.worldedit.extent.clipboard.io.ClipboardWriter; +import com.sk89q.worldedit.function.mask.BlockMask; +import com.sk89q.worldedit.function.mask.ExistingBlockMask; +import com.sk89q.worldedit.function.operation.ForwardExtentCopy; +import com.sk89q.worldedit.function.operation.Operations; +import com.sk89q.worldedit.regions.CuboidRegion; +import com.sk89q.worldedit.world.registry.WorldData; +import net.countercraft.movecraft.MovecraftLocation; +import net.countercraft.movecraft.MovecraftRepair; +import net.countercraft.movecraft.config.Settings; +import net.countercraft.movecraft.craft.Craft; +import net.countercraft.movecraft.utils.HashHitBox; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.World; +import org.bukkit.block.Block; +import org.bukkit.block.Dispenser; +import org.bukkit.block.Sign; +import org.bukkit.inventory.ItemStack; +import org.bukkit.plugin.Plugin; + +import java.io.*; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Set; + +public class IMovecraftRepair extends MovecraftRepair { + private HashMap> locMissingBlocksMap = new HashMap<>(); + private HashMap numDiffBlocksMap = new HashMap<>(); + private HashMap> missingBlocksMap = new HashMap<>(); + + @Override + public boolean saveCraftRepairState (Craft craft, Sign sign, Plugin plugin, String s) { + HashHitBox hitBox = craft.getHitBox(); + File saveDirectory = new File(plugin.getDataFolder(), "CraftRepairStates"); + World world = craft.getW(); + com.sk89q.worldedit.world.World weWorld = new BukkitWorld(world); + WorldData worldData = weWorld.getWorldData(); + if (!saveDirectory.exists()){ + saveDirectory.mkdirs(); + } + Vector minPos = new Vector(hitBox.getMinX(), hitBox.getMinY(), hitBox.getMinZ()); + Vector maxPos = new Vector(hitBox.getMaxX(), hitBox.getMaxY(), hitBox.getMaxZ()); + CuboidRegion cRegion = new CuboidRegion(minPos, maxPos); + File repairStateFile = new File(saveDirectory, s + ".schematic"); + Set blockSet = baseBlocksFromCraft(craft); + try { + + BlockArrayClipboard clipboard = new BlockArrayClipboard(cRegion); + Extent source = WorldEdit.getInstance().getEditSessionFactory().getEditSession(weWorld, -1); + Extent destination = clipboard; + ForwardExtentCopy copy = new ForwardExtentCopy(source, cRegion, clipboard.getOrigin(), destination, minPos); + BlockMask mask = new BlockMask(source, blockSet); + copy.setSourceMask(mask); + Operations.completeLegacy(copy); + ClipboardWriter writer = ClipboardFormat.SCHEMATIC.getWriter(new FileOutputStream(repairStateFile, false)); + writer.write(clipboard, worldData); + writer.close(); + return true; + + } catch (MaxChangedBlocksException e) { + e.printStackTrace(); + return false; + } catch (IOException e) { + e.printStackTrace(); + return false; + } + + + } + + @Override + public boolean saveRegionRepairState(Plugin plugin, World world, org.bukkit.util.Vector minPos, org.bukkit.util.Vector maxPos, String s) { + File saveDirectory = new File(plugin.getDataFolder(), "CraftRepairStates"); + com.sk89q.worldedit.world.World weWorld = new BukkitWorld(world); + WorldData worldData = weWorld.getWorldData(); + Vector weMinPos = new Vector(minPos.getBlockX(), minPos.getBlockY(), minPos.getBlockZ()); + Vector weMaxPos = new Vector(maxPos.getBlockX(), maxPos.getBlockY(), maxPos.getBlockZ()); + if (!saveDirectory.exists()) { + saveDirectory.mkdirs(); + } + + CuboidRegion cRegion = new CuboidRegion(weMinPos, weMaxPos); + File repairStateFile = new File(saveDirectory, s + ".schematic"); + try { + + BlockArrayClipboard clipboard = new BlockArrayClipboard(cRegion); + Extent source = WorldEdit.getInstance().getEditSessionFactory().getEditSession(weWorld, -1); + Extent destination = clipboard; + ForwardExtentCopy copy = new ForwardExtentCopy(source, cRegion, clipboard.getOrigin(), destination, weMinPos); + ExistingBlockMask mask = new ExistingBlockMask(source); + copy.setSourceMask(mask); + Operations.completeLegacy(copy); + ClipboardWriter writer = ClipboardFormat.SCHEMATIC.getWriter(new FileOutputStream(repairStateFile, false)); + writer.write(clipboard, worldData); + writer.close(); + return true; + + } catch (MaxChangedBlocksException e) { + e.printStackTrace(); + return false; + } catch (IOException e) { + e.printStackTrace(); + return false; + } + } + + @Override + public boolean repairRegion(World world, String s) { + return false; + } + + @Override + public Clipboard loadCraftRepairStateClipboard(Plugin plugin, Sign sign, String repairStateFile, World world) { + File dataDirectory = new File(plugin.getDataFolder(), "CraftRepairStates"); + File file = new File(dataDirectory, repairStateFile + ".schematic"); // The schematic file + com.sk89q.worldedit.world.World weWorld = new BukkitWorld(world); + WorldData worldData = weWorld.getWorldData(); + Clipboard clipboard; + try { + clipboard = ClipboardFormat.SCHEMATIC.getReader(new FileInputStream(file)).read(worldData); + + } catch (FileNotFoundException e) { + e.printStackTrace(); + return null; + } catch (IOException e) { + e.printStackTrace(); + return null; + } + if (clipboard != null){ + long numDiffBlocks = 0; + HashMap missingBlocks = new HashMap<>(); + HashSet locMissingBlocks = new HashSet<>(); + Vector distMP = getDistanceFromSignToLowestPoint(clipboard, sign.getLine(1)); + Vector minPos = new Vector(sign.getLocation().getBlockX() - distMP.getBlockX(), sign.getLocation().getBlockY() - distMP.getBlockY(), sign.getLocation().getBlockZ() - distMP.getBlockZ()); + Vector distance = new Vector(minPos.getBlockX() - clipboard.getMinimumPoint().getBlockX(), minPos.getBlockY() - clipboard.getMinimumPoint().getBlockY(), minPos.getBlockZ() - clipboard.getMinimumPoint().getBlockZ()); + for (int x = clipboard.getMinimumPoint().getBlockX(); x <= clipboard.getMaximumPoint().getBlockX(); x++){ + for (int y = clipboard.getMinimumPoint().getBlockY(); y <= clipboard.getMaximumPoint().getBlockY(); y++){ + for (int z = clipboard.getMinimumPoint().getBlockZ(); z <= clipboard.getMaximumPoint().getBlockZ(); z++){ + Vector position = new Vector(x,y,z); + Location bukkitLoc = new Location(sign.getWorld(), x + distance.getBlockX(), y + distance.getBlockY(), z + distance.getBlockZ()); + BaseBlock block = clipboard.getBlock(position); + Block bukkitBlock = sign.getWorld().getBlockAt(bukkitLoc); + boolean isImportant = true; + if (block.getType() == 0){ + isImportant = false; + } + + if (isImportant && bukkitBlock.getTypeId() != block.getType()) { + int itemToConsume = block.getType(); + double qtyToConsume = 1.0; + numDiffBlocks++; + //some blocks aren't represented by items with the same number as the block + if (itemToConsume == 63 || itemToConsume == 68) // signs + itemToConsume = 323; + if (itemToConsume == 93 || itemToConsume == 94) // repeaters + itemToConsume = 356; + if (itemToConsume == 149 || itemToConsume == 150) // comparators + itemToConsume = 404; + if (itemToConsume == 55) // redstone + itemToConsume = 331; + if (itemToConsume == 118) // cauldron + itemToConsume = 380; + if (itemToConsume == 124) // lit redstone lamp + itemToConsume = 123; + if (itemToConsume == 75) // lit redstone torch + itemToConsume = 76; + if (itemToConsume == 8 || itemToConsume == 9) { // don't require water to be in the chest + itemToConsume = 0; + qtyToConsume = 0.0; + } + if (itemToConsume == 10 || itemToConsume == 11) { // don't require lava either, yeah you could exploit this for free lava, so make sure you set a price per block + itemToConsume = 0; + qtyToConsume = 0.0; + } + if (itemToConsume == 26) { //beds + itemToConsume = 355; + qtyToConsume = 0.5; + } + if (itemToConsume == 64) { //doors + itemToConsume = 324; //since doors and beds encompass two blocks, require only 0.5 block for each of the two blocks + qtyToConsume = 0.5; + } + if (itemToConsume == 71){ + itemToConsume = 330; + qtyToConsume = 0.5; + } + if (itemToConsume == 193){ + itemToConsume = 427; + qtyToConsume = 0.5; + } + if (itemToConsume == 194){ + itemToConsume = 428; + qtyToConsume = 0.5; + } + if (itemToConsume == 195){ + itemToConsume = 429; + qtyToConsume = 0.5; + } + if (itemToConsume == 196){ + itemToConsume = 430; + qtyToConsume = 0.5; + } + if (itemToConsume == 197) { + itemToConsume = 431; + qtyToConsume = 0.5; + } + if (itemToConsume == 23){ + Tag t = block.getNbtData().getValue().get("Items"); + ListTag lt = null; + if (t instanceof ListTag){ + lt = (ListTag) t; + } + int numTNT = 0; + int numFireCharges = 0; + int numWaterBuckets = 0; + if (lt != null) { + for (Tag entryTag : lt.getValue()) { + if (entryTag instanceof CompoundTag){ + CompoundTag cTag = (CompoundTag) entryTag; + if (cTag.toString().contains("minecraft:tnt")){ + numTNT += cTag.getByte("Count"); + } + if (cTag.toString().contains("minecraft:fire_charge")){ + numFireCharges += cTag.getByte("Count"); + } + if (cTag.toString().contains("minecraft:water_bucket")){ + numWaterBuckets += cTag.getByte("Count"); + } + } + } + } + + + if (numTNT > 0){ + if (!missingBlocks.containsKey(Material.TNT)){ + missingBlocks.put(Material.TNT, (double) numTNT); + } else { + Double num = missingBlocks.get(Material.TNT); + num += numTNT; + missingBlocks.put(Material.TNT, num); + } + } + if (numFireCharges > 0){ + if (!missingBlocks.containsKey(Material.FIREBALL)){ + missingBlocks.put(Material.FIREBALL, (double) numFireCharges); + } else { + Double num = missingBlocks.get(Material.FIREBALL); + num += numFireCharges; + missingBlocks.put(Material.FIREBALL, num); + + } + } + if (numWaterBuckets > 0){ + if (!missingBlocks.containsKey(Material.WATER_BUCKET)){ + missingBlocks.put(Material.WATER_BUCKET, (double) numWaterBuckets); + } else { + Double num = missingBlocks.get(Material.WATER_BUCKET); + num += numWaterBuckets; + missingBlocks.put(Material.WATER_BUCKET, num); + } + } + } + if (itemToConsume == 43) { // for double slabs, require 2 slabs + itemToConsume = 44; + qtyToConsume = 2; + } + if (itemToConsume == 125) { // for double wood slabs, require 2 wood slabs + itemToConsume = 126; + qtyToConsume = 2; + } + if (itemToConsume == 181) { // for double red sandstone slabs, require 2 red sandstone slabs + itemToConsume = 182; + qtyToConsume = 2; + } + if (itemToConsume != 0){ + if (!missingBlocks.containsKey(Material.getMaterial(itemToConsume))){ + missingBlocks.put(Material.getMaterial(itemToConsume), qtyToConsume); + } else { + Double num = missingBlocks.get(Material.getMaterial(itemToConsume)); + num += qtyToConsume; + missingBlocks.put(Material.getMaterial(itemToConsume), num); + } + locMissingBlocks.add(new Vector(x,y,z)); + } + } + if (bukkitBlock.getType() == Material.DISPENSER && block.getType() == 23){ + boolean needReplace = false; + Tag t = block.getNbtData().getValue().get("Items"); + ListTag lt = null; + if (t instanceof ListTag){ + lt = (ListTag) t; + } + int numTNT = 0; + int numFireCharges = 0; + int numWaterBuckets = 0; + if (lt != null) { + for (Tag entryTag : lt.getValue()) { + if (entryTag instanceof CompoundTag){ + CompoundTag cTag = (CompoundTag) entryTag; + if (cTag.toString().contains("minecraft:tnt")){ + numTNT += cTag.getByte("Count"); + } + if (cTag.toString().contains("minecraft:fire_charge")){ + numFireCharges += cTag.getByte("Count"); + } + if (cTag.toString().contains("minecraft:water_bucket")){ + numWaterBuckets += cTag.getByte("Count"); + } + } + } + } + Dispenser bukkitDispenser = (Dispenser) bukkitBlock.getState(); + //Bukkit.getLogger().info(String.format("TNT: %d, Fireballs: %d, Water buckets: %d", numTNT, numFireCharges, numWaterBuckets)); + for (ItemStack iStack : bukkitDispenser.getInventory().getContents()){ + if (iStack != null) { + if (iStack.getType() == Material.TNT) { + numTNT -= iStack.getAmount(); + } + if (iStack.getType() == Material.FIREBALL) { + numFireCharges -= iStack.getAmount(); + } + if (iStack.getType() == Material.WATER_BUCKET) { + numWaterBuckets -= iStack.getAmount(); + } + } + } + //Bukkit.getLogger().info(String.format("TNT: %d, Fireballs: %d, Water buckets: %d", numTNT, numFireCharges, numWaterBuckets)); + if (numTNT > 0){ + if (!missingBlocks.containsKey(Material.TNT)){ + missingBlocks.put(Material.TNT, (double) numTNT); + } else { + Double num = missingBlocks.get(Material.TNT); + num += numTNT; + missingBlocks.put(Material.TNT, num); + } + needReplace = true; + } + if (numFireCharges > 0){ + if (!missingBlocks.containsKey(Material.FIREBALL)){ + missingBlocks.put(Material.FIREBALL, (double) numFireCharges); + } else { + Double num = missingBlocks.get(Material.FIREBALL); + num += numFireCharges; + missingBlocks.put(Material.FIREBALL, num); + + } + needReplace = true; + } + if (numWaterBuckets > 0){ + if (!missingBlocks.containsKey(Material.WATER_BUCKET)){ + missingBlocks.put(Material.WATER_BUCKET, (double) numWaterBuckets); + } else { + Double num = missingBlocks.get(Material.WATER_BUCKET); + num += numWaterBuckets; + missingBlocks.put(Material.WATER_BUCKET, num); + } + needReplace = true; + } + if (needReplace){ + numDiffBlocks++; + locMissingBlocks.add(new Vector(x,y,z)); + } + } + } + } + } + locMissingBlocksMap.put(repairStateFile, locMissingBlocks); + missingBlocksMap.put(repairStateFile, missingBlocks); + numDiffBlocksMap.put(repairStateFile, numDiffBlocks); + } + return clipboard; + } + + @Override + public Clipboard loadRegionRepairStateClipboard(Plugin plugin, String s, World world) { + return null; + } + + @Override + public HashMap getMissingBlocks(String repairName) { + if (missingBlocksMap.get(repairName) == null){ + return null; + } + return missingBlocksMap.get(repairName); + } + + @Override + public HashSet getMissingBlockLocations(String repairName) { + return locMissingBlocksMap.get(repairName); + } + + @Override + public long getNumDiffBlocks(String s) { + return numDiffBlocksMap.get(s); + } + + @Override + public Vector getDistanceFromSignToLowestPoint(Clipboard clipboard, String repairName) { + Vector returnDistance = null; + for (int x = clipboard.getMinimumPoint().getBlockX(); x <= clipboard.getMaximumPoint().getBlockX(); x++) { + for (int y = clipboard.getMinimumPoint().getBlockY(); y <= clipboard.getMaximumPoint().getBlockY(); y++) { + for (int z = clipboard.getMinimumPoint().getBlockZ(); z <= clipboard.getMaximumPoint().getBlockZ(); z++) { + Vector pos = new Vector(x,y,z); + BaseBlock block = clipboard.getBlock(pos); + if (block.getType() == 68 || block.getType() == 63) { + String firstLine = block.getNbtData().getString("Text1"); + firstLine = firstLine.substring(2); + if (firstLine.substring(0, 5).equalsIgnoreCase("extra")){ + firstLine = firstLine.substring(17); + String[] parts = firstLine.split("\""); + firstLine = parts[0]; + } + String secondLine = block.getNbtData().getString("Text2"); + secondLine = secondLine.substring(2); + if (secondLine.substring(0, 5).equalsIgnoreCase("extra")){ + secondLine = secondLine.substring(17); + String[] parts = secondLine.split("\""); + secondLine = parts[0]; + } + if (firstLine.equalsIgnoreCase("Repair:")&& secondLine.contains(repairName)){ + returnDistance = new Vector(x - clipboard.getMinimumPoint().getBlockX(), y - clipboard.getMinimumPoint().getBlockY(), z - clipboard.getMinimumPoint().getBlockZ()); + } + } + } + } + } + return returnDistance; + } + + private Set baseBlocksFromCraft(Craft craft){ + HashSet returnSet = new HashSet<>(); + HashHitBox hitBox = craft.getHitBox(); + World w = craft.getW(); + for (MovecraftLocation location : hitBox){ + Integer id = w.getBlockTypeIdAt(location.getX(), location.getY(), location.getZ()); + Byte data = w.getBlockAt(location.getX(), location.getY(), location.getZ()).getData(); + returnSet.add(new BaseBlock(id, data)); + } + Bukkit.getLogger().info(returnSet.toString()); + return returnSet; + } + + private Set baseBlocksFromAssaultRegion(Vector minPos, Vector maxPos, World world){ + HashSet returnSet = new HashSet<>(); + for (int x = minPos.getBlockX(); x <= maxPos.getBlockX(); x++){ + for (int y = minPos.getBlockY(); y <= maxPos.getBlockY(); y++){ + for (int z = minPos.getBlockZ(); z <= maxPos.getBlockZ(); z++){ + int id = world.getBlockTypeIdAt(x,y,z); + byte data = world.getBlockAt(x,y,z).getData(); + //exclude air and blocks that are not destroyable during an assault + if (!Settings.AssaultDestroyableBlocks.contains(id) || id == 0){ + continue; + } + returnSet.add(new BaseBlock(id, data)); + } + } + } + + return returnSet; + } +} diff --git a/modules/v1_12_R1/pom.xml b/modules/v1_12_R1/pom.xml index b862a9d12..e428473e6 100644 --- a/modules/v1_12_R1/pom.xml +++ b/modules/v1_12_R1/pom.xml @@ -11,14 +11,25 @@ UTF-8 + net.countercraft movecraft-parent parent ../../ - + + + sk89q-repo + http://maven.sk89q.com/repo/ + + + + com.sk89q + worldedit + LATEST + net.countercraft movecraft-api diff --git a/modules/v1_13_R2/pom.xml b/modules/v1_13_R2/pom.xml new file mode 100644 index 000000000..609b224b8 --- /dev/null +++ b/modules/v1_13_R2/pom.xml @@ -0,0 +1,79 @@ + + + 4.0.0 + net.countercraft + movecraft-v1_13_R2 + jar + Movecraft-v1_13_R2 + http://github.com/eirikh1996/Movecraft + v1_13_R2 + + + UTF-8 + + + net.countercraft + movecraft-parent + parent + ../../ + + + + sk89q-repo + http://maven.sk89q.com/repo/ + + + + + com.sk89q.worldedit + worldedit-bukkit + 7.0.0-SNAPSHOT + + + net.countercraft + movecraft-api + API + jar + + + org.jetbrains + annotations-java5 + RELEASE + + + org.bukkit + craftbukkit + 1.13.2-R0.1-SNAPSHOT + + + + src/main/java + + + org.apache.maven.plugins + maven-compiler-plugin + 3.7.0 + + + net/countercraft/movecraft/compat/v1_12_R1/** + + 1.8 + 1.8 + + + + org.apache.maven.plugins + maven-jar-plugin + 2.4 + + + net/countercraft/movecraft/compat/v1_12_R1/** + + + + + + + \ No newline at end of file diff --git a/modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/IMovecraftRepair.java b/modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/IMovecraftRepair.java new file mode 100644 index 000000000..87fdff157 --- /dev/null +++ b/modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/IMovecraftRepair.java @@ -0,0 +1,131 @@ +package net.countercraft.movecraft.compat.v1_13_R2; + +import com.sk89q.jnbt.NBTInputStream; +import com.sk89q.jnbt.NBTOutputStream; +import com.sk89q.worldedit.MaxChangedBlocksException; +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.bukkit.BukkitWorld; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard; +import com.sk89q.worldedit.extent.clipboard.Clipboard; +import com.sk89q.worldedit.extent.clipboard.io.*; +import com.sk89q.worldedit.function.mask.ExistingBlockMask; +import com.sk89q.worldedit.function.operation.ForwardExtentCopy; +import com.sk89q.worldedit.function.operation.Operations; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.regions.CuboidRegion; +import com.sk89q.worldedit.schematic.SchematicFormat; +import com.sk89q.worldedit.world.registry.WorldData; +import net.countercraft.movecraft.MovecraftRepair; +import net.countercraft.movecraft.craft.Craft; +import net.countercraft.movecraft.utils.HashHitBox; +import org.bukkit.Material; +import org.bukkit.World; +import org.bukkit.block.Sign; +import org.bukkit.plugin.Plugin; + +import java.io.*; +import java.util.HashMap; +import java.util.HashSet; + +public class IMovecraftRepair extends MovecraftRepair { + @Override + public boolean saveCraftRepairState(Craft craft, Sign sign, Plugin plugin, String s) { + HashHitBox hitBox = craft.getHitBox(); + File saveDirectory = new File(plugin.getDataFolder(), "CraftRepairStates"); + World world = craft.getW(); + if (!saveDirectory.exists()){ + saveDirectory.mkdirs(); + } + BlockVector3 minPos = BlockVector3.at(hitBox.getMinX(), hitBox.getMinY(), hitBox.getMinZ()); + BlockVector3 maxPos = BlockVector3.at(hitBox.getMaxX(), hitBox.getMaxY(), hitBox.getMaxZ()); + CuboidRegion region = new CuboidRegion(minPos, maxPos); + com.sk89q.worldedit.world.World weWorld = new BukkitWorld(world); + BlockArrayClipboard clipboard = new BlockArrayClipboard(region); + Extent source = WorldEdit.getInstance().getEditSessionFactory().getEditSession(weWorld, -1); + Extent destination = clipboard; + ForwardExtentCopy copy = new ForwardExtentCopy(source, region, clipboard.getOrigin(), destination, minPos); + ExistingBlockMask mask = new ExistingBlockMask(source); + copy.setSourceMask(mask); + try { + Operations.completeLegacy(copy); + } catch (MaxChangedBlocksException e) { + e.printStackTrace(); + return false; + } + File schematicFile = new File(saveDirectory, s + ".schematic"); + try { + OutputStream output = new FileOutputStream(schematicFile); + NBTOutputStream outputStream = new NBTOutputStream(output); + SpongeSchematicWriter writer = new SpongeSchematicWriter(outputStream); + writer.write(clipboard); + writer.close(); + } catch (IOException e) { + e.printStackTrace(); + return false; + } + + return true; + } + + @Override + public boolean saveRegionRepairState(Plugin plugin, World world, org.bukkit.util.Vector vector, org.bukkit.util.Vector vector1, String s) { + return false; + } + + @Override + public boolean repairRegion(World world, String s) { + return false; + } + + @Override + public Clipboard loadCraftRepairStateClipboard(Plugin plugin, Sign sign, String s, World world) { + File dataDirectory = new File(plugin.getDataFolder(), "CraftRepairStates"); + File file = new File(dataDirectory, s + ".schematic"); // The schematic file + com.sk89q.worldedit.world.World weWorld = new BukkitWorld(world); + Clipboard clipboard; + if (file == null){ + return null; + } + ClipboardFormat format = ClipboardFormats.findByFile(file); + + try { + InputStream input = new FileInputStream(file); + ClipboardReader reader = format.getReader(input); + clipboard = reader.read(); + reader.close(); + return clipboard; + + } catch (IOException e) { + e.printStackTrace(); + } + + return null; + } + + @Override + public Clipboard loadRegionRepairStateClipboard(Plugin plugin, String s, World world) { + return null; + } + + @Override + public HashMap getMissingBlocks(String s) { + return null; + } + + @Override + public HashSet getMissingBlockLocations(String s) { + return null; + } + + @Override + public long getNumDiffBlocks(String s) { + return 0; + } + + @Override + public Vector getDistanceFromSignToLowestPoint(Clipboard clipboard, String s) { + return null; + } +} diff --git a/pom.xml b/pom.xml index 67aa428e7..b130f0946 100644 --- a/pom.xml +++ b/pom.xml @@ -1,49 +1,50 @@ - - 4.0.0 - net.countercraft - movecraft-parent - pom - parent - - - org.spigotmc - spigot-api - 1.10.2-R0.1-SNAPSHOT - - - Movecraft Parent Pom - http://github.com/apdevteam/Movecraft - - UTF-8 - - - - modules/api - modules/v1_10_R1 - modules/v1_11_R1 - modules/v1_12_R1 - modules/Movecraft - - - - - spigot-repo - https://hub.spigotmc.org/nexus/content/groups/public/ - - - - - - - org.apache.maven.plugins - maven-compiler-plugin - 3.7.0 - - 1.8 - 1.8 - - - - + + 4.0.0 + net.countercraft + movecraft-parent + pom + parent + + + org.spigotmc + spigot-api + 1.10.2-R0.1-SNAPSHOT + + + Movecraft Parent Pom + http://github.com/apdevteam/Movecraft + + UTF-8 + + + + modules/api + modules/v1_10_R1 + modules/v1_11_R1 + modules/v1_12_R1 + modules/v1_13_R2 + modules/Movecraft + + + + + spigot-repo + https://hub.spigotmc.org/nexus/content/groups/public/ + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.7.0 + + 1.8 + 1.8 + + + + \ No newline at end of file From a33023fe297c212743c9997e2797f3842ace1e45 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Sat, 5 Jan 2019 17:19:37 +0100 Subject: [PATCH 003/304] New repair system, phased out numerical block IDs and 1.13 update+ --- .../countercraft/movecraft/repair/Repair.java | 112 ++++ .../movecraft/repair/RepairManager.java | 33 ++ .../movecraft/repair/RepairTask.java | 65 +++ .../movecraft/sign/RegionDamagedSign.java | 80 +++ .../localisation/movecraftlang_no.properties | 85 +++ .../movecraft/utils/LegacyUtils.java | 123 +++++ .../compat/v1_12_R1/IMovecraftRepair.java | 499 ++++++++++++++++++ .../compat/v1_13_R2/IWorldHandler.java | 380 +++++++++++++ .../compat/v1_13_R2/NextTickProvider.java | 67 +++ 9 files changed, 1444 insertions(+) create mode 100644 modules/Movecraft/src/main/java/net/countercraft/movecraft/repair/Repair.java create mode 100644 modules/Movecraft/src/main/java/net/countercraft/movecraft/repair/RepairManager.java create mode 100644 modules/Movecraft/src/main/java/net/countercraft/movecraft/repair/RepairTask.java create mode 100644 modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RegionDamagedSign.java create mode 100644 modules/Movecraft/src/main/resources/localisation/movecraftlang_no.properties create mode 100644 modules/api/src/main/java/net/countercraft/movecraft/utils/LegacyUtils.java create mode 100644 modules/v1_12_R1/src/main/java/net/countercraft/movecraft/compat/v1_12_R1/IMovecraftRepair.java create mode 100644 modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/IWorldHandler.java create mode 100644 modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/NextTickProvider.java diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/repair/Repair.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/repair/Repair.java new file mode 100644 index 000000000..50d79381a --- /dev/null +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/repair/Repair.java @@ -0,0 +1,112 @@ +package net.countercraft.movecraft.repair; + +import net.countercraft.movecraft.config.Settings; +import net.countercraft.movecraft.craft.Craft; +import net.countercraft.movecraft.mapUpdater.update.UpdateCommand; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.boss.BarColor; +import org.bukkit.boss.BarFlag; +import org.bukkit.boss.BarStyle; +import org.bukkit.boss.BossBar; + +import java.util.LinkedList; +import java.util.UUID; +import java.util.concurrent.atomic.AtomicBoolean; + +public class Repair { + private String name; + private Craft craft; + private LinkedList updateCommands, fragileBlockUpdateCommands; + private UUID playerUUID; + private long missingBlocks, durationInTicks, ticksSinceStart; + private BossBar progressBar; + private Location signLoc; + private AtomicBoolean running = new AtomicBoolean(true); + public Repair(String name, Craft craft, LinkedList updateCommands, LinkedList fragileBlockUpdateCommands, UUID playerUUID, long missingBlocks, Location signLoc){ + this.name = name; + this.craft = craft; + this.updateCommands = updateCommands; + this.fragileBlockUpdateCommands = fragileBlockUpdateCommands; + this.durationInTicks = missingBlocks * Settings.RepairTicksPerBlock; + this.ticksSinceStart = 0; + this.missingBlocks = missingBlocks; + this.playerUUID = playerUUID; + this.signLoc = signLoc; + progressBar = Bukkit.createBossBar(this.name, BarColor.WHITE, BarStyle.SOLID, BarFlag.DARKEN_SKY); + progressBar.setVisible(true); + progressBar.setProgress(0.0); + } + public String getName(){ + return name; + } + + public UUID getPlayerUUID() { + return playerUUID; + } + + public void setPlayerUUID(UUID playerUUID) { + this.playerUUID = playerUUID; + } + + public void setName(String name) { + this.name = name; + } + + public long getMissingBlocks() { + return missingBlocks; + } + + public void setMissingBlocks(int missingBlocks) { + this.missingBlocks = missingBlocks; + } + + public AtomicBoolean getRunning() { + return running; + } + + public void setRunning(AtomicBoolean running) { + this.running = running; + } + + public long getDurationInTicks() { + return durationInTicks; + } + + public void setDurationInTicks(int durationInTicks) { + this.durationInTicks = durationInTicks; + } + + public Location getSignLoc() { + return signLoc; + } + + public void setSignLoc(Location signLoc) { + this.signLoc = signLoc; + } + + public Craft getCraft() { + return craft; + } + + public BossBar getProgressBar() { + return progressBar; + } + + public LinkedList getUpdateCommands() { + return updateCommands; + } + + public long getTicksSinceStart() { + return ticksSinceStart; + } + + public void setTicksSinceStart(long ticksSinceStart) { + this.ticksSinceStart = ticksSinceStart; + } + + public LinkedList getFragileBlockUpdateCommands() { + return fragileBlockUpdateCommands; + } + +} diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/repair/RepairManager.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/repair/RepairManager.java new file mode 100644 index 000000000..b25724ccc --- /dev/null +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/repair/RepairManager.java @@ -0,0 +1,33 @@ +package net.countercraft.movecraft.repair; + +import org.bukkit.Bukkit; +import org.bukkit.plugin.Plugin; +import org.bukkit.scheduler.BukkitRunnable; + +import java.util.Iterator; +import java.util.List; +import java.util.concurrent.CopyOnWriteArrayList; + +public class RepairManager extends BukkitRunnable { + private List repairs = new CopyOnWriteArrayList<>(); + private Plugin movecraft; + + public RepairManager(Plugin movecraft){ + this.movecraft = movecraft; + } + @Override + public void run() { + for (Repair repair : repairs){ + if (repair.getRunning().get()) { + new RepairTask(repair).runTask(movecraft); + } + + + } + //Bukkit.getLogger().info("running"); + } + + public List getRepairs() { + return repairs; + } +} diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/repair/RepairTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/repair/RepairTask.java new file mode 100644 index 000000000..fdffdaba7 --- /dev/null +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/repair/RepairTask.java @@ -0,0 +1,65 @@ +package net.countercraft.movecraft.repair; + +import com.sk89q.worldedit.Vector; +import net.countercraft.movecraft.Movecraft; +import net.countercraft.movecraft.MovecraftRepair; +import net.countercraft.movecraft.config.Settings; +import net.countercraft.movecraft.craft.CraftManager; +import net.countercraft.movecraft.localisation.I18nSupport; +import net.countercraft.movecraft.mapUpdater.MapUpdateManager; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.entity.Player; +import org.bukkit.scheduler.BukkitRunnable; + +import java.util.concurrent.atomic.AtomicBoolean; + +public class RepairTask extends BukkitRunnable { + private Repair repair; + + public RepairTask(Repair repair){ + this.repair = repair; + } + @Override + public void run() { + long ticksFromStart = repair.getTicksSinceStart(); + Player p = Bukkit.getPlayer(repair.getPlayerUUID()); + if (p != null) { + repair.getProgressBar().addPlayer(p); + } + long secsFromStart = ticksFromStart / 20; + long durationInSecs = repair.getDurationInTicks() / 20; + double repairProgress = (double) ticksFromStart / (double) repair.getDurationInTicks(); + if (repairProgress >= 0.0 && repairProgress <= 1.0) { + repair.getProgressBar().setProgress(repairProgress); + } + repair.getProgressBar().setTitle(repair.getName() + ": " + secsFromStart + "/" + durationInSecs); + + if (p != null && ticksFromStart % 1200 == 0){ + p.sendMessage(I18nSupport.getInternationalisedString("Repairs underway") + ": " + secsFromStart + "/" + durationInSecs); + } + ticksFromStart++; + repair.setTicksSinceStart(ticksFromStart); + if (ticksFromStart % Settings.RepairTicksPerBlock == 0){ + //To avoid any issues during the repair, such as fragile blocks missing, or guns firing by accident, place the blocks in correct order + if (!repair.getUpdateCommands().isEmpty()){ //first, all the solid blocks + MapUpdateManager.getInstance().scheduleUpdate(repair.getUpdateCommands().pop()); + return; + } + if (!repair.getFragileBlockUpdateCommands().isEmpty()){//Then all the fragile blocks requiring support from blocks to the side of or above it + MapUpdateManager.getInstance().scheduleUpdate(repair.getFragileBlockUpdateCommands().pop()); + return; + } + + } + //When the time is up and there are no more blocks to place, finish the repair. + if ((ticksFromStart >= repair.getDurationInTicks()) && repair.getUpdateCommands().isEmpty() && repair.getFragileBlockUpdateCommands().isEmpty()){ + if (p != null && repair.getRunning().get()) { + p.sendMessage(I18nSupport.getInternationalisedString("Repairs complete. You may now pilot the craft")); + CraftManager.getInstance().removeCraft(repair.getCraft()); + } + repair.getProgressBar().setVisible(false); + repair.setRunning(new AtomicBoolean(false)); + } + } +} diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RegionDamagedSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RegionDamagedSign.java new file mode 100644 index 000000000..e2cb9fb41 --- /dev/null +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RegionDamagedSign.java @@ -0,0 +1,80 @@ +package net.countercraft.movecraft.sign; + +import com.sk89q.worldguard.protection.regions.ProtectedRegion; +import net.countercraft.movecraft.Movecraft; +import net.countercraft.movecraft.config.Settings; +import net.countercraft.movecraft.localisation.I18nSupport; +import net.countercraft.movecraft.repair.RepairUtils; +import net.countercraft.movecraft.utils.LegacyUtils; +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.Material; +import org.bukkit.block.Sign; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.block.Action; +import org.bukkit.event.player.PlayerInteractEvent; + +import java.util.UUID; + +public class RegionDamagedSign implements Listener { + private String HEADER = ChatColor.RED + "REGION DAMAGED!"; + + @EventHandler + public void onSignRigtClick(PlayerInteractEvent event){ + Player p = event.getPlayer(); + + if (event.getAction() != Action.RIGHT_CLICK_BLOCK){ + return; + } + if (!event.getClickedBlock().getType().equals(Material.WALL_SIGN)){ + return; + } + Sign sign = (Sign) event.getClickedBlock().getState(); + if (!sign.getLine(0).equals(HEADER)){ + return; + } + String regionName = sign.getLine(1).substring(7); + Long damages = Long.parseLong(sign.getLine(2).substring(7)); + String[] owners = sign.getLine(3).substring(6).split(","); + if (Movecraft.getInstance().getEconomy().has(event.getPlayer(), damages)) { + Movecraft.getInstance().getEconomy().withdrawPlayer(event.getPlayer(), damages); + } else { + event.getPlayer().sendMessage(I18nSupport.getInternationalisedString("You do not have enough money")); + return; + } + event.getPlayer().sendMessage(I18nSupport.getInternationalisedString("Repairing region")); + if (!RepairUtils.repairRegion(regionName, event.getClickedBlock().getWorld())) { + Bukkit.getServer().broadcastMessage(String.format("REPAIR OF %s FAILED, CONTACT AN ADMIN", regionName)); + return; + } + ProtectedRegion aRegion = Movecraft.getInstance().getWorldGuardPlugin().getRegionManager(event.getClickedBlock().getWorld()).getRegion(regionName); + for (String ownerName : owners) { + if (ownerName.length() > 16) { + aRegion.getOwners().addPlayer(UUID.fromString(ownerName)); + } else { + + if (Bukkit.getPlayer(ownerName) != null){//Cannot add names directly as bug will allow free assaults + aRegion.getOwners().addPlayer(Bukkit.getPlayer(ownerName).getUniqueId()); + } else { + aRegion.getOwners().addPlayer(Bukkit.getOfflinePlayer(ownerName).getUniqueId()); + } + //aRegion.getOwners().addPlayer(ownerName); + + } + //event.getPlayer().sendMessage(ownerName); + } + int beaconX = sign.getX() - 2; + int beaconY = sign.getY() - 3; + int beaconZ = sign.getZ() - 1; + for (int x = beaconX; x < beaconX + 5; x++) { + for (int y = beaconY; y < beaconY + 4; y++) { + for (int z = beaconZ; z < beaconZ + 5; z++) { + event.getClickedBlock().getWorld().getBlockAt(x, y, z).setType(Material.AIR); + } + } + } + return; + } +} diff --git a/modules/Movecraft/src/main/resources/localisation/movecraftlang_no.properties b/modules/Movecraft/src/main/resources/localisation/movecraftlang_no.properties new file mode 100644 index 000000000..78ec54b07 --- /dev/null +++ b/modules/Movecraft/src/main/resources/localisation/movecraftlang_no.properties @@ -0,0 +1,85 @@ +# +# This file is part of Movecraft. +# +# Movecraft is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Movecraft is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Movecraft. If not, see . +# + +# Message returned when a craft is too small. One Integer which is the minimum size of that Craft Type +Detection\ -\ Craft\ too\ small=Gjenkjenning mislyktes\! Fartøyet var for lite. Minste tillatte størrelse for denne typen er %d +Detection\ -\ Craft\ too\ large=Gjenkjenning mislyktes\! Fartøyet var for stort. Største tillatte størrelse for denne typen er %d +Detection\ -\ Forbidden\ block\ found=Gjenkjenning mislyktes\! Forbudt blokk ble funnet på fartøyet. +Detection\ -\ Failed\ -\ Already\ commanding\ a\ craft=Du styrer allerede et fartøy\! +Detection\ -\ Failed\ Craft\ is\ already\ being\ controlled=Fartøyet blir allerede styrt\! +Detection\ -\ Successfully\ piloted\ craft=Styring av fartøy vellykket\! +Rotation\ -\ Craft\ is\ obstructed=Fartøyet er blokkert +Rotation\ -\ Craft\ Collision=Fartøyskollisjon +Translation\ -\ Failed\ Craft\ hit\ height\ limit=Fartøyet har nådd høydegrensen +Translation\ -\ Failed\ Craft\ is\ obstructed=Fartøyet kan ikke flyttes da leden er blokkert\! +Translation\ -\ Failed\ Craft\ out\ of\ fuel=Fartøyet er tomt for drivstoff\! +Translation\ -\ Failed\ Craft\ hit\ minimum\ height\ limit=Fartøyet har nådd den nedre høydegrensen +Translation\\=-\\ Failed\\ Craft\\ over\\ water=Fartøyet kan ikke føres over vann\\! +Translation\ -\ Craft\ collision=Fartøyskollisjon +Internal\ -\ Error\ -\ Proccessor\ thread\ encountered\ an\ error=Async Task genererte et unntak. +Startup\ -\ Number\ of\ craft\ files\ loaded=lastet inn %d Craft-filer +Startup\ -\ Error\ parsing\ CraftType\ file=***ERROR PARSING CRAFT FILE FROM DIRECTORY \: %s*** +Startup\ -\ Error\ -\ Reload\ error=Movecraft er inkompatible med reload-kommandoen. Movecraft har slått seg av og startes på nytt når serveren starter på nytt. +Startup\ -\ Error\ -\ Disable\ warning\ for\ reload=Hvis du vil bruke reload-kommandoen og Movecraft, kan du deaktivere denne innstillingen i config.yml ved å stille inn 'safeReload \: false' +Startup\ -\ Enabled\ message=[V %S] har blitt aktivert. +Item\ -\ Storage\ Crate\ name=Lagerkasse +Player-\ Craft\ has\ been\ released=Fartøyet ditt er frigitt\! +Player-\ Craft\ should\ sink\ but\ PVP\ is\ not\ allowed\ in\ this\ WorldGuard\ region=Spiller- Fartøyet skulle synke, men PVP er ikke tillatt i denne WorldGuard-region +Player-\ Craft\ is\ sinking=Fartøyet ditt har tatt for mye skade og synker\! FORLAT SKIPET\! +Player-\ Error\ -\ You\ do\ not\ have\ a\ craft\ to\ release!=Du har ikke et fartøy du kan frigi\! +Player\ -\ Error\ -\ Already\ piloting\ craft=Du styrer allerede et fartøy\! +MCStats\ -\ \:(\ -\ Admin\ has\ opted\ out=You have selected to opt out of mcstats.org data submission. The developer of Movecraft would greatly appreciate you submitting your data. +MCStats\ -\ Thank\ you\ message=Submitted statistics to mcstats.org succesfully. Thank you for your support. +MCStats\ -\ Error\ -\ Unable\ to\ upload\ stats=Unable to upload statistics to mcstats.org. Please check your network connection. +Release\ -\ Player\ has\ left\ craft=Du har forlatt fartøyet\! Du har 15 på å returnere ellers vil fartøyet ditt automatisk bli frigitt. +Release\ -\ Craft\ has\ been\ released\ message=Du har frigitt fartøyet ditt. +Release\ -\ Player\ has\ released\ a\ craft\ console=Spiller %s har frigitt et fartøy av typen %s av størrelse %d ved koordinatene \: %d x , %d z +Detection\ -\ Success\ -\ Log\ Output=Spiller %s tok kommando over et fartøy av typen %s av størrelse %d ved\: %d x, %d z +Not\ enough\ flyblock=Ikke nok flyveblokker +Too\ much\ flyblock=For mange flyveblokker +Detection\ -\ ERROR\:\ Double\ chest\ found=Gjenkjenning mislyktes\! FEIL \: Dobbeltkiste funnet +Detection\ -\ Failed\ -\ Water\ contact\ required\ but\ not\ found=Gjenkjenning mislyktes\: Kontakt med vann kreves, men ble ikke funnet +Rotation\ -\ Player\ is\ not\ permitted\ to\ build\ in\ this\ WorldGuard\ region=Rotasjon - Spiller har ikke tillatelse til å bygge i denne WorldGuard-regionen +Translation\ -\ Failed\ Player\ is\ not\ permitted\ to\ build\ in\ this\ WorldGuard\ region=Translasjon mislyktes - Spiller har ikke tillatelse til å bygge i denne WorldGuard-regionen +Parent\ Craft\ is\ busy=Foreldrefartøyet er opptatt +Insufficient\ Permissions=Utilstrekkelig med tillatelser +ERROR\:\ Remote\ Sign\ must\ be\ a\ part\ of\ a\ piloted\ craft\!=FEIL\: Remote Sign må være del av et kommandert fartøy\! +ERROR\:\ Remote\ Signs\ not\ allowed\ on\ this\ craft\!=FEIL\: Remote Signs tillates ikke på dette fartøyet\! +ERROR\:\ Could\ not\ find\ target\ sign\!=FEIL\: Kunne ikke finne målskilt\! +Entering\ Direct\ Control\ Mode=Går inn i direktekontrollmodus +Leaving\ Direct\ Control\ Mode=Går ut av direktekontrollmodus +Craft\ is\ too\ big\ to\ check\ its\ borders\.\ Make\ sure\ this\ area\ is\ safe\ to\ release\ your\ craft\ in\.=Fartøyet er for stort til å sjekke sine grenser. Se til at fartøyet trygt kan frigis i området. +You\ have\ left\ your\ craft\.\ You\ may\ return\ to\ your\ craft\ by\ typing\ \/manoverboard\ any\ time\ before\ the\ timeout\ expires=You have left your craft. If you have fallen out of your craft, you man type /manoverboard before the timout expires and be returned to it. +WARNING\!\ There\ are\ blocks\ near\ your\ craft\ that\ may\ merge\ with\ the\ \craft\ "=ADVARSEL\! Det er blokker i nærheten av fartøyet som kan bli del av fartøyet +You\ can\ only\ create\ a\ Crew\:\ sign\ for\ yourself=Du kan kun lage Crew\:-skilt til deg selv +Repair\ functionality\ is\ disabled\ or\ WorldEdit\ was\ not\ detected=Reparasjonsfunksjon er deaktivert eller WorldEdit ble ikke gjenkjent +You\ must\ be\ piloting\ a\ craft=Du må ha kommando over et fartøy +Could\ not\ save\ file=Kan ikke lagre fil +State\ saved=tilstand lagret +REPAIR\ STATE\ NOT\ FOUND=REPARASJONSTILSTAND IKKE FUNNET +Repairs\ underway=Reparasjon underveis +Repairs\ complete\.\ You\ may\ now\ pilot\ the\ craft=Reparasjon fullført. du kan nå ta kommando over fartøyet +You\ do\ not\ have\ enough\ money=Du har ikke nok penger +Need\ more\ of\ material=Trenger mer materiale +Towny\ -\ Detection\ Failed=Gjenkjenning mislyktes - Du har ikke tillatelse til å ta kommando over et fartøy på denne tomt i byen +Towny\ -\ Translation\ Failed=Translasjon mislyktes - Du har ikke tillatelse til å flytte et fartøy på denne tomt i byen +Towny\ -\ Rotation\ Failed=Rotasjon mislyktes - Du har ikke tillatelse til å ta rotere et fartøy på denne tomt i byen +Towny\ -\ Sinking\ a\ craft\ is\ not\ allowed\ in\ this\ town\ plot=Det tillates ikke å senke et fartøy i denne bytomten\! +WGCustomFlags\ -\ Translation\ Failed=Translasjon mislyktes - Du har ikke tillatelse til å flytte et fartøy i denne WorldGuard-regionen +WGCustomFlags\ -\ Rotation\ Failed=Rotasjon mislyktes - Du har ikke tillatelse til å rotere et fartøy i denne WorldGuard-regionen +WGCustomFlags\ -\ Detection\ Failed=Gjenkjenning mislyktes - Du har ikke tillatelse til å ta kommando over et fartøy i denne WorldGuard-regionen +WGCustomFlags\ -\ Sinking\ a\ craft\ is\ not\ allowed\ in\ this\ WorldGuard\ region=Ikke tillatt å synke i denne WorldGuard-regionen\! diff --git a/modules/api/src/main/java/net/countercraft/movecraft/utils/LegacyUtils.java b/modules/api/src/main/java/net/countercraft/movecraft/utils/LegacyUtils.java new file mode 100644 index 000000000..a2dc84cc9 --- /dev/null +++ b/modules/api/src/main/java/net/countercraft/movecraft/utils/LegacyUtils.java @@ -0,0 +1,123 @@ +package net.countercraft.movecraft.utils; + +import org.bukkit.Material; +import org.bukkit.Sound; +import org.bukkit.block.Block; + +public class LegacyUtils { + + //Materials removed in 1.13 + public static Material BED_BLOCK = Material.BED_BLOCK; + public static Material CARPET = Material.CARPET; + public static Material CROPS = Material.CROPS; + public static Material DAYLIGHT_DETECTOR_INVERTED = Material.DAYLIGHT_DETECTOR_INVERTED; + public static Material DIODE = Material.DIODE; + public static Material DIODE_BLOCK_OFF = Material.DIODE_BLOCK_OFF; + public static Material DIODE_BLOCK_ON = Material.DIODE_BLOCK_ON; + public static Material DOUBLE_PLANT = Material.DOUBLE_PLANT; + public static Material FENCE = Material.FENCE; + public static Material FIREBALL = Material.FIREBALL; + public static Material GOLD_PLATE = Material.GOLD_PLATE; + public static Material IRON_DOOR_BLOCK = Material.IRON_DOOR_BLOCK; + public static Material IRON_FENCE = Material.IRON_FENCE; + public static Material IRON_PLATE = Material.IRON_PLATE; + public static Material LEAVES = Material.LEAVES; + public static Material LEAVES_2 = Material.LEAVES_2; + public static Material LOG = Material.LOG; + public static Material LOG_2 = Material.LOG_2; + public static Material LONG_GRASS = Material.LONG_GRASS; + public static Material PISTON_BASE = Material.PISTON_BASE; + public static Material PISTON_EXTENSION = Material.PISTON_EXTENSION; + public static Material PISTON_STICKY_BASE = Material.PISTON_STICKY_BASE; + public static Material RED_ROSE = Material.RED_ROSE; + public static Material REDSTONE_COMPARATOR = Material.REDSTONE_COMPARATOR; + public static Material REDSTONE_COMPARATOR_OFF = Material.REDSTONE_COMPARATOR_OFF; + public static Material REDSTONE_COMPARATOR_ON = Material.REDSTONE_COMPARATOR_ON; + public static Material REDSTONE_TORCH_ON = Material.REDSTONE_TORCH_ON; + public static Material REDSTONE_TORCH_OFF = Material.REDSTONE_TORCH_OFF; + public static Material SEEDS = Material.SEEDS; + public static Material SMOOTH_STAIRS = Material.SMOOTH_STAIRS; + public static Material STAINED_GLASS = Material.STAINED_GLASS; + public static Material STAINED_GLASS_PANE = Material.STAINED_GLASS_PANE; + public static Material STATIONARY_WATER = Material.STATIONARY_WATER; + public static Material STATIONARY_LAVA = Material.STATIONARY_LAVA; + public static Material STEP = Material.STEP; + public static Material STONE_PLATE = Material.STONE_PLATE; + public static Material SIGN_POST = Material.SIGN_POST; + public static Material SUGAR_CANE_BLOCK = Material.SUGAR_CANE_BLOCK; + public static Material THIN_GLASS = Material.THIN_GLASS; + public static Material TRAP_DOOR = Material.TRAP_DOOR; + public static Material WATER_LILY = Material.WATER_LILY; + public static Material WEB = Material.WEB; + public static Material WOOL = Material.WOOL; + public static Material WOOD = Material.WOOD; + public static Material WOOD_BUTTON = Material.WOOD_BUTTON; + public static Material WOOD_DOOR = Material.WOOD_DOOR; + public static Material WOOD_PLATE = Material.WOOD_PLATE; + public static Material YELLOW_FLOWER = Material.YELLOW_FLOWER; + + //Sounds removed in 1.13 + public static Sound ENITIY_IRONGOLEM_DEATH = Sound.ENTITY_IRONGOLEM_DEATH; + //Methods removed in 1.13 + public static Material getMaterial(int id){ + try { + return Material.getMaterial(id); + } catch (IllegalArgumentException e){ + return null; + } + } + + + + + private static Material get(String name) { + + try { + return Material.valueOf(name); + } catch (IllegalArgumentException e) { + return null; + } + } + + public static void setTypeIdAndData(Block b, int id, byte data, boolean b1){ + b.setTypeIdAndData(id, data, b1); + } + public static void setData(Block b, byte data){ + b.setData(data); + } + + private String getColorFromData(byte data){ + String color = ""; + switch (data){ + case 0 : + color = "WHITE"; + break; + case 1 : + color = "ORANGE"; + break; + case 2 : + color = "MAGENTA"; + break; + case 3 : + color = "LIGHT_BLUE"; + break; + case 4 : + color = "YELLOW"; + break; + case 5 : + color = "LIME"; + break; + case 6 : + color = "PINK"; + break; + case 7 : + color = "GRAY"; + break; + case 8 : + color = "LIGHT_GRAY"; + break; + } + return color; + } + +} diff --git a/modules/v1_12_R1/src/main/java/net/countercraft/movecraft/compat/v1_12_R1/IMovecraftRepair.java b/modules/v1_12_R1/src/main/java/net/countercraft/movecraft/compat/v1_12_R1/IMovecraftRepair.java new file mode 100644 index 000000000..32f95558b --- /dev/null +++ b/modules/v1_12_R1/src/main/java/net/countercraft/movecraft/compat/v1_12_R1/IMovecraftRepair.java @@ -0,0 +1,499 @@ +package net.countercraft.movecraft.compat.v1_12_R1; + +import com.sk89q.jnbt.*; +import com.sk89q.worldedit.MaxChangedBlocksException; +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.blocks.*; +import com.sk89q.worldedit.bukkit.BukkitWorld; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard; +import com.sk89q.worldedit.extent.clipboard.Clipboard; +import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormat; +import com.sk89q.worldedit.extent.clipboard.io.ClipboardWriter; +import com.sk89q.worldedit.function.mask.BlockMask; +import com.sk89q.worldedit.function.mask.ExistingBlockMask; +import com.sk89q.worldedit.function.operation.ForwardExtentCopy; +import com.sk89q.worldedit.function.operation.Operations; +import com.sk89q.worldedit.masks.BlockTypeMask; +import com.sk89q.worldedit.regions.CuboidRegion; +import com.sk89q.worldedit.world.registry.WorldData; +import net.countercraft.movecraft.MovecraftLocation; +import net.countercraft.movecraft.MovecraftRepair; +import net.countercraft.movecraft.config.Settings; +import net.countercraft.movecraft.craft.Craft; +import net.countercraft.movecraft.utils.HashHitBox; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.World; +import org.bukkit.block.*; +import org.bukkit.inventory.ItemStack; +import org.bukkit.plugin.Plugin; + +import java.io.*; +import java.util.*; + +public class IMovecraftRepair extends MovecraftRepair { + private HashMap> locMissingBlocksMap = new HashMap<>(); + private HashMap numDiffBlocksMap = new HashMap<>(); + private HashMap> missingBlocksMap = new HashMap<>(); + + @Override + public boolean saveCraftRepairState (Craft craft, Sign sign, Plugin plugin, String s) { + HashHitBox hitBox = craft.getHitBox(); + File saveDirectory = new File(plugin.getDataFolder(), "CraftRepairStates"); + World world = craft.getW(); + com.sk89q.worldedit.world.World weWorld = new BukkitWorld(world); + WorldData worldData = weWorld.getWorldData(); + if (!saveDirectory.exists()){ + saveDirectory.mkdirs(); + } + Vector minPos = new Vector(hitBox.getMinX(), hitBox.getMinY(), hitBox.getMinZ()); + Vector maxPos = new Vector(hitBox.getMaxX(), hitBox.getMaxY(), hitBox.getMaxZ()); + CuboidRegion cRegion = new CuboidRegion(minPos, maxPos); + File repairStateFile = new File(saveDirectory, s + ".schematic"); + Set blockSet = baseBlocksFromCraft(craft); + try { + + BlockArrayClipboard clipboard = new BlockArrayClipboard(cRegion); + Extent source = WorldEdit.getInstance().getEditSessionFactory().getEditSession(weWorld, -1); + Extent destination = clipboard; + ForwardExtentCopy copy = new ForwardExtentCopy(source, cRegion, clipboard.getOrigin(), destination, minPos); + BlockMask mask = new BlockMask(source, blockSet); + copy.setSourceMask(mask); + Operations.completeLegacy(copy); + ClipboardWriter writer = ClipboardFormat.SCHEMATIC.getWriter(new FileOutputStream(repairStateFile, false)); + writer.write(clipboard, worldData); + writer.close(); + return true; + + } catch (MaxChangedBlocksException e) { + e.printStackTrace(); + return false; + } catch (IOException e) { + e.printStackTrace(); + return false; + } + + + } + + @Override + public boolean saveRegionRepairState(Plugin plugin, World world, org.bukkit.util.Vector minPos, org.bukkit.util.Vector maxPos, String s) { + File saveDirectory = new File(plugin.getDataFolder(), "RegionRepairStates"); + com.sk89q.worldedit.world.World weWorld = new BukkitWorld(world); + WorldData worldData = weWorld.getWorldData(); + Vector weMinPos = new Vector(minPos.getBlockX(), minPos.getBlockY(), minPos.getBlockZ()); + Vector weMaxPos = new Vector(maxPos.getBlockX(), maxPos.getBlockY(), maxPos.getBlockZ()); + if (!saveDirectory.exists()){ + saveDirectory.mkdirs(); + } + Set baseBlockSet = new HashSet<>(); + CuboidRegion cRegion = new CuboidRegion(weMinPos, weMaxPos); + File repairStateFile = new File(saveDirectory, s + ".schematic"); + for (int x = weMinPos.getBlockX(); x <= weMaxPos.getBlockX(); x++){ + for (int y = weMinPos.getBlockY(); y <= weMaxPos.getBlockY(); y++){ + for (int z = weMinPos.getBlockZ(); z <= weMaxPos.getBlockZ(); z++){ + Block block = world.getBlockAt(x,y,z); + if (block.getType().equals(Material.AIR)){ + continue; + } + if (Settings.AssaultDestroyableBlocks.contains(block.getType())){ + baseBlockSet.add(new BaseBlock(block.getTypeId(), block.getData())); + } + } + } + } + try { + + BlockArrayClipboard clipboard = new BlockArrayClipboard(cRegion); + Extent source = WorldEdit.getInstance().getEditSessionFactory().getEditSession(weWorld, -1); + Extent destination = clipboard; + ForwardExtentCopy copy = new ForwardExtentCopy(source, cRegion, clipboard.getOrigin(), destination, weMinPos); + BlockMask mask = new BlockMask(source, baseBlockSet); + copy.setSourceMask(mask); + Operations.completeLegacy(copy); + ClipboardWriter writer = ClipboardFormat.SCHEMATIC.getWriter(new FileOutputStream(repairStateFile, false)); + writer.write(clipboard, worldData); + writer.close(); + return true; + + } catch (MaxChangedBlocksException e) { + e.printStackTrace(); + return false; + } catch (IOException e) { + e.printStackTrace(); + return false; + } + } + + @Override + public boolean repairRegion(World world, String s) { + return false; + } + + @Override + public Clipboard loadCraftRepairStateClipboard(Plugin plugin,Sign sign, String repairStateFile, World world) { + File dataDirectory = new File(plugin.getDataFolder(), "CraftRepairStates"); + File file = new File(dataDirectory, repairStateFile + ".schematic"); // The schematic file + com.sk89q.worldedit.world.World weWorld = new BukkitWorld(world); + WorldData worldData = weWorld.getWorldData(); + Clipboard clipboard; + try { + clipboard = ClipboardFormat.SCHEMATIC.getReader(new FileInputStream(file)).read(worldData); + + } catch (FileNotFoundException e) { + e.printStackTrace(); + return null; + } catch (IOException e) { + e.printStackTrace(); + return null; + } + if (clipboard != null){ + long numDiffBlocks = 0; + HashMap missingBlocks = new HashMap<>(); + HashSet locMissingBlocks = new HashSet<>(); + Vector distMP = getDistanceFromSignToLowestPoint(clipboard, sign.getLine(1)); + Vector minPos = new Vector(sign.getLocation().getBlockX() - distMP.getBlockX(), sign.getLocation().getBlockY() - distMP.getBlockY(), sign.getLocation().getBlockZ() - distMP.getBlockZ()); + Vector distance = new Vector(minPos.getBlockX() - clipboard.getMinimumPoint().getBlockX(), minPos.getBlockY() - clipboard.getMinimumPoint().getBlockY(), minPos.getBlockZ() - clipboard.getMinimumPoint().getBlockZ()); + for (int x = clipboard.getMinimumPoint().getBlockX(); x <= clipboard.getMaximumPoint().getBlockX(); x++){ + for (int y = clipboard.getMinimumPoint().getBlockY(); y <= clipboard.getMaximumPoint().getBlockY(); y++){ + for (int z = clipboard.getMinimumPoint().getBlockZ(); z <= clipboard.getMaximumPoint().getBlockZ(); z++){ + Vector position = new Vector(x,y,z); + Location bukkitLoc = new Location(sign.getWorld(), x + distance.getBlockX(), y + distance.getBlockY(), z + distance.getBlockZ()); + BaseBlock block = clipboard.getBlock(position); + Block bukkitBlock = sign.getWorld().getBlockAt(bukkitLoc); + boolean isImportant = true; + if (block.getType() == 0){ + isImportant = false; + } + + if (isImportant && bukkitBlock.getTypeId() != block.getType()) { + int itemToConsume = block.getType(); + double qtyToConsume = 1.0; + numDiffBlocks++; + //some blocks aren't represented by items with the same number as the block + if (itemToConsume == 63 || itemToConsume == 68) // signs + itemToConsume = 323; + if (itemToConsume == 93 || itemToConsume == 94) // repeaters + itemToConsume = 356; + if (itemToConsume == 149 || itemToConsume == 150) // comparators + itemToConsume = 404; + if (itemToConsume == 55) // redstone + itemToConsume = 331; + if (itemToConsume == 118) // cauldron + itemToConsume = 380; + if (itemToConsume == 124) // lit redstone lamp + itemToConsume = 123; + if (itemToConsume == 75) // lit redstone torch + itemToConsume = 76; + if (itemToConsume == 8 || itemToConsume == 9) { // don't require water to be in the chest + itemToConsume = 0; + qtyToConsume = 0.0; + } + if (itemToConsume == 10 || itemToConsume == 11) { // don't require lava either, yeah you could exploit this for free lava, so make sure you set a price per block + itemToConsume = 0; + qtyToConsume = 0.0; + } + if (itemToConsume == 26) { //beds + itemToConsume = 355; + qtyToConsume = 0.5; + } + if (itemToConsume == 64) { //doors + itemToConsume = 324; //since doors and beds encompass two blocks, require only 0.5 block for each of the two blocks + qtyToConsume = 0.5; + } + if (itemToConsume == 71){ + itemToConsume = 330; + qtyToConsume = 0.5; + } + if (itemToConsume == 193){ + itemToConsume = 427; + qtyToConsume = 0.5; + } + if (itemToConsume == 194){ + itemToConsume = 428; + qtyToConsume = 0.5; + } + if (itemToConsume == 195){ + itemToConsume = 429; + qtyToConsume = 0.5; + } + if (itemToConsume == 196){ + itemToConsume = 430; + qtyToConsume = 0.5; + } + if (itemToConsume == 197) { + itemToConsume = 431; + qtyToConsume = 0.5; + } + if (itemToConsume == 23){ + Tag t = block.getNbtData().getValue().get("Items"); + ListTag lt = null; + if (t instanceof ListTag){ + lt = (ListTag) t; + } + int numTNT = 0; + int numFireCharges = 0; + int numWaterBuckets = 0; + if (lt != null) { + for (Tag entryTag : lt.getValue()) { + if (entryTag instanceof CompoundTag){ + CompoundTag cTag = (CompoundTag) entryTag; + if (cTag.toString().contains("minecraft:tnt")){ + numTNT += cTag.getByte("Count"); + } + if (cTag.toString().contains("minecraft:fire_charge")){ + numFireCharges += cTag.getByte("Count"); + } + if (cTag.toString().contains("minecraft:water_bucket")){ + numWaterBuckets += cTag.getByte("Count"); + } + } + } + } + + + if (numTNT > 0){ + if (!missingBlocks.containsKey(Material.TNT)){ + missingBlocks.put(Material.TNT, (double) numTNT); + } else { + Double num = missingBlocks.get(Material.TNT); + num += numTNT; + missingBlocks.put(Material.TNT, num); + } + } + if (numFireCharges > 0){ + if (!missingBlocks.containsKey(Material.FIREBALL)){ + missingBlocks.put(Material.FIREBALL, (double) numFireCharges); + } else { + Double num = missingBlocks.get(Material.FIREBALL); + num += numFireCharges; + missingBlocks.put(Material.FIREBALL, num); + + } + } + if (numWaterBuckets > 0){ + if (!missingBlocks.containsKey(Material.WATER_BUCKET)){ + missingBlocks.put(Material.WATER_BUCKET, (double) numWaterBuckets); + } else { + Double num = missingBlocks.get(Material.WATER_BUCKET); + num += numWaterBuckets; + missingBlocks.put(Material.WATER_BUCKET, num); + } + } + } + if (itemToConsume == 43) { // for double slabs, require 2 slabs + itemToConsume = 44; + qtyToConsume = 2; + } + if (itemToConsume == 125) { // for double wood slabs, require 2 wood slabs + itemToConsume = 126; + qtyToConsume = 2; + } + if (itemToConsume == 181) { // for double red sandstone slabs, require 2 red sandstone slabs + itemToConsume = 182; + qtyToConsume = 2; + } + if (itemToConsume != 0){ + if (!missingBlocks.containsKey(Material.getMaterial(itemToConsume))){ + missingBlocks.put(Material.getMaterial(itemToConsume), qtyToConsume); + } else { + Double num = missingBlocks.get(Material.getMaterial(itemToConsume)); + num += qtyToConsume; + missingBlocks.put(Material.getMaterial(itemToConsume), num); + } + locMissingBlocks.add(new Vector(x,y,z)); + } + } + if (bukkitBlock.getType() == Material.DISPENSER && block.getType() == 23){ + boolean needReplace = false; + Tag t = block.getNbtData().getValue().get("Items"); + ListTag lt = null; + if (t instanceof ListTag){ + lt = (ListTag) t; + } + int numTNT = 0; + int numFireCharges = 0; + int numWaterBuckets = 0; + if (lt != null) { + for (Tag entryTag : lt.getValue()) { + if (entryTag instanceof CompoundTag){ + CompoundTag cTag = (CompoundTag) entryTag; + if (cTag.toString().contains("minecraft:tnt")){ + numTNT += cTag.getByte("Count"); + } + if (cTag.toString().contains("minecraft:fire_charge")){ + numFireCharges += cTag.getByte("Count"); + } + if (cTag.toString().contains("minecraft:water_bucket")){ + numWaterBuckets += cTag.getByte("Count"); + } + } + } + } + Dispenser bukkitDispenser = (Dispenser) bukkitBlock.getState(); + //Bukkit.getLogger().info(String.format("TNT: %d, Fireballs: %d, Water buckets: %d", numTNT, numFireCharges, numWaterBuckets)); + for (ItemStack iStack : bukkitDispenser.getInventory().getContents()){ + if (iStack != null) { + if (iStack.getType() == Material.TNT) { + numTNT -= iStack.getAmount(); + } + if (iStack.getType() == Material.FIREBALL) { + numFireCharges -= iStack.getAmount(); + } + if (iStack.getType() == Material.WATER_BUCKET) { + numWaterBuckets -= iStack.getAmount(); + } + } + } + //Bukkit.getLogger().info(String.format("TNT: %d, Fireballs: %d, Water buckets: %d", numTNT, numFireCharges, numWaterBuckets)); + if (numTNT > 0){ + if (!missingBlocks.containsKey(Material.TNT)){ + missingBlocks.put(Material.TNT, (double) numTNT); + } else { + Double num = missingBlocks.get(Material.TNT); + num += numTNT; + missingBlocks.put(Material.TNT, num); + } + needReplace = true; + } + if (numFireCharges > 0){ + if (!missingBlocks.containsKey(Material.FIREBALL)){ + missingBlocks.put(Material.FIREBALL, (double) numFireCharges); + } else { + Double num = missingBlocks.get(Material.FIREBALL); + num += numFireCharges; + missingBlocks.put(Material.FIREBALL, num); + + } + needReplace = true; + } + if (numWaterBuckets > 0){ + if (!missingBlocks.containsKey(Material.WATER_BUCKET)){ + missingBlocks.put(Material.WATER_BUCKET, (double) numWaterBuckets); + } else { + Double num = missingBlocks.get(Material.WATER_BUCKET); + num += numWaterBuckets; + missingBlocks.put(Material.WATER_BUCKET, num); + } + needReplace = true; + } + if (needReplace){ + numDiffBlocks++; + locMissingBlocks.add(new Vector(x,y,z)); + } + } + } + } + } + locMissingBlocksMap.put(repairStateFile, locMissingBlocks); + missingBlocksMap.put(repairStateFile, missingBlocks); + numDiffBlocksMap.put(repairStateFile, numDiffBlocks); + } + return clipboard; + } + + @Override + public Clipboard loadRegionRepairStateClipboard(Plugin plugin, String s, World world) { + File dataDirectory = new File(plugin.getDataFolder(), "RegionRepairStates"); + File file = new File(dataDirectory, s + ".schematic"); // The schematic file + com.sk89q.worldedit.world.World weWorld = new BukkitWorld(world); + WorldData worldData = weWorld.getWorldData(); + try { + return ClipboardFormat.SCHEMATIC.getReader(new FileInputStream(file)).read(worldData); + + } catch (FileNotFoundException e) { + e.printStackTrace(); + return null; + } catch (IOException e) { + e.printStackTrace(); + return null; + } + } + + @Override + public HashMap getMissingBlocks(String repairName) { + if (missingBlocksMap.get(repairName) == null){ + return null; + } + return missingBlocksMap.get(repairName); + } + + @Override + public HashSet getMissingBlockLocations(String repairName) { + return locMissingBlocksMap.get(repairName); + } + + @Override + public long getNumDiffBlocks(String s) { + return numDiffBlocksMap.get(s); + } + + @Override + public Vector getDistanceFromSignToLowestPoint(Clipboard clipboard, String repairName) { + Vector returnDistance = null; + for (int x = clipboard.getMinimumPoint().getBlockX(); x <= clipboard.getMaximumPoint().getBlockX(); x++) { + for (int y = clipboard.getMinimumPoint().getBlockY(); y <= clipboard.getMaximumPoint().getBlockY(); y++) { + for (int z = clipboard.getMinimumPoint().getBlockZ(); z <= clipboard.getMaximumPoint().getBlockZ(); z++) { + Vector pos = new Vector(x,y,z); + BaseBlock block = clipboard.getBlock(pos); + if (block.getType() == 68 || block.getType() == 63) { + String firstLine = block.getNbtData().getString("Text1"); + firstLine = firstLine.substring(2); + if (firstLine.substring(0, 5).equalsIgnoreCase("extra")){ + firstLine = firstLine.substring(17); + String[] parts = firstLine.split("\""); + firstLine = parts[0]; + } + String secondLine = block.getNbtData().getString("Text2"); + secondLine = secondLine.substring(2); + if (secondLine.substring(0, 5).equalsIgnoreCase("extra")){ + secondLine = secondLine.substring(17); + String[] parts = secondLine.split("\""); + secondLine = parts[0]; + } + if (firstLine.equalsIgnoreCase("Repair:")&& secondLine.contains(repairName)){ + returnDistance = new Vector(x - clipboard.getMinimumPoint().getBlockX(), y - clipboard.getMinimumPoint().getBlockY(), z - clipboard.getMinimumPoint().getBlockZ()); + } + } + } + } + } + return returnDistance; + } + + private Set baseBlocksFromCraft(Craft craft){ + HashSet returnSet = new HashSet<>(); + HashHitBox hitBox = craft.getHitBox(); + World w = craft.getW(); + for (MovecraftLocation location : hitBox){ + Integer id = w.getBlockTypeIdAt(location.getX(), location.getY(), location.getZ()); + Byte data = w.getBlockAt(location.getX(), location.getY(), location.getZ()).getData(); + returnSet.add(new BaseBlock(id, data)); + } + Bukkit.getLogger().info(returnSet.toString()); + return returnSet; + } + + private Set baseBlocksFromAssaultRegion(Vector minPos, Vector maxPos, World world){ + HashSet returnSet = new HashSet<>(); + for (int x = minPos.getBlockX(); x <= maxPos.getBlockX(); x++){ + for (int y = minPos.getBlockY(); y <= maxPos.getBlockY(); y++){ + for (int z = minPos.getBlockZ(); z <= maxPos.getBlockZ(); z++){ + int id = world.getBlockTypeIdAt(x,y,z); + byte data = world.getBlockAt(x,y,z).getData(); + //exclude air and blocks that are not destroyable during an assault + if (!Settings.AssaultDestroyableBlocks.contains(id) || id == 0){ + continue; + } + returnSet.add(new BaseBlock(id, data)); + } + } + } + + return returnSet; + } +} diff --git a/modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/IWorldHandler.java b/modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/IWorldHandler.java new file mode 100644 index 000000000..001684fac --- /dev/null +++ b/modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/IWorldHandler.java @@ -0,0 +1,380 @@ +package net.countercraft.movecraft.compat.v1_13_R2; + +import net.countercraft.movecraft.config.Settings; +import net.countercraft.movecraft.utils.MathUtils; +import net.countercraft.movecraft.MovecraftLocation; +import net.countercraft.movecraft.Rotation; +import net.countercraft.movecraft.utils.CollectionUtils; +import net.countercraft.movecraft.WorldHandler; +import net.countercraft.movecraft.craft.Craft; +import net.minecraft.server.v1_13_R2.*; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.craftbukkit.v1_13_R2.CraftWorld; +import org.bukkit.craftbukkit.v1_13_R2.block.CraftBlockState; +import org.bukkit.craftbukkit.v1_13_R2.entity.CraftPlayer; +import org.bukkit.craftbukkit.v1_13_R2.util.CraftMagicNumbers; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.*; + +public class IWorldHandler extends WorldHandler{ + private static final EnumBlockRotation ROTATION[]; + static { + ROTATION = new EnumBlockRotation[3]; + ROTATION[Rotation.NONE.ordinal()] = EnumBlockRotation.NONE; + ROTATION[Rotation.CLOCKWISE.ordinal()] = EnumBlockRotation.CLOCKWISE_90; + ROTATION[Rotation.ANTICLOCKWISE.ordinal()] = EnumBlockRotation.COUNTERCLOCKWISE_90; + } + private final NextTickProvider tickProvider = new NextTickProvider(); + private final HashMap> bMap = new HashMap<>(); + private MethodHandle internalTeleportMH; + + public IWorldHandler() { + MethodHandles.Lookup lookup = MethodHandles.lookup(); + Method teleport = null; + try { + teleport = PlayerConnection.class.getDeclaredMethod("internalTeleport", double.class, double.class, double.class, float.class, float.class, Set.class); + teleport.setAccessible(true); + internalTeleportMH = lookup.unreflect(teleport); + + } catch (NoSuchMethodException | IllegalAccessException e) { + e.printStackTrace(); + } + } + + @Override + public void addPlayerLocation(Player player, double x, double y, double z, float yaw, float pitch){ + EntityPlayer ePlayer = ((CraftPlayer) player).getHandle(); + if(internalTeleportMH == null) { + //something went wrong + super.addPlayerLocation(player, x, y, z, yaw, pitch); + return; + } + try { + internalTeleportMH.invoke(ePlayer.playerConnection, x, y, z, yaw, pitch, EnumSet.allOf(PacketPlayOutPosition.EnumPlayerTeleportFlags.class)); + } catch (Throwable throwable) { + throwable.printStackTrace(); + } + } + + @Override + public void rotateCraft(@NotNull Craft craft, @NotNull MovecraftLocation originPoint, @NotNull Rotation rotation) { + //******************************************* + //* Step one: Convert to Positions * + //******************************************* + HashMap rotatedPositions = new HashMap<>(); + Rotation counterRotation = rotation == Rotation.CLOCKWISE ? Rotation.ANTICLOCKWISE : Rotation.CLOCKWISE; + for(MovecraftLocation newLocation : craft.getHitBox()){ + rotatedPositions.put(locationToPosition(MathUtils.rotateVec(counterRotation, newLocation.subtract(originPoint)).add(originPoint)),locationToPosition(newLocation)); + } + //******************************************* + //* Step two: Get the tiles * + //******************************************* + World nativeWorld = ((CraftWorld) craft.getW()).getHandle(); + List tiles = new ArrayList<>(); + //get the tiles + for(BlockPosition position : rotatedPositions.keySet()){ + //TileEntity tile = nativeWorld.removeTileEntity(position); + TileEntity tile = removeTileEntity(nativeWorld,position); + if(tile == null) + continue; + tile.a(ROTATION[rotation.ordinal()]); + //get the nextTick to move with the tile + tiles.add(new TileHolder(tile, tickProvider.getNextTick((WorldServer)nativeWorld,position), position)); + } + + //******************************************* + //* Step three: Translate all the blocks * + //******************************************* + // blockedByWater=false means an ocean-going vessel + //TODO: Simplify + //TODO: go by chunks + //TODO: Don't move unnecessary blocks + //get the blocks and rotate them + HashMap blockData = new HashMap<>(); + for(BlockPosition position : rotatedPositions.keySet()){ + blockData.put(position,nativeWorld.getType(position).a(ROTATION[rotation.ordinal()])); + } + //create the new block + for(Map.Entry entry : blockData.entrySet()) { + setBlockFast(nativeWorld, rotatedPositions.get(entry.getKey()), entry.getValue()); + } + + + //******************************************* + //* Step four: replace all the tiles * + //******************************************* + //TODO: go by chunks + for(TileHolder tileHolder : tiles){ + moveTileEntity(nativeWorld, rotatedPositions.get(tileHolder.getTilePosition()),tileHolder.getTile()); + if(tileHolder.getNextTick()==null) + continue; + final long currentTime = nativeWorld.worldData.getTime(); + //nativeWorld.b(rotatedPositions.get(tileHolder.getNextTick().a), tileHolder.getNextTick().a(), (int) (tileHolder.getNextTick().b - currentTime), tileHolder.getNextTick().c); + //BlockPosition, Object, int, TickListPriority + nativeWorld.b(rotatedPositions.get(tileHolder.getNextTick().a), tileHolder.getTile()); + } + + //******************************************* + //* Step five: Destroy the leftovers * + //******************************************* + //TODO: add support for pass-through + Collection deletePositions = CollectionUtils.filter(rotatedPositions.keySet(),rotatedPositions.values()); + for(BlockPosition position : deletePositions){ + setBlockFast(nativeWorld, position, Blocks.AIR.getBlockData()); + } + + //******************************************* + //* Step six: Update the blocks * + //******************************************* + for(BlockPosition newPosition : rotatedPositions.values()) { + // CraftBlockState.getBlockState(nativeWorld,newPosition.getX(), newPosition.getY(), newPosition.getZ()).update(false,false); + CraftBlockState.getBlockState(nativeWorld, newPosition, 3).update(false, false); + } + for(BlockPosition deletedPosition : deletePositions){ + // CraftBlockState.getBlockState(nativeWorld,deletedPosition.getX(), deletedPosition.getY(), deletedPosition.getZ()).update(false,false); + CraftBlockState.getBlockState(nativeWorld, deletedPosition, 3).update(false, false); + } + //******************************************* + //* Step seven: Send to players * + //******************************************* + List chunks = new ArrayList<>(); + for(BlockPosition position : rotatedPositions.values()){ + Chunk chunk = nativeWorld.getChunkAtWorldCoords(position); + if(!chunks.contains(chunk)){ + chunks.add(chunk); + } + } + for(BlockPosition position : deletePositions){ + Chunk chunk = nativeWorld.getChunkAtWorldCoords(position); + if(!chunks.contains(chunk)){ + chunks.add(chunk); + } + } + } + + @Override + public void translateCraft(@NotNull Craft craft, @NotNull MovecraftLocation displacement) { + //TODO: Add supourt for rotations + //A craftTranslateCommand should only occur if the craft is moving to a valid position + //******************************************* + //* Step one: Convert to Positions * + //******************************************* + BlockPosition translateVector = locationToPosition(displacement); + List positions = new ArrayList<>(); + for(MovecraftLocation movecraftLocation : craft.getHitBox()) { + positions.add(locationToPosition((movecraftLocation)).b(translateVector)); + + } + //******************************************* + //* Step two: Get the tiles * + //******************************************* + World nativeWorld = ((CraftWorld) craft.getW()).getHandle(); + List tiles = new ArrayList<>(); + //get the tiles + for(BlockPosition position : positions){ + if(nativeWorld.getType(position) == Blocks.AIR.getBlockData()) + continue; + //TileEntity tile = nativeWorld.removeTileEntity(position); + TileEntity tile = removeTileEntity(nativeWorld,position); + if(tile == null) + continue; + //get the nextTick to move with the tile + + //nativeWorld.capturedTileEntities.remove(position); + //nativeWorld.getChunkAtWorldCoords(position).getTileEntities().remove(position); + tiles.add(new TileHolder(tile, tickProvider.getNextTick((WorldServer)nativeWorld,position), position)); + + } + //******************************************* + //* Step three: Translate all the blocks * + //******************************************* + // blockedByWater=false means an ocean-going vessel + //TODO: Simplify + //TODO: go by chunks + //TODO: Don't move unnecessary blocks + //get the blocks + List blockData = new ArrayList<>(); + for(BlockPosition position : positions){ + blockData.add(nativeWorld.getType(position)); + } + //translate the positions + List newPositions = new ArrayList<>(); + for(BlockPosition position : positions){ + newPositions.add(position.a(translateVector)); + } + //create the new block + for(int i = 0; i deletePositions = CollectionUtils.filter(positions,newPositions); + for(BlockPosition position : deletePositions){ + setBlockFast(nativeWorld, position, Blocks.AIR.getBlockData()); + } + + //******************************************* + //* Step six: Update the blocks * + //******************************************* + for(BlockPosition newPosition : newPositions) { + CraftBlockState.getBlockState(nativeWorld, newPosition, 3).update(false,false); + } + for(BlockPosition deletedPosition : deletePositions){ + CraftBlockState.getBlockState(nativeWorld, deletedPosition, 3).update(false,false); + } + //******************************************* + //* Step seven: Send to players * + //******************************************* + List chunks = new ArrayList<>(); + for(BlockPosition position : newPositions){ + Chunk chunk = nativeWorld.getChunkAtWorldCoords(position); + if(!chunks.contains(chunk)){ + chunks.add(chunk); + } + } + for(BlockPosition position : deletePositions){ + Chunk chunk = nativeWorld.getChunkAtWorldCoords(position); + if(!chunks.contains(chunk)){ + chunks.add(chunk); + } + } + //sendToPlayers(chunks.toArray(new Chunk[0])); + } + + @Nullable + private TileEntity removeTileEntity(@NotNull World world, @NotNull BlockPosition position){ + TileEntity tile = world.getTileEntity(position); + if(tile == null) + return null; + //cleanup + world.capturedTileEntities.remove(position); + world.getChunkAtWorldCoords(position).getTileEntities().remove(position); + if(!Settings.IsPaper) + world.tileEntityList.remove(tile); + world.tileEntityListTick.remove(tile); + if(!bMap.containsKey(world)){ + try { + Field bField = World.class.getDeclaredField("b"); + bField.setAccessible(true); + bMap.put(world, (List) bField.get(world)); + } catch (IllegalAccessException | IllegalArgumentException | NoSuchFieldException | SecurityException e1) { + e1.printStackTrace(); + } + } + bMap.get(world).remove(tile); + return tile; + } + + @NotNull + private BlockPosition locationToPosition(@NotNull MovecraftLocation loc) { + return new BlockPosition(loc.getX(), loc.getY(), loc.getZ()); + } + + private void setBlockFast(@NotNull World world, @NotNull BlockPosition position,@NotNull IBlockData data) { + Chunk chunk = world.getChunkAtWorldCoords(position); + ChunkSection chunkSection = chunk.getSections()[position.getY()>>4]; + if (chunkSection == null) { + // Put a GLASS block to initialize the section. It will be replaced next with the real block. + chunk.a(position, (TileEntity) Blocks.GLASS.getBlockData()); + chunkSection = chunk.getSections()[position.getY() >> 4]; + } + + chunkSection.setType(position.getX()&15, position.getY()&15, position.getZ()&15, data); + } + + @Override + public void setBlockFast(@NotNull Location location, @NotNull Material material, byte data){ + setBlockFast(location, Rotation.NONE, material, data); + } + + @Override + public void setBlockFast(@NotNull Location location, @NotNull Rotation rotation, @NotNull Material material, byte data) { + IBlockData blockData = CraftMagicNumbers.getBlock(material).getBlockData(); + blockData = blockData.a(ROTATION[rotation.ordinal()]); + World world = ((CraftWorld)(location.getWorld())).getHandle(); + BlockPosition blockPosition = locationToPosition(bukkit2MovecraftLoc(location)); + setBlockFast(world,blockPosition,blockData); + } + + @Override + public void disableShadow(@NotNull Material type) { + Method method; + try { + Block tempBlock = CraftMagicNumbers.getBlock(type); + method = Block.class.getDeclaredMethod("d", int.class); + method.setAccessible(true); + method.invoke(tempBlock, 0); + } catch (NoSuchMethodException | InvocationTargetException | IllegalArgumentException | IllegalAccessException | SecurityException e1) { + // TODO Auto-generated catch block + e1.printStackTrace(); + } + } + + private static MovecraftLocation bukkit2MovecraftLoc(Location l) { + return new MovecraftLocation(l.getBlockX(), l.getBlockY(), l.getBlockZ()); + } + + private void moveTileEntity(@NotNull World nativeWorld, @NotNull BlockPosition newPosition, @NotNull TileEntity tile){ + Chunk chunk = nativeWorld.getChunkAtWorldCoords(newPosition); + tile.invalidateBlockCache(); + if(nativeWorld.captureBlockStates) { + tile.setWorld(nativeWorld); + tile.setPosition(newPosition); + nativeWorld.capturedTileEntities.put(newPosition, tile); + return; + } + tile.setPosition(newPosition); + chunk.tileEntities.put(newPosition, tile); + } + + private class TileHolder{ + @NotNull private final TileEntity tile; + @Nullable + private final NextTickListEntry nextTick; + @NotNull private final BlockPosition tilePosition; + + public TileHolder(@NotNull TileEntity tile, @Nullable NextTickListEntry nextTick, @NotNull BlockPosition tilePosition){ + this.tile = tile; + this.nextTick = nextTick; + this.tilePosition = tilePosition; + } + + + @NotNull + public TileEntity getTile() { + return tile; + } + + @Nullable + public NextTickListEntry getNextTick() { + return nextTick; + } + + @NotNull + public BlockPosition getTilePosition() { + return tilePosition; + } + } +} diff --git a/modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/NextTickProvider.java b/modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/NextTickProvider.java new file mode 100644 index 000000000..94867d6d2 --- /dev/null +++ b/modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/NextTickProvider.java @@ -0,0 +1,67 @@ +package net.countercraft.movecraft.compat.v1_13_R2; + +import net.minecraft.server.v1_13_R2.BlockPosition; +import net.minecraft.server.v1_13_R2.NextTickListEntry; +import net.minecraft.server.v1_13_R2.WorldServer; +import org.apache.commons.lang3.tuple.ImmutablePair; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import org.bukkit.craftbukkit.v1_13_R2.util.HashTreeSet; + +import java.lang.reflect.Field; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; + +public class NextTickProvider { + private Map,List>> tickMap = new HashMap<>(); + + private boolean isRegistered(@NotNull WorldServer world){ + return tickMap.containsKey(world); + } + + @SuppressWarnings("unchecked") + private void registerWorld(@NotNull WorldServer world){ + List W = new ArrayList<>(); + HashTreeSet nextTickList = new HashTreeSet<>(); + + try { + + Field WField = WorldServer.class.getDeclaredField("W"); + WField.setAccessible(true); + W = (List) WField.get(world); + Field nextTickListField = WorldServer.class.getDeclaredField("nextTickList"); + nextTickListField.setAccessible(true); + nextTickList = (HashTreeSet) nextTickListField.get(world); + } catch (IllegalAccessException | IllegalArgumentException | NoSuchFieldException | SecurityException e1) { + e1.printStackTrace(); + } + tickMap.put(world, new ImmutablePair<>(nextTickList,W)); + } + + @Nullable + public NextTickListEntry getNextTick(@NotNull WorldServer world,@NotNull BlockPosition position){ + if(!isRegistered(world)) + registerWorld(world); + ImmutablePair, List> listPair = tickMap.get(world); + for(Iterator iterator = listPair.left.iterator(); iterator.hasNext();) { + NextTickListEntry listEntry = iterator.next(); + if (position.equals(listEntry.a)) { + iterator.remove(); + return listEntry; + } + } + for(Iterator iterator = listPair.right.iterator(); iterator.hasNext();) { + NextTickListEntry listEntry = iterator.next(); + if (position.equals(listEntry.a)) { + iterator.remove(); + return listEntry; + } + } + return null; + + } +} From 6c0b8d9dd46aadc5ae16fc3cd2c5f36261856fcb Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Tue, 8 Jan 2019 13:28:12 +0100 Subject: [PATCH 004/304] More phasing out numerical IDs, bug fixes on translation and begun implementing custom fuel types --- modules/Movecraft/pom.xml | 5 + .../async/detection/DetectionTask.java | 8 +- .../async/translation/TranslationTask.java | 108 ++++++++++++------ .../movecraft/listener/BlockListener.java | 30 +++-- .../update/EntityUpdateCommand.java | 11 +- .../countercraft/movecraft/sign/NameSign.java | 4 + .../worldguard/WorldGuard700Compat.java | 7 ++ .../worldguard/WorldGuardCompatManager.java | 31 ++++- .../movecraft/config/Settings.java | 2 + .../countercraft/movecraft/craft/Craft.java | 25 ++-- .../movecraft/craft/CraftType.java | 8 +- .../movecraft/utils/LegacyUtils.java | 99 ++++++++-------- modules/v1_12_R1/pom.xml | 1 - modules/v1_13_R2/pom.xml | 7 +- .../compat/v1_13_R2/IWorldHandler.java | 9 +- .../compat/v1_13_R2/NextTickProvider.java | 24 ++-- pom.xml | 2 +- 17 files changed, 234 insertions(+), 147 deletions(-) create mode 100644 modules/Movecraft/src/main/java/net/countercraft/movecraft/worldguard/WorldGuard700Compat.java diff --git a/modules/Movecraft/pom.xml b/modules/Movecraft/pom.xml index 88cf9644b..91276bf26 100644 --- a/modules/Movecraft/pom.xml +++ b/modules/Movecraft/pom.xml @@ -71,6 +71,11 @@ worldguard LATEST + + com.sk89q.worldguard + worldguard-core + 7.0.0-SNAPSHOT + com.sk89q worldedit diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/detection/DetectionTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/detection/DetectionTask.java index ee2135144..74def17be 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/detection/DetectionTask.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/detection/DetectionTask.java @@ -18,6 +18,7 @@ package net.countercraft.movecraft.async.detection; +import net.countercraft.movecraft.Movecraft; import net.countercraft.movecraft.MovecraftLocation; import net.countercraft.movecraft.async.AsyncTask; import net.countercraft.movecraft.config.Settings; @@ -70,6 +71,7 @@ public void execute() { detectSurrounding(blockStack.pop()); } while (!blockStack.isEmpty()); if (data.failed()) { + Movecraft.getInstance().getLogger().info("failed"); return; } if (getCraft().getType().getDynamicFlyBlockSpeedFactor() != 0.0) { @@ -100,7 +102,6 @@ private void detectBlock(int x, int y, int z) { if (notVisited(workingLocation, visited)) { Material testType = null; - int testID = 0; int testData = 0; try { testData = data.getWorld().getBlockAt(x, y, z).getData(); @@ -135,9 +136,6 @@ private void detectBlock(int x, int y, int z) { "Detection - Forbidden sign string found")); } } - if (s.getLine(0).equalsIgnoreCase("Name:") && !craft.getType().getCanBeNamed()){ - fail("This craft type cannot be named"); - } } } if (isForbiddenBlock(testType, testData)) { @@ -195,9 +193,7 @@ private void detectBlock(int x, int y, int z) { addToBlockList(workingLocation); Material blockType = testType; - int blockID = testID; int dataID = testData; - Integer shiftedID = (blockID << 4) + dataID + 10000; for (Map> flyBlockDef : dFlyBlocks.keySet()) { if ((flyBlockDef.containsKey(blockType) && flyBlockDef.get(blockType).isEmpty()) || (flyBlockDef.containsKey(blockType) && flyBlockDef.get(blockType).contains(dataID))) { addToBlockCount(flyBlockDef); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java index 844fc5d35..bdfcdb3bc 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java @@ -18,7 +18,9 @@ import org.bukkit.Material; import org.bukkit.Sound; import org.bukkit.block.Block; +import org.bukkit.block.BlockState; import org.bukkit.block.Chest; +import org.bukkit.block.Furnace; import org.bukkit.entity.Entity; import org.bukkit.entity.EntityType; import org.bukkit.entity.Player; @@ -31,9 +33,10 @@ import java.util.concurrent.ThreadLocalRandom; public class TranslationTask extends AsyncTask { - private static final Material[] FALL_THROUGH_BLOCKS = {Material.AIR, Material.WATER, LegacyUtils.STATIONARY_WATER, Material.LAVA, LegacyUtils.STATIONARY_LAVA, LegacyUtils.LONG_GRASS, LegacyUtils.YELLOW_FLOWER, LegacyUtils.RED_ROSE, + private static final Material[] FALL_THROUGH_BLOCKS = Settings.IsLegacy ? new Material[]{Material.AIR, Material.WATER, LegacyUtils.STATIONARY_WATER, Material.LAVA, LegacyUtils.STATIONARY_LAVA, LegacyUtils.LONG_GRASS, LegacyUtils.YELLOW_FLOWER, LegacyUtils.RED_ROSE, Material.BROWN_MUSHROOM, Material.RED_MUSHROOM, Material.TORCH, Material.FIRE, Material.REDSTONE_WIRE, LegacyUtils.CROPS, LegacyUtils.SIGN_POST, Material.LADDER, Material.WALL_SIGN, Material.LEVER, LegacyUtils.STONE_PLATE, LegacyUtils.REDSTONE_TORCH_ON, LegacyUtils.REDSTONE_TORCH_OFF, Material.STONE_BUTTON, - Material.SNOW, LegacyUtils.SUGAR_CANE_BLOCK, LegacyUtils.FENCE, LegacyUtils.DIODE_BLOCK_OFF, LegacyUtils.DIODE_BLOCK_ON, LegacyUtils.WATER_LILY, Material.CARROT, Material.POTATO, LegacyUtils.WOOD_BUTTON, LegacyUtils.CARPET}; + Material.SNOW, LegacyUtils.SUGAR_CANE_BLOCK, LegacyUtils.FENCE, LegacyUtils.DIODE_BLOCK_OFF, LegacyUtils.DIODE_BLOCK_ON, LegacyUtils.WATER_LILY, Material.CARROT, Material.POTATO, LegacyUtils.WOOD_BUTTON, LegacyUtils.CARPET} + : new Material[]{Material.AIR, Material.WATER}; //private static final int[] FALL_THROUGH_BLOCKS = {0, 8, 9, 10, 11, 31, 37, 38, 39, 40, 50, 51, 55, 59, 63, 65, 68, 69, 70, 72, 75, 76, 77, 78, 83, 85, 93, 94, 111, 141, 142, 143, 171}; private int dx, dy, dz; @@ -114,18 +117,6 @@ protected void execute() { return; } - if (Movecraft.getInstance().getWorldGuardPlugin() != null ){ - - } - - if (Movecraft.getInstance().getFactionsPlugin() != null){ - - } - - if (Movecraft.getInstance().getTownyPlugin() != null){ - - } - boolean blockObstructed; if (craft.getSinking()) { blockObstructed = !(Arrays.binarySearch(FALL_THROUGH_BLOCKS, testMaterial) >= 0); @@ -133,8 +124,7 @@ protected void execute() { if (Settings.IsLegacy) { blockObstructed = !craft.getType().getPassthroughBlocks().contains(testMaterial) && !testMaterial.equals(Material.AIR); } else { //1.13 has more than just one air type - blockObstructed = !craft.getType().getPassthroughBlocks().contains(testMaterial) && !testMaterial.equals(Material.AIR) || - !testMaterial.equals(Material.CAVE_AIR) || !testMaterial.equals(Material.VOID_AIR); + blockObstructed = !craft.getType().getPassthroughBlocks().contains(testMaterial) && (!testMaterial.toString().endsWith("AIR")); } } @@ -392,12 +382,18 @@ private boolean checkFuel(){ for (MovecraftLocation bTest : oldHitBox) { Block b = craft.getW().getBlockAt(bTest.getX(), bTest.getY(), bTest.getZ()); if (b.getType() == Material.FURNACE) { - InventoryHolder inventoryHolder = (InventoryHolder) b.getState(); - if ((!Settings.IsLegacy ? (inventoryHolder.getInventory().contains(Material.COAL) || - inventoryHolder.getInventory().contains(Material.CHARCOAL)) - : (inventoryHolder.getInventory().contains(Material.COAL)) || - inventoryHolder.getInventory().contains(Material.COAL_BLOCK))) { - fuelHolder = b; + if (Settings.IsLegacy) { + InventoryHolder inventoryHolder = (InventoryHolder) b.getState(); + if (inventoryHolder.getInventory().contains(Material.COAL)|| inventoryHolder.getInventory().contains(Material.COAL_BLOCK)) { + fuelHolder = b; + } + } else { + if (b.getState() instanceof Furnace) { + Furnace furnace = (Furnace) b.getState(); + if (furnace.getInventory().contains(Material.COAL) || furnace.getInventory().contains(Material.COAL_BLOCK) || furnace.getInventory().contains(Material.CHARCOAL)) { + fuelHolder = b; + } + } } } } @@ -405,25 +401,63 @@ private boolean checkFuel(){ fail(I18nSupport.getInternationalisedString("Translation - Failed Craft out of fuel")); return false; } - InventoryHolder inventoryHolder = (InventoryHolder) fuelHolder.getState(); - if (inventoryHolder.getInventory().contains(Material.COAL)) { - ItemStack iStack = inventoryHolder.getInventory().getItem(inventoryHolder.getInventory().first(Material.COAL)); - int amount = iStack.getAmount(); - if (amount == 1) { - inventoryHolder.getInventory().remove(iStack); + if (Settings.IsLegacy) { + InventoryHolder inventoryHolder = (InventoryHolder) fuelHolder.getState(); + if (inventoryHolder.getInventory().contains(Material.COAL)) { + ItemStack iStack = inventoryHolder.getInventory().getItem(inventoryHolder.getInventory().first(Material.COAL)); + int amount = iStack.getAmount(); + if (amount == 1) { + inventoryHolder.getInventory().remove(iStack); + } else { + iStack.setAmount(amount - 1); + } + craft.setBurningFuel(craft.getBurningFuel() + 7.0); } else { - iStack.setAmount(amount - 1); + ItemStack iStack = inventoryHolder.getInventory().getItem(inventoryHolder.getInventory().first(Material.COAL_BLOCK)); + int amount = iStack.getAmount(); + if (amount == 1) { + inventoryHolder.getInventory().remove(iStack); + } else { + iStack.setAmount(amount - 1); + } + craft.setBurningFuel(craft.getBurningFuel() + 79.0); + } - craft.setBurningFuel(craft.getBurningFuel() + 7.0); } else { - ItemStack iStack = inventoryHolder.getInventory().getItem(inventoryHolder.getInventory().first(Material.COAL_BLOCK)); - int amount = iStack.getAmount(); - if (amount == 1) { - inventoryHolder.getInventory().remove(iStack); - } else { - iStack.setAmount(amount - 1); + BlockState state = fuelHolder.getState(); + if (state instanceof Furnace){ + Furnace furnace = (Furnace) state; + if (furnace.getInventory().contains(Material.COAL)){ + ItemStack iStack = furnace.getInventory().getItem(furnace.getInventory().first(Material.COAL)); + int amount = iStack.getAmount(); + if (amount == 1) { + furnace.getInventory().remove(iStack); + } else { + iStack.setAmount(amount - 1); + } + craft.setBurningFuel(craft.getBurningFuel() + 7.0); + } + if (furnace.getInventory().contains(Material.CHARCOAL)){ + ItemStack iStack = furnace.getInventory().getItem(furnace.getInventory().first(Material.CHARCOAL)); + int amount = iStack.getAmount(); + if (amount == 1) { + furnace.getInventory().remove(iStack); + } else { + iStack.setAmount(amount - 1); + } + craft.setBurningFuel(craft.getBurningFuel() + 7.0); + } + if (furnace.getInventory().contains(Material.COAL_BLOCK)){ + ItemStack iStack = furnace.getInventory().getItem(furnace.getInventory().first(Material.COAL_BLOCK)); + int amount = iStack.getAmount(); + if (amount == 1) { + furnace.getInventory().remove(iStack); + } else { + iStack.setAmount(amount - 1); + } + craft.setBurningFuel(craft.getBurningFuel() + 79.0); + } } - craft.setBurningFuel(craft.getBurningFuel() + 79.0); } return true; diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/BlockListener.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/BlockListener.java index bbb5fe25f..c595a0707 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/BlockListener.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/BlockListener.java @@ -165,13 +165,22 @@ public void onRedstoneEvent(BlockRedstoneEvent event) { CraftManager.getInstance().getCraftsInWorld(block.getWorld()); for (Craft tcraft : CraftManager.getInstance().getCraftsInWorld(block.getWorld())) { MovecraftLocation mloc = new MovecraftLocation(block.getX(), block.getY(), block.getZ()); - if (MathUtils.locIsNearCraftFast(tcraft, mloc) && - tcraft.getCruising() && (block.getType() == LegacyUtils.PISTON_STICKY_BASE || - block.getType() == LegacyUtils.PISTON_BASE || block.getType() == Material.DISPENSER || block.getType() == Material.PISTON || - block.getType() == Material.STICKY_PISTON && - !tcraft.isNotProcessing())) { - event.setNewCurrent(event.getOldCurrent()); // don't allow piston movement on cruising crafts - return; + if (Settings.IsLegacy) { + if (MathUtils.locIsNearCraftFast(tcraft, mloc) && + tcraft.getCruising() && (block.getType() == LegacyUtils.PISTON_STICKY_BASE || + block.getType() == LegacyUtils.PISTON_BASE || block.getType() == Material.DISPENSER && + !tcraft.isNotProcessing())) { + event.setNewCurrent(event.getOldCurrent()); // don't allow piston movement on cruising crafts + return; + } + } else { + if (MathUtils.locIsNearCraftFast(tcraft, mloc) && + tcraft.getCruising() && (block.getType() == Material.STICKY_PISTON || + block.getType() == Material.PISTON || block.getType() == Material.DISPENSER && + !tcraft.isNotProcessing())) { + event.setNewCurrent(event.getOldCurrent()); // don't allow piston movement on cruising crafts + return; + } } } } @@ -216,8 +225,9 @@ public void onPhysics(BlockPhysicsEvent event) { Block block = event.getBlock(); - final Material[] legacyFragileBlocks = new Material[]{LegacyUtils.BED_BLOCK, LegacyUtils.PISTON_EXTENSION, Material.TORCH, Material.REDSTONE_WIRE, LegacyUtils.SIGN_POST, LegacyUtils.WOOD_DOOR, Material.LADDER, Material.WALL_SIGN, Material.LEVER, LegacyUtils.STONE_PLATE, LegacyUtils.IRON_DOOR_BLOCK, LegacyUtils.WOOD_PLATE, LegacyUtils.REDSTONE_TORCH_OFF, LegacyUtils.REDSTONE_TORCH_ON, Material.STONE_BUTTON, LegacyUtils.DIODE_BLOCK_OFF, LegacyUtils.DIODE_BLOCK_ON, LegacyUtils.TRAP_DOOR, Material.TRIPWIRE_HOOK, - Material.TRIPWIRE, LegacyUtils.WOOD_BUTTON, LegacyUtils.GOLD_PLATE, LegacyUtils.IRON_PLATE, LegacyUtils.REDSTONE_COMPARATOR_OFF, LegacyUtils.REDSTONE_COMPARATOR_ON, Material.DAYLIGHT_DETECTOR, LegacyUtils.CARPET, LegacyUtils.DAYLIGHT_DETECTOR_INVERTED, Material.SPRUCE_DOOR, Material.BIRCH_DOOR, Material.JUNGLE_DOOR, Material.ACACIA_DOOR, Material.DARK_OAK_DOOR}; + final Material[] fragileBlocks = Settings.IsLegacy ? new Material[]{LegacyUtils.BED_BLOCK, LegacyUtils.PISTON_EXTENSION, Material.TORCH, Material.REDSTONE_WIRE, LegacyUtils.SIGN_POST, LegacyUtils.WOOD_DOOR, Material.LADDER, Material.WALL_SIGN, Material.LEVER, LegacyUtils.STONE_PLATE, LegacyUtils.IRON_DOOR_BLOCK, LegacyUtils.WOOD_PLATE, LegacyUtils.REDSTONE_TORCH_OFF, LegacyUtils.REDSTONE_TORCH_ON, Material.STONE_BUTTON, LegacyUtils.DIODE_BLOCK_OFF, LegacyUtils.DIODE_BLOCK_ON, LegacyUtils.TRAP_DOOR, Material.TRIPWIRE_HOOK, + Material.TRIPWIRE, LegacyUtils.WOOD_BUTTON, LegacyUtils.GOLD_PLATE, LegacyUtils.IRON_PLATE, LegacyUtils.REDSTONE_COMPARATOR_OFF, LegacyUtils.REDSTONE_COMPARATOR_ON, Material.DAYLIGHT_DETECTOR, LegacyUtils.CARPET, LegacyUtils.DAYLIGHT_DETECTOR_INVERTED, Material.SPRUCE_DOOR, Material.BIRCH_DOOR, Material.JUNGLE_DOOR, Material.ACACIA_DOOR, Material.DARK_OAK_DOOR} + : null; CraftManager.getInstance().getCraftsInWorld(block.getWorld()); for (Craft tcraft : CraftManager.getInstance().getCraftsInWorld(block.getWorld())) { MovecraftLocation mloc = new MovecraftLocation(block.getX(), block.getY(), block.getZ()); @@ -226,7 +236,7 @@ public void onPhysics(BlockPhysicsEvent event) { } if (Settings.IsLegacy) { - if (Arrays.binarySearch(legacyFragileBlocks, block.getType()) >= 0) { + if (Arrays.binarySearch(fragileBlocks, block.getType()) >= 0) { MaterialData m = block.getState().getData(); BlockFace face = BlockFace.DOWN; boolean faceAlwaysDown = false; diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/EntityUpdateCommand.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/EntityUpdateCommand.java index 6e93fea47..3b3d391d7 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/EntityUpdateCommand.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/EntityUpdateCommand.java @@ -50,12 +50,11 @@ public Entity getEntity() { @Override public void doUpdate() { - if (!(entity instanceof Player)) { - Location playerLoc = entity.getLocation(); - entity.teleport(new Location(entity.getWorld(), x + playerLoc.getX(),y + playerLoc.getY(),z + playerLoc.getZ(),yaw + playerLoc.getYaw(),pitch + playerLoc.getPitch())); - return; - } - Movecraft.getInstance().getWorldHandler().addPlayerLocation((Player) entity,x,y,z,yaw,pitch); + + Location playerLoc = entity.getLocation(); + entity.teleport(new Location(entity.getWorld(), x + playerLoc.getX(),y + playerLoc.getY(),z + playerLoc.getZ(),yaw + playerLoc.getYaw(),pitch + playerLoc.getPitch())); + + } @Override diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/NameSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/NameSign.java index 692859193..d34fcdf4e 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/NameSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/NameSign.java @@ -27,6 +27,10 @@ public void onCraftDetect(@NotNull CraftDetectEvent event){ Sign s = (Sign) b.getState(); String name = ""; if (s.getLine(0).equalsIgnoreCase(HEADER)){ + if (!c.getType().getCanBeNamed()){ + c.getNotificationPlayer().sendMessage("Warning: Name: sign was found on the craft, but the craft type used (" + c.getType().getCraftName() + ") is unnameable"); + return; + } if (s.getLine(1) != null){ name += s.getLine(1) + " "; //reserved for prefix (HMA, SS, MS, USS, HMS, etc...) } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/worldguard/WorldGuard700Compat.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/worldguard/WorldGuard700Compat.java new file mode 100644 index 000000000..40202ae05 --- /dev/null +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/worldguard/WorldGuard700Compat.java @@ -0,0 +1,7 @@ +package net.countercraft.movecraft.worldguard; + +import com.sk89q.worldguard.bukkit.RegionQuery; + +public class WorldGuard700Compat { + +} diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/worldguard/WorldGuardCompatManager.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/worldguard/WorldGuardCompatManager.java index d152f4794..0d99259dc 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/worldguard/WorldGuardCompatManager.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/worldguard/WorldGuardCompatManager.java @@ -1,11 +1,21 @@ package net.countercraft.movecraft.worldguard; +import com.sk89q.minecraft.util.commands.CommandException; +import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter; +import com.sk89q.worldedit.extension.platform.Actor; +import com.sk89q.worldedit.util.Location; +import com.sk89q.worldguard.LocalPlayer; +import com.sk89q.worldguard.WorldGuard; +import com.sk89q.worldguard.protection.flags.StateFlag; +import com.sk89q.worldguard.protection.regions.RegionQuery; import net.countercraft.movecraft.Movecraft; import net.countercraft.movecraft.MovecraftLocation; import net.countercraft.movecraft.config.Settings; import net.countercraft.movecraft.events.CraftRotateEvent; import net.countercraft.movecraft.events.CraftTranslateEvent; import net.countercraft.movecraft.localisation.I18nSupport; +import org.bukkit.World; +import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; @@ -22,6 +32,7 @@ public void onCraftTranslateEvent(CraftTranslateEvent event){ event.setFailMessage(String.format( I18nSupport.getInternationalisedString( "Translation - Failed Player is not permitted to build in this WorldGuard region" )+" @ %d,%d,%d", location.getX(), location.getY(), location.getZ() ) ); return; } + } } @@ -32,12 +43,30 @@ public void onCraftRotateEvent(CraftRotateEvent event){ if(event.getCraft().getNotificationPlayer() == null) return; for(MovecraftLocation location : event.getNewHitBox()){ - if(!Movecraft.getInstance().getWorldGuardPlugin().canBuild(event.getCraft().getNotificationPlayer(),location.toBukkit(event.getCraft().getW()))){ + if(!pilotHasAccessToRegion(event.getCraft().getNotificationPlayer(), location, event.getCraft().getW())){ event.setCancelled(true); event.setFailMessage(String.format( I18nSupport.getInternationalisedString("Rotation - Player is not permitted to build in this WorldGuard region" )+" @ %d,%d,%d", location.getX(), location.getY(), location.getZ())); return; } } } + private boolean pilotHasAccessToRegion(Player player, MovecraftLocation location, World world){ + if (Settings.IsLegacy){ + return Movecraft.getInstance().getWorldGuardPlugin().canBuild(player, location.toBukkit(world)); + } else { + RegionQuery query = WorldGuard.getInstance().getPlatform().getRegionContainer().createQuery(); + LocalPlayer lPlayer; + Location wgLoc; + + try { + lPlayer = WorldGuard.getInstance().checkPlayer((Actor) player); + } catch (CommandException e) { + e.printStackTrace(); + lPlayer = null; + } + query.getApplicableRegions(location.toBukkit(world)) + return true; + } + } } diff --git a/modules/api/src/main/java/net/countercraft/movecraft/config/Settings.java b/modules/api/src/main/java/net/countercraft/movecraft/config/Settings.java index e569fb22d..f661e16cf 100644 --- a/modules/api/src/main/java/net/countercraft/movecraft/config/Settings.java +++ b/modules/api/src/main/java/net/countercraft/movecraft/config/Settings.java @@ -20,6 +20,7 @@ import net.countercraft.movecraft.utils.TownyWorldHeightLimits; import org.bukkit.Material; +import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; @@ -83,6 +84,7 @@ public class Settings { public static HashSet AssaultDestroyableBlocks = new HashSet<>(); public static int AssaultDamagesPerBlock; public static HashSet DisableShadowBlocks = new HashSet<>(); + public static Map FuelTypes = new HashMap<>(); public static boolean SiegeEnable; } diff --git a/modules/api/src/main/java/net/countercraft/movecraft/craft/Craft.java b/modules/api/src/main/java/net/countercraft/movecraft/craft/Craft.java index 4075cb6de..3e4867cf1 100644 --- a/modules/api/src/main/java/net/countercraft/movecraft/craft/Craft.java +++ b/modules/api/src/main/java/net/countercraft/movecraft/craft/Craft.java @@ -19,6 +19,7 @@ import net.countercraft.movecraft.MovecraftLocation; import net.countercraft.movecraft.Rotation; +import net.countercraft.movecraft.config.Settings; import net.countercraft.movecraft.events.CraftSinkEvent; import net.countercraft.movecraft.utils.HashHitBox; import net.md_5.bungee.api.ChatMessageType; @@ -368,34 +369,34 @@ public int getWaterLine(){ int posZ; posZ = hitBox.getMinZ() - 1; for (posX = hitBox.getMinX() - 1; posX <= hitBox.getMaxX() + 1; posX++) { - int typeID = w.getBlockAt(posX, posY, posZ).getTypeId(); - if (typeID == 9) + Material type = w.getBlockAt(posX, posY, posZ).getType(); + if (Settings.IsLegacy ? type == Material.STATIONARY_WATER : type == Material.WATER) numWater++; - if (typeID == 0) + if (Settings.IsLegacy ? type == Material.AIR : (type == Material.AIR || type == Material.getMaterial("CAVE_AIR") || type == Material.getMaterial("VOID_AIR"))) numAir++; } posZ = hitBox.getMaxZ() + 1; for (posX = hitBox.getMinX() - 1; posX <= hitBox.getMaxX() + 1; posX++) { - int typeID = w.getBlockAt(posX, posY, posZ).getTypeId(); - if (typeID == 9) + Material type = w.getBlockAt(posX, posY, posZ).getType(); + if (Settings.IsLegacy ? type == Material.STATIONARY_WATER : type == Material.WATER) numWater++; - if (typeID == 0) + if (Settings.IsLegacy ? type == Material.AIR : (type == Material.AIR || type == Material.getMaterial("CAVE_AIR") || type == Material.getMaterial("VOID_AIR"))) numAir++; } posX = hitBox.getMinX() - 1; for (posZ = hitBox.getMinZ(); posZ <= hitBox.getMaxZ(); posZ++) { - int typeID = w.getBlockAt(posX, posY, posZ).getTypeId(); - if (typeID == 9) + Material type = w.getBlockAt(posX, posY, posZ).getType(); + if (Settings.IsLegacy ? type == Material.STATIONARY_WATER : type == Material.WATER) numWater++; - if (typeID == 0) + if (Settings.IsLegacy ? type == Material.AIR : (type == Material.AIR || type == Material.getMaterial("CAVE_AIR") || type == Material.getMaterial("VOID_AIR"))) numAir++; } posX = hitBox.getMaxX() + 1; for (posZ = hitBox.getMinZ(); posZ <= hitBox.getMaxZ(); posZ++) { - int typeID = w.getBlockAt(posX, posY, posZ).getTypeId(); - if (typeID == 9) + Material type = w.getBlockAt(posX, posY, posZ).getType(); + if (Settings.IsLegacy ? type == Material.STATIONARY_WATER : type == Material.WATER) numWater++; - if (typeID == 0) + if (Settings.IsLegacy ? type == Material.AIR : (type == Material.AIR || type == Material.getMaterial("CAVE_AIR") || type == Material.getMaterial("VOID_AIR"))) numAir++; } if (numWater > numAir) { diff --git a/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java b/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java index 30a027d92..e778f976d 100644 --- a/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java +++ b/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java @@ -401,8 +401,7 @@ public CraftType(File f) { } } if(!blockedByWater){ - passthroughBlocks.add(Material.WATER); - passthroughBlocks.add(Material.STATIONARY_WATER); + passthroughBlocks.add(Settings.IsLegacy ? Material.STATIONARY_WATER : Material.WATER); } if (data.containsKey("allowVerticalTakeoffAndLanding")) { allowVerticalTakeoffAndLanding = (Boolean) data.get("allowVerticalTakeoffAndLanding"); @@ -501,6 +500,9 @@ private Map> materialMapFromObject(Object obj){ } else { returnMap.put(type, new ArrayList<>(data)); } + } else { + Material type = Material.getMaterial(string); + returnMap.put(type,new ArrayList<>()); } } else { Material type = (Material) o; @@ -622,7 +624,7 @@ private Map>, List> materialMapListFromObjec } } else if (i instanceof Integer) { Integer typeID = (Integer) i; - Material type = Material.getMaterial(typeID); + Material type = Settings.IsLegacy ? Material.getMaterial(typeID) : null; materialMap.put(type, new ArrayList<>()); } else if (i instanceof String) { String string = (String) i; diff --git a/modules/api/src/main/java/net/countercraft/movecraft/utils/LegacyUtils.java b/modules/api/src/main/java/net/countercraft/movecraft/utils/LegacyUtils.java index a2dc84cc9..934eb0725 100644 --- a/modules/api/src/main/java/net/countercraft/movecraft/utils/LegacyUtils.java +++ b/modules/api/src/main/java/net/countercraft/movecraft/utils/LegacyUtils.java @@ -1,5 +1,6 @@ package net.countercraft.movecraft.utils; +import net.countercraft.movecraft.config.Settings; import org.bukkit.Material; import org.bukkit.Sound; import org.bukkit.block.Block; @@ -7,57 +8,57 @@ public class LegacyUtils { //Materials removed in 1.13 - public static Material BED_BLOCK = Material.BED_BLOCK; - public static Material CARPET = Material.CARPET; - public static Material CROPS = Material.CROPS; - public static Material DAYLIGHT_DETECTOR_INVERTED = Material.DAYLIGHT_DETECTOR_INVERTED; - public static Material DIODE = Material.DIODE; - public static Material DIODE_BLOCK_OFF = Material.DIODE_BLOCK_OFF; - public static Material DIODE_BLOCK_ON = Material.DIODE_BLOCK_ON; - public static Material DOUBLE_PLANT = Material.DOUBLE_PLANT; - public static Material FENCE = Material.FENCE; - public static Material FIREBALL = Material.FIREBALL; - public static Material GOLD_PLATE = Material.GOLD_PLATE; - public static Material IRON_DOOR_BLOCK = Material.IRON_DOOR_BLOCK; - public static Material IRON_FENCE = Material.IRON_FENCE; - public static Material IRON_PLATE = Material.IRON_PLATE; - public static Material LEAVES = Material.LEAVES; - public static Material LEAVES_2 = Material.LEAVES_2; - public static Material LOG = Material.LOG; - public static Material LOG_2 = Material.LOG_2; - public static Material LONG_GRASS = Material.LONG_GRASS; - public static Material PISTON_BASE = Material.PISTON_BASE; - public static Material PISTON_EXTENSION = Material.PISTON_EXTENSION; - public static Material PISTON_STICKY_BASE = Material.PISTON_STICKY_BASE; - public static Material RED_ROSE = Material.RED_ROSE; - public static Material REDSTONE_COMPARATOR = Material.REDSTONE_COMPARATOR; - public static Material REDSTONE_COMPARATOR_OFF = Material.REDSTONE_COMPARATOR_OFF; - public static Material REDSTONE_COMPARATOR_ON = Material.REDSTONE_COMPARATOR_ON; - public static Material REDSTONE_TORCH_ON = Material.REDSTONE_TORCH_ON; - public static Material REDSTONE_TORCH_OFF = Material.REDSTONE_TORCH_OFF; - public static Material SEEDS = Material.SEEDS; - public static Material SMOOTH_STAIRS = Material.SMOOTH_STAIRS; - public static Material STAINED_GLASS = Material.STAINED_GLASS; - public static Material STAINED_GLASS_PANE = Material.STAINED_GLASS_PANE; - public static Material STATIONARY_WATER = Material.STATIONARY_WATER; - public static Material STATIONARY_LAVA = Material.STATIONARY_LAVA; - public static Material STEP = Material.STEP; - public static Material STONE_PLATE = Material.STONE_PLATE; - public static Material SIGN_POST = Material.SIGN_POST; - public static Material SUGAR_CANE_BLOCK = Material.SUGAR_CANE_BLOCK; - public static Material THIN_GLASS = Material.THIN_GLASS; - public static Material TRAP_DOOR = Material.TRAP_DOOR; - public static Material WATER_LILY = Material.WATER_LILY; - public static Material WEB = Material.WEB; - public static Material WOOL = Material.WOOL; - public static Material WOOD = Material.WOOD; - public static Material WOOD_BUTTON = Material.WOOD_BUTTON; - public static Material WOOD_DOOR = Material.WOOD_DOOR; - public static Material WOOD_PLATE = Material.WOOD_PLATE; - public static Material YELLOW_FLOWER = Material.YELLOW_FLOWER; + public static Material BED_BLOCK = Settings.IsLegacy ? Material.BED_BLOCK : null; + public static Material CARPET = Settings.IsLegacy ? Material.CARPET : null; + public static Material CROPS = Settings.IsLegacy ? Material.CROPS : null; + public static Material DAYLIGHT_DETECTOR_INVERTED = Settings.IsLegacy ? Material.DAYLIGHT_DETECTOR_INVERTED : null; + public static Material DIODE = Settings.IsLegacy ? Material.DIODE : null; + public static Material DIODE_BLOCK_OFF = Settings.IsLegacy ? Material.DIODE_BLOCK_OFF : null; + public static Material DIODE_BLOCK_ON = Settings.IsLegacy ? Material.DIODE_BLOCK_ON : null; + public static Material DOUBLE_PLANT = Settings.IsLegacy ? Material.DOUBLE_PLANT : null; + public static Material FENCE = Settings.IsLegacy ? Material.FENCE : null; + public static Material FIREBALL = Settings.IsLegacy ? Material.FIREBALL : null; + public static Material GOLD_PLATE = Settings.IsLegacy ? Material.GOLD_PLATE : null; + public static Material IRON_DOOR_BLOCK = Settings.IsLegacy ? Material.IRON_DOOR_BLOCK : null; + public static Material IRON_FENCE = Settings.IsLegacy ? Material.IRON_FENCE : null; + public static Material IRON_PLATE = Settings.IsLegacy ? Material.IRON_PLATE : null; + public static Material LEAVES = Settings.IsLegacy ? Material.LEAVES : null; + public static Material LEAVES_2 = Settings.IsLegacy ? Material.LEAVES_2 : null; + public static Material LOG = Settings.IsLegacy ? Material.LOG : null; + public static Material LOG_2 = Settings.IsLegacy ? Material.LOG_2 : null; + public static Material LONG_GRASS = Settings.IsLegacy ? Material.LONG_GRASS : null; + public static Material PISTON_BASE = Settings.IsLegacy ? Material.PISTON_BASE : null; + public static Material PISTON_EXTENSION = Settings.IsLegacy ? Material.PISTON_EXTENSION : null; + public static Material PISTON_STICKY_BASE = Settings.IsLegacy ? Material.PISTON_STICKY_BASE : null; + public static Material RED_ROSE = Settings.IsLegacy ? Material.RED_ROSE : null; + public static Material REDSTONE_COMPARATOR = Settings.IsLegacy ? Material.REDSTONE_COMPARATOR : null; + public static Material REDSTONE_COMPARATOR_OFF = Settings.IsLegacy ? Material.REDSTONE_COMPARATOR_OFF : null; + public static Material REDSTONE_COMPARATOR_ON = Settings.IsLegacy ? Material.REDSTONE_COMPARATOR_ON : null; + public static Material REDSTONE_TORCH_ON = Settings.IsLegacy ? Material.REDSTONE_TORCH_ON : null; + public static Material REDSTONE_TORCH_OFF = Settings.IsLegacy ? Material.REDSTONE_TORCH_OFF : null; + public static Material SEEDS = Settings.IsLegacy ? Material.SEEDS : null; + public static Material SMOOTH_STAIRS = Settings.IsLegacy ? Material.SMOOTH_STAIRS : null; + public static Material STAINED_GLASS = Settings.IsLegacy ? Material.STAINED_GLASS : null; + public static Material STAINED_GLASS_PANE = Settings.IsLegacy ? Material.STAINED_GLASS_PANE : null; + public static Material STATIONARY_WATER = Settings.IsLegacy ? Material.STATIONARY_WATER : null; + public static Material STATIONARY_LAVA = Settings.IsLegacy ? Material.STATIONARY_LAVA : null; + public static Material STEP = Settings.IsLegacy ? Material.STEP : null; + public static Material STONE_PLATE = Settings.IsLegacy ? Material.STONE_PLATE : null; + public static Material SIGN_POST = Settings.IsLegacy ? Material.SIGN_POST : null; + public static Material SUGAR_CANE_BLOCK = Settings.IsLegacy ? Material.SUGAR_CANE_BLOCK : null; + public static Material THIN_GLASS = Settings.IsLegacy ? Material.THIN_GLASS : null; + public static Material TRAP_DOOR = Settings.IsLegacy ? Material.TRAP_DOOR : null; + public static Material WATER_LILY = Settings.IsLegacy ? Material.WATER_LILY : null; + public static Material WEB = Settings.IsLegacy ? Material.WEB : null; + public static Material WOOL = Settings.IsLegacy ? Material.WOOL : null; + public static Material WOOD = Settings.IsLegacy ? Material.WOOD : null; + public static Material WOOD_BUTTON = Settings.IsLegacy ? Material.WOOD_BUTTON : null; + public static Material WOOD_DOOR = Settings.IsLegacy ? Material.WOOD_DOOR : null; + public static Material WOOD_PLATE = Settings.IsLegacy ? Material.WOOD_PLATE : null; + public static Material YELLOW_FLOWER = Settings.IsLegacy ? Material.YELLOW_FLOWER : null; //Sounds removed in 1.13 - public static Sound ENITIY_IRONGOLEM_DEATH = Sound.ENTITY_IRONGOLEM_DEATH; + public static Sound ENITIY_IRONGOLEM_DEATH = Settings.IsLegacy ? Sound.ENTITY_IRONGOLEM_DEATH : null; //Methods removed in 1.13 public static Material getMaterial(int id){ try { diff --git a/modules/v1_12_R1/pom.xml b/modules/v1_12_R1/pom.xml index e428473e6..d4ea08821 100644 --- a/modules/v1_12_R1/pom.xml +++ b/modules/v1_12_R1/pom.xml @@ -11,7 +11,6 @@ UTF-8 - net.countercraft movecraft-parent diff --git a/modules/v1_13_R2/pom.xml b/modules/v1_13_R2/pom.xml index 609b224b8..865f19e47 100644 --- a/modules/v1_13_R2/pom.xml +++ b/modules/v1_13_R2/pom.xml @@ -3,7 +3,6 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 - net.countercraft movecraft-v1_13_R2 jar Movecraft-v1_13_R2 @@ -13,12 +12,14 @@ UTF-8 + net.countercraft movecraft-parent parent ../../ + sk89q-repo @@ -57,7 +58,7 @@ 3.7.0 - net/countercraft/movecraft/compat/v1_12_R1/** + net/countercraft/movecraft/compat/v1_13_R2/** 1.8 1.8 @@ -69,7 +70,7 @@ 2.4 - net/countercraft/movecraft/compat/v1_12_R1/** + net/countercraft/movecraft/compat/v1_13_R2/** diff --git a/modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/IWorldHandler.java b/modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/IWorldHandler.java index 001684fac..eb4baab40 100644 --- a/modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/IWorldHandler.java +++ b/modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/IWorldHandler.java @@ -59,7 +59,7 @@ public void addPlayerLocation(Player player, double x, double y, double z, float return; } try { - internalTeleportMH.invoke(ePlayer.playerConnection, x, y, z, yaw, pitch, EnumSet.allOf(PacketPlayOutPosition.EnumPlayerTeleportFlags.class)); + internalTeleportMH.invoke(ePlayer.playerConnection, (player.getLocation().getX() + x), (player.getLocation().getY() + y), (player.getLocation().getZ() + z), yaw, pitch, EnumSet.allOf(PacketPlayOutPosition.EnumPlayerTeleportFlags.class)); } catch (Throwable throwable) { throwable.printStackTrace(); } @@ -276,9 +276,9 @@ private TileEntity removeTileEntity(@NotNull World world, @NotNull BlockPosition world.tileEntityListTick.remove(tile); if(!bMap.containsKey(world)){ try { - Field bField = World.class.getDeclaredField("b"); + Field bField = World.class.getDeclaredField("c"); bField.setAccessible(true); - bMap.put(world, (List) bField.get(world)); + bMap.put(world, (List) bField.get(world));//TODO bug fix } catch (IllegalAccessException | IllegalArgumentException | NoSuchFieldException | SecurityException e1) { e1.printStackTrace(); } @@ -297,8 +297,9 @@ private void setBlockFast(@NotNull World world, @NotNull BlockPosition position, ChunkSection chunkSection = chunk.getSections()[position.getY()>>4]; if (chunkSection == null) { // Put a GLASS block to initialize the section. It will be replaced next with the real block. - chunk.a(position, (TileEntity) Blocks.GLASS.getBlockData()); + chunk.setType(position, Blocks.GLASS.getBlockData(), true); chunkSection = chunk.getSections()[position.getY() >> 4]; + } chunkSection.setType(position.getX()&15, position.getY()&15, position.getZ()&15, data); diff --git a/modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/NextTickProvider.java b/modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/NextTickProvider.java index 94867d6d2..06b2080ec 100644 --- a/modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/NextTickProvider.java +++ b/modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/NextTickProvider.java @@ -1,8 +1,6 @@ package net.countercraft.movecraft.compat.v1_13_R2; -import net.minecraft.server.v1_13_R2.BlockPosition; -import net.minecraft.server.v1_13_R2.NextTickListEntry; -import net.minecraft.server.v1_13_R2.WorldServer; +import net.minecraft.server.v1_13_R2.*; import org.apache.commons.lang3.tuple.ImmutablePair; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -17,7 +15,7 @@ import java.util.Map; public class NextTickProvider { - private Map,List>> tickMap = new HashMap<>(); + private Map,List>>> tickMap = new HashMap<>(); private boolean isRegistered(@NotNull WorldServer world){ return tickMap.containsKey(world); @@ -25,17 +23,15 @@ private boolean isRegistered(@NotNull WorldServer world){ @SuppressWarnings("unchecked") private void registerWorld(@NotNull WorldServer world){ - List W = new ArrayList<>(); + List> W = new ArrayList<>(); HashTreeSet nextTickList = new HashTreeSet<>(); + Chunk chunk = world.getChunkProvider().a().iterator().next(); try { - - Field WField = WorldServer.class.getDeclaredField("W"); - WField.setAccessible(true); - W = (List) WField.get(world); - Field nextTickListField = WorldServer.class.getDeclaredField("nextTickList"); - nextTickListField.setAccessible(true); - nextTickList = (HashTreeSet) nextTickListField.get(world); + W = world.getBlockTickList().a(chunk, false); + Field ntlField = TickListServer.class.getDeclaredField("nextTickList"); + ntlField.setAccessible(true); + ntlField.get(world.getBlockTickList()); } catch (IllegalAccessException | IllegalArgumentException | NoSuchFieldException | SecurityException e1) { e1.printStackTrace(); } @@ -46,7 +42,7 @@ private void registerWorld(@NotNull WorldServer world){ public NextTickListEntry getNextTick(@NotNull WorldServer world,@NotNull BlockPosition position){ if(!isRegistered(world)) registerWorld(world); - ImmutablePair, List> listPair = tickMap.get(world); + ImmutablePair, List>> listPair = tickMap.get(world); for(Iterator iterator = listPair.left.iterator(); iterator.hasNext();) { NextTickListEntry listEntry = iterator.next(); if (position.equals(listEntry.a)) { @@ -54,7 +50,7 @@ public NextTickListEntry getNextTick(@NotNull WorldServer world,@NotNull BlockPo return listEntry; } } - for(Iterator iterator = listPair.right.iterator(); iterator.hasNext();) { + for(Iterator> iterator = listPair.right.iterator(); iterator.hasNext();) { NextTickListEntry listEntry = iterator.next(); if (position.equals(listEntry.a)) { iterator.remove(); diff --git a/pom.xml b/pom.xml index b130f0946..d3b158035 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ org.spigotmc spigot-api - 1.10.2-R0.1-SNAPSHOT + 1.13.2-R0.1-SNAPSHOT Movecraft Parent Pom From 18c0a27731f871926e265675616334bd8e1cd1c1 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Sat, 12 Jan 2019 18:02:05 +0100 Subject: [PATCH 005/304] Implementing commits from APDevTeam repo and adding repair command to manage craft repairs --- .../net/countercraft/movecraft/Movecraft.java | 36 +++-- .../async/translation/TranslationTask.java | 5 + .../movecraft/commands/MovecraftCommand.java | 5 +- .../movecraft/commands/RepairCommand.java | 70 +++++++++ .../FactionsCompatManager.java | 2 +- .../WorldGuardCompatManager.java | 27 ++-- .../movecraft/listener/BlockListener.java | 2 +- .../movecraft/repair/RepairUtils.java | 21 ++- .../movecraft/sign/RemoteSign.java | 67 +++++++-- .../movecraft/sign/RepairSign.java | 3 +- .../movecraft/utils/WorldguardUtils.java | 8 + .../warfare/assault/AssaultTask.java | 88 ++++++----- .../warfare/assault/AssaultUtils.java | 45 ++++-- .../worldguard/WorldGuard700Compat.java | 7 - .../Movecraft/src/main/resources/config.yml | 140 +++++++++--------- .../main/resources/legacyconfig/config.yml | 114 ++++++++++++++ .../movecraft/config/Settings.java | 10 +- 17 files changed, 475 insertions(+), 175 deletions(-) create mode 100644 modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/RepairCommand.java rename modules/Movecraft/src/main/java/net/countercraft/movecraft/{factions => compatmanager}/FactionsCompatManager.java (93%) rename modules/Movecraft/src/main/java/net/countercraft/movecraft/{worldguard => compatmanager}/WorldGuardCompatManager.java (75%) delete mode 100644 modules/Movecraft/src/main/java/net/countercraft/movecraft/worldguard/WorldGuard700Compat.java create mode 100644 modules/Movecraft/src/main/resources/legacyconfig/config.yml diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java index 2cdac94f6..2a5257359 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java @@ -41,7 +41,7 @@ import net.countercraft.movecraft.warfare.assault.AssaultManager; import net.countercraft.movecraft.warfare.siege.Siege; import net.countercraft.movecraft.warfare.siege.SiegeManager; -import net.countercraft.movecraft.worldguard.WorldGuardCompatManager; +import net.countercraft.movecraft.compatmanager.WorldGuardCompatManager; import net.milkbowl.vault.economy.Economy; import org.bukkit.Material; import org.bukkit.plugin.Plugin; @@ -97,8 +97,22 @@ public void onDisable() { @Override public void onEnable() { + String packageName = this.getServer().getClass().getPackage().getName(); + String version = packageName.substring(packageName.lastIndexOf('.') + 1); + String[] parts = version.split("_"); + Integer versionNumber = Integer.valueOf(parts[1]); + //Check if the server is 1.12 and lower or 1.13 and higher + if (versionNumber <= 12){ + Settings.IsLegacy = true; + } else { + Settings.IsLegacy = false; + } // Read in config - this.saveDefaultConfig(); + if (Settings.IsLegacy) { + this.saveDefaultConfig(); + } else { + this.saveResource("legacyconfig/config.yml", false); + } try { Class.forName("com.destroystokyo.paper.Title"); Settings.IsPaper = true; @@ -132,16 +146,7 @@ public void onEnable() { } logger.log(Level.INFO, "CompatiblityMode is set to {0}", Settings.CompatibilityMode);*/ //Switch to interfaces - String packageName = this.getServer().getClass().getPackage().getName(); - String version = packageName.substring(packageName.lastIndexOf('.') + 1); - String[] parts = version.split("_"); - Integer versionNumber = Integer.valueOf(parts[1]); - //Check if the server is 1.12 and lower or 1.13 anf higher - if (versionNumber <= 12){ - Settings.IsLegacy = true; - } else { - Settings.IsLegacy = false; - } + try { final Class clazz = Class.forName("net.countercraft.movecraft.compat." + version + ".IWorldHandler"); // Check if we have a NMSHandler class at that location. @@ -187,7 +192,11 @@ public void onEnable() { Settings.AssaultDuration = getConfig().getInt("AssaultDuration", 1800); Settings.AssaultCostPercent = getConfig().getDouble("AssaultCostPercent", 0.25); Settings.AssaultDamagesPerBlock = getConfig().getInt("AssaultDamagesPerBlock", 15); - Settings.AssaultRequiredDefendersOnline = getConfig().getInt("AssaultRequiredDefendersOnline", 3); + Settings.AssaultRequiredDefendersOnline = getConfig().getInt("AssaultRequiredDefendersOnline", 2); + Settings.AssaultRequiredOwnersOnline = getConfig().getInt("AssaultRequiredOwnersOnline", 1); + Settings.AssaultMaxBalance = getConfig().getDouble("AssaultMaxBalance", 5000000); + Settings.AssaultOwnerWeightPercent = getConfig().getInt("AssaultOwnerWeightPercent", 100); + Settings.AssaultMemberWeightPercent = getConfig().getInt("AssaultMemberWeightPercent", 100); List assaultDestroyableBlocks = getConfig().getStringList("AssaultDestroyableBlocks"); for (String matStr : assaultDestroyableBlocks){ Settings.AssaultDestroyableBlocks.add(Material.getMaterial(matStr)); @@ -197,6 +206,7 @@ public void onEnable() { Settings.DisableShadowBlocks.add(Material.getMaterial(typ)); } Settings.RepairMaxPercent = getConfig().getDouble("RepairMaxPercent", 50.0); + Settings.ForbiddenRemoteSigns = new HashSet<>(getConfig().getStringList("ForbiddenRemoteSigns")); Settings.SiegeEnable = getConfig().getBoolean("SiegeEnable", false); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java index bdfcdb3bc..e61d04d86 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java @@ -62,6 +62,11 @@ protected void execute() { if(oldHitBox.isEmpty()){ return; } + //Prevent disabled crafts from moving + if (getCraft().getDisabled() && (!getCraft().getSinking())) { + fail(I18nSupport.getInternationalisedString("Craft is disabled!")); + return; + } final int minY = oldHitBox.getMinY(); final int maxY = oldHitBox.getMaxY(); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/MovecraftCommand.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/MovecraftCommand.java index bf21a2bfc..27240ce79 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/MovecraftCommand.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/MovecraftCommand.java @@ -1,9 +1,11 @@ package net.countercraft.movecraft.commands; +import net.countercraft.movecraft.Movecraft; import net.countercraft.movecraft.craft.CraftManager; import org.bukkit.command.Command; import org.bukkit.command.CommandSender; import org.bukkit.command.TabExecutor; +import org.bukkit.plugin.PluginDescriptionFile; import java.util.ArrayList; import java.util.Collections; @@ -23,7 +25,8 @@ public boolean onCommand(CommandSender commandSender, Command command, String s, } if(args.length == 0){ - commandSender.sendMessage(MOVECRAFT_COMMAND_PREFIX + "Movecraft 7.0 pre release 5 by cccm5"); + PluginDescriptionFile descriptionFile = Movecraft.getInstance().getDescription(); + commandSender.sendMessage(MOVECRAFT_COMMAND_PREFIX + "Movecraft " + descriptionFile.getVersion() + " by " + descriptionFile.getAuthors()); return true; } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/RepairCommand.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/RepairCommand.java new file mode 100644 index 000000000..39b3f3b12 --- /dev/null +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/RepairCommand.java @@ -0,0 +1,70 @@ +package net.countercraft.movecraft.commands; + +import net.countercraft.movecraft.Movecraft; +import net.countercraft.movecraft.repair.Repair; +import net.countercraft.movecraft.utils.TopicPaginator; +import org.bukkit.Bukkit; +import org.bukkit.command.Command; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; + +import java.util.Collection; + +import static net.countercraft.movecraft.utils.ChatUtils.MOVECRAFT_COMMAND_PREFIX; + +public class RepairCommand implements CommandExecutor { + @Override + public boolean onCommand(CommandSender sender, Command command, String s, String[] args) { + if (!command.getName().equalsIgnoreCase("repair")){ + return false; + } + if (!sender.hasPermission("movecraft.commands.repair")){ + sender.sendMessage(MOVECRAFT_COMMAND_PREFIX + "Error, invalid permissions"); + return true; + } + if (args.length < 1){ + TopicPaginator paginator = new TopicPaginator("Repair"); + paginator.addLine("/repair list [playername:all:you] = Display list of ongoing repairs"); + paginator.addLine("/repair enable = Enables repair functionality."); + paginator.addLine("/repair disable = Disables repair functionality."); + } + + Player player = (Player) sender; + if (args[0].equalsIgnoreCase("list")){ + if (args.length >= 1){ + TopicPaginator paginator = new TopicPaginator(String.format("Repairs by %s", player.getName())); + for (Repair repair : Movecraft.getInstance().getRepairManager().getRepairs()){ + if (repair.getPlayerUUID() == player.getUniqueId()){ + if (repair.getRunning().get()){ + paginator.addLine(String.format("%s - %d/%d", repair.getName(), (repair.getFragileBlockUpdateCommands().size() + repair.getUpdateCommands().size()), repair.getMissingBlocks())); + } + } + } + int page; + try { + if (args.length == 1){ + page = 1; + } else { + page = Integer.parseInt(args[1]); + } + } catch (NumberFormatException e){ + player.sendMessage(MOVECRAFT_COMMAND_PREFIX + "Invalid page " + args[1]); + return true; + } + if (paginator.isEmpty()){ + player.sendMessage(MOVECRAFT_COMMAND_PREFIX + "You have no active repairs."); + return true; + } + for (String line : paginator.getPage(page)){ + player.sendMessage(line); + } + } else if (args[1].equalsIgnoreCase("all")){ + + } else { + + } + } + return false; + } +} diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/factions/FactionsCompatManager.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/compatmanager/FactionsCompatManager.java similarity index 93% rename from modules/Movecraft/src/main/java/net/countercraft/movecraft/factions/FactionsCompatManager.java rename to modules/Movecraft/src/main/java/net/countercraft/movecraft/compatmanager/FactionsCompatManager.java index 92af8331a..3a6b4092b 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/factions/FactionsCompatManager.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/compatmanager/FactionsCompatManager.java @@ -1,4 +1,4 @@ -package net.countercraft.movecraft.factions; +package net.countercraft.movecraft.compatmanager; import com.massivecraft.factions.Factions; import com.massivecraft.factions.entity.MPlayer; diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/worldguard/WorldGuardCompatManager.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/compatmanager/WorldGuardCompatManager.java similarity index 75% rename from modules/Movecraft/src/main/java/net/countercraft/movecraft/worldguard/WorldGuardCompatManager.java rename to modules/Movecraft/src/main/java/net/countercraft/movecraft/compatmanager/WorldGuardCompatManager.java index 0d99259dc..5646950d6 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/worldguard/WorldGuardCompatManager.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/compatmanager/WorldGuardCompatManager.java @@ -1,12 +1,14 @@ -package net.countercraft.movecraft.worldguard; +package net.countercraft.movecraft.compatmanager; import com.sk89q.minecraft.util.commands.CommandException; -import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter; +import com.sk89q.worldedit.bukkit.BukkitWorld; import com.sk89q.worldedit.extension.platform.Actor; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.extent.world.BlockQuirkExtent; +import com.sk89q.worldedit.extent.world.FastModeExtent; import com.sk89q.worldedit.util.Location; import com.sk89q.worldguard.LocalPlayer; import com.sk89q.worldguard.WorldGuard; -import com.sk89q.worldguard.protection.flags.StateFlag; import com.sk89q.worldguard.protection.regions.RegionQuery; import net.countercraft.movecraft.Movecraft; import net.countercraft.movecraft.MovecraftLocation; @@ -14,6 +16,7 @@ import net.countercraft.movecraft.events.CraftRotateEvent; import net.countercraft.movecraft.events.CraftTranslateEvent; import net.countercraft.movecraft.localisation.I18nSupport; +import net.countercraft.movecraft.utils.WorldguardUtils; import org.bukkit.World; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; @@ -52,20 +55,14 @@ public void onCraftRotateEvent(CraftRotateEvent event){ } private boolean pilotHasAccessToRegion(Player player, MovecraftLocation location, World world){ if (Settings.IsLegacy){ - return Movecraft.getInstance().getWorldGuardPlugin().canBuild(player, location.toBukkit(world)); + return WorldguardUtils.canBuild(world, location, player); } else { RegionQuery query = WorldGuard.getInstance().getPlatform().getRegionContainer().createQuery(); - LocalPlayer lPlayer; - Location wgLoc; - - try { - lPlayer = WorldGuard.getInstance().checkPlayer((Actor) player); - } catch (CommandException e) { - e.printStackTrace(); - lPlayer = null; - } - query.getApplicableRegions(location.toBukkit(world)) - return true; + LocalPlayer lPlayer = Movecraft.getInstance().getWorldGuardPlugin().wrapPlayer(player); + Extent ext = new FastModeExtent(new BukkitWorld(world)); + Location wgLoc = new Location(ext, location.getX(), location.getY(), location.getZ()); + return query.getApplicableRegions(wgLoc).isOwnerOfAll(lPlayer) || query.getApplicableRegions(wgLoc).isMemberOfAll(lPlayer) || + player.hasPermission("movecraft.region.bypass"); } } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/BlockListener.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/BlockListener.java index c595a0707..53d583037 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/BlockListener.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/BlockListener.java @@ -276,7 +276,7 @@ public void onBlockIgnite(BlockIgniteEvent event) { if (!testBlock.getType().isBurnable()) { return; } - // check to see if fire spread is allowed, don't check if worldguard integration is not enabled + // check to see if fire spread is allowed, don't check if compatmanager integration is not enabled if (Movecraft.getInstance().getWorldGuardPlugin() != null && (Settings.WorldGuardBlockMoveOnBuildPerm || Settings.WorldGuardBlockSinkOnPVPPerm)) { ApplicableRegionSet set = Movecraft.getInstance().getWorldGuardPlugin().getRegionManager(testBlock.getWorld()).getApplicableRegions(testBlock.getLocation()); if (!set.allows(DefaultFlag.FIRE_SPREAD)) { diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/repair/RepairUtils.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/repair/RepairUtils.java index 77b65848c..3cc1b70c6 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/repair/RepairUtils.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/repair/RepairUtils.java @@ -21,7 +21,14 @@ import java.lang.reflect.Method; public class RepairUtils { - + private static Method GET_BLOCK; + static { + try { + GET_BLOCK = BlockArrayClipboard.class.getDeclaredMethod("getBlock", Vector.class); + } catch (NoSuchMethodException e) { + GET_BLOCK = null; + } + } public static boolean repairRegion(String regionName, World world){ MovecraftRepair movecraftRepair = Movecraft.getInstance().getMovecraftRepair(); @@ -41,7 +48,7 @@ public static boolean repairRegion(String regionName, World world){ for (int z = minZ; z <= maxZ; z++){ if (Settings.IsLegacy){ Vector pos = new Vector(x,y,z); - BaseBlock bb = clipboard.getBlock(pos); + BaseBlock bb = getBlock(clipboard, pos); if (bb.isAir()){ continue; } @@ -64,5 +71,15 @@ public static boolean repairRegion(String regionName, World world){ return true; } + public static BaseBlock getBlock(Clipboard clipboard, Vector pos){ + BlockArrayClipboard bac = (BlockArrayClipboard) clipboard; + try { + return GET_BLOCK != null ? (BaseBlock) GET_BLOCK.invoke(bac, pos) : null; + } catch (IllegalAccessException | InvocationTargetException e) { + e.printStackTrace(); + return null; + } + } + } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RemoteSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RemoteSign.java index 3580ccb8b..03c149ad1 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RemoteSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RemoteSign.java @@ -15,12 +15,35 @@ import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; import org.bukkit.event.block.Action; +import org.bukkit.event.block.SignChangeEvent; import org.bukkit.event.player.PlayerInteractEvent; import java.util.LinkedList; public final class RemoteSign implements Listener{ private static final String HEADER = "Remote Sign"; + @EventHandler + public final void onSignChange(SignChangeEvent event) { + if (!event.getLine(0).equalsIgnoreCase(HEADER)) { + return; + } + else if(event.getLine(1).equals("")) { + event.getPlayer().sendMessage("ERROR: Remote Signs can't be blank!"); + event.setLine(0,""); + event.setLine(2,""); + event.setLine(3,""); + return; + } + else if (event.getLine(1).equalsIgnoreCase("Name:")){ + event.getPlayer().sendMessage("ERROR: Remote Signs can't target Name: signs!"); + event.setLine(0,""); + event.setLine(1,""); + event.setLine(2,""); + event.setLine(3,""); + return; + } + } + @EventHandler public final void onSignClick(PlayerInteractEvent event) { if (event.getAction() != Action.RIGHT_CLICK_BLOCK && event.getAction() != Action.LEFT_CLICK_BLOCK) { @@ -63,30 +86,28 @@ public final void onSignClick(PlayerInteractEvent event) { return; } LinkedList foundLocations = new LinkedList(); + boolean firstError = true; for (MovecraftLocation tloc : foundCraft.getHitBox()) { Block tb = event.getClickedBlock().getWorld().getBlockAt(tloc.getX(), tloc.getY(), tloc.getZ()); if (!tb.getType().equals((Settings.IsLegacy ? LegacyUtils.SIGN_POST : Material.SIGN)) && !tb.getType().equals(Material.WALL_SIGN)) { continue; } Sign ts = (Sign) tb.getState(); - if (ChatColor.stripColor(ts.getLine(0)).equalsIgnoreCase(HEADER)) - continue; - if (ChatColor.stripColor(ts.getLine(0)).equalsIgnoreCase(targetText)){ - foundLocations.add(tloc); - continue; - } - if (ChatColor.stripColor(ts.getLine(1)).equalsIgnoreCase(targetText)){ - foundLocations.add(tloc); - continue; - } - if (ChatColor.stripColor(ts.getLine(2)).equalsIgnoreCase(targetText)) { - foundLocations.add(tloc); - continue; + if (isEqualSign(ts, targetText)) { + if (isForbidden(ts)) { + if (firstError) { + event.getPlayer().sendMessage("Warning: Forbidden remote sign(s) found at the following locations with the following text:"); + firstError = false; + } + event.getPlayer().sendMessage(" - ".concat(tloc.toString()).concat(" : ").concat(ts.getLine(0))); + } else { + foundLocations.add(tloc); + } } - if (ChatColor.stripColor(ts.getLine(3)).equalsIgnoreCase(targetText)) - foundLocations.add(tloc); } - if (foundLocations.isEmpty()) { + if (!firstError) { + return; + } else if (foundLocations.isEmpty()) { event.getPlayer().sendMessage(I18nSupport.getInternationalisedString("ERROR: Could not find target sign!")); return; } @@ -102,4 +123,18 @@ public final void onSignClick(PlayerInteractEvent event) { event.setCancelled(true); } + private boolean isEqualSign(Sign test, String target) { + return !ChatColor.stripColor(test.getLine(0)).equalsIgnoreCase(HEADER) && ( ChatColor.stripColor(test.getLine(0)).equalsIgnoreCase(target) + || ChatColor.stripColor(test.getLine(1)).equalsIgnoreCase(target) + || ChatColor.stripColor(test.getLine(2)).equalsIgnoreCase(target) + || ChatColor.stripColor(test.getLine(3)).equalsIgnoreCase(target)); + } + private boolean isForbidden(Sign test) { + for (int i = 0; i < 4; i++) { + String t = test.getLine(i).toLowerCase(); + if(Settings.ForbiddenRemoteSigns.contains(t)) + return true; + } + return false; + } } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RepairSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RepairSign.java index 1590ff436..ed841275b 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RepairSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RepairSign.java @@ -15,6 +15,7 @@ import net.countercraft.movecraft.mapUpdater.update.WorldEditUpdateCommand; import net.countercraft.movecraft.repair.Repair; import net.countercraft.movecraft.repair.RepairManager; +import net.countercraft.movecraft.repair.RepairUtils; import net.countercraft.movecraft.utils.LegacyUtils; import org.bukkit.Bukkit; import org.bukkit.ChatColor; @@ -216,7 +217,7 @@ private void signRightClick(PlayerInteractEvent event){ MovecraftLocation moveLoc = new MovecraftLocation(cLoc.getBlockX() + distance.getBlockX(), cLoc.getBlockY() + distance.getBlockY(), cLoc.getBlockZ() + distance.getBlockZ()); //To avoid any issues during the repair, keep certain blocks in different linked lists if (Settings.IsLegacy) { - BaseBlock baseBlock = clipboard.getBlock(cLoc); + BaseBlock baseBlock = RepairUtils.getBlock(clipboard, cLoc); if (Arrays.binarySearch(fragileBlocks, LegacyUtils.getMaterial(baseBlock.getType())) >= 0) { WorldEditUpdateCommand updateCommand = new WorldEditUpdateCommand(baseBlock, sign.getWorld(), moveLoc, LegacyUtils.getMaterial(baseBlock.getType()), (byte) baseBlock.getData()); updateCommandsFragileBlocks.add(updateCommand); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/WorldguardUtils.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/WorldguardUtils.java index b7db54c4a..f61b9d6f5 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/WorldguardUtils.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/WorldguardUtils.java @@ -1,8 +1,12 @@ package net.countercraft.movecraft.utils; import com.sk89q.worldguard.protection.regions.ProtectedRegion; +import net.countercraft.movecraft.Movecraft; +import net.countercraft.movecraft.MovecraftLocation; import org.bukkit.Bukkit; import org.bukkit.OfflinePlayer; +import org.bukkit.World; +import org.bukkit.entity.Player; import java.util.UUID; @@ -36,4 +40,8 @@ public static String getRegionOwnerList(ProtectedRegion tRegion) { } return output.toString(); } + + public static boolean canBuild(World world, MovecraftLocation location, Player player){ + return Movecraft.getInstance().getWorldGuardPlugin().canBuild(player, location.toBukkit(world)); + } } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/assault/AssaultTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/assault/AssaultTask.java index aee2233bb..b547912c1 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/assault/AssaultTask.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/assault/AssaultTask.java @@ -81,52 +81,66 @@ public void run() { //first, find a position for the repair beacon int beaconX = assault.getMinPos().getBlockX(); int beaconZ = assault.getMinPos().getBlockZ(); - int beaconY = w.getHighestBlockAt(beaconX, beaconZ).getY(); - int x, y, z; - for (x = beaconX; x < beaconX + 5; x++) - for (z = beaconZ; z < beaconZ + 5; z++) - if (!w.isChunkLoaded(x >> 4, z >> z)) - w.loadChunk(x >> 4, z >> 4); - boolean empty = false; - while (!empty && beaconY < 250) { - empty = true; - beaconY++; - for (x = beaconX; x < beaconX + 5; x++) { - for (y = beaconY; y < beaconY + 4; y++) { - for (z = beaconZ; z < beaconZ + 5; z++) { - if (!w.getBlockAt(x, y, z).isEmpty()) - empty = false; + boolean good = false; + int beaconY = 0; + for(int i = 0; i < 255; i++) { + if(w.getBlockAt(beaconX, i, beaconZ).getType() == Material.AIR) { + good = true; + beaconY = i; + break; + } + } + if(!good) { + Bukkit.getServer().broadcastMessage(String.format("BEACON PLACEMENT FOR %s FAILED, CONTACT AN ADMIN!", assault)); + } + else { + int x, y, z; + for (x = beaconX; x < beaconX + 5; x++) + for (z = beaconZ; z < beaconZ + 5; z++) + if (!w.isChunkLoaded(x >> 4, z >> z)) + w.loadChunk(x >> 4, z >> 4); + boolean empty = false; + while (!empty && beaconY < 250) { + empty = true; + beaconY++; + for (x = beaconX; x < beaconX + 5; x++) { + for (y = beaconY; y < beaconY + 4; y++) { + for (z = beaconZ; z < beaconZ + 5; z++) { + if (!w.getBlockAt(x, y, z).isEmpty()) + empty = false; + } } } } - } + //now make the beacon y = beaconY; for (x = beaconX + 1; x < beaconX + 4; x++) for (z = beaconZ + 1; z < beaconZ + 4; z++) - w.getBlockAt(x, y, z).setType(Material.BEDROCK); - y = beaconY + 1; - for (x = beaconX; x < beaconX + 5; x++) - for (z = beaconZ; z < beaconZ + 5; z++) - if (x == beaconX || z == beaconZ || x == beaconX + 4 || z == beaconZ + 4) w.getBlockAt(x, y, z).setType(Material.BEDROCK); - else - w.getBlockAt(x, y, z).setType(Material.IRON_BLOCK); - y = beaconY + 2; - for (x = beaconX + 1; x < beaconX + 4; x++) - for (z = beaconZ + 1; z < beaconZ + 4; z++) - w.getBlockAt(x, y, z).setType(Material.BEDROCK); - w.getBlockAt(beaconX + 2, beaconY + 2, beaconZ + 2).setType(Material.BEACON); - w.getBlockAt(beaconX + 2, beaconY + 3, beaconZ + 2).setType(Material.BEDROCK); - // finally the sign on the beacon - w.getBlockAt(beaconX + 2, beaconY + 3, beaconZ + 1).setType(Material.WALL_SIGN); - Sign s = (Sign) w.getBlockAt(beaconX + 2, beaconY + 3, beaconZ + 1).getState(); - s.setLine(0, ChatColor.RED + "REGION DAMAGED!"); - s.setLine(1, "Region:" + assault.getRegionName()); - s.setLine(2, "Damage:" + assault.getDamages()); - s.setLine(3, "Owner:" + getRegionOwnerList(tRegion)); - s.update(); + y = beaconY + 1; + for (x = beaconX; x < beaconX + 5; x++) + for (z = beaconZ; z < beaconZ + 5; z++) + if (x == beaconX || z == beaconZ || x == beaconX + 4 || z == beaconZ + 4) + w.getBlockAt(x, y, z).setType(Material.BEDROCK); + else + w.getBlockAt(x, y, z).setType(Material.IRON_BLOCK); + y = beaconY + 2; + for (x = beaconX + 1; x < beaconX + 4; x++) + for (z = beaconZ + 1; z < beaconZ + 4; z++) + w.getBlockAt(x, y, z).setType(Material.BEDROCK); + w.getBlockAt(beaconX + 2, beaconY + 2, beaconZ + 2).setType(Material.BEACON); + w.getBlockAt(beaconX + 2, beaconY + 3, beaconZ + 2).setType(Material.BEDROCK); + // finally the sign on the beacon + w.getBlockAt(beaconX + 2, beaconY + 3, beaconZ + 1).setType(Material.WALL_SIGN); + Sign s = (Sign) w.getBlockAt(beaconX + 2, beaconY + 3, beaconZ + 1).getState(); + s.setLine(0, ChatColor.RED + "REGION DAMAGED!"); + s.setLine(1, "Region:" + assault); + s.setLine(2, "Damage:" + assault.getDamages()); + s.setLine(3, "Owner:" + getRegionOwnerList(tRegion)); + s.update(); + } tRegion.getOwners().clear(); } else { // assault was not successful diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/assault/AssaultUtils.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/assault/AssaultUtils.java index a22e010a7..14a655a5f 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/assault/AssaultUtils.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/assault/AssaultUtils.java @@ -38,9 +38,23 @@ public class AssaultUtils { Material.IRON_TRAPDOOR, Material.ACACIA_TRAPDOOR, Material.BIRCH_TRAPDOOR}; public static boolean areDefendersOnline(ProtectedRegion tRegion) { HashSet players = new HashSet<>(); - players.addAll(tRegion.getMembers().getUniqueIds()); players.addAll(tRegion.getOwners().getUniqueIds()); int numOnline = 0; + + if(Settings.AssaultRequiredOwnersOnline > 0) { + for (UUID playerName : players) { + if (Bukkit.getPlayer(playerName) != null) { + numOnline++; + } + } + + if (numOnline < Settings.AssaultRequiredOwnersOnline) { + return false; + } + numOnline = 0; + } + + players.addAll(tRegion.getMembers().getUniqueIds()); for (UUID playerName : players) { if (Bukkit.getPlayer(playerName) != null) { numOnline++; @@ -51,35 +65,46 @@ public static boolean areDefendersOnline(ProtectedRegion tRegion) { public static double getCostToAssault(ProtectedRegion tRegion) { + return getAssaultBalance(tRegion) * Settings.AssaultCostPercent / 100.0; + } + + public static double getMaxDamages(ProtectedRegion tRegion) { + + return getAssaultBalance(tRegion) * Settings.AssaultDamagesCapPercent / 100.0; + } + + private static double getAssaultBalance(ProtectedRegion tRegion) { + return getOwnerBalance(tRegion) + getMemberBalance(tRegion); + } + + private static double getOwnerBalance(ProtectedRegion tRegion) { HashSet players = new HashSet<>(); - players.addAll(tRegion.getMembers().getUniqueIds()); players.addAll(tRegion.getOwners().getUniqueIds()); double total = 0.0; for (UUID playerName : players) { OfflinePlayer offP = Bukkit.getOfflinePlayer(playerName); if (offP.getName() != null) - if (Movecraft.getInstance().getEconomy().getBalance(offP) > 5000000) - total += 5000000; + if (Movecraft.getInstance().getEconomy().getBalance(offP) > Settings.AssaultMaxBalance) + total += Settings.AssaultMaxBalance; else total += Movecraft.getInstance().getEconomy().getBalance(offP); } - return total * Settings.AssaultCostPercent / 100.0; + return total * (Settings.AssaultOwnerWeightPercent / 100.0); } - public static double getMaxDamages(ProtectedRegion tRegion) { + public static double getMemberBalance(ProtectedRegion tRegion) { HashSet players = new HashSet<>(); players.addAll(tRegion.getMembers().getUniqueIds()); - players.addAll(tRegion.getOwners().getUniqueIds()); double total = 0.0; for (UUID playerName : players) { OfflinePlayer offP = Bukkit.getOfflinePlayer(playerName); if (offP.getName() != null) - if (Movecraft.getInstance().getEconomy().getBalance(offP) > 5000000) - total += 5000000; + if (Movecraft.getInstance().getEconomy().getBalance(offP) > Settings.AssaultMaxBalance) + total += Settings.AssaultMaxBalance; else total += Movecraft.getInstance().getEconomy().getBalance(offP); } - return total * (Settings.AssaultDamagesCapPercent / 100.0); + return total * (Settings.AssaultMemberWeightPercent / 100.0); } public static void processAssault(EntityExplodeEvent e){ diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/worldguard/WorldGuard700Compat.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/worldguard/WorldGuard700Compat.java deleted file mode 100644 index 40202ae05..000000000 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/worldguard/WorldGuard700Compat.java +++ /dev/null @@ -1,7 +0,0 @@ -package net.countercraft.movecraft.worldguard; - -import com.sk89q.worldguard.bukkit.RegionQuery; - -public class WorldGuard700Compat { - -} diff --git a/modules/Movecraft/src/main/resources/config.yml b/modules/Movecraft/src/main/resources/config.yml index 4007c920f..224f420ef 100644 --- a/modules/Movecraft/src/main/resources/config.yml +++ b/modules/Movecraft/src/main/resources/config.yml @@ -1,9 +1,9 @@ -Locale: en +Locale: en CompatibilityMode: false SinkRateTicks: 20 SinkCheckTicks: 100 TracerRateTicks: 5 -PilotTool: 280 +PilotTool: STICK WorldGuardBlockMoveOnBuildPerm: true WorldGuardBlockSinkOnPVPPerm: true ManOverBoardTimeout: 30 @@ -12,92 +12,98 @@ FireballPenetration: true ProtectPilotedCrafts: true DisableSpillProtection: false RequireCreatePerm: false # require users to have the movecract..create permission in order to place command signs +RequireNamePerm: false TNTContactExplosives: true DisableCrates: true FadeWrecksAfter: 600 BlockQueueChunkSize: 200000 RepairTicksPerBlock: 10 RepairMoneyPerBlock: 10 +RepairMaxPercent: 60.0 AllowCrewSigns: true SetHomeToCrewSign: false -AssaultEnable: false # system to damage a region, incurring money damages. If enough damage is inflicted, ownership is lost. Ownership can be restored, and the region repaired, by paying damages +AssaultEnable: true # system to damage a region, incurring money damages. If enough damage is inflicted, ownership is lost. Ownership can be restored, and the region repaired, by paying damages AssaultDamagesCapPercent: 1.0 # percentage of the total wealth of all members of the region which is the maximum damages that can be inflicted AssaultCooldownHours: 24 # time before a region owner can have one of their regions assaulted again -AssaultDelay: 1800 # time (in seconds) between when an assault is announced, and when it happens +AssaultDelay: 120 # time (in seconds) between when an assault is announced, and when it happens AssaultDuration: 1800 # time (in seconds) for the assault AssaultCostPercent: 0.25 # percentage of the total wealth of all members of the region which is the cost to assault it AssaultDamagesPerBlock: 15 # the damages incurred for every block that would have been destroyed in an assault -AssaultRequiredDefendersOnline: 3 # At least this many members or owners must be online for the region to be assaulted +AssaultMaxBalance: 5000000 # Maximum balance of each player that will be contributed to the cost & damages (previously hard coded at 5 million) +AssaultRequiredDefendersOnline: 2 # At least this many members or owners must be online for the region to be assaulted +AssaultRequiredOwnersOnline: 1 # At least this many owners must be online for the region to be assaulted, set to 0 to ignore +AssaultOwnerWeightPercent: 100 # Percentage of each Owner's balance (under the maximum) to include in the total cost & damages (Can be greater than 100) +AssaultMemberWeightPercent: 100 # Percentage of each Member's balance (under the maximum) to include in the total cost & damages (Can be greater than 100) AssaultDestroyableBlocks: # these blocks will be removed if destroyed in assault. Other blocks will not be removed, but still count for damages. Don't include craft flyblocks, or blocks with metadata, or you can have issues. - - 1 - - 2 - - 3 - - 4 - - 12 - - 13 - - 15 - - 16 - - 18 - - 19 - - 24 - - 31 - - 37 - - 38 - - 39 - - 40 - - 46 - - 48 - - 60 - - 67 - - 73 - - 74 - - 78 - - 79 - - 80 - - 81 - - 98 - - 108 - - 128 - - 129 - - 161 - - 162 - - 163 - - 168 - - 169 - - 174 - - 175 - - 179 - - 180 - - 181 - - 182 - - 212 + - STONE + - GRASS + - DIRT + - COBBLESTONE + - SAND + - GRAVEL + - IRON_ORE + - COAL_ORE + - LEAVES + - SPONGE + - SANDSTONE + - LONG_GRASS + - YELLOW_FLOWER + - RED_ROSE + - BROWN_MUSHROOM + - RED_MUSHROOM + - TNT + - MOSSY_COBBLESTONE + - SOIL + - COBBLESTONE_STAIRS + - REDSTONE_ORE + - GLOWING_REDSTONE_ORE + - SNOW + - ICE + - SNOW_BLOCK + - CACTUS + - CLAY + - BRICK_STAIRS + - SANDSTONE_STAIRS + - EMERALD_ORE + - LEAVES_2 + - LOG_2 + - ACACIA_STAIRS + - PRISMARINE + - SEA_LANTERN + - PACKED_ICE + - DOUBLE_PLANT + - RED_SANDSTONE + - RED_SANDSTONE_STAIRS + - DOUBLE_STONE_SLAB2 + - STONE_SLAB2 + - FROSTED_ICE SiegeEnable: true DisableShadowBlocks: # These blocks will not cast shadows. This improves the speed of moving ships of these blocks immensely. - - 26 - - 35 - - 42 - - 43 - - 44 - - 55 - - 109 - - 112 - - 114 - - 121 - - 146 - - 152 - - 155 - - 156 - - 159 - - 165 - - 173 - - 206 + - BED_BLOCK + - WOOL + - IRON_BLOCK + - DOUBLE_STEP + - STEP + - REDSTONE_WIRE + - SMOOTH_STAIRS + - NETHER_BRICK + - NETHER_BRICK_STAIRS + - ENDER_STONE + - TRAPPED_CHEST + - REDSTONE_BLOCK + - QUARTZ_BLOCK + - QUARTZ_STAIRS + - STAINED_CLAY + - SLIME_BLOCK + - COAL_BLOCK + - END_BRICKS WGCustomFlagsUsePilotFlag: false WGCustomFlagsUseMoveFlag: false WGCustomFlagsUseRotateFlag: false WGCustomFlagsUseSinkFlag: false DurabilityOverride: - 121: 80 - 206: 80 + ENDER_STONE: 80 + END_BRICKS: 80 TownyBlockMoveOnSwitchPerm: false TownyBlockSinkOnNoPVP: false TownyWorldHeightLimits: diff --git a/modules/Movecraft/src/main/resources/legacyconfig/config.yml b/modules/Movecraft/src/main/resources/legacyconfig/config.yml new file mode 100644 index 000000000..224f420ef --- /dev/null +++ b/modules/Movecraft/src/main/resources/legacyconfig/config.yml @@ -0,0 +1,114 @@ +Locale: en +CompatibilityMode: false +SinkRateTicks: 20 +SinkCheckTicks: 100 +TracerRateTicks: 5 +PilotTool: STICK +WorldGuardBlockMoveOnBuildPerm: true +WorldGuardBlockSinkOnPVPPerm: true +ManOverBoardTimeout: 30 +FireballLifespan: 6 +FireballPenetration: true +ProtectPilotedCrafts: true +DisableSpillProtection: false +RequireCreatePerm: false # require users to have the movecract..create permission in order to place command signs +RequireNamePerm: false +TNTContactExplosives: true +DisableCrates: true +FadeWrecksAfter: 600 +BlockQueueChunkSize: 200000 +RepairTicksPerBlock: 10 +RepairMoneyPerBlock: 10 +RepairMaxPercent: 60.0 +AllowCrewSigns: true +SetHomeToCrewSign: false +AssaultEnable: true # system to damage a region, incurring money damages. If enough damage is inflicted, ownership is lost. Ownership can be restored, and the region repaired, by paying damages +AssaultDamagesCapPercent: 1.0 # percentage of the total wealth of all members of the region which is the maximum damages that can be inflicted +AssaultCooldownHours: 24 # time before a region owner can have one of their regions assaulted again +AssaultDelay: 120 # time (in seconds) between when an assault is announced, and when it happens +AssaultDuration: 1800 # time (in seconds) for the assault +AssaultCostPercent: 0.25 # percentage of the total wealth of all members of the region which is the cost to assault it +AssaultDamagesPerBlock: 15 # the damages incurred for every block that would have been destroyed in an assault +AssaultMaxBalance: 5000000 # Maximum balance of each player that will be contributed to the cost & damages (previously hard coded at 5 million) +AssaultRequiredDefendersOnline: 2 # At least this many members or owners must be online for the region to be assaulted +AssaultRequiredOwnersOnline: 1 # At least this many owners must be online for the region to be assaulted, set to 0 to ignore +AssaultOwnerWeightPercent: 100 # Percentage of each Owner's balance (under the maximum) to include in the total cost & damages (Can be greater than 100) +AssaultMemberWeightPercent: 100 # Percentage of each Member's balance (under the maximum) to include in the total cost & damages (Can be greater than 100) +AssaultDestroyableBlocks: # these blocks will be removed if destroyed in assault. Other blocks will not be removed, but still count for damages. Don't include craft flyblocks, or blocks with metadata, or you can have issues. + - STONE + - GRASS + - DIRT + - COBBLESTONE + - SAND + - GRAVEL + - IRON_ORE + - COAL_ORE + - LEAVES + - SPONGE + - SANDSTONE + - LONG_GRASS + - YELLOW_FLOWER + - RED_ROSE + - BROWN_MUSHROOM + - RED_MUSHROOM + - TNT + - MOSSY_COBBLESTONE + - SOIL + - COBBLESTONE_STAIRS + - REDSTONE_ORE + - GLOWING_REDSTONE_ORE + - SNOW + - ICE + - SNOW_BLOCK + - CACTUS + - CLAY + - BRICK_STAIRS + - SANDSTONE_STAIRS + - EMERALD_ORE + - LEAVES_2 + - LOG_2 + - ACACIA_STAIRS + - PRISMARINE + - SEA_LANTERN + - PACKED_ICE + - DOUBLE_PLANT + - RED_SANDSTONE + - RED_SANDSTONE_STAIRS + - DOUBLE_STONE_SLAB2 + - STONE_SLAB2 + - FROSTED_ICE +SiegeEnable: true +DisableShadowBlocks: # These blocks will not cast shadows. This improves the speed of moving ships of these blocks immensely. + - BED_BLOCK + - WOOL + - IRON_BLOCK + - DOUBLE_STEP + - STEP + - REDSTONE_WIRE + - SMOOTH_STAIRS + - NETHER_BRICK + - NETHER_BRICK_STAIRS + - ENDER_STONE + - TRAPPED_CHEST + - REDSTONE_BLOCK + - QUARTZ_BLOCK + - QUARTZ_STAIRS + - STAINED_CLAY + - SLIME_BLOCK + - COAL_BLOCK + - END_BRICKS +WGCustomFlagsUsePilotFlag: false +WGCustomFlagsUseMoveFlag: false +WGCustomFlagsUseRotateFlag: false +WGCustomFlagsUseSinkFlag: false +DurabilityOverride: + ENDER_STONE: 80 + END_BRICKS: 80 +TownyBlockMoveOnSwitchPerm: false +TownyBlockSinkOnNoPVP: false +TownyWorldHeightLimits: + world: + worldMin: -1 + worldMax: -1 + aboveTownSpawn: 96 + underTownSpawn: 255 diff --git a/modules/api/src/main/java/net/countercraft/movecraft/config/Settings.java b/modules/api/src/main/java/net/countercraft/movecraft/config/Settings.java index f661e16cf..34d33a1dd 100644 --- a/modules/api/src/main/java/net/countercraft/movecraft/config/Settings.java +++ b/modules/api/src/main/java/net/countercraft/movecraft/config/Settings.java @@ -20,10 +20,7 @@ import net.countercraft.movecraft.utils.TownyWorldHeightLimits; import org.bukkit.Material; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; +import java.util.*; public class Settings { public static boolean RestrictSiBsToRegions = false; @@ -47,6 +44,7 @@ public class Settings { public static boolean RequireCreatePerm = false; public static boolean RequireNamePerm = false; public static boolean TNTContactExplosives = true; + public static HashSet ForbiddenRemoteSigns; public static int FadeWrecksAfter = 0; public static int ManOverBoardTimeout = 60; public static int FireballLifespan = 6; @@ -80,7 +78,11 @@ public class Settings { public static int AssaultDelay; public static int AssaultDuration; public static int AssaultRequiredDefendersOnline; + public static int AssaultRequiredOwnersOnline; public static double AssaultCostPercent; + public static double AssaultMaxBalance; + public static int AssaultOwnerWeightPercent; + public static int AssaultMemberWeightPercent; public static HashSet AssaultDestroyableBlocks = new HashSet<>(); public static int AssaultDamagesPerBlock; public static HashSet DisableShadowBlocks = new HashSet<>(); From e4fd58445799100d47bf3a28e0af704870fcdaf2 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Wed, 6 Feb 2019 09:45:50 +0100 Subject: [PATCH 006/304] bug fixes --- .../net/countercraft/movecraft/Movecraft.java | 9 +- .../async/rotation/RotationTask.java | 9 +- .../async/translation/TranslationTask.java | 2 +- .../WorldGuardCompatManager.java | 10 +-- .../movecraft/listener/InteractListener.java | 7 -- .../movecraft/localisation/I18nSupport.java | 28 ++++-- .../update/EntityUpdateCommand.java | 6 +- .../update/ExplosionUpdateCommand.java | 21 ++++- .../movecraft/sign/RemoteSign.java | 29 ++++++- .../movecraft/sign/RepairSign.java | 4 +- .../warfare/assault/AssaultUtils.java | 6 +- .../localisation/movecraftlang_ar.properties | 85 +++++++++++++++++++ .../localisation/movecraftlang_he.properties | 85 +++++++++++++++++++ .../movecraft/MovecraftRepair.java | 1 + .../countercraft/movecraft/craft/Craft.java | 4 +- .../movecraft/craft/CraftType.java | 9 +- .../compat/v1_10_R1/IMovecraftRepair.java | 5 ++ .../compat/v1_11_R1/IMovecraftRepair.java | 5 ++ .../compat/v1_12_R1/IMovecraftRepair.java | 5 ++ .../compat/v1_13_R2/IMovecraftRepair.java | 6 ++ 20 files changed, 287 insertions(+), 49 deletions(-) create mode 100644 modules/Movecraft/src/main/resources/localisation/movecraftlang_ar.properties create mode 100644 modules/Movecraft/src/main/resources/localisation/movecraftlang_he.properties diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java index 2a5257359..d0b812050 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java @@ -111,7 +111,10 @@ public void onEnable() { if (Settings.IsLegacy) { this.saveDefaultConfig(); } else { - this.saveResource("legacyconfig/config.yml", false); + File configFile = new File(Movecraft.getInstance().getDataFolder().getAbsolutePath() + "/config.yml"); + if (!configFile.exists()) { + this.saveResource("legacyconfig/config.yml", false); + } } try { Class.forName("com.destroystokyo.paper.Title"); @@ -131,7 +134,7 @@ public void onEnable() { + getConfig().getString("PilotTool")); Settings.PilotTool = Material.getMaterial(getConfig().getString("PilotTool")); } else { - logger.log(Level.INFO, "No PilotTool setting, using default of 280"); + logger.log(Level.INFO, "No PilotTool setting, using default of stick"); } // if the CompatibilityMode is specified in the config.yml file, use it. // Otherwise set to false. @@ -161,7 +164,7 @@ public void onEnable() { } this.getLogger().info("Loading support for " + version); - this.getLogger().info("isLegacy: " + Settings.IsLegacy); + Settings.SinkCheckTicks = getConfig().getDouble("SinkCheckTicks", 100.0); Settings.TracerRateTicks = getConfig().getDouble("TracerRateTicks", 5.0); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/rotation/RotationTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/rotation/RotationTask.java index 6166140cd..6258781e3 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/rotation/RotationTask.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/rotation/RotationTask.java @@ -177,14 +177,7 @@ protected void execute() { // See if they are permitted to build in the area, if WorldGuard integration is turned on Location plugLoc = newLocation.toBukkit(w); - if (craftPilot != null && - Movecraft.getInstance().getWorldGuardPlugin() != null && - Settings.WorldGuardBlockMoveOnBuildPerm && - !Movecraft.getInstance().getWorldGuardPlugin().canBuild(craftPilot, plugLoc)) { - failed = true; - failMessage = String.format(I18nSupport.getInternationalisedString("Rotation - Player is not permitted to build in this WorldGuard region") + " @ %d,%d,%d", newLocation.getX(), newLocation.getY(), newLocation.getZ()); - break; - } + //TODO: ADD TOWNY //TODO: ADD FACTIONS diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java index e61d04d86..d1ce4a16d 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java @@ -266,7 +266,7 @@ private void fail(String message) { craft.getW().playSound(location, Sound.BLOCK_ANVIL_LAND, 1.0f, 0.25f); //craft.setCurTickCooldown(craft.getType().getCruiseTickCooldown()); } else { - craft.getW().playSound(location, Settings.IsLegacy ? Sound.ENTITY_IRON_GOLEM_DEATH : LegacyUtils.ENITIY_IRONGOLEM_DEATH, 5.0f, 5.0f); + craft.getW().playSound(location, Settings.IsLegacy ? LegacyUtils.ENITIY_IRONGOLEM_DEATH : Sound.ENTITY_IRON_GOLEM_DEATH, 5.0f, 5.0f); //craft.setCurTickCooldown(craft.getType().getCruiseTickCooldown()); } } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/compatmanager/WorldGuardCompatManager.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/compatmanager/WorldGuardCompatManager.java index 5646950d6..b26534318 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/compatmanager/WorldGuardCompatManager.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/compatmanager/WorldGuardCompatManager.java @@ -30,7 +30,7 @@ public void onCraftTranslateEvent(CraftTranslateEvent event){ if(event.getCraft().getNotificationPlayer() == null) return; for(MovecraftLocation location : event.getNewHitBox()){ - if(!Movecraft.getInstance().getWorldGuardPlugin().canBuild(event.getCraft().getNotificationPlayer(),location.toBukkit(event.getCraft().getW()))){ + if(!pilotHasAccessToRegion(event.getCraft().getNotificationPlayer(), location, event.getCraft().getW())){ event.setCancelled(true); event.setFailMessage(String.format( I18nSupport.getInternationalisedString( "Translation - Failed Player is not permitted to build in this WorldGuard region" )+" @ %d,%d,%d", location.getX(), location.getY(), location.getZ() ) ); return; @@ -55,14 +55,14 @@ public void onCraftRotateEvent(CraftRotateEvent event){ } private boolean pilotHasAccessToRegion(Player player, MovecraftLocation location, World world){ if (Settings.IsLegacy){ - return WorldguardUtils.canBuild(world, location, player); + return Movecraft.getInstance().getWorldGuardPlugin().canBuild(player, location.toBukkit(world)); } else { RegionQuery query = WorldGuard.getInstance().getPlatform().getRegionContainer().createQuery(); LocalPlayer lPlayer = Movecraft.getInstance().getWorldGuardPlugin().wrapPlayer(player); - Extent ext = new FastModeExtent(new BukkitWorld(world)); - Location wgLoc = new Location(ext, location.getX(), location.getY(), location.getZ()); + com.sk89q.worldedit.world.World weWorld = new BukkitWorld(world); + Location wgLoc = new Location(weWorld, location.getX(), location.getY(), location.getZ()); return query.getApplicableRegions(wgLoc).isOwnerOfAll(lPlayer) || query.getApplicableRegions(wgLoc).isMemberOfAll(lPlayer) || - player.hasPermission("movecraft.region.bypass"); + player.hasPermission("worldguard.build.*"); } } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/InteractListener.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/InteractListener.java index a1d19b3cc..618c0881a 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/InteractListener.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/InteractListener.java @@ -71,13 +71,6 @@ public void onPlayerInteractStick(PlayerInteractEvent event) { // if not in command of craft, don't process pilot tool clicks if (c == null) return; - -/* if( c.getCannonDirector()==event.getPlayer() ) // if the player is the cannon director, don't let them move the ship - return; - - if( c.getAADirector()==event.getPlayer() ) // if the player is the cannon director, don't let them move the ship - return; -*/ if (event.getAction() == Action.RIGHT_CLICK_AIR || event.getAction() == Action.RIGHT_CLICK_BLOCK) { Craft craft = CraftManager.getInstance().getCraftByPlayer(event.getPlayer()); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/localisation/I18nSupport.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/localisation/I18nSupport.java index 4a53955f5..cd6d42ac5 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/localisation/I18nSupport.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/localisation/I18nSupport.java @@ -20,17 +20,15 @@ import net.countercraft.movecraft.Movecraft; import net.countercraft.movecraft.config.Settings; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStream; +import java.io.*; +import java.util.Arrays; import java.util.Properties; import java.util.logging.Level; public class I18nSupport { private static Properties languageFile; - + private static boolean hasOtherScript = false; + private static final String[] otherScriptLangs = {"el", "ar", "ur", "he", "zh", "jp"}; public static void init() { languageFile = new Properties(); @@ -47,6 +45,7 @@ public static void init() { e.printStackTrace(); } + if (is == null) { Movecraft.getInstance().getLogger().log(Level.SEVERE, "Critical Error in Localisation System"); Movecraft.getInstance().getServer().shutdown(); @@ -62,9 +61,22 @@ public static void init() { } - + public static boolean writtenFromRightToLeft(){ + boolean ret = (boolean) languageFile.getOrDefault("writtenFromRightToLeft", false); + return ret; + } public static String getInternationalisedString(String key) { - String ret = languageFile.getProperty(key); + String ret; + if (Arrays.binarySearch(otherScriptLangs, Settings.LOCALE) >= 0){ + try { + ret = new String(languageFile.getProperty(key).getBytes(),"UTF-8"); + } catch (UnsupportedEncodingException e) { + ret = languageFile.getProperty(key); + e.printStackTrace(); + } + } else { + ret = languageFile.getProperty(key); + } if (ret != null) { return ret; } else { diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/EntityUpdateCommand.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/EntityUpdateCommand.java index 3b3d391d7..65dd0cd92 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/EntityUpdateCommand.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/EntityUpdateCommand.java @@ -50,10 +50,12 @@ public Entity getEntity() { @Override public void doUpdate() { - + if (!(entity instanceof Player)){ Location playerLoc = entity.getLocation(); entity.teleport(new Location(entity.getWorld(), x + playerLoc.getX(),y + playerLoc.getY(),z + playerLoc.getZ(),yaw + playerLoc.getYaw(),pitch + playerLoc.getPitch())); - + return; + } + Movecraft.getInstance().getWorldHandler().addPlayerLocation((Player) entity,x,y,z,yaw,pitch); } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/ExplosionUpdateCommand.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/ExplosionUpdateCommand.java index f32e6c334..b831ddc44 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/ExplosionUpdateCommand.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/ExplosionUpdateCommand.java @@ -1,8 +1,13 @@ package net.countercraft.movecraft.mapUpdater.update; +import com.sk89q.worldedit.bukkit.BukkitWorld; +import com.sk89q.worldguard.WorldGuard; import com.sk89q.worldguard.protection.ApplicableRegionSet; import com.sk89q.worldguard.protection.flags.DefaultFlag; +import com.sk89q.worldguard.protection.flags.Flag; +import com.sk89q.worldguard.protection.regions.RegionQuery; import net.countercraft.movecraft.Movecraft; +import net.countercraft.movecraft.config.Settings; import org.bukkit.Location; import java.util.Objects; @@ -38,10 +43,20 @@ public void doUpdate() { private void createExplosion(Location loc, float explosionPower) { if (Movecraft.getInstance().getWorldGuardPlugin() != null) { - ApplicableRegionSet set = Movecraft.getInstance().getWorldGuardPlugin().getRegionManager(loc.getWorld()).getApplicableRegions(loc); - if (!set.allows(DefaultFlag.OTHER_EXPLOSION)) { - return; + ApplicableRegionSet set; + if (Settings.IsLegacy) { + set = Movecraft.getInstance().getWorldGuardPlugin().getRegionManager(loc.getWorld()).getApplicableRegions(loc); + if (!set.allows(DefaultFlag.OTHER_EXPLOSION)) { + return; + } + } else { + RegionQuery query = WorldGuard.getInstance().getPlatform().getRegionContainer().createQuery(); + com.sk89q.worldedit.world.World weWorld = new BukkitWorld(loc.getWorld()); + com.sk89q.worldedit.util.Location wgLoc = new com.sk89q.worldedit.util.Location(weWorld, loc.getBlockX(), loc.getBlockY(), loc.getBlockZ()); + set = query.getApplicableRegions(wgLoc); + } + } loc.getWorld().createExplosion(loc.getX() + 0.5, loc.getY() + 0.5, loc.getZ() + 0.5, explosionPower); } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RemoteSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RemoteSign.java index 03c149ad1..25fb3c13c 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RemoteSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RemoteSign.java @@ -17,6 +17,8 @@ import org.bukkit.event.block.Action; import org.bukkit.event.block.SignChangeEvent; import org.bukkit.event.player.PlayerInteractEvent; + +import java.util.LinkedHashMap; import java.util.LinkedList; public final class RemoteSign implements Listener{ @@ -81,11 +83,13 @@ public final void onSignClick(PlayerInteractEvent event) { } String targetText = ChatColor.stripColor(sign.getLine(1)); + if(targetText.equalsIgnoreCase(HEADER)) { event.getPlayer().sendMessage("ERROR: Remote Sign can't remote another Remote Sign!"); return; } LinkedList foundLocations = new LinkedList(); + LinkedHashMap foundLocs = new LinkedHashMap<>(); boolean firstError = true; for (MovecraftLocation tloc : foundCraft.getHitBox()) { Block tb = event.getClickedBlock().getWorld().getBlockAt(tloc.getX(), tloc.getY(), tloc.getZ()); @@ -114,9 +118,24 @@ public final void onSignClick(PlayerInteractEvent event) { for (MovecraftLocation foundLoc : foundLocations) { Block newBlock = event.getClickedBlock().getWorld().getBlockAt(foundLoc.getX(), foundLoc.getY(), foundLoc.getZ()); + Sign foundSign = (Sign) newBlock.getState(); + boolean inverted = false;//set to true if target name has an ! in front of the text + //check Remote sign if the target strings are inverted + PlayerInteractEvent newEvent = null; - PlayerInteractEvent newEvent = new PlayerInteractEvent(event.getPlayer(), event.getAction(), event.getItem(), newBlock, event.getBlockFace()); - + if (inverted) { + Action action = null; + if (event.getAction() == Action.RIGHT_CLICK_BLOCK){ + action = Action.LEFT_CLICK_BLOCK; + } else if (event.getAction() == Action.LEFT_CLICK_BLOCK){ + action = Action.RIGHT_CLICK_BLOCK; + } + if (action != null){ + newEvent = new PlayerInteractEvent(event.getPlayer(), action, event.getItem(), newBlock, event.getBlockFace()); + } + } else { + newEvent = new PlayerInteractEvent(event.getPlayer(), event.getAction(), event.getItem(), newBlock, event.getBlockFace()); + } //TODO: DON'T DO THIS Bukkit.getServer().getPluginManager().callEvent(newEvent); } @@ -124,6 +143,9 @@ public final void onSignClick(PlayerInteractEvent event) { event.setCancelled(true); } private boolean isEqualSign(Sign test, String target) { + if (target.charAt(0) == '!'){ + target = target.substring(1); + } return !ChatColor.stripColor(test.getLine(0)).equalsIgnoreCase(HEADER) && ( ChatColor.stripColor(test.getLine(0)).equalsIgnoreCase(target) || ChatColor.stripColor(test.getLine(1)).equalsIgnoreCase(target) || ChatColor.stripColor(test.getLine(2)).equalsIgnoreCase(target) @@ -137,4 +159,7 @@ private boolean isForbidden(Sign test) { } return false; } + private boolean invertAction(String line){ + return line.charAt(0) == '!'; + } } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RepairSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RepairSign.java index ed841275b..5e0b1b52a 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RepairSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RepairSign.java @@ -209,8 +209,8 @@ private void signRightClick(PlayerInteractEvent event){ final LinkedList updateCommands = new LinkedList<>(); final LinkedList updateCommandsFragileBlocks = new LinkedList<>(); final Vector distToOffset = movecraftRepair.getDistanceFromSignToLowestPoint(clipboard, sign.getLine(1)); - final Vector offsetFromSign = new Vector(sign.getLocation().getBlockX() - distToOffset.getBlockX(), sign.getLocation().getBlockY() - distToOffset.getBlockY(), sign.getLocation().getBlockZ() - distToOffset.getBlockZ()); - final Vector distance = new Vector(offsetFromSign.getBlockX() - clipboard.getMinimumPoint().getBlockX(), offsetFromSign.getBlockY() - clipboard.getMinimumPoint().getBlockY(), offsetFromSign.getBlockZ() - clipboard.getMinimumPoint().getBlockZ()); + final org.bukkit.util.Vector offsetFromSign = new org.bukkit.util.Vector(sign.getLocation().getBlockX() - distToOffset.getBlockX(), sign.getLocation().getBlockY() - distToOffset.getBlockY(), sign.getLocation().getBlockZ() - distToOffset.getBlockZ()); + final org.bukkit.util.Vector distance = movecraftRepair.getDistanceFromClipboardToWorldOffset(offsetFromSign, clipboard); final TreeSet sortedLocMissingBlocks = new TreeSet<>(locMissingBlocks); for (Vector cLoc : sortedLocMissingBlocks){ diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/assault/AssaultUtils.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/assault/AssaultUtils.java index 14a655a5f..236699931 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/assault/AssaultUtils.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/assault/AssaultUtils.java @@ -149,9 +149,11 @@ public static void processAssault(EntityExplodeEvent e){ // whether or not you actually destroyed the block, add to damages long damages = assault.getDamages() + Settings.AssaultDamagesPerBlock; - //if (damages < assault.getMaxDamages()) { + if (damages < assault.getMaxDamages()) { assault.setDamages(damages); - //} + } else { + assault.setDamages(assault.getMaxDamages()); + } // notify nearby players of the damages, do this 1 second later so all damages from this volley will be included if (System.currentTimeMillis() < lastDamagesUpdate + 4000) { diff --git a/modules/Movecraft/src/main/resources/localisation/movecraftlang_ar.properties b/modules/Movecraft/src/main/resources/localisation/movecraftlang_ar.properties new file mode 100644 index 000000000..298a7c5ae --- /dev/null +++ b/modules/Movecraft/src/main/resources/localisation/movecraftlang_ar.properties @@ -0,0 +1,85 @@ +# +# This file is part of Movecraft. +# +# Movecraft is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Movecraft is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Movecraft. If not, see . +# + +# Message returned when a craft is too small. One Integer which is the minimum size of that Craft Type +Detection\ -\ Craft\ too\ small=%d ??? ???\! ???? ??????? ????? ??????. ???? ?????? ???? ????? ?? +Detection\ -\ Craft\ too\ large=%d ??? ???\! ???? ??????? ????? ????. ???? ?????? ???? ????? ?? +Detection\ -\ Forbidden\ block\ found=??? ???\! ?? ?????? ??? ???? ?????? ??? ???????. +Detection\ -\ Failed\ -\ Already\ commanding\ a\ craft=You are already commanding a craft\! +Detection\ -\ Failed\ Craft\ is\ already\ being\ controlled=The craft is already being controlled\! +Detection\ -\ Successfully\ piloted\ craft=Succesfully piloted craft\! +Rotation\ -\ Craft\ is\ obstructed=Craft is obstructed +Rotation\ -\ Craft\ Collision=Craft Collision +Translation\ -\ Failed\ Craft\ hit\ height\ limit=Craft has hit the height limit +Translation\ -\ Failed\ Craft\ is\ obstructed=The craft cannot move because its path is obstructed\! +Translation\ -\ Failed\ Craft\ out\ of\ fuel=The craft is out of fuel\! +Translation\ -\ Failed\ Craft\ hit\ minimum\ height\ limit=Craft has hit the minimum height limit +Translation\\=-\\ Failed\\ Craft\\ over\\ water=This craft cannot move over water\\! +Translation\ -\ Craft\ collision=Craft Collision +Internal\ -\ Error\ -\ Proccessor\ thread\ encountered\ an\ error=Async Task generated an exception. +Startup\ -\ Number\ of\ craft\ files\ loaded=Loaded %d Craft files +Startup\ -\ Error\ parsing\ CraftType\ file=***ERROR PARSING CRAFT FILE FROM DIRECTORY \: %s*** +Startup\ -\ Error\ -\ Reload\ error=Movecraft is incompatible with the reload command. Movecraft has shut down and will restart when the server is restarted. +Startup\ -\ Error\ -\ Disable\ warning\ for\ reload=If you wish to use the reload command and Movecraft, you may disable this check inside the config.yml by setting 'safeReload \: false' +Startup\ -\ Enabled\ message=[V %S] has been enabled. +Item\ -\ Storage\ Crate\ name=Storage Crate +Player-\ Craft\ has\ been\ released=Your craft has been released\! +Player-\ Craft\ should\ sink\ but\ PVP\ is\ not\ allowed\ in\ this\ WorldGuard\ region=Player- Craft should sink but PVP is not allowed in this WorldGuard region +Player-\ Craft\ is\ sinking=Your craft has taken too much damage and is sinking\! ABANDON SHIP\! +Player-\ Error\ -\ You\ do\ not\ have\ a\ craft\ to\ release!=You do not have a craft to release\! +Player\ -\ Error\ -\ Already\ piloting\ craft=You are already commanding a craft\! +MCStats\ -\ \:(\ -\ Admin\ has\ opted\ out=You have selected to opt out of mcstats.org data submission. The developer of Movecraft would greatly appreciate you submitting your data. +MCStats\ -\ Thank\ you\ message=Submitted statistics to mcstats.org succesfully. Thank you for your support. +MCStats\ -\ Error\ -\ Unable\ to\ upload\ stats=Unable to upload statistics to mcstats.org. Please check your network connection. +Release\ -\ Player\ has\ left\ craft=You have left your craft\! You have 15 seconds to return to it or it will be automatically released. +Release\ -\ Craft\ has\ been\ released\ message=You have released your craft. +Release\ -\ Player\ has\ released\ a\ craft\ console=Player %s has released a craft of type %s with size %d at coordinates \: %d x , %d z +Detection\ -\ Success\ -\ Log\ Output=Player %s piloted a craft of type %s with size %d at location\: %d x, %d z +Not\ enough\ flyblock=Not enough flyblock +Too\ much\ flyblock=Too much flyblock +Detection\ -\ ERROR\:\ Double\ chest\ found=Detection failed\! ERROR \: Double chest found +Detection\ -\ Failed\ -\ Water\ contact\ required\ but\ not\ found=Detection failed\: Water contact required but not found +Rotation\ -\ Player\ is\ not\ permitted\ to\ build\ in\ this\ WorldGuard\ region=Rotation - Player is not permitted to build in this WorldGuard region +Translation\ -\ Failed\ Player\ is\ not\ permitted\ to\ build\ in\ this\ WorldGuard\ region=Translation Failed - Player is not permitted to build in this WorldGuard region +Parent\ Craft\ is\ busy=Parent Craft is busy +Insufficient\ Permissions=Insufficient Permissions +ERROR\:\ Remote\ Sign\ must\ be\ a\ part\ of\ a\ piloted\ craft\!=ERROR\: Remote Sign must be a part of a piloted craft\! +ERROR\:\ Remote\ Signs\ not\ allowed\ on\ this\ craft\!=ERROR\: Remote Signs not allowed on this craft\! +ERROR\:\ Could\ not\ find\ target\ sign\!=ERROR\: Could not find target sign\! +Entering\ Direct\ Control\ Mode=Entering Direct Control Mode +Leaving\ Direct\ Control\ Mode=Leaving Direct Control Mode +Craft\ is\ too\ big\ to\ check\ its\ borders\.\ Make\ sure\ this\ area\ is\ safe\ to\ release\ your\ craft\ in\.=Craft is too big to check its borders. Make sure this area is safe to release your craft in. +You\ have\ left\ your\ craft\.\ You\ may\ return\ to\ your\ craft\ by\ typing\ \/manoverboard\ any\ time\ before\ the\ timeout\ expires=You have left your craft. If you have fallen out of your craft, you man type /manoverboard before the timout expires and be returned to it. +WARNING\!\ There\ are\ blocks\ near\ your\ craft\ that\ may\ merge\ with\ the\ \craft\ "=WARNING\! There are blocks near your craft that may merge with the craft +You\ can\ only\ create\ a\ Crew\:\ sign\ for\ yourself=You can only create a Crew\: sign for yourself +Repair\ functionality\ is\ disabled\ or\ WorldEdit\ was\ not\ detected=Repair functionality is disabled or WorldEdit was not detected +You\ must\ be\ piloting\ a\ craft=You must be piloting a craft +Could\ not\ save\ file=Could not save file +State\ saved=State saved +REPAIR\ STATE\ NOT\ FOUND=REPAIR STATE NOT FOUND +Repairs\ underway=Repairs underway +Repairs\ complete\.\ You\ may\ now\ pilot\ the\ craft=Repairs complete. You may now pilot the craft +You\ do\ not\ have\ enough\ money=You do not have enough money +Need\ more\ of\ material=Need more of material +Towny\ -\ Detection\ Failed=Detection Failed - You are not permitted to pilot a craft on this plot in the town +Towny\ -\ Translation\ Failed=Translation Failed - You are not permitted to move a craft on this plot in the town +Towny\ -\ Rotation\ Failed=Rotation Failed - You are not permitted to rotate a craft on this plot in the town +Towny\ -\ Sinking\ a\ craft\ is\ not\ allowed\ in\ this\ town\ plot=Sinking a craft is not allowed in this town plot\! +WGCustomFlags\ -\ Translation\ Failed=Translation Failed - You are not permitted to move a craft in this WorldGuard region +WGCustomFlags\ -\ Rotation\ Failed=Rotation Failed - You are not permitterd to rotate a craft in this WorldGuard region +WGCustomFlags\ -\ Detection\ Failed=Detection Failed - You are not permitted to pilot a craft in this WorldGuard region +WGCustomFlags\ -\ Sinking\ a\ craft\ is\ not\ allowed\ in\ this\ WorldGuard\ region=Sinking is not allowed in this WorldGuard region\! diff --git a/modules/Movecraft/src/main/resources/localisation/movecraftlang_he.properties b/modules/Movecraft/src/main/resources/localisation/movecraftlang_he.properties new file mode 100644 index 000000000..d7d42d1ac --- /dev/null +++ b/modules/Movecraft/src/main/resources/localisation/movecraftlang_he.properties @@ -0,0 +1,85 @@ +# +# This file is part of Movecraft. +# +# Movecraft is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Movecraft is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Movecraft. If not, see . +# + +# Message returned when a craft is too small. One Integer which is the minimum size of that Craft Type +Detection\ -\ Craft\ too\ small=%d ????? ????\! ??? ???? ??? ??? ???. ??????? ???? ?? ??? +Detection\ -\ Craft\ too\ large=????? ????\! ??? ???? ??? ???? ???. ??????? ???? ?? ??? d% +Detection\ -\ Forbidden\ block\ found= +Detection\ -\ Failed\ -\ Already\ commanding\ a\ craft=You are already commanding a craft\! +Detection\ -\ Failed\ Craft\ is\ already\ being\ controlled=The craft is already being controlled\! +Detection\ -\ Successfully\ piloted\ craft=Succesfully piloted craft\! +Rotation\ -\ Craft\ is\ obstructed=Craft is obstructed +Rotation\ -\ Craft\ Collision=Craft Collision +Translation\ -\ Failed\ Craft\ hit\ height\ limit=Craft has hit the height limit +Translation\ -\ Failed\ Craft\ is\ obstructed=The craft cannot move because its path is obstructed\! +Translation\ -\ Failed\ Craft\ out\ of\ fuel=The craft is out of fuel\! +Translation\ -\ Failed\ Craft\ hit\ minimum\ height\ limit=Craft has hit the minimum height limit +Translation\\=-\\ Failed\\ Craft\\ over\\ water=This craft cannot move over water\\! +Translation\ -\ Craft\ collision=Craft Collision +Internal\ -\ Error\ -\ Proccessor\ thread\ encountered\ an\ error=Async Task generated an exception. +Startup\ -\ Number\ of\ craft\ files\ loaded=Loaded %d Craft files +Startup\ -\ Error\ parsing\ CraftType\ file=***ERROR PARSING CRAFT FILE FROM DIRECTORY \: %s*** +Startup\ -\ Error\ -\ Reload\ error=Movecraft is incompatible with the reload command. Movecraft has shut down and will restart when the server is restarted. +Startup\ -\ Error\ -\ Disable\ warning\ for\ reload=If you wish to use the reload command and Movecraft, you may disable this check inside the config.yml by setting 'safeReload \: false' +Startup\ -\ Enabled\ message=[V %S] has been enabled. +Item\ -\ Storage\ Crate\ name=Storage Crate +Player-\ Craft\ has\ been\ released=Your craft has been released\! +Player-\ Craft\ should\ sink\ but\ PVP\ is\ not\ allowed\ in\ this\ WorldGuard\ region=Player- Craft should sink but PVP is not allowed in this WorldGuard region +Player-\ Craft\ is\ sinking=Your craft has taken too much damage and is sinking\! ABANDON SHIP\! +Player-\ Error\ -\ You\ do\ not\ have\ a\ craft\ to\ release!=You do not have a craft to release\! +Player\ -\ Error\ -\ Already\ piloting\ craft=You are already commanding a craft\! +MCStats\ -\ \:(\ -\ Admin\ has\ opted\ out=You have selected to opt out of mcstats.org data submission. The developer of Movecraft would greatly appreciate you submitting your data. +MCStats\ -\ Thank\ you\ message=Submitted statistics to mcstats.org succesfully. Thank you for your support. +MCStats\ -\ Error\ -\ Unable\ to\ upload\ stats=Unable to upload statistics to mcstats.org. Please check your network connection. +Release\ -\ Player\ has\ left\ craft=You have left your craft\! You have 15 seconds to return to it or it will be automatically released. +Release\ -\ Craft\ has\ been\ released\ message=You have released your craft. +Release\ -\ Player\ has\ released\ a\ craft\ console=Player %s has released a craft of type %s with size %d at coordinates \: %d x , %d z +Detection\ -\ Success\ -\ Log\ Output=Player %s piloted a craft of type %s with size %d at location\: %d x, %d z +Not\ enough\ flyblock=Not enough flyblock +Too\ much\ flyblock=Too much flyblock +Detection\ -\ ERROR\:\ Double\ chest\ found=Detection failed\! ERROR \: Double chest found +Detection\ -\ Failed\ -\ Water\ contact\ required\ but\ not\ found=Detection failed\: Water contact required but not found +Rotation\ -\ Player\ is\ not\ permitted\ to\ build\ in\ this\ WorldGuard\ region=Rotation - Player is not permitted to build in this WorldGuard region +Translation\ -\ Failed\ Player\ is\ not\ permitted\ to\ build\ in\ this\ WorldGuard\ region=Translation Failed - Player is not permitted to build in this WorldGuard region +Parent\ Craft\ is\ busy=Parent Craft is busy +Insufficient\ Permissions=Insufficient Permissions +ERROR\:\ Remote\ Sign\ must\ be\ a\ part\ of\ a\ piloted\ craft\!=ERROR\: Remote Sign must be a part of a piloted craft\! +ERROR\:\ Remote\ Signs\ not\ allowed\ on\ this\ craft\!=ERROR\: Remote Signs not allowed on this craft\! +ERROR\:\ Could\ not\ find\ target\ sign\!=ERROR\: Could not find target sign\! +Entering\ Direct\ Control\ Mode=Entering Direct Control Mode +Leaving\ Direct\ Control\ Mode=Leaving Direct Control Mode +Craft\ is\ too\ big\ to\ check\ its\ borders\.\ Make\ sure\ this\ area\ is\ safe\ to\ release\ your\ craft\ in\.=Craft is too big to check its borders. Make sure this area is safe to release your craft in. +You\ have\ left\ your\ craft\.\ You\ may\ return\ to\ your\ craft\ by\ typing\ \/manoverboard\ any\ time\ before\ the\ timeout\ expires=You have left your craft. If you have fallen out of your craft, you man type /manoverboard before the timout expires and be returned to it. +WARNING\!\ There\ are\ blocks\ near\ your\ craft\ that\ may\ merge\ with\ the\ \craft\ "=WARNING\! There are blocks near your craft that may merge with the craft +You\ can\ only\ create\ a\ Crew\:\ sign\ for\ yourself=You can only create a Crew\: sign for yourself +Repair\ functionality\ is\ disabled\ or\ WorldEdit\ was\ not\ detected=Repair functionality is disabled or WorldEdit was not detected +You\ must\ be\ piloting\ a\ craft=You must be piloting a craft +Could\ not\ save\ file=Could not save file +State\ saved=State saved +REPAIR\ STATE\ NOT\ FOUND=REPAIR STATE NOT FOUND +Repairs\ underway=Repairs underway +Repairs\ complete\.\ You\ may\ now\ pilot\ the\ craft=Repairs complete. You may now pilot the craft +You\ do\ not\ have\ enough\ money=You do not have enough money +Need\ more\ of\ material=Need more of material +Towny\ -\ Detection\ Failed=Detection Failed - You are not permitted to pilot a craft on this plot in the town +Towny\ -\ Translation\ Failed=Translation Failed - You are not permitted to move a craft on this plot in the town +Towny\ -\ Rotation\ Failed=Rotation Failed - You are not permitted to rotate a craft on this plot in the town +Towny\ -\ Sinking\ a\ craft\ is\ not\ allowed\ in\ this\ town\ plot=Sinking a craft is not allowed in this town plot\! +WGCustomFlags\ -\ Translation\ Failed=Translation Failed - You are not permitted to move a craft in this WorldGuard region +WGCustomFlags\ -\ Rotation\ Failed=Rotation Failed - You are not permitterd to rotate a craft in this WorldGuard region +WGCustomFlags\ -\ Detection\ Failed=Detection Failed - You are not permitted to pilot a craft in this WorldGuard region +WGCustomFlags\ -\ Sinking\ a\ craft\ is\ not\ allowed\ in\ this\ WorldGuard\ region=Sinking is not allowed in this WorldGuard region\! diff --git a/modules/api/src/main/java/net/countercraft/movecraft/MovecraftRepair.java b/modules/api/src/main/java/net/countercraft/movecraft/MovecraftRepair.java index 96518fbc6..99edd1b4d 100644 --- a/modules/api/src/main/java/net/countercraft/movecraft/MovecraftRepair.java +++ b/modules/api/src/main/java/net/countercraft/movecraft/MovecraftRepair.java @@ -24,6 +24,7 @@ public abstract class MovecraftRepair { public abstract HashSet getMissingBlockLocations(String repairName); public abstract long getNumDiffBlocks(String repairName); public abstract Vector getDistanceFromSignToLowestPoint(Clipboard clipboard, String repairName); + public abstract org.bukkit.util.Vector getDistanceFromClipboardToWorldOffset(org.bukkit.util.Vector offset, Clipboard clipboard); } diff --git a/modules/api/src/main/java/net/countercraft/movecraft/craft/Craft.java b/modules/api/src/main/java/net/countercraft/movecraft/craft/Craft.java index 3e4867cf1..640cb609c 100644 --- a/modules/api/src/main/java/net/countercraft/movecraft/craft/Craft.java +++ b/modules/api/src/main/java/net/countercraft/movecraft/craft/Craft.java @@ -69,7 +69,7 @@ public abstract class Craft { private int numMoves; @NotNull private final Map phaseBlocks = new HashMap<>(); @NotNull private final HashMap crewSigns = new HashMap<>(); - private String uniqueName = ""; + @NotNull private String uniqueName = ""; public Craft(@NotNull CraftType type, @NotNull World world) { this.type = type; @@ -416,11 +416,11 @@ public Map getCrewSigns(){ return crewSigns; } + @NotNull public String getUniqueName(){ return uniqueName; } public void setUniqueName(String uniqueName){ this.uniqueName = uniqueName; - } } \ No newline at end of file diff --git a/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java b/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java index e778f976d..91fb8ec5c 100644 --- a/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java +++ b/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java @@ -109,10 +109,7 @@ public CraftType(File f) { craftName = (String) data.get("name"); maxSize = integerFromObject(data.get("maxSize")); minSize = integerFromObject(data.get("minSize")); -// allowedBlocks = ((ArrayList ) data.get( "allowedBlocks" )).toArray( new Integer[1] ); allowedBlocks = materialMapFromObject(data.get("allowedBlocks")); - //Collections.sort(allowedBlocks); - forbiddenBlocks = materialMapFromObject(data.get("forbiddenBlocks")); forbiddenSignStrings = stringListFromObject(data.get("forbiddenSignStrings")); if (data.containsKey("canFly")) { @@ -401,7 +398,11 @@ public CraftType(File f) { } } if(!blockedByWater){ - passthroughBlocks.add(Settings.IsLegacy ? Material.STATIONARY_WATER : Material.WATER); + passthroughBlocks.add(Material.WATER); + if (Settings.IsLegacy){ + passthroughBlocks.add(Material.STATIONARY_WATER); + } + } if (data.containsKey("allowVerticalTakeoffAndLanding")) { allowVerticalTakeoffAndLanding = (Boolean) data.get("allowVerticalTakeoffAndLanding"); diff --git a/modules/v1_10_R1/src/main/java/net/countercraft/movecraft/compat/v1_10_R1/IMovecraftRepair.java b/modules/v1_10_R1/src/main/java/net/countercraft/movecraft/compat/v1_10_R1/IMovecraftRepair.java index bcd6ae614..82ce7310b 100644 --- a/modules/v1_10_R1/src/main/java/net/countercraft/movecraft/compat/v1_10_R1/IMovecraftRepair.java +++ b/modules/v1_10_R1/src/main/java/net/countercraft/movecraft/compat/v1_10_R1/IMovecraftRepair.java @@ -442,6 +442,10 @@ public Vector getDistanceFromSignToLowestPoint(Clipboard clipboard, String repai } return returnDistance; } + @Override + public org.bukkit.util.Vector getDistanceFromClipboardToWorldOffset(org.bukkit.util.Vector offset, Clipboard clipboard) { + return new org.bukkit.util.Vector(offset.getBlockX() - clipboard.getMinimumPoint().getBlockX(), offset.getBlockY() - clipboard.getMinimumPoint().getBlockY(), offset.getBlockZ() - clipboard.getMinimumPoint().getBlockZ()); + } private Set baseBlocksFromCraft(Craft craft){ HashSet returnSet = new HashSet<>(); @@ -474,4 +478,5 @@ private Set baseBlocksFromAssaultRegion(Vector minPos, Vector maxPos, return returnSet; } + } diff --git a/modules/v1_11_R1/src/main/java/net/countercraft/movecraft/compat/v1_11_R1/IMovecraftRepair.java b/modules/v1_11_R1/src/main/java/net/countercraft/movecraft/compat/v1_11_R1/IMovecraftRepair.java index cd0fa2a70..cea439f96 100644 --- a/modules/v1_11_R1/src/main/java/net/countercraft/movecraft/compat/v1_11_R1/IMovecraftRepair.java +++ b/modules/v1_11_R1/src/main/java/net/countercraft/movecraft/compat/v1_11_R1/IMovecraftRepair.java @@ -443,6 +443,11 @@ public Vector getDistanceFromSignToLowestPoint(Clipboard clipboard, String repai return returnDistance; } + @Override + public org.bukkit.util.Vector getDistanceFromClipboardToWorldOffset(org.bukkit.util.Vector offset, Clipboard clipboard) { + return new org.bukkit.util.Vector(offset.getBlockX() - clipboard.getMinimumPoint().getBlockX(), offset.getBlockY() - clipboard.getMinimumPoint().getBlockY(), offset.getBlockZ() - clipboard.getMinimumPoint().getBlockZ()); + } + private Set baseBlocksFromCraft(Craft craft){ HashSet returnSet = new HashSet<>(); HashHitBox hitBox = craft.getHitBox(); diff --git a/modules/v1_12_R1/src/main/java/net/countercraft/movecraft/compat/v1_12_R1/IMovecraftRepair.java b/modules/v1_12_R1/src/main/java/net/countercraft/movecraft/compat/v1_12_R1/IMovecraftRepair.java index 32f95558b..93fae70e6 100644 --- a/modules/v1_12_R1/src/main/java/net/countercraft/movecraft/compat/v1_12_R1/IMovecraftRepair.java +++ b/modules/v1_12_R1/src/main/java/net/countercraft/movecraft/compat/v1_12_R1/IMovecraftRepair.java @@ -465,6 +465,11 @@ public Vector getDistanceFromSignToLowestPoint(Clipboard clipboard, String repai return returnDistance; } + @Override + public org.bukkit.util.Vector getDistanceFromClipboardToWorldOffset(org.bukkit.util.Vector offset, Clipboard clipboard) { + return new org.bukkit.util.Vector(offset.getBlockX() - clipboard.getMinimumPoint().getBlockX(), offset.getBlockY() - clipboard.getMinimumPoint().getBlockY(), offset.getBlockZ() - clipboard.getMinimumPoint().getBlockZ()); + } + private Set baseBlocksFromCraft(Craft craft){ HashSet returnSet = new HashSet<>(); HashHitBox hitBox = craft.getHitBox(); diff --git a/modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/IMovecraftRepair.java b/modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/IMovecraftRepair.java index 87fdff157..d4de07990 100644 --- a/modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/IMovecraftRepair.java +++ b/modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/IMovecraftRepair.java @@ -128,4 +128,10 @@ public long getNumDiffBlocks(String s) { public Vector getDistanceFromSignToLowestPoint(Clipboard clipboard, String s) { return null; } + + + @Override + public org.bukkit.util.Vector getDistanceFromClipboardToWorldOffset(org.bukkit.util.Vector offset, Clipboard clipboard) { + return new org.bukkit.util.Vector(offset.getBlockX() - clipboard.getMinimumPoint().getBlockX(), offset.getBlockY() - clipboard.getMinimumPoint().getBlockY(), offset.getBlockZ() - clipboard.getMinimumPoint().getBlockZ()); + } } From c0cd9e0fc3581bb77310a235f8ca1718fe1906a2 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Sat, 16 Feb 2019 02:18:30 +0100 Subject: [PATCH 007/304] fixing bugs and adding "chemical weapons" aka ability fo apply potion effects around explosions from weapon craft types. --- modules/Movecraft/pom.xml | 7 +++ .../net/countercraft/movecraft/Movecraft.java | 24 +++++++++- .../async/translation/TranslationTask.java | 5 +++ .../compatmanager/DeadboltCompatManager.java | 16 +++++++ .../movecraft/listener/PlayerListener.java | 5 +++ .../update/EntityUpdateCommand.java | 3 +- .../update/ExplosionUpdateCommand.java | 25 +++++------ .../update/PotionEffectsUpdateCommand.java | 32 ++++++++++++++ .../movecraft/utils/WorldguardUtils.java | 31 +++++++++++++ .../movecraft/craft/CraftType.java | 44 +++++++++++++++++++ .../compat/v1_13_R2/IWorldHandler.java | 14 ++---- 11 files changed, 179 insertions(+), 27 deletions(-) create mode 100644 modules/Movecraft/src/main/java/net/countercraft/movecraft/compatmanager/DeadboltCompatManager.java create mode 100644 modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/PotionEffectsUpdateCommand.java diff --git a/modules/Movecraft/pom.xml b/modules/Movecraft/pom.xml index 91276bf26..d4e72d8fb 100644 --- a/modules/Movecraft/pom.xml +++ b/modules/Movecraft/pom.xml @@ -146,6 +146,13 @@ system ${project.basedir}/../../libs/MassiveCore.jar + + com.daemitus + Deadbolt + 1.0 + system + ${project.basedir}/../../libs/Deadbolt-1.0-SNAPSHOT.jar + org.jetbrains annotations-java5 diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java index d0b812050..973700840 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java @@ -18,6 +18,7 @@ package net.countercraft.movecraft; import at.pavlov.cannons.Cannons; +import com.daemitus.deadbolt.DeadboltPlugin; import com.earth2me.essentials.Essentials; import com.massivecraft.factions.Factions; import com.mewin.WGCustomFlags.WGCustomFlagsPlugin; @@ -49,6 +50,7 @@ import org.bukkit.plugin.java.JavaPlugin; import org.yaml.snakeyaml.Yaml; + import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; @@ -71,6 +73,7 @@ public class Movecraft extends JavaPlugin { private static Towny townyPlugin = null; private static Essentials essentialsPlugin = null; private static Factions factionsPlugin; + private static DeadboltPlugin deadboltPlugin; /*public HashMap blockFadeTimeMap = new HashMap<>(); public HashMap blockFadeTypeMap = new HashMap<>(); public HashMap blockFadeWaterMap = new HashMap<>(); @@ -108,7 +111,7 @@ public void onEnable() { Settings.IsLegacy = false; } // Read in config - if (Settings.IsLegacy) { + if (!Settings.IsLegacy) { this.saveDefaultConfig(); } else { File configFile = new File(Movecraft.getInstance().getDataFolder().getAbsolutePath() + "/config.yml"); @@ -227,14 +230,16 @@ public void onEnable() { Settings.SiegeEnable = false; Settings.AssaultEnable = false; Settings.RestrictSiBsToRegions = false; + worldGuardPlugin = null; } else { logger.log(Level.INFO, "Found a compatible version of WorldGuard. Enabling WorldGuard integration"); Settings.WorldGuardBlockMoveOnBuildPerm = getConfig().getBoolean("WorldGuardBlockMoveOnBuildPerm", false); Settings.WorldGuardBlockSinkOnPVPPerm = getConfig().getBoolean("WorldGuardBlockSinkOnPVPPerm", false); logger.log(Level.INFO, "Settings: WorldGuardBlockMoveOnBuildPerm - {0}, WorldGuardBlockSinkOnPVPPerm - {1}", new Object[]{Settings.WorldGuardBlockMoveOnBuildPerm, Settings.WorldGuardBlockSinkOnPVPPerm}); getServer().getPluginManager().registerEvents(new WorldGuardCompatManager(), this); + worldGuardPlugin = (WorldGuardPlugin) wGPlugin; } - worldGuardPlugin = (WorldGuardPlugin) wGPlugin; + //load up WorldEdit if it's present Plugin wEPlugin = getServer().getPluginManager().getPlugin("WorldEdit"); @@ -333,6 +338,17 @@ public void onEnable() { if (factionsPlugin == null){ logger.info("Movecraft did not find a compatible version of Factions. Disabling Factions integration"); } + // Deadbolt + Plugin tempDeadboltPlugin = getServer().getPluginManager().getPlugin("Deadbolt"); + if (tempDeadboltPlugin != null){ + if (tempDeadboltPlugin instanceof DeadboltPlugin){ + deadboltPlugin = (DeadboltPlugin) tempDeadboltPlugin; + logger.info("Movecraft found a compatible version of Deadbolt. Enabling Deadbolt integration"); + } + } + if (deadboltPlugin == null){ + logger.info("Movecraft did not find a compatible version of Deadbolt. Disabling Deadbolt integration"); + } // and now Vault if (getServer().getPluginManager().getPlugin("Vault") != null) { RegisteredServiceProvider rsp = getServer().getServicesManager().getRegistration(Economy.class); @@ -533,5 +549,9 @@ public RepairManager getRepairManager() { public Factions getFactionsPlugin(){ return factionsPlugin; } + + public DeadboltPlugin getDeadboltPlugin(){ + return deadboltPlugin; + } } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java index d1ce4a16d..8df7498ae 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java @@ -27,6 +27,7 @@ import org.bukkit.inventory.Inventory; import org.bukkit.inventory.InventoryHolder; import org.bukkit.inventory.ItemStack; +import org.bukkit.potion.PotionEffect; import org.bukkit.scheduler.BukkitRunnable; import java.util.*; @@ -206,9 +207,13 @@ protected void execute() { }*/ explosionKey = explosionForce; Location loc = location.toBukkit(craft.getW()); + int potEffRange = craft.getType().getEffectRange(); + Set potionEffects = craft.getType().getPotionEffectsToApply(); if (!loc.getBlock().getType().equals(Material.AIR)) { updates.add(new ExplosionUpdateCommand(loc, explosionKey)); collisionExplosion = true; + if (potEffRange != 0 && !potionEffects.isEmpty()) + updates.add(new PotionEffectsUpdateCommand(loc,potEffRange,potionEffects)); } if (craft.getType().getFocusedExplosion()) { // don't handle any further collisions if it is set to focusedexplosion break; diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/compatmanager/DeadboltCompatManager.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/compatmanager/DeadboltCompatManager.java new file mode 100644 index 000000000..c17cc416b --- /dev/null +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/compatmanager/DeadboltCompatManager.java @@ -0,0 +1,16 @@ +package net.countercraft.movecraft.compatmanager; + +import net.countercraft.movecraft.events.SignTranslateEvent; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; + +public class DeadboltCompatManager implements Listener { + private static String PRIVATE = "[private]"; + @EventHandler + public void onSignTranslate(SignTranslateEvent event){ + if (!event.getLine(0).equalsIgnoreCase(PRIVATE)){ + return; + } + + } +} diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/PlayerListener.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/PlayerListener.java index 9c030ecab..95cd45968 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/PlayerListener.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/PlayerListener.java @@ -30,6 +30,7 @@ import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; import org.bukkit.event.entity.EntityDamageByEntityEvent; +import org.bukkit.event.entity.PlayerDeathEvent; import org.bukkit.event.player.PlayerJoinEvent; import org.bukkit.event.player.PlayerMoveEvent; import org.bukkit.event.player.PlayerQuitEvent; @@ -176,6 +177,10 @@ public void onPlayerDeath(EntityDamageByEntityEvent e) { // changed to death so } } + public void onPDeath(PlayerDeathEvent event){ + + } + @EventHandler public void onPlayerMove(PlayerMoveEvent event) { final Craft c = CraftManager.getInstance().getCraftByPlayer(event.getPlayer()); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/EntityUpdateCommand.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/EntityUpdateCommand.java index 65dd0cd92..e416dd7b2 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/EntityUpdateCommand.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/EntityUpdateCommand.java @@ -18,6 +18,7 @@ package net.countercraft.movecraft.mapUpdater.update; import net.countercraft.movecraft.Movecraft; +import net.countercraft.movecraft.config.Settings; import org.bukkit.Location; import org.bukkit.entity.Entity; import org.bukkit.entity.Player; @@ -54,7 +55,7 @@ public void doUpdate() { Location playerLoc = entity.getLocation(); entity.teleport(new Location(entity.getWorld(), x + playerLoc.getX(),y + playerLoc.getY(),z + playerLoc.getZ(),yaw + playerLoc.getYaw(),pitch + playerLoc.getPitch())); return; - } + } Movecraft.getInstance().getWorldHandler().addPlayerLocation((Player) entity,x,y,z,yaw,pitch); } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/ExplosionUpdateCommand.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/ExplosionUpdateCommand.java index b831ddc44..19d1baae0 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/ExplosionUpdateCommand.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/ExplosionUpdateCommand.java @@ -8,10 +8,20 @@ import com.sk89q.worldguard.protection.regions.RegionQuery; import net.countercraft.movecraft.Movecraft; import net.countercraft.movecraft.config.Settings; +import net.countercraft.movecraft.utils.WorldguardUtils; import org.bukkit.Location; +import org.bukkit.entity.Entity; +import org.bukkit.entity.LivingEntity; +import org.bukkit.potion.PotionEffect; +import org.bukkit.potion.PotionEffectType; +import org.bukkit.util.Vector; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; import java.util.Objects; + public class ExplosionUpdateCommand extends UpdateCommand { private final Location explosionLocation; private final float explosionStrength; @@ -43,20 +53,9 @@ public void doUpdate() { private void createExplosion(Location loc, float explosionPower) { if (Movecraft.getInstance().getWorldGuardPlugin() != null) { - ApplicableRegionSet set; - if (Settings.IsLegacy) { - set = Movecraft.getInstance().getWorldGuardPlugin().getRegionManager(loc.getWorld()).getApplicableRegions(loc); - if (!set.allows(DefaultFlag.OTHER_EXPLOSION)) { - return; - } - } else { - RegionQuery query = WorldGuard.getInstance().getPlatform().getRegionContainer().createQuery(); - com.sk89q.worldedit.world.World weWorld = new BukkitWorld(loc.getWorld()); - com.sk89q.worldedit.util.Location wgLoc = new com.sk89q.worldedit.util.Location(weWorld, loc.getBlockX(), loc.getBlockY(), loc.getBlockZ()); - set = query.getApplicableRegions(wgLoc); - + if (!WorldguardUtils.explosionsPermitted(loc)){ + return; } - } loc.getWorld().createExplosion(loc.getX() + 0.5, loc.getY() + 0.5, loc.getZ() + 0.5, explosionPower); } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/PotionEffectsUpdateCommand.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/PotionEffectsUpdateCommand.java new file mode 100644 index 000000000..96babf8e7 --- /dev/null +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/PotionEffectsUpdateCommand.java @@ -0,0 +1,32 @@ +package net.countercraft.movecraft.mapUpdater.update; + +import org.bukkit.Location; +import org.bukkit.entity.Entity; +import org.bukkit.entity.LivingEntity; +import org.bukkit.potion.PotionEffect; +import org.bukkit.potion.PotionEffectType; + +import java.util.*; + +public class PotionEffectsUpdateCommand extends UpdateCommand { + + private final Set livingEntities = new HashSet<>(); + private final Set potionEffects; + public PotionEffectsUpdateCommand(Location loc, int effectRange, Set potionEffects){ + this.potionEffects = potionEffects; + for (Entity entity : loc.getWorld().getNearbyEntities(loc,effectRange,effectRange,effectRange)){ + if (!(entity instanceof LivingEntity)){ + continue; + } + livingEntities.add((LivingEntity) entity); + } + } + @Override + public void doUpdate() { + for (LivingEntity entity : livingEntities){ + for (PotionEffect effect : potionEffects){ + entity.addPotionEffect(effect); + } + } + } +} diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/WorldguardUtils.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/WorldguardUtils.java index f61b9d6f5..741414b08 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/WorldguardUtils.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/WorldguardUtils.java @@ -1,9 +1,18 @@ package net.countercraft.movecraft.utils; +import com.sk89q.worldedit.bukkit.BukkitWorld; +import com.sk89q.worldguard.WorldGuard; +import com.sk89q.worldguard.protection.ApplicableRegionSet; +import com.sk89q.worldguard.protection.flags.DefaultFlag; +import com.sk89q.worldguard.protection.flags.Flags; +import com.sk89q.worldguard.protection.flags.StateFlag; import com.sk89q.worldguard.protection.regions.ProtectedRegion; +import com.sk89q.worldguard.protection.regions.RegionQuery; import net.countercraft.movecraft.Movecraft; import net.countercraft.movecraft.MovecraftLocation; +import net.countercraft.movecraft.config.Settings; import org.bukkit.Bukkit; +import org.bukkit.Location; import org.bukkit.OfflinePlayer; import org.bukkit.World; import org.bukkit.entity.Player; @@ -44,4 +53,26 @@ public static String getRegionOwnerList(ProtectedRegion tRegion) { public static boolean canBuild(World world, MovecraftLocation location, Player player){ return Movecraft.getInstance().getWorldGuardPlugin().canBuild(player, location.toBukkit(world)); } + + public static boolean explosionsPermitted(Location loc){ + ApplicableRegionSet set; + if (Settings.IsLegacy) { + set = Movecraft.getInstance().getWorldGuardPlugin().getRegionManager(loc.getWorld()).getApplicableRegions(loc); + if (!set.allows(DefaultFlag.OTHER_EXPLOSION)) { + return false; + } + } else { + RegionQuery query = WorldGuard.getInstance().getPlatform().getRegionContainer().createQuery(); + com.sk89q.worldedit.world.World weWorld = new BukkitWorld(loc.getWorld()); + com.sk89q.worldedit.util.Location wgLoc = new com.sk89q.worldedit.util.Location(weWorld, loc.getBlockX(), loc.getBlockY(), loc.getBlockZ()); + set = query.getApplicableRegions(wgLoc); + for (ProtectedRegion region : set.getRegions()){ + if (region.getFlag(Flags.OTHER_EXPLOSION) == StateFlag.State.DENY){ + return false; + } + } + + } + return true; + } } diff --git a/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java b/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java index 91fb8ec5c..e0efb451a 100644 --- a/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java +++ b/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java @@ -20,6 +20,8 @@ import net.countercraft.movecraft.config.Settings; import org.bukkit.Material; import org.bukkit.block.Block; +import org.bukkit.potion.PotionEffect; +import org.bukkit.potion.PotionEffectType; import org.jetbrains.annotations.NotNull; import org.yaml.snakeyaml.Yaml; @@ -94,6 +96,8 @@ final public class CraftType { @NotNull private final List harvestBlocks; @NotNull private final List harvesterBladeBlocks; @NotNull private final Set passthroughBlocks; + @NotNull private final int effectRange; + @NotNull private final Set potionEffectsToApply; public CraftType(File f) { final Map data; @@ -426,6 +430,8 @@ public CraftType(File f) { dynamicFlyBlock = null; } chestPenalty = data.containsKey("chestPenalty") ? doubleFromObject(data.get("chestPenalty")) : 0d; + effectRange = data.containsKey("effectRange") ? integerFromObject(data.get("effectRange")) : 0; + potionEffectsToApply = data.containsKey("potionEffectsToApply") ? effectListFromObject(data.get("potionEffectsToApply")) : Collections.emptySet(); } private Integer integerFromObject(Object obj) { @@ -449,6 +455,35 @@ private Material materialFromObject(Object obj){ } } + private Set effectListFromObject(Object obj){ + Map objMap = (Map) obj; + Set ret = new HashSet<>(); + for (Object o : objMap.keySet()){ + PotionEffectType effect = null; + int duration = 0; + int amplifier = 1; + if (o instanceof String){ + String string = (String) o; + effect = PotionEffectType.getByName(string); + } + Map subObjMap = (Map) objMap.get(o); + for (Object i : subObjMap.keySet()){ + String str = (String) i; + int integer = (int) subObjMap.get(i); + if (str.equals("duration")){ + duration = integer; + } + if (str.equals("amplifier")){ + amplifier = integer; + } + } + if (effect == null){ + continue; + } + ret.add(new PotionEffect(effect,duration,amplifier)); + } + return ret; + } private int[] blockIDListFromObject(Object obj) { ArrayList returnList = new ArrayList<>(); @@ -1008,6 +1043,15 @@ public boolean getOnlyMovePlayers() { return onlyMovePlayers; } + @NotNull + public Set getPotionEffectsToApply() { + return potionEffectsToApply; + } + + public int getEffectRange() { + return effectRange; + } + private class TypeNotFoundException extends RuntimeException { public TypeNotFoundException(String s) { super(s); diff --git a/modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/IWorldHandler.java b/modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/IWorldHandler.java index eb4baab40..ed1045e26 100644 --- a/modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/IWorldHandler.java +++ b/modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/IWorldHandler.java @@ -52,17 +52,9 @@ public IWorldHandler() { @Override public void addPlayerLocation(Player player, double x, double y, double z, float yaw, float pitch){ - EntityPlayer ePlayer = ((CraftPlayer) player).getHandle(); - if(internalTeleportMH == null) { - //something went wrong - super.addPlayerLocation(player, x, y, z, yaw, pitch); - return; - } - try { - internalTeleportMH.invoke(ePlayer.playerConnection, (player.getLocation().getX() + x), (player.getLocation().getY() + y), (player.getLocation().getZ() + z), yaw, pitch, EnumSet.allOf(PacketPlayOutPosition.EnumPlayerTeleportFlags.class)); - } catch (Throwable throwable) { - throwable.printStackTrace(); - } + //Due to a bug in the 1.13 NMS method, use Bukkit method instead + Location playerLoc = player.getLocation(); + player.teleport(new Location(player.getWorld(), x + playerLoc.getX(),y + playerLoc.getY(),z + playerLoc.getZ(),yaw + playerLoc.getYaw(),pitch + playerLoc.getPitch())); } @Override From e97e0e4545e5846ee5d414ee75ffa6f7e4f3f6ac Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Mon, 18 Feb 2019 03:23:12 +0100 Subject: [PATCH 008/304] Movecraft now has a working repair system for 1.13 (not FAWE compatible yet) --- modules/FAWEUtils/pom.xml | 71 ++++++ .../movecraft/utils/FAWEUtils.java | 64 +++++ modules/Movecraft/pom.xml | 11 +- .../net/countercraft/movecraft/Movecraft.java | 10 + .../async/rotation/RotationTask.java | 2 +- .../update/PotionEffectsUpdateCommand.java | 1 + .../update/WorldEditUpdateCommand.java | 153 ++++++++---- .../movecraft/sign/RepairSign.java | 61 ++++- .../movecraft/utils/SignUtils.java | 5 + .../movecraft/utils/WorldEditUtils.java | 33 +++ .../localisation/movecraftlang_ar.properties | 2 +- .../movecraft/MovecraftRepair.java | 8 +- .../movecraft/RepairLocation.java | 20 ++ .../movecraft/config/Settings.java | 1 + .../movecraft/craft/CraftType.java | 15 +- .../compat/v1_10_R1/IMovecraftRepair.java | 25 +- .../compat/v1_11_R1/IMovecraftRepair.java | 25 +- .../compat/v1_12_R1/IMovecraftRepair.java | 27 ++- modules/v1_13_R2/pom.xml | 7 + .../compat/v1_13_R2/IMovecraftRepair.java | 227 ++++++++++++++++-- .../compat/v1_13_R2/IWorldHandler.java | 7 - pom.xml | 2 + 22 files changed, 653 insertions(+), 124 deletions(-) create mode 100644 modules/FAWEUtils/pom.xml create mode 100644 modules/FAWEUtils/src/main/java/net/countercraft/movecraft/utils/FAWEUtils.java create mode 100644 modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/WorldEditUtils.java create mode 100644 modules/api/src/main/java/net/countercraft/movecraft/RepairLocation.java diff --git a/modules/FAWEUtils/pom.xml b/modules/FAWEUtils/pom.xml new file mode 100644 index 000000000..f1c61cba8 --- /dev/null +++ b/modules/FAWEUtils/pom.xml @@ -0,0 +1,71 @@ + + + + movecraft-parent + net.countercraft + parent + ../../pom.xml + + 4.0.0 + movecraft-FAWEUtils + jar + Movecraft-FAWEUtils + FAWEUtils + http://github.com/eirikh1996/Movecraft + + + + + fawe-repo + http://ci.athion.net/job/FastAsyncWorldEdit/ws/mvn/ + + + + + com.boydti + fawe-api + latest + + + net.countercraft + movecraft-api + API + jar + + + org.jetbrains + annotations-java5 + RELEASE + + + + src/main/java + + + org.apache.maven.plugins + maven-compiler-plugin + 3.7.0 + + + net/countercraft/movecraft/utils/** + + 1.8 + 1.8 + + + + org.apache.maven.plugins + maven-jar-plugin + 2.4 + + + net/countercraft/movecraft/utils/** + + + + + + + \ No newline at end of file diff --git a/modules/FAWEUtils/src/main/java/net/countercraft/movecraft/utils/FAWEUtils.java b/modules/FAWEUtils/src/main/java/net/countercraft/movecraft/utils/FAWEUtils.java new file mode 100644 index 000000000..8c2a774ec --- /dev/null +++ b/modules/FAWEUtils/src/main/java/net/countercraft/movecraft/utils/FAWEUtils.java @@ -0,0 +1,64 @@ +package net.countercraft.movecraft.utils; + +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.bukkit.BukkitWorld; +import com.sk89q.worldedit.extent.Extent; +import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard; +import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormat; +import com.sk89q.worldedit.extent.clipboard.io.ClipboardWriter; +import com.sk89q.worldedit.function.mask.ExistingBlockMask; +import com.sk89q.worldedit.function.operation.ForwardExtentCopy; +import com.sk89q.worldedit.function.operation.Operations; +import com.sk89q.worldedit.regions.CuboidRegion; +import com.sk89q.worldedit.world.registry.WorldData; +import net.countercraft.movecraft.craft.Craft; +import org.bukkit.World; +import org.bukkit.block.Sign; +import org.bukkit.plugin.Plugin; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.OutputStream; + +public class FAWEUtils { + public static boolean faweSaveCraftRepairState(Craft craft, Sign sign, Plugin plugin, String s) { + HashHitBox hitBox = craft.getHitBox(); + File saveDirectory = new File(plugin.getDataFolder(), "CraftRepairStates"); + World world = craft.getW(); + if (!saveDirectory.exists()) { + saveDirectory.mkdirs(); + } + Vector minPos = new Vector(hitBox.getMinX(), hitBox.getMinY(), hitBox.getMinZ()); + Vector maxPos = new Vector(hitBox.getMaxX(), hitBox.getMaxY(), hitBox.getMaxZ()); + CuboidRegion region = new CuboidRegion(minPos, maxPos); + com.sk89q.worldedit.world.World weWorld = new BukkitWorld(world); + BlockArrayClipboard clipboard = new BlockArrayClipboard(region); + Extent source = WorldEdit.getInstance().getEditSessionFactory().getEditSession(weWorld, -1); + Extent destination = clipboard; + ForwardExtentCopy copy = new ForwardExtentCopy(source, region, clipboard.getOrigin(), destination, minPos); + ExistingBlockMask mask = new ExistingBlockMask(source); + copy.setSourceMask(mask); + WorldData data = weWorld.getWorldData(); + try { + Operations.complete(copy); + } catch (WorldEditException e) { + e.printStackTrace(); + return false; + } + File schematicFile = new File(saveDirectory, s + ".schematic"); + try { + OutputStream output = new FileOutputStream(schematicFile); + ClipboardWriter writer = ClipboardFormat.SCHEMATIC.getWriter(output); + writer.write(clipboard, data); + writer.close(); + } catch (IOException e) { + e.printStackTrace(); + return false; + } + + return true; + } +} diff --git a/modules/Movecraft/pom.xml b/modules/Movecraft/pom.xml index d4e72d8fb..901744017 100644 --- a/modules/Movecraft/pom.xml +++ b/modules/Movecraft/pom.xml @@ -35,6 +35,11 @@ + + com.sk89q.worldedit + worldedit-bukkit + 7.0.0-SNAPSHOT + net.countercraft movecraft-v1_13_R2 @@ -81,11 +86,7 @@ worldedit LATEST - - com.sk89q.worldedit - worldedit-bukkit - 7.0.0-SNAPSHOT - + at.pavlov Cannons diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java index 973700840..a1dacf56f 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java @@ -261,12 +261,22 @@ public void onEnable() { this.getLogger().severe("Could not find a compatible repair class. Disabling repair function"); Settings.RepairTicksPerBlock = 0; } + if (!Settings.IsLegacy) { + //Check if FAWE us used + try { + Class.forName("com.boydti.fawe.bukkit.FaweBukkit"); + Settings.UseFAWE = true; + } catch (ClassNotFoundException e) { + Settings.UseFAWE = false; + } + } } worldEditPlugin = (WorldEditPlugin) wEPlugin; + // next is Cannons Plugin plug = getServer().getPluginManager().getPlugin("Cannons"); if (plug != null && plug instanceof Cannons) { diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/rotation/RotationTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/rotation/RotationTask.java index 6258781e3..392198d91 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/rotation/RotationTask.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/rotation/RotationTask.java @@ -108,7 +108,7 @@ protected void execute() { Block b = getCraft().getW().getBlockAt(bTest.getX(), bTest.getY(), bTest.getZ()); if (b.getType() == Material.FURNACE) { InventoryHolder inventoryHolder = (InventoryHolder) b.getState(); - if ((!Settings.IsLegacy ? (inventoryHolder.getInventory().contains(Material.COAL) || inventoryHolder.getInventory().contains(Material.CHARCOAL)) : (inventoryHolder.getInventory().contains(Material.COAL)) || inventoryHolder.getInventory().contains(Material.COAL_BLOCK))) { + if ((!Settings.IsLegacy ? (inventoryHolder.getInventory().contains(Material.COAL) || inventoryHolder.getInventory().contains(Material.CHARCOAL)) || inventoryHolder.getInventory().contains(Material.COAL_BLOCK): (inventoryHolder.getInventory().contains(Material.COAL)) || inventoryHolder.getInventory().contains(Material.COAL_BLOCK))) { fuelHolder = b; } } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/PotionEffectsUpdateCommand.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/PotionEffectsUpdateCommand.java index 96babf8e7..b1da224a1 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/PotionEffectsUpdateCommand.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/PotionEffectsUpdateCommand.java @@ -25,6 +25,7 @@ public PotionEffectsUpdateCommand(Location loc, int effectRange, Set 0) { + ItemStack fireItems = new ItemStack(Material.FIRE_CHARGE, numFireCharges); + disp.getInventory().addItem(fireItems); + } + if (numTNT > 0) { + ItemStack TNTItems = new ItemStack(Material.TNT, numTNT); + disp.getInventory().addItem(TNTItems); + } + if (numWater > 0) { + ItemStack WaterItems = new ItemStack(Material.WATER_BUCKET, numWater); + disp.getInventory().addItem(WaterItems); + } + } + if (BukkitAdapter.adapt(worldEdit7BaseBlock.getBlockType()).equals(Material.SIGN)||BukkitAdapter.adapt(worldEdit7BaseBlock.getBlockType()).equals(Material.WALL_SIGN)){ + BlockState state = block.getState(); + if (state instanceof Sign) { + Sign s = (Sign) state; + CompoundTag nbtData = worldEdit7BaseBlock.getNbtData(); + //first line + String firstLine = nbtData.getString("Text1"); + firstLine = firstLine.substring(2); + if (firstLine.substring(0, 5).equalsIgnoreCase("extra")){ + firstLine = firstLine.substring(17); + String[] parts = firstLine.split("\""); + firstLine = parts[0]; + } else { + firstLine = ""; + } + //second line + String secondLine = nbtData.getString("Text2"); + secondLine = secondLine.substring(2); + if (secondLine.substring(0, 5).equalsIgnoreCase("extra")){ + secondLine = secondLine.substring(17); + String[] parts = secondLine.split("\""); + secondLine = parts[0]; + } else { + secondLine = ""; + } + //third line + String thirdLine = nbtData.getString("Text3"); + thirdLine = thirdLine.substring(2); + if (thirdLine.substring(0, 5).equalsIgnoreCase("extra")){ + thirdLine = thirdLine.substring(17); + String[] parts = thirdLine.split("\""); + thirdLine = parts[0]; + } else { + thirdLine = ""; + } + //fourth line + String fourthLine = nbtData.getString("Text4"); + fourthLine = fourthLine.substring(2); + if (fourthLine.substring(0, 5).equalsIgnoreCase("extra")){ + fourthLine = fourthLine.substring(17); + String[] parts = fourthLine.split("\""); + fourthLine = parts[0]; + } else { + fourthLine = ""; + } + String[] lines = new String[4]; + if (firstLine.equalsIgnoreCase("\\\\ || /")){ + firstLine = "\\ || /"; + secondLine = "== =="; + thirdLine = "/ || \\"; + } + lines[0] = firstLine; + lines[1] = secondLine; + lines[2] = thirdLine; + lines[3] = fourthLine; + for (int line = 0; line < lines.length; line++) { + s.setLine(line, lines[line]); + } + s.update(false, false); + } } - Furnace furnace = (Furnace) world.getBlockAt(location.getX(),location.getY(),location.getZ()).getState(); - }*/ + } } } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RepairSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RepairSign.java index 5e0b1b52a..2be37fec6 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RepairSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RepairSign.java @@ -1,8 +1,9 @@ package net.countercraft.movecraft.sign; -import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.blocks.BaseBlock; +import com.sk89q.worldedit.bukkit.BukkitAdapter; import com.sk89q.worldedit.extent.clipboard.Clipboard; +import com.sk89q.worldedit.world.block.BlockState; import com.sk89q.worldedit.world.block.BlockStateHolder; import net.countercraft.movecraft.Movecraft; import net.countercraft.movecraft.MovecraftLocation; @@ -17,9 +18,11 @@ import net.countercraft.movecraft.repair.RepairManager; import net.countercraft.movecraft.repair.RepairUtils; import net.countercraft.movecraft.utils.LegacyUtils; +import net.countercraft.movecraft.utils.WorldEditUtils; import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.Material; +import org.bukkit.Material.*; import org.bukkit.World; import org.bukkit.block.Block; import org.bukkit.block.Sign; @@ -31,6 +34,7 @@ import org.bukkit.event.player.PlayerInteractEvent; import org.bukkit.inventory.InventoryHolder; import org.bukkit.inventory.ItemStack; +import org.bukkit.util.Vector; import java.util.*; @@ -38,8 +42,35 @@ public class RepairSign implements Listener{ private String HEADER = "Repair:"; private HashMap playerInteractTimeMap = new HashMap<>();//Players must be assigned by the UUID, or NullPointerExceptions are thrown private final Material[] fragileBlocks = new Material[]{ Material.TORCH, Material.LADDER, Material.WALL_SIGN, Material.LEVER, Material.STONE_BUTTON, LegacyUtils.TRAP_DOOR, Material.TRIPWIRE_HOOK, LegacyUtils.WOOD_BUTTON, Material.IRON_TRAPDOOR, }; - //final int[] fragileBlocks = new int[]{ 171, 323, 324, 330, 331, 356, 404}; + private static final Material[] wallBlocks; + static { + Set types = new HashSet<>(); + for (Material type : Material.values()){ + int index = 0; + boolean add = false; + if (type.name().startsWith("WALL_")) { + types.add(type); + } + if (type.name().contains("_WALL_")){ + types.add(type); + } + if (type.name().endsWith("_BUTTON")){ + types.add(type); + } + if (type.name().endsWith("_TRAPDOOR")){ + types.add(type); + } + } + Material[] typeArr = new Material[types.size()]; + int index = 0; + for (Material type : types){ + typeArr[index] = type; + index++; + } + + wallBlocks = typeArr; + } @EventHandler public void onSignChange(SignChangeEvent event){ if (!event.getLine(0).equalsIgnoreCase(HEADER)){ @@ -103,7 +134,10 @@ private void signLeftClick(PlayerInteractEvent event){ return; } MovecraftRepair movecraftRepair = Movecraft.getInstance().getMovecraftRepair(); - movecraftRepair.saveCraftRepairState(pCraft, sign, Movecraft.getInstance(), repairName); + if (movecraftRepair.saveCraftRepairState(pCraft, sign, Movecraft.getInstance(), repairName)) + event.getPlayer().sendMessage(I18nSupport.getInternationalisedString("State saved")); + else + event.getPlayer().sendMessage(I18nSupport.getInternationalisedString("Could not save file")); event.setCancelled(true); } @@ -142,7 +176,7 @@ private void signRightClick(PlayerInteractEvent event){ } } HashMap numMissingItems = movecraftRepair.getMissingBlocks(repairName); - HashSet locMissingBlocks = movecraftRepair.getMissingBlockLocations(repairName); + LinkedList locMissingBlocks = movecraftRepair.getMissingBlockLocations(repairName); int totalSize = locMissingBlocks.size() + pCraft.getHitBox().size(); if (secondClick){ @@ -208,16 +242,16 @@ private void signRightClick(PlayerInteractEvent event){ Bukkit.getLogger().info(event.getPlayer().getName() + " has begun a repair with the cost of " + String.valueOf(Cost)); final LinkedList updateCommands = new LinkedList<>(); final LinkedList updateCommandsFragileBlocks = new LinkedList<>(); - final Vector distToOffset = movecraftRepair.getDistanceFromSignToLowestPoint(clipboard, sign.getLine(1)); + final org.bukkit.util.Vector distToOffset = movecraftRepair.getDistanceFromSignToLowestPoint(clipboard, sign.getLine(1)); final org.bukkit.util.Vector offsetFromSign = new org.bukkit.util.Vector(sign.getLocation().getBlockX() - distToOffset.getBlockX(), sign.getLocation().getBlockY() - distToOffset.getBlockY(), sign.getLocation().getBlockZ() - distToOffset.getBlockZ()); final org.bukkit.util.Vector distance = movecraftRepair.getDistanceFromClipboardToWorldOffset(offsetFromSign, clipboard); - final TreeSet sortedLocMissingBlocks = new TreeSet<>(locMissingBlocks); - for (Vector cLoc : sortedLocMissingBlocks){ + while (!locMissingBlocks.isEmpty()){ + Vector cLoc = locMissingBlocks.pop(); MovecraftLocation moveLoc = new MovecraftLocation(cLoc.getBlockX() + distance.getBlockX(), cLoc.getBlockY() + distance.getBlockY(), cLoc.getBlockZ() + distance.getBlockZ()); //To avoid any issues during the repair, keep certain blocks in different linked lists if (Settings.IsLegacy) { - BaseBlock baseBlock = RepairUtils.getBlock(clipboard, cLoc); + BaseBlock baseBlock = RepairUtils.getBlock(clipboard, WorldEditUtils.toWeVector(cLoc)); if (Arrays.binarySearch(fragileBlocks, LegacyUtils.getMaterial(baseBlock.getType())) >= 0) { WorldEditUpdateCommand updateCommand = new WorldEditUpdateCommand(baseBlock, sign.getWorld(), moveLoc, LegacyUtils.getMaterial(baseBlock.getType()), (byte) baseBlock.getData()); updateCommandsFragileBlocks.add(updateCommand); @@ -226,8 +260,15 @@ private void signRightClick(PlayerInteractEvent event){ updateCommands.add(updateCommand); } } else { - BlockStateHolder bsHolder; - + com.sk89q.worldedit.world.block.BaseBlock bb = clipboard.getFullBlock(WorldEditUtils.toBlockVector(cLoc)); + Material type = BukkitAdapter.adapt(bb.getBlockType()); + if (Arrays.binarySearch(wallBlocks, type) >= 0){ + WorldEditUpdateCommand weUp = new WorldEditUpdateCommand(bb,sign.getWorld(),moveLoc, type); + updateCommandsFragileBlocks.add(weUp); + } else { + WorldEditUpdateCommand weUp = new WorldEditUpdateCommand(bb,sign.getWorld(),moveLoc, type); + updateCommands.add(weUp); + } } } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/SignUtils.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/SignUtils.java index b3d451426..bc3eeb50d 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/SignUtils.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/SignUtils.java @@ -1,5 +1,6 @@ package net.countercraft.movecraft.utils; +import org.bukkit.block.Block; import org.bukkit.block.BlockFace; import org.bukkit.block.Sign; import org.bukkit.material.MaterialData; @@ -14,4 +15,8 @@ public static BlockFace getFacing(Sign sign) { org.bukkit.material.Sign matSign = (org.bukkit.material.Sign) materialData; return matSign.getFacing(); } + + public static boolean isSign(Block block){ + return (block.getState() instanceof Sign); + } } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/WorldEditUtils.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/WorldEditUtils.java new file mode 100644 index 000000000..295ead35b --- /dev/null +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/WorldEditUtils.java @@ -0,0 +1,33 @@ +package net.countercraft.movecraft.utils; + +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.math.BlockVector3; + +import java.util.HashSet; +import java.util.Set; + +public class WorldEditUtils { + public static Vector toWeVector(org.bukkit.util.Vector bukkitVector){ + return new Vector(bukkitVector.getBlockX(),bukkitVector.getBlockY(),bukkitVector.getBlockZ()); + } + + public static BlockVector3 toBlockVector(org.bukkit.util.Vector bukkitVector){ + return BlockVector3.at(bukkitVector.getBlockX(),bukkitVector.getBlockY(),bukkitVector.getBlockZ()); + } + + public static HashSet toWeVectorSet(Set bukkitVectorSet){ + HashSet ret = new HashSet<>(); + for (org.bukkit.util.Vector bukkitVector : bukkitVectorSet){ + ret.add(toWeVector(bukkitVector)); + } + return ret; + } + + public static HashSet toBlockVectorSet(Set bukkitVectorSet){ + HashSet ret = new HashSet<>(); + for (org.bukkit.util.Vector bukkitVector : bukkitVectorSet){ + ret.add(toBlockVector(bukkitVector)); + } + return ret; + } +} diff --git a/modules/Movecraft/src/main/resources/localisation/movecraftlang_ar.properties b/modules/Movecraft/src/main/resources/localisation/movecraftlang_ar.properties index 298a7c5ae..ff50c49eb 100644 --- a/modules/Movecraft/src/main/resources/localisation/movecraftlang_ar.properties +++ b/modules/Movecraft/src/main/resources/localisation/movecraftlang_ar.properties @@ -16,7 +16,7 @@ # # Message returned when a craft is too small. One Integer which is the minimum size of that Craft Type -Detection\ -\ Craft\ too\ small=%d ??? ???\! ???? ??????? ????? ??????. ???? ?????? ???? ????? ?? +Detection\ -\ Craft\ too\ small=%d ??? ????????\! ???? ??????? ????? ??????. ???? ?????? ???? ?????? ?? Detection\ -\ Craft\ too\ large=%d ??? ???\! ???? ??????? ????? ????. ???? ?????? ???? ????? ?? Detection\ -\ Forbidden\ block\ found=??? ???\! ?? ?????? ??? ???? ?????? ??? ???????. Detection\ -\ Failed\ -\ Already\ commanding\ a\ craft=You are already commanding a craft\! diff --git a/modules/api/src/main/java/net/countercraft/movecraft/MovecraftRepair.java b/modules/api/src/main/java/net/countercraft/movecraft/MovecraftRepair.java index 99edd1b4d..734f788e3 100644 --- a/modules/api/src/main/java/net/countercraft/movecraft/MovecraftRepair.java +++ b/modules/api/src/main/java/net/countercraft/movecraft/MovecraftRepair.java @@ -1,6 +1,5 @@ package net.countercraft.movecraft; -import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard; import com.sk89q.worldedit.extent.clipboard.Clipboard; import net.countercraft.movecraft.craft.Craft; @@ -9,10 +8,12 @@ import org.bukkit.block.Sign; import org.bukkit.entity.Player; import org.bukkit.plugin.Plugin; +import org.bukkit.util.Vector; import java.io.File; import java.util.HashMap; import java.util.HashSet; +import java.util.LinkedList; public abstract class MovecraftRepair { public abstract boolean saveCraftRepairState(Craft craft, Sign sign, Plugin plugin, String repairStateName); @@ -21,10 +22,11 @@ public abstract class MovecraftRepair { public abstract Clipboard loadCraftRepairStateClipboard(Plugin plugin, Sign sign, String repairStateName, World bukkitWorld); public abstract Clipboard loadRegionRepairStateClipboard(Plugin plugin, String repairStateName, World bukkitWorld); public abstract HashMap getMissingBlocks(String repairName); - public abstract HashSet getMissingBlockLocations(String repairName); + public abstract LinkedList getMissingBlockLocations(String repairName); public abstract long getNumDiffBlocks(String repairName); - public abstract Vector getDistanceFromSignToLowestPoint(Clipboard clipboard, String repairName); + public abstract org.bukkit.util.Vector getDistanceFromSignToLowestPoint(Clipboard clipboard, String repairName); public abstract org.bukkit.util.Vector getDistanceFromClipboardToWorldOffset(org.bukkit.util.Vector offset, Clipboard clipboard); + public abstract void setFawePlugin(Plugin fawePlugin); } diff --git a/modules/api/src/main/java/net/countercraft/movecraft/RepairLocation.java b/modules/api/src/main/java/net/countercraft/movecraft/RepairLocation.java new file mode 100644 index 000000000..b18106cd0 --- /dev/null +++ b/modules/api/src/main/java/net/countercraft/movecraft/RepairLocation.java @@ -0,0 +1,20 @@ +package net.countercraft.movecraft; + +import org.bukkit.block.Block; + +public final class RepairLocation implements Comparable { + private final int x; + private final int y; + private final int z; + private final Block block; + public RepairLocation(int x, int y, int z, Block block){ + this.x = x; + this.y = y; + this.z = z; + this.block = block; + } + @Override + public int compareTo(RepairLocation other) { + return 0; + } +} diff --git a/modules/api/src/main/java/net/countercraft/movecraft/config/Settings.java b/modules/api/src/main/java/net/countercraft/movecraft/config/Settings.java index 34d33a1dd..bffc4b2d7 100644 --- a/modules/api/src/main/java/net/countercraft/movecraft/config/Settings.java +++ b/modules/api/src/main/java/net/countercraft/movecraft/config/Settings.java @@ -71,6 +71,7 @@ public class Settings { public static Map DurabilityOverride; public static boolean IsPaper = false; public static boolean IsLegacy = true; //false if version is 1.13 or higher + public static boolean UseFAWE = false; public static boolean AssaultEnable; public static double AssaultDamagesCapPercent; diff --git a/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java b/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java index e0efb451a..017767b37 100644 --- a/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java +++ b/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java @@ -98,6 +98,7 @@ final public class CraftType { @NotNull private final Set passthroughBlocks; @NotNull private final int effectRange; @NotNull private final Set potionEffectsToApply; + @NotNull private final Map potionEffectDelays = Collections.emptyMap(); public CraftType(File f) { final Map data; @@ -462,6 +463,7 @@ private Set effectListFromObject(Object obj){ PotionEffectType effect = null; int duration = 0; int amplifier = 1; + int delay = 0; if (o instanceof String){ String string = (String) o; effect = PotionEffectType.getByName(string); @@ -471,16 +473,20 @@ private Set effectListFromObject(Object obj){ String str = (String) i; int integer = (int) subObjMap.get(i); if (str.equals("duration")){ - duration = integer; + duration = 20 * integer; } if (str.equals("amplifier")){ amplifier = integer; } + if (str.equals("delay")){ + delay = 20 * integer; + } } if (effect == null){ continue; } - ret.add(new PotionEffect(effect,duration,amplifier)); + PotionEffect potEffect = new PotionEffect(effect,duration,amplifier); + ret.add(potEffect); } return ret; } @@ -1052,6 +1058,11 @@ public int getEffectRange() { return effectRange; } + @NotNull + public Map getPotionEffectDelays() { + return potionEffectDelays; + } + private class TypeNotFoundException extends RuntimeException { public TypeNotFoundException(String s) { super(s); diff --git a/modules/v1_10_R1/src/main/java/net/countercraft/movecraft/compat/v1_10_R1/IMovecraftRepair.java b/modules/v1_10_R1/src/main/java/net/countercraft/movecraft/compat/v1_10_R1/IMovecraftRepair.java index 82ce7310b..e18d99787 100644 --- a/modules/v1_10_R1/src/main/java/net/countercraft/movecraft/compat/v1_10_R1/IMovecraftRepair.java +++ b/modules/v1_10_R1/src/main/java/net/countercraft/movecraft/compat/v1_10_R1/IMovecraftRepair.java @@ -37,10 +37,11 @@ import java.io.*; import java.util.HashMap; import java.util.HashSet; +import java.util.LinkedList; import java.util.Set; public class IMovecraftRepair extends MovecraftRepair { - private HashMap> locMissingBlocksMap = new HashMap<>(); + private HashMap> locMissingBlocksMap = new HashMap<>(); private HashMap numDiffBlocksMap = new HashMap<>(); private HashMap> missingBlocksMap = new HashMap<>(); @@ -145,8 +146,9 @@ public Clipboard loadCraftRepairStateClipboard(Plugin plugin, Sign sign, String if (clipboard != null){ long numDiffBlocks = 0; HashMap missingBlocks = new HashMap<>(); - HashSet locMissingBlocks = new HashSet<>(); - Vector distMP = getDistanceFromSignToLowestPoint(clipboard, sign.getLine(1)); + LinkedList locMissingBlocks = new LinkedList<>(); + org.bukkit.util.Vector bukkitDistMP = getDistanceFromSignToLowestPoint(clipboard, sign.getLine(1)); + Vector distMP = new Vector(bukkitDistMP.getBlockX(),bukkitDistMP.getBlockY(),bukkitDistMP.getBlockZ()); Vector minPos = new Vector(sign.getLocation().getBlockX() - distMP.getBlockX(), sign.getLocation().getBlockY() - distMP.getBlockY(), sign.getLocation().getBlockZ() - distMP.getBlockZ()); Vector distance = new Vector(minPos.getBlockX() - clipboard.getMinimumPoint().getBlockX(), minPos.getBlockY() - clipboard.getMinimumPoint().getBlockY(), minPos.getBlockZ() - clipboard.getMinimumPoint().getBlockZ()); for (int x = clipboard.getMinimumPoint().getBlockX(); x <= clipboard.getMaximumPoint().getBlockX(); x++){ @@ -296,7 +298,7 @@ public Clipboard loadCraftRepairStateClipboard(Plugin plugin, Sign sign, String num += qtyToConsume; missingBlocks.put(Material.getMaterial(itemToConsume), num); } - locMissingBlocks.add(new Vector(x,y,z)); + locMissingBlocks.push(new org.bukkit.util.Vector(x,y,z)); } } if (bukkitBlock.getType() == Material.DISPENSER && block.getType() == 23){ @@ -374,7 +376,7 @@ public Clipboard loadCraftRepairStateClipboard(Plugin plugin, Sign sign, String } if (needReplace){ numDiffBlocks++; - locMissingBlocks.add(new Vector(x,y,z)); + locMissingBlocks.push(new org.bukkit.util.Vector(x,y,z)); } } } @@ -401,7 +403,7 @@ public HashMap getMissingBlocks(String repairName) { } @Override - public HashSet getMissingBlockLocations(String repairName) { + public LinkedList getMissingBlockLocations(String repairName) { return locMissingBlocksMap.get(repairName); } @@ -411,8 +413,8 @@ public long getNumDiffBlocks(String s) { } @Override - public Vector getDistanceFromSignToLowestPoint(Clipboard clipboard, String repairName) { - Vector returnDistance = null; + public org.bukkit.util.Vector getDistanceFromSignToLowestPoint(Clipboard clipboard, String repairName) { + org.bukkit.util.Vector returnDistance = null; for (int x = clipboard.getMinimumPoint().getBlockX(); x <= clipboard.getMaximumPoint().getBlockX(); x++) { for (int y = clipboard.getMinimumPoint().getBlockY(); y <= clipboard.getMaximumPoint().getBlockY(); y++) { for (int z = clipboard.getMinimumPoint().getBlockZ(); z <= clipboard.getMaximumPoint().getBlockZ(); z++) { @@ -434,7 +436,7 @@ public Vector getDistanceFromSignToLowestPoint(Clipboard clipboard, String repai secondLine = parts[0]; } if (firstLine.equalsIgnoreCase("Repair:")&& secondLine.contains(repairName)){ - returnDistance = new Vector(x - clipboard.getMinimumPoint().getBlockX(), y - clipboard.getMinimumPoint().getBlockY(), z - clipboard.getMinimumPoint().getBlockZ()); + returnDistance = new org.bukkit.util.Vector(x - clipboard.getMinimumPoint().getBlockX(), y - clipboard.getMinimumPoint().getBlockY(), z - clipboard.getMinimumPoint().getBlockZ()); } } } @@ -447,6 +449,11 @@ public org.bukkit.util.Vector getDistanceFromClipboardToWorldOffset(org.bukkit.u return new org.bukkit.util.Vector(offset.getBlockX() - clipboard.getMinimumPoint().getBlockX(), offset.getBlockY() - clipboard.getMinimumPoint().getBlockY(), offset.getBlockZ() - clipboard.getMinimumPoint().getBlockZ()); } + @Override + public void setFawePlugin(Plugin fawePlugin) { + + } + private Set baseBlocksFromCraft(Craft craft){ HashSet returnSet = new HashSet<>(); HashHitBox hitBox = craft.getHitBox(); diff --git a/modules/v1_11_R1/src/main/java/net/countercraft/movecraft/compat/v1_11_R1/IMovecraftRepair.java b/modules/v1_11_R1/src/main/java/net/countercraft/movecraft/compat/v1_11_R1/IMovecraftRepair.java index cea439f96..caa9da1b1 100644 --- a/modules/v1_11_R1/src/main/java/net/countercraft/movecraft/compat/v1_11_R1/IMovecraftRepair.java +++ b/modules/v1_11_R1/src/main/java/net/countercraft/movecraft/compat/v1_11_R1/IMovecraftRepair.java @@ -37,10 +37,11 @@ import java.io.*; import java.util.HashMap; import java.util.HashSet; +import java.util.LinkedList; import java.util.Set; public class IMovecraftRepair extends MovecraftRepair { - private HashMap> locMissingBlocksMap = new HashMap<>(); + private HashMap> locMissingBlocksMap = new HashMap<>(); private HashMap numDiffBlocksMap = new HashMap<>(); private HashMap> missingBlocksMap = new HashMap<>(); @@ -145,8 +146,9 @@ public Clipboard loadCraftRepairStateClipboard(Plugin plugin, Sign sign, String if (clipboard != null){ long numDiffBlocks = 0; HashMap missingBlocks = new HashMap<>(); - HashSet locMissingBlocks = new HashSet<>(); - Vector distMP = getDistanceFromSignToLowestPoint(clipboard, sign.getLine(1)); + LinkedList locMissingBlocks = new LinkedList<>(); + org.bukkit.util.Vector bukkitDistMP = getDistanceFromSignToLowestPoint(clipboard, sign.getLine(1)); + Vector distMP = new Vector(bukkitDistMP.getBlockX(),bukkitDistMP.getBlockY(),bukkitDistMP.getBlockZ()); Vector minPos = new Vector(sign.getLocation().getBlockX() - distMP.getBlockX(), sign.getLocation().getBlockY() - distMP.getBlockY(), sign.getLocation().getBlockZ() - distMP.getBlockZ()); Vector distance = new Vector(minPos.getBlockX() - clipboard.getMinimumPoint().getBlockX(), minPos.getBlockY() - clipboard.getMinimumPoint().getBlockY(), minPos.getBlockZ() - clipboard.getMinimumPoint().getBlockZ()); for (int x = clipboard.getMinimumPoint().getBlockX(); x <= clipboard.getMaximumPoint().getBlockX(); x++){ @@ -296,7 +298,7 @@ public Clipboard loadCraftRepairStateClipboard(Plugin plugin, Sign sign, String num += qtyToConsume; missingBlocks.put(Material.getMaterial(itemToConsume), num); } - locMissingBlocks.add(new Vector(x,y,z)); + locMissingBlocks.push(new org.bukkit.util.Vector(x,y,z)); } } if (bukkitBlock.getType() == Material.DISPENSER && block.getType() == 23){ @@ -374,7 +376,7 @@ public Clipboard loadCraftRepairStateClipboard(Plugin plugin, Sign sign, String } if (needReplace){ numDiffBlocks++; - locMissingBlocks.add(new Vector(x,y,z)); + locMissingBlocks.push(new org.bukkit.util.Vector(x,y,z)); } } } @@ -401,7 +403,7 @@ public HashMap getMissingBlocks(String repairName) { } @Override - public HashSet getMissingBlockLocations(String repairName) { + public LinkedList getMissingBlockLocations(String repairName) { return locMissingBlocksMap.get(repairName); } @@ -411,8 +413,8 @@ public long getNumDiffBlocks(String s) { } @Override - public Vector getDistanceFromSignToLowestPoint(Clipboard clipboard, String repairName) { - Vector returnDistance = null; + public org.bukkit.util.Vector getDistanceFromSignToLowestPoint(Clipboard clipboard, String repairName) { + org.bukkit.util.Vector returnDistance = null; for (int x = clipboard.getMinimumPoint().getBlockX(); x <= clipboard.getMaximumPoint().getBlockX(); x++) { for (int y = clipboard.getMinimumPoint().getBlockY(); y <= clipboard.getMaximumPoint().getBlockY(); y++) { for (int z = clipboard.getMinimumPoint().getBlockZ(); z <= clipboard.getMaximumPoint().getBlockZ(); z++) { @@ -434,7 +436,7 @@ public Vector getDistanceFromSignToLowestPoint(Clipboard clipboard, String repai secondLine = parts[0]; } if (firstLine.equalsIgnoreCase("Repair:")&& secondLine.contains(repairName)){ - returnDistance = new Vector(x - clipboard.getMinimumPoint().getBlockX(), y - clipboard.getMinimumPoint().getBlockY(), z - clipboard.getMinimumPoint().getBlockZ()); + returnDistance = new org.bukkit.util.Vector(x - clipboard.getMinimumPoint().getBlockX(), y - clipboard.getMinimumPoint().getBlockY(), z - clipboard.getMinimumPoint().getBlockZ()); } } } @@ -448,6 +450,11 @@ public org.bukkit.util.Vector getDistanceFromClipboardToWorldOffset(org.bukkit.u return new org.bukkit.util.Vector(offset.getBlockX() - clipboard.getMinimumPoint().getBlockX(), offset.getBlockY() - clipboard.getMinimumPoint().getBlockY(), offset.getBlockZ() - clipboard.getMinimumPoint().getBlockZ()); } + @Override + public void setFawePlugin(Plugin fawePlugin) { + + } + private Set baseBlocksFromCraft(Craft craft){ HashSet returnSet = new HashSet<>(); HashHitBox hitBox = craft.getHitBox(); diff --git a/modules/v1_12_R1/src/main/java/net/countercraft/movecraft/compat/v1_12_R1/IMovecraftRepair.java b/modules/v1_12_R1/src/main/java/net/countercraft/movecraft/compat/v1_12_R1/IMovecraftRepair.java index 93fae70e6..5c58acd86 100644 --- a/modules/v1_12_R1/src/main/java/net/countercraft/movecraft/compat/v1_12_R1/IMovecraftRepair.java +++ b/modules/v1_12_R1/src/main/java/net/countercraft/movecraft/compat/v1_12_R1/IMovecraftRepair.java @@ -36,7 +36,7 @@ import java.util.*; public class IMovecraftRepair extends MovecraftRepair { - private HashMap> locMissingBlocksMap = new HashMap<>(); + private HashMap> locMissingBlocksMap = new HashMap<>(); private HashMap numDiffBlocksMap = new HashMap<>(); private HashMap> missingBlocksMap = new HashMap<>(); @@ -154,8 +154,9 @@ public Clipboard loadCraftRepairStateClipboard(Plugin plugin,Sign sign, String r if (clipboard != null){ long numDiffBlocks = 0; HashMap missingBlocks = new HashMap<>(); - HashSet locMissingBlocks = new HashSet<>(); - Vector distMP = getDistanceFromSignToLowestPoint(clipboard, sign.getLine(1)); + LinkedList locMissingBlocks = new LinkedList<>(); + org.bukkit.util.Vector bukkitDistMP = getDistanceFromSignToLowestPoint(clipboard, sign.getLine(1)); + Vector distMP = new Vector(bukkitDistMP.getBlockX(),bukkitDistMP.getBlockY(),bukkitDistMP.getBlockZ()); Vector minPos = new Vector(sign.getLocation().getBlockX() - distMP.getBlockX(), sign.getLocation().getBlockY() - distMP.getBlockY(), sign.getLocation().getBlockZ() - distMP.getBlockZ()); Vector distance = new Vector(minPos.getBlockX() - clipboard.getMinimumPoint().getBlockX(), minPos.getBlockY() - clipboard.getMinimumPoint().getBlockY(), minPos.getBlockZ() - clipboard.getMinimumPoint().getBlockZ()); for (int x = clipboard.getMinimumPoint().getBlockX(); x <= clipboard.getMaximumPoint().getBlockX(); x++){ @@ -305,7 +306,7 @@ public Clipboard loadCraftRepairStateClipboard(Plugin plugin,Sign sign, String r num += qtyToConsume; missingBlocks.put(Material.getMaterial(itemToConsume), num); } - locMissingBlocks.add(new Vector(x,y,z)); + locMissingBlocks.push(new org.bukkit.util.Vector(x,y,z)); } } if (bukkitBlock.getType() == Material.DISPENSER && block.getType() == 23){ @@ -383,7 +384,7 @@ public Clipboard loadCraftRepairStateClipboard(Plugin plugin,Sign sign, String r } if (needReplace){ numDiffBlocks++; - locMissingBlocks.add(new Vector(x,y,z)); + locMissingBlocks.push(new org.bukkit.util.Vector(x,y,z)); } } } @@ -416,14 +417,11 @@ public Clipboard loadRegionRepairStateClipboard(Plugin plugin, String s, World w @Override public HashMap getMissingBlocks(String repairName) { - if (missingBlocksMap.get(repairName) == null){ - return null; - } return missingBlocksMap.get(repairName); } @Override - public HashSet getMissingBlockLocations(String repairName) { + public LinkedList getMissingBlockLocations(String repairName) { return locMissingBlocksMap.get(repairName); } @@ -433,8 +431,8 @@ public long getNumDiffBlocks(String s) { } @Override - public Vector getDistanceFromSignToLowestPoint(Clipboard clipboard, String repairName) { - Vector returnDistance = null; + public org.bukkit.util.Vector getDistanceFromSignToLowestPoint(Clipboard clipboard, String repairName) { + org.bukkit.util.Vector returnDistance = null; for (int x = clipboard.getMinimumPoint().getBlockX(); x <= clipboard.getMaximumPoint().getBlockX(); x++) { for (int y = clipboard.getMinimumPoint().getBlockY(); y <= clipboard.getMaximumPoint().getBlockY(); y++) { for (int z = clipboard.getMinimumPoint().getBlockZ(); z <= clipboard.getMaximumPoint().getBlockZ(); z++) { @@ -456,7 +454,7 @@ public Vector getDistanceFromSignToLowestPoint(Clipboard clipboard, String repai secondLine = parts[0]; } if (firstLine.equalsIgnoreCase("Repair:")&& secondLine.contains(repairName)){ - returnDistance = new Vector(x - clipboard.getMinimumPoint().getBlockX(), y - clipboard.getMinimumPoint().getBlockY(), z - clipboard.getMinimumPoint().getBlockZ()); + returnDistance = new org.bukkit.util.Vector(x - clipboard.getMinimumPoint().getBlockX(), y - clipboard.getMinimumPoint().getBlockY(), z - clipboard.getMinimumPoint().getBlockZ()); } } } @@ -470,6 +468,11 @@ public org.bukkit.util.Vector getDistanceFromClipboardToWorldOffset(org.bukkit.u return new org.bukkit.util.Vector(offset.getBlockX() - clipboard.getMinimumPoint().getBlockX(), offset.getBlockY() - clipboard.getMinimumPoint().getBlockY(), offset.getBlockZ() - clipboard.getMinimumPoint().getBlockZ()); } + @Override + public void setFawePlugin(Plugin fawePlugin) { + + } + private Set baseBlocksFromCraft(Craft craft){ HashSet returnSet = new HashSet<>(); HashHitBox hitBox = craft.getHitBox(); diff --git a/modules/v1_13_R2/pom.xml b/modules/v1_13_R2/pom.xml index 865f19e47..a4f0b8f6a 100644 --- a/modules/v1_13_R2/pom.xml +++ b/modules/v1_13_R2/pom.xml @@ -21,6 +21,7 @@ + sk89q-repo http://maven.sk89q.com/repo/ @@ -38,6 +39,12 @@ API jar + + net.countercraft + movecraft-FAWEUtils + FAWEUtils + jar + org.jetbrains annotations-java5 diff --git a/modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/IMovecraftRepair.java b/modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/IMovecraftRepair.java index d4de07990..15c956a95 100644 --- a/modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/IMovecraftRepair.java +++ b/modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/IMovecraftRepair.java @@ -1,10 +1,11 @@ package net.countercraft.movecraft.compat.v1_13_R2; -import com.sk89q.jnbt.NBTInputStream; -import com.sk89q.jnbt.NBTOutputStream; -import com.sk89q.worldedit.MaxChangedBlocksException; -import com.sk89q.worldedit.Vector; +import com.sk89q.jnbt.CompoundTag; +import com.sk89q.jnbt.ListTag; +import com.sk89q.jnbt.Tag; import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.bukkit.BukkitAdapter; import com.sk89q.worldedit.bukkit.BukkitWorld; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard; @@ -15,23 +16,39 @@ import com.sk89q.worldedit.function.operation.Operations; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.regions.CuboidRegion; -import com.sk89q.worldedit.schematic.SchematicFormat; -import com.sk89q.worldedit.world.registry.WorldData; +import com.sk89q.worldedit.registry.state.EnumProperty; +import com.sk89q.worldedit.registry.state.Property; +import com.sk89q.worldedit.world.block.BaseBlock; import net.countercraft.movecraft.MovecraftRepair; +import net.countercraft.movecraft.config.Settings; import net.countercraft.movecraft.craft.Craft; +import net.countercraft.movecraft.utils.FAWEUtils; import net.countercraft.movecraft.utils.HashHitBox; +import org.bukkit.Bukkit; +import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.World; +import org.bukkit.block.Block; import org.bukkit.block.Sign; +import org.bukkit.block.data.type.Slab; import org.bukkit.plugin.Plugin; +import org.bukkit.util.Vector; import java.io.*; import java.util.HashMap; import java.util.HashSet; +import java.util.LinkedList; +import java.util.logging.Logger; public class IMovecraftRepair extends MovecraftRepair { + private HashMap> locMissingBlocksMap = new HashMap<>(); + private HashMap numDiffBlocksMap = new HashMap<>(); + private HashMap> missingBlocksMap = new HashMap<>(); @Override public boolean saveCraftRepairState(Craft craft, Sign sign, Plugin plugin, String s) { + if (Settings.UseFAWE){ + return FAWEUtils.faweSaveCraftRepairState(craft,sign,plugin,s); + } HashHitBox hitBox = craft.getHitBox(); File saveDirectory = new File(plugin.getDataFolder(), "CraftRepairStates"); World world = craft.getW(); @@ -49,16 +66,15 @@ public boolean saveCraftRepairState(Craft craft, Sign sign, Plugin plugin, Strin ExistingBlockMask mask = new ExistingBlockMask(source); copy.setSourceMask(mask); try { - Operations.completeLegacy(copy); - } catch (MaxChangedBlocksException e) { + Operations.complete(copy); + } catch (WorldEditException e) { e.printStackTrace(); return false; } File schematicFile = new File(saveDirectory, s + ".schematic"); try { OutputStream output = new FileOutputStream(schematicFile); - NBTOutputStream outputStream = new NBTOutputStream(output); - SpongeSchematicWriter writer = new SpongeSchematicWriter(outputStream); + ClipboardWriter writer = BuiltInClipboardFormat.SPONGE_SCHEMATIC.getWriter(output); writer.write(clipboard); writer.close(); } catch (IOException e) { @@ -84,10 +100,7 @@ public Clipboard loadCraftRepairStateClipboard(Plugin plugin, Sign sign, String File dataDirectory = new File(plugin.getDataFolder(), "CraftRepairStates"); File file = new File(dataDirectory, s + ".schematic"); // The schematic file com.sk89q.worldedit.world.World weWorld = new BukkitWorld(world); - Clipboard clipboard; - if (file == null){ - return null; - } + Clipboard clipboard = null; ClipboardFormat format = ClipboardFormats.findByFile(file); try { @@ -95,13 +108,150 @@ public Clipboard loadCraftRepairStateClipboard(Plugin plugin, Sign sign, String ClipboardReader reader = format.getReader(input); clipboard = reader.read(); reader.close(); - return clipboard; - } catch (IOException e) { + + } catch (IOException | NullPointerException e) { e.printStackTrace(); } + if (clipboard != null){ + long numDiffBlocks = 0; + int index = 0; + HashMap missingBlocks = new HashMap<>(); + LinkedList locMissingBlocks = new LinkedList<>(); + org.bukkit.util.Vector distMP = getDistanceFromSignToLowestPoint(clipboard,s); + BlockVector3 minPos = BlockVector3.at(sign.getLocation().getBlockX() - distMP.getBlockX(),sign.getLocation().getBlockY() - distMP.getBlockY(),sign.getLocation().getBlockZ() - distMP.getBlockZ()); + BlockVector3 distance = BlockVector3.at(minPos.getBlockX() - clipboard.getMinimumPoint().getBlockX(), minPos.getBlockY() - clipboard.getMinimumPoint().getBlockY(),minPos.getBlockZ() - clipboard.getMinimumPoint().getBlockZ()); + for (int x = clipboard.getMinimumPoint().getBlockX(); x <= clipboard.getMaximumPoint().getBlockX(); x++) { + for (int y = clipboard.getMinimumPoint().getBlockY(); y <= clipboard.getMaximumPoint().getBlockY(); y++) { + for (int z = clipboard.getMinimumPoint().getBlockZ(); z <= clipboard.getMaximumPoint().getBlockZ(); z++) { + index++; + BlockVector3 position = BlockVector3.at(x,y,z); + BaseBlock block = clipboard.getFullBlock(position); + Material type = BukkitAdapter.adapt(block.getBlockType()); + Location loc = new Location(sign.getWorld(),x + distance.getBlockX(),y + distance.getBlockY(),z + distance.getBlockZ()); + Block bukkitBlock = sign.getWorld().getBlockAt(loc); + boolean isImportant = true; - return null; + if (type.equals(Material.AIR) || type.equals(Material.CAVE_AIR) || type.equals(Material.VOID_AIR)){ + isImportant = false; + } + boolean blockMissing = isImportant && type != bukkitBlock.getType(); + if (type.name().endsWith("_SLAB")){ + plugin.getLogger().info(type.name()); + for (Property property : block.getStates().keySet()){ + if (!(property instanceof EnumProperty)){ + continue; + } + @SuppressWarnings("unchecked") + String prop = (String) block.getState(property); + if (bukkitBlock.getBlockData() instanceof Slab){ + Slab slab = (Slab) bukkitBlock.getBlockData(); + blockMissing = slab.getType() != Slab.Type.valueOf(prop.toUpperCase()); + } + } + } + + if (blockMissing){ + Material typeToConsume = type; + double qtyToConsume = 1.0; + if (type.equals(Material.WATER)||type.equals(Material.LAVA)){ + qtyToConsume = 0; + } + if (type.name().endsWith("_SLAB")){ + plugin.getLogger().info(type.name()); + for (Property property : block.getStates().keySet()){ + if (!(property instanceof EnumProperty)){ + continue; + } + @SuppressWarnings("unchecked") + String prop = (String) block.getState(property); + if (prop.equals("double")){ + qtyToConsume = 2.0; + } + } + } + if (type.equals(Material.WALL_SIGN)){ + typeToConsume = Material.SIGN; + } + if (type.equals(Material.REDSTONE_WALL_TORCH)){ + typeToConsume = Material.REDSTONE_TORCH; + } + if (type.equals(Material.WALL_TORCH)){ + typeToConsume = Material.TORCH; + } + if (type.name().endsWith("_DOOR") || type.name().endsWith("_BED")){ + qtyToConsume = 0.5; + } + if (type.equals(Material.DISPENSER)){ + int numTNT = 0; + int numFirecharge = 0; + int numWaterBucket = 0; + ListTag listTag = block.getNbtData().getListTag("Items"); + if (listTag != null) { + for (Tag entry : listTag.getValue()) { + //To avoid ClassCastExceptions, continue if tag is not a CompoundTag + if (!(entry instanceof CompoundTag)) { + continue; + } + CompoundTag cTag = (CompoundTag) entry; + if (cTag.getString("id").equals("minecraft:tnt")) { + numTNT += cTag.getByte("Count"); + } + if (cTag.getString("id").equals("minecraft:fire_charge")) { + numFirecharge += cTag.getByte("Count"); + } + if (cTag.getString("id").equals("minecraft:water_bucket")) { + numWaterBucket += cTag.getByte("Count"); + } + } + } + if (numTNT > 0){ + if (missingBlocks.containsKey(Material.TNT)){ + double count = missingBlocks.get(Material.TNT); + count += numTNT; + missingBlocks.put(Material.TNT,count); + } else { + missingBlocks.put(Material.TNT, (double) numTNT); + } + } + if (numFirecharge > 0){ + if (missingBlocks.containsKey(Material.FIRE_CHARGE)){ + double count = missingBlocks.get(Material.FIRE_CHARGE); + count += numFirecharge; + missingBlocks.put(Material.FIRE_CHARGE,count); + } else { + missingBlocks.put(Material.FIRE_CHARGE, (double) numFirecharge); + } + } + if (numWaterBucket > 0){ + if (missingBlocks.containsKey(Material.WATER_BUCKET)){ + double count = missingBlocks.get(Material.WATER_BUCKET); + count += numWaterBucket; + missingBlocks.put(Material.WATER_BUCKET,count); + } else { + missingBlocks.put(Material.WATER_BUCKET, (double) numWaterBucket); + } + } + } + locMissingBlocks.push(new Vector(x,y,z)); + numDiffBlocks++; + if (missingBlocks.containsKey(typeToConsume)){ + double count = missingBlocks.get(typeToConsume); + count += qtyToConsume; + missingBlocks.put(typeToConsume,count); + } else { + missingBlocks.put(typeToConsume,qtyToConsume); + } + } + + } + } + } + locMissingBlocksMap.put(s, locMissingBlocks); + missingBlocksMap.put(s, missingBlocks); + numDiffBlocksMap.put(s, numDiffBlocks); + } + return clipboard; } @Override @@ -111,22 +261,50 @@ public Clipboard loadRegionRepairStateClipboard(Plugin plugin, String s, World w @Override public HashMap getMissingBlocks(String s) { - return null; + return missingBlocksMap.get(s); } @Override - public HashSet getMissingBlockLocations(String s) { - return null; + public LinkedList getMissingBlockLocations(String s) { + + return locMissingBlocksMap.get(s); } @Override public long getNumDiffBlocks(String s) { - return 0; + return numDiffBlocksMap.get(s); } @Override public Vector getDistanceFromSignToLowestPoint(Clipboard clipboard, String s) { - return null; + org.bukkit.util.Vector returnDistance = null; + for (int x = clipboard.getMinimumPoint().getBlockX(); x <= clipboard.getMaximumPoint().getBlockX(); x++) { + for (int y = clipboard.getMinimumPoint().getBlockY(); y <= clipboard.getMaximumPoint().getBlockY(); y++) { + for (int z = clipboard.getMinimumPoint().getBlockZ(); z <= clipboard.getMaximumPoint().getBlockZ(); z++) { + BlockVector3 pos = BlockVector3.at(x,y,z); + BaseBlock block = clipboard.getFullBlock(pos); + if (block.getBlockType().getId().equals("minecraft:sign")||block.getBlockType().getId().equals("minecraft:wall_sign")){ + Logger log = Bukkit.getLogger(); + String firstLine = block.getNbtData().getString("Text1"); + firstLine = firstLine.substring(2); + if (firstLine.startsWith("extra")){ + firstLine = firstLine.substring(17); + firstLine = firstLine.replace("\"}],\"text\":\"\"}",""); + } + String secondLine = block.getNbtData().getString("Text2"); + secondLine = secondLine.substring(2); + if (secondLine.startsWith("extra")){ + secondLine = secondLine.substring(17); + secondLine = secondLine.replace("\"}],\"text\":\"\"}",""); + } + if (firstLine.equalsIgnoreCase("Repair:") && s.endsWith(secondLine)) + returnDistance = new Vector(x - clipboard.getMinimumPoint().getBlockX(),y - clipboard.getMinimumPoint().getBlockY(),z - clipboard.getMinimumPoint().getBlockZ()); + } + + } + } + } + return returnDistance; } @@ -134,4 +312,9 @@ public Vector getDistanceFromSignToLowestPoint(Clipboard clipboard, String s) { public org.bukkit.util.Vector getDistanceFromClipboardToWorldOffset(org.bukkit.util.Vector offset, Clipboard clipboard) { return new org.bukkit.util.Vector(offset.getBlockX() - clipboard.getMinimumPoint().getBlockX(), offset.getBlockY() - clipboard.getMinimumPoint().getBlockY(), offset.getBlockZ() - clipboard.getMinimumPoint().getBlockZ()); } + + @Override + public void setFawePlugin(Plugin fawePlugin) { + + } } diff --git a/modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/IWorldHandler.java b/modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/IWorldHandler.java index ed1045e26..1c28a6ab5 100644 --- a/modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/IWorldHandler.java +++ b/modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/IWorldHandler.java @@ -50,13 +50,6 @@ public IWorldHandler() { } } - @Override - public void addPlayerLocation(Player player, double x, double y, double z, float yaw, float pitch){ - //Due to a bug in the 1.13 NMS method, use Bukkit method instead - Location playerLoc = player.getLocation(); - player.teleport(new Location(player.getWorld(), x + playerLoc.getX(),y + playerLoc.getY(),z + playerLoc.getZ(),yaw + playerLoc.getYaw(),pitch + playerLoc.getPitch())); - } - @Override public void rotateCraft(@NotNull Craft craft, @NotNull MovecraftLocation originPoint, @NotNull Rotation rotation) { //******************************************* diff --git a/pom.xml b/pom.xml index d3b158035..22d0feb85 100644 --- a/pom.xml +++ b/pom.xml @@ -19,12 +19,14 @@ + modules/FAWEUtils modules/api modules/v1_10_R1 modules/v1_11_R1 modules/v1_12_R1 modules/v1_13_R2 modules/Movecraft + From 2c37848760826417b88afdd4a497aa418218babb Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Mon, 18 Feb 2019 19:41:41 +0100 Subject: [PATCH 009/304] Fixed a 1.13-exclusive repair system bug causing repairs to require redstone wire instead of redstone + retracted codes in the WorldEditUpdateCommand --- .../update/WorldEditUpdateCommand.java | 125 +++--------------- .../compat/v1_13_R2/IMovecraftRepair.java | 2 + 2 files changed, 17 insertions(+), 110 deletions(-) diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/WorldEditUpdateCommand.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/WorldEditUpdateCommand.java index 5ae36f91f..446973034 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/WorldEditUpdateCommand.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/WorldEditUpdateCommand.java @@ -49,119 +49,19 @@ public WorldEditUpdateCommand(com.sk89q.worldedit.world.block.BaseBlock worldEdi public void doUpdate() { Block block = world.getBlockAt(location.getX(), location.getY(), location.getZ()); block.setType(type); + Material weType; if (Settings.IsLegacy) { LegacyUtils.setData(block, data); - - // put inventory into dispensers if its a repair - if (type == Material.DISPENSER) { - //DispenserBlock dispBlock = new DispenserBlock(worldEditBaseBlock.getData()); - //dispBlock.setNbtData(worldEditBaseBlock.getNbtData()); - Tag t = worldEditBaseBlock.getNbtData().getValue().get("Items"); - ListTag lt = null; - if (t instanceof ListTag) { - lt = (ListTag) t; - } - int numFireCharges = 0; - int numTNT = 0; - int numWater = 0; - if (lt != null) { - for (Tag entryTag : lt.getValue()) { - if (entryTag instanceof CompoundTag) { - CompoundTag cTag = (CompoundTag) entryTag; - if (cTag.toString().contains("minecraft:tnt")) { - numTNT += cTag.getByte("Count"); - } - if (cTag.toString().contains("minecraft:fire_charge")) { - numFireCharges += cTag.getByte("Count"); - } - if (cTag.toString().contains("minecraft:water_bucket")) { - numWater += cTag.getByte("Count"); - } - } - } - } - Dispenser disp = (Dispenser) world.getBlockAt(location.getX(), location.getY(), location.getZ()).getState(); - if (numFireCharges > 0) { - ItemStack fireItems = new ItemStack(LegacyUtils.FIREBALL, numFireCharges); - disp.getInventory().addItem(fireItems); - } - if (numTNT > 0) { - ItemStack TNTItems = new ItemStack(Material.TNT, numTNT); - disp.getInventory().addItem(TNTItems); - } - if (numWater > 0) { - ItemStack WaterItems = new ItemStack(Material.WATER_BUCKET, numWater); - disp.getInventory().addItem(WaterItems); - } - - - } - if (worldEditBaseBlock.getType() == 63 || worldEditBaseBlock.getType() == 68) { - BlockState state = world.getBlockAt(location.getX(), location.getY(), location.getZ()).getState(); - if (state instanceof Sign) { - Sign s = (Sign) state; - CompoundTag nbtData = worldEditBaseBlock.getNbtData(); - //first line - String firstLine = nbtData.getString("Text1"); - firstLine = firstLine.substring(2); - if (firstLine.substring(0, 5).equalsIgnoreCase("extra")){ - firstLine = firstLine.substring(17); - String[] parts = firstLine.split("\""); - firstLine = parts[0]; - } else { - firstLine = ""; - } - //second line - String secondLine = nbtData.getString("Text2"); - secondLine = secondLine.substring(2); - if (secondLine.substring(0, 5).equalsIgnoreCase("extra")){ - secondLine = secondLine.substring(17); - String[] parts = secondLine.split("\""); - secondLine = parts[0]; - } else { - secondLine = ""; - } - //third line - String thirdLine = nbtData.getString("Text3"); - thirdLine = thirdLine.substring(2); - if (thirdLine.substring(0, 5).equalsIgnoreCase("extra")){ - thirdLine = thirdLine.substring(17); - String[] parts = thirdLine.split("\""); - thirdLine = parts[0]; - } else { - thirdLine = ""; - } - //fourth line - String fourthLine = nbtData.getString("Text4"); - fourthLine = fourthLine.substring(2); - if (fourthLine.substring(0, 5).equalsIgnoreCase("extra")){ - fourthLine = fourthLine.substring(17); - String[] parts = fourthLine.split("\""); - fourthLine = parts[0]; - } else { - fourthLine = ""; - } - String[] lines = new String[4]; - if (firstLine.equalsIgnoreCase("\\\\ || /")){ - firstLine = "\\ || /"; - secondLine = "== =="; - thirdLine = "/ || \\"; - } - lines[0] = firstLine; - lines[1] = secondLine; - lines[2] = thirdLine; - lines[3] = fourthLine; - for (int line = 0; line < lines.length; line++) { - s.setLine(line, lines[line]); - } - s.update(false, false); - } - } + assert worldEditBaseBlock != null; + weType = LegacyUtils.getMaterial(worldEditBaseBlock.getType()); } else { + assert worldEdit7BaseBlock != null; BlockData bData = BukkitAdapter.adapt(worldEdit7BaseBlock); block.setBlockData(bData); + weType = BukkitAdapter.adapt(worldEdit7BaseBlock.getBlockType()); + } if (type == Material.DISPENSER){ - Tag t = worldEdit7BaseBlock.getNbtData().getValue().get("Items"); + Tag t = Settings.IsLegacy ? worldEditBaseBlock.getNbtData().getValue().get("Items") : worldEdit7BaseBlock.getNbtData().getValue().get("Items"); ListTag lt = null; if (t instanceof ListTag) { lt = (ListTag) t; @@ -199,11 +99,11 @@ public void doUpdate() { disp.getInventory().addItem(WaterItems); } } - if (BukkitAdapter.adapt(worldEdit7BaseBlock.getBlockType()).equals(Material.SIGN)||BukkitAdapter.adapt(worldEdit7BaseBlock.getBlockType()).equals(Material.WALL_SIGN)){ + if (isSign(weType)){ BlockState state = block.getState(); if (state instanceof Sign) { Sign s = (Sign) state; - CompoundTag nbtData = worldEdit7BaseBlock.getNbtData(); + CompoundTag nbtData = Settings.IsLegacy ? worldEditBaseBlock.getNbtData() : worldEdit7BaseBlock.getNbtData(); //first line String firstLine = nbtData.getString("Text1"); firstLine = firstLine.substring(2); @@ -260,6 +160,11 @@ public void doUpdate() { s.update(false, false); } } - } + + } + + private boolean isSign(Material type){ + if (Settings.IsLegacy) return type.equals(LegacyUtils.SIGN_POST) || type.equals(Material.WALL_SIGN); + else return type.equals(Material.SIGN) || type.equals(Material.WALL_SIGN); } } diff --git a/modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/IMovecraftRepair.java b/modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/IMovecraftRepair.java index 15c956a95..695b2ab3c 100644 --- a/modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/IMovecraftRepair.java +++ b/modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/IMovecraftRepair.java @@ -182,6 +182,8 @@ public Clipboard loadCraftRepairStateClipboard(Plugin plugin, Sign sign, String if (type.name().endsWith("_DOOR") || type.name().endsWith("_BED")){ qtyToConsume = 0.5; } + if (type.equals(Material.REDSTONE_WIRE)) + typeToConsume = Material.REDSTONE; if (type.equals(Material.DISPENSER)){ int numTNT = 0; int numFirecharge = 0; From 2fb7073fe0e4c4eadf833bbfc45f8e57c8c75420 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Wed, 3 Apr 2019 10:19:58 +0200 Subject: [PATCH 010/304] Fixed several bugs in assault and siege for 1.13 + Added the ability for multiple dynamic flyblocks + Organized MovecraftRepair classes into separate modules --- modules/Movecraft/pom.xml | 43 +- .../net/countercraft/movecraft/Movecraft.java | 104 ++-- .../movecraft/async/AsyncManager.java | 1 + .../async/detection/DetectionTask.java | 13 +- .../async/rotation/RotationTask.java | 32 +- .../async/translation/TranslationTask.java | 105 ++-- .../movecraft/commands/AssaultCommand.java | 72 ++- .../commands/AssaultInfoCommand.java | 16 +- .../movecraft/commands/MovecraftCommand.java | 6 + .../movecraft/commands/ReleaseCommand.java | 1 - .../movecraft/commands/RepairCommand.java | 3 - .../movecraft/commands/SiegeCommand.java | 60 ++- .../compatmanager/DeadboltCompatManager.java | 3 + .../GriefPreventionCompatManager.java | 56 ++ .../RedProtectCompatManager.java | 12 + .../WorldGuardCompatManager.java | 6 - .../movecraft/listener/BlockListener.java | 3 - .../movecraft/listener/PlayerListener.java | 3 - .../mapUpdater/update/BlockCreateCommand.java | 1 - .../mapUpdater/update/CraftRotateCommand.java | 2 +- .../update/CraftTranslateCommand.java | 4 +- .../update/ExplosionUpdateCommand.java | 18 +- .../update/PotionEffectsUpdateCommand.java | 21 +- .../update/WorldEditUpdateCommand.java | 18 +- .../movecraft/repair/RepairUtils.java | 53 +- .../movecraft/sign/AscendSign.java | 2 - .../countercraft/movecraft/sign/CrewSign.java | 2 - .../movecraft/sign/RegionDamagedSign.java | 57 +- .../movecraft/sign/RepairSign.java | 3 - .../movecraft/sign/StatusSign.java | 1 - .../movecraft/sign/SubcraftRotateSign.java | 4 - .../movecraft/utils/LegacyWEUtils.java | 15 + .../movecraft/utils/WorldEditUtils.java | 8 + .../movecraft/utils/WorldguardUtils.java | 36 ++ .../movecraft/utils/weVectorUtils.java | 60 +++ .../warfare/assault/AssaultBarTask.java | 9 + .../warfare/assault/AssaultTask.java | 29 +- .../warfare/assault/AssaultUtils.java | 19 +- .../warfare/siege/SiegeProgressTask.java | 8 +- modules/api/pom.xml | 15 +- .../movecraft/MovecraftRepair.java | 3 +- .../countercraft/movecraft/RegionUtils.java | 8 + .../movecraft/config/Settings.java | 1 + .../countercraft/movecraft/craft/Craft.java | 5 +- .../movecraft/craft/CraftType.java | 53 +- .../movecraft/events/CraftRotateEvent.java | 2 - .../compat/v1_10_R1/IMovecraftRepair.java | 489 ------------------ .../compat/v1_11_R1/IMovecraftRepair.java | 489 ------------------ .../compat/v1_13_R2/IWorldHandler.java | 2 - .../compat/v1_13_R2/NextTickProvider.java | 17 +- modules/{ => worldedit}/FAWEUtils/pom.xml | 6 +- .../compat/fawe/IMovecraftRepair.java} | 65 ++- modules/worldedit/WE6Utils/pom.xml | 74 +++ .../compat/we6}/IMovecraftRepair.java | 84 +-- modules/worldedit/WE7Utils/pom.xml | 88 ++++ .../compat/we7}/IMovecraftRepair.java | 181 ++++++- pom.xml | 5 +- 57 files changed, 1168 insertions(+), 1328 deletions(-) create mode 100644 modules/Movecraft/src/main/java/net/countercraft/movecraft/compatmanager/GriefPreventionCompatManager.java create mode 100644 modules/Movecraft/src/main/java/net/countercraft/movecraft/compatmanager/RedProtectCompatManager.java create mode 100644 modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/LegacyWEUtils.java create mode 100644 modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/weVectorUtils.java create mode 100644 modules/api/src/main/java/net/countercraft/movecraft/RegionUtils.java delete mode 100644 modules/v1_10_R1/src/main/java/net/countercraft/movecraft/compat/v1_10_R1/IMovecraftRepair.java delete mode 100644 modules/v1_11_R1/src/main/java/net/countercraft/movecraft/compat/v1_11_R1/IMovecraftRepair.java rename modules/{ => worldedit}/FAWEUtils/pom.xml (91%) rename modules/{FAWEUtils/src/main/java/net/countercraft/movecraft/utils/FAWEUtils.java => worldedit/FAWEUtils/src/main/java/net/countercraft/movecraft/compat/fawe/IMovecraftRepair.java} (58%) create mode 100644 modules/worldedit/WE6Utils/pom.xml rename modules/{v1_12_R1/src/main/java/net/countercraft/movecraft/compat/v1_12_R1 => worldedit/WE6Utils/src/main/java/net/countercraft/movecraft/compat/we6}/IMovecraftRepair.java (89%) create mode 100644 modules/worldedit/WE7Utils/pom.xml rename modules/{v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2 => worldedit/WE7Utils/src/main/java/net/countercraft/movecraft/compat/we7}/IMovecraftRepair.java (63%) diff --git a/modules/Movecraft/pom.xml b/modules/Movecraft/pom.xml index 901744017..c4f39e866 100644 --- a/modules/Movecraft/pom.xml +++ b/modules/Movecraft/pom.xml @@ -71,6 +71,9 @@ API jar + + + com.sk89q worldguard @@ -86,7 +89,24 @@ worldedit LATEST - + + net.countercraft + movecraft-WE7Utils + WE7Utils + jar + + + net.countercraft + movecraft-FAWEUtils + FAWEUtils + jar + + + net.countercraft + movecraft-WE6Utils + WE6Utils + jar + at.pavlov Cannons @@ -154,6 +174,27 @@ system ${project.basedir}/../../libs/Deadbolt-1.0-SNAPSHOT.jar + + sun.jdk + gp + 1.5.0 + system + ${project.basedir}/../../libs/GriefPrevention.jar + + + sun.jdk + kingdoms + 1.5.0 + system + ${project.basedir}/../../libs/FabledKingdoms.jar + + + sun.jdk + redprotect + 1.5.0 + system + ${project.basedir}/../../libs/RedProtect-7.5.5-b129-Universal.jar + org.jetbrains annotations-java5 diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java index a1dacf56f..c0cebd0de 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java @@ -26,8 +26,10 @@ import com.sk89q.worldedit.bukkit.WorldEditPlugin; import com.sk89q.worldguard.bukkit.WorldGuardPlugin; import com.sk89q.worldguard.protection.flags.StateFlag; +import me.ryanhamshire.GriefPrevention.GriefPrevention; import net.countercraft.movecraft.async.AsyncManager; import net.countercraft.movecraft.commands.*; +import net.countercraft.movecraft.compatmanager.GriefPreventionCompatManager; import net.countercraft.movecraft.config.Settings; import net.countercraft.movecraft.craft.CraftManager; import net.countercraft.movecraft.listener.BlockListener; @@ -74,6 +76,7 @@ public class Movecraft extends JavaPlugin { private static Essentials essentialsPlugin = null; private static Factions factionsPlugin; private static DeadboltPlugin deadboltPlugin; + private static GriefPrevention griefPreventionPlugin; /*public HashMap blockFadeTimeMap = new HashMap<>(); public HashMap blockFadeTypeMap = new HashMap<>(); public HashMap blockFadeWaterMap = new HashMap<>(); @@ -105,11 +108,7 @@ public void onEnable() { String[] parts = version.split("_"); Integer versionNumber = Integer.valueOf(parts[1]); //Check if the server is 1.12 and lower or 1.13 and higher - if (versionNumber <= 12){ - Settings.IsLegacy = true; - } else { - Settings.IsLegacy = false; - } + Settings.IsLegacy = versionNumber <= 12; // Read in config if (!Settings.IsLegacy) { this.saveDefaultConfig(); @@ -127,6 +126,7 @@ public void onEnable() { } + Settings.LOCALE = getConfig().getString("Locale"); Settings.RestrictSiBsToRegions = getConfig().getBoolean("RestrictSiBsToRegions", false); Settings.Debug = getConfig().getBoolean("Debug", false); @@ -139,18 +139,6 @@ public void onEnable() { } else { logger.log(Level.INFO, "No PilotTool setting, using default of stick"); } - // if the CompatibilityMode is specified in the config.yml file, use it. - // Otherwise set to false. - /*Settings.CompatibilityMode = getConfig().getBoolean("CompatibilityMode", false); - if (!Settings.CompatibilityMode) { - try { - Class.forName("net.minecraft.server.v1_10_R1.Chunk"); - } catch (ClassNotFoundException e) { - Settings.CompatibilityMode = true; - logger.log(Level.INFO, "WARNING: CompatibilityMode was set to false, but required build-specific classes were not found. FORCING COMPATIBILITY MODE"); - } - } - logger.log(Level.INFO, "CompatiblityMode is set to {0}", Settings.CompatibilityMode);*/ //Switch to interfaces try { @@ -183,6 +171,25 @@ public void onEnable() { Settings.RequireNamePerm = getConfig().getBoolean("RequireNamePerm", false); Settings.TNTContactExplosives = getConfig().getBoolean("TNTContactExplosives", true); Settings.FadeWrecksAfter = getConfig().getInt("FadeWrecksAfter", 0); + if (getConfig().contains("FuelTypes")){ + Map fuelTypes = getConfig().getConfigurationSection("FuelTypes").getValues(false); + int numFuelTypes = 0; + for (String fuelTypeId : fuelTypes.keySet()){ + Settings.FuelTypes.put(Material.getMaterial(fuelTypeId), (Double) fuelTypes.get(fuelTypeId)); + numFuelTypes++; + } + logger.info(numFuelTypes + " fuel types registered"); + } else { + Settings.FuelTypes.put(Material.COAL_BLOCK,79.0); + Settings.FuelTypes.put(Material.COAL,7.0); + if (!Settings.IsLegacy) + Settings.FuelTypes.put(Material.CHARCOAL,7.0); + String loggerMsg = "No fuel types specified in config. Registering default fuel types "; + for (Material fuel : Settings.FuelTypes.keySet()){ + loggerMsg += fuel.name().toLowerCase() + " with burning time " + Settings.FuelTypes.get(fuel) + ", "; + } + logger.info(loggerMsg); + } if (getConfig().contains("DurabilityOverride")) { Map temp = getConfig().getConfigurationSection("DurabilityOverride").getValues(false); Settings.DurabilityOverride = new HashMap<>(); @@ -205,15 +212,16 @@ public void onEnable() { Settings.AssaultMemberWeightPercent = getConfig().getInt("AssaultMemberWeightPercent", 100); List assaultDestroyableBlocks = getConfig().getStringList("AssaultDestroyableBlocks"); for (String matStr : assaultDestroyableBlocks){ - Settings.AssaultDestroyableBlocks.add(Material.getMaterial(matStr)); + Settings.AssaultDestroyableBlocks.add(Material.getMaterial(matStr.toUpperCase())); } List disableShadowBlocks = getConfig().getStringList("DisableShadowBlocks"); for (String typ : disableShadowBlocks){ - Settings.DisableShadowBlocks.add(Material.getMaterial(typ)); + Settings.DisableShadowBlocks.add(Material.getMaterial(typ.toUpperCase())); } Settings.RepairMaxPercent = getConfig().getDouble("RepairMaxPercent", 50.0); Settings.ForbiddenRemoteSigns = new HashSet<>(getConfig().getStringList("ForbiddenRemoteSigns")); Settings.SiegeEnable = getConfig().getBoolean("SiegeEnable", false); + Settings.SiegeTimeZone = getConfig().getString("SiegeTimeZone", "UTC"); @@ -242,33 +250,54 @@ public void onEnable() { //load up WorldEdit if it's present - Plugin wEPlugin = getServer().getPluginManager().getPlugin("WorldEdit"); + + Plugin wEPlugin = null; + if (getServer().getPluginManager().getPlugin("WorldEdit") != null){ + wEPlugin = getServer().getPluginManager().getPlugin("WorldEdit"); + } else { + if (!Settings.IsLegacy){ + wEPlugin = getServer().getPluginManager().getPlugin("FastAsyncWorldEdit"); + } + } if (wEPlugin == null || !(wEPlugin instanceof WorldEditPlugin)) { logger.log(Level.INFO, "Movecraft did not find a compatible version of WorldEdit. Disabling WorldEdit integration"); Settings.AssaultEnable = false; } else { logger.log(Level.INFO, "Found a compatible version of WorldEdit. Enabling WorldEdit integration"); Settings.RepairTicksPerBlock = getConfig().getInt("RepairTicksPerBlock", 0); + + if (!Settings.IsLegacy) { + //Check if FAWE us used + try { + Class.forName("com.boydti.fawe.bukkit.FaweBukkit"); + Settings.UseFAWE = true; + } catch (ClassNotFoundException e) { + Settings.UseFAWE = false; + } + } + String weVersion; + //Now decide which WE compat should be used + if (!Settings.IsLegacy){ + if (Settings.UseFAWE) { + weVersion = "fawe"; + } else { + weVersion = "we7"; + } + } else { + weVersion = "we6"; + } //Test if a compatible MovecraftRepair is present try { - final Class clazz = Class.forName("net.countercraft.movecraft.compat." + version + ".IMovecraftRepair"); + final Class clazz = Class.forName("net.countercraft.movecraft.compat." + weVersion + ".IMovecraftRepair"); //Check if we have a Repair class at that location if (MovecraftRepair.class.isAssignableFrom(clazz)){ this.movecraftRepair = (MovecraftRepair) clazz.getConstructor().newInstance(); } } catch (final Exception e){ e.printStackTrace(); - this.getLogger().severe("Could not find a compatible repair class. Disabling repair function"); + this.getLogger().severe("Could not find a compatible repair class. Disabling repair and assault functions"); Settings.RepairTicksPerBlock = 0; - } - if (!Settings.IsLegacy) { - //Check if FAWE us used - try { - Class.forName("com.boydti.fawe.bukkit.FaweBukkit"); - Settings.UseFAWE = true; - } catch (ClassNotFoundException e) { - Settings.UseFAWE = false; - } + Settings.AssaultEnable = false; } } worldEditPlugin = (WorldEditPlugin) wEPlugin; @@ -348,6 +377,15 @@ public void onEnable() { if (factionsPlugin == null){ logger.info("Movecraft did not find a compatible version of Factions. Disabling Factions integration"); } + //GriefPrevention + Plugin gpPlugin = getServer().getPluginManager().getPlugin("GriefPrevention"); + if (gpPlugin != null){ + if (gpPlugin instanceof GriefPrevention){ + logger.info("Found a compatible version of GriefPrevention. Enabling GriefPrevention integration"); + getServer().getPluginManager().registerEvents(new GriefPreventionCompatManager(),this); + griefPreventionPlugin = (GriefPrevention) gpPlugin; + } + } // Deadbolt Plugin tempDeadboltPlugin = getServer().getPluginManager().getPlugin("Deadbolt"); if (tempDeadboltPlugin != null){ @@ -560,6 +598,10 @@ public Factions getFactionsPlugin(){ return factionsPlugin; } + public GriefPrevention getGriefPreventionPlugin() { + return griefPreventionPlugin; + } + public DeadboltPlugin getDeadboltPlugin(){ return deadboltPlugin; } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java index ff1a38cf3..0e0b8392f 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java @@ -189,6 +189,7 @@ private void processAlgorithmQueue() { c.getPhaseBlocks().put(location, Material.WATER); } } + } if (notifyP != null) { diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/detection/DetectionTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/detection/DetectionTask.java index 74def17be..1237198ed 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/detection/DetectionTask.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/detection/DetectionTask.java @@ -21,11 +21,11 @@ import net.countercraft.movecraft.Movecraft; import net.countercraft.movecraft.MovecraftLocation; import net.countercraft.movecraft.async.AsyncTask; +import net.countercraft.movecraft.utils.HashHitBox; +import net.countercraft.movecraft.utils.LegacyUtils; import net.countercraft.movecraft.config.Settings; import net.countercraft.movecraft.craft.Craft; import net.countercraft.movecraft.localisation.I18nSupport; -import net.countercraft.movecraft.utils.*; -import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.World; @@ -79,8 +79,11 @@ public void execute() { double ratio = (double) foundDynamicFlyBlock / totalBlocks; double foundMinimum = 0.0; for (Map> i : flyBlocks.keySet()) { - if (i.containsKey(getCraft().getType().getDynamicFlyBlock())) - foundMinimum = flyBlocks.get(i).get(0); + for (Material dFlyBlock : getCraft().getType().getDynamicFlyBlocks()){ + if (i.containsKey(dFlyBlock)) + foundMinimum = flyBlocks.get(i).get(0); + } + } ratio = ratio - (foundMinimum / 100.0); ratio = ratio * getCraft().getType().getDynamicFlyBlockSpeedFactor(); @@ -202,7 +205,7 @@ private void detectBlock(int x, int y, int z) { } } if (getCraft().getType().getDynamicFlyBlockSpeedFactor() != 0.0) { - if (blockType == getCraft().getType().getDynamicFlyBlock()) { + if (getCraft().getType().getDynamicFlyBlocks().contains(blockType)) { foundDynamicFlyBlock++; } } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/rotation/RotationTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/rotation/RotationTask.java index 392198d91..326dbf4a5 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/rotation/RotationTask.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/rotation/RotationTask.java @@ -27,9 +27,7 @@ import net.countercraft.movecraft.Rotation; import net.countercraft.movecraft.craft.Craft; import net.countercraft.movecraft.events.CraftRotateEvent; -import net.countercraft.movecraft.events.CraftTranslateEvent; import net.countercraft.movecraft.utils.*; -import net.countercraft.movecraft.utils.HashHitBox; import net.countercraft.movecraft.async.AsyncTask; import net.countercraft.movecraft.config.Settings; import net.countercraft.movecraft.craft.CraftManager; @@ -42,15 +40,14 @@ import org.bukkit.Material; import org.bukkit.World; import org.bukkit.block.Block; +import org.bukkit.block.Furnace; import org.bukkit.entity.Entity; import org.bukkit.entity.EntityType; import org.bukkit.entity.Player; import org.bukkit.inventory.InventoryHolder; import org.bukkit.inventory.ItemStack; -import org.bukkit.scheduler.BukkitRunnable; import java.util.HashSet; -import java.util.List; import java.util.Set; public class RotationTask extends AsyncTask { @@ -106,11 +103,16 @@ protected void execute() { Block fuelHolder = null; for (MovecraftLocation bTest : oldHitBox) { Block b = getCraft().getW().getBlockAt(bTest.getX(), bTest.getY(), bTest.getZ()); - if (b.getType() == Material.FURNACE) { + if (b.getState() instanceof Furnace) { InventoryHolder inventoryHolder = (InventoryHolder) b.getState(); - if ((!Settings.IsLegacy ? (inventoryHolder.getInventory().contains(Material.COAL) || inventoryHolder.getInventory().contains(Material.CHARCOAL)) || inventoryHolder.getInventory().contains(Material.COAL_BLOCK): (inventoryHolder.getInventory().contains(Material.COAL)) || inventoryHolder.getInventory().contains(Material.COAL_BLOCK))) { - fuelHolder = b; + for (Material fuelType : Settings.FuelTypes.keySet()){ + if (inventoryHolder.getInventory().contains(fuelType)){ + fuelHolder = b; + } } + /*if ((!Settings.IsLegacy ? (inventoryHolder.getInventory().contains(Material.COAL) || inventoryHolder.getInventory().contains(Material.CHARCOAL)) || inventoryHolder.getInventory().contains(Material.COAL_BLOCK): (inventoryHolder.getInventory().contains(Material.COAL)) || inventoryHolder.getInventory().contains(Material.COAL_BLOCK))) { + fuelHolder = b; + }*/ } } if (fuelHolder == null) { @@ -118,7 +120,19 @@ protected void execute() { failMessage = I18nSupport.getInternationalisedString("Translation - Failed Craft out of fuel"); } else { InventoryHolder inventoryHolder = (InventoryHolder) fuelHolder.getState(); - if (inventoryHolder.getInventory().contains(Material.COAL)) { + for (Material fuel : Settings.FuelTypes.keySet()){ + if (inventoryHolder.getInventory().contains(fuel)){ + ItemStack iStack = inventoryHolder.getInventory().getItem(inventoryHolder.getInventory().first(fuel)); + int amount = iStack.getAmount(); + if (amount == 1) { + inventoryHolder.getInventory().remove(iStack); + } else { + iStack.setAmount(amount - 1); + } + craft.setBurningFuel(craft.getBurningFuel() + Settings.FuelTypes.get(fuel)); + } + } + /*if (inventoryHolder.getInventory().contains(Material.COAL)) { ItemStack iStack = inventoryHolder.getInventory().getItem(inventoryHolder.getInventory().first(Material.COAL)); int amount = iStack.getAmount(); if (amount == 1) { @@ -146,7 +160,7 @@ protected void execute() { iStack.setAmount(amount - 1); } getCraft().setBurningFuel(getCraft().getBurningFuel() + 7.0); - } + }*/ } } else { getCraft().setBurningFuel(getCraft().getBurningFuel() - fuelBurnRate); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java index 8df7498ae..353cf5114 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java @@ -1,6 +1,5 @@ package net.countercraft.movecraft.async.translation; -import net.countercraft.movecraft.Movecraft; import net.countercraft.movecraft.MovecraftLocation; import net.countercraft.movecraft.async.AsyncTask; import net.countercraft.movecraft.config.Settings; @@ -17,10 +16,11 @@ import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.Sound; -import org.bukkit.block.Block; -import org.bukkit.block.BlockState; -import org.bukkit.block.Chest; -import org.bukkit.block.Furnace; +import org.bukkit.block.*; +import org.bukkit.block.data.Bisected; +import org.bukkit.block.data.BlockData; +import org.bukkit.block.data.Waterlogged; +import org.bukkit.block.data.type.TrapDoor; import org.bukkit.entity.Entity; import org.bukkit.entity.EntityType; import org.bukkit.entity.Player; @@ -28,7 +28,6 @@ import org.bukkit.inventory.InventoryHolder; import org.bukkit.inventory.ItemStack; import org.bukkit.potion.PotionEffect; -import org.bukkit.scheduler.BukkitRunnable; import java.util.*; import java.util.concurrent.ThreadLocalRandom; @@ -208,7 +207,7 @@ protected void execute() { explosionKey = explosionForce; Location loc = location.toBukkit(craft.getW()); int potEffRange = craft.getType().getEffectRange(); - Set potionEffects = craft.getType().getPotionEffectsToApply(); + Map potionEffects = craft.getType().getPotionEffectsToApply(); if (!loc.getBlock().getType().equals(Material.AIR)) { updates.add(new ExplosionUpdateCommand(loc, explosionKey)); collisionExplosion = true; @@ -391,29 +390,37 @@ private boolean checkFuel(){ Block fuelHolder = null; for (MovecraftLocation bTest : oldHitBox) { Block b = craft.getW().getBlockAt(bTest.getX(), bTest.getY(), bTest.getZ()); - if (b.getType() == Material.FURNACE) { - if (Settings.IsLegacy) { + if (b.getState() instanceof Furnace) { InventoryHolder inventoryHolder = (InventoryHolder) b.getState(); - if (inventoryHolder.getInventory().contains(Material.COAL)|| inventoryHolder.getInventory().contains(Material.COAL_BLOCK)) { - fuelHolder = b; - } - } else { - if (b.getState() instanceof Furnace) { - Furnace furnace = (Furnace) b.getState(); - if (furnace.getInventory().contains(Material.COAL) || furnace.getInventory().contains(Material.COAL_BLOCK) || furnace.getInventory().contains(Material.CHARCOAL)) { + for (Material fuelType : Settings.FuelTypes.keySet()){ + if (inventoryHolder.getInventory().contains(fuelType)){ fuelHolder = b; } } - } + + //if (furnace.getInventory().contains(Material.COAL) || furnace.getInventory().contains(Material.COAL_BLOCK) || furnace.getInventory().contains(Material.CHARCOAL)) { + // fuelHolder = b; + //} } } if (fuelHolder == null) { fail(I18nSupport.getInternationalisedString("Translation - Failed Craft out of fuel")); return false; } - if (Settings.IsLegacy) { InventoryHolder inventoryHolder = (InventoryHolder) fuelHolder.getState(); - if (inventoryHolder.getInventory().contains(Material.COAL)) { + for (Material fuel : Settings.FuelTypes.keySet()){ + if (inventoryHolder.getInventory().contains(fuel)){ + ItemStack iStack = inventoryHolder.getInventory().getItem(inventoryHolder.getInventory().first(fuel)); + int amount = iStack.getAmount(); + if (amount == 1) { + inventoryHolder.getInventory().remove(iStack); + } else { + iStack.setAmount(amount - 1); + } + craft.setBurningFuel(craft.getBurningFuel() + Settings.FuelTypes.get(fuel)); + } + } + /*if (inventoryHolder.getInventory().contains(Material.COAL)) { ItemStack iStack = inventoryHolder.getInventory().getItem(inventoryHolder.getInventory().first(Material.COAL)); int amount = iStack.getAmount(); if (amount == 1) { @@ -432,45 +439,35 @@ private boolean checkFuel(){ } craft.setBurningFuel(craft.getBurningFuel() + 79.0); + }*/ + + return true; + } + + private void processWaterlogging(){ + HitBox hitBox = craft.getHitBox(); + for (MovecraftLocation moveLoc : hitBox){ + Block b = moveLoc.toBukkit(craft.getW()).getBlock(); + BlockData data = b.getBlockData(); + if (!(data instanceof Waterlogged)){ + continue; } - } else { - BlockState state = fuelHolder.getState(); - if (state instanceof Furnace){ - Furnace furnace = (Furnace) state; - if (furnace.getInventory().contains(Material.COAL)){ - ItemStack iStack = furnace.getInventory().getItem(furnace.getInventory().first(Material.COAL)); - int amount = iStack.getAmount(); - if (amount == 1) { - furnace.getInventory().remove(iStack); - } else { - iStack.setAmount(amount - 1); - } - craft.setBurningFuel(craft.getBurningFuel() + 7.0); - } - if (furnace.getInventory().contains(Material.CHARCOAL)){ - ItemStack iStack = furnace.getInventory().getItem(furnace.getInventory().first(Material.CHARCOAL)); - int amount = iStack.getAmount(); - if (amount == 1) { - furnace.getInventory().remove(iStack); - } else { - iStack.setAmount(amount - 1); - } - craft.setBurningFuel(craft.getBurningFuel() + 7.0); - } - if (furnace.getInventory().contains(Material.COAL_BLOCK)){ - ItemStack iStack = furnace.getInventory().getItem(furnace.getInventory().first(Material.COAL_BLOCK)); - int amount = iStack.getAmount(); - if (amount == 1) { - furnace.getInventory().remove(iStack); - } else { - iStack.setAmount(amount - 1); - } - craft.setBurningFuel(craft.getBurningFuel() + 79.0); + if (b.getLocation().getY() > craft.getWaterLine()){ + Waterlogged wLog = (Waterlogged) data; + wLog.setWaterlogged(false); + continue; + } + if (data instanceof TrapDoor){ + TrapDoor tDoor = (TrapDoor) data; + if (tDoor.getHalf() == Bisected.Half.TOP && b.getRelative(BlockFace.DOWN).getType() == Material.WATER){ + tDoor.setWaterlogged(true); + } else if (tDoor.getHalf() == Bisected.Half.BOTTOM && b.getRelative(BlockFace.UP).getType() == Material.WATER){ + tDoor.setWaterlogged(true); + } else if (b.getRelative(tDoor.getFacing().getOppositeFace()).getType() == Material.WATER){ + tDoor.setWaterlogged(true); } } - } - return true; } public boolean failed(){ diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/AssaultCommand.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/AssaultCommand.java index 53323a034..371764343 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/AssaultCommand.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/AssaultCommand.java @@ -1,37 +1,42 @@ package net.countercraft.movecraft.commands; -import com.sk89q.worldedit.CuboidClipboard; -import com.sk89q.worldedit.Vector; -import com.sk89q.worldedit.blocks.BaseBlock; -import com.sk89q.worldedit.bukkit.selections.CuboidSelection; -import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard; +import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldguard.LocalPlayer; import com.sk89q.worldguard.protection.flags.DefaultFlag; +import com.sk89q.worldguard.protection.flags.Flag; +import com.sk89q.worldguard.protection.flags.Flags; import com.sk89q.worldguard.protection.flags.StateFlag; +import com.sk89q.worldguard.protection.managers.RegionManager; import com.sk89q.worldguard.protection.regions.ProtectedRegion; import net.countercraft.movecraft.Movecraft; import net.countercraft.movecraft.MovecraftRepair; +import net.countercraft.movecraft.compat.we7.IMovecraftRepair; import net.countercraft.movecraft.config.Settings; import net.countercraft.movecraft.localisation.I18nSupport; +import net.countercraft.movecraft.utils.WorldEditUtils; +import net.countercraft.movecraft.utils.WorldguardUtils; +import net.countercraft.movecraft.utils.weVectorUtils; import net.countercraft.movecraft.warfare.assault.Assault; import net.countercraft.movecraft.warfare.assault.AssaultBarTask; import net.countercraft.movecraft.warfare.assault.AssaultUtils; import net.countercraft.movecraft.warfare.siege.Siege; import org.bukkit.*; -import org.bukkit.block.Block; import org.bukkit.command.Command; import org.bukkit.command.CommandExecutor; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; import org.bukkit.scheduler.BukkitRunnable; +import org.bukkit.util.Vector; -import java.io.File; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; import java.util.Map; import static net.countercraft.movecraft.utils.ChatUtils.MOVECRAFT_COMMAND_PREFIX; import static net.countercraft.movecraft.warfare.assault.AssaultUtils.getCostToAssault; public class AssaultCommand implements CommandExecutor{ + @Override public boolean onCommand(CommandSender commandSender, Command command, String s, String[] args) { if (!command.getName().equalsIgnoreCase("assault")) { @@ -46,7 +51,6 @@ public boolean onCommand(CommandSender commandSender, Command command, String s, return true; } Player player = (Player) commandSender; - if (!player.hasPermission("movecraft.assault")) { player.sendMessage(MOVECRAFT_COMMAND_PREFIX + I18nSupport.getInternationalisedString("Insufficient Permissions")); return true; @@ -55,16 +59,25 @@ public boolean onCommand(CommandSender commandSender, Command command, String s, player.sendMessage(MOVECRAFT_COMMAND_PREFIX + I18nSupport.getInternationalisedString("No region specified")); return true; } - ProtectedRegion aRegion = Movecraft.getInstance().getWorldGuardPlugin().getRegionManager(player.getWorld()).getRegion(args[0]); + RegionManager manager = WorldguardUtils.getRegionManager(player.getWorld()); + ProtectedRegion aRegion = manager.getRegion(args[0]); + + if (aRegion == null) { player.sendMessage(MOVECRAFT_COMMAND_PREFIX + I18nSupport.getInternationalisedString("Region not found")); return true; } LocalPlayer lp = Movecraft.getInstance().getWorldGuardPlugin().wrapPlayer(player); - Map allRegions = Movecraft.getInstance().getWorldGuardPlugin().getRegionManager(player.getWorld()).getRegions(); + Map allRegions = WorldguardUtils.getRegionManager(player.getWorld()).getRegions(); + Flag flag; + if (Settings.IsLegacy){ + flag = DefaultFlag.TNT; + } else { + flag = Flags.TNT; + } boolean foundOwnedRegion = false; for (ProtectedRegion iRegion : allRegions.values()) { - if (iRegion.isOwner(lp) && iRegion.getFlag(DefaultFlag.TNT) == StateFlag.State.DENY) { + if (iRegion.isOwner(lp) && iRegion.getFlag(flag) == StateFlag.State.DENY) { foundOwnedRegion = true; break; } @@ -83,7 +96,7 @@ public boolean onCommand(CommandSender commandSender, Command command, String s, } // a region can only be assaulted if it disables TNT, this is to prevent child regions or sub regions from being assaulted // regions with no owners can not be assaulted - if (aRegion.getFlag(DefaultFlag.TNT) != StateFlag.State.DENY || aRegion.getOwners().size() == 0) + if (aRegion.getFlag(flag) != StateFlag.State.DENY || aRegion.getOwners().size() == 0) canBeAssaulted = false; { @@ -102,7 +115,8 @@ public boolean onCommand(CommandSender commandSender, Command command, String s, } } } - if (!AssaultUtils.areDefendersOnline(aRegion)) { + boolean areDefendersOnline = AssaultUtils.areDefendersOnline(aRegion); + if (!areDefendersOnline) { canBeAssaulted = false; } if (aRegion.isMember(lp)) { @@ -118,7 +132,7 @@ public boolean onCommand(CommandSender commandSender, Command command, String s, return true; } // if(aRegion.getType() instanceof ProtectedCuboidRegion) { // Originally I wasn't going to do non-cubes, but we'll try it and see how it goes. In theory it may repair more than it should but... meh... - String repairStateName = Movecraft.getInstance().getDataFolder().getAbsolutePath() + "/RegionRepairStates"; + /*String repairStateName = Movecraft.getInstance().getDataFolder().getAbsolutePath() + "/RegionRepairStates"; File file = new File(repairStateName); if (!file.exists()) { file.mkdirs(); @@ -127,11 +141,12 @@ public boolean onCommand(CommandSender commandSender, Command command, String s, repairStateName += aRegion.getId().replaceAll("\\s+", "_"); repairStateName += ".schematic"; file = new File(repairStateName); +*/ org.bukkit.util.Vector min = weVectorUtils.getMinimumPoint(aRegion); + org.bukkit.util.Vector max = weVectorUtils.getMaximumPoint(aRegion); - org.bukkit.util.Vector min = new org.bukkit.util.Vector(aRegion.getMinimumPoint().getBlockX(), aRegion.getMinimumPoint().getBlockY(), aRegion.getMinimumPoint().getBlockZ()); - org.bukkit.util.Vector max = new org.bukkit.util.Vector(aRegion.getMaximumPoint().getBlockX(), aRegion.getMaximumPoint().getBlockY(), aRegion.getMaximumPoint().getBlockZ()); - /*if (max.subtract(min).getBlockX() > 256) { + /* + if (max.subtract(min).getBlockX() > 256) { if (min.getBlockX() < player.getLocation().getBlockX() - 128) { min = min.setX(player.getLocation().getBlockX() - 128); } @@ -148,7 +163,8 @@ public boolean onCommand(CommandSender commandSender, Command command, String s, } }*/ MovecraftRepair movecraftRepair = Movecraft.getInstance().getMovecraftRepair(); - if (!movecraftRepair.saveRegionRepairState(Movecraft.getInstance(), ((Player) commandSender).getWorld(),min, max, aRegion.getId().replaceAll("´\\s+", "_"))){ + + if (!movecraftRepair.saveRegionRepairState(Movecraft.getInstance(), (player).getWorld(),aRegion)){ player.sendMessage(I18nSupport.getInternationalisedString("Could not save file")); return true; } @@ -162,31 +178,37 @@ public boolean onCommand(CommandSender commandSender, Command command, String s, for (Player p : Bukkit.getOnlinePlayers()) { p.playSound(p.getLocation(), Sound.ENTITY_WITHER_DEATH, 1, (float) 0.25); } - new AssaultBarTask(Movecraft.getInstance() ,args[0] ,System.currentTimeMillis()).runTaskTimer(Movecraft.getInstance(), 0, 20); + AssaultBarTask abTask = new AssaultBarTask(Movecraft.getInstance() ,args[0] ,System.currentTimeMillis()); + abTask.runTaskTimer(Movecraft.getInstance(), 0, 20); final String taskAssaultName = args[0]; final Player taskPlayer = player; final World taskWorld = player.getWorld(); - final Long taskMaxDamages = (long) AssaultUtils.getMaxDamages(aRegion); + final long taskMaxDamages = (long) AssaultUtils.getMaxDamages(aRegion); final org.bukkit.util.Vector taskMin = min; final org.bukkit.util.Vector taskMax = max; //TODO: Make async new BukkitRunnable() { @Override public void run() { - //progressBar.setVisible(false); + abTask.cancel(); Bukkit.getServer().broadcastMessage(String.format("The Assault of %s has commenced! The assault leader is %s. Destroy the enemy region!" , taskAssaultName, taskPlayer.getDisplayName())); for (Player p : Bukkit.getOnlinePlayers()) { p.playSound(p.getLocation(), Sound.ENTITY_WITHER_DEATH, 1, 0.25F); } Movecraft.getInstance().getAssaultManager().getAssaults().add(new Assault(taskAssaultName, taskPlayer, taskWorld, System.currentTimeMillis(), taskMaxDamages, taskMin, taskMax)); - ProtectedRegion tRegion = Movecraft.getInstance().getWorldGuardPlugin().getRegionManager(taskWorld).getRegion(taskAssaultName); - tRegion.setFlag(DefaultFlag.TNT, StateFlag.State.ALLOW); - } - }.runTaskLater(Movecraft.getInstance(), (20 * Settings.AssaultDelay)); + RegionManager manager1 = WorldguardUtils.getRegionManager(taskWorld); + ProtectedRegion tRegion = manager1.getRegion(taskAssaultName); + + tRegion.setFlag(flag, StateFlag.State.ALLOW); + } + }.runTaskLaterAsynchronously(Movecraft.getInstance(), (20 * Settings.AssaultDelay)); return true; + } + + } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/AssaultInfoCommand.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/AssaultInfoCommand.java index e886c140f..2c4b58d59 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/AssaultInfoCommand.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/AssaultInfoCommand.java @@ -3,6 +3,8 @@ import com.sk89q.worldguard.LocalPlayer; import com.sk89q.worldguard.protection.ApplicableRegionSet; import com.sk89q.worldguard.protection.flags.DefaultFlag; +import com.sk89q.worldguard.protection.flags.Flag; +import com.sk89q.worldguard.protection.flags.Flags; import com.sk89q.worldguard.protection.flags.StateFlag; import com.sk89q.worldguard.protection.regions.ProtectedRegion; import net.countercraft.movecraft.Movecraft; @@ -42,16 +44,22 @@ public boolean onCommand(CommandSender commandSender, Command command, String s, player.sendMessage(MOVECRAFT_COMMAND_PREFIX + I18nSupport.getInternationalisedString("Insufficient Permissions")); return true; } - ApplicableRegionSet regions = Movecraft.getInstance().getWorldGuardPlugin().getRegionManager(player.getWorld()).getApplicableRegions(player.getLocation()); + ApplicableRegionSet regions = WorldguardUtils.getRegionsAt(player.getLocation()); if (regions.size() == 0) { player.sendMessage(MOVECRAFT_COMMAND_PREFIX + I18nSupport.getInternationalisedString("No Assault eligible regions found")); return true; } LocalPlayer lp = Movecraft.getInstance().getWorldGuardPlugin().wrapPlayer(player); - Map allRegions = Movecraft.getInstance().getWorldGuardPlugin().getRegionManager(player.getWorld()).getRegions(); + Map allRegions = WorldguardUtils.getRegionManager(player.getWorld()).getRegions(); boolean foundOwnedRegion = false; + Flag flag; + if (Settings.IsLegacy){ + flag = DefaultFlag.TNT; + } else { + flag = Flags.TNT; + } for (ProtectedRegion iRegion : allRegions.values()) { - if (iRegion.isOwner(lp) && iRegion.getFlag(DefaultFlag.TNT) == StateFlag.State.DENY) { + if (iRegion.isOwner(lp) && iRegion.getFlag(flag) == StateFlag.State.DENY) { foundOwnedRegion = true; } } @@ -65,7 +73,7 @@ public boolean onCommand(CommandSender commandSender, Command command, String s, for (ProtectedRegion tRegion : regions.getRegions()) { // a region can only be assaulted if it disables TNT, this is to prevent child regions or sub regions from being assaulted // regions with no owners can not be assaulted - if (tRegion.getFlag(DefaultFlag.TNT) != StateFlag.State.DENY || tRegion.getOwners().size() == 0) + if (tRegion.getFlag(flag) != StateFlag.State.DENY || tRegion.getOwners().size() == 0) continue ; for (Siege siege : Movecraft.getInstance().getSiegeManager().getSieges()) { // siegable regions can not be assaulted diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/MovecraftCommand.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/MovecraftCommand.java index 27240ce79..1c1f6e14b 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/MovecraftCommand.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/MovecraftCommand.java @@ -35,6 +35,11 @@ public boolean onCommand(CommandSender commandSender, Command command, String s, commandSender.sendMessage(MOVECRAFT_COMMAND_PREFIX + "Reloaded types"); return true; } + if (args.length == 1 && args[0].equalsIgnoreCase("reloadconfig") && commandSender.hasPermission("movecraft.commands.movecraft.reloadconfig")){ + Movecraft.getInstance().reloadConfig(); + commandSender.sendMessage(MOVECRAFT_COMMAND_PREFIX + "Reloaded config"); + return true; + } commandSender.sendMessage(MOVECRAFT_COMMAND_PREFIX + "Error, invalid syntax"); return true; @@ -46,6 +51,7 @@ public List onTabComplete(CommandSender commandSender, Command command, return Collections.emptyList(); List completions = new ArrayList<>(); completions.add("reloadtypes"); + completions.add("reloadconfig"); List returnValues = new ArrayList<>(); for(String completion : completions) if(completion.toLowerCase().startsWith(args[args.length-1].toLowerCase())) diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/ReleaseCommand.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/ReleaseCommand.java index f08dc3648..06ae68db1 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/ReleaseCommand.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/ReleaseCommand.java @@ -4,7 +4,6 @@ import net.countercraft.movecraft.craft.CraftManager; import net.countercraft.movecraft.localisation.I18nSupport; import org.bukkit.Bukkit; -import org.bukkit.ChatColor; import org.bukkit.command.Command; import org.bukkit.command.CommandSender; import org.bukkit.command.TabExecutor; diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/RepairCommand.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/RepairCommand.java index 39b3f3b12..69a4a2373 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/RepairCommand.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/RepairCommand.java @@ -3,14 +3,11 @@ import net.countercraft.movecraft.Movecraft; import net.countercraft.movecraft.repair.Repair; import net.countercraft.movecraft.utils.TopicPaginator; -import org.bukkit.Bukkit; import org.bukkit.command.Command; import org.bukkit.command.CommandExecutor; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; -import java.util.Collection; - import static net.countercraft.movecraft.utils.ChatUtils.MOVECRAFT_COMMAND_PREFIX; public class RepairCommand implements CommandExecutor { diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/SiegeCommand.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/SiegeCommand.java index 509ec0bed..12d7a43d8 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/SiegeCommand.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/SiegeCommand.java @@ -1,37 +1,42 @@ package net.countercraft.movecraft.commands; +import com.sk89q.worldedit.bukkit.BukkitWorld; +import com.sk89q.worldedit.util.Location; +import com.sk89q.worldguard.LocalPlayer; +import com.sk89q.worldguard.WorldGuard; import com.sk89q.worldguard.protection.ApplicableRegionSet; import com.sk89q.worldguard.protection.regions.ProtectedRegion; +import com.sk89q.worldguard.protection.regions.RegionQuery; import net.countercraft.movecraft.Movecraft; -import net.countercraft.movecraft.craft.Craft; -import net.countercraft.movecraft.craft.CraftManager; +import net.countercraft.movecraft.config.Settings; import net.countercraft.movecraft.localisation.I18nSupport; -import net.countercraft.movecraft.utils.HashHitBox; import net.countercraft.movecraft.utils.TopicPaginator; +import net.countercraft.movecraft.utils.WorldguardUtils; import net.countercraft.movecraft.warfare.siege.Siege; import net.countercraft.movecraft.warfare.siege.SiegeManager; import net.countercraft.movecraft.warfare.siege.SiegeStage; import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.Sound; +import org.bukkit.World; import org.bukkit.boss.BarColor; import org.bukkit.boss.BarFlag; import org.bukkit.boss.BarStyle; import org.bukkit.command.Command; import org.bukkit.command.CommandExecutor; import org.bukkit.command.CommandSender; +import org.bukkit.command.TabExecutor; import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.text.NumberFormat; -import java.util.Arrays; -import java.util.Calendar; -import java.util.TimeZone; -import java.util.concurrent.atomic.AtomicReference; +import java.util.*; import java.util.logging.Level; import static net.countercraft.movecraft.utils.ChatUtils.MOVECRAFT_COMMAND_PREFIX; -public class SiegeCommand implements CommandExecutor { +public class SiegeCommand implements TabExecutor { //TODO: Add tab complete private final NumberFormat currencyFormat = NumberFormat.getCurrencyInstance(); @Override @@ -86,8 +91,8 @@ private boolean infoCommand(CommandSender commandSender, String[] args){ commandSender.sendMessage("Cost to siege: " + ChatColor.RED + currencyFormat.format(siege.getCost())); commandSender.sendMessage("Daily income: " + ChatColor.RED + currencyFormat.format(siege.getDailyIncome())); commandSender.sendMessage("Day of week: " + ChatColor.RED + dayToString(siege.getDayOfWeek())); - commandSender.sendMessage("Start time: " + ChatColor.RED + String.format("%02d", siege.getStartTime()/100) + ":" + String.format("%02d", siege.getStartTime()%100) + " UTC"); - commandSender.sendMessage("End time: " + ChatColor.RED + String.format("%02d", siege.getScheduleEnd()/100) + ":" + String.format("%02d",siege.getScheduleEnd()%100) + " UTC"); + commandSender.sendMessage("Start time: " + ChatColor.RED + String.format("%02d", siege.getStartTime()/100) + ":" + String.format("%02d", siege.getStartTime()%100) + " " + Settings.SiegeTimeZone); + commandSender.sendMessage("End time: " + ChatColor.RED + String.format("%02d", siege.getScheduleEnd()/100) + ":" + String.format("%02d",siege.getScheduleEnd()%100) + " " + Settings.SiegeTimeZone); commandSender.sendMessage("Duration: " + ChatColor.RED + String.format("%02d", siege.getDuration()/100) + ":" + String.format("%02d", siege.getDuration()%100)); return true; @@ -134,7 +139,7 @@ private boolean beginCommand(CommandSender commandSender){ } } Siege siege = null; - ApplicableRegionSet regions = Movecraft.getInstance().getWorldGuardPlugin().getRegionManager(player.getWorld()).getApplicableRegions(player.getLocation()); + ApplicableRegionSet regions = WorldguardUtils.getRegionsAt(player.getLocation()); search: for (ProtectedRegion tRegion : regions.getRegions()) { for (Siege tempSiege : siegeManager.getSieges()) { @@ -150,7 +155,7 @@ private boolean beginCommand(CommandSender commandSender){ } long cost = siege.getCost(); for (Siege tempSiege : siegeManager.getSieges()) { - ProtectedRegion tregion = Movecraft.getInstance().getWorldGuardPlugin().getRegionManager(player.getWorld()).getRegion(tempSiege.getCaptureRegion()); + ProtectedRegion tregion = WorldguardUtils.getRegionManager(player.getWorld()).getRegion(tempSiege.getCaptureRegion()); assert tregion != null; if (tempSiege.isDoubleCostPerOwnedSiegeRegion() && tregion.getOwners().contains(player.getUniqueId())) cost *= 2; @@ -160,15 +165,22 @@ private boolean beginCommand(CommandSender commandSender){ player.sendMessage(MOVECRAFT_COMMAND_PREFIX + String.format("You do not have enough money. You need %d", cost)); return true; } - Calendar rightNow = Calendar.getInstance(TimeZone.getTimeZone("UTC")); + Calendar rightNow = Calendar.getInstance(TimeZone.getTimeZone(Settings.SiegeTimeZone)); int hour = rightNow.get(Calendar.HOUR_OF_DAY); int minute = rightNow.get(Calendar.MINUTE); int currMilitaryTime = hour * 100 + minute; int dayOfWeek = rightNow.get(Calendar.DAY_OF_WEEK); - if (currMilitaryTime <= siege.getScheduleStart() || currMilitaryTime >= siege.getScheduleEnd() || dayOfWeek != siege.getDayOfWeek()) { + Movecraft.getInstance().getLogger().info(String.valueOf(currMilitaryTime)); + if (currMilitaryTime <= siege.getScheduleStart() || currMilitaryTime >= siege.getScheduleEnd()) { player.sendMessage(MOVECRAFT_COMMAND_PREFIX + I18nSupport.getInternationalisedString("The time is not during the Siege schedule")); return true; } + if (siege.getDayOfWeek() > 0){ + if (dayOfWeek != siege.getDayOfWeek()){ + player.sendMessage(MOVECRAFT_COMMAND_PREFIX + I18nSupport.getInternationalisedString("The time is not during the Siege schedule")); + return true; + } + } for (String startCommand : siege.getCommandsOnStart()) { Bukkit.getServer().dispatchCommand(Bukkit.getServer().getConsoleSender(), startCommand.replaceAll("%r", siege.getAttackRegion()).replaceAll("%c", "" + siege.getCost())); } @@ -191,6 +203,8 @@ private boolean beginCommand(CommandSender commandSender){ private String dayToString(int day){ String output = "Error"; switch (day){ + case 0: output = "All days"; + break; case 1: output = "Monday"; break; case 2: output = "Tuesday"; @@ -209,4 +223,22 @@ private String dayToString(int day){ } return output; } + + @Nullable + @Override + public List onTabComplete(@NotNull CommandSender commandSender, @NotNull Command command, @NotNull String s, @NotNull String[] strings) { + List completions = new ArrayList<>(); + List returnList = new ArrayList<>(); + if (strings.length == 1){ + completions.add("begin"); + completions.add("info"); + completions.add("list"); + } + for (String str : completions){ + if (str.toLowerCase().startsWith(strings[strings.length -1].toLowerCase())){ + returnList.add(str); + } + } + return returnList; + } } \ No newline at end of file diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/compatmanager/DeadboltCompatManager.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/compatmanager/DeadboltCompatManager.java index c17cc416b..fe965b285 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/compatmanager/DeadboltCompatManager.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/compatmanager/DeadboltCompatManager.java @@ -1,5 +1,7 @@ package net.countercraft.movecraft.compatmanager; +import com.daemitus.deadbolt.DeadboltPlugin; +import net.countercraft.movecraft.Movecraft; import net.countercraft.movecraft.events.SignTranslateEvent; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; @@ -12,5 +14,6 @@ public void onSignTranslate(SignTranslateEvent event){ return; } + } } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/compatmanager/GriefPreventionCompatManager.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/compatmanager/GriefPreventionCompatManager.java new file mode 100644 index 000000000..fbb8feb22 --- /dev/null +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/compatmanager/GriefPreventionCompatManager.java @@ -0,0 +1,56 @@ +package net.countercraft.movecraft.compatmanager; + +import me.ryanhamshire.GriefPrevention.DataStore; +import me.ryanhamshire.GriefPrevention.GriefPrevention; +import me.ryanhamshire.GriefPrevention.Messages; +import net.countercraft.movecraft.Movecraft; +import net.countercraft.movecraft.MovecraftLocation; +import net.countercraft.movecraft.craft.Craft; +import net.countercraft.movecraft.events.CraftRotateEvent; +import net.countercraft.movecraft.events.CraftTranslateEvent; +import net.countercraft.movecraft.localisation.I18nSupport; +import org.bukkit.Location; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; + +public class GriefPreventionCompatManager implements Listener { + @EventHandler + public void onCraftTranslate(CraftTranslateEvent event){ + if (Movecraft.getInstance().getGriefPreventionPlugin() == null){ + return; + } + Craft craft = event.getCraft(); + for (MovecraftLocation mLoc : event.getNewHitBox()){ + Location loc = mLoc.toBukkit(craft.getW()); + GriefPrevention gp = Movecraft.getInstance().getGriefPreventionPlugin(); + String gpMessage = gp.allowBuild(craft.getNotificationPlayer(), loc); + if (gpMessage == null){ + return; + } + if (gpMessage.contains(gp.dataStore.getMessage(Messages.NoBuildPermission).replace("{0}", ""))){ + event.setFailMessage(I18nSupport.getInternationalisedString("Translation - Failed GriefPrevention")); + event.setCancelled(true); + } + } + } + + @EventHandler + public void onCraftRotate(CraftRotateEvent event){ + if (Movecraft.getInstance().getGriefPreventionPlugin() == null){ + return; + } + Craft craft = event.getCraft(); + for (MovecraftLocation mLoc : event.getNewHitBox()){ + Location loc = mLoc.toBukkit(craft.getW()); + GriefPrevention gp = Movecraft.getInstance().getGriefPreventionPlugin(); + String gpMessage = gp.allowBuild(craft.getNotificationPlayer(), loc); + if (gpMessage == null){ + return; + } + if (gpMessage.contains(gp.dataStore.getMessage(Messages.NoBuildPermission).replace("{0}", ""))){ + event.setFailMessage(I18nSupport.getInternationalisedString("Rotation - Failed GriefPrevention")); + event.setCancelled(true); + } + } + } +} diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/compatmanager/RedProtectCompatManager.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/compatmanager/RedProtectCompatManager.java new file mode 100644 index 000000000..5f906ec9e --- /dev/null +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/compatmanager/RedProtectCompatManager.java @@ -0,0 +1,12 @@ +package net.countercraft.movecraft.compatmanager; + +import net.countercraft.movecraft.events.CraftTranslateEvent; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; + +public class RedProtectCompatManager implements Listener { + @EventHandler + public void onCraftTranslate(CraftTranslateEvent event){ + + } +} diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/compatmanager/WorldGuardCompatManager.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/compatmanager/WorldGuardCompatManager.java index b26534318..a48508fc1 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/compatmanager/WorldGuardCompatManager.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/compatmanager/WorldGuardCompatManager.java @@ -1,11 +1,6 @@ package net.countercraft.movecraft.compatmanager; -import com.sk89q.minecraft.util.commands.CommandException; import com.sk89q.worldedit.bukkit.BukkitWorld; -import com.sk89q.worldedit.extension.platform.Actor; -import com.sk89q.worldedit.extent.Extent; -import com.sk89q.worldedit.extent.world.BlockQuirkExtent; -import com.sk89q.worldedit.extent.world.FastModeExtent; import com.sk89q.worldedit.util.Location; import com.sk89q.worldguard.LocalPlayer; import com.sk89q.worldguard.WorldGuard; @@ -16,7 +11,6 @@ import net.countercraft.movecraft.events.CraftRotateEvent; import net.countercraft.movecraft.events.CraftTranslateEvent; import net.countercraft.movecraft.localisation.I18nSupport; -import net.countercraft.movecraft.utils.WorldguardUtils; import org.bukkit.World; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/BlockListener.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/BlockListener.java index 53d583037..bf2f0c51c 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/BlockListener.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/BlockListener.java @@ -17,7 +17,6 @@ package net.countercraft.movecraft.listener; -import com.sk89q.worldguard.bukkit.WorldGuardPlugin; import com.sk89q.worldguard.protection.ApplicableRegionSet; import com.sk89q.worldguard.protection.flags.DefaultFlag; import net.countercraft.movecraft.Movecraft; @@ -28,7 +27,6 @@ import net.countercraft.movecraft.config.Settings; import net.countercraft.movecraft.craft.CraftManager; import net.countercraft.movecraft.localisation.I18nSupport; -import net.countercraft.movecraft.warfare.assault.Assault; import net.countercraft.movecraft.warfare.assault.AssaultUtils; import org.bukkit.Bukkit; import org.bukkit.ChatColor; @@ -61,7 +59,6 @@ import org.bukkit.scheduler.BukkitRunnable; import java.util.Arrays; -import java.util.Iterator; import java.util.List; import java.util.Random; diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/PlayerListener.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/PlayerListener.java index 95cd45968..b8fdcbaa0 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/PlayerListener.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/PlayerListener.java @@ -17,8 +17,6 @@ package net.countercraft.movecraft.listener; -import net.countercraft.movecraft.Movecraft; -import net.countercraft.movecraft.repair.Repair; import net.countercraft.movecraft.utils.HitBox; import net.countercraft.movecraft.utils.MathUtils; import net.countercraft.movecraft.MovecraftLocation; @@ -31,7 +29,6 @@ import org.bukkit.event.Listener; import org.bukkit.event.entity.EntityDamageByEntityEvent; import org.bukkit.event.entity.PlayerDeathEvent; -import org.bukkit.event.player.PlayerJoinEvent; import org.bukkit.event.player.PlayerMoveEvent; import org.bukkit.event.player.PlayerQuitEvent; diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/BlockCreateCommand.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/BlockCreateCommand.java index c42d88d3f..05f9a7993 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/BlockCreateCommand.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/BlockCreateCommand.java @@ -8,7 +8,6 @@ import org.bukkit.Material; import org.bukkit.World; import org.bukkit.block.Block; -import org.bukkit.block.BlockState; import org.bukkit.block.data.BlockData; import org.jetbrains.annotations.NotNull; diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftRotateCommand.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftRotateCommand.java index 74433d008..896e00c5b 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftRotateCommand.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftRotateCommand.java @@ -1,10 +1,10 @@ package net.countercraft.movecraft.mapUpdater.update; -import com.google.common.collect.Sets; import net.countercraft.movecraft.Movecraft; import net.countercraft.movecraft.MovecraftLocation; import net.countercraft.movecraft.Rotation; import net.countercraft.movecraft.WorldHandler; +import net.countercraft.movecraft.compat.fawe.*; import net.countercraft.movecraft.config.Settings; import net.countercraft.movecraft.craft.Craft; import net.countercraft.movecraft.craft.CraftManager; diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftTranslateCommand.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftTranslateCommand.java index 21fd0d52b..8dfdd88ff 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftTranslateCommand.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftTranslateCommand.java @@ -1,6 +1,5 @@ package net.countercraft.movecraft.mapUpdater.update; -import com.google.common.collect.Sets; import net.countercraft.movecraft.Movecraft; import net.countercraft.movecraft.MovecraftLocation; import net.countercraft.movecraft.WorldHandler; @@ -17,7 +16,6 @@ import java.util.HashSet; import java.util.LinkedList; -import java.util.Map; import java.util.Objects; import java.util.Queue; import java.util.Set; @@ -199,6 +197,8 @@ public void doUpdate() { craft.addMoveTime(time/1e9f); } + + @NotNull public Craft getCraft(){ return craft; diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/ExplosionUpdateCommand.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/ExplosionUpdateCommand.java index 19d1baae0..98243283d 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/ExplosionUpdateCommand.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/ExplosionUpdateCommand.java @@ -1,24 +1,12 @@ package net.countercraft.movecraft.mapUpdater.update; -import com.sk89q.worldedit.bukkit.BukkitWorld; -import com.sk89q.worldguard.WorldGuard; -import com.sk89q.worldguard.protection.ApplicableRegionSet; -import com.sk89q.worldguard.protection.flags.DefaultFlag; -import com.sk89q.worldguard.protection.flags.Flag; -import com.sk89q.worldguard.protection.regions.RegionQuery; import net.countercraft.movecraft.Movecraft; -import net.countercraft.movecraft.config.Settings; import net.countercraft.movecraft.utils.WorldguardUtils; import org.bukkit.Location; -import org.bukkit.entity.Entity; -import org.bukkit.entity.LivingEntity; -import org.bukkit.potion.PotionEffect; -import org.bukkit.potion.PotionEffectType; -import org.bukkit.util.Vector; +import org.bukkit.entity.TNTPrimed; +import org.bukkit.event.Event; +import org.bukkit.event.entity.EntityExplodeEvent; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; import java.util.Objects; diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/PotionEffectsUpdateCommand.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/PotionEffectsUpdateCommand.java index b1da224a1..735531431 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/PotionEffectsUpdateCommand.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/PotionEffectsUpdateCommand.java @@ -1,18 +1,20 @@ package net.countercraft.movecraft.mapUpdater.update; +import net.countercraft.movecraft.Movecraft; import org.bukkit.Location; import org.bukkit.entity.Entity; import org.bukkit.entity.LivingEntity; import org.bukkit.potion.PotionEffect; import org.bukkit.potion.PotionEffectType; +import org.bukkit.scheduler.BukkitRunnable; import java.util.*; public class PotionEffectsUpdateCommand extends UpdateCommand { private final Set livingEntities = new HashSet<>(); - private final Set potionEffects; - public PotionEffectsUpdateCommand(Location loc, int effectRange, Set potionEffects){ + private final Map potionEffects; + public PotionEffectsUpdateCommand(Location loc, int effectRange, Map potionEffects){ this.potionEffects = potionEffects; for (Entity entity : loc.getWorld().getNearbyEntities(loc,effectRange,effectRange,effectRange)){ if (!(entity instanceof LivingEntity)){ @@ -24,9 +26,20 @@ public PotionEffectsUpdateCommand(Location loc, int effectRange, Set 0) { ItemStack fireItems = new ItemStack(Material.FIRE_CHARGE, numFireCharges); disp.getInventory().addItem(fireItems); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/repair/RepairUtils.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/repair/RepairUtils.java index 3cc1b70c6..80c617ea3 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/repair/RepairUtils.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/repair/RepairUtils.java @@ -5,7 +5,6 @@ import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard; import com.sk89q.worldedit.extent.clipboard.Clipboard; import com.sk89q.worldedit.math.BlockVector3; -import com.sk89q.worldedit.world.block.BlockState; import net.countercraft.movecraft.Movecraft; import net.countercraft.movecraft.MovecraftLocation; import net.countercraft.movecraft.MovecraftRepair; @@ -13,9 +12,7 @@ import net.countercraft.movecraft.mapUpdater.MapUpdateManager; import net.countercraft.movecraft.mapUpdater.update.WorldEditUpdateCommand; import net.countercraft.movecraft.utils.LegacyUtils; -import org.bukkit.Material; import org.bukkit.World; -import org.bukkit.event.player.PlayerInteractEvent; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; @@ -30,47 +27,23 @@ public class RepairUtils { } } - public static boolean repairRegion(String regionName, World world){ - MovecraftRepair movecraftRepair = Movecraft.getInstance().getMovecraftRepair(); - Clipboard clipboard = movecraftRepair.loadRegionRepairStateClipboard(Movecraft.getInstance(), regionName, world); - if (clipboard == null){ - return false; - } - int minX = clipboard.getMinimumPoint().getBlockX(); - int minY = clipboard.getMinimumPoint().getBlockY(); - int minZ = clipboard.getMinimumPoint().getBlockZ(); - int maxX = clipboard.getMaximumPoint().getBlockX(); - int maxY = clipboard.getMaximumPoint().getBlockY(); - int maxZ = clipboard.getMaximumPoint().getBlockZ(); - for (int x = minX; x <= maxX; x++){ - for (int y = minY; y <= maxY; y++){ - for (int z = minZ; z <= maxZ; z++){ - if (Settings.IsLegacy){ - Vector pos = new Vector(x,y,z); - BaseBlock bb = getBlock(clipboard, pos); - if (bb.isAir()){ - continue; - } - if (Settings.AssaultDestroyableBlocks.contains(LegacyUtils.getMaterial(bb.getId()))){ - if (!world.getChunkAt(x >> 4, z >> 4).isLoaded()) - world.loadChunk(x >> 4, z >> 4); - if (world.getBlockAt(x, y, z).isEmpty() || world.getBlockAt(x, y, z).isLiquid()) { - MovecraftLocation moveloc = new MovecraftLocation(x, y, z); - WorldEditUpdateCommand updateCommand = new WorldEditUpdateCommand(bb, world, moveloc, LegacyUtils.getMaterial(bb.getType()), (byte) bb.getData()); - MapUpdateManager.getInstance().scheduleUpdate(updateCommand); - } - } - } else { - BlockVector3 pos = BlockVector3.at(x,y,z); - BlockArrayClipboard bac = (BlockArrayClipboard) clipboard; - } - } + public static void legacyRepairRegion(Clipboard clipboard, World world, int x, int y, int z){ + Vector pos = new Vector(x,y,z); + BaseBlock bb = getBlock(clipboard, pos); + if (bb.isAir()){ + return; + } + if (Settings.AssaultDestroyableBlocks.contains(LegacyUtils.getMaterial(bb.getId()))){ + if (!world.getChunkAt(x >> 4, z >> 4).isLoaded()) + world.loadChunk(x >> 4, z >> 4); + if (world.getBlockAt(x, y, z).isEmpty() || world.getBlockAt(x, y, z).isLiquid()) { + MovecraftLocation moveloc = new MovecraftLocation(x, y, z); + WorldEditUpdateCommand updateCommand = new WorldEditUpdateCommand(bb, world, moveloc, LegacyUtils.getMaterial(bb.getType()), (byte) bb.getData()); + MapUpdateManager.getInstance().scheduleUpdate(updateCommand); } } - return true; } - public static BaseBlock getBlock(Clipboard clipboard, Vector pos){ BlockArrayClipboard bac = (BlockArrayClipboard) clipboard; try { diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/AscendSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/AscendSign.java index 7c981b969..749bede7e 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/AscendSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/AscendSign.java @@ -5,9 +5,7 @@ import net.countercraft.movecraft.craft.Craft; import net.countercraft.movecraft.craft.CraftManager; import net.countercraft.movecraft.events.CraftDetectEvent; -import net.countercraft.movecraft.events.CraftPilotEvent; import net.countercraft.movecraft.utils.LegacyUtils; -import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.Material; import org.bukkit.World; diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CrewSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CrewSign.java index fde7913ed..66cffc865 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CrewSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CrewSign.java @@ -21,9 +21,7 @@ import org.bukkit.event.player.PlayerInteractEvent; import org.bukkit.event.player.PlayerRespawnEvent; -import java.util.ArrayList; import java.util.Arrays; -import java.util.List; public class CrewSign implements Listener { //As of 1.13, each bed color have their own values diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RegionDamagedSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RegionDamagedSign.java index e2cb9fb41..93b14bbde 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RegionDamagedSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RegionDamagedSign.java @@ -1,14 +1,22 @@ package net.countercraft.movecraft.sign; +import com.sk89q.worldedit.bukkit.BukkitAdapter; +import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard; +import com.sk89q.worldedit.extent.clipboard.Clipboard; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.world.block.BaseBlock; +import com.sk89q.worldguard.protection.managers.RegionManager; import com.sk89q.worldguard.protection.regions.ProtectedRegion; import net.countercraft.movecraft.Movecraft; +import net.countercraft.movecraft.MovecraftLocation; +import net.countercraft.movecraft.MovecraftRepair; import net.countercraft.movecraft.config.Settings; import net.countercraft.movecraft.localisation.I18nSupport; +import net.countercraft.movecraft.mapUpdater.MapUpdateManager; +import net.countercraft.movecraft.mapUpdater.update.WorldEditUpdateCommand; import net.countercraft.movecraft.repair.RepairUtils; -import net.countercraft.movecraft.utils.LegacyUtils; -import org.bukkit.Bukkit; -import org.bukkit.ChatColor; -import org.bukkit.Material; +import net.countercraft.movecraft.utils.WorldguardUtils; +import org.bukkit.*; import org.bukkit.block.Sign; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; @@ -45,11 +53,12 @@ public void onSignRigtClick(PlayerInteractEvent event){ return; } event.getPlayer().sendMessage(I18nSupport.getInternationalisedString("Repairing region")); - if (!RepairUtils.repairRegion(regionName, event.getClickedBlock().getWorld())) { + if (!repairRegion(regionName, event.getClickedBlock().getWorld())) { Bukkit.getServer().broadcastMessage(String.format("REPAIR OF %s FAILED, CONTACT AN ADMIN", regionName)); return; } - ProtectedRegion aRegion = Movecraft.getInstance().getWorldGuardPlugin().getRegionManager(event.getClickedBlock().getWorld()).getRegion(regionName); + RegionManager manager = WorldguardUtils.getRegionManager(event.getClickedBlock().getWorld()); + ProtectedRegion aRegion = manager.getRegion(regionName); for (String ownerName : owners) { if (ownerName.length() > 16) { aRegion.getOwners().addPlayer(UUID.fromString(ownerName)); @@ -77,4 +86,40 @@ public void onSignRigtClick(PlayerInteractEvent event){ } return; } + public static boolean repairRegion(String regionName, World world){ + MovecraftRepair movecraftRepair = Movecraft.getInstance().getMovecraftRepair(); + Clipboard clipboard = movecraftRepair.loadRegionRepairStateClipboard(Movecraft.getInstance(), regionName, world); + if (clipboard == null){ + return false; + } + int minX = clipboard.getMinimumPoint().getBlockX(); + int minY = clipboard.getMinimumPoint().getBlockY(); + int minZ = clipboard.getMinimumPoint().getBlockZ(); + int maxX = clipboard.getMaximumPoint().getBlockX(); + int maxY = clipboard.getMaximumPoint().getBlockY(); + int maxZ = clipboard.getMaximumPoint().getBlockZ(); + + for (int x = minX; x <= maxX; x++){ + for (int y = minY; y <= maxY; y++){ + for (int z = minZ; z <= maxZ; z++){ + if (Settings.IsLegacy){ + RepairUtils.legacyRepairRegion(clipboard, world,x,y,z); + } else { + BlockVector3 pos = BlockVector3.at(x,y,z); + MovecraftLocation location = new MovecraftLocation(x,y,z); + BaseBlock block = clipboard.getFullBlock(pos); + Location bukkitLoc = location.toBukkit(world); + if (bukkitLoc.getBlock().isLiquid() || bukkitLoc.getBlock().getType().name().endsWith("AIR")) + continue; + if (!Settings.AssaultDestroyableBlocks.contains(bukkitLoc.getBlock().getType())) + continue; + Material type = BukkitAdapter.adapt(block.getBlockType()); + WorldEditUpdateCommand weUp = new WorldEditUpdateCommand(block, world, location, type); + MapUpdateManager.getInstance().scheduleUpdate(weUp); + } + } + } + } + return true; + } } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RepairSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RepairSign.java index 2be37fec6..72f10fd8d 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RepairSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RepairSign.java @@ -3,8 +3,6 @@ import com.sk89q.worldedit.blocks.BaseBlock; import com.sk89q.worldedit.bukkit.BukkitAdapter; import com.sk89q.worldedit.extent.clipboard.Clipboard; -import com.sk89q.worldedit.world.block.BlockState; -import com.sk89q.worldedit.world.block.BlockStateHolder; import net.countercraft.movecraft.Movecraft; import net.countercraft.movecraft.MovecraftLocation; import net.countercraft.movecraft.MovecraftRepair; @@ -22,7 +20,6 @@ import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.Material; -import org.bukkit.Material.*; import org.bukkit.World; import org.bukkit.block.Block; import org.bukkit.block.Sign; diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/StatusSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/StatusSign.java index cddcb1b80..a9e418fc3 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/StatusSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/StatusSign.java @@ -16,7 +16,6 @@ import org.bukkit.inventory.InventoryHolder; import org.bukkit.inventory.ItemStack; -import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/SubcraftRotateSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/SubcraftRotateSign.java index e33ad8b9f..5a60e9a58 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/SubcraftRotateSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/SubcraftRotateSign.java @@ -8,12 +8,8 @@ import net.countercraft.movecraft.craft.CraftManager; import net.countercraft.movecraft.craft.CraftType; import net.countercraft.movecraft.craft.ICraft; -import net.countercraft.movecraft.events.CraftDetectEvent; -import net.countercraft.movecraft.events.CraftReleaseEvent; -import net.countercraft.movecraft.events.CraftRotateEvent; import net.countercraft.movecraft.localisation.I18nSupport; import net.countercraft.movecraft.utils.LegacyUtils; -import net.countercraft.movecraft.utils.MathUtils; import org.bukkit.ChatColor; import org.bukkit.Location; import org.bukkit.Material; diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/LegacyWEUtils.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/LegacyWEUtils.java new file mode 100644 index 000000000..43cf53474 --- /dev/null +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/LegacyWEUtils.java @@ -0,0 +1,15 @@ +package net.countercraft.movecraft.utils; + +import com.sk89q.worldguard.protection.regions.ProtectedRegion; +import org.bukkit.util.Vector; + +public class LegacyWEUtils { + public static Vector getMinimumPoint(ProtectedRegion region){ + com.sk89q.worldedit.Vector weMin = region.getMaximumPoint(); + return WorldEditUtils.toBukkitVector(weMin); + } + public static Vector getMaximumPoint(ProtectedRegion region){ + com.sk89q.worldedit.Vector weMax = region.getMaximumPoint(); + return WorldEditUtils.toBukkitVector(weMax); + } +} diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/WorldEditUtils.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/WorldEditUtils.java index 295ead35b..d793cbdc1 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/WorldEditUtils.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/WorldEditUtils.java @@ -11,6 +11,14 @@ public static Vector toWeVector(org.bukkit.util.Vector bukkitVector){ return new Vector(bukkitVector.getBlockX(),bukkitVector.getBlockY(),bukkitVector.getBlockZ()); } + public static org.bukkit.util.Vector toBukkitVector(Vector vector){ + return new org.bukkit.util.Vector(vector.getBlockX(),vector.getBlockY(),vector.getBlockZ()); + } + + public static org.bukkit.util.Vector toBukkitVector(BlockVector3 vector){ + return new org.bukkit.util.Vector(vector.getBlockX(),vector.getBlockY(),vector.getBlockZ()); + } + public static BlockVector3 toBlockVector(org.bukkit.util.Vector bukkitVector){ return BlockVector3.at(bukkitVector.getBlockX(),bukkitVector.getBlockY(),bukkitVector.getBlockZ()); } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/WorldguardUtils.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/WorldguardUtils.java index 741414b08..bc0ccdaec 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/WorldguardUtils.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/WorldguardUtils.java @@ -1,11 +1,15 @@ package net.countercraft.movecraft.utils; +import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.bukkit.BukkitWorld; +import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldguard.WorldGuard; import com.sk89q.worldguard.protection.ApplicableRegionSet; import com.sk89q.worldguard.protection.flags.DefaultFlag; +import com.sk89q.worldguard.protection.flags.Flag; import com.sk89q.worldguard.protection.flags.Flags; import com.sk89q.worldguard.protection.flags.StateFlag; +import com.sk89q.worldguard.protection.managers.RegionManager; import com.sk89q.worldguard.protection.regions.ProtectedRegion; import com.sk89q.worldguard.protection.regions.RegionQuery; import net.countercraft.movecraft.Movecraft; @@ -17,6 +21,8 @@ import org.bukkit.World; import org.bukkit.entity.Player; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; import java.util.UUID; public class WorldguardUtils { @@ -75,4 +81,34 @@ public static boolean explosionsPermitted(Location loc){ } return true; } + public static ApplicableRegionSet getRegionsAt(Location loc){ + World world = loc.getWorld(); + ApplicableRegionSet regions; + if (Settings.IsLegacy) { + regions = Movecraft.getInstance().getWorldGuardPlugin().getRegionManager(world).getApplicableRegions(loc); + } else { + RegionQuery query = WorldGuard.getInstance().getPlatform().getRegionContainer().createQuery(); + com.sk89q.worldedit.world.World weWorld = new BukkitWorld(world); + com.sk89q.worldedit.util.Location wgLoc = new com.sk89q.worldedit.util.Location(weWorld, loc.getX(), loc.getY(), loc.getZ()); + regions = query.getApplicableRegions(wgLoc); + } + return regions; + } + public static RegionManager getRegionManager(World world){ + RegionManager manager; + if (Settings.IsLegacy){ + try { + manager = Movecraft.getInstance().getWorldGuardPlugin().getRegionManager(world); + } catch (Throwable t){ + manager = null; + } + } else { + com.sk89q.worldedit.world.World weWorld = new BukkitWorld(world); + manager = WorldGuard.getInstance().getPlatform().getRegionContainer().get(weWorld); + } + return manager; + } + public Flag flag(String string){ + return null; + } } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/weVectorUtils.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/weVectorUtils.java new file mode 100644 index 000000000..f06052949 --- /dev/null +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/weVectorUtils.java @@ -0,0 +1,60 @@ +package net.countercraft.movecraft.utils; + +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldguard.protection.regions.ProtectedRegion; +import net.countercraft.movecraft.config.Settings; +import org.bukkit.util.Vector; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +public class weVectorUtils { + private static Method getMinimumPoint; + private static Method getMaximumPoint; + static { + try { + getMinimumPoint = ProtectedRegion.class.getDeclaredMethod("getMinimumPoint"); + getMaximumPoint = ProtectedRegion.class.getDeclaredMethod("getMaximumPoint"); + } catch (NoSuchMethodException e) { + getMaximumPoint = null; + getMinimumPoint = null; + } + } + public static org.bukkit.util.Vector getMinimumPoint(ProtectedRegion region) { + org.bukkit.util.Vector ret = null; + if (Settings.IsLegacy) { + ret = LegacyWEUtils.getMinimumPoint(region); + + } else { + + try { + BlockVector3 min = getMinimumPoint != null ? (BlockVector3) getMinimumPoint.invoke(region) : null; + if (min != null) { + ret = new org.bukkit.util.Vector(min.getBlockX(), min.getBlockY(), min.getBlockZ()); + } + } catch (IllegalAccessException | InvocationTargetException e) { + e.printStackTrace(); + } + } + return ret; + } + + public static org.bukkit.util.Vector getMaximumPoint(ProtectedRegion region){ + org.bukkit.util.Vector ret = null; + if (Settings.IsLegacy) { + ret = LegacyWEUtils.getMaximumPoint(region); + + } else { + try { + BlockVector3 min = getMaximumPoint != null ? (BlockVector3) getMaximumPoint.invoke(region) : null; + if (min != null) { + ret = new Vector(min.getBlockX(), min.getBlockY(), min.getBlockZ()); + } + } catch (IllegalAccessException | InvocationTargetException e) { + e.printStackTrace(); + } + + } + return ret; + } +} diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/assault/AssaultBarTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/assault/AssaultBarTask.java index 1485661ce..aeea5d5ee 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/assault/AssaultBarTask.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/assault/AssaultBarTask.java @@ -37,6 +37,9 @@ public void run() { //Bukkit.broadcastMessage(String.valueOf(startTime) + ", " + String.valueOf(System.currentTimeMillis()) + ", " + String.valueOf(progress) + ", " + String.valueOf(timePassed)); if (assaultInPreparation){ prepBar.setVisible(true); + if (progress > 1.0){ + progress = 1.0; + } if (progress >= 0.0 && progress <= 1.0){ prepBar.setProgress(progress); @@ -46,4 +49,10 @@ public void run() { this.cancel(); } } + + public void cancel(){ + prepBar.setVisible(false); + prepBar = null; + super.cancel(); + } } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/assault/AssaultTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/assault/AssaultTask.java index b547912c1..53becbe9a 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/assault/AssaultTask.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/assault/AssaultTask.java @@ -1,11 +1,16 @@ package net.countercraft.movecraft.warfare.assault; import com.sk89q.worldguard.protection.flags.DefaultFlag; +import com.sk89q.worldguard.protection.flags.Flag; +import com.sk89q.worldguard.protection.flags.Flags; import com.sk89q.worldguard.protection.flags.StateFlag; +import com.sk89q.worldguard.protection.managers.RegionManager; import com.sk89q.worldguard.protection.regions.ProtectedRegion; import net.countercraft.movecraft.Movecraft; import net.countercraft.movecraft.config.Settings; import net.countercraft.movecraft.repair.RepairUtils; +import net.countercraft.movecraft.sign.RegionDamagedSign; +import net.countercraft.movecraft.utils.WorldguardUtils; import org.bukkit.*; import org.bukkit.block.Sign; import org.bukkit.boss.BarColor; @@ -17,9 +22,14 @@ public class AssaultTask extends BukkitRunnable { private final Assault assault; - + private final Flag flag; public AssaultTask(Assault assault) { this.assault = assault; + if (Settings.IsLegacy){ + flag = DefaultFlag.TNT; + } else { + flag = Flags.TNT; + } } @@ -74,9 +84,14 @@ public void run() { assault.getRunning().set(false); World w = assault.getWorld(); Bukkit.getServer().broadcastMessage(String.format("The assault of %s was successful!", assault.getRegionName())); - ProtectedRegion tRegion = Movecraft.getInstance().getWorldGuardPlugin().getRegionManager(w).getRegion(assault.getRegionName()); + RegionManager manager = WorldguardUtils.getRegionManager(w); + ProtectedRegion tRegion = manager.getRegion(assault.getRegionName()); assert tRegion != null; - tRegion.setFlag(DefaultFlag.TNT, StateFlag.State.DENY); + if (Settings.IsLegacy) { + tRegion.setFlag(flag, StateFlag.State.DENY); + } else { + tRegion.setFlag(flag, StateFlag.State.DENY); + } //first, find a position for the repair beacon int beaconX = assault.getMinPos().getBlockX(); @@ -91,7 +106,7 @@ public void run() { } } if(!good) { - Bukkit.getServer().broadcastMessage(String.format("BEACON PLACEMENT FOR %s FAILED, CONTACT AN ADMIN!", assault)); + Bukkit.getServer().broadcastMessage(String.format("BEACON PLACEMENT FOR %s FAILED, CONTACT AN ADMIN!", assault.getRegionName().toUpperCase())); } else { int x, y, z; @@ -136,7 +151,7 @@ public void run() { w.getBlockAt(beaconX + 2, beaconY + 3, beaconZ + 1).setType(Material.WALL_SIGN); Sign s = (Sign) w.getBlockAt(beaconX + 2, beaconY + 3, beaconZ + 1).getState(); s.setLine(0, ChatColor.RED + "REGION DAMAGED!"); - s.setLine(1, "Region:" + assault); + s.setLine(1, "Region:" + assault.getRegionName()); s.setLine(2, "Damage:" + assault.getDamages()); s.setLine(3, "Owner:" + getRegionOwnerList(tRegion)); s.update(); @@ -152,9 +167,9 @@ public void run() { Bukkit.getServer().broadcastMessage(String.format("The assault of %s has failed!", assault.getRegionName())); ProtectedRegion tRegion = Movecraft.getInstance().getWorldGuardPlugin().getRegionManager(assault.getWorld()).getRegion(assault.getRegionName()); assert tRegion != null; - tRegion.setFlag(DefaultFlag.TNT, StateFlag.State.DENY); + tRegion.setFlag(flag, StateFlag.State.DENY); // repair the damages that have occurred so far - if (!RepairUtils.repairRegion(assault.getRegionName(), assault.getWorld())) { + if (!RegionDamagedSign.repairRegion(assault.getRegionName(), assault.getWorld())) { Bukkit.getServer().broadcastMessage(String.format("REPAIR OF %s FAILED, CONTACT AN ADMIN", assault.getRegionName().toUpperCase())); } } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/assault/AssaultUtils.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/assault/AssaultUtils.java index 236699931..0d4716c4f 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/assault/AssaultUtils.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/assault/AssaultUtils.java @@ -1,19 +1,31 @@ package net.countercraft.movecraft.warfare.assault; +import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldguard.bukkit.WorldGuardPlugin; import com.sk89q.worldguard.protection.ApplicableRegionSet; +import com.sk89q.worldguard.protection.flags.DefaultFlag; +import com.sk89q.worldguard.protection.flags.Flag; +import com.sk89q.worldguard.protection.flags.Flags; +import com.sk89q.worldguard.protection.flags.StateFlag; import com.sk89q.worldguard.protection.regions.ProtectedRegion; import net.countercraft.movecraft.Movecraft; +import net.countercraft.movecraft.MovecraftRepair; import net.countercraft.movecraft.config.Settings; +import net.countercraft.movecraft.localisation.I18nSupport; import net.countercraft.movecraft.utils.LegacyUtils; +import net.countercraft.movecraft.utils.WorldEditUtils; +import net.countercraft.movecraft.utils.WorldguardUtils; +import net.countercraft.movecraft.utils.weVectorUtils; import org.bukkit.*; import org.bukkit.block.Block; import org.bukkit.block.BlockFace; -import org.bukkit.boss.BossBar; import org.bukkit.entity.Player; import org.bukkit.event.entity.EntityExplodeEvent; import org.bukkit.scheduler.BukkitRunnable; +import org.bukkit.util.Vector; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; import java.util.*; public class AssaultUtils { @@ -36,6 +48,7 @@ public class AssaultUtils { Material.SPRUCE_DOOR, Material.BIRCH_DOOR, Material.JUNGLE_DOOR, Material.ACACIA_DOOR, Material.DARK_OAK_DOOR, Material.OAK_DOOR, Material.IRON_DOOR, //Trapdoors Material.IRON_TRAPDOOR, Material.ACACIA_TRAPDOOR, Material.BIRCH_TRAPDOOR}; + public static boolean areDefendersOnline(ProtectedRegion tRegion) { HashSet players = new HashSet<>(); players.addAll(tRegion.getOwners().getUniqueIds()); @@ -119,7 +132,7 @@ public static void processAssault(EntityExplodeEvent e){ Block b = i.next(); if (b.getWorld() != assault.getWorld()) continue; - ApplicableRegionSet regions = worldGuard.getRegionManager(b.getWorld()).getApplicableRegions(b.getLocation()); + ApplicableRegionSet regions = WorldguardUtils.getRegionsAt(b.getLocation()); boolean isInAssaultRegion = false; for (com.sk89q.worldguard.protection.regions.ProtectedRegion tregion : regions.getRegions()) { if (assault.getRegionName().equals(tregion.getId())) { @@ -180,4 +193,6 @@ public void run() { } } + + } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/siege/SiegeProgressTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/siege/SiegeProgressTask.java index bfbf15428..865510acf 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/siege/SiegeProgressTask.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/siege/SiegeProgressTask.java @@ -1,11 +1,13 @@ package net.countercraft.movecraft.warfare.siege; import com.sk89q.worldguard.domains.DefaultDomain; +import com.sk89q.worldguard.protection.managers.RegionManager; import com.sk89q.worldguard.protection.regions.ProtectedRegion; import net.countercraft.movecraft.Movecraft; import net.countercraft.movecraft.craft.Craft; import net.countercraft.movecraft.utils.HashHitBox; import net.countercraft.movecraft.craft.CraftManager; +import net.countercraft.movecraft.utils.WorldguardUtils; import org.bukkit.Bukkit; import org.bukkit.Sound; import org.bukkit.boss.BarColor; @@ -40,7 +42,8 @@ public void run() { midX = (hitBox.getMaxX() + hitBox.getMinX()) / 2; midY = (hitBox.getMaxY() + hitBox.getMinY()) / 2; midZ = (hitBox.getMaxZ() + hitBox.getMinZ()) / 2; - siegeLeaderShipInRegion = Movecraft.getInstance().getWorldGuardPlugin().getRegionManager(siegeLeader.getWorld()).getRegion(siege.getAttackRegion()).contains(midX, midY, midZ); + RegionManager manager = WorldguardUtils.getRegionManager(siegeLeader.getWorld()); + siegeLeaderShipInRegion = manager.getRegion(siege.getAttackRegion()).contains(midX, midY, midZ); } @@ -77,7 +80,8 @@ public void run() { if (siegeLeaderShipInRegion) { Bukkit.getServer().broadcastMessage(String.format("The Siege of %s has succeeded! The forces of %s have been victorious!", siege.getName(), siegeLeader.getDisplayName())); - ProtectedRegion controlRegion = Movecraft.getInstance().getWorldGuardPlugin().getRegionManager(siegeLeader.getWorld()).getRegion(siege.getCaptureRegion()); + RegionManager manager = WorldguardUtils.getRegionManager(siegeLeader.getWorld()); + ProtectedRegion controlRegion = manager.getRegion(siege.getCaptureRegion()); DefaultDomain newOwner = new DefaultDomain(); newOwner.addPlayer(siege.getPlayerUUID()); controlRegion.setOwners(newOwner); diff --git a/modules/api/pom.xml b/modules/api/pom.xml index 249c292f0..a35241f70 100644 --- a/modules/api/pom.xml +++ b/modules/api/pom.xml @@ -30,11 +30,6 @@ - - com.sk89q - worldedit - LATEST - org.spigotmc @@ -64,6 +59,16 @@ 1.3 test + + com.sk89q + worldedit + LATEST + + + com.sk89q + worldguard + 6.1.1-SNAPSHOT + diff --git a/modules/api/src/main/java/net/countercraft/movecraft/MovecraftRepair.java b/modules/api/src/main/java/net/countercraft/movecraft/MovecraftRepair.java index 734f788e3..09c89218b 100644 --- a/modules/api/src/main/java/net/countercraft/movecraft/MovecraftRepair.java +++ b/modules/api/src/main/java/net/countercraft/movecraft/MovecraftRepair.java @@ -2,6 +2,7 @@ import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard; import com.sk89q.worldedit.extent.clipboard.Clipboard; +import com.sk89q.worldguard.protection.regions.ProtectedRegion; import net.countercraft.movecraft.craft.Craft; import org.bukkit.Material; import org.bukkit.World; @@ -17,7 +18,7 @@ public abstract class MovecraftRepair { public abstract boolean saveCraftRepairState(Craft craft, Sign sign, Plugin plugin, String repairStateName); - public abstract boolean saveRegionRepairState(Plugin plugin, World world, org.bukkit.util.Vector minPos, org.bukkit.util.Vector maxPos, String regionName); + public abstract boolean saveRegionRepairState(Plugin plugin, World world, ProtectedRegion region); public abstract boolean repairRegion(World world, String regionName); public abstract Clipboard loadCraftRepairStateClipboard(Plugin plugin, Sign sign, String repairStateName, World bukkitWorld); public abstract Clipboard loadRegionRepairStateClipboard(Plugin plugin, String repairStateName, World bukkitWorld); diff --git a/modules/api/src/main/java/net/countercraft/movecraft/RegionUtils.java b/modules/api/src/main/java/net/countercraft/movecraft/RegionUtils.java new file mode 100644 index 000000000..bf3935869 --- /dev/null +++ b/modules/api/src/main/java/net/countercraft/movecraft/RegionUtils.java @@ -0,0 +1,8 @@ +package net.countercraft.movecraft; + +import com.sk89q.worldguard.protection.regions.ProtectedRegion; +import org.bukkit.util.Vector; + +public abstract class RegionUtils { + public abstract Vector getRegionPoint(ProtectedRegion region, boolean minPoint); +} diff --git a/modules/api/src/main/java/net/countercraft/movecraft/config/Settings.java b/modules/api/src/main/java/net/countercraft/movecraft/config/Settings.java index bffc4b2d7..95f305e12 100644 --- a/modules/api/src/main/java/net/countercraft/movecraft/config/Settings.java +++ b/modules/api/src/main/java/net/countercraft/movecraft/config/Settings.java @@ -90,4 +90,5 @@ public class Settings { public static Map FuelTypes = new HashMap<>(); public static boolean SiegeEnable; + public static String SiegeTimeZone; } diff --git a/modules/api/src/main/java/net/countercraft/movecraft/craft/Craft.java b/modules/api/src/main/java/net/countercraft/movecraft/craft/Craft.java index 640cb609c..71679bf60 100644 --- a/modules/api/src/main/java/net/countercraft/movecraft/craft/Craft.java +++ b/modules/api/src/main/java/net/countercraft/movecraft/craft/Craft.java @@ -34,6 +34,7 @@ import java.util.HashMap; import java.util.Map; +import java.util.Set; import java.util.UUID; import java.util.concurrent.atomic.AtomicBoolean; @@ -322,9 +323,9 @@ public int getTickCooldown() { return type.getTickCooldown()+(int)chestPenalty; if(type.getDynamicFlyBlockSpeedFactor()!=0){ double count = 0; - Material flyBlockMaterial = type.getDynamicFlyBlock(); + Set flyBlockMaterials = type.getDynamicFlyBlocks(); for(MovecraftLocation location : hitBox){ - if(location.toBukkit(w).getBlock().getType()==flyBlockMaterial) + if(flyBlockMaterials.contains(location.toBukkit(w).getBlock().getType())) count++; } return Math.max((int) (20 / (type.getCruiseTickCooldown() * (1 + type.getDynamicFlyBlockSpeedFactor() * (count /hitBox.size() - .5)))), 1); diff --git a/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java b/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java index 017767b37..465559f52 100644 --- a/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java +++ b/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java @@ -72,7 +72,7 @@ final public class CraftType { private final int smokeOnSink; private final int tickCooldown; private final int hoverLimit; - private final Material dynamicFlyBlock; + private final Set dynamicFlyBlocks; private final double fuelBurnRate; private final double sinkPercent; private final double overallSinkPercent; @@ -97,7 +97,7 @@ final public class CraftType { @NotNull private final List harvesterBladeBlocks; @NotNull private final Set passthroughBlocks; @NotNull private final int effectRange; - @NotNull private final Set potionEffectsToApply; + @NotNull private final Map potionEffectsToApply; @NotNull private final Map potionEffectDelays = Collections.emptyMap(); public CraftType(File f) { @@ -115,7 +115,11 @@ public CraftType(File f) { maxSize = integerFromObject(data.get("maxSize")); minSize = integerFromObject(data.get("minSize")); allowedBlocks = materialMapFromObject(data.get("allowedBlocks")); - forbiddenBlocks = materialMapFromObject(data.get("forbiddenBlocks")); + if (data.containsKey("forbiddenBlocks")){ + forbiddenBlocks = materialMapFromObject(data.get("forbiddenBlocks")); + } else { + forbiddenBlocks = Collections.emptyMap(); + } forbiddenSignStrings = stringListFromObject(data.get("forbiddenSignStrings")); if (data.containsKey("canFly")) { blockedByWater = (Boolean) data.get("canFly"); @@ -406,6 +410,8 @@ public CraftType(File f) { passthroughBlocks.add(Material.WATER); if (Settings.IsLegacy){ passthroughBlocks.add(Material.STATIONARY_WATER); + } else { + passthroughBlocks.add(Material.getMaterial("BUBBLE_COLUMN")); } } @@ -425,14 +431,20 @@ public CraftType(File f) { } else { dynamicFlyBlockSpeedFactor = 0d; } - if (data.containsKey("dynamicFlyBlock")) { - dynamicFlyBlock = materialFromObject(data.get("dynamicFlyBlock")); - } else { - dynamicFlyBlock = null; + dynamicFlyBlocks = new HashSet<>(); + if (data.containsKey("dynamicFlyBlocks")) { + ArrayList entries = (ArrayList) data.get("dynamicFlyBlocks"); + for (Object o : entries){ + if (o instanceof String){ + dynamicFlyBlocks.add(Material.getMaterial((String) o)); + } else { + dynamicFlyBlocks.add(Material.getMaterial((Integer) o)); + } + } } chestPenalty = data.containsKey("chestPenalty") ? doubleFromObject(data.get("chestPenalty")) : 0d; effectRange = data.containsKey("effectRange") ? integerFromObject(data.get("effectRange")) : 0; - potionEffectsToApply = data.containsKey("potionEffectsToApply") ? effectListFromObject(data.get("potionEffectsToApply")) : Collections.emptySet(); + potionEffectsToApply = data.containsKey("potionEffectsToApply") ? effectListFromObject(data.get("potionEffectsToApply")) : Collections.emptyMap(); } private Integer integerFromObject(Object obj) { @@ -456,9 +468,9 @@ private Material materialFromObject(Object obj){ } } - private Set effectListFromObject(Object obj){ + private HashMap effectListFromObject(Object obj){ Map objMap = (Map) obj; - Set ret = new HashSet<>(); + HashMap ret = new HashMap<>(); for (Object o : objMap.keySet()){ PotionEffectType effect = null; int duration = 0; @@ -486,7 +498,7 @@ private Set effectListFromObject(Object obj){ continue; } PotionEffect potEffect = new PotionEffect(effect,duration,amplifier); - ret.add(potEffect); + ret.put(potEffect,delay); } return ret; } @@ -522,7 +534,12 @@ private Map> materialMapFromObject(Object obj){ for (Object o : (ArrayList) obj){ if (o instanceof Integer){ Integer id = (Integer) o; - Material type = Material.getMaterial(id); + Material type; + try { + type = Material.getMaterial(id); + } catch (Throwable t){ + throw new CraftTypeException("Numerical block IDs are not supported by your current Minecraft version", t); + } returnMap.put(type, new ArrayList<>()); } else if (o instanceof String){ String string = (String) o; @@ -1032,8 +1049,8 @@ public double getDynamicFlyBlockSpeedFactor() { return dynamicFlyBlockSpeedFactor; } - public Material getDynamicFlyBlock() { - return dynamicFlyBlock; + public Set getDynamicFlyBlocks() { + return dynamicFlyBlocks; } public double getChestPenalty() { @@ -1050,7 +1067,7 @@ public boolean getOnlyMovePlayers() { } @NotNull - public Set getPotionEffectsToApply() { + public Map getPotionEffectsToApply() { return potionEffectsToApply; } @@ -1068,4 +1085,10 @@ public TypeNotFoundException(String s) { super(s); } } + + private class CraftTypeException extends RuntimeException{ + public CraftTypeException(String message, Throwable cause){ + super(message,cause); + } + } } diff --git a/modules/api/src/main/java/net/countercraft/movecraft/events/CraftRotateEvent.java b/modules/api/src/main/java/net/countercraft/movecraft/events/CraftRotateEvent.java index 28310da9b..ccebade05 100644 --- a/modules/api/src/main/java/net/countercraft/movecraft/events/CraftRotateEvent.java +++ b/modules/api/src/main/java/net/countercraft/movecraft/events/CraftRotateEvent.java @@ -1,8 +1,6 @@ package net.countercraft.movecraft.events; -import net.countercraft.movecraft.Rotation; import net.countercraft.movecraft.craft.Craft; -import net.countercraft.movecraft.utils.HashHitBox; import net.countercraft.movecraft.utils.HitBox; import org.bukkit.event.Cancellable; import org.bukkit.event.HandlerList; diff --git a/modules/v1_10_R1/src/main/java/net/countercraft/movecraft/compat/v1_10_R1/IMovecraftRepair.java b/modules/v1_10_R1/src/main/java/net/countercraft/movecraft/compat/v1_10_R1/IMovecraftRepair.java deleted file mode 100644 index e18d99787..000000000 --- a/modules/v1_10_R1/src/main/java/net/countercraft/movecraft/compat/v1_10_R1/IMovecraftRepair.java +++ /dev/null @@ -1,489 +0,0 @@ -package net.countercraft.movecraft.compat.v1_10_R1; - -import com.sk89q.jnbt.CompoundTag; -import com.sk89q.jnbt.ListTag; -import com.sk89q.jnbt.Tag; -import com.sk89q.worldedit.MaxChangedBlocksException; -import com.sk89q.worldedit.Vector; -import com.sk89q.worldedit.WorldEdit; -import com.sk89q.worldedit.blocks.BaseBlock; -import com.sk89q.worldedit.bukkit.BukkitWorld; -import com.sk89q.worldedit.extent.Extent; -import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard; -import com.sk89q.worldedit.extent.clipboard.Clipboard; -import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormat; -import com.sk89q.worldedit.extent.clipboard.io.ClipboardWriter; -import com.sk89q.worldedit.function.mask.BlockMask; -import com.sk89q.worldedit.function.mask.ExistingBlockMask; -import com.sk89q.worldedit.function.operation.ForwardExtentCopy; -import com.sk89q.worldedit.function.operation.Operations; -import com.sk89q.worldedit.regions.CuboidRegion; -import com.sk89q.worldedit.world.registry.WorldData; -import net.countercraft.movecraft.MovecraftLocation; -import net.countercraft.movecraft.MovecraftRepair; -import net.countercraft.movecraft.config.Settings; -import net.countercraft.movecraft.craft.Craft; -import net.countercraft.movecraft.utils.HashHitBox; -import org.bukkit.Bukkit; -import org.bukkit.Location; -import org.bukkit.Material; -import org.bukkit.World; -import org.bukkit.block.Block; -import org.bukkit.block.Dispenser; -import org.bukkit.block.Sign; -import org.bukkit.inventory.ItemStack; -import org.bukkit.plugin.Plugin; - -import java.io.*; -import java.util.HashMap; -import java.util.HashSet; -import java.util.LinkedList; -import java.util.Set; - -public class IMovecraftRepair extends MovecraftRepair { - private HashMap> locMissingBlocksMap = new HashMap<>(); - private HashMap numDiffBlocksMap = new HashMap<>(); - private HashMap> missingBlocksMap = new HashMap<>(); - - @Override - public boolean saveCraftRepairState (Craft craft, Sign sign, Plugin plugin, String s) { - HashHitBox hitBox = craft.getHitBox(); - File saveDirectory = new File(plugin.getDataFolder(), "CraftRepairStates"); - World world = craft.getW(); - com.sk89q.worldedit.world.World weWorld = new BukkitWorld(world); - WorldData worldData = weWorld.getWorldData(); - if (!saveDirectory.exists()){ - saveDirectory.mkdirs(); - } - Vector minPos = new Vector(hitBox.getMinX(), hitBox.getMinY(), hitBox.getMinZ()); - Vector maxPos = new Vector(hitBox.getMaxX(), hitBox.getMaxY(), hitBox.getMaxZ()); - CuboidRegion cRegion = new CuboidRegion(minPos, maxPos); - File repairStateFile = new File(saveDirectory, s + ".schematic"); - Set blockSet = baseBlocksFromCraft(craft); - try { - - BlockArrayClipboard clipboard = new BlockArrayClipboard(cRegion); - Extent source = WorldEdit.getInstance().getEditSessionFactory().getEditSession(weWorld, -1); - Extent destination = clipboard; - ForwardExtentCopy copy = new ForwardExtentCopy(source, cRegion, clipboard.getOrigin(), destination, minPos); - BlockMask mask = new BlockMask(source, blockSet); - copy.setSourceMask(mask); - Operations.completeLegacy(copy); - ClipboardWriter writer = ClipboardFormat.SCHEMATIC.getWriter(new FileOutputStream(repairStateFile, false)); - writer.write(clipboard, worldData); - writer.close(); - return true; - - } catch (MaxChangedBlocksException e) { - e.printStackTrace(); - return false; - } catch (IOException e) { - e.printStackTrace(); - return false; - } - - - } - - @Override - public boolean saveRegionRepairState(Plugin plugin, World world, org.bukkit.util.Vector minPos, org.bukkit.util.Vector maxPos, String s) { - File saveDirectory = new File(plugin.getDataFolder(), "CraftRepairStates"); - com.sk89q.worldedit.world.World weWorld = new BukkitWorld(world); - WorldData worldData = weWorld.getWorldData(); - Vector weMinPos = new Vector(minPos.getBlockX(), minPos.getBlockY(), minPos.getBlockZ()); - Vector weMaxPos = new Vector(maxPos.getBlockX(), maxPos.getBlockY(), maxPos.getBlockZ()); - if (!saveDirectory.exists()){ - saveDirectory.mkdirs(); - } - - CuboidRegion cRegion = new CuboidRegion(weMinPos, weMaxPos); - File repairStateFile = new File(saveDirectory, s + ".schematic"); - try { - - BlockArrayClipboard clipboard = new BlockArrayClipboard(cRegion); - Extent source = WorldEdit.getInstance().getEditSessionFactory().getEditSession(weWorld, -1); - Extent destination = clipboard; - ForwardExtentCopy copy = new ForwardExtentCopy(source, cRegion, clipboard.getOrigin(), destination, weMinPos); - ExistingBlockMask mask = new ExistingBlockMask(source); - copy.setSourceMask(mask); - Operations.completeLegacy(copy); - ClipboardWriter writer = ClipboardFormat.SCHEMATIC.getWriter(new FileOutputStream(repairStateFile, false)); - writer.write(clipboard, worldData); - writer.close(); - return true; - - } catch (MaxChangedBlocksException e) { - e.printStackTrace(); - return false; - } catch (IOException e) { - e.printStackTrace(); - return false; - } - } - - @Override - public boolean repairRegion(World world, String s) { - return false; - } - - @Override - public Clipboard loadCraftRepairStateClipboard(Plugin plugin, Sign sign, String repairStateFile, World world) { - File dataDirectory = new File(plugin.getDataFolder(), "CraftRepairStates"); - File file = new File(dataDirectory, repairStateFile + ".schematic"); // The schematic file - com.sk89q.worldedit.world.World weWorld = new BukkitWorld(world); - WorldData worldData = weWorld.getWorldData(); - Clipboard clipboard; - try { - clipboard = ClipboardFormat.SCHEMATIC.getReader(new FileInputStream(file)).read(worldData); - - } catch (FileNotFoundException e) { - e.printStackTrace(); - return null; - } catch (IOException e) { - e.printStackTrace(); - return null; - } - if (clipboard != null){ - long numDiffBlocks = 0; - HashMap missingBlocks = new HashMap<>(); - LinkedList locMissingBlocks = new LinkedList<>(); - org.bukkit.util.Vector bukkitDistMP = getDistanceFromSignToLowestPoint(clipboard, sign.getLine(1)); - Vector distMP = new Vector(bukkitDistMP.getBlockX(),bukkitDistMP.getBlockY(),bukkitDistMP.getBlockZ()); - Vector minPos = new Vector(sign.getLocation().getBlockX() - distMP.getBlockX(), sign.getLocation().getBlockY() - distMP.getBlockY(), sign.getLocation().getBlockZ() - distMP.getBlockZ()); - Vector distance = new Vector(minPos.getBlockX() - clipboard.getMinimumPoint().getBlockX(), minPos.getBlockY() - clipboard.getMinimumPoint().getBlockY(), minPos.getBlockZ() - clipboard.getMinimumPoint().getBlockZ()); - for (int x = clipboard.getMinimumPoint().getBlockX(); x <= clipboard.getMaximumPoint().getBlockX(); x++){ - for (int y = clipboard.getMinimumPoint().getBlockY(); y <= clipboard.getMaximumPoint().getBlockY(); y++){ - for (int z = clipboard.getMinimumPoint().getBlockZ(); z <= clipboard.getMaximumPoint().getBlockZ(); z++){ - Vector position = new Vector(x,y,z); - Location bukkitLoc = new Location(sign.getWorld(), x + distance.getBlockX(), y + distance.getBlockY(), z + distance.getBlockZ()); - BaseBlock block = clipboard.getBlock(position); - Block bukkitBlock = sign.getWorld().getBlockAt(bukkitLoc); - boolean isImportant = true; - if (block.getType() == 0){ - isImportant = false; - } - - if (isImportant && bukkitBlock.getTypeId() != block.getType()) { - int itemToConsume = block.getType(); - double qtyToConsume = 1.0; - numDiffBlocks++; - //some blocks aren't represented by items with the same number as the block - if (itemToConsume == 63 || itemToConsume == 68) // signs - itemToConsume = 323; - if (itemToConsume == 93 || itemToConsume == 94) // repeaters - itemToConsume = 356; - if (itemToConsume == 149 || itemToConsume == 150) // comparators - itemToConsume = 404; - if (itemToConsume == 55) // redstone - itemToConsume = 331; - if (itemToConsume == 118) // cauldron - itemToConsume = 380; - if (itemToConsume == 124) // lit redstone lamp - itemToConsume = 123; - if (itemToConsume == 75) // lit redstone torch - itemToConsume = 76; - if (itemToConsume == 8 || itemToConsume == 9) { // don't require water to be in the chest - itemToConsume = 0; - qtyToConsume = 0.0; - } - if (itemToConsume == 10 || itemToConsume == 11) { // don't require lava either, yeah you could exploit this for free lava, so make sure you set a price per block - itemToConsume = 0; - qtyToConsume = 0.0; - } - if (itemToConsume == 26) { //beds - itemToConsume = 355; - qtyToConsume = 0.5; - } - if (itemToConsume == 64) { //doors - itemToConsume = 324; //since doors and beds encompass two blocks, require only 0.5 block for each of the two blocks - qtyToConsume = 0.5; - } - if (itemToConsume == 71){ - itemToConsume = 330; - qtyToConsume = 0.5; - } - if (itemToConsume == 193){ - itemToConsume = 427; - qtyToConsume = 0.5; - } - if (itemToConsume == 194){ - itemToConsume = 428; - qtyToConsume = 0.5; - } - if (itemToConsume == 195){ - itemToConsume = 429; - qtyToConsume = 0.5; - } - if (itemToConsume == 196){ - itemToConsume = 430; - qtyToConsume = 0.5; - } - if (itemToConsume == 197) { - itemToConsume = 431; - qtyToConsume = 0.5; - } - if (itemToConsume == 23){ - Tag t = block.getNbtData().getValue().get("Items"); - ListTag lt = null; - if (t instanceof ListTag){ - lt = (ListTag) t; - } - int numTNT = 0; - int numFireCharges = 0; - int numWaterBuckets = 0; - if (lt != null) { - for (Tag entryTag : lt.getValue()) { - if (entryTag instanceof CompoundTag){ - CompoundTag cTag = (CompoundTag) entryTag; - if (cTag.toString().contains("minecraft:tnt")){ - numTNT += cTag.getByte("Count"); - } - if (cTag.toString().contains("minecraft:fire_charge")){ - numFireCharges += cTag.getByte("Count"); - } - if (cTag.toString().contains("minecraft:water_bucket")){ - numWaterBuckets += cTag.getByte("Count"); - } - } - } - } - - - if (numTNT > 0){ - if (!missingBlocks.containsKey(Material.TNT)){ - missingBlocks.put(Material.TNT, (double) numTNT); - } else { - Double num = missingBlocks.get(Material.TNT); - num += numTNT; - missingBlocks.put(Material.TNT, num); - } - } - if (numFireCharges > 0){ - if (!missingBlocks.containsKey(Material.FIREBALL)){ - missingBlocks.put(Material.FIREBALL, (double) numFireCharges); - } else { - Double num = missingBlocks.get(Material.FIREBALL); - num += numFireCharges; - missingBlocks.put(Material.FIREBALL, num); - - } - } - if (numWaterBuckets > 0){ - if (!missingBlocks.containsKey(Material.WATER_BUCKET)){ - missingBlocks.put(Material.WATER_BUCKET, (double) numWaterBuckets); - } else { - Double num = missingBlocks.get(Material.WATER_BUCKET); - num += numWaterBuckets; - missingBlocks.put(Material.WATER_BUCKET, num); - } - } - } - if (itemToConsume == 43) { // for double slabs, require 2 slabs - itemToConsume = 44; - qtyToConsume = 2; - } - if (itemToConsume == 125) { // for double wood slabs, require 2 wood slabs - itemToConsume = 126; - qtyToConsume = 2; - } - if (itemToConsume == 181) { // for double red sandstone slabs, require 2 red sandstone slabs - itemToConsume = 182; - qtyToConsume = 2; - } - if (itemToConsume != 0){ - if (!missingBlocks.containsKey(Material.getMaterial(itemToConsume))){ - missingBlocks.put(Material.getMaterial(itemToConsume), qtyToConsume); - } else { - Double num = missingBlocks.get(Material.getMaterial(itemToConsume)); - num += qtyToConsume; - missingBlocks.put(Material.getMaterial(itemToConsume), num); - } - locMissingBlocks.push(new org.bukkit.util.Vector(x,y,z)); - } - } - if (bukkitBlock.getType() == Material.DISPENSER && block.getType() == 23){ - boolean needReplace = false; - Tag t = block.getNbtData().getValue().get("Items"); - ListTag lt = null; - if (t instanceof ListTag){ - lt = (ListTag) t; - } - int numTNT = 0; - int numFireCharges = 0; - int numWaterBuckets = 0; - if (lt != null) { - for (Tag entryTag : lt.getValue()) { - if (entryTag instanceof CompoundTag){ - CompoundTag cTag = (CompoundTag) entryTag; - if (cTag.toString().contains("minecraft:tnt")){ - numTNT += cTag.getByte("Count"); - } - if (cTag.toString().contains("minecraft:fire_charge")){ - numFireCharges += cTag.getByte("Count"); - } - if (cTag.toString().contains("minecraft:water_bucket")){ - numWaterBuckets += cTag.getByte("Count"); - } - } - } - } - Dispenser bukkitDispenser = (Dispenser) bukkitBlock.getState(); - //Bukkit.getLogger().info(String.format("TNT: %d, Fireballs: %d, Water buckets: %d", numTNT, numFireCharges, numWaterBuckets)); - for (ItemStack iStack : bukkitDispenser.getInventory().getContents()){ - if (iStack != null) { - if (iStack.getType() == Material.TNT) { - numTNT -= iStack.getAmount(); - } - if (iStack.getType() == Material.FIREBALL) { - numFireCharges -= iStack.getAmount(); - } - if (iStack.getType() == Material.WATER_BUCKET) { - numWaterBuckets -= iStack.getAmount(); - } - } - } - //Bukkit.getLogger().info(String.format("TNT: %d, Fireballs: %d, Water buckets: %d", numTNT, numFireCharges, numWaterBuckets)); - if (numTNT > 0){ - if (!missingBlocks.containsKey(Material.TNT)){ - missingBlocks.put(Material.TNT, (double) numTNT); - } else { - Double num = missingBlocks.get(Material.TNT); - num += numTNT; - missingBlocks.put(Material.TNT, num); - } - needReplace = true; - } - if (numFireCharges > 0){ - if (!missingBlocks.containsKey(Material.FIREBALL)){ - missingBlocks.put(Material.FIREBALL, (double) numFireCharges); - } else { - Double num = missingBlocks.get(Material.FIREBALL); - num += numFireCharges; - missingBlocks.put(Material.FIREBALL, num); - - } - needReplace = true; - } - if (numWaterBuckets > 0){ - if (!missingBlocks.containsKey(Material.WATER_BUCKET)){ - missingBlocks.put(Material.WATER_BUCKET, (double) numWaterBuckets); - } else { - Double num = missingBlocks.get(Material.WATER_BUCKET); - num += numWaterBuckets; - missingBlocks.put(Material.WATER_BUCKET, num); - } - needReplace = true; - } - if (needReplace){ - numDiffBlocks++; - locMissingBlocks.push(new org.bukkit.util.Vector(x,y,z)); - } - } - } - } - } - locMissingBlocksMap.put(repairStateFile, locMissingBlocks); - missingBlocksMap.put(repairStateFile, missingBlocks); - numDiffBlocksMap.put(repairStateFile, numDiffBlocks); - } - return clipboard; - } - - @Override - public Clipboard loadRegionRepairStateClipboard(Plugin plugin, String s, World world) { - return null; - } - - @Override - public HashMap getMissingBlocks(String repairName) { - if (missingBlocksMap.get(repairName) == null){ - return null; - } - return missingBlocksMap.get(repairName); - } - - @Override - public LinkedList getMissingBlockLocations(String repairName) { - return locMissingBlocksMap.get(repairName); - } - - @Override - public long getNumDiffBlocks(String s) { - return numDiffBlocksMap.get(s); - } - - @Override - public org.bukkit.util.Vector getDistanceFromSignToLowestPoint(Clipboard clipboard, String repairName) { - org.bukkit.util.Vector returnDistance = null; - for (int x = clipboard.getMinimumPoint().getBlockX(); x <= clipboard.getMaximumPoint().getBlockX(); x++) { - for (int y = clipboard.getMinimumPoint().getBlockY(); y <= clipboard.getMaximumPoint().getBlockY(); y++) { - for (int z = clipboard.getMinimumPoint().getBlockZ(); z <= clipboard.getMaximumPoint().getBlockZ(); z++) { - Vector pos = new Vector(x,y,z); - BaseBlock block = clipboard.getBlock(pos); - if (block.getType() == 68 || block.getType() == 63) { - String firstLine = block.getNbtData().getString("Text1"); - firstLine = firstLine.substring(2); - if (firstLine.substring(0, 5).equalsIgnoreCase("extra")){ - firstLine = firstLine.substring(17); - String[] parts = firstLine.split("\""); - firstLine = parts[0]; - } - String secondLine = block.getNbtData().getString("Text2"); - secondLine = secondLine.substring(2); - if (secondLine.substring(0, 5).equalsIgnoreCase("extra")){ - secondLine = secondLine.substring(17); - String[] parts = secondLine.split("\""); - secondLine = parts[0]; - } - if (firstLine.equalsIgnoreCase("Repair:")&& secondLine.contains(repairName)){ - returnDistance = new org.bukkit.util.Vector(x - clipboard.getMinimumPoint().getBlockX(), y - clipboard.getMinimumPoint().getBlockY(), z - clipboard.getMinimumPoint().getBlockZ()); - } - } - } - } - } - return returnDistance; - } - @Override - public org.bukkit.util.Vector getDistanceFromClipboardToWorldOffset(org.bukkit.util.Vector offset, Clipboard clipboard) { - return new org.bukkit.util.Vector(offset.getBlockX() - clipboard.getMinimumPoint().getBlockX(), offset.getBlockY() - clipboard.getMinimumPoint().getBlockY(), offset.getBlockZ() - clipboard.getMinimumPoint().getBlockZ()); - } - - @Override - public void setFawePlugin(Plugin fawePlugin) { - - } - - private Set baseBlocksFromCraft(Craft craft){ - HashSet returnSet = new HashSet<>(); - HashHitBox hitBox = craft.getHitBox(); - World w = craft.getW(); - for (MovecraftLocation location : hitBox){ - Integer id = w.getBlockTypeIdAt(location.getX(), location.getY(), location.getZ()); - Byte data = w.getBlockAt(location.getX(), location.getY(), location.getZ()).getData(); - returnSet.add(new BaseBlock(id, data)); - } - Bukkit.getLogger().info(returnSet.toString()); - return returnSet; - } - - private Set baseBlocksFromAssaultRegion(Vector minPos, Vector maxPos, World world){ - HashSet returnSet = new HashSet<>(); - for (int x = minPos.getBlockX(); x <= maxPos.getBlockX(); x++){ - for (int y = minPos.getBlockY(); y <= maxPos.getBlockY(); y++){ - for (int z = minPos.getBlockZ(); z <= maxPos.getBlockZ(); z++){ - int id = world.getBlockTypeIdAt(x,y,z); - byte data = world.getBlockAt(x,y,z).getData(); - //exclude air and blocks that are not destroyable during an assault - if (!Settings.AssaultDestroyableBlocks.contains(id) || id == 0){ - continue; - } - returnSet.add(new BaseBlock(id, data)); - } - } - } - - return returnSet; - } - -} diff --git a/modules/v1_11_R1/src/main/java/net/countercraft/movecraft/compat/v1_11_R1/IMovecraftRepair.java b/modules/v1_11_R1/src/main/java/net/countercraft/movecraft/compat/v1_11_R1/IMovecraftRepair.java deleted file mode 100644 index caa9da1b1..000000000 --- a/modules/v1_11_R1/src/main/java/net/countercraft/movecraft/compat/v1_11_R1/IMovecraftRepair.java +++ /dev/null @@ -1,489 +0,0 @@ -package net.countercraft.movecraft.compat.v1_11_R1; - -import com.sk89q.jnbt.CompoundTag; -import com.sk89q.jnbt.ListTag; -import com.sk89q.jnbt.Tag; -import com.sk89q.worldedit.MaxChangedBlocksException; -import com.sk89q.worldedit.Vector; -import com.sk89q.worldedit.WorldEdit; -import com.sk89q.worldedit.blocks.BaseBlock; -import com.sk89q.worldedit.bukkit.BukkitWorld; -import com.sk89q.worldedit.extent.Extent; -import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard; -import com.sk89q.worldedit.extent.clipboard.Clipboard; -import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormat; -import com.sk89q.worldedit.extent.clipboard.io.ClipboardWriter; -import com.sk89q.worldedit.function.mask.BlockMask; -import com.sk89q.worldedit.function.mask.ExistingBlockMask; -import com.sk89q.worldedit.function.operation.ForwardExtentCopy; -import com.sk89q.worldedit.function.operation.Operations; -import com.sk89q.worldedit.regions.CuboidRegion; -import com.sk89q.worldedit.world.registry.WorldData; -import net.countercraft.movecraft.MovecraftLocation; -import net.countercraft.movecraft.MovecraftRepair; -import net.countercraft.movecraft.config.Settings; -import net.countercraft.movecraft.craft.Craft; -import net.countercraft.movecraft.utils.HashHitBox; -import org.bukkit.Bukkit; -import org.bukkit.Location; -import org.bukkit.Material; -import org.bukkit.World; -import org.bukkit.block.Block; -import org.bukkit.block.Dispenser; -import org.bukkit.block.Sign; -import org.bukkit.inventory.ItemStack; -import org.bukkit.plugin.Plugin; - -import java.io.*; -import java.util.HashMap; -import java.util.HashSet; -import java.util.LinkedList; -import java.util.Set; - -public class IMovecraftRepair extends MovecraftRepair { - private HashMap> locMissingBlocksMap = new HashMap<>(); - private HashMap numDiffBlocksMap = new HashMap<>(); - private HashMap> missingBlocksMap = new HashMap<>(); - - @Override - public boolean saveCraftRepairState (Craft craft, Sign sign, Plugin plugin, String s) { - HashHitBox hitBox = craft.getHitBox(); - File saveDirectory = new File(plugin.getDataFolder(), "CraftRepairStates"); - World world = craft.getW(); - com.sk89q.worldedit.world.World weWorld = new BukkitWorld(world); - WorldData worldData = weWorld.getWorldData(); - if (!saveDirectory.exists()){ - saveDirectory.mkdirs(); - } - Vector minPos = new Vector(hitBox.getMinX(), hitBox.getMinY(), hitBox.getMinZ()); - Vector maxPos = new Vector(hitBox.getMaxX(), hitBox.getMaxY(), hitBox.getMaxZ()); - CuboidRegion cRegion = new CuboidRegion(minPos, maxPos); - File repairStateFile = new File(saveDirectory, s + ".schematic"); - Set blockSet = baseBlocksFromCraft(craft); - try { - - BlockArrayClipboard clipboard = new BlockArrayClipboard(cRegion); - Extent source = WorldEdit.getInstance().getEditSessionFactory().getEditSession(weWorld, -1); - Extent destination = clipboard; - ForwardExtentCopy copy = new ForwardExtentCopy(source, cRegion, clipboard.getOrigin(), destination, minPos); - BlockMask mask = new BlockMask(source, blockSet); - copy.setSourceMask(mask); - Operations.completeLegacy(copy); - ClipboardWriter writer = ClipboardFormat.SCHEMATIC.getWriter(new FileOutputStream(repairStateFile, false)); - writer.write(clipboard, worldData); - writer.close(); - return true; - - } catch (MaxChangedBlocksException e) { - e.printStackTrace(); - return false; - } catch (IOException e) { - e.printStackTrace(); - return false; - } - - - } - - @Override - public boolean saveRegionRepairState(Plugin plugin, World world, org.bukkit.util.Vector minPos, org.bukkit.util.Vector maxPos, String s) { - File saveDirectory = new File(plugin.getDataFolder(), "CraftRepairStates"); - com.sk89q.worldedit.world.World weWorld = new BukkitWorld(world); - WorldData worldData = weWorld.getWorldData(); - Vector weMinPos = new Vector(minPos.getBlockX(), minPos.getBlockY(), minPos.getBlockZ()); - Vector weMaxPos = new Vector(maxPos.getBlockX(), maxPos.getBlockY(), maxPos.getBlockZ()); - if (!saveDirectory.exists()) { - saveDirectory.mkdirs(); - } - - CuboidRegion cRegion = new CuboidRegion(weMinPos, weMaxPos); - File repairStateFile = new File(saveDirectory, s + ".schematic"); - try { - - BlockArrayClipboard clipboard = new BlockArrayClipboard(cRegion); - Extent source = WorldEdit.getInstance().getEditSessionFactory().getEditSession(weWorld, -1); - Extent destination = clipboard; - ForwardExtentCopy copy = new ForwardExtentCopy(source, cRegion, clipboard.getOrigin(), destination, weMinPos); - ExistingBlockMask mask = new ExistingBlockMask(source); - copy.setSourceMask(mask); - Operations.completeLegacy(copy); - ClipboardWriter writer = ClipboardFormat.SCHEMATIC.getWriter(new FileOutputStream(repairStateFile, false)); - writer.write(clipboard, worldData); - writer.close(); - return true; - - } catch (MaxChangedBlocksException e) { - e.printStackTrace(); - return false; - } catch (IOException e) { - e.printStackTrace(); - return false; - } - } - - @Override - public boolean repairRegion(World world, String s) { - return false; - } - - @Override - public Clipboard loadCraftRepairStateClipboard(Plugin plugin, Sign sign, String repairStateFile, World world) { - File dataDirectory = new File(plugin.getDataFolder(), "CraftRepairStates"); - File file = new File(dataDirectory, repairStateFile + ".schematic"); // The schematic file - com.sk89q.worldedit.world.World weWorld = new BukkitWorld(world); - WorldData worldData = weWorld.getWorldData(); - Clipboard clipboard; - try { - clipboard = ClipboardFormat.SCHEMATIC.getReader(new FileInputStream(file)).read(worldData); - - } catch (FileNotFoundException e) { - e.printStackTrace(); - return null; - } catch (IOException e) { - e.printStackTrace(); - return null; - } - if (clipboard != null){ - long numDiffBlocks = 0; - HashMap missingBlocks = new HashMap<>(); - LinkedList locMissingBlocks = new LinkedList<>(); - org.bukkit.util.Vector bukkitDistMP = getDistanceFromSignToLowestPoint(clipboard, sign.getLine(1)); - Vector distMP = new Vector(bukkitDistMP.getBlockX(),bukkitDistMP.getBlockY(),bukkitDistMP.getBlockZ()); - Vector minPos = new Vector(sign.getLocation().getBlockX() - distMP.getBlockX(), sign.getLocation().getBlockY() - distMP.getBlockY(), sign.getLocation().getBlockZ() - distMP.getBlockZ()); - Vector distance = new Vector(minPos.getBlockX() - clipboard.getMinimumPoint().getBlockX(), minPos.getBlockY() - clipboard.getMinimumPoint().getBlockY(), minPos.getBlockZ() - clipboard.getMinimumPoint().getBlockZ()); - for (int x = clipboard.getMinimumPoint().getBlockX(); x <= clipboard.getMaximumPoint().getBlockX(); x++){ - for (int y = clipboard.getMinimumPoint().getBlockY(); y <= clipboard.getMaximumPoint().getBlockY(); y++){ - for (int z = clipboard.getMinimumPoint().getBlockZ(); z <= clipboard.getMaximumPoint().getBlockZ(); z++){ - Vector position = new Vector(x,y,z); - Location bukkitLoc = new Location(sign.getWorld(), x + distance.getBlockX(), y + distance.getBlockY(), z + distance.getBlockZ()); - BaseBlock block = clipboard.getBlock(position); - Block bukkitBlock = sign.getWorld().getBlockAt(bukkitLoc); - boolean isImportant = true; - if (block.getType() == 0){ - isImportant = false; - } - - if (isImportant && bukkitBlock.getTypeId() != block.getType()) { - int itemToConsume = block.getType(); - double qtyToConsume = 1.0; - numDiffBlocks++; - //some blocks aren't represented by items with the same number as the block - if (itemToConsume == 63 || itemToConsume == 68) // signs - itemToConsume = 323; - if (itemToConsume == 93 || itemToConsume == 94) // repeaters - itemToConsume = 356; - if (itemToConsume == 149 || itemToConsume == 150) // comparators - itemToConsume = 404; - if (itemToConsume == 55) // redstone - itemToConsume = 331; - if (itemToConsume == 118) // cauldron - itemToConsume = 380; - if (itemToConsume == 124) // lit redstone lamp - itemToConsume = 123; - if (itemToConsume == 75) // lit redstone torch - itemToConsume = 76; - if (itemToConsume == 8 || itemToConsume == 9) { // don't require water to be in the chest - itemToConsume = 0; - qtyToConsume = 0.0; - } - if (itemToConsume == 10 || itemToConsume == 11) { // don't require lava either, yeah you could exploit this for free lava, so make sure you set a price per block - itemToConsume = 0; - qtyToConsume = 0.0; - } - if (itemToConsume == 26) { //beds - itemToConsume = 355; - qtyToConsume = 0.5; - } - if (itemToConsume == 64) { //doors - itemToConsume = 324; //since doors and beds encompass two blocks, require only 0.5 block for each of the two blocks - qtyToConsume = 0.5; - } - if (itemToConsume == 71){ - itemToConsume = 330; - qtyToConsume = 0.5; - } - if (itemToConsume == 193){ - itemToConsume = 427; - qtyToConsume = 0.5; - } - if (itemToConsume == 194){ - itemToConsume = 428; - qtyToConsume = 0.5; - } - if (itemToConsume == 195){ - itemToConsume = 429; - qtyToConsume = 0.5; - } - if (itemToConsume == 196){ - itemToConsume = 430; - qtyToConsume = 0.5; - } - if (itemToConsume == 197) { - itemToConsume = 431; - qtyToConsume = 0.5; - } - if (itemToConsume == 23){ - Tag t = block.getNbtData().getValue().get("Items"); - ListTag lt = null; - if (t instanceof ListTag){ - lt = (ListTag) t; - } - int numTNT = 0; - int numFireCharges = 0; - int numWaterBuckets = 0; - if (lt != null) { - for (Tag entryTag : lt.getValue()) { - if (entryTag instanceof CompoundTag){ - CompoundTag cTag = (CompoundTag) entryTag; - if (cTag.toString().contains("minecraft:tnt")){ - numTNT += cTag.getByte("Count"); - } - if (cTag.toString().contains("minecraft:fire_charge")){ - numFireCharges += cTag.getByte("Count"); - } - if (cTag.toString().contains("minecraft:water_bucket")){ - numWaterBuckets += cTag.getByte("Count"); - } - } - } - } - - - if (numTNT > 0){ - if (!missingBlocks.containsKey(Material.TNT)){ - missingBlocks.put(Material.TNT, (double) numTNT); - } else { - Double num = missingBlocks.get(Material.TNT); - num += numTNT; - missingBlocks.put(Material.TNT, num); - } - } - if (numFireCharges > 0){ - if (!missingBlocks.containsKey(Material.FIREBALL)){ - missingBlocks.put(Material.FIREBALL, (double) numFireCharges); - } else { - Double num = missingBlocks.get(Material.FIREBALL); - num += numFireCharges; - missingBlocks.put(Material.FIREBALL, num); - - } - } - if (numWaterBuckets > 0){ - if (!missingBlocks.containsKey(Material.WATER_BUCKET)){ - missingBlocks.put(Material.WATER_BUCKET, (double) numWaterBuckets); - } else { - Double num = missingBlocks.get(Material.WATER_BUCKET); - num += numWaterBuckets; - missingBlocks.put(Material.WATER_BUCKET, num); - } - } - } - if (itemToConsume == 43) { // for double slabs, require 2 slabs - itemToConsume = 44; - qtyToConsume = 2; - } - if (itemToConsume == 125) { // for double wood slabs, require 2 wood slabs - itemToConsume = 126; - qtyToConsume = 2; - } - if (itemToConsume == 181) { // for double red sandstone slabs, require 2 red sandstone slabs - itemToConsume = 182; - qtyToConsume = 2; - } - if (itemToConsume != 0){ - if (!missingBlocks.containsKey(Material.getMaterial(itemToConsume))){ - missingBlocks.put(Material.getMaterial(itemToConsume), qtyToConsume); - } else { - Double num = missingBlocks.get(Material.getMaterial(itemToConsume)); - num += qtyToConsume; - missingBlocks.put(Material.getMaterial(itemToConsume), num); - } - locMissingBlocks.push(new org.bukkit.util.Vector(x,y,z)); - } - } - if (bukkitBlock.getType() == Material.DISPENSER && block.getType() == 23){ - boolean needReplace = false; - Tag t = block.getNbtData().getValue().get("Items"); - ListTag lt = null; - if (t instanceof ListTag){ - lt = (ListTag) t; - } - int numTNT = 0; - int numFireCharges = 0; - int numWaterBuckets = 0; - if (lt != null) { - for (Tag entryTag : lt.getValue()) { - if (entryTag instanceof CompoundTag){ - CompoundTag cTag = (CompoundTag) entryTag; - if (cTag.toString().contains("minecraft:tnt")){ - numTNT += cTag.getByte("Count"); - } - if (cTag.toString().contains("minecraft:fire_charge")){ - numFireCharges += cTag.getByte("Count"); - } - if (cTag.toString().contains("minecraft:water_bucket")){ - numWaterBuckets += cTag.getByte("Count"); - } - } - } - } - Dispenser bukkitDispenser = (Dispenser) bukkitBlock.getState(); - //Bukkit.getLogger().info(String.format("TNT: %d, Fireballs: %d, Water buckets: %d", numTNT, numFireCharges, numWaterBuckets)); - for (ItemStack iStack : bukkitDispenser.getInventory().getContents()){ - if (iStack != null) { - if (iStack.getType() == Material.TNT) { - numTNT -= iStack.getAmount(); - } - if (iStack.getType() == Material.FIREBALL) { - numFireCharges -= iStack.getAmount(); - } - if (iStack.getType() == Material.WATER_BUCKET) { - numWaterBuckets -= iStack.getAmount(); - } - } - } - //Bukkit.getLogger().info(String.format("TNT: %d, Fireballs: %d, Water buckets: %d", numTNT, numFireCharges, numWaterBuckets)); - if (numTNT > 0){ - if (!missingBlocks.containsKey(Material.TNT)){ - missingBlocks.put(Material.TNT, (double) numTNT); - } else { - Double num = missingBlocks.get(Material.TNT); - num += numTNT; - missingBlocks.put(Material.TNT, num); - } - needReplace = true; - } - if (numFireCharges > 0){ - if (!missingBlocks.containsKey(Material.FIREBALL)){ - missingBlocks.put(Material.FIREBALL, (double) numFireCharges); - } else { - Double num = missingBlocks.get(Material.FIREBALL); - num += numFireCharges; - missingBlocks.put(Material.FIREBALL, num); - - } - needReplace = true; - } - if (numWaterBuckets > 0){ - if (!missingBlocks.containsKey(Material.WATER_BUCKET)){ - missingBlocks.put(Material.WATER_BUCKET, (double) numWaterBuckets); - } else { - Double num = missingBlocks.get(Material.WATER_BUCKET); - num += numWaterBuckets; - missingBlocks.put(Material.WATER_BUCKET, num); - } - needReplace = true; - } - if (needReplace){ - numDiffBlocks++; - locMissingBlocks.push(new org.bukkit.util.Vector(x,y,z)); - } - } - } - } - } - locMissingBlocksMap.put(repairStateFile, locMissingBlocks); - missingBlocksMap.put(repairStateFile, missingBlocks); - numDiffBlocksMap.put(repairStateFile, numDiffBlocks); - } - return clipboard; - } - - @Override - public Clipboard loadRegionRepairStateClipboard(Plugin plugin, String s, World world) { - return null; - } - - @Override - public HashMap getMissingBlocks(String repairName) { - if (missingBlocksMap.get(repairName) == null){ - return null; - } - return missingBlocksMap.get(repairName); - } - - @Override - public LinkedList getMissingBlockLocations(String repairName) { - return locMissingBlocksMap.get(repairName); - } - - @Override - public long getNumDiffBlocks(String s) { - return numDiffBlocksMap.get(s); - } - - @Override - public org.bukkit.util.Vector getDistanceFromSignToLowestPoint(Clipboard clipboard, String repairName) { - org.bukkit.util.Vector returnDistance = null; - for (int x = clipboard.getMinimumPoint().getBlockX(); x <= clipboard.getMaximumPoint().getBlockX(); x++) { - for (int y = clipboard.getMinimumPoint().getBlockY(); y <= clipboard.getMaximumPoint().getBlockY(); y++) { - for (int z = clipboard.getMinimumPoint().getBlockZ(); z <= clipboard.getMaximumPoint().getBlockZ(); z++) { - Vector pos = new Vector(x,y,z); - BaseBlock block = clipboard.getBlock(pos); - if (block.getType() == 68 || block.getType() == 63) { - String firstLine = block.getNbtData().getString("Text1"); - firstLine = firstLine.substring(2); - if (firstLine.substring(0, 5).equalsIgnoreCase("extra")){ - firstLine = firstLine.substring(17); - String[] parts = firstLine.split("\""); - firstLine = parts[0]; - } - String secondLine = block.getNbtData().getString("Text2"); - secondLine = secondLine.substring(2); - if (secondLine.substring(0, 5).equalsIgnoreCase("extra")){ - secondLine = secondLine.substring(17); - String[] parts = secondLine.split("\""); - secondLine = parts[0]; - } - if (firstLine.equalsIgnoreCase("Repair:")&& secondLine.contains(repairName)){ - returnDistance = new org.bukkit.util.Vector(x - clipboard.getMinimumPoint().getBlockX(), y - clipboard.getMinimumPoint().getBlockY(), z - clipboard.getMinimumPoint().getBlockZ()); - } - } - } - } - } - return returnDistance; - } - - @Override - public org.bukkit.util.Vector getDistanceFromClipboardToWorldOffset(org.bukkit.util.Vector offset, Clipboard clipboard) { - return new org.bukkit.util.Vector(offset.getBlockX() - clipboard.getMinimumPoint().getBlockX(), offset.getBlockY() - clipboard.getMinimumPoint().getBlockY(), offset.getBlockZ() - clipboard.getMinimumPoint().getBlockZ()); - } - - @Override - public void setFawePlugin(Plugin fawePlugin) { - - } - - private Set baseBlocksFromCraft(Craft craft){ - HashSet returnSet = new HashSet<>(); - HashHitBox hitBox = craft.getHitBox(); - World w = craft.getW(); - for (MovecraftLocation location : hitBox){ - Integer id = w.getBlockTypeIdAt(location.getX(), location.getY(), location.getZ()); - Byte data = w.getBlockAt(location.getX(), location.getY(), location.getZ()).getData(); - returnSet.add(new BaseBlock(id, data)); - } - Bukkit.getLogger().info(returnSet.toString()); - return returnSet; - } - - private Set baseBlocksFromAssaultRegion(Vector minPos, Vector maxPos, World world){ - HashSet returnSet = new HashSet<>(); - for (int x = minPos.getBlockX(); x <= maxPos.getBlockX(); x++){ - for (int y = minPos.getBlockY(); y <= maxPos.getBlockY(); y++){ - for (int z = minPos.getBlockZ(); z <= maxPos.getBlockZ(); z++){ - int id = world.getBlockTypeIdAt(x,y,z); - byte data = world.getBlockAt(x,y,z).getData(); - //exclude air and blocks that are not destroyable during an assault - if (!Settings.AssaultDestroyableBlocks.contains(id) || id == 0){ - continue; - } - returnSet.add(new BaseBlock(id, data)); - } - } - } - - return returnSet; - } -} diff --git a/modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/IWorldHandler.java b/modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/IWorldHandler.java index 1c28a6ab5..5a6f9bd40 100644 --- a/modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/IWorldHandler.java +++ b/modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/IWorldHandler.java @@ -12,9 +12,7 @@ import org.bukkit.Material; import org.bukkit.craftbukkit.v1_13_R2.CraftWorld; import org.bukkit.craftbukkit.v1_13_R2.block.CraftBlockState; -import org.bukkit.craftbukkit.v1_13_R2.entity.CraftPlayer; import org.bukkit.craftbukkit.v1_13_R2.util.CraftMagicNumbers; -import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; diff --git a/modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/NextTickProvider.java b/modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/NextTickProvider.java index 06b2080ec..f23508bce 100644 --- a/modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/NextTickProvider.java +++ b/modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/NextTickProvider.java @@ -15,7 +15,7 @@ import java.util.Map; public class NextTickProvider { - private Map,List>>> tickMap = new HashMap<>(); + private Map,List>> tickMap = new HashMap<>(); private boolean isRegistered(@NotNull WorldServer world){ return tickMap.containsKey(world); @@ -23,15 +23,16 @@ private boolean isRegistered(@NotNull WorldServer world){ @SuppressWarnings("unchecked") private void registerWorld(@NotNull WorldServer world){ - List> W = new ArrayList<>(); + List W = new ArrayList<>(); HashTreeSet nextTickList = new HashTreeSet<>(); - Chunk chunk = world.getChunkProvider().a().iterator().next(); - + TickListServer blockTickListServer = world.getBlockTickList(); try { - W = world.getBlockTickList().a(chunk, false); + Field gField = TickListServer.class.getDeclaredField("g"); + gField.setAccessible(true); + W = (List) gField.get(blockTickListServer); Field ntlField = TickListServer.class.getDeclaredField("nextTickList"); ntlField.setAccessible(true); - ntlField.get(world.getBlockTickList()); + nextTickList = (HashTreeSet) ntlField.get(blockTickListServer); } catch (IllegalAccessException | IllegalArgumentException | NoSuchFieldException | SecurityException e1) { e1.printStackTrace(); } @@ -42,7 +43,7 @@ private void registerWorld(@NotNull WorldServer world){ public NextTickListEntry getNextTick(@NotNull WorldServer world,@NotNull BlockPosition position){ if(!isRegistered(world)) registerWorld(world); - ImmutablePair, List>> listPair = tickMap.get(world); + ImmutablePair, List> listPair = tickMap.get(world); for(Iterator iterator = listPair.left.iterator(); iterator.hasNext();) { NextTickListEntry listEntry = iterator.next(); if (position.equals(listEntry.a)) { @@ -50,7 +51,7 @@ public NextTickListEntry getNextTick(@NotNull WorldServer world,@NotNull BlockPo return listEntry; } } - for(Iterator> iterator = listPair.right.iterator(); iterator.hasNext();) { + for(Iterator iterator = listPair.right.iterator(); iterator.hasNext();) { NextTickListEntry listEntry = iterator.next(); if (position.equals(listEntry.a)) { iterator.remove(); diff --git a/modules/FAWEUtils/pom.xml b/modules/worldedit/FAWEUtils/pom.xml similarity index 91% rename from modules/FAWEUtils/pom.xml rename to modules/worldedit/FAWEUtils/pom.xml index f1c61cba8..426d11821 100644 --- a/modules/FAWEUtils/pom.xml +++ b/modules/worldedit/FAWEUtils/pom.xml @@ -6,7 +6,7 @@ movecraft-parent net.countercraft parent - ../../pom.xml + ../../../pom.xml 4.0.0 movecraft-FAWEUtils @@ -49,7 +49,7 @@ 3.7.0 - net/countercraft/movecraft/utils/** + net/countercraft/movecraft/compat/fawe/** 1.8 1.8 @@ -61,7 +61,7 @@ 2.4 - net/countercraft/movecraft/utils/** + net/countercraft/movecraft/compat/fawe/** diff --git a/modules/FAWEUtils/src/main/java/net/countercraft/movecraft/utils/FAWEUtils.java b/modules/worldedit/FAWEUtils/src/main/java/net/countercraft/movecraft/compat/fawe/IMovecraftRepair.java similarity index 58% rename from modules/FAWEUtils/src/main/java/net/countercraft/movecraft/utils/FAWEUtils.java rename to modules/worldedit/FAWEUtils/src/main/java/net/countercraft/movecraft/compat/fawe/IMovecraftRepair.java index 8c2a774ec..58a641664 100644 --- a/modules/FAWEUtils/src/main/java/net/countercraft/movecraft/utils/FAWEUtils.java +++ b/modules/worldedit/FAWEUtils/src/main/java/net/countercraft/movecraft/compat/fawe/IMovecraftRepair.java @@ -1,4 +1,4 @@ -package net.countercraft.movecraft.utils; +package net.countercraft.movecraft.compat.fawe; import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.WorldEdit; @@ -6,6 +6,7 @@ import com.sk89q.worldedit.bukkit.BukkitWorld; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard; +import com.sk89q.worldedit.extent.clipboard.Clipboard; import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormat; import com.sk89q.worldedit.extent.clipboard.io.ClipboardWriter; import com.sk89q.worldedit.function.mask.ExistingBlockMask; @@ -13,7 +14,11 @@ import com.sk89q.worldedit.function.operation.Operations; import com.sk89q.worldedit.regions.CuboidRegion; import com.sk89q.worldedit.world.registry.WorldData; +import com.sk89q.worldguard.protection.regions.ProtectedRegion; +import net.countercraft.movecraft.MovecraftRepair; import net.countercraft.movecraft.craft.Craft; +import net.countercraft.movecraft.utils.HashHitBox; +import org.bukkit.Material; import org.bukkit.World; import org.bukkit.block.Sign; import org.bukkit.plugin.Plugin; @@ -22,9 +27,13 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.OutputStream; +import java.util.HashMap; +import java.util.LinkedList; -public class FAWEUtils { - public static boolean faweSaveCraftRepairState(Craft craft, Sign sign, Plugin plugin, String s) { +public class IMovecraftRepair extends MovecraftRepair { + + @Override + public boolean saveCraftRepairState(Craft craft, Sign sign, Plugin plugin, String s) { HashHitBox hitBox = craft.getHitBox(); File saveDirectory = new File(plugin.getDataFolder(), "CraftRepairStates"); World world = craft.getW(); @@ -61,4 +70,54 @@ public static boolean faweSaveCraftRepairState(Craft craft, Sign sign, Plugin pl return true; } + + @Override + public boolean saveRegionRepairState(Plugin plugin, World world, ProtectedRegion region) { + return false; + } + + @Override + public boolean repairRegion(World world, String regionName) { + return false; + } + + @Override + public Clipboard loadCraftRepairStateClipboard(Plugin plugin, Sign sign, String repairStateName, World bukkitWorld) { + return null; + } + + @Override + public Clipboard loadRegionRepairStateClipboard(Plugin plugin, String repairStateName, World bukkitWorld) { + return null; + } + + @Override + public HashMap getMissingBlocks(String repairName) { + return null; + } + + @Override + public LinkedList getMissingBlockLocations(String repairName) { + return null; + } + + @Override + public long getNumDiffBlocks(String repairName) { + return 0; + } + + @Override + public org.bukkit.util.Vector getDistanceFromSignToLowestPoint(Clipboard clipboard, String repairName) { + return null; + } + + @Override + public org.bukkit.util.Vector getDistanceFromClipboardToWorldOffset(org.bukkit.util.Vector offset, Clipboard clipboard) { + return null; + } + + @Override + public void setFawePlugin(Plugin fawePlugin) { + + } } diff --git a/modules/worldedit/WE6Utils/pom.xml b/modules/worldedit/WE6Utils/pom.xml new file mode 100644 index 000000000..df78ceb57 --- /dev/null +++ b/modules/worldedit/WE6Utils/pom.xml @@ -0,0 +1,74 @@ + + + + movecraft-parent + net.countercraft + parent + ../../../pom.xml + + 4.0.0 + + movecraft-WE6Utils + jar + Movecraft-WE6Utils + WE6Utils + + + sk89q-repo + http://maven.sk89q.com/repo/ + + + + + com.sk89q + worldedit + LATEST + + + net.countercraft + movecraft-api + API + jar + + + org.jetbrains + annotations-java5 + RELEASE + + + com.sk89q + worldguard + 6.1.1-SNAPSHOT + + + + src/main/java + + + org.apache.maven.plugins + maven-compiler-plugin + 3.7.0 + + + net/countercraft/movecraft/compat/we6/** + + 1.8 + 1.8 + + + + org.apache.maven.plugins + maven-jar-plugin + 2.4 + + + net/countercraft/movecraft/compat/we6/** + + + + + + + \ No newline at end of file diff --git a/modules/v1_12_R1/src/main/java/net/countercraft/movecraft/compat/v1_12_R1/IMovecraftRepair.java b/modules/worldedit/WE6Utils/src/main/java/net/countercraft/movecraft/compat/we6/IMovecraftRepair.java similarity index 89% rename from modules/v1_12_R1/src/main/java/net/countercraft/movecraft/compat/v1_12_R1/IMovecraftRepair.java rename to modules/worldedit/WE6Utils/src/main/java/net/countercraft/movecraft/compat/we6/IMovecraftRepair.java index 5c58acd86..a3662f9e8 100644 --- a/modules/v1_12_R1/src/main/java/net/countercraft/movecraft/compat/v1_12_R1/IMovecraftRepair.java +++ b/modules/worldedit/WE6Utils/src/main/java/net/countercraft/movecraft/compat/we6/IMovecraftRepair.java @@ -1,11 +1,11 @@ -package net.countercraft.movecraft.compat.v1_12_R1; +package net.countercraft.movecraft.compat.we6; -import com.sk89q.jnbt.*; +import com.sk89q.jnbt.CompoundTag; +import com.sk89q.jnbt.ListTag; +import com.sk89q.jnbt.Tag; import com.sk89q.worldedit.MaxChangedBlocksException; -import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.WorldEdit; -import com.sk89q.worldedit.WorldEditException; -import com.sk89q.worldedit.blocks.*; +import com.sk89q.worldedit.blocks.BaseBlock; import com.sk89q.worldedit.bukkit.BukkitWorld; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard; @@ -13,12 +13,15 @@ import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormat; import com.sk89q.worldedit.extent.clipboard.io.ClipboardWriter; import com.sk89q.worldedit.function.mask.BlockMask; -import com.sk89q.worldedit.function.mask.ExistingBlockMask; import com.sk89q.worldedit.function.operation.ForwardExtentCopy; import com.sk89q.worldedit.function.operation.Operations; -import com.sk89q.worldedit.masks.BlockTypeMask; import com.sk89q.worldedit.regions.CuboidRegion; +import com.sk89q.worldedit.regions.Polygonal2DRegion; +import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.world.registry.WorldData; +import com.sk89q.worldguard.protection.regions.ProtectedCuboidRegion; +import com.sk89q.worldguard.protection.regions.ProtectedPolygonalRegion; +import com.sk89q.worldguard.protection.regions.ProtectedRegion; import net.countercraft.movecraft.MovecraftLocation; import net.countercraft.movecraft.MovecraftRepair; import net.countercraft.movecraft.config.Settings; @@ -28,15 +31,21 @@ import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.World; -import org.bukkit.block.*; +import org.bukkit.block.Block; +import org.bukkit.block.Dispenser; +import org.bukkit.block.Sign; import org.bukkit.inventory.ItemStack; import org.bukkit.plugin.Plugin; +import org.bukkit.util.Vector; import java.io.*; -import java.util.*; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.Set; public class IMovecraftRepair extends MovecraftRepair { - private HashMap> locMissingBlocksMap = new HashMap<>(); + private HashMap> locMissingBlocksMap = new HashMap<>(); private HashMap numDiffBlocksMap = new HashMap<>(); private HashMap> missingBlocksMap = new HashMap<>(); @@ -50,8 +59,8 @@ public boolean saveCraftRepairState (Craft craft, Sign sign, Plugin plugin, Stri if (!saveDirectory.exists()){ saveDirectory.mkdirs(); } - Vector minPos = new Vector(hitBox.getMinX(), hitBox.getMinY(), hitBox.getMinZ()); - Vector maxPos = new Vector(hitBox.getMaxX(), hitBox.getMaxY(), hitBox.getMaxZ()); + com.sk89q.worldedit.Vector minPos = new com.sk89q.worldedit.Vector(hitBox.getMinX(), hitBox.getMinY(), hitBox.getMinZ()); + com.sk89q.worldedit.Vector maxPos = new com.sk89q.worldedit.Vector(hitBox.getMaxX(), hitBox.getMaxY(), hitBox.getMaxZ()); CuboidRegion cRegion = new CuboidRegion(minPos, maxPos); File repairStateFile = new File(saveDirectory, s + ".schematic"); Set blockSet = baseBlocksFromCraft(craft); @@ -69,10 +78,7 @@ public boolean saveCraftRepairState (Craft craft, Sign sign, Plugin plugin, Stri writer.close(); return true; - } catch (MaxChangedBlocksException e) { - e.printStackTrace(); - return false; - } catch (IOException e) { + } catch (MaxChangedBlocksException | IOException e) { e.printStackTrace(); return false; } @@ -81,18 +87,28 @@ public boolean saveCraftRepairState (Craft craft, Sign sign, Plugin plugin, Stri } @Override - public boolean saveRegionRepairState(Plugin plugin, World world, org.bukkit.util.Vector minPos, org.bukkit.util.Vector maxPos, String s) { + public boolean saveRegionRepairState(Plugin plugin, World world, ProtectedRegion region) { + File saveDirectory = new File(plugin.getDataFolder(), "RegionRepairStates"); com.sk89q.worldedit.world.World weWorld = new BukkitWorld(world); WorldData worldData = weWorld.getWorldData(); - Vector weMinPos = new Vector(minPos.getBlockX(), minPos.getBlockY(), minPos.getBlockZ()); - Vector weMaxPos = new Vector(maxPos.getBlockX(), maxPos.getBlockY(), maxPos.getBlockZ()); + com.sk89q.worldedit.Vector weMinPos = region.getMinimumPoint(); + com.sk89q.worldedit.Vector weMaxPos = region.getMaximumPoint(); if (!saveDirectory.exists()){ saveDirectory.mkdirs(); } Set baseBlockSet = new HashSet<>(); - CuboidRegion cRegion = new CuboidRegion(weMinPos, weMaxPos); - File repairStateFile = new File(saveDirectory, s + ".schematic"); + Region weRegion = null; + if (region instanceof ProtectedCuboidRegion){ + weRegion = new CuboidRegion(weMinPos, weMaxPos); + } else if (region instanceof ProtectedPolygonalRegion){ + ProtectedPolygonalRegion polyReg = (ProtectedPolygonalRegion) region; + weRegion = new Polygonal2DRegion(weWorld,polyReg.getPoints(),polyReg.getMinimumPoint().getBlockY(),polyReg.getMaximumPoint().getBlockY()); + } + + + + File repairStateFile = new File(saveDirectory, region.getId().replaceAll("´\\s+", "_") + ".schematic"); for (int x = weMinPos.getBlockX(); x <= weMaxPos.getBlockX(); x++){ for (int y = weMinPos.getBlockY(); y <= weMaxPos.getBlockY(); y++){ for (int z = weMinPos.getBlockZ(); z <= weMaxPos.getBlockZ(); z++){ @@ -108,10 +124,10 @@ public boolean saveRegionRepairState(Plugin plugin, World world, org.bukkit.util } try { - BlockArrayClipboard clipboard = new BlockArrayClipboard(cRegion); + BlockArrayClipboard clipboard = new BlockArrayClipboard(weRegion); Extent source = WorldEdit.getInstance().getEditSessionFactory().getEditSession(weWorld, -1); Extent destination = clipboard; - ForwardExtentCopy copy = new ForwardExtentCopy(source, cRegion, clipboard.getOrigin(), destination, weMinPos); + ForwardExtentCopy copy = new ForwardExtentCopy(source, weRegion, clipboard.getOrigin(), destination, weMinPos); BlockMask mask = new BlockMask(source, baseBlockSet); copy.setSourceMask(mask); Operations.completeLegacy(copy); @@ -120,10 +136,7 @@ public boolean saveRegionRepairState(Plugin plugin, World world, org.bukkit.util writer.close(); return true; - } catch (MaxChangedBlocksException e) { - e.printStackTrace(); - return false; - } catch (IOException e) { + } catch (MaxChangedBlocksException | IOException e) { e.printStackTrace(); return false; } @@ -135,7 +148,7 @@ public boolean repairRegion(World world, String s) { } @Override - public Clipboard loadCraftRepairStateClipboard(Plugin plugin,Sign sign, String repairStateFile, World world) { + public Clipboard loadCraftRepairStateClipboard(Plugin plugin, Sign sign, String repairStateFile, World world) { File dataDirectory = new File(plugin.getDataFolder(), "CraftRepairStates"); File file = new File(dataDirectory, repairStateFile + ".schematic"); // The schematic file com.sk89q.worldedit.world.World weWorld = new BukkitWorld(world); @@ -144,9 +157,6 @@ public Clipboard loadCraftRepairStateClipboard(Plugin plugin,Sign sign, String r try { clipboard = ClipboardFormat.SCHEMATIC.getReader(new FileInputStream(file)).read(worldData); - } catch (FileNotFoundException e) { - e.printStackTrace(); - return null; } catch (IOException e) { e.printStackTrace(); return null; @@ -156,13 +166,13 @@ public Clipboard loadCraftRepairStateClipboard(Plugin plugin,Sign sign, String r HashMap missingBlocks = new HashMap<>(); LinkedList locMissingBlocks = new LinkedList<>(); org.bukkit.util.Vector bukkitDistMP = getDistanceFromSignToLowestPoint(clipboard, sign.getLine(1)); - Vector distMP = new Vector(bukkitDistMP.getBlockX(),bukkitDistMP.getBlockY(),bukkitDistMP.getBlockZ()); - Vector minPos = new Vector(sign.getLocation().getBlockX() - distMP.getBlockX(), sign.getLocation().getBlockY() - distMP.getBlockY(), sign.getLocation().getBlockZ() - distMP.getBlockZ()); - Vector distance = new Vector(minPos.getBlockX() - clipboard.getMinimumPoint().getBlockX(), minPos.getBlockY() - clipboard.getMinimumPoint().getBlockY(), minPos.getBlockZ() - clipboard.getMinimumPoint().getBlockZ()); + com.sk89q.worldedit.Vector distMP = new com.sk89q.worldedit.Vector(bukkitDistMP.getBlockX(),bukkitDistMP.getBlockY(),bukkitDistMP.getBlockZ()); + com.sk89q.worldedit.Vector minPos = new com.sk89q.worldedit.Vector(sign.getLocation().getBlockX() - distMP.getBlockX(), sign.getLocation().getBlockY() - distMP.getBlockY(), sign.getLocation().getBlockZ() - distMP.getBlockZ()); + com.sk89q.worldedit.Vector distance = new com.sk89q.worldedit.Vector(minPos.getBlockX() - clipboard.getMinimumPoint().getBlockX(), minPos.getBlockY() - clipboard.getMinimumPoint().getBlockY(), minPos.getBlockZ() - clipboard.getMinimumPoint().getBlockZ()); for (int x = clipboard.getMinimumPoint().getBlockX(); x <= clipboard.getMaximumPoint().getBlockX(); x++){ for (int y = clipboard.getMinimumPoint().getBlockY(); y <= clipboard.getMaximumPoint().getBlockY(); y++){ for (int z = clipboard.getMinimumPoint().getBlockZ(); z <= clipboard.getMaximumPoint().getBlockZ(); z++){ - Vector position = new Vector(x,y,z); + com.sk89q.worldedit.Vector position = new com.sk89q.worldedit.Vector(x,y,z); Location bukkitLoc = new Location(sign.getWorld(), x + distance.getBlockX(), y + distance.getBlockY(), z + distance.getBlockZ()); BaseBlock block = clipboard.getBlock(position); Block bukkitBlock = sign.getWorld().getBlockAt(bukkitLoc); @@ -436,7 +446,7 @@ public org.bukkit.util.Vector getDistanceFromSignToLowestPoint(Clipboard clipboa for (int x = clipboard.getMinimumPoint().getBlockX(); x <= clipboard.getMaximumPoint().getBlockX(); x++) { for (int y = clipboard.getMinimumPoint().getBlockY(); y <= clipboard.getMaximumPoint().getBlockY(); y++) { for (int z = clipboard.getMinimumPoint().getBlockZ(); z <= clipboard.getMaximumPoint().getBlockZ(); z++) { - Vector pos = new Vector(x,y,z); + com.sk89q.worldedit.Vector pos = new com.sk89q.worldedit.Vector(x,y,z); BaseBlock block = clipboard.getBlock(pos); if (block.getType() == 68 || block.getType() == 63) { String firstLine = block.getNbtData().getString("Text1"); @@ -486,7 +496,7 @@ private Set baseBlocksFromCraft(Craft craft){ return returnSet; } - private Set baseBlocksFromAssaultRegion(Vector minPos, Vector maxPos, World world){ + private Set baseBlocksFromAssaultRegion(com.sk89q.worldedit.Vector minPos, com.sk89q.worldedit.Vector maxPos, World world){ HashSet returnSet = new HashSet<>(); for (int x = minPos.getBlockX(); x <= maxPos.getBlockX(); x++){ for (int y = minPos.getBlockY(); y <= maxPos.getBlockY(); y++){ diff --git a/modules/worldedit/WE7Utils/pom.xml b/modules/worldedit/WE7Utils/pom.xml new file mode 100644 index 000000000..869f5e392 --- /dev/null +++ b/modules/worldedit/WE7Utils/pom.xml @@ -0,0 +1,88 @@ + + + + movecraft-parent + net.countercraft + parent + ../../../pom.xml + + 4.0.0 + + movecraft-WE7Utils + jar + Movecraft-WE7Utils + WE7Utils + + + + sk89q-repo + http://maven.sk89q.com/repo/ + + + + + com.sk89q.worldedit + worldedit-bukkit + 7.0.0-SNAPSHOT + provided + + + com.sk89q.worldedit + worldedit-core + 7.0.0-SNAPSHOT + provided + + + com.sk89q.worldguard + worldguard-core + 7.0.0-SNAPSHOT + + + com.sk89q.worldguard + worldguard-legacy + 7.0.0-SNAPSHOT + + + net.countercraft + movecraft-api + API + jar + + + org.jetbrains + annotations-java5 + RELEASE + + + + + src/main/java + + + org.apache.maven.plugins + maven-compiler-plugin + 3.7.0 + + + net/countercraft/movecraft/compat/we7/** + + 1.8 + 1.8 + + + + org.apache.maven.plugins + maven-jar-plugin + 2.4 + + + net/countercraft/movecraft/compat/we7/** + + + + + + + \ No newline at end of file diff --git a/modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/IMovecraftRepair.java b/modules/worldedit/WE7Utils/src/main/java/net/countercraft/movecraft/compat/we7/IMovecraftRepair.java similarity index 63% rename from modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/IMovecraftRepair.java rename to modules/worldedit/WE7Utils/src/main/java/net/countercraft/movecraft/compat/we7/IMovecraftRepair.java index 695b2ab3c..a3cdd9e9a 100644 --- a/modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/IMovecraftRepair.java +++ b/modules/worldedit/WE7Utils/src/main/java/net/countercraft/movecraft/compat/we7/IMovecraftRepair.java @@ -1,8 +1,9 @@ -package net.countercraft.movecraft.compat.v1_13_R2; +package net.countercraft.movecraft.compat.we7; import com.sk89q.jnbt.CompoundTag; import com.sk89q.jnbt.ListTag; import com.sk89q.jnbt.Tag; +import com.sk89q.worldedit.MaxChangedBlocksException; import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.bukkit.BukkitAdapter; @@ -11,18 +12,26 @@ import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard; import com.sk89q.worldedit.extent.clipboard.Clipboard; import com.sk89q.worldedit.extent.clipboard.io.*; +import com.sk89q.worldedit.function.mask.BlockMask; +import com.sk89q.worldedit.function.mask.BlockTypeMask; import com.sk89q.worldedit.function.mask.ExistingBlockMask; import com.sk89q.worldedit.function.operation.ForwardExtentCopy; import com.sk89q.worldedit.function.operation.Operations; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.regions.CuboidRegion; +import com.sk89q.worldedit.regions.Polygonal2DRegion; +import com.sk89q.worldedit.regions.Region; import com.sk89q.worldedit.registry.state.EnumProperty; import com.sk89q.worldedit.registry.state.Property; import com.sk89q.worldedit.world.block.BaseBlock; +import com.sk89q.worldedit.world.block.BlockType; +import com.sk89q.worldedit.world.registry.WorldData; +import com.sk89q.worldguard.protection.regions.ProtectedCuboidRegion; +import com.sk89q.worldguard.protection.regions.ProtectedPolygonalRegion; +import com.sk89q.worldguard.protection.regions.ProtectedRegion; import net.countercraft.movecraft.MovecraftRepair; import net.countercraft.movecraft.config.Settings; import net.countercraft.movecraft.craft.Craft; -import net.countercraft.movecraft.utils.FAWEUtils; import net.countercraft.movecraft.utils.HashHitBox; import org.bukkit.Bukkit; import org.bukkit.Location; @@ -30,7 +39,9 @@ import org.bukkit.World; import org.bukkit.block.Block; import org.bukkit.block.Sign; +import org.bukkit.block.Dispenser; import org.bukkit.block.data.type.Slab; +import org.bukkit.inventory.ItemStack; import org.bukkit.plugin.Plugin; import org.bukkit.util.Vector; @@ -38,6 +49,7 @@ import java.util.HashMap; import java.util.HashSet; import java.util.LinkedList; +import java.util.Set; import java.util.logging.Logger; public class IMovecraftRepair extends MovecraftRepair { @@ -46,9 +58,6 @@ public class IMovecraftRepair extends MovecraftRepair { private HashMap> missingBlocksMap = new HashMap<>(); @Override public boolean saveCraftRepairState(Craft craft, Sign sign, Plugin plugin, String s) { - if (Settings.UseFAWE){ - return FAWEUtils.faweSaveCraftRepairState(craft,sign,plugin,s); - } HashHitBox hitBox = craft.getHitBox(); File saveDirectory = new File(plugin.getDataFolder(), "CraftRepairStates"); World world = craft.getW(); @@ -86,10 +95,60 @@ public boolean saveCraftRepairState(Craft craft, Sign sign, Plugin plugin, Strin } @Override - public boolean saveRegionRepairState(Plugin plugin, World world, org.bukkit.util.Vector vector, org.bukkit.util.Vector vector1, String s) { - return false; + public boolean saveRegionRepairState(Plugin plugin, World world, ProtectedRegion region) { + File saveDirectory = new File(plugin.getDataFolder(), "RegionRepairStates"); + com.sk89q.worldedit.world.World weWorld = new BukkitWorld(world); + BlockVector3 weMinPos = region.getMinimumPoint(); + BlockVector3 weMaxPos = region.getMaximumPoint(); + if (!saveDirectory.exists()){ + saveDirectory.mkdirs(); + } + Set blockTypeSet = new HashSet<>(); + Region weRegion = null; + if (region instanceof ProtectedCuboidRegion){ + weRegion = new CuboidRegion(weMinPos, weMaxPos); + } else if (region instanceof ProtectedPolygonalRegion){ + ProtectedPolygonalRegion polyReg = (ProtectedPolygonalRegion) region; + weRegion = new Polygonal2DRegion(weWorld,polyReg.getPoints(),polyReg.getMinimumPoint().getBlockY(),polyReg.getMaximumPoint().getBlockY()); + } + + + + File repairStateFile = new File(saveDirectory, region.getId().replaceAll("´\\s+", "_") + ".schematic"); + for (int x = weMinPos.getBlockX(); x <= weMaxPos.getBlockX(); x++){ + for (int y = weMinPos.getBlockY(); y <= weMaxPos.getBlockY(); y++){ + for (int z = weMinPos.getBlockZ(); z <= weMaxPos.getBlockZ(); z++){ + Block block = world.getBlockAt(x,y,z); + if (block.getType().equals(Material.AIR)){ + continue; + } + if (Settings.AssaultDestroyableBlocks.contains(block.getType())){ + blockTypeSet.add(new BlockType("minecraft:" + block.getType().name().toLowerCase())); + } + } + } + } + try { + + BlockArrayClipboard clipboard = new BlockArrayClipboard(weRegion); + Extent source = WorldEdit.getInstance().getEditSessionFactory().getEditSession(weWorld, -1); + Extent destination = clipboard; + ForwardExtentCopy copy = new ForwardExtentCopy(source, weRegion, destination, weMinPos); + BlockTypeMask mask = new BlockTypeMask(source, blockTypeSet); + copy.setSourceMask(mask); + Operations.completeLegacy(copy); + ClipboardWriter writer = BuiltInClipboardFormat.SPONGE_SCHEMATIC.getWriter(new FileOutputStream(repairStateFile, false)); + writer.write(clipboard); + writer.close(); + return true; + + } catch (MaxChangedBlocksException | IOException e) { + e.printStackTrace(); + return false; + } } + @Override public boolean repairRegion(World world, String s) { return false; @@ -115,16 +174,14 @@ public Clipboard loadCraftRepairStateClipboard(Plugin plugin, Sign sign, String } if (clipboard != null){ long numDiffBlocks = 0; - int index = 0; HashMap missingBlocks = new HashMap<>(); LinkedList locMissingBlocks = new LinkedList<>(); org.bukkit.util.Vector distMP = getDistanceFromSignToLowestPoint(clipboard,s); BlockVector3 minPos = BlockVector3.at(sign.getLocation().getBlockX() - distMP.getBlockX(),sign.getLocation().getBlockY() - distMP.getBlockY(),sign.getLocation().getBlockZ() - distMP.getBlockZ()); BlockVector3 distance = BlockVector3.at(minPos.getBlockX() - clipboard.getMinimumPoint().getBlockX(), minPos.getBlockY() - clipboard.getMinimumPoint().getBlockY(),minPos.getBlockZ() - clipboard.getMinimumPoint().getBlockZ()); - for (int x = clipboard.getMinimumPoint().getBlockX(); x <= clipboard.getMaximumPoint().getBlockX(); x++) { - for (int y = clipboard.getMinimumPoint().getBlockY(); y <= clipboard.getMaximumPoint().getBlockY(); y++) { - for (int z = clipboard.getMinimumPoint().getBlockZ(); z <= clipboard.getMaximumPoint().getBlockZ(); z++) { - index++; + for (int y = clipboard.getMinimumPoint().getBlockY(); y <= clipboard.getMaximumPoint().getBlockY(); y++) { + for (int z = clipboard.getMinimumPoint().getBlockZ(); z <= clipboard.getMaximumPoint().getBlockZ(); z++) { + for (int x = clipboard.getMinimumPoint().getBlockX(); x <= clipboard.getMaximumPoint().getBlockX(); x++) { BlockVector3 position = BlockVector3.at(x,y,z); BaseBlock block = clipboard.getFullBlock(position); Material type = BukkitAdapter.adapt(block.getBlockType()); @@ -136,6 +193,7 @@ public Clipboard loadCraftRepairStateClipboard(Plugin plugin, Sign sign, String isImportant = false; } boolean blockMissing = isImportant && type != bukkitBlock.getType(); + //Check if single slabs are at locations where double slabs should be located and vice versa if (type.name().endsWith("_SLAB")){ plugin.getLogger().info(type.name()); for (Property property : block.getStates().keySet()){ @@ -176,12 +234,10 @@ public Clipboard loadCraftRepairStateClipboard(Plugin plugin, Sign sign, String if (type.equals(Material.REDSTONE_WALL_TORCH)){ typeToConsume = Material.REDSTONE_TORCH; } - if (type.equals(Material.WALL_TORCH)){ + if (type.equals(Material.WALL_TORCH)) typeToConsume = Material.TORCH; - } - if (type.name().endsWith("_DOOR") || type.name().endsWith("_BED")){ + if (type.name().endsWith("_DOOR") || type.name().endsWith("_BED")) qtyToConsume = 0.5; - } if (type.equals(Material.REDSTONE_WIRE)) typeToConsume = Material.REDSTONE; if (type.equals(Material.DISPENSER)){ @@ -245,6 +301,83 @@ public Clipboard loadCraftRepairStateClipboard(Plugin plugin, Sign sign, String missingBlocks.put(typeToConsume,qtyToConsume); } } + if (bukkitBlock.getState() instanceof Dispenser){ + if (!type.equals(Material.DISPENSER)) + continue; + Dispenser dispenser = (Dispenser) bukkitBlock.getState(); + int numTNT = 0; + int numFireCharge = 0; + int numWaterBucket = 0; + ListTag listTag = block.getNbtData().getListTag("Items"); + if (listTag != null) { + for (Tag entry : listTag.getValue()) { + //To avoid ClassCastExceptions, continue if tag is not a CompoundTag + if (!(entry instanceof CompoundTag)) { + continue; + } + CompoundTag cTag = (CompoundTag) entry; + if (cTag.getString("id").equals("minecraft:tnt")) { + numTNT += (int) cTag.getByte("Count"); + } + if (cTag.getString("id").equals("minecraft:fire_charge")) { + numFireCharge += (int) cTag.getByte("Count"); + } + if (cTag.getString("id").equals("minecraft:water_bucket")) { + numWaterBucket += (int) cTag.getByte("Count"); + } + } + } + ItemStack[] contents = dispenser.getInventory().getContents(); + for (ItemStack iStack : contents){ + if (iStack == null){ + continue; + } + if (iStack.getType().equals(Material.TNT)){ + numTNT -= iStack.getAmount(); + } + if (iStack.getType().equals(Material.WATER_BUCKET)){ + numWaterBucket -= iStack.getAmount(); + } + if (iStack.getType().equals(Material.FIRE_CHARGE)){ + numFireCharge -= iStack.getAmount(); + } + } + boolean needsReplace = false; + if (numTNT > 0){ + if (missingBlocks.containsKey(Material.TNT)){ + double count = missingBlocks.get(Material.TNT); + count += numTNT; + missingBlocks.put(Material.TNT,count); + } else { + missingBlocks.put(Material.TNT, (double) numTNT); + } + needsReplace = true; + } + if (numFireCharge > 0){ + if (missingBlocks.containsKey(Material.FIRE_CHARGE)){ + double count = missingBlocks.get(Material.FIRE_CHARGE); + count += numFireCharge; + missingBlocks.put(Material.FIRE_CHARGE,count); + } else { + missingBlocks.put(Material.FIRE_CHARGE, (double) numFireCharge); + } + needsReplace = true; + } + if (numWaterBucket > 0){ + if (missingBlocks.containsKey(Material.WATER_BUCKET)){ + double count = missingBlocks.get(Material.WATER_BUCKET); + count += numWaterBucket; + missingBlocks.put(Material.WATER_BUCKET,count); + } else { + missingBlocks.put(Material.WATER_BUCKET, (double) numWaterBucket); + } + needsReplace = true; + } + if (needsReplace){ + locMissingBlocks.push(new Vector(x,y,z)); + numDiffBlocks++; + } + } } } @@ -258,7 +391,21 @@ public Clipboard loadCraftRepairStateClipboard(Plugin plugin, Sign sign, String @Override public Clipboard loadRegionRepairStateClipboard(Plugin plugin, String s, World world) { - return null; + Clipboard clipboard; + File dataDirectory = new File(plugin.getDataFolder(), "RegionRepairStates"); + File file = new File(dataDirectory, s + ".schematic"); // The schematic file + com.sk89q.worldedit.world.World weWorld = new BukkitWorld(world); + ClipboardFormat format = ClipboardFormats.findByFile(file); + try { + InputStream input = new FileInputStream(file); + ClipboardReader reader = format.getReader(input); + clipboard = reader.read(); + reader.close(); + } catch (IOException e) { + clipboard = null; + e.printStackTrace(); + } + return clipboard; } @Override diff --git a/pom.xml b/pom.xml index 22d0feb85..5c630492d 100644 --- a/pom.xml +++ b/pom.xml @@ -19,14 +19,17 @@ - modules/FAWEUtils modules/api modules/v1_10_R1 modules/v1_11_R1 modules/v1_12_R1 modules/v1_13_R2 + modules/worldedit/FAWEUtils + modules/worldedit/WE6Utils + modules/worldedit/WE7Utils modules/Movecraft + From 1bca2361e2f837f95bdf84737d893f3530c531f2 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Fri, 12 Apr 2019 10:04:45 +0200 Subject: [PATCH 011/304] More bug fixes --- modules/Movecraft/pom.xml | 1 + .../net/countercraft/movecraft/Movecraft.java | 28 ++++-- .../async/detection/DetectionTask.java | 71 ++++++++++++--- .../commands/ManOverboardCommand.java | 1 + .../movecraft/commands/MovecraftCommand.java | 8 +- .../update/CraftTranslateCommand.java | 7 ++ .../update/ExplosionUpdateCommand.java | 1 + .../update/PotionEffectsUpdateCommand.java | 3 +- .../update/WaterlogUpdateCommand.java | 88 +++++++++++++++++++ .../config.yml => config_legacy.yml} | 0 .../movecraft/craft/CraftType.java | 4 +- .../movecraft/events/CraftExplodeEvent.java | 27 ++++++ .../compat/v1_13_R2/IWorldHandler.java | 14 +-- 13 files changed, 221 insertions(+), 32 deletions(-) create mode 100644 modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/WaterlogUpdateCommand.java rename modules/Movecraft/src/main/resources/{legacyconfig/config.yml => config_legacy.yml} (100%) create mode 100644 modules/api/src/main/java/net/countercraft/movecraft/events/CraftExplodeEvent.java diff --git a/modules/Movecraft/pom.xml b/modules/Movecraft/pom.xml index c4f39e866..69c052077 100644 --- a/modules/Movecraft/pom.xml +++ b/modules/Movecraft/pom.xml @@ -214,6 +214,7 @@ plugin.yml config.yml + config_legacy.yml localisation/** types/*.craft diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java index c0cebd0de..40f3d3c58 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java @@ -47,16 +47,15 @@ import net.countercraft.movecraft.compatmanager.WorldGuardCompatManager; import net.milkbowl.vault.economy.Economy; import org.bukkit.Material; +import org.bukkit.configuration.file.FileConfiguration; +import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.plugin.Plugin; import org.bukkit.plugin.RegisteredServiceProvider; import org.bukkit.plugin.java.JavaPlugin; import org.yaml.snakeyaml.Yaml; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.InputStream; +import java.io.*; import java.util.*; import java.util.logging.Level; import java.util.logging.Logger; @@ -113,10 +112,7 @@ public void onEnable() { if (!Settings.IsLegacy) { this.saveDefaultConfig(); } else { - File configFile = new File(Movecraft.getInstance().getDataFolder().getAbsolutePath() + "/config.yml"); - if (!configFile.exists()) { - this.saveResource("legacyconfig/config.yml", false); - } + saveLegacyConfig(); } try { Class.forName("com.destroystokyo.paper.Title"); @@ -131,7 +127,7 @@ public void onEnable() { Settings.RestrictSiBsToRegions = getConfig().getBoolean("RestrictSiBsToRegions", false); Settings.Debug = getConfig().getBoolean("Debug", false); Settings.DisableSpillProtection = getConfig().getBoolean("DisableSpillProtection", false); - // if the PilotTool is specified in the config.yml file, use it + // if the PilotTool is specified in the config_legacy.yml file, use it if (getConfig().getString("PilotTool") != null || getConfig().getString("PilotTool") != "") { logger.log(Level.INFO, "Recognized PilotTool setting of: " + getConfig().getString("PilotTool")); @@ -547,6 +543,20 @@ public void onLoad() { logger = getLogger(); } + private void saveLegacyConfig(){ + File configFile = new File(getDataFolder(), "config.yml"); + if (configFile.exists()) + return; + InputStream resource = getResource("config_legacy.yml"); + Reader reader = new InputStreamReader(resource); + FileConfiguration config = YamlConfiguration.loadConfiguration(reader); + try { + config.save(configFile); + } catch (IOException e) { + e.printStackTrace(); + } + } + public WorldGuardPlugin getWorldGuardPlugin() { diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/detection/DetectionTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/detection/DetectionTask.java index 1237198ed..297133647 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/detection/DetectionTask.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/detection/DetectionTask.java @@ -29,8 +29,10 @@ import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.World; +import org.bukkit.block.Block; import org.bukkit.block.BlockState; import org.bukkit.block.Sign; +import org.bukkit.block.data.type.Chest; import org.bukkit.entity.Player; import java.util.*; @@ -105,6 +107,7 @@ private void detectBlock(int x, int y, int z) { if (notVisited(workingLocation, visited)) { Material testType = null; + Block testBlock = null; int testData = 0; try { testData = data.getWorld().getBlockAt(x, y, z).getData(); @@ -145,19 +148,43 @@ private void detectBlock(int x, int y, int z) { fail(I18nSupport.getInternationalisedString("Detection - Forbidden block found")); } else if (isAllowedBlock(testType, testData)) { // check for double chests - if (testType == Material.CHEST) { + /*if (testType == Material.CHEST) { boolean foundDoubleChest = false; if (data.getWorld().getBlockAt(x - 1, y, z).getType() == Material.CHEST) { - foundDoubleChest = true; + if (Settings.IsLegacy) + foundDoubleChest = true; + else { + Chest chest = (Chest) data.getWorld().getBlockAt(x - 1, y, z).getBlockData(); + if (chest.getType() != Chest.Type.SINGLE) + foundDoubleChest = true; + } } if (data.getWorld().getBlockAt(x + 1, y, z).getType() == Material.CHEST) { - foundDoubleChest = true; + if (Settings.IsLegacy) + foundDoubleChest = true; + else { + Chest chest = (Chest) data.getWorld().getBlockAt(x + 1, y, z).getBlockData(); + if (chest.getType() != Chest.Type.SINGLE) + foundDoubleChest = true; + } } if (data.getWorld().getBlockAt(x, y, z - 1).getType() == Material.CHEST) { - foundDoubleChest = true; + if (Settings.IsLegacy) + foundDoubleChest = true; + else { + Chest chest = (Chest) data.getWorld().getBlockAt(x , y, z - 1).getBlockData(); + if (chest.getType() != Chest.Type.SINGLE) + foundDoubleChest = true; + } } if (data.getWorld().getBlockAt(x, y, z + 1).getType() == Material.CHEST) { - foundDoubleChest = true; + if (Settings.IsLegacy) + foundDoubleChest = true; + else { + Chest chest = (Chest) data.getWorld().getBlockAt(x , y, z + 1).getBlockData(); + if (chest.getType() != Chest.Type.SINGLE) + foundDoubleChest = true; + } } if (foundDoubleChest) { fail(I18nSupport.getInternationalisedString( @@ -168,22 +195,46 @@ private void detectBlock(int x, int y, int z) { if (testType == Material.TRAPPED_CHEST) { boolean foundDoubleChest = false; if (data.getWorld().getBlockAt(x - 1, y, z).getType() == Material.TRAPPED_CHEST) { - foundDoubleChest = true; + if (Settings.IsLegacy) + foundDoubleChest = true; + else { + Chest chest = (Chest) data.getWorld().getBlockAt(x - 1, y, z).getBlockData(); + if (chest.getType() != Chest.Type.SINGLE) + foundDoubleChest = true; + } } if (data.getWorld().getBlockAt(x + 1, y, z).getType() == Material.TRAPPED_CHEST) { - foundDoubleChest = true; + if (Settings.IsLegacy) + foundDoubleChest = true; + else { + Chest chest = (Chest) data.getWorld().getBlockAt(x + 1, y, z).getBlockData(); + if (chest.getType() != Chest.Type.SINGLE) + foundDoubleChest = true; + } } if (data.getWorld().getBlockAt(x, y, z - 1).getType() == Material.TRAPPED_CHEST) { - foundDoubleChest = true; + if (Settings.IsLegacy) + foundDoubleChest = true; + else { + Chest chest = (Chest) data.getWorld().getBlockAt(x, y, z - 1).getBlockData(); + if (chest.getType() != Chest.Type.SINGLE) + foundDoubleChest = true; + } } if (data.getWorld().getBlockAt(x, y, z + 1).getType() == Material.TRAPPED_CHEST) { - foundDoubleChest = true; + if (Settings.IsLegacy) + foundDoubleChest = true; + else { + Chest chest = (Chest) data.getWorld().getBlockAt(x, y, z + 1).getBlockData(); + if (chest.getType() != Chest.Type.SINGLE) + foundDoubleChest = true; + } } if (foundDoubleChest) { fail(I18nSupport.getInternationalisedString( "Detection - ERROR: Double chest found")); } - } + }*/ Location loc = new Location(data.getWorld(), x, y, z); Player p; diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/ManOverboardCommand.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/ManOverboardCommand.java index 9717698dd..502a45bbf 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/ManOverboardCommand.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/ManOverboardCommand.java @@ -54,6 +54,7 @@ public boolean onCommand(CommandSender commandSender, Command command, String s, if (craft.getDisabled() || craft.getSinking()) { player.sendMessage(MOVECRAFT_COMMAND_PREFIX + "Can't teleport to a disabled craft"); + return true; } player.teleport(telPoint); return true; diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/MovecraftCommand.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/MovecraftCommand.java index 1c1f6e14b..5b2b4d3f7 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/MovecraftCommand.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/MovecraftCommand.java @@ -35,9 +35,11 @@ public boolean onCommand(CommandSender commandSender, Command command, String s, commandSender.sendMessage(MOVECRAFT_COMMAND_PREFIX + "Reloaded types"); return true; } - if (args.length == 1 && args[0].equalsIgnoreCase("reloadconfig") && commandSender.hasPermission("movecraft.commands.movecraft.reloadconfig")){ + if (args.length == 1 && args[0].equalsIgnoreCase("reloadplugin") && commandSender.hasPermission("movecraft.commands.movecraft.reloadconfig")){ Movecraft.getInstance().reloadConfig(); - commandSender.sendMessage(MOVECRAFT_COMMAND_PREFIX + "Reloaded config"); + Movecraft.getInstance().getLogger().info("Reloading Movecraft"); + Movecraft.getInstance().onEnable(); + commandSender.sendMessage(MOVECRAFT_COMMAND_PREFIX + "Reloaded Movecraft"); return true; } commandSender.sendMessage(MOVECRAFT_COMMAND_PREFIX + "Error, invalid syntax"); @@ -51,7 +53,7 @@ public List onTabComplete(CommandSender commandSender, Command command, return Collections.emptyList(); List completions = new ArrayList<>(); completions.add("reloadtypes"); - completions.add("reloadconfig"); + completions.add("reloadplugin"); List returnValues = new ArrayList<>(); for(String completion : completions) if(completion.toLowerCase().startsWith(args[args.length-1].toLowerCase())) diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftTranslateCommand.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftTranslateCommand.java index 8dfdd88ff..4fa3aa4ff 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftTranslateCommand.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftTranslateCommand.java @@ -7,6 +7,7 @@ import net.countercraft.movecraft.craft.Craft; import net.countercraft.movecraft.craft.CraftManager; import net.countercraft.movecraft.events.SignTranslateEvent; +import net.countercraft.movecraft.mapUpdater.MapUpdateManager; import net.countercraft.movecraft.utils.*; import org.bukkit.Bukkit; import org.bukkit.Material; @@ -65,6 +66,10 @@ public void doUpdate() { passthroughBlocks.add(Material.SUNFLOWER); passthroughBlocks.add(Material.LILAC); passthroughBlocks.add(Material.PEONY); + passthroughBlocks.add(Material.KELP_PLANT); + passthroughBlocks.add(Material.TALL_SEAGRASS); + passthroughBlocks.add(Material.SEA_PICKLE); + passthroughBlocks.add(Material.SEAGRASS); } @@ -189,6 +194,8 @@ public void doUpdate() { } } } + if (!Settings.IsLegacy) + MapUpdateManager.getInstance().scheduleUpdate(new WaterlogUpdateCommand(craft)); if (!craft.isNotProcessing()) craft.setProcessing(false); time = System.nanoTime() - time; diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/ExplosionUpdateCommand.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/ExplosionUpdateCommand.java index 98243283d..2f5ad589a 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/ExplosionUpdateCommand.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/ExplosionUpdateCommand.java @@ -45,6 +45,7 @@ private void createExplosion(Location loc, float explosionPower) { return; } } + Movecraft.getInstance().getLogger().info(loc.getBlock().getType().name()); loc.getWorld().createExplosion(loc.getX() + 0.5, loc.getY() + 0.5, loc.getZ() + 0.5, explosionPower); } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/PotionEffectsUpdateCommand.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/PotionEffectsUpdateCommand.java index 735531431..84fdefa7e 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/PotionEffectsUpdateCommand.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/PotionEffectsUpdateCommand.java @@ -36,9 +36,10 @@ public void run() { if (timePassed < delay) return; entity.addPotionEffect(effect); + cancel(); } - }.runTaskTimerAsynchronously(Movecraft.getInstance(),0,20); + }.runTaskTimer(Movecraft.getInstance(),0,20); } } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/WaterlogUpdateCommand.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/WaterlogUpdateCommand.java new file mode 100644 index 000000000..0dbdaee1e --- /dev/null +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/WaterlogUpdateCommand.java @@ -0,0 +1,88 @@ +package net.countercraft.movecraft.mapUpdater.update; + +import net.countercraft.movecraft.Movecraft; +import net.countercraft.movecraft.MovecraftLocation; +import net.countercraft.movecraft.craft.Craft; +import net.countercraft.movecraft.utils.HashHitBox; +import net.countercraft.movecraft.utils.HitBox; +import org.bukkit.Material; +import org.bukkit.block.Block; +import org.bukkit.block.data.Bisected; +import org.bukkit.block.data.Waterlogged; +import org.bukkit.block.data.type.TrapDoor; +import org.bukkit.scheduler.BukkitRunnable; + +public class WaterlogUpdateCommand extends UpdateCommand{ + private final Craft craft; + public WaterlogUpdateCommand(Craft craft){ + this.craft = craft; + } + @Override + public void doUpdate() { + HashHitBox hitBox = craft.getHitBox(); + for (MovecraftLocation moveLoc : hitBox){ + Block b = moveLoc.toBukkit(craft.getW()).getBlock(); + if (!(b.getBlockData() instanceof Waterlogged)){ + continue; + } + BukkitRunnable runnable = null; + Waterlogged wLog = (Waterlogged) b.getBlockData(); + if (b.getY() > craft.getWaterLine()){ + runnable = new BukkitRunnable() { + @Override + public void run() { + wLog.setWaterlogged(false); + } + }; + runnable.runTask(Movecraft.getInstance()); + continue; + } + if (wLog instanceof TrapDoor){ + TrapDoor tDoor = (TrapDoor) wLog; + if (tDoor.getHalf() == Bisected.Half.BOTTOM && b.getRelative(0,1,0).getType() == Material.WATER){ + runnable = new BukkitRunnable() { + @Override + public void run() { + tDoor.setWaterlogged(true); + } + }; + + } + if (tDoor.getHalf() == Bisected.Half.TOP && b.getRelative(0,-1,0).getType() == Material.WATER){ + runnable = new BukkitRunnable() { + @Override + public void run() { + tDoor.setWaterlogged(true); + } + }; + } + if (b.getRelative(tDoor.getFacing().getOppositeFace()).getType() == Material.WATER){ + runnable = new BukkitRunnable() { + @Override + public void run() { + tDoor.setWaterlogged(true); + } + }; + } + } else { + if (b.getRelative(0,1,0).getType() == Material.WATER || + b.getRelative(0,-1,0).getType() == Material.WATER || + b.getRelative(0,0,1).getType() == Material.WATER || + b.getRelative(0,0,-1).getType() == Material.WATER || + b.getRelative(1,0,0).getType() == Material.WATER || + b.getRelative(-1,0,0).getType() == Material.WATER ){ + runnable = new BukkitRunnable() { + @Override + public void run() { + wLog.setWaterlogged(true); + } + }; + + } + } + if (runnable == null) + return; + runnable.runTask(Movecraft.getInstance()); + } + } +} diff --git a/modules/Movecraft/src/main/resources/legacyconfig/config.yml b/modules/Movecraft/src/main/resources/config_legacy.yml similarity index 100% rename from modules/Movecraft/src/main/resources/legacyconfig/config.yml rename to modules/Movecraft/src/main/resources/config_legacy.yml diff --git a/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java b/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java index 465559f52..e3df6b053 100644 --- a/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java +++ b/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java @@ -491,13 +491,13 @@ private HashMap effectListFromObject(Object obj){ amplifier = integer; } if (str.equals("delay")){ - delay = 20 * integer; + delay = integer; } } if (effect == null){ continue; } - PotionEffect potEffect = new PotionEffect(effect,duration,amplifier); + PotionEffect potEffect = new PotionEffect(effect,duration,amplifier,true,true); ret.put(potEffect,delay); } return ret; diff --git a/modules/api/src/main/java/net/countercraft/movecraft/events/CraftExplodeEvent.java b/modules/api/src/main/java/net/countercraft/movecraft/events/CraftExplodeEvent.java new file mode 100644 index 000000000..7cb5accd3 --- /dev/null +++ b/modules/api/src/main/java/net/countercraft/movecraft/events/CraftExplodeEvent.java @@ -0,0 +1,27 @@ +package net.countercraft.movecraft.events; + +import net.countercraft.movecraft.craft.Craft; +import org.bukkit.block.Block; +import org.bukkit.event.HandlerList; +import org.jetbrains.annotations.NotNull; + +import java.util.Set; + +public class CraftExplodeEvent extends CraftEvent { + private static HandlerList handlerList = new HandlerList(); + private double explosionForce; + private Set destroyedBlocks; + public CraftExplodeEvent(@NotNull Craft craft) { + super(craft); + } + + + @Override + public HandlerList getHandlers() { + return handlerList; + } + + public static HandlerList getHandlerList(){ + return handlerList; + } +} diff --git a/modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/IWorldHandler.java b/modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/IWorldHandler.java index 5a6f9bd40..b57dfa9db 100644 --- a/modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/IWorldHandler.java +++ b/modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/IWorldHandler.java @@ -305,15 +305,15 @@ public void setBlockFast(@NotNull Location location, @NotNull Rotation rotation, @Override public void disableShadow(@NotNull Material type) { Method method; - try { + //try { Block tempBlock = CraftMagicNumbers.getBlock(type); - method = Block.class.getDeclaredMethod("d", int.class); - method.setAccessible(true); - method.invoke(tempBlock, 0); - } catch (NoSuchMethodException | InvocationTargetException | IllegalArgumentException | IllegalAccessException | SecurityException e1) { + //method = Block.class.getDeclaredMethod("d", int.class); + //method.setAccessible(true); + //method.invoke(tempBlock, 0); + //} catch (NoSuchMethodException | InvocationTargetException | IllegalArgumentException | IllegalAccessException | SecurityException e1) { // TODO Auto-generated catch block - e1.printStackTrace(); - } + // e1.printStackTrace(); + //} } private static MovecraftLocation bukkit2MovecraftLoc(Location l) { From a554e84a384431f7f2246d0dfd6ab1faa3753e09 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Tue, 16 Apr 2019 21:10:24 +0200 Subject: [PATCH 012/304] Signs are now checked by their BlockState instead of their Material type --- .../net/countercraft/movecraft/Movecraft.java | 5 +- .../movecraft/async/AsyncManager.java | 10 ++ .../movecraft/listener/InteractListener.java | 6 +- .../update/CraftTranslateCommand.java | 2 +- .../update/WorldEdit7UpdateCommand.java | 153 ++++++++++++++++++ .../update/WorldEditUpdateCommand.java | 22 +-- .../movecraft/repair/RepairManager.java | 11 +- .../sign/AntiAircraftDirectorSign.java | 2 +- .../movecraft/sign/AscendSign.java | 2 +- .../movecraft/sign/CannonDirectorSign.java | 2 +- .../movecraft/sign/ContactsSign.java | 2 +- .../movecraft/sign/CraftSign.java | 2 +- .../countercraft/movecraft/sign/CrewSign.java | 4 +- .../movecraft/sign/CruiseSign.java | 5 +- .../movecraft/sign/DescendSign.java | 2 +- .../countercraft/movecraft/sign/HelmSign.java | 2 +- .../countercraft/movecraft/sign/MoveSign.java | 2 +- .../countercraft/movecraft/sign/NameSign.java | 2 +- .../movecraft/sign/RegionDamagedSign.java | 5 +- .../movecraft/sign/RelativeMoveSign.java | 2 +- .../movecraft/sign/ReleaseSign.java | 2 +- .../movecraft/sign/RemoteSign.java | 2 +- .../movecraft/sign/RepairSign.java | 67 ++++++-- .../movecraft/sign/SpeedSign.java | 2 +- .../movecraft/sign/StatusSign.java | 2 +- .../movecraft/sign/SubcraftRotateSign.java | 2 +- .../movecraft/sign/TeleportSign.java | 2 +- .../localisation/movecraftlang_en.properties | 1 + .../movecraft/config/Settings.java | 1 + modules/worldedit/FAWEUtils/pom.xml | 71 -------- .../compat/fawe/IMovecraftRepair.java | 123 -------------- .../compat/we7/IMovecraftRepair.java | 19 ++- pom.xml | 1 - 33 files changed, 268 insertions(+), 270 deletions(-) create mode 100644 modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/WorldEdit7UpdateCommand.java delete mode 100644 modules/worldedit/FAWEUtils/pom.xml delete mode 100644 modules/worldedit/FAWEUtils/src/main/java/net/countercraft/movecraft/compat/fawe/IMovecraftRepair.java diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java index 40f3d3c58..0e19416ae 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java @@ -105,9 +105,10 @@ public void onEnable() { String packageName = this.getServer().getClass().getPackage().getName(); String version = packageName.substring(packageName.lastIndexOf('.') + 1); String[] parts = version.split("_"); - Integer versionNumber = Integer.valueOf(parts[1]); + int versionNumber = Integer.valueOf(parts[1]); //Check if the server is 1.12 and lower or 1.13 and higher Settings.IsLegacy = versionNumber <= 12; + Settings.is1_14 = versionNumber == 14; // Read in config if (!Settings.IsLegacy) { this.saveDefaultConfig(); @@ -487,7 +488,7 @@ public void onEnable() { getServer().getPluginManager().registerEvents(new InteractListener(), this); if (worldEditPlugin != null) { //getServer().getPluginManager().registerEvents(new WorldEditInteractListener(), this); - repairManager = new RepairManager(this); + repairManager = new RepairManager(); repairManager.runTaskTimerAsynchronously(this, 0,1); } this.getCommand("movecraft").setExecutor(new MovecraftCommand()); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java index 0e0b8392f..e9caa13ff 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java @@ -62,6 +62,7 @@ public class AsyncManager extends BukkitRunnable { private long lastFadeCheck = 0; private long lastContactCheck = 0; private HashSet transparent = null; + private boolean climb = false; public AsyncManager() { transparent = new HashSet<>(); @@ -365,6 +366,7 @@ private void processCruise() { bankLeft = true; if (pcraft.getNotificationPlayer().getInventory().getHeldItemSlot() == 5) bankRight = true; + } if (Math.abs(ticksElapsed) < pcraft.getTickCooldown()) { @@ -399,6 +401,10 @@ private void processCruise() { if (bankLeft) { dz = (1 + pcraft.getType().getCruiseSkipBlocks()) >> 1; } + if (climb){ + dy = (1 + pcraft.getType().getCruiseSkipBlocks()) >> 1; + climb = false; + } } // ship faces east if (pcraft.getCruiseDirection() == 0x4) { @@ -1118,4 +1124,8 @@ private void clearAll() { clearanceSet.clear(); } + + public void setClimb(boolean climb){ + this.climb = climb; + } } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/InteractListener.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/InteractListener.java index 618c0881a..6b61bf200 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/InteractListener.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/InteractListener.java @@ -17,6 +17,7 @@ package net.countercraft.movecraft.listener; +import net.countercraft.movecraft.Movecraft; import net.countercraft.movecraft.utils.LegacyUtils; import net.countercraft.movecraft.utils.MathUtils; import net.countercraft.movecraft.craft.Craft; @@ -107,10 +108,13 @@ public void onPlayerInteractStick(PlayerInteractEvent event) { if (craft.getPilotLocked()) { // right click moves up or down if using direct // control + if (craft.getCruising()){ + Movecraft.getInstance().getAsyncManager().setClimb(true); + return; + } int DY = 1; if (event.getPlayer().isSneaking()) DY = -1; - craft.translate(0, DY, 0); timeMap.put(event.getPlayer(), System.currentTimeMillis()); craft.setLastCruisUpdate(System.currentTimeMillis()); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftTranslateCommand.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftTranslateCommand.java index 4fa3aa4ff..8c2c5629f 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftTranslateCommand.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftTranslateCommand.java @@ -80,7 +80,7 @@ public void doUpdate() { //trigger sign events for(MovecraftLocation location : craft.getHitBox()){ Block block = location.toBukkit(craft.getW()).getBlock(); - if(block.getType() == Material.WALL_SIGN || block.getType() == (Settings.IsLegacy ? LegacyUtils.SIGN_POST : Material.SIGN)){ + if(block.getState() instanceof Sign){ Sign sign = (Sign) block.getState(); Bukkit.getServer().getPluginManager().callEvent(new SignTranslateEvent(block, craft, sign.getLines())); sign.update(); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/WorldEdit7UpdateCommand.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/WorldEdit7UpdateCommand.java new file mode 100644 index 000000000..e591a7da9 --- /dev/null +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/WorldEdit7UpdateCommand.java @@ -0,0 +1,153 @@ +package net.countercraft.movecraft.mapUpdater.update; + +import com.sk89q.jnbt.CompoundTag; +import com.sk89q.jnbt.ListTag; +import com.sk89q.jnbt.Tag; +import com.sk89q.worldedit.bukkit.BukkitAdapter; +import net.countercraft.movecraft.MovecraftLocation; +import net.countercraft.movecraft.config.Settings; +import org.bukkit.Material; +import org.bukkit.World; +import org.bukkit.block.Block; +import org.bukkit.block.BlockState; +import org.bukkit.block.Dispenser; +import org.bukkit.block.Sign; +import org.bukkit.block.data.BlockData; +import org.bukkit.inventory.ItemStack; + +public class WorldEdit7UpdateCommand extends UpdateCommand { + private final com.sk89q.worldedit.world.block.BaseBlock worldEdit7BaseBlock; + private World world; + private MovecraftLocation location; + private Material type; + public WorldEdit7UpdateCommand(com.sk89q.worldedit.world.block.BaseBlock worldEditBlockState, World world, MovecraftLocation location, Material type){ + this.worldEdit7BaseBlock = worldEditBlockState; + this.world = world; + this.location = location; + this.type = type; + } + @Override + public void doUpdate() { + Block block = world.getBlockAt(location.getX(), location.getY(), location.getZ()); + block.setType(type); + assert worldEdit7BaseBlock != null; + BlockData bData = BukkitAdapter.adapt(worldEdit7BaseBlock); + block.setBlockData(bData); + Material weType = BukkitAdapter.adapt(worldEdit7BaseBlock.getBlockType()); + if (type == Material.DISPENSER){ + Tag t = worldEdit7BaseBlock.getNbtData().getValue().get("Items"); + ListTag lt = null; + if (t instanceof ListTag) { + lt = (ListTag) t; + } + int numFireCharges = 0; + int numTNT = 0; + int numWater = 0; + if (lt != null) { + for (Tag entryTag : lt.getValue()) { + if (entryTag instanceof CompoundTag) { + CompoundTag cTag = (CompoundTag) entryTag; + if (cTag.toString().contains("minecraft:tnt")) { + numTNT += cTag.getByte("Count"); + } + if (cTag.toString().contains("minecraft:fire_charge")) { + numFireCharges += cTag.getByte("Count"); + } + if (cTag.toString().contains("minecraft:water_bucket")) { + numWater += cTag.getByte("Count"); + } + } + } + } + Dispenser disp = (Dispenser) block.getState(); + ItemStack[] contents = disp.getInventory().getContents(); + for (ItemStack iStack : contents){ + if (iStack == null){ + continue; + } + if (iStack.getType().equals(Material.TNT)){ + numTNT -= iStack.getAmount(); + } + if (iStack.getType().equals(Material.WATER_BUCKET)){ + numWater -= iStack.getAmount(); + } + if (iStack.getType().equals(Material.FIRE_CHARGE)){ + numFireCharges -= iStack.getAmount(); + } + } + if (numFireCharges > 0) { + ItemStack fireItems = new ItemStack(Material.FIRE_CHARGE, numFireCharges); + disp.getInventory().addItem(fireItems); + } + if (numTNT > 0) { + ItemStack TNTItems = new ItemStack(Material.TNT, numTNT); + disp.getInventory().addItem(TNTItems); + } + if (numWater > 0) { + ItemStack WaterItems = new ItemStack(Material.WATER_BUCKET, numWater); + disp.getInventory().addItem(WaterItems); + } + } + if (type.name().endsWith("SIGN")){ + BlockState state = block.getState(); + if (state instanceof Sign) { + Sign s = (Sign) state; + CompoundTag nbtData = worldEdit7BaseBlock.getNbtData(); + //first line + String firstLine = nbtData.getString("Text1"); + firstLine = firstLine.substring(2); + if (firstLine.substring(0, 5).equalsIgnoreCase("extra")){ + firstLine = firstLine.substring(17); + String[] parts = firstLine.split("\""); + firstLine = parts[0]; + } else { + firstLine = ""; + } + //second line + String secondLine = nbtData.getString("Text2"); + secondLine = secondLine.substring(2); + if (secondLine.substring(0, 5).equalsIgnoreCase("extra")){ + secondLine = secondLine.substring(17); + String[] parts = secondLine.split("\""); + secondLine = parts[0]; + } else { + secondLine = ""; + } + //third line + String thirdLine = nbtData.getString("Text3"); + thirdLine = thirdLine.substring(2); + if (thirdLine.substring(0, 5).equalsIgnoreCase("extra")){ + thirdLine = thirdLine.substring(17); + String[] parts = thirdLine.split("\""); + thirdLine = parts[0]; + } else { + thirdLine = ""; + } + //fourth line + String fourthLine = nbtData.getString("Text4"); + fourthLine = fourthLine.substring(2); + if (fourthLine.substring(0, 5).equalsIgnoreCase("extra")){ + fourthLine = fourthLine.substring(17); + String[] parts = fourthLine.split("\""); + fourthLine = parts[0]; + } else { + fourthLine = ""; + } + String[] lines = new String[4]; + if (firstLine.equalsIgnoreCase("\\\\ || /")){ + firstLine = "\\ || /"; + secondLine = "== =="; + thirdLine = "/ || \\"; + } + lines[0] = firstLine; + lines[1] = secondLine; + lines[2] = thirdLine; + lines[3] = fourthLine; + for (int line = 0; line < lines.length; line++) { + s.setLine(line, lines[line]); + } + s.update(false, false); + } + } + } +} diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/WorldEditUpdateCommand.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/WorldEditUpdateCommand.java index b315098b7..74fe0f2e2 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/WorldEditUpdateCommand.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/WorldEditUpdateCommand.java @@ -19,7 +19,6 @@ public class WorldEditUpdateCommand extends UpdateCommand { private final BaseBlock worldEditBaseBlock; - private final com.sk89q.worldedit.world.block.BaseBlock worldEdit7BaseBlock; private World world; private MovecraftLocation location; private Material type; @@ -27,38 +26,23 @@ public class WorldEditUpdateCommand extends UpdateCommand { public WorldEditUpdateCommand(BaseBlock worldEditBaseBlock, World world, MovecraftLocation location, Material type, byte data) { this.worldEditBaseBlock = worldEditBaseBlock; - worldEdit7BaseBlock = null; this.world = world; this.location = location; this.type = type; this.data = data; } - //1.13 constructor - public WorldEditUpdateCommand(com.sk89q.worldedit.world.block.BaseBlock worldEditBlockState, World world, MovecraftLocation location, Material type){ - worldEditBaseBlock = null; - this.worldEdit7BaseBlock = worldEditBlockState; - this.world = world; - this.location = location; - this.type = type; - } + @Override public void doUpdate() { Block block = world.getBlockAt(location.getX(), location.getY(), location.getZ()); block.setType(type); Material weType; - if (Settings.IsLegacy) { LegacyUtils.setData(block, data); assert worldEditBaseBlock != null; weType = LegacyUtils.getMaterial(worldEditBaseBlock.getType()); - } else { - assert worldEdit7BaseBlock != null; - BlockData bData = BukkitAdapter.adapt(worldEdit7BaseBlock); - block.setBlockData(bData); - weType = BukkitAdapter.adapt(worldEdit7BaseBlock.getBlockType()); - } if (type == Material.DISPENSER){ - Tag t = Settings.IsLegacy ? worldEditBaseBlock.getNbtData().getValue().get("Items") : worldEdit7BaseBlock.getNbtData().getValue().get("Items"); + Tag t = worldEditBaseBlock.getNbtData().getValue().get("Items"); ListTag lt = null; if (t instanceof ListTag) { lt = (ListTag) t; @@ -115,7 +99,7 @@ public void doUpdate() { BlockState state = block.getState(); if (state instanceof Sign) { Sign s = (Sign) state; - CompoundTag nbtData = Settings.IsLegacy ? worldEditBaseBlock.getNbtData() : worldEdit7BaseBlock.getNbtData(); + CompoundTag nbtData = worldEditBaseBlock.getNbtData(); //first line String firstLine = nbtData.getString("Text1"); firstLine = firstLine.substring(2); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/repair/RepairManager.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/repair/RepairManager.java index b25724ccc..51af511de 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/repair/RepairManager.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/repair/RepairManager.java @@ -1,5 +1,6 @@ package net.countercraft.movecraft.repair; +import net.countercraft.movecraft.Movecraft; import org.bukkit.Bukkit; import org.bukkit.plugin.Plugin; import org.bukkit.scheduler.BukkitRunnable; @@ -10,21 +11,17 @@ public class RepairManager extends BukkitRunnable { private List repairs = new CopyOnWriteArrayList<>(); - private Plugin movecraft; - public RepairManager(Plugin movecraft){ - this.movecraft = movecraft; + public RepairManager(){ + } @Override public void run() { for (Repair repair : repairs){ if (repair.getRunning().get()) { - new RepairTask(repair).runTask(movecraft); + new RepairTask(repair).runTask(Movecraft.getInstance()); } - - } - //Bukkit.getLogger().info("running"); } public List getRepairs() { diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/AntiAircraftDirectorSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/AntiAircraftDirectorSign.java index dd7c0ae36..22ceae916 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/AntiAircraftDirectorSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/AntiAircraftDirectorSign.java @@ -24,7 +24,7 @@ public final void onSignClick(PlayerInteractEvent event) { return; } Block block = event.getClickedBlock(); - if (block.getType() != (Settings.IsLegacy ? LegacyUtils.SIGN_POST : Material.SIGN) && block.getType() != Material.WALL_SIGN){ + if (!(block.getState() instanceof Sign)){ return; } Sign sign = (Sign) event.getClickedBlock().getState(); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/AscendSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/AscendSign.java index 749bede7e..b34480478 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/AscendSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/AscendSign.java @@ -23,7 +23,7 @@ public void onCraftDetect(CraftDetectEvent event){ World world = event.getCraft().getW(); for(MovecraftLocation location: event.getCraft().getHitBox()){ Block block = location.toBukkit(world).getBlock(); - if(block.getType() == Material.WALL_SIGN || block.getType() == (Settings.IsLegacy ? LegacyUtils.SIGN_POST : Material.SIGN)){ + if(block.getState() instanceof Sign){ Sign sign = (Sign) block.getState(); if (ChatColor.stripColor(sign.getLine(0)).equalsIgnoreCase("Ascend: ON")) { sign.setLine(0, "Ascend: OFF"); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CannonDirectorSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CannonDirectorSign.java index 0a3857e7f..e6ac33251 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CannonDirectorSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CannonDirectorSign.java @@ -24,7 +24,7 @@ public final void onSignClick(PlayerInteractEvent event) { return; } Block block = event.getClickedBlock(); - if (block.getType() != (Settings.IsLegacy ? LegacyUtils.SIGN_POST : Material.SIGN) && block.getType() != Material.WALL_SIGN) { + if (!(block.getState() instanceof Sign)) { return; } Sign sign = (Sign) event.getClickedBlock().getState(); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/ContactsSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/ContactsSign.java index 2c5f22c90..bea89f9e1 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/ContactsSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/ContactsSign.java @@ -22,7 +22,7 @@ public void onCraftDetect(CraftDetectEvent event){ World world = event.getCraft().getW(); for(MovecraftLocation location: event.getCraft().getHitBox()){ Block block = location.toBukkit(world).getBlock(); - if(block.getType() == Material.WALL_SIGN || block.getType() == (Settings.IsLegacy ? LegacyUtils.SIGN_POST : Material.SIGN)){ + if(block.getState() instanceof Sign){ Sign sign = (Sign) block.getState(); if (ChatColor.stripColor(sign.getLine(0)).equalsIgnoreCase("Contacts:")) { sign.setLine(1, ""); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CraftSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CraftSign.java index 6cbe5ab8e..89e219c29 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CraftSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CraftSign.java @@ -44,7 +44,7 @@ public final void onSignClick(PlayerInteractEvent event) { return; } Block block = event.getClickedBlock(); - if (block.getType() != (Settings.IsLegacy ? LegacyUtils.SIGN_POST : Material.SIGN) && block.getType() != Material.WALL_SIGN) { + if (!(block.getState() instanceof Sign)) { return; } Sign sign = (Sign) event.getClickedBlock().getState(); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CrewSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CrewSign.java index 66cffc865..a68c9f23d 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CrewSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CrewSign.java @@ -49,7 +49,7 @@ public final void onSignTranslate(SignTranslateEvent event) { return; } Location location = event.getBlock().getLocation().subtract(0,1,0); - if (Settings.IsLegacy ? !craft.getW().getBlockAt(location).getType().equals(LegacyUtils.BED_BLOCK) : Arrays.binarySearch(beds, craft.getW().getBlockAt(location).getType()) < 0) { + if (Settings.IsLegacy ? !craft.getW().getBlockAt(location).getType().equals(LegacyUtils.BED_BLOCK) : Arrays.binarySearch(beds, craft.getW().getBlockAt(location).getType()) >= 0) { return; } craft.getCrewSigns().put(crewPlayer.getUniqueId(), location); @@ -109,7 +109,7 @@ public void onCraftDetect(CraftDetectEvent event){ World world = event.getCraft().getW(); for(MovecraftLocation location: event.getCraft().getHitBox()){ Block block = location.toBukkit(world).getBlock(); - if (block.getType() != Material.WALL_SIGN && block.getType() != (Settings.IsLegacy ? LegacyUtils.SIGN_POST : Material.SIGN)) { + if (!(block.getState() instanceof Sign)) { continue; } Sign sign = (Sign) block.getState(); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CruiseSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CruiseSign.java index 73c539dc8..140bfdd9f 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CruiseSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CruiseSign.java @@ -27,7 +27,7 @@ public void onCraftDetect(CraftDetectEvent event){ World world = event.getCraft().getW(); for(MovecraftLocation location: event.getCraft().getHitBox()){ Block block = location.toBukkit(world).getBlock(); - if(block.getType() == Material.WALL_SIGN || block.getType() == (Settings.IsLegacy ? LegacyUtils.SIGN_POST : Material.SIGN)){ + if(block.getState() instanceof Sign){ Sign sign = (Sign) block.getState(); if (ChatColor.stripColor(sign.getLine(0)).equalsIgnoreCase("Cruise: ON")) { sign.setLine(0, "Cruise: OFF"); @@ -43,7 +43,7 @@ public final void onSignClick(PlayerInteractEvent event) { return; } Block block = event.getClickedBlock(); - if (block.getType() != (Settings.IsLegacy ? LegacyUtils.SIGN_POST : Material.SIGN) && block.getType() != Material.WALL_SIGN) { + if (!(block.getState() instanceof Sign)) { return; } Sign sign = (Sign) event.getClickedBlock().getState(); @@ -56,6 +56,7 @@ public final void onSignClick(PlayerInteractEvent event) { return; } //c.resetSigns(false, true, true); + sign.setLine(0, "Cruise: ON"); sign.update(true); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/DescendSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/DescendSign.java index e4ae30a80..8da3fdde0 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/DescendSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/DescendSign.java @@ -23,7 +23,7 @@ public void onCraftDetect(CraftDetectEvent event){ World world = event.getCraft().getW(); for(MovecraftLocation location: event.getCraft().getHitBox()){ Block block = location.toBukkit(world).getBlock(); - if(block.getType() == Material.WALL_SIGN || block.getType() == (Settings.IsLegacy ? LegacyUtils.SIGN_POST : Material.SIGN)){ + if(block.getState() instanceof Sign){ Sign sign = (Sign) block.getState(); if (ChatColor.stripColor(sign.getLine(0)).equalsIgnoreCase("Descend: ON")) { sign.setLine(0, "Descend: OFF"); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/HelmSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/HelmSign.java index 0913ba4e7..b328d49c8 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/HelmSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/HelmSign.java @@ -40,7 +40,7 @@ public final void onSignClick(PlayerInteractEvent event) { return; } Block block = event.getClickedBlock(); - if (block.getType() != (Settings.IsLegacy ? LegacyUtils.SIGN_POST : Material.SIGN) && block.getType() != Material.WALL_SIGN) { + if (!(block.getState() instanceof Sign)) { return; } Sign sign = (Sign) event.getClickedBlock().getState(); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/MoveSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/MoveSign.java index 971ee57b8..9592b71ae 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/MoveSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/MoveSign.java @@ -22,7 +22,7 @@ public final void onSignClick(PlayerInteractEvent event) { return; } Block block = event.getClickedBlock(); - if (block.getType() != (Settings.IsLegacy ? LegacyUtils.SIGN_POST : Material.SIGN) && block.getType() != Material.WALL_SIGN) { + if (!(block.getState() instanceof Sign)) { return; } Sign sign = (Sign) event.getClickedBlock().getState(); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/NameSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/NameSign.java index d34fcdf4e..6853a7b02 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/NameSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/NameSign.java @@ -23,7 +23,7 @@ public void onCraftDetect(@NotNull CraftDetectEvent event){ World w = c.getW(); for (MovecraftLocation location : event.getCraft().getHitBox()){ Block b = location.toBukkit(w).getBlock(); - if (b.getType() == (Settings.IsLegacy ? LegacyUtils.SIGN_POST : Material.SIGN) || b.getType() == Material.WALL_SIGN){ + if (b.getState() instanceof Sign){ Sign s = (Sign) b.getState(); String name = ""; if (s.getLine(0).equalsIgnoreCase(HEADER)){ diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RegionDamagedSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RegionDamagedSign.java index 93b14bbde..094c965b0 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RegionDamagedSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RegionDamagedSign.java @@ -13,6 +13,7 @@ import net.countercraft.movecraft.config.Settings; import net.countercraft.movecraft.localisation.I18nSupport; import net.countercraft.movecraft.mapUpdater.MapUpdateManager; +import net.countercraft.movecraft.mapUpdater.update.WorldEdit7UpdateCommand; import net.countercraft.movecraft.mapUpdater.update.WorldEditUpdateCommand; import net.countercraft.movecraft.repair.RepairUtils; import net.countercraft.movecraft.utils.WorldguardUtils; @@ -36,7 +37,7 @@ public void onSignRigtClick(PlayerInteractEvent event){ if (event.getAction() != Action.RIGHT_CLICK_BLOCK){ return; } - if (!event.getClickedBlock().getType().equals(Material.WALL_SIGN)){ + if (!event.getClickedBlock().getType().name().endsWith("WALL_SIGN")){ return; } Sign sign = (Sign) event.getClickedBlock().getState(); @@ -114,7 +115,7 @@ public static boolean repairRegion(String regionName, World world){ if (!Settings.AssaultDestroyableBlocks.contains(bukkitLoc.getBlock().getType())) continue; Material type = BukkitAdapter.adapt(block.getBlockType()); - WorldEditUpdateCommand weUp = new WorldEditUpdateCommand(block, world, location, type); + WorldEdit7UpdateCommand weUp = new WorldEdit7UpdateCommand(block, world, location, type); MapUpdateManager.getInstance().scheduleUpdate(weUp); } } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RelativeMoveSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RelativeMoveSign.java index 33dca6688..838fde10e 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RelativeMoveSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RelativeMoveSign.java @@ -22,7 +22,7 @@ public final void onSignClick(PlayerInteractEvent event) { return; } Block block = event.getClickedBlock(); - if (block.getType() != (Settings.IsLegacy ? LegacyUtils.SIGN_POST : Material.SIGN) && block.getType() != Material.WALL_SIGN) { + if (!(block.getState() instanceof Sign)) { return; } Sign sign = (Sign) event.getClickedBlock().getState(); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/ReleaseSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/ReleaseSign.java index a30fe54a1..a89627b1f 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/ReleaseSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/ReleaseSign.java @@ -22,7 +22,7 @@ public final void onSignClick(PlayerInteractEvent event) { return; } Block block = event.getClickedBlock(); - if (block.getType() != (Settings.IsLegacy ? LegacyUtils.SIGN_POST : Material.SIGN) && block.getType() != Material.WALL_SIGN) { + if (!(block.getState() instanceof Sign)) { return; } Sign sign = (Sign) event.getClickedBlock().getState(); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RemoteSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RemoteSign.java index 25fb3c13c..2a2910b1c 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RemoteSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RemoteSign.java @@ -52,7 +52,7 @@ public final void onSignClick(PlayerInteractEvent event) { return; } Block block = event.getClickedBlock(); - if (block.getType() != (Settings.IsLegacy ? LegacyUtils.SIGN_POST : Material.SIGN) && block.getType() != Material.WALL_SIGN) { + if (!(block.getState() instanceof Sign)) { return; } Sign sign = (Sign) event.getClickedBlock().getState(); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RepairSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RepairSign.java index 72f10fd8d..6c810fbb8 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RepairSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RepairSign.java @@ -11,6 +11,7 @@ import net.countercraft.movecraft.craft.CraftManager; import net.countercraft.movecraft.localisation.I18nSupport; import net.countercraft.movecraft.mapUpdater.update.UpdateCommand; +import net.countercraft.movecraft.mapUpdater.update.WorldEdit7UpdateCommand; import net.countercraft.movecraft.mapUpdater.update.WorldEditUpdateCommand; import net.countercraft.movecraft.repair.Repair; import net.countercraft.movecraft.repair.RepairManager; @@ -22,6 +23,7 @@ import org.bukkit.Material; import org.bukkit.World; import org.bukkit.block.Block; +import org.bukkit.block.BlockState; import org.bukkit.block.Sign; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; @@ -84,8 +86,8 @@ public void onSignChange(SignChangeEvent event){ public void onSignClick(PlayerInteractEvent event){ String firstLine = ""; if (event.getAction() == Action.RIGHT_CLICK_BLOCK || event.getAction() == Action.LEFT_CLICK_BLOCK) { - Material m = event.getClickedBlock().getType(); - if (m.equals((Settings.IsLegacy ? LegacyUtils.SIGN_POST : Material.SIGN)) || m.equals(Material.WALL_SIGN)) { + BlockState state = event.getClickedBlock().getState(); + if (state instanceof Sign) { Sign sign = (Sign) event.getClickedBlock().getState(); String signText = ChatColor.stripColor(sign.getLine(0)); @@ -95,19 +97,16 @@ public void onSignClick(PlayerInteractEvent event){ } } if (event.getAction() == Action.RIGHT_CLICK_BLOCK) { - Material m = event.getClickedBlock().getType(); - if (m.equals((Settings.IsLegacy ? LegacyUtils.SIGN_POST : Material.SIGN)) || m.equals(Material.WALL_SIGN)) { - - signRightClick(event); + BlockState state = event.getClickedBlock().getState(); + if (state instanceof Sign) { + signRightClick(event); } return; } if (event.getAction() == Action.LEFT_CLICK_BLOCK) { - Material m = event.getClickedBlock().getType(); - if (m == (Settings.IsLegacy ? LegacyUtils.SIGN_POST : Material.SIGN) || m == Material.WALL_SIGN) { - - signLeftClick(event); - + BlockState state = event.getClickedBlock().getState(); + if (state instanceof Sign) { + signLeftClick(event); } } } @@ -130,6 +129,24 @@ private void signLeftClick(PlayerInteractEvent event){ event.getPlayer().sendMessage(I18nSupport.getInternationalisedString("You must be piloting a craft")); return; } + Set foundSimilarSigns = new HashSet<>(); + for (MovecraftLocation moveLoc : pCraft.getHitBox()){ + Block cBlock = moveLoc.toBukkit(sign.getWorld()).getBlock(); + if (!(cBlock.getState() instanceof Sign)) + continue; + Sign foundSign = (Sign) cBlock.getState(); + if (foundSign.getLocation().equals(sign.getLocation())) + continue; + if (!foundSign.getLine(0).equalsIgnoreCase(HEADER) && !foundSign.getLine(1).equals(sign.getLine(1))) + continue; + foundSimilarSigns.add(foundSign); + } + if (foundSimilarSigns.size() > 0){ + event.getPlayer().sendMessage("Warning: Similar repair signs found at these locations:"); + for (Sign s : foundSimilarSigns) + event.getPlayer().sendMessage("- (" + s.getX() + ", " + s.getY() + ", " + s.getX() + ")"); + return; + } MovecraftRepair movecraftRepair = Movecraft.getInstance().getMovecraftRepair(); if (movecraftRepair.saveCraftRepairState(pCraft, sign, Movecraft.getInstance(), repairName)) event.getPlayer().sendMessage(I18nSupport.getInternationalisedString("State saved")); @@ -154,6 +171,27 @@ private void signRightClick(PlayerInteractEvent event){ event.getPlayer().sendMessage(I18nSupport.getInternationalisedString("Repair functionality is disabled or WorldEdit was not detected")); return; } + //Check for other similar repair signs on the craft + Set foundSimilarSigns = new HashSet<>(); + for (MovecraftLocation moveLoc : pCraft.getHitBox()){ + Block cBlock = moveLoc.toBukkit(sign.getWorld()).getBlock(); + if (!(cBlock.getState() instanceof Sign)) + continue; + Sign foundSign = (Sign) cBlock.getState(); + //Do not include clicked repair sign + if (foundSign.getLocation().equals(sign.getLocation())) + continue; + if (!foundSign.getLine(0).equalsIgnoreCase(HEADER) && !foundSign.getLine(1).equals(sign.getLine(1))) + continue; + foundSimilarSigns.add(foundSign); + } + //Warn the player if multiple similar repair signs are found + if (foundSimilarSigns.size() > 0){ + event.getPlayer().sendMessage("Warning: Similar repair signs found at these locations:"); + for (Sign s : foundSimilarSigns) + event.getPlayer().sendMessage("- (" + s.getX() + ", " + s.getY() + ", " + s.getX() + ")"); + return; + } String repairName = event.getPlayer().getName(); repairName += "_"; repairName += sign.getLine(1); @@ -163,7 +201,6 @@ private void signRightClick(PlayerInteractEvent event){ if (clipboard == null){ p.sendMessage(I18nSupport.getInternationalisedString("REPAIR STATE NOT FOUND")); - return; } else { //if clipboard is not null long numDifferentBlocks = movecraftRepair.getNumDiffBlocks(repairName); boolean secondClick = false; @@ -259,11 +296,11 @@ private void signRightClick(PlayerInteractEvent event){ } else { com.sk89q.worldedit.world.block.BaseBlock bb = clipboard.getFullBlock(WorldEditUtils.toBlockVector(cLoc)); Material type = BukkitAdapter.adapt(bb.getBlockType()); - if (Arrays.binarySearch(wallBlocks, type) >= 0){ - WorldEditUpdateCommand weUp = new WorldEditUpdateCommand(bb,sign.getWorld(),moveLoc, type); + if (type.name().contains("WALL")){ + WorldEdit7UpdateCommand weUp = new WorldEdit7UpdateCommand(bb,sign.getWorld(),moveLoc, type); updateCommandsFragileBlocks.add(weUp); } else { - WorldEditUpdateCommand weUp = new WorldEditUpdateCommand(bb,sign.getWorld(),moveLoc, type); + WorldEdit7UpdateCommand weUp = new WorldEdit7UpdateCommand(bb,sign.getWorld(),moveLoc, type); updateCommands.add(weUp); } } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/SpeedSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/SpeedSign.java index 3d5f16361..e0331c97a 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/SpeedSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/SpeedSign.java @@ -20,7 +20,7 @@ public void onCraftDetect(CraftDetectEvent event){ World world = event.getCraft().getW(); for(MovecraftLocation location: event.getCraft().getHitBox()){ Block block = location.toBukkit(world).getBlock(); - if(block.getType() == Material.WALL_SIGN || block.getType() == (Settings.IsLegacy ? LegacyUtils.SIGN_POST : Material.SIGN)){ + if(block.getState() instanceof Sign) { Sign sign = (Sign) block.getState(); if (ChatColor.stripColor(sign.getLine(0)).equalsIgnoreCase("Speed:")) { sign.setLine(1, "0 m/s"); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/StatusSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/StatusSign.java index a9e418fc3..e3bf5370d 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/StatusSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/StatusSign.java @@ -27,7 +27,7 @@ public void onCraftDetect(CraftDetectEvent event){ World world = event.getCraft().getW(); for(MovecraftLocation location: event.getCraft().getHitBox()){ Block block = location.toBukkit(world).getBlock(); - if(block.getType() == Material.WALL_SIGN || block.getType() == (Settings.IsLegacy ? LegacyUtils.SIGN_POST : Material.SIGN)){ + if(block.getState() instanceof Sign){ Sign sign = (Sign) block.getState(); if (ChatColor.stripColor(sign.getLine(0)).equalsIgnoreCase("Status:")) { sign.setLine(1, ""); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/SubcraftRotateSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/SubcraftRotateSign.java index 5a60e9a58..83b7ef63d 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/SubcraftRotateSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/SubcraftRotateSign.java @@ -38,7 +38,7 @@ public final void onSignClick(PlayerInteractEvent event) { return; } Block block = event.getClickedBlock(); - if (block.getType() != (Settings.IsLegacy ? LegacyUtils.SIGN_POST : Material.SIGN) && block.getType() != Material.WALL_SIGN) { + if (!(block.getState() instanceof Sign)) { return; } Sign sign = (Sign) event.getClickedBlock().getState(); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/TeleportSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/TeleportSign.java index e725f6529..2161f2bed 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/TeleportSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/TeleportSign.java @@ -21,7 +21,7 @@ public final void onSignClick(PlayerInteractEvent event) { return; } Block block = event.getClickedBlock(); - if (block.getType() != (Settings.IsLegacy ? LegacyUtils.SIGN_POST : Material.SIGN) && block.getType() != Material.WALL_SIGN) { + if (!(block.getState() instanceof Sign)) { return; } Sign sign = (Sign) event.getClickedBlock().getState(); diff --git a/modules/Movecraft/src/main/resources/localisation/movecraftlang_en.properties b/modules/Movecraft/src/main/resources/localisation/movecraftlang_en.properties index 795eaec08..0dd9abc7f 100644 --- a/modules/Movecraft/src/main/resources/localisation/movecraftlang_en.properties +++ b/modules/Movecraft/src/main/resources/localisation/movecraftlang_en.properties @@ -46,6 +46,7 @@ MCStats\ -\ \:(\ -\ Admin\ has\ opted\ out=You have selected to opt out of mcsta MCStats\ -\ Thank\ you\ message=Submitted statistics to mcstats.org succesfully. Thank you for your support. MCStats\ -\ Error\ -\ Unable\ to\ upload\ stats=Unable to upload statistics to mcstats.org. Please check your network connection. Release\ -\ Player\ has\ left\ craft=You have left your craft\! You have 15 seconds to return to it or it will be automatically released. +Release\ -\ Blocks\ may\ merge=WARNING\! There are blocks near your craft that may merge with the craft\! Release\ -\ Craft\ has\ been\ released\ message=You have released your craft. Release\ -\ Player\ has\ released\ a\ craft\ console=Player %s has released a craft of type %s with size %d at coordinates \: %d x , %d z Detection\ -\ Success\ -\ Log\ Output=Player %s piloted a craft of type %s with size %d at location\: %d x, %d z diff --git a/modules/api/src/main/java/net/countercraft/movecraft/config/Settings.java b/modules/api/src/main/java/net/countercraft/movecraft/config/Settings.java index 95f305e12..128822ecc 100644 --- a/modules/api/src/main/java/net/countercraft/movecraft/config/Settings.java +++ b/modules/api/src/main/java/net/countercraft/movecraft/config/Settings.java @@ -71,6 +71,7 @@ public class Settings { public static Map DurabilityOverride; public static boolean IsPaper = false; public static boolean IsLegacy = true; //false if version is 1.13 or higher + public static boolean is1_14 = false; public static boolean UseFAWE = false; public static boolean AssaultEnable; diff --git a/modules/worldedit/FAWEUtils/pom.xml b/modules/worldedit/FAWEUtils/pom.xml deleted file mode 100644 index 426d11821..000000000 --- a/modules/worldedit/FAWEUtils/pom.xml +++ /dev/null @@ -1,71 +0,0 @@ - - - - movecraft-parent - net.countercraft - parent - ../../../pom.xml - - 4.0.0 - movecraft-FAWEUtils - jar - Movecraft-FAWEUtils - FAWEUtils - http://github.com/eirikh1996/Movecraft - - - - - fawe-repo - http://ci.athion.net/job/FastAsyncWorldEdit/ws/mvn/ - - - - - com.boydti - fawe-api - latest - - - net.countercraft - movecraft-api - API - jar - - - org.jetbrains - annotations-java5 - RELEASE - - - - src/main/java - - - org.apache.maven.plugins - maven-compiler-plugin - 3.7.0 - - - net/countercraft/movecraft/compat/fawe/** - - 1.8 - 1.8 - - - - org.apache.maven.plugins - maven-jar-plugin - 2.4 - - - net/countercraft/movecraft/compat/fawe/** - - - - - - - \ No newline at end of file diff --git a/modules/worldedit/FAWEUtils/src/main/java/net/countercraft/movecraft/compat/fawe/IMovecraftRepair.java b/modules/worldedit/FAWEUtils/src/main/java/net/countercraft/movecraft/compat/fawe/IMovecraftRepair.java deleted file mode 100644 index 58a641664..000000000 --- a/modules/worldedit/FAWEUtils/src/main/java/net/countercraft/movecraft/compat/fawe/IMovecraftRepair.java +++ /dev/null @@ -1,123 +0,0 @@ -package net.countercraft.movecraft.compat.fawe; - -import com.sk89q.worldedit.Vector; -import com.sk89q.worldedit.WorldEdit; -import com.sk89q.worldedit.WorldEditException; -import com.sk89q.worldedit.bukkit.BukkitWorld; -import com.sk89q.worldedit.extent.Extent; -import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard; -import com.sk89q.worldedit.extent.clipboard.Clipboard; -import com.sk89q.worldedit.extent.clipboard.io.ClipboardFormat; -import com.sk89q.worldedit.extent.clipboard.io.ClipboardWriter; -import com.sk89q.worldedit.function.mask.ExistingBlockMask; -import com.sk89q.worldedit.function.operation.ForwardExtentCopy; -import com.sk89q.worldedit.function.operation.Operations; -import com.sk89q.worldedit.regions.CuboidRegion; -import com.sk89q.worldedit.world.registry.WorldData; -import com.sk89q.worldguard.protection.regions.ProtectedRegion; -import net.countercraft.movecraft.MovecraftRepair; -import net.countercraft.movecraft.craft.Craft; -import net.countercraft.movecraft.utils.HashHitBox; -import org.bukkit.Material; -import org.bukkit.World; -import org.bukkit.block.Sign; -import org.bukkit.plugin.Plugin; - -import java.io.File; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.OutputStream; -import java.util.HashMap; -import java.util.LinkedList; - -public class IMovecraftRepair extends MovecraftRepair { - - @Override - public boolean saveCraftRepairState(Craft craft, Sign sign, Plugin plugin, String s) { - HashHitBox hitBox = craft.getHitBox(); - File saveDirectory = new File(plugin.getDataFolder(), "CraftRepairStates"); - World world = craft.getW(); - if (!saveDirectory.exists()) { - saveDirectory.mkdirs(); - } - Vector minPos = new Vector(hitBox.getMinX(), hitBox.getMinY(), hitBox.getMinZ()); - Vector maxPos = new Vector(hitBox.getMaxX(), hitBox.getMaxY(), hitBox.getMaxZ()); - CuboidRegion region = new CuboidRegion(minPos, maxPos); - com.sk89q.worldedit.world.World weWorld = new BukkitWorld(world); - BlockArrayClipboard clipboard = new BlockArrayClipboard(region); - Extent source = WorldEdit.getInstance().getEditSessionFactory().getEditSession(weWorld, -1); - Extent destination = clipboard; - ForwardExtentCopy copy = new ForwardExtentCopy(source, region, clipboard.getOrigin(), destination, minPos); - ExistingBlockMask mask = new ExistingBlockMask(source); - copy.setSourceMask(mask); - WorldData data = weWorld.getWorldData(); - try { - Operations.complete(copy); - } catch (WorldEditException e) { - e.printStackTrace(); - return false; - } - File schematicFile = new File(saveDirectory, s + ".schematic"); - try { - OutputStream output = new FileOutputStream(schematicFile); - ClipboardWriter writer = ClipboardFormat.SCHEMATIC.getWriter(output); - writer.write(clipboard, data); - writer.close(); - } catch (IOException e) { - e.printStackTrace(); - return false; - } - - return true; - } - - @Override - public boolean saveRegionRepairState(Plugin plugin, World world, ProtectedRegion region) { - return false; - } - - @Override - public boolean repairRegion(World world, String regionName) { - return false; - } - - @Override - public Clipboard loadCraftRepairStateClipboard(Plugin plugin, Sign sign, String repairStateName, World bukkitWorld) { - return null; - } - - @Override - public Clipboard loadRegionRepairStateClipboard(Plugin plugin, String repairStateName, World bukkitWorld) { - return null; - } - - @Override - public HashMap getMissingBlocks(String repairName) { - return null; - } - - @Override - public LinkedList getMissingBlockLocations(String repairName) { - return null; - } - - @Override - public long getNumDiffBlocks(String repairName) { - return 0; - } - - @Override - public org.bukkit.util.Vector getDistanceFromSignToLowestPoint(Clipboard clipboard, String repairName) { - return null; - } - - @Override - public org.bukkit.util.Vector getDistanceFromClipboardToWorldOffset(org.bukkit.util.Vector offset, Clipboard clipboard) { - return null; - } - - @Override - public void setFawePlugin(Plugin fawePlugin) { - - } -} diff --git a/modules/worldedit/WE7Utils/src/main/java/net/countercraft/movecraft/compat/we7/IMovecraftRepair.java b/modules/worldedit/WE7Utils/src/main/java/net/countercraft/movecraft/compat/we7/IMovecraftRepair.java index a3cdd9e9a..e802e0f89 100644 --- a/modules/worldedit/WE7Utils/src/main/java/net/countercraft/movecraft/compat/we7/IMovecraftRepair.java +++ b/modules/worldedit/WE7Utils/src/main/java/net/countercraft/movecraft/compat/we7/IMovecraftRepair.java @@ -432,26 +432,29 @@ public Vector getDistanceFromSignToLowestPoint(Clipboard clipboard, String s) { for (int z = clipboard.getMinimumPoint().getBlockZ(); z <= clipboard.getMaximumPoint().getBlockZ(); z++) { BlockVector3 pos = BlockVector3.at(x,y,z); BaseBlock block = clipboard.getFullBlock(pos); - if (block.getBlockType().getId().equals("minecraft:sign")||block.getBlockType().getId().equals("minecraft:wall_sign")){ + if (block.getBlockType().getId().equals("minecraft:sign")||block.getBlockType().getId().equals("minecraft:wall_sign")) { Logger log = Bukkit.getLogger(); String firstLine = block.getNbtData().getString("Text1"); firstLine = firstLine.substring(2); - if (firstLine.startsWith("extra")){ + if (firstLine.startsWith("extra")) { firstLine = firstLine.substring(17); - firstLine = firstLine.replace("\"}],\"text\":\"\"}",""); + firstLine = firstLine.replace("\"}],\"text\":\"\"}", ""); } String secondLine = block.getNbtData().getString("Text2"); secondLine = secondLine.substring(2); - if (secondLine.startsWith("extra")){ + if (secondLine.startsWith("extra")) { secondLine = secondLine.substring(17); - secondLine = secondLine.replace("\"}],\"text\":\"\"}",""); + secondLine = secondLine.replace("\"}],\"text\":\"\"}", ""); + } + if (firstLine.equalsIgnoreCase("Repair:") && s.endsWith(secondLine)) { + returnDistance = new Vector(x - clipboard.getMinimumPoint().getBlockX(), y - clipboard.getMinimumPoint().getBlockY(), z - clipboard.getMinimumPoint().getBlockZ()); + break; } - if (firstLine.equalsIgnoreCase("Repair:") && s.endsWith(secondLine)) - returnDistance = new Vector(x - clipboard.getMinimumPoint().getBlockX(),y - clipboard.getMinimumPoint().getBlockY(),z - clipboard.getMinimumPoint().getBlockZ()); } - } + if (returnDistance != null) break; } + if (returnDistance != null) break; } return returnDistance; } diff --git a/pom.xml b/pom.xml index 5c630492d..743dd6bb3 100644 --- a/pom.xml +++ b/pom.xml @@ -24,7 +24,6 @@ modules/v1_11_R1 modules/v1_12_R1 modules/v1_13_R2 - modules/worldedit/FAWEUtils modules/worldedit/WE6Utils modules/worldedit/WE7Utils modules/Movecraft From 3b2054d2d284205aefced1824a6ff31630288f3d Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Wed, 24 Apr 2019 23:42:34 +0200 Subject: [PATCH 013/304] Fixed wreckage clearing bug and 1.14 update (WARNING: Bugs may currently break core functions in 1.14 due to unstable API) --- modules/Movecraft/pom.xml | 8 + .../movecraft/async/AsyncManager.java | 7 + .../async/detection/DetectionTask.java | 11 +- .../async/translation/TranslationTask.java | 71 ++- .../movecraft/commands/SiegeCommand.java | 49 +- .../movecraft/craft/CraftManager.java | 23 +- .../movecraft/listener/PlayerListener.java | 14 + .../update/CraftTranslateCommand.java | 9 +- .../update/WorldEdit7UpdateCommand.java | 2 + .../movecraft/sign/RemoteSign.java | 10 +- .../movecraft/sign/RepairSign.java | 61 +-- .../movecraft/warfare/siege/Siege.java | 24 +- .../movecraft/warfare/siege/SiegeManager.java | 2 + .../warfare/siege/SiegePreparationTask.java | 12 +- .../warfare/siege/SiegeProgressTask.java | 34 +- .../Movecraft/src/main/resources/plugin.yml | 2 +- .../resources/types/1_14/BigAirship.craft | 305 ++++++++++++ .../resources/types/1_14/BigSubAirship.craft | 306 ++++++++++++ .../resources/types/1_14/LaunchTorpedo.craft | 30 ++ .../src/main/resources/types/1_14/Ship.craft | 282 +++++++++++ .../resources/types/1_14/SubAirship.craft | 306 ++++++++++++ .../main/resources/types/1_14/Submarine.craft | 283 +++++++++++ .../main/resources/types/1_14/Turret.craft | 210 ++++++++ .../main/resources/types/1_14/airship.craft | 302 ++++++++++++ .../main/resources/types/1_14/airskiff.craft | 260 ++++++++++ .../main/resources/types/1_14/elevator.craft | 223 +++++++++ .../src/main/resources/types/BigAirship.craft | 460 ++++++++--------- .../main/resources/types/BigSubAirship.craft | 461 +++++++++--------- .../src/main/resources/types/Ship.craft | 461 +++++++++--------- .../src/main/resources/types/SubAirship.craft | 461 +++++++++--------- .../src/main/resources/types/Submarine.craft | 52 +- .../src/main/resources/types/airship.craft | 461 +++++++++--------- .../movecraft/MovecraftRepair.java | 11 +- .../movecraft/RepairLocation.java | 20 - .../movecraft/config/Settings.java | 1 + .../countercraft/movecraft/craft/Craft.java | 14 +- .../compat/v1_12_R1/IWorldHandler.java | 5 + modules/v1_13_R2/pom.xml | 18 - modules/v1_14_R1/pom.xml | 69 +++ .../compat/v1_14_R1/IWorldHandler.java | 366 ++++++++++++++ .../compat/v1_14_R1/NextTickProvider.java | 60 +++ .../compat/we6/IMovecraftRepair.java | 47 +- .../compat/we7/IMovecraftRepair.java | 63 +-- pom.xml | 4 +- 44 files changed, 4568 insertions(+), 1312 deletions(-) create mode 100644 modules/Movecraft/src/main/resources/types/1_14/BigAirship.craft create mode 100644 modules/Movecraft/src/main/resources/types/1_14/BigSubAirship.craft create mode 100644 modules/Movecraft/src/main/resources/types/1_14/LaunchTorpedo.craft create mode 100644 modules/Movecraft/src/main/resources/types/1_14/Ship.craft create mode 100644 modules/Movecraft/src/main/resources/types/1_14/SubAirship.craft create mode 100644 modules/Movecraft/src/main/resources/types/1_14/Submarine.craft create mode 100644 modules/Movecraft/src/main/resources/types/1_14/Turret.craft create mode 100644 modules/Movecraft/src/main/resources/types/1_14/airship.craft create mode 100644 modules/Movecraft/src/main/resources/types/1_14/airskiff.craft create mode 100644 modules/Movecraft/src/main/resources/types/1_14/elevator.craft delete mode 100644 modules/api/src/main/java/net/countercraft/movecraft/RepairLocation.java create mode 100644 modules/v1_14_R1/pom.xml create mode 100644 modules/v1_14_R1/src/main/java/net/countercraft/movecraft/compat/v1_14_R1/IWorldHandler.java create mode 100644 modules/v1_14_R1/src/main/java/net/countercraft/movecraft/compat/v1_14_R1/NextTickProvider.java diff --git a/modules/Movecraft/pom.xml b/modules/Movecraft/pom.xml index 69c052077..1f9a93593 100644 --- a/modules/Movecraft/pom.xml +++ b/modules/Movecraft/pom.xml @@ -40,6 +40,12 @@ worldedit-bukkit 7.0.0-SNAPSHOT + + net.countercraft + movecraft-v1_14_R1 + v1_14_R1 + jar + net.countercraft movecraft-v1_13_R2 @@ -216,6 +222,8 @@ config.yml config_legacy.yml localisation/** + types/1_14/*.craft + types/legacy/*.craft types/*.craft diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java index e9caa13ff..d0a49c617 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java @@ -746,6 +746,10 @@ private void processFireballs() { } } + private void processWaterlogging(){ + + } + private Craft fastNearestCraftToLoc(Location loc) { Craft ret = null; long closestDistSquared = 1000000000L; @@ -1088,6 +1092,9 @@ public void run() { processTracers(); processFireballs(); processTNTContactExplosives(); + if (!Settings.IsLegacy) { + processWaterlogging(); + } //processFadingBlocks(); processDetection(); processAlgorithmQueue(); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/detection/DetectionTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/detection/DetectionTask.java index 297133647..60c0bdd24 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/detection/DetectionTask.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/detection/DetectionTask.java @@ -32,7 +32,6 @@ import org.bukkit.block.Block; import org.bukkit.block.BlockState; import org.bukkit.block.Sign; -import org.bukkit.block.data.type.Chest; import org.bukkit.entity.Player; import java.util.*; @@ -107,7 +106,6 @@ private void detectBlock(int x, int y, int z) { if (notVisited(workingLocation, visited)) { Material testType = null; - Block testBlock = null; int testData = 0; try { testData = data.getWorld().getBlockAt(x, y, z).getData(); @@ -120,8 +118,13 @@ private void detectBlock(int x, int y, int z) { if ((testType == Material.WATER) || (testType == LegacyUtils.STATIONARY_WATER)) { data.setWaterContact(true); } - if (testType == (Settings.IsLegacy ? LegacyUtils.SIGN_POST : Material.SIGN) || testType == Material.WALL_SIGN) { - BlockState state = data.getWorld().getBlockAt(x, y, z).getState(); + if (testType.name().contains("SIGN")) { + BlockState state; + try { + state = data.getWorld().getBlockAt(x, y, z).getState(); + } catch (Exception e){ + return; + } if (state instanceof Sign) { Sign s = (Sign) state; if (s.getLine(0).equalsIgnoreCase("Pilot:") && data.getPlayer() != null) { diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java index 353cf5114..389cf4102 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java @@ -1,5 +1,6 @@ package net.countercraft.movecraft.async.translation; +import net.countercraft.movecraft.Movecraft; import net.countercraft.movecraft.MovecraftLocation; import net.countercraft.movecraft.async.AsyncTask; import net.countercraft.movecraft.config.Settings; @@ -33,10 +34,22 @@ import java.util.concurrent.ThreadLocalRandom; public class TranslationTask extends AsyncTask { - private static final Material[] FALL_THROUGH_BLOCKS = Settings.IsLegacy ? new Material[]{Material.AIR, Material.WATER, LegacyUtils.STATIONARY_WATER, Material.LAVA, LegacyUtils.STATIONARY_LAVA, LegacyUtils.LONG_GRASS, LegacyUtils.YELLOW_FLOWER, LegacyUtils.RED_ROSE, - Material.BROWN_MUSHROOM, Material.RED_MUSHROOM, Material.TORCH, Material.FIRE, Material.REDSTONE_WIRE, LegacyUtils.CROPS, LegacyUtils.SIGN_POST, Material.LADDER, Material.WALL_SIGN, Material.LEVER, LegacyUtils.STONE_PLATE, LegacyUtils.REDSTONE_TORCH_ON, LegacyUtils.REDSTONE_TORCH_OFF, Material.STONE_BUTTON, - Material.SNOW, LegacyUtils.SUGAR_CANE_BLOCK, LegacyUtils.FENCE, LegacyUtils.DIODE_BLOCK_OFF, LegacyUtils.DIODE_BLOCK_ON, LegacyUtils.WATER_LILY, Material.CARROT, Material.POTATO, LegacyUtils.WOOD_BUTTON, LegacyUtils.CARPET} - : new Material[]{Material.AIR, Material.WATER}; + private static final Set FALL_THROUGH_BLOCKS = new HashSet<>();//Settings.IsLegacy ? new Material[]{}:new Material[]{Material.AIR, + /*Material.WATER, + Material.LAVA, + Material.BROWN_MUSHROOM, + Material.RED_MUSHROOM, + Material.TORCH, + Material.FIRE, + Material.REDSTONE_WIRE, + Material.LADDER, + Material.WALL_SIGN, + Material.LEVER, + Material.STONE_BUTTON, + Material.SNOW, + Material.CARROT, + Material.POTATO, + };*/ //private static final int[] FALL_THROUGH_BLOCKS = {0, 8, 9, 10, 11, 31, 37, 38, 39, 40, 50, 51, 55, 59, 63, 65, 68, 69, 70, 72, 75, 76, 77, 78, 83, 85, 93, 94, 111, 141, 142, 143, 171}; private int dx, dy, dz; @@ -53,6 +66,48 @@ public TranslationTask(Craft c, int dx, int dy, int dz) { this.dz = dz; newHitBox = new HashHitBox(); oldHitBox = new HashHitBox(c.getHitBox()); + + FALL_THROUGH_BLOCKS.add(Material.AIR); + FALL_THROUGH_BLOCKS.add(Material.WATER); + FALL_THROUGH_BLOCKS.add(Material.LAVA); + FALL_THROUGH_BLOCKS.add(Material.BROWN_MUSHROOM); + FALL_THROUGH_BLOCKS.add(Material.RED_MUSHROOM); + FALL_THROUGH_BLOCKS.add(Material.TORCH); + FALL_THROUGH_BLOCKS.add(Material.FIRE); + FALL_THROUGH_BLOCKS.add(Material.REDSTONE_WIRE); + FALL_THROUGH_BLOCKS.add(Material.LADDER); + FALL_THROUGH_BLOCKS.add(Material.WALL_SIGN); + FALL_THROUGH_BLOCKS.add(Material.LEVER); + FALL_THROUGH_BLOCKS.add(Material.STONE_BUTTON); + FALL_THROUGH_BLOCKS.add(Material.SNOW); + FALL_THROUGH_BLOCKS.add(Material.CARROT); + FALL_THROUGH_BLOCKS.add(Material.POTATO); + if (Settings.IsLegacy) { + FALL_THROUGH_BLOCKS.add(LegacyUtils.STATIONARY_WATER); + FALL_THROUGH_BLOCKS.add(LegacyUtils.STATIONARY_LAVA); + FALL_THROUGH_BLOCKS.add(LegacyUtils.LONG_GRASS); + FALL_THROUGH_BLOCKS.add(LegacyUtils.YELLOW_FLOWER); + FALL_THROUGH_BLOCKS.add(LegacyUtils.RED_ROSE); + FALL_THROUGH_BLOCKS.add(LegacyUtils.CROPS); + FALL_THROUGH_BLOCKS.add(LegacyUtils.SIGN_POST); + FALL_THROUGH_BLOCKS.add(LegacyUtils.STONE_PLATE); + FALL_THROUGH_BLOCKS.add(LegacyUtils.REDSTONE_TORCH_ON); + FALL_THROUGH_BLOCKS.add(LegacyUtils.REDSTONE_TORCH_OFF); + FALL_THROUGH_BLOCKS.add(LegacyUtils.SUGAR_CANE_BLOCK); + FALL_THROUGH_BLOCKS.add(LegacyUtils.FENCE); + FALL_THROUGH_BLOCKS.add(LegacyUtils.DIODE_BLOCK_OFF); + FALL_THROUGH_BLOCKS.add(LegacyUtils.DIODE_BLOCK_ON); + FALL_THROUGH_BLOCKS.add(LegacyUtils.WATER_LILY); + FALL_THROUGH_BLOCKS.add(LegacyUtils.WOOD_BUTTON); + FALL_THROUGH_BLOCKS.add(LegacyUtils.CARPET); + } else { + FALL_THROUGH_BLOCKS.add(Material.BUBBLE_COLUMN); + FALL_THROUGH_BLOCKS.add(Material.KELP); + FALL_THROUGH_BLOCKS.add(Material.KELP_PLANT); + FALL_THROUGH_BLOCKS.add(Material.SEAGRASS); + FALL_THROUGH_BLOCKS.add(Material.TALL_SEAGRASS); + + } } @Override @@ -124,7 +179,7 @@ protected void execute() { boolean blockObstructed; if (craft.getSinking()) { - blockObstructed = !(Arrays.binarySearch(FALL_THROUGH_BLOCKS, testMaterial) >= 0); + blockObstructed = !FALL_THROUGH_BLOCKS.contains(testMaterial); } else { if (Settings.IsLegacy) { blockObstructed = !craft.getType().getPassthroughBlocks().contains(testMaterial) && !testMaterial.equals(Material.AIR); @@ -186,10 +241,11 @@ protected void execute() { toRemove.add(next); next = next.add(new MovecraftLocation(0,1,0)); }while (newHitBox.contains(next)); - + craft.getCollapsedHitBox().addAll(toRemove); newHitBox.removeAll(toRemove); - } + } + Bukkit.getLogger().info("Collapsed hitbox: "+craft.getCollapsedHitBox().size() + ", New hitbox: " + newHitBox.size()); }else{ for(MovecraftLocation location : collisionBox){ if (!(craft.getType().getCollisionExplosion() != 0.0F) || System.currentTimeMillis() - craft.getOrigPilotTime() <= 1000) { @@ -393,6 +449,7 @@ private boolean checkFuel(){ if (b.getState() instanceof Furnace) { InventoryHolder inventoryHolder = (InventoryHolder) b.getState(); for (Material fuelType : Settings.FuelTypes.keySet()){ + Movecraft.getInstance().getLogger().info(b.getLocation().toString()); if (inventoryHolder.getInventory().contains(fuelType)){ fuelHolder = b; } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/SiegeCommand.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/SiegeCommand.java index 12d7a43d8..b0e7b59cf 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/SiegeCommand.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/SiegeCommand.java @@ -39,6 +39,7 @@ public class SiegeCommand implements TabExecutor { //TODO: Add tab complete private final NumberFormat currencyFormat = NumberFormat.getCurrencyInstance(); + private final Map playerTimeMap = new HashMap<>(); @Override public boolean onCommand(CommandSender commandSender, Command command, String s, String[] args) { if (!command.getName().equalsIgnoreCase("siege")) { @@ -64,6 +65,8 @@ public boolean onCommand(CommandSender commandSender, Command command, String s, return beginCommand(commandSender); }else if(args[0].equalsIgnoreCase("info")){ return infoCommand(commandSender,args); + } else if (args[0].equalsIgnoreCase("abort")){ + return abortCommand(commandSender); } commandSender.sendMessage(MOVECRAFT_COMMAND_PREFIX + "Invalid argument specified, valid arguments include begin, info, and list."); return true; @@ -188,11 +191,11 @@ private boolean beginCommand(CommandSender commandSender){ , player.getDisplayName(), siege.getName(), siege.getDelayBeforeStart() / 60)); for (Player p : Bukkit.getOnlinePlayers()) { p.playSound(p.getLocation(), Sound.ENTITY_WITHER_DEATH, 1, 0.25F); + p.setScoreboard(siege.getScoreboard()); } Movecraft.getInstance().getLogger().log(Level.INFO, String.format("Siege: %s commenced by %s for a cost of %d", siege.getName(), player.getName(), cost)); Movecraft.getInstance().getEconomy().withdrawPlayer(player, cost); - siege.setProgressBar(Bukkit.createBossBar(siege.getName(), BarColor.BLUE, BarStyle.SOLID, BarFlag.DARKEN_SKY)); - siege.getProgressBar().setVisible(true); + siege.setPlayerUUID(player.getUniqueId()); siege.setStartTime((int)System.currentTimeMillis()); siege.setStage(SiegeStage.PREPERATION); @@ -200,6 +203,48 @@ private boolean beginCommand(CommandSender commandSender){ } + private boolean abortCommand(CommandSender sender){ + if (!(sender instanceof Player)){ + sender.sendMessage(MOVECRAFT_COMMAND_PREFIX + "you need to be a player to abort a siege"); + } + List sieges = Movecraft.getInstance().getSiegeManager().getSieges(); + UUID playerID = ((Player)sender).getUniqueId(); + Siege activeSiege = null; + boolean siegeLeader = false; + for (Siege siege : sieges){ + if (siege.getStage().get() != SiegeStage.INACTIVE){ + activeSiege = siege; + break; + } + + } + if (activeSiege == null){ + sender.sendMessage(MOVECRAFT_COMMAND_PREFIX + "No sieges are running"); + return true; + } else if (!activeSiege.getPlayerUUID().equals(playerID)){ + sender.sendMessage(MOVECRAFT_COMMAND_PREFIX + "you need to be a siege leader to abort a siege"); + return true; + } + boolean confirm = playerTimeMap.containsKey(playerID) && playerTimeMap.get(playerID) - System.currentTimeMillis() <= 7000; + if (confirm){ + Bukkit.broadcastMessage(String.format("The siege of %s has been aborted!", activeSiege.getName())); + activeSiege.setStage(SiegeStage.INACTIVE); + if (activeSiege.getCommandsOnLose() != null) + for (String command : activeSiege.getCommandsOnLose()) { + Bukkit.getServer().dispatchCommand(Bukkit.getServer().getConsoleSender(), command + .replaceAll("%r", activeSiege.getCaptureRegion()) + .replaceAll("%c", "" + activeSiege.getCost()) + .replaceAll("%l", Bukkit.getPlayer(activeSiege.getPlayerUUID()).getName())); + } + return true; + } else { + playerTimeMap.put(playerID,System.currentTimeMillis()); + sender.sendMessage(MOVECRAFT_COMMAND_PREFIX + "WARNING! You are about to abort an ongoing siege. Aborting a siege count as losing it. Type /siege abort once again to confirm"); + return true; + } + + } + private String dayToString(int day){ String output = "Error"; switch (day){ diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/CraftManager.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/CraftManager.java index e10306a90..f7072e452 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/CraftManager.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/CraftManager.java @@ -29,6 +29,7 @@ import org.jetbrains.annotations.Nullable; import java.io.File; +import java.io.FileWriter; import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; @@ -74,7 +75,27 @@ private Set loadCraftTypes(){ Movecraft.getInstance().saveResource("types/legacy/SubAirship.craft", false); Movecraft.getInstance().saveResource("types/legacy/Submarine.craft", false); Movecraft.getInstance().saveResource("types/legacy/Turret.craft", false); - } else { //if 1.13 and higher, save 1.13 files + } else if (Settings.is1_14){ //if 1.14, save 1.14 files + Movecraft.getInstance().getResource("types/1_14/airship.craft"); + Movecraft.getInstance().saveResource("types/1_14/airship.craft", false); + Movecraft.getInstance().saveResource("types/1_14/airskiff.craft", false); + Movecraft.getInstance().saveResource("types/1_14/BigAirship.craft", false); + Movecraft.getInstance().saveResource("types/1_14/BigSubAirship.craft", false); + Movecraft.getInstance().saveResource("types/1_14/elevator.craft", false); + Movecraft.getInstance().saveResource("types/1_14/LaunchTorpedo.craft", false); + Movecraft.getInstance().saveResource("types/1_14/Ship.craft", false); + Movecraft.getInstance().saveResource("types/1_14/SubAirship.craft", false); + Movecraft.getInstance().saveResource("types/1_14/Submarine.craft", false); + Movecraft.getInstance().saveResource("types/1_14/Turret.craft", false); + final File v1_14dir = new File(craftsFile,"/1_14"); + for (File craftFile : v1_14dir.listFiles()){ + final String fileName = craftFile.getName(); + if (!craftFile.renameTo(new File(craftFile, fileName))) continue; + craftFile.delete(); + } + if (v1_14dir.listFiles().length == 0) + v1_14dir.delete(); + } else { //if 1.13, save 1.13 files Movecraft.getInstance().saveResource("types/airship.craft", false); Movecraft.getInstance().saveResource("types/airskiff.craft", false); Movecraft.getInstance().saveResource("types/BigAirship.craft", false); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/PlayerListener.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/PlayerListener.java index b8fdcbaa0..cb51b5fcd 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/PlayerListener.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/PlayerListener.java @@ -17,6 +17,7 @@ package net.countercraft.movecraft.listener; +import net.countercraft.movecraft.Movecraft; import net.countercraft.movecraft.utils.HitBox; import net.countercraft.movecraft.utils.MathUtils; import net.countercraft.movecraft.MovecraftLocation; @@ -24,11 +25,14 @@ import net.countercraft.movecraft.config.Settings; import net.countercraft.movecraft.craft.CraftManager; import net.countercraft.movecraft.localisation.I18nSupport; +import net.countercraft.movecraft.warfare.siege.Siege; +import net.countercraft.movecraft.warfare.siege.SiegeStage; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; import org.bukkit.event.entity.EntityDamageByEntityEvent; import org.bukkit.event.entity.PlayerDeathEvent; +import org.bukkit.event.player.PlayerLoginEvent; import org.bukkit.event.player.PlayerMoveEvent; import org.bukkit.event.player.PlayerQuitEvent; @@ -164,6 +168,16 @@ public void onPLayerLogout(PlayerQuitEvent e) { CraftManager.getInstance().removeCraftByPlayer(e.getPlayer()); } + @EventHandler + public void onPlayerLogin(PlayerLoginEvent e){ + Player p = e.getPlayer(); + if (!Settings.SiegeEnable) + return; + for (Siege siege : Movecraft.getInstance().getSiegeManager().getSieges()){ + if (siege.getStage().get() == SiegeStage.INACTIVE) continue; + p.setScoreboard(siege.getScoreboard()); + } + } @EventHandler diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftTranslateCommand.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftTranslateCommand.java index 8c2c5629f..15d4d8c51 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftTranslateCommand.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftTranslateCommand.java @@ -66,11 +66,14 @@ public void doUpdate() { passthroughBlocks.add(Material.SUNFLOWER); passthroughBlocks.add(Material.LILAC); passthroughBlocks.add(Material.PEONY); + passthroughBlocks.add(Material.KELP); passthroughBlocks.add(Material.KELP_PLANT); passthroughBlocks.add(Material.TALL_SEAGRASS); passthroughBlocks.add(Material.SEA_PICKLE); passthroughBlocks.add(Material.SEAGRASS); + passthroughBlocks.add(Material.BUBBLE_COLUMN); + } } @@ -163,7 +166,7 @@ public void doUpdate() { //trigger sign events for (MovecraftLocation location : craft.getHitBox()) { Block block = location.toBukkit(craft.getW()).getBlock(); - if (block.getType() == Material.WALL_SIGN || block.getType() == (Settings.IsLegacy ? LegacyUtils.SIGN_POST : Material.SIGN)) { + if (block.getState() instanceof Sign) { Sign sign = (Sign) block.getState(); Bukkit.getServer().getPluginManager().callEvent(new SignTranslateEvent(block, craft, sign.getLines())); sign.update(); @@ -175,6 +178,8 @@ public void doUpdate() { if (!craft.getPhaseBlocks().containsKey(location)) { continue; } + if(craft.getCollapsedHitBox().contains(location)) + continue; handler.setBlockFast(location.toBukkit(craft.getW()), craft.getPhaseBlocks().get(location), (byte) 0); craft.getPhaseBlocks().remove(location); } @@ -194,8 +199,6 @@ public void doUpdate() { } } } - if (!Settings.IsLegacy) - MapUpdateManager.getInstance().scheduleUpdate(new WaterlogUpdateCommand(craft)); if (!craft.isNotProcessing()) craft.setProcessing(false); time = System.nanoTime() - time; diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/WorldEdit7UpdateCommand.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/WorldEdit7UpdateCommand.java index e591a7da9..9c5902040 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/WorldEdit7UpdateCommand.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/WorldEdit7UpdateCommand.java @@ -6,6 +6,7 @@ import com.sk89q.worldedit.bukkit.BukkitAdapter; import net.countercraft.movecraft.MovecraftLocation; import net.countercraft.movecraft.config.Settings; +import org.bukkit.Bukkit; import org.bukkit.Material; import org.bukkit.World; import org.bukkit.block.Block; @@ -29,6 +30,7 @@ public WorldEdit7UpdateCommand(com.sk89q.worldedit.world.block.BaseBlock worldEd @Override public void doUpdate() { Block block = world.getBlockAt(location.getX(), location.getY(), location.getZ()); + Bukkit.broadcastMessage(type.name()); block.setType(type); assert worldEdit7BaseBlock != null; BlockData bData = BukkitAdapter.adapt(worldEdit7BaseBlock); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RemoteSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RemoteSign.java index 2a2910b1c..d8d1e62ae 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RemoteSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RemoteSign.java @@ -93,7 +93,7 @@ public final void onSignClick(PlayerInteractEvent event) { boolean firstError = true; for (MovecraftLocation tloc : foundCraft.getHitBox()) { Block tb = event.getClickedBlock().getWorld().getBlockAt(tloc.getX(), tloc.getY(), tloc.getZ()); - if (!tb.getType().equals((Settings.IsLegacy ? LegacyUtils.SIGN_POST : Material.SIGN)) && !tb.getType().equals(Material.WALL_SIGN)) { + if (!(tb.getState() instanceof Sign)) { continue; } Sign ts = (Sign) tb.getState(); @@ -121,6 +121,14 @@ public final void onSignClick(PlayerInteractEvent event) { Sign foundSign = (Sign) newBlock.getState(); boolean inverted = false;//set to true if target name has an ! in front of the text //check Remote sign if the target strings are inverted + for (String line : foundSign.getLines()){ + if (line == null) + continue; + if (!line.equals("!" + targetText)) + continue; + inverted = true; + break; + } PlayerInteractEvent newEvent = null; if (inverted) { diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RepairSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RepairSign.java index 6c810fbb8..80508d74f 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RepairSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RepairSign.java @@ -129,24 +129,7 @@ private void signLeftClick(PlayerInteractEvent event){ event.getPlayer().sendMessage(I18nSupport.getInternationalisedString("You must be piloting a craft")); return; } - Set foundSimilarSigns = new HashSet<>(); - for (MovecraftLocation moveLoc : pCraft.getHitBox()){ - Block cBlock = moveLoc.toBukkit(sign.getWorld()).getBlock(); - if (!(cBlock.getState() instanceof Sign)) - continue; - Sign foundSign = (Sign) cBlock.getState(); - if (foundSign.getLocation().equals(sign.getLocation())) - continue; - if (!foundSign.getLine(0).equalsIgnoreCase(HEADER) && !foundSign.getLine(1).equals(sign.getLine(1))) - continue; - foundSimilarSigns.add(foundSign); - } - if (foundSimilarSigns.size() > 0){ - event.getPlayer().sendMessage("Warning: Similar repair signs found at these locations:"); - for (Sign s : foundSimilarSigns) - event.getPlayer().sendMessage("- (" + s.getX() + ", " + s.getY() + ", " + s.getX() + ")"); - return; - } + MovecraftRepair movecraftRepair = Movecraft.getInstance().getMovecraftRepair(); if (movecraftRepair.saveCraftRepairState(pCraft, sign, Movecraft.getInstance(), repairName)) event.getPlayer().sendMessage(I18nSupport.getInternationalisedString("State saved")); @@ -171,32 +154,11 @@ private void signRightClick(PlayerInteractEvent event){ event.getPlayer().sendMessage(I18nSupport.getInternationalisedString("Repair functionality is disabled or WorldEdit was not detected")); return; } - //Check for other similar repair signs on the craft - Set foundSimilarSigns = new HashSet<>(); - for (MovecraftLocation moveLoc : pCraft.getHitBox()){ - Block cBlock = moveLoc.toBukkit(sign.getWorld()).getBlock(); - if (!(cBlock.getState() instanceof Sign)) - continue; - Sign foundSign = (Sign) cBlock.getState(); - //Do not include clicked repair sign - if (foundSign.getLocation().equals(sign.getLocation())) - continue; - if (!foundSign.getLine(0).equalsIgnoreCase(HEADER) && !foundSign.getLine(1).equals(sign.getLine(1))) - continue; - foundSimilarSigns.add(foundSign); - } - //Warn the player if multiple similar repair signs are found - if (foundSimilarSigns.size() > 0){ - event.getPlayer().sendMessage("Warning: Similar repair signs found at these locations:"); - for (Sign s : foundSimilarSigns) - event.getPlayer().sendMessage("- (" + s.getX() + ", " + s.getY() + ", " + s.getX() + ")"); - return; - } String repairName = event.getPlayer().getName(); repairName += "_"; repairName += sign.getLine(1); MovecraftRepair movecraftRepair = Movecraft.getInstance().getMovecraftRepair(); - Clipboard clipboard = movecraftRepair.loadCraftRepairStateClipboard(Movecraft.getInstance(), sign, repairName, world); + Clipboard clipboard = movecraftRepair.loadCraftRepairStateClipboard(Movecraft.getInstance(),pCraft, sign, repairName, world); if (clipboard == null){ @@ -210,7 +172,7 @@ private void signRightClick(PlayerInteractEvent event){ } } HashMap numMissingItems = movecraftRepair.getMissingBlocks(repairName); - LinkedList locMissingBlocks = movecraftRepair.getMissingBlockLocations(repairName); + ArrayDeque locMissingBlocks = movecraftRepair.getMissingBlockLocations(repairName); int totalSize = locMissingBlocks.size() + pCraft.getHitBox().size(); if (secondClick){ @@ -273,19 +235,20 @@ private void signRightClick(PlayerInteractEvent event){ } double Cost = numDifferentBlocks * Settings.RepairMoneyPerBlock; - Bukkit.getLogger().info(event.getPlayer().getName() + " has begun a repair with the cost of " + String.valueOf(Cost)); + Movecraft.getInstance().getLogger().info(event.getPlayer().getName() + " has begun a repair with the cost of " + Cost); final LinkedList updateCommands = new LinkedList<>(); final LinkedList updateCommandsFragileBlocks = new LinkedList<>(); - final org.bukkit.util.Vector distToOffset = movecraftRepair.getDistanceFromSignToLowestPoint(clipboard, sign.getLine(1)); + final org.bukkit.util.Vector distToOffset = movecraftRepair.getDistanceFromSignToLowestPoint(clipboard); final org.bukkit.util.Vector offsetFromSign = new org.bukkit.util.Vector(sign.getLocation().getBlockX() - distToOffset.getBlockX(), sign.getLocation().getBlockY() - distToOffset.getBlockY(), sign.getLocation().getBlockZ() - distToOffset.getBlockZ()); - final org.bukkit.util.Vector distance = movecraftRepair.getDistanceFromClipboardToWorldOffset(offsetFromSign, clipboard); - + final org.bukkit.util.Vector distance = movecraftRepair.getDistance(repairName); + Bukkit.broadcastMessage(distToOffset.toString()); while (!locMissingBlocks.isEmpty()){ - Vector cLoc = locMissingBlocks.pop(); - MovecraftLocation moveLoc = new MovecraftLocation(cLoc.getBlockX() + distance.getBlockX(), cLoc.getBlockY() + distance.getBlockY(), cLoc.getBlockZ() + distance.getBlockZ()); + Vector cLoc = locMissingBlocks.pollFirst(); + Vector clipBoardLoc = cLoc.add(movecraftRepair.getDistance(repairName)); + MovecraftLocation moveLoc = new MovecraftLocation(cLoc.getBlockX(), cLoc.getBlockY(), cLoc.getBlockZ()); //To avoid any issues during the repair, keep certain blocks in different linked lists if (Settings.IsLegacy) { - BaseBlock baseBlock = RepairUtils.getBlock(clipboard, WorldEditUtils.toWeVector(cLoc)); + BaseBlock baseBlock = RepairUtils.getBlock(clipboard, WorldEditUtils.toWeVector(clipBoardLoc)); if (Arrays.binarySearch(fragileBlocks, LegacyUtils.getMaterial(baseBlock.getType())) >= 0) { WorldEditUpdateCommand updateCommand = new WorldEditUpdateCommand(baseBlock, sign.getWorld(), moveLoc, LegacyUtils.getMaterial(baseBlock.getType()), (byte) baseBlock.getData()); updateCommandsFragileBlocks.add(updateCommand); @@ -294,7 +257,7 @@ private void signRightClick(PlayerInteractEvent event){ updateCommands.add(updateCommand); } } else { - com.sk89q.worldedit.world.block.BaseBlock bb = clipboard.getFullBlock(WorldEditUtils.toBlockVector(cLoc)); + com.sk89q.worldedit.world.block.BaseBlock bb = clipboard.getFullBlock(WorldEditUtils.toBlockVector(clipBoardLoc)); Material type = BukkitAdapter.adapt(bb.getBlockType()); if (type.name().contains("WALL")){ WorldEdit7UpdateCommand weUp = new WorldEdit7UpdateCommand(bb,sign.getWorld(),moveLoc, type); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/siege/Siege.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/siege/Siege.java index 3a1abf950..13001abb6 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/siege/Siege.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/siege/Siege.java @@ -1,6 +1,11 @@ package net.countercraft.movecraft.warfare.siege; +import net.countercraft.movecraft.Movecraft; +import org.bukkit.Bukkit; import org.bukkit.boss.BossBar; +import org.bukkit.scoreboard.DisplaySlot; +import org.bukkit.scoreboard.Objective; +import org.bukkit.scoreboard.Scoreboard; import org.jetbrains.annotations.NotNull; import java.util.List; @@ -17,7 +22,7 @@ public class Siege { private long lastPayout; private final boolean doubleCostPerOwnedSiegeRegion; private UUID playerUUID; - private BossBar progressBar; + private final Scoreboard scoreboard; public Siege(@NotNull String name, @NotNull String captureRegion, @NotNull String attackRegion, int scheduleStart, int scheduleEnd, int delayBeforeStart, int duration, int dayOfWeek, int dailyIncome, int cost, boolean doubleCostPerOwnedSiegeRegion, @NotNull List craftsToWin, @NotNull List commandsOnStart, @NotNull List commandsOnWin, @NotNull List commandsOnLose) { this.commandsOnWin = commandsOnWin; @@ -39,7 +44,14 @@ public Siege(@NotNull String name, @NotNull String captureRegion, @NotNull Strin lastUpdate = 0; stage = new AtomicReference<>(); stage.set(SiegeStage.INACTIVE); - progressBar = null; + scoreboard = Bukkit.getScoreboardManager().getNewScoreboard(); + scoreboard.registerNewObjective(name, "dummy",name); + scoreboard.registerNewObjective("stage","dummy","Stage: " + stage.get().name().toLowerCase().replace("_", " ")); + scoreboard.registerNewObjective("timeLeft","dummy","Time left: "); + scoreboard.registerNewObjective("shipInRegion", "dummy", ""); + for (Objective objective : scoreboard.getObjectives()){ + objective.setDisplaySlot(DisplaySlot.SIDEBAR); + } } @NotNull @@ -149,11 +161,7 @@ public boolean isDoubleCostPerOwnedSiegeRegion() { return doubleCostPerOwnedSiegeRegion; } - public BossBar getProgressBar(){ - return progressBar; - } - - public void setProgressBar(BossBar progressBar){ - this.progressBar = progressBar; + public Scoreboard getScoreboard(){ + return scoreboard; } } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/siege/SiegeManager.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/siege/SiegeManager.java index 74fec8112..520c563b4 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/siege/SiegeManager.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/siege/SiegeManager.java @@ -1,5 +1,7 @@ package net.countercraft.movecraft.warfare.siege; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; import org.bukkit.plugin.Plugin; import org.bukkit.scheduler.BukkitRunnable; diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/siege/SiegePreparationTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/siege/SiegePreparationTask.java index 39eb2d9f2..845ee2285 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/siege/SiegePreparationTask.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/siege/SiegePreparationTask.java @@ -20,22 +20,18 @@ public void run() { siege.setStage(SiegeStage.IN_PROGRESS); } double progress = (double) timePassedinSeconds / (double) siege.getDelayBeforeStart(); - if (progress <= 1.0) { - siege.getProgressBar().setProgress(progress); - } + //Bukkit.getServer().broadcastMessage(String.valueOf(progress) + ", " + String.valueOf(timePassedinSeconds) + ", " + String.valueOf(siege.getDuration())); - for (Player p : Bukkit.getOnlinePlayers()){ - siege.getProgressBar().addPlayer(p); - } + if ((siege.getDelayBeforeStart() - timePassed/1000) % 60 != 0 || timePassed < 3000){ return; } int timeLeft = siege.getDelayBeforeStart() - (timePassed/1000); - broadcastSiegePreparation(siege.getPlayerUUID(), siege.getName(), (int) timeLeft); + broadcastSiegePreparation(siege.getPlayerUUID(), siege.getName(), timeLeft); } private void broadcastSiegePreparation(UUID playerUUID, String siegeName, int timeLeft){ - String playerName = "An offline siege leader"; + String playerName; Player player = Bukkit.getPlayer(playerUUID); if (player != null){ playerName = player.getDisplayName(); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/siege/SiegeProgressTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/siege/SiegeProgressTask.java index 865510acf..32cec869c 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/siege/SiegeProgressTask.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/siege/SiegeProgressTask.java @@ -4,14 +4,17 @@ import com.sk89q.worldguard.protection.managers.RegionManager; import com.sk89q.worldguard.protection.regions.ProtectedRegion; import net.countercraft.movecraft.Movecraft; +import net.countercraft.movecraft.config.Settings; import net.countercraft.movecraft.craft.Craft; import net.countercraft.movecraft.utils.HashHitBox; import net.countercraft.movecraft.craft.CraftManager; import net.countercraft.movecraft.utils.WorldguardUtils; import org.bukkit.Bukkit; +import org.bukkit.ChatColor; import org.bukkit.Sound; import org.bukkit.boss.BarColor; import org.bukkit.entity.Player; +import org.bukkit.scoreboard.Objective; public class SiegeProgressTask extends SiegeTask { @@ -29,11 +32,7 @@ public void run() { //Allows the siege leader to not pilot a craft without having an NPE generated if (siegeCraft == null){ siegeLeaderPilotingShip = false; - } else if (siege.getCraftsToWin().contains(siegeCraft.getType().getCraftName())){ - siegeLeaderPilotingShip = true; - } else { - siegeLeaderPilotingShip = false; - } + } else siegeLeaderPilotingShip = siege.getCraftsToWin().contains(siegeCraft.getType().getCraftName()); int midX = 0; int midY = 0; int midZ = 0; @@ -46,23 +45,25 @@ public void run() { siegeLeaderShipInRegion = manager.getRegion(siege.getAttackRegion()).contains(midX, midY, midZ); } + if (Settings.KOTHSiege){ + } + int timeLeft = (siege.getDuration() - (((int)System.currentTimeMillis() - siege.getStartTime())/1000)); double progress = (double) ((((int)System.currentTimeMillis() - siege.getStartTime())/1000) - siege.getDelayBeforeStart()) / (double) (siege.getDuration() - siege.getDelayBeforeStart()); - if (progress <= 1.0 && progress >= 0.0) { //Make sure progress is between 0.0 and 1.0 when it is registered to the progressbar - siege.getProgressBar().setProgress(progress); - } - if (siegeLeaderShipInRegion){ - siege.getProgressBar().setColor(BarColor.GREEN); - } else { - siege.getProgressBar().setColor(BarColor.RED); - } - if ((siege.getDuration() - ((System.currentTimeMillis() - siege.getStartTime()) / 1000)) % 60 != 0) { + Objective status = siege.getScoreboard().getObjective("shipInRegion"); + Objective time = siege.getScoreboard().getObjective("timeLeft"); + String statusText = (siegeLeaderShipInRegion ? ChatColor.GREEN : ChatColor.RED) + "Ship is " + (siegeLeaderShipInRegion ? "" : "not ") + " in siege region!"; + status.setDisplayName(statusText); + int hours = (timeLeft / 1000) / 3600; + int minutes = (timeLeft / 1000) / 60 - hours * 60; + int seconds = (timeLeft / 1000) - minutes * 60; + time.setDisplayName(String.format("Time left: %2d:%2d:%2d",hours,minutes,seconds)); + if (timeLeft % 60 != 0) { return; } - int timeLeft = (siege.getDuration() - (((int)System.currentTimeMillis() - siege.getStartTime())/1000)); - Bukkit.getPlayer(siege.getPlayerUUID()).sendMessage(String.valueOf(timeLeft)); + if (timeLeft > 10) { if (siegeLeaderShipInRegion) { Bukkit.getServer().broadcastMessage(String.format( @@ -106,7 +107,6 @@ public void run() { .replaceAll("%l", siegeLeader.toString())); } } - siege.getProgressBar().setVisible(false); siege.setStage(SiegeStage.INACTIVE); } for (Player p : Bukkit.getOnlinePlayers()){ diff --git a/modules/Movecraft/src/main/resources/plugin.yml b/modules/Movecraft/src/main/resources/plugin.yml index 408f5470b..aafa4ef7e 100644 --- a/modules/Movecraft/src/main/resources/plugin.yml +++ b/modules/Movecraft/src/main/resources/plugin.yml @@ -1,7 +1,7 @@ name: Movecraft softdepend: [WorldGuard, WorldEdit, FastAsyncWorldEdit, Cannons, Vault ,Essentials, WGCustomFlags, Towny] version: ${project.version} -api-version: 1.13 +api-version: 1.14 #version: ${env.BUILD_NUMBER} description: The original flight and movement plugin for minecraft. author: BaccaYarro diff --git a/modules/Movecraft/src/main/resources/types/1_14/BigAirship.craft b/modules/Movecraft/src/main/resources/types/1_14/BigAirship.craft new file mode 100644 index 000000000..de85ebe12 --- /dev/null +++ b/modules/Movecraft/src/main/resources/types/1_14/BigAirship.craft @@ -0,0 +1,305 @@ +name: BigAirship +maxSize: 20000 +minSize: 10000 +allowedBlocks: + #beds + - WHITE_BED + - ORANGE_BED + - MAGENTA_BED + - LIGHT_BLUE_BED + - YELLOW_BED + - LIME_BED + - PINK_BED + - GRAY_BED + - LIGHT_BED + - CYAN_BED + - PURPLE_BED + - BLUE_BED + - BROWN_BED + - GREEN_BED + - RED_BED + - BLACK_BED + #buttons + - ACACIA_BUTTON + - BIRCH_BUTTON + - DARK_OAK_BUTTON + - JUNGLE_BUTTON + - OAK_BUTTON + - SPRUCE_BUTTON + - STONE_BUTTON + #carpets + - WHITE_CARPET + - ORANGE_CARPET + - MAGENTA_CARPET + - LIGHT_BLUE_CARPET + - YELLOW_CARPET + - LIME_CARPET + - PINK_CARPET + - GRAY_CARPET + - LIGHT_CARPET + - CYAN_CARPET + - PURPLE_CARPET + - BLUE_CARPET + - BROWN_CARPET + - GREEN_CARPET + - RED_CARPET + - BLACK_CARPET + #doors + - ACACIA_DOOR + - BIRCH_DOOR + - DARK_OAK_DOOR + - IRON_DOOR + - JUNGLE_DOOR + - OAK_DOOR + - SPRUCE_DOOR + #fences + - ACACIA_FENCE + - BIRCH_FENCE + - DARK_OAK_FENCE + - JUNGLE_FENCE + - OAK_FENCE + - NETHER_BRICK_FENCE + - SPRUCE_FENCE + #fence gates + - ACACIA_FENCE_GATE + - BIRCH_FENCE_GATE + - DARK_OAK_FENCE_GATE + - JUNGLE_FENCE_GATE + - OAK_FENCE_GATE + - SPRUCE_FENCE_GATE + #glass + - GLASS + - WHITE_STAINED_GLASS + - ORANGE_STAINED_GLASS + - MAGENTA_STAINED_GLASS + - LIGHT_BLUE_STAINED_GLASS + - YELLOW_STAINED_GLASS + - LIME_STAINED_GLASS + - PINK_STAINED_GLASS + - GRAY_STAINED_GLASS + - LIGHT_GRAY_STAINED_GLASS + - CYAN_STAINED_GLASS + - PURPLE_STAINED_GLASS + - BLUE_STAINED_GLASS + - BROWN_STAINED_GLASS + - GREEN_STAINED_GLASS + - RED_STAINED_GLASS + - BLACK_STAINED_GLASS + #glass pane + - GLASS_PANE + - WHITE_STAINED_GLASS_PANE + - ORANGE_STAINED_GLASS_PANE + - MAGENTA_STAINED_GLASS_PANE + - LIGHT_BLUE_STAINED_GLASS_PANE + - YELLOW_STAINED_GLASS_PANE + - LIME_STAINED_GLASS_PANE + - PINK_STAINED_GLASS_PANE + - GRAY_STAINED_GLASS_PANE + - LIGHT_GRAY_STAINED_GLASS_PANE + - CYAN_STAINED_GLASS_PANE + - PURPLE_STAINED_GLASS_PANE + - BLUE_STAINED_GLASS_PANE + - BROWN_STAINED_GLASS_PANE + - GREEN_STAINED_GLASS_PANE + - RED_STAINED_GLASS_PANE + - BLACK_STAINED_GLASS_PANE + #liquids + - LAVA + - WATER + #logs + - BIRCH_LOG + - JUNGLE_LOG + - OAK_LOG + - SPRUCE_LOG + - STRIPPED_BIRCH_LOG + - STRIPPED_JUNGLE_LOG + - STRIPPED_OAK_LOG + - STRIPPED_SPRUCE_LOG + #misc + - BOOKSHELF + - BREWING_STAND + - CRAFTING_TABLE + - CAULDRON + - FURNACE + - GLOWSTONE + - IRON_BARS + - LADDER + - NETHER_BRICKS + - TORCH + - WALL_TORCH + #planks + - ACACIA_PLANKS + - BIRCH_PLANKS + - DARK_OAK_PLANKS + - JUNGLE_PLANKS + - OAK_PLANKS + - SPRUCE_PLANKS + #pressure plates + - ACACIA_PRESSURE_PLATE + - BIRCH_PRESSURE_PLATE + - DARK_OAK_PRESSURE_PLATE + - HEAVY_WEIGHTED_PRESSURE_PLATE + - JUNGLE_PRESSURE_PLATE + - LIGHT_WEIGHTED_PRESSURE_PLATE + - OAK_PRESSURE_PLATE + - SPRUCE_PRESSURE_PLATE + - STONE_PRESSURE_PLATE + #redstone + - COMPARATOR + - LEVER + - NOTE_BLOCK + - PISTON + - PISTON_HEAD + - REDSTONE_BLOCK + - REDSTONE_WIRE + - REPEATER + - REDSTONE_TORCH + - REDSTONE_WALL_TORCH + - STICKY_PISTON + - TRIPWIRE_HOOK + #signs + - ACACIA_SIGN + - ACACIA_WALL_SIGN + - BIRCH_SIGN + - BIRCH_WALL_SIGN + - DARK_OAK_SIGN + - DARK_OAK_WALL_SIGN + - JUNGLE_SIGN + - JUNGLE_WALL_SIGN + - OAK_SIGN + - OAK_WALL_SIGN + - SPRUCE_SIGN + - SPRUCE_WALL_SIGN + #slabs + - ACACIA_SLAB + - BIRCH_SLAB + - BRICK_SLAB + - COBBLESTONE_SLAB + - DARK_OAK_SLAB + - DARK_PRISMARINE + - JUNGLE_SLAB + - NETHER_BRICK_SLAB + - OAK_SLAB + - PETRIFIED_OAK_SLAB + - PRISMARINE_SLAB + - PRISMARINE_BRICK_SLAB + - RED_SANDSTONE_SLAB + - QUARTZ_SLAB + - SPRUCE_SLAB + - STONE_SLAB + #stairs + - BIRCH_STAIRS + - JUNGLE_STAIRS + - OAK_STAIRS + - NETHER_BRICK_STAIRS + - SMOOTH_STAIRS + - SPRUCE_STAIRS + - STONE_BRICK_STAIRS + #storage + - CHEST + - DISPENSER + - DROPPER + - HOPPER + - TRAPPED_CHEST + #terracotta + - WHITE_TERRACOTTA + - ORANGE_TERRACOTTA + - MAGENTA_TERRACOTTA + - LIGHT_BLUE_TERRACOTTA + - YELLOW_TERRACOTTA + - LIME_TERRACOTTA + - PINK_TERRACOTTA + - GRAY_TERRACOTTA + - LIGHT_GRAY_TERRACOTTA + - CYAN_TERRACOTTA + - PURPLE_TERRACOTTA + - BLUE_TERRACOTTA + - BROWN_TERRACOTTA + - GREEN_TERRACOTTA + - RED_TERRACOTTA + - BLACK_TERRACOTTA + #trapdoors + - ACACIA_TRAPDOOR + - BIRCH_TRAPDOOR + - DARK_OAK_TRAPDOOR + - JUNGLE_TRAPDOOR + - OAK_TRAPDOOR + - SPRUCE_TRAPDOOR + #weapon blocks + - COAL_BLOCK + #wood + - ACACIA_WOOD + - BIRCH_WOOD + - DARK_OAK_WOOD + - OAK_WOOD + - SPRUCE_WOOD + - STRIPPED_ACACIA_WOOD + - STRIPPED_BIRCH_WOOD + - STRIPPED_DARK_OAK_WOOD + - STRIPPED_OAK_WOOD + - STRIPPED_SPRUCE_WOOD + #wool + - WHITE_WOOL + - ORANGE_WOOL + - MAGENTA_WOOL + - LIGHT_BLUE_WOOL + - YELLOW_WOOL + - LIME_WOOL + - PINK_WOOL + - GRAY_WOOL + - LIGHT_GRAY_WOOL + - CYAN_WOOL + - PURPLE_WOOL + - BLUE_WOOL + - BROWN_WOOL + - GREEN_WOOL + - RED_WOOL + - BLACK_WOOL + + + +canCruise: true +rotateAtMidpoint: true +blockRemoteRotate: true +canFly: true +maxHeightLimit: 110 +maxHeightAboveGround: 50 +vertCruiseSkipBlocks: 1 +collisionExplosion: 0.0 +speed: 0.3 +detectionMultiplier: 10.0 +underwaterDetectionMultiplier: 1.0 +cruiseSkipBlocks: 4 +cruiseSpeed: 0.3 +fuelBurnRate: 4.0 +sinkPercent: 99.0 +overallSinkPercent: 60.0 +tryNudge: false +canStaticMove: true +maxStaticMove: 2 +moveblocks: + REDSTONE_BLOCK: # redstone represents engines + - 1.0 + - 100.0 +flyblocks: + [WHITE_WOOL, ORANGE_WOOL, MAGENTA_WOOL,LIGHT_BLUE_WOOL,YELLOW_WOOL,LIME_WOOL,PINK_WOOL,GRAY_WOOL,LIGHT_GRAY_WOOL,CYAN_WOOL,PURPLE_WOOL,BLUE_WOOL,BROWN_WOOL, GREEN_WOOL, RED_WOOL, BLACK_WOOL]: #wool represents lift + - 50.0 + - 100.0 + [CHEST,TRAPPED_CHEST]: # limit chests to make big airships important for merchant missions + - 0.0 + - 1.0 + [DISPENSER,DROPPER,HOPPER]: # dispensers and hoppers can be used for inventory too, so limit them as well + - 0.0 + - 2.0 + FURNACE: # Furnaces for cargo? really guys? + - 0.0 + - N50 + ANVIL: # anvils are OP armor, so limit it + - 0.0 + - 1.0 + OBSIDIAN: # so is obsidian + - 0.0 + - 1.0 + WATER: # so is water + - 0.0 + - 1.0 diff --git a/modules/Movecraft/src/main/resources/types/1_14/BigSubAirship.craft b/modules/Movecraft/src/main/resources/types/1_14/BigSubAirship.craft new file mode 100644 index 000000000..d2eaac321 --- /dev/null +++ b/modules/Movecraft/src/main/resources/types/1_14/BigSubAirship.craft @@ -0,0 +1,306 @@ +name: BigSubAirship +maxSize: 20000 +minSize: 10000 +allowedBlocks: + #beds + - WHITE_BED + - ORANGE_BED + - MAGENTA_BED + - LIGHT_BLUE_BED + - YELLOW_BED + - LIME_BED + - PINK_BED + - GRAY_BED + - LIGHT_BED + - CYAN_BED + - PURPLE_BED + - BLUE_BED + - BROWN_BED + - GREEN_BED + - RED_BED + - BLACK_BED + #buttons + - ACACIA_BUTTON + - BIRCH_BUTTON + - DARK_OAK_BUTTON + - JUNGLE_BUTTON + - OAK_BUTTON + - SPRUCE_BUTTON + - STONE_BUTTON + #carpets + - WHITE_CARPET + - ORANGE_CARPET + - MAGENTA_CARPET + - LIGHT_BLUE_CARPET + - YELLOW_CARPET + - LIME_CARPET + - PINK_CARPET + - GRAY_CARPET + - LIGHT_CARPET + - CYAN_CARPET + - PURPLE_CARPET + - BLUE_CARPET + - BROWN_CARPET + - GREEN_CARPET + - RED_CARPET + - BLACK_CARPET + #doors + - ACACIA_DOOR + - BIRCH_DOOR + - DARK_OAK_DOOR + - IRON_DOOR + - JUNGLE_DOOR + - OAK_DOOR + - SPRUCE_DOOR + #fences + - ACACIA_FENCE + - BIRCH_FENCE + - DARK_OAK_FENCE + - JUNGLE_FENCE + - OAK_FENCE + - NETHER_BRICK_FENCE + - SPRUCE_FENCE + #fence gates + - ACACIA_FENCE_GATE + - BIRCH_FENCE_GATE + - DARK_OAK_FENCE_GATE + - JUNGLE_FENCE_GATE + - OAK_FENCE_GATE + - SPRUCE_FENCE_GATE + #glass + - GLASS + - WHITE_STAINED_GLASS + - ORANGE_STAINED_GLASS + - MAGENTA_STAINED_GLASS + - LIGHT_BLUE_STAINED_GLASS + - YELLOW_STAINED_GLASS + - LIME_STAINED_GLASS + - PINK_STAINED_GLASS + - GRAY_STAINED_GLASS + - LIGHT_GRAY_STAINED_GLASS + - CYAN_STAINED_GLASS + - PURPLE_STAINED_GLASS + - BLUE_STAINED_GLASS + - BROWN_STAINED_GLASS + - GREEN_STAINED_GLASS + - RED_STAINED_GLASS + - BLACK_STAINED_GLASS + #glass pane + - GLASS_PANE + - WHITE_STAINED_GLASS_PANE + - ORANGE_STAINED_GLASS_PANE + - MAGENTA_STAINED_GLASS_PANE + - LIGHT_BLUE_STAINED_GLASS_PANE + - YELLOW_STAINED_GLASS_PANE + - LIME_STAINED_GLASS_PANE + - PINK_STAINED_GLASS_PANE + - GRAY_STAINED_GLASS_PANE + - LIGHT_GRAY_STAINED_GLASS_PANE + - CYAN_STAINED_GLASS_PANE + - PURPLE_STAINED_GLASS_PANE + - BLUE_STAINED_GLASS_PANE + - BROWN_STAINED_GLASS_PANE + - GREEN_STAINED_GLASS_PANE + - RED_STAINED_GLASS_PANE + - BLACK_STAINED_GLASS_PANE + #liquids + - LAVA + - WATER + #logs + - BIRCH_LOG + - JUNGLE_LOG + - OAK_LOG + - SPRUCE_LOG + - STRIPPED_BIRCH_LOG + - STRIPPED_JUNGLE_LOG + - STRIPPED_OAK_LOG + - STRIPPED_SPRUCE_LOG + #misc + - BOOKSHELF + - BREWING_STAND + - CRAFTING_TABLE + - CAULDRON + - FURNACE + - GLOWSTONE + - IRON_BARS + - LADDER + - NETHER_BRICKS + - TORCH + - WALL_TORCH + #planks + - ACACIA_PLANKS + - BIRCH_PLANKS + - DARK_OAK_PLANKS + - JUNGLE_PLANKS + - OAK_PLANKS + - SPRUCE_PLANKS + #pressure plates + - ACACIA_PRESSURE_PLATE + - BIRCH_PRESSURE_PLATE + - DARK_OAK_PRESSURE_PLATE + - HEAVY_WEIGHTED_PRESSURE_PLATE + - JUNGLE_PRESSURE_PLATE + - LIGHT_WEIGHTED_PRESSURE_PLATE + - OAK_PRESSURE_PLATE + - SPRUCE_PRESSURE_PLATE + - STONE_PRESSURE_PLATE + #redstone + - COMPARATOR + - LEVER + - NOTE_BLOCK + - PISTON + - PISTON_HEAD + - REDSTONE_BLOCK + - REDSTONE_WIRE + - REPEATER + - REDSTONE_TORCH + - REDSTONE_WALL_TORCH + - STICKY_PISTON + - TRIPWIRE_HOOK + #signs + - ACACIA_SIGN + - ACACIA_WALL_SIGN + - BIRCH_SIGN + - BIRCH_WALL_SIGN + - DARK_OAK_SIGN + - DARK_OAK_WALL_SIGN + - JUNGLE_SIGN + - JUNGLE_WALL_SIGN + - OAK_SIGN + - OAK_WALL_SIGN + - SPRUCE_SIGN + - SPRUCE_WALL_SIGN + #slabs + - ACACIA_SLAB + - BIRCH_SLAB + - BRICK_SLAB + - COBBLESTONE_SLAB + - DARK_OAK_SLAB + - DARK_PRISMARINE + - JUNGLE_SLAB + - NETHER_BRICK_SLAB + - OAK_SLAB + - PETRIFIED_OAK_SLAB + - PRISMARINE_SLAB + - PRISMARINE_BRICK_SLAB + - RED_SANDSTONE_SLAB + - QUARTZ_SLAB + - SPRUCE_SLAB + - STONE_SLAB + #stairs + - BIRCH_STAIRS + - JUNGLE_STAIRS + - OAK_STAIRS + - NETHER_BRICK_STAIRS + - SMOOTH_STAIRS + - SPRUCE_STAIRS + - STONE_BRICK_STAIRS + #storage + - CHEST + - DISPENSER + - DROPPER + - HOPPER + - TRAPPED_CHEST + #terracotta + - WHITE_TERRACOTTA + - ORANGE_TERRACOTTA + - MAGENTA_TERRACOTTA + - LIGHT_BLUE_TERRACOTTA + - YELLOW_TERRACOTTA + - LIME_TERRACOTTA + - PINK_TERRACOTTA + - GRAY_TERRACOTTA + - LIGHT_GRAY_TERRACOTTA + - CYAN_TERRACOTTA + - PURPLE_TERRACOTTA + - BLUE_TERRACOTTA + - BROWN_TERRACOTTA + - GREEN_TERRACOTTA + - RED_TERRACOTTA + - BLACK_TERRACOTTA + #trapdoors + - ACACIA_TRAPDOOR + - BIRCH_TRAPDOOR + - DARK_OAK_TRAPDOOR + - JUNGLE_TRAPDOOR + - OAK_TRAPDOOR + - SPRUCE_TRAPDOOR + #weapon blocks + - COAL_BLOCK + #wood + - ACACIA_WOOD + - BIRCH_WOOD + - DARK_OAK_WOOD + - OAK_WOOD + - SPRUCE_WOOD + - STRIPPED_ACACIA_WOOD + - STRIPPED_BIRCH_WOOD + - STRIPPED_DARK_OAK_WOOD + - STRIPPED_OAK_WOOD + - STRIPPED_SPRUCE_WOOD + #wool + - WHITE_WOOL + - ORANGE_WOOL + - MAGENTA_WOOL + - LIGHT_BLUE_WOOL + - YELLOW_WOOL + - LIME_WOOL + - PINK_WOOL + - GRAY_WOOL + - LIGHT_GRAY_WOOL + - CYAN_WOOL + - PURPLE_WOOL + - BLUE_WOOL + - BROWN_WOOL + - GREEN_WOOL + - RED_WOOL + - BLACK_WOOL + +canCruise: true +rotateAtMidpoint: true +blockRemoteRotate: true +cruiseSkipBlocks: 4 +cruiseSpeed: 0.17 +canFly: false +minHeightLimit: 1 +maxHeightLimit: 110 +maxHeightAboveGround: 50 +vertCruiseSkipBlocks: 1 +detectionMultiplier: 10.0 +underwaterDetectionMultiplier: 1.0 +speed: 0.17 +collisionExplosion: 0.0 +fuelBurnRate: 4.0 +tryNudge: false +sinkPercent: 99.0 +overallSinkPercent: 60.0 +halfSpeedUnderwater: true +moveblocks: + REDSTONE_BLOCK: # redstone represents engines + - 1.0 + - 100.0 +flyblocks: + IRON_BLOCK: # iron represents ballast tanks + - 10.0 + - 100.0 + [WHITE_WOOL, ORANGE_WOOL, MAGENTA_WOOL,LIGHT_BLUE_WOOL,YELLOW_WOOL,LIME_WOOL,PINK_WOOL,GRAY_WOOL,LIGHT_GRAY_WOOL,CYAN_WOOL,PURPLE_WOOL,BLUE_WOOL,BROWN_WOOL, GREEN_WOOL, RED_WOOL, BLACK_WOOL]: #wool represents lift + - 50.0 + - 100.0 + [CHEST,TRAPPED_CHEST]: # limit chests to make big airships important for merchant missions + - 0.0 + - 1.0 + [DISPENSER,DROPPER,HOPPER]: # dispensers and hoppers can be used for inventory too, so limit them as well + - 0.0 + - 2.0 + FURNACE: # Furnaces for cargo? really guys? + - 0.0 + - N50 + ANVIL: # anvils are OP armor, so limit it + - 0.0 + - 1.0 + OBSIDIAN: # so is obsidian + - 0.0 + - 1.0 + WATER: # so is water + - 0.0 + - 1.0 diff --git a/modules/Movecraft/src/main/resources/types/1_14/LaunchTorpedo.craft b/modules/Movecraft/src/main/resources/types/1_14/LaunchTorpedo.craft new file mode 100644 index 000000000..ace8eb4b7 --- /dev/null +++ b/modules/Movecraft/src/main/resources/types/1_14/LaunchTorpedo.craft @@ -0,0 +1,30 @@ +name: LaunchTorpedo +maxSize: 7 +minSize: 1 +allowedBlocks: + - COAL_BLOCK + +forbiddenBlocks: + - BEDROCK + +canCruise: true +cruiseOnPilot: true +focusedExplosion: true +mustBeSubcraft: true +cruiseSkipBlocks: 1 +canFly: false +minHeightLimit: 65 +maxHeightLimit: 65 +detectionMultiplier: 40.0 +underwaterDetectionMultiplier: 4.0 +collisionExplosion: 3.0 +explodeOnCrash: 3.0 +moveEntities: false +speed: 9.0 +tryNudge: false +sinkPercent: 99.0 +overallSinkPercent: 99.0 +flyblocks: + COAL_BLOCK: + - 10.0 + - 100.0 diff --git a/modules/Movecraft/src/main/resources/types/1_14/Ship.craft b/modules/Movecraft/src/main/resources/types/1_14/Ship.craft new file mode 100644 index 000000000..cdbc6145c --- /dev/null +++ b/modules/Movecraft/src/main/resources/types/1_14/Ship.craft @@ -0,0 +1,282 @@ +name: Ship +maxSize: 100000 +minSize: 10 +allowedBlocks: +#beds + - WHITE_BED + - ORANGE_BED + - MAGENTA_BED + - LIGHT_BLUE_BED + - YELLOW_BED + - LIME_BED + - PINK_BED + - GRAY_BED + - LIGHT_BED + - CYAN_BED + - PURPLE_BED + - BLUE_BED + - BROWN_BED + - GREEN_BED + - RED_BED + - BLACK_BED + #buttons + - ACACIA_BUTTON + - BIRCH_BUTTON + - DARK_OAK_BUTTON + - JUNGLE_BUTTON + - OAK_BUTTON + - SPRUCE_BUTTON + - STONE_BUTTON + #carpets + - WHITE_CARPET + - ORANGE_CARPET + - MAGENTA_CARPET + - LIGHT_BLUE_CARPET + - YELLOW_CARPET + - LIME_CARPET + - PINK_CARPET + - GRAY_CARPET + - LIGHT_CARPET + - CYAN_CARPET + - PURPLE_CARPET + - BLUE_CARPET + - BROWN_CARPET + - GREEN_CARPET + - RED_CARPET + - BLACK_CARPET + #doors + - ACACIA_DOOR + - BIRCH_DOOR + - DARK_OAK_DOOR + - IRON_DOOR + - JUNGLE_DOOR + - OAK_DOOR + - SPRUCE_DOOR + #fences + - ACACIA_FENCE + - BIRCH_FENCE + - DARK_OAK_FENCE + - JUNGLE_FENCE + - OAK_FENCE + - NETHER_BRICK_FENCE + - SPRUCE_FENCE + #fence gates + - ACACIA_FENCE_GATE + - BIRCH_FENCE_GATE + - DARK_OAK_FENCE_GATE + - JUNGLE_FENCE_GATE + - OAK_FENCE_GATE + - SPRUCE_FENCE_GATE + #glass + - GLASS + - WHITE_STAINED_GLASS + - ORANGE_STAINED_GLASS + - MAGENTA_STAINED_GLASS + - LIGHT_BLUE_STAINED_GLASS + - YELLOW_STAINED_GLASS + - LIME_STAINED_GLASS + - PINK_STAINED_GLASS + - GRAY_STAINED_GLASS + - LIGHT_GRAY_STAINED_GLASS + - CYAN_STAINED_GLASS + - PURPLE_STAINED_GLASS + - BLUE_STAINED_GLASS + - BROWN_STAINED_GLASS + - GREEN_STAINED_GLASS + - RED_STAINED_GLASS + - BLACK_STAINED_GLASS + #glass pane + - GLASS_PANE + - WHITE_STAINED_GLASS_PANE + - ORANGE_STAINED_GLASS_PANE + - MAGENTA_STAINED_GLASS_PANE + - LIGHT_BLUE_STAINED_GLASS_PANE + - YELLOW_STAINED_GLASS_PANE + - LIME_STAINED_GLASS_PANE + - PINK_STAINED_GLASS_PANE + - GRAY_STAINED_GLASS_PANE + - LIGHT_GRAY_STAINED_GLASS_PANE + - CYAN_STAINED_GLASS_PANE + - PURPLE_STAINED_GLASS_PANE + - BLUE_STAINED_GLASS_PANE + - BROWN_STAINED_GLASS_PANE + - GREEN_STAINED_GLASS_PANE + - RED_STAINED_GLASS_PANE + - BLACK_STAINED_GLASS_PANE + #liquids + - LAVA + - WATER + #logs + - BIRCH_LOG + - JUNGLE_LOG + - OAK_LOG + - SPRUCE_LOG + - STRIPPED_BIRCH_LOG + - STRIPPED_JUNGLE_LOG + - STRIPPED_OAK_LOG + - STRIPPED_SPRUCE_LOG + #misc + - BOOKSHELF + - BREWING_STAND + - CRAFTING_TABLE + - CAULDRON + - FURNACE + - GLOWSTONE + - IRON_BARS + - LADDER + - NETHER_BRICKS + - TORCH + - WALL_TORCH + #planks + - ACACIA_PLANKS + - BIRCH_PLANKS + - DARK_OAK_PLANKS + - JUNGLE_PLANKS + - OAK_PLANKS + - SPRUCE_PLANKS + #pressure plates + - ACACIA_PRESSURE_PLATE + - BIRCH_PRESSURE_PLATE + - DARK_OAK_PRESSURE_PLATE + - HEAVY_WEIGHTED_PRESSURE_PLATE + - JUNGLE_PRESSURE_PLATE + - LIGHT_WEIGHTED_PRESSURE_PLATE + - OAK_PRESSURE_PLATE + - SPRUCE_PRESSURE_PLATE + - STONE_PRESSURE_PLATE + #redstone + - COMPARATOR + - LEVER + - NOTE_BLOCK + - PISTON + - PISTON_HEAD + - REDSTONE_BLOCK + - REDSTONE_WIRE + - REPEATER + - REDSTONE_TORCH + - REDSTONE_WALL_TORCH + - STICKY_PISTON + - TRIPWIRE_HOOK + #signs + - ACACIA_SIGN + - ACACIA_WALL_SIGN + - BIRCH_SIGN + - BIRCH_WALL_SIGN + - DARK_OAK_SIGN + - DARK_OAK_WALL_SIGN + - JUNGLE_SIGN + - JUNGLE_WALL_SIGN + - OAK_SIGN + - OAK_WALL_SIGN + - SPRUCE_SIGN + - SPRUCE_WALL_SIGN + #slabs + - ACACIA_SLAB + - BIRCH_SLAB + - BRICK_SLAB + - COBBLESTONE_SLAB + - DARK_OAK_SLAB + - DARK_PRISMARINE + - JUNGLE_SLAB + - NETHER_BRICK_SLAB + - OAK_SLAB + - PETRIFIED_OAK_SLAB + - PRISMARINE_SLAB + - PRISMARINE_BRICK_SLAB + - RED_SANDSTONE_SLAB + - QUARTZ_SLAB + - SPRUCE_SLAB + - STONE_SLAB + #stairs + - BIRCH_STAIRS + - JUNGLE_STAIRS + - OAK_STAIRS + - NETHER_BRICK_STAIRS + - SMOOTH_STAIRS + - SPRUCE_STAIRS + - STONE_BRICK_STAIRS + #storage + - CHEST + - DISPENSER + - DROPPER + - HOPPER + - TRAPPED_CHEST + #terracotta + - WHITE_TERRACOTTA + - ORANGE_TERRACOTTA + - MAGENTA_TERRACOTTA + - LIGHT_BLUE_TERRACOTTA + - YELLOW_TERRACOTTA + - LIME_TERRACOTTA + - PINK_TERRACOTTA + - GRAY_TERRACOTTA + - LIGHT_GRAY_TERRACOTTA + - CYAN_TERRACOTTA + - PURPLE_TERRACOTTA + - BLUE_TERRACOTTA + - BROWN_TERRACOTTA + - GREEN_TERRACOTTA + - RED_TERRACOTTA + - BLACK_TERRACOTTA + #trapdoors + - ACACIA_TRAPDOOR + - BIRCH_TRAPDOOR + - DARK_OAK_TRAPDOOR + - JUNGLE_TRAPDOOR + - OAK_TRAPDOOR + - SPRUCE_TRAPDOOR + #weapon blocks + - COAL_BLOCK + #wood + - ACACIA_WOOD + - BIRCH_WOOD + - DARK_OAK_WOOD + - OAK_WOOD + - SPRUCE_WOOD + - STRIPPED_ACACIA_WOOD + - STRIPPED_BIRCH_WOOD + - STRIPPED_DARK_OAK_WOOD + - STRIPPED_OAK_WOOD + - STRIPPED_SPRUCE_WOOD + #wool + - WHITE_WOOL + - ORANGE_WOOL + - MAGENTA_WOOL + - LIGHT_BLUE_WOOL + - YELLOW_WOOL + - LIME_WOOL + - PINK_WOOL + - GRAY_WOOL + - LIGHT_GRAY_WOOL + - CYAN_WOOL + - PURPLE_WOOL + - BLUE_WOOL + - BROWN_WOOL + - GREEN_WOOL + - RED_WOOL + - BLACK_WOOL + +canCruise: true +cruiseSkipBlocks: 4 +canFly: false +sinkPercent: 99.0 +overallSinkPercent: 60.0 +minHeightLimit: 50 +maxHeightLimit: 80 +requireWaterContact: true +allowVerticalMovement: false +speed: 0.5 +tryNudge: false +flyblocks: + 5: + - 25.0 + - 100.0 + 145: # anvils are OP armor, so limit it + - 0.0 + - 1.0 + 49: # so is obsidian + - 0.0 + - 1.0 + 8: # so is water + - 0.0 + - 1.0 diff --git a/modules/Movecraft/src/main/resources/types/1_14/SubAirship.craft b/modules/Movecraft/src/main/resources/types/1_14/SubAirship.craft new file mode 100644 index 000000000..8fce88adf --- /dev/null +++ b/modules/Movecraft/src/main/resources/types/1_14/SubAirship.craft @@ -0,0 +1,306 @@ +name: SubAirship +maxSize: 5000 +minSize: 1000 +allowedBlocks: +#beds + - WHITE_BED + - ORANGE_BED + - MAGENTA_BED + - LIGHT_BLUE_BED + - YELLOW_BED + - LIME_BED + - PINK_BED + - GRAY_BED + - LIGHT_BED + - CYAN_BED + - PURPLE_BED + - BLUE_BED + - BROWN_BED + - GREEN_BED + - RED_BED + - BLACK_BED + #buttons + - ACACIA_BUTTON + - BIRCH_BUTTON + - DARK_OAK_BUTTON + - JUNGLE_BUTTON + - OAK_BUTTON + - SPRUCE_BUTTON + - STONE_BUTTON + #carpets + - WHITE_CARPET + - ORANGE_CARPET + - MAGENTA_CARPET + - LIGHT_BLUE_CARPET + - YELLOW_CARPET + - LIME_CARPET + - PINK_CARPET + - GRAY_CARPET + - LIGHT_CARPET + - CYAN_CARPET + - PURPLE_CARPET + - BLUE_CARPET + - BROWN_CARPET + - GREEN_CARPET + - RED_CARPET + - BLACK_CARPET + #doors + - ACACIA_DOOR + - BIRCH_DOOR + - DARK_OAK_DOOR + - IRON_DOOR + - JUNGLE_DOOR + - OAK_DOOR + - SPRUCE_DOOR + #fences + - ACACIA_FENCE + - BIRCH_FENCE + - DARK_OAK_FENCE + - JUNGLE_FENCE + - OAK_FENCE + - NETHER_BRICK_FENCE + - SPRUCE_FENCE + #fence gates + - ACACIA_FENCE_GATE + - BIRCH_FENCE_GATE + - DARK_OAK_FENCE_GATE + - JUNGLE_FENCE_GATE + - OAK_FENCE_GATE + - SPRUCE_FENCE_GATE + #glass + - GLASS + - WHITE_STAINED_GLASS + - ORANGE_STAINED_GLASS + - MAGENTA_STAINED_GLASS + - LIGHT_BLUE_STAINED_GLASS + - YELLOW_STAINED_GLASS + - LIME_STAINED_GLASS + - PINK_STAINED_GLASS + - GRAY_STAINED_GLASS + - LIGHT_GRAY_STAINED_GLASS + - CYAN_STAINED_GLASS + - PURPLE_STAINED_GLASS + - BLUE_STAINED_GLASS + - BROWN_STAINED_GLASS + - GREEN_STAINED_GLASS + - RED_STAINED_GLASS + - BLACK_STAINED_GLASS + #glass pane + - GLASS_PANE + - WHITE_STAINED_GLASS_PANE + - ORANGE_STAINED_GLASS_PANE + - MAGENTA_STAINED_GLASS_PANE + - LIGHT_BLUE_STAINED_GLASS_PANE + - YELLOW_STAINED_GLASS_PANE + - LIME_STAINED_GLASS_PANE + - PINK_STAINED_GLASS_PANE + - GRAY_STAINED_GLASS_PANE + - LIGHT_GRAY_STAINED_GLASS_PANE + - CYAN_STAINED_GLASS_PANE + - PURPLE_STAINED_GLASS_PANE + - BLUE_STAINED_GLASS_PANE + - BROWN_STAINED_GLASS_PANE + - GREEN_STAINED_GLASS_PANE + - RED_STAINED_GLASS_PANE + - BLACK_STAINED_GLASS_PANE + #liquids + - LAVA + - WATER + #logs + - BIRCH_LOG + - JUNGLE_LOG + - OAK_LOG + - SPRUCE_LOG + - STRIPPED_BIRCH_LOG + - STRIPPED_JUNGLE_LOG + - STRIPPED_OAK_LOG + - STRIPPED_SPRUCE_LOG + #misc + - BOOKSHELF + - BREWING_STAND + - CRAFTING_TABLE + - CAULDRON + - FURNACE + - GLOWSTONE + - IRON_BARS + - LADDER + - NETHER_BRICKS + - TORCH + - WALL_TORCH + #planks + - ACACIA_PLANKS + - BIRCH_PLANKS + - DARK_OAK_PLANKS + - JUNGLE_PLANKS + - OAK_PLANKS + - SPRUCE_PLANKS + #pressure plates + - ACACIA_PRESSURE_PLATE + - BIRCH_PRESSURE_PLATE + - DARK_OAK_PRESSURE_PLATE + - HEAVY_WEIGHTED_PRESSURE_PLATE + - JUNGLE_PRESSURE_PLATE + - LIGHT_WEIGHTED_PRESSURE_PLATE + - OAK_PRESSURE_PLATE + - SPRUCE_PRESSURE_PLATE + - STONE_PRESSURE_PLATE + #redstone + - COMPARATOR + - LEVER + - NOTE_BLOCK + - PISTON + - PISTON_HEAD + - REDSTONE_BLOCK + - REDSTONE_WIRE + - REPEATER + - REDSTONE_TORCH + - REDSTONE_WALL_TORCH + - STICKY_PISTON + - TRIPWIRE_HOOK + #signs + - ACACIA_SIGN + - ACACIA_WALL_SIGN + - BIRCH_SIGN + - BIRCH_WALL_SIGN + - DARK_OAK_SIGN + - DARK_OAK_WALL_SIGN + - JUNGLE_SIGN + - JUNGLE_WALL_SIGN + - OAK_SIGN + - OAK_WALL_SIGN + - SPRUCE_SIGN + - SPRUCE_WALL_SIGN + #slabs + - ACACIA_SLAB + - BIRCH_SLAB + - BRICK_SLAB + - COBBLESTONE_SLAB + - DARK_OAK_SLAB + - DARK_PRISMARINE + - JUNGLE_SLAB + - NETHER_BRICK_SLAB + - OAK_SLAB + - PETRIFIED_OAK_SLAB + - PRISMARINE_SLAB + - PRISMARINE_BRICK_SLAB + - RED_SANDSTONE_SLAB + - QUARTZ_SLAB + - SPRUCE_SLAB + - STONE_SLAB + #stairs + - BIRCH_STAIRS + - JUNGLE_STAIRS + - OAK_STAIRS + - NETHER_BRICK_STAIRS + - SMOOTH_STAIRS + - SPRUCE_STAIRS + - STONE_BRICK_STAIRS + #storage + - CHEST + - DISPENSER + - DROPPER + - HOPPER + - TRAPPED_CHEST + #terracotta + - WHITE_TERRACOTTA + - ORANGE_TERRACOTTA + - MAGENTA_TERRACOTTA + - LIGHT_BLUE_TERRACOTTA + - YELLOW_TERRACOTTA + - LIME_TERRACOTTA + - PINK_TERRACOTTA + - GRAY_TERRACOTTA + - LIGHT_GRAY_TERRACOTTA + - CYAN_TERRACOTTA + - PURPLE_TERRACOTTA + - BLUE_TERRACOTTA + - BROWN_TERRACOTTA + - GREEN_TERRACOTTA + - RED_TERRACOTTA + - BLACK_TERRACOTTA + #trapdoors + - ACACIA_TRAPDOOR + - BIRCH_TRAPDOOR + - DARK_OAK_TRAPDOOR + - JUNGLE_TRAPDOOR + - OAK_TRAPDOOR + - SPRUCE_TRAPDOOR + #weapon blocks + - COAL_BLOCK + #wood + - ACACIA_WOOD + - BIRCH_WOOD + - DARK_OAK_WOOD + - OAK_WOOD + - SPRUCE_WOOD + - STRIPPED_ACACIA_WOOD + - STRIPPED_BIRCH_WOOD + - STRIPPED_DARK_OAK_WOOD + - STRIPPED_OAK_WOOD + - STRIPPED_SPRUCE_WOOD + #wool + - WHITE_WOOL + - ORANGE_WOOL + - MAGENTA_WOOL + - LIGHT_BLUE_WOOL + - YELLOW_WOOL + - LIME_WOOL + - PINK_WOOL + - GRAY_WOOL + - LIGHT_GRAY_WOOL + - CYAN_WOOL + - PURPLE_WOOL + - BLUE_WOOL + - BROWN_WOOL + - GREEN_WOOL + - RED_WOOL + - BLACK_WOOL + +canCruise: true +rotateAtMidpoint: true +cruiseSkipBlocks: 4 +vertCruiseSkipBlocks: 1 +cruiseSpeed: 0.5 +canFly: false +minHeightLimit: 1 +maxHeightLimit: 135 +maxHeightAboveGround: 50 +speed: 1.0 +collisionExplosion: 0.0 +detectionMultiplier: 10.0 +underwaterDetectionMultiplier: 1.0 +fuelBurnRate: 2.0 +tryNudge: false +halfSpeedUnderwater: true +sinkPercent: 99.0 +overallSinkPercent: 60.0 +moveblocks: + 152: # redstone represents engines + - 1.0 + - 100.0 +flyblocks: + IRON_BLOCK: # iron represents ballast tanks + - 10.0 + - 100.0 + [WHITE_WOOL, ORANGE_WOOL, MAGENTA_WOOL,LIGHT_BLUE_WOOL,YELLOW_WOOL,LIME_WOOL,PINK_WOOL,GRAY_WOOL,LIGHT_GRAY_WOOL,CYAN_WOOL,PURPLE_WOOL,BLUE_WOOL,BROWN_WOOL, GREEN_WOOL, RED_WOOL, BLACK_WOOL]: #wool represents lift + - 50.0 + - 100.0 + [CHEST,TRAPPED_CHEST]: # limit chests to make big airships important for merchant missions + - 0.0 + - 1.0 + [DISPENSER,DROPPER,HOPPER]: # dispensers and hoppers can be used for inventory too, so limit them as well + - 0.0 + - 2.0 + FURNACE: # Furnaces for cargo? really guys? + - 0.0 + - N50 + ANVIL: # anvils are OP armor, so limit it + - 0.0 + - 1.0 + OBSIDIAN: # so is obsidian + - 0.0 + - 1.0 + WATER: # so is water + - 0.0 + - 1.0 + diff --git a/modules/Movecraft/src/main/resources/types/1_14/Submarine.craft b/modules/Movecraft/src/main/resources/types/1_14/Submarine.craft new file mode 100644 index 000000000..ce3189fba --- /dev/null +++ b/modules/Movecraft/src/main/resources/types/1_14/Submarine.craft @@ -0,0 +1,283 @@ +name: Submarine +maxSize: 100000 +minSize: 10 +allowedBlocks: + #beds + - WHITE_BED + - ORANGE_BED + - MAGENTA_BED + - LIGHT_BLUE_BED + - YELLOW_BED + - LIME_BED + - PINK_BED + - GRAY_BED + - LIGHT_BED + - CYAN_BED + - PURPLE_BED + - BLUE_BED + - BROWN_BED + - GREEN_BED + - RED_BED + - BLACK_BED + #buttons + - ACACIA_BUTTON + - BIRCH_BUTTON + - DARK_OAK_BUTTON + - JUNGLE_BUTTON + - OAK_BUTTON + - SPRUCE_BUTTON + - STONE_BUTTON + #carpets + - WHITE_CARPET + - ORANGE_CARPET + - MAGENTA_CARPET + - LIGHT_BLUE_CARPET + - YELLOW_CARPET + - LIME_CARPET + - PINK_CARPET + - GRAY_CARPET + - LIGHT_CARPET + - CYAN_CARPET + - PURPLE_CARPET + - BLUE_CARPET + - BROWN_CARPET + - GREEN_CARPET + - RED_CARPET + - BLACK_CARPET + #doors + - ACACIA_DOOR + - BIRCH_DOOR + - DARK_OAK_DOOR + - IRON_DOOR + - JUNGLE_DOOR + - OAK_DOOR + - SPRUCE_DOOR + #fences + - ACACIA_FENCE + - BIRCH_FENCE + - DARK_OAK_FENCE + - JUNGLE_FENCE + - OAK_FENCE + - NETHER_BRICK_FENCE + - SPRUCE_FENCE + #fence gates + - ACACIA_FENCE_GATE + - BIRCH_FENCE_GATE + - DARK_OAK_FENCE_GATE + - JUNGLE_FENCE_GATE + - OAK_FENCE_GATE + - SPRUCE_FENCE_GATE + #glass + - GLASS + - WHITE_STAINED_GLASS + - ORANGE_STAINED_GLASS + - MAGENTA_STAINED_GLASS + - LIGHT_BLUE_STAINED_GLASS + - YELLOW_STAINED_GLASS + - LIME_STAINED_GLASS + - PINK_STAINED_GLASS + - GRAY_STAINED_GLASS + - LIGHT_GRAY_STAINED_GLASS + - CYAN_STAINED_GLASS + - PURPLE_STAINED_GLASS + - BLUE_STAINED_GLASS + - BROWN_STAINED_GLASS + - GREEN_STAINED_GLASS + - RED_STAINED_GLASS + - BLACK_STAINED_GLASS + #glass pane + - GLASS_PANE + - WHITE_STAINED_GLASS_PANE + - ORANGE_STAINED_GLASS_PANE + - MAGENTA_STAINED_GLASS_PANE + - LIGHT_BLUE_STAINED_GLASS_PANE + - YELLOW_STAINED_GLASS_PANE + - LIME_STAINED_GLASS_PANE + - PINK_STAINED_GLASS_PANE + - GRAY_STAINED_GLASS_PANE + - LIGHT_GRAY_STAINED_GLASS_PANE + - CYAN_STAINED_GLASS_PANE + - PURPLE_STAINED_GLASS_PANE + - BLUE_STAINED_GLASS_PANE + - BROWN_STAINED_GLASS_PANE + - GREEN_STAINED_GLASS_PANE + - RED_STAINED_GLASS_PANE + - BLACK_STAINED_GLASS_PANE + #liquids + - LAVA + - WATER + #logs + - BIRCH_LOG + - JUNGLE_LOG + - OAK_LOG + - SPRUCE_LOG + - STRIPPED_BIRCH_LOG + - STRIPPED_JUNGLE_LOG + - STRIPPED_OAK_LOG + - STRIPPED_SPRUCE_LOG + #misc + - BOOKSHELF + - BREWING_STAND + - CRAFTING_TABLE + - CAULDRON + - FURNACE + - GLOWSTONE + - IRON_BARS + - LADDER + - NETHER_BRICKS + - TORCH + - WALL_TORCH + #planks + - ACACIA_PLANKS + - BIRCH_PLANKS + - DARK_OAK_PLANKS + - JUNGLE_PLANKS + - OAK_PLANKS + - SPRUCE_PLANKS + #pressure plates + - ACACIA_PRESSURE_PLATE + - BIRCH_PRESSURE_PLATE + - DARK_OAK_PRESSURE_PLATE + - HEAVY_WEIGHTED_PRESSURE_PLATE + - JUNGLE_PRESSURE_PLATE + - LIGHT_WEIGHTED_PRESSURE_PLATE + - OAK_PRESSURE_PLATE + - SPRUCE_PRESSURE_PLATE + - STONE_PRESSURE_PLATE + #redstone + - COMPARATOR + - LEVER + - NOTE_BLOCK + - PISTON + - PISTON_HEAD + - REDSTONE_BLOCK + - REDSTONE_WIRE + - REPEATER + - REDSTONE_TORCH + - REDSTONE_WALL_TORCH + - STICKY_PISTON + - TRIPWIRE_HOOK + #signs + - ACACIA_SIGN + - ACACIA_WALL_SIGN + - BIRCH_SIGN + - BIRCH_WALL_SIGN + - DARK_OAK_SIGN + - DARK_OAK_WALL_SIGN + - JUNGLE_SIGN + - JUNGLE_WALL_SIGN + - OAK_SIGN + - OAK_WALL_SIGN + - SPRUCE_SIGN + - SPRUCE_WALL_SIGN + #slabs + - ACACIA_SLAB + - BIRCH_SLAB + - BRICK_SLAB + - COBBLESTONE_SLAB + - DARK_OAK_SLAB + - DARK_PRISMARINE + - JUNGLE_SLAB + - NETHER_BRICK_SLAB + - OAK_SLAB + - PETRIFIED_OAK_SLAB + - PRISMARINE_SLAB + - PRISMARINE_BRICK_SLAB + - RED_SANDSTONE_SLAB + - QUARTZ_SLAB + - SPRUCE_SLAB + - STONE_SLAB + #stairs + - BIRCH_STAIRS + - JUNGLE_STAIRS + - OAK_STAIRS + - NETHER_BRICK_STAIRS + - SMOOTH_STAIRS + - SPRUCE_STAIRS + - STONE_BRICK_STAIRS + #storage + - CHEST + - DISPENSER + - DROPPER + - HOPPER + - TRAPPED_CHEST + #terracotta + - WHITE_TERRACOTTA + - ORANGE_TERRACOTTA + - MAGENTA_TERRACOTTA + - LIGHT_BLUE_TERRACOTTA + - YELLOW_TERRACOTTA + - LIME_TERRACOTTA + - PINK_TERRACOTTA + - GRAY_TERRACOTTA + - LIGHT_GRAY_TERRACOTTA + - CYAN_TERRACOTTA + - PURPLE_TERRACOTTA + - BLUE_TERRACOTTA + - BROWN_TERRACOTTA + - GREEN_TERRACOTTA + - RED_TERRACOTTA + - BLACK_TERRACOTTA + #trapdoors + - ACACIA_TRAPDOOR + - BIRCH_TRAPDOOR + - DARK_OAK_TRAPDOOR + - JUNGLE_TRAPDOOR + - OAK_TRAPDOOR + - SPRUCE_TRAPDOOR + #weapon blocks + - COAL_BLOCK + #wood + - ACACIA_WOOD + - BIRCH_WOOD + - DARK_OAK_WOOD + - OAK_WOOD + - SPRUCE_WOOD + - STRIPPED_ACACIA_WOOD + - STRIPPED_BIRCH_WOOD + - STRIPPED_DARK_OAK_WOOD + - STRIPPED_OAK_WOOD + - STRIPPED_SPRUCE_WOOD + #wool + - WHITE_WOOL + - ORANGE_WOOL + - MAGENTA_WOOL + - LIGHT_BLUE_WOOL + - YELLOW_WOOL + - LIME_WOOL + - PINK_WOOL + - GRAY_WOOL + - LIGHT_GRAY_WOOL + - CYAN_WOOL + - PURPLE_WOOL + - BLUE_WOOL + - BROWN_WOOL + - GREEN_WOOL + - RED_WOOL + - BLACK_WOOL + +canCruise: true +cruiseSkipBlocks: 4 +canFly: false +minHeightLimit: 10 +maxHeightLimit: 67 +sinkPercent: 99.0 +overallSinkPercent: 60.0 +speed: 0.5 +requireWaterContact: true +allowVerticalMovement: true +fuelBurnRate: 1.0 +tryNudge: false +flyblocks: + [ACACIA_PLANKS, BIRCH_PLANKS, DARK_OAK_PLANKS, JUNGLE_PLANKS, OAK_PLANKS, SPRUCE_PLANKS]: + - 25.0 + - 100.0 + ANVIL: # anvils are OP armor, so limit it + - 0.0 + - 1.0 + OBSIDIAN: # so is obsidian + - 0.0 + - 1.0 + IRON_BLOCK: + - 15.0 + - 100.0 \ No newline at end of file diff --git a/modules/Movecraft/src/main/resources/types/1_14/Turret.craft b/modules/Movecraft/src/main/resources/types/1_14/Turret.craft new file mode 100644 index 000000000..15cc0d687 --- /dev/null +++ b/modules/Movecraft/src/main/resources/types/1_14/Turret.craft @@ -0,0 +1,210 @@ +name: Turret +maxSize: 1000 +minSize: 1 +allowedBlocks: + #beds + - WHITE_BED + - ORANGE_BED + - MAGENTA_BED + - LIGHT_BLUE_BED + - YELLOW_BED + - LIME_BED + - PINK_BED + - GRAY_BED + - LIGHT_BED + - CYAN_BED + - PURPLE_BED + - BLUE_BED + - BROWN_BED + - GREEN_BED + - RED_BED + - BLACK_BED + #buttons + - ACACIA_BUTTON + - BIRCH_BUTTON + - DARK_OAK_BUTTON + - JUNGLE_BUTTON + - OAK_BUTTON + - SPRUCE_BUTTON + - STONE_BUTTON + #doors + - ACACIA_DOOR + - BIRCH_DOOR + - DARK_OAK_DOOR + - IRON_DOOR + - JUNGLE_DOOR + - OAK_DOOR + - SPRUCE_DOOR + #fences + - ACACIA_FENCE + - BIRCH_FENCE + - DARK_OAK_FENCE + - JUNGLE_FENCE + - OAK_FENCE + - SPRUCE_FENCE + #fence gates + - ACACIA_FENCE_GATE + - BIRCH_FENCE_GATE + - DARK_OAK_FENCE_GATE + - JUNGLE_FENCE_GATE + - OAK_FENCE_GATE + - SPRUCE_FENCE_GATE + #glass + - GLASS + - WHITE_STAINED_GLASS + - ORANGE_STAINED_GLASS + - MAGENTA_STAINED_GLASS + - LIGHT_BLUE_STAINED_GLASS + - YELLOW_STAINED_GLASS + - LIME_STAINED_GLASS + - PINK_STAINED_GLASS + - GRAY_STAINED_GLASS + - LIGHT_GRAY_STAINED_GLASS + - CYAN_STAINED_GLASS + - PURPLE_STAINED_GLASS + - BLUE_STAINED_GLASS + - BROWN_STAINED_GLASS + - GREEN_STAINED_GLASS + - RED_STAINED_GLASS + - BLACK_STAINED_GLASS + #glass pane + - GLASS_PANE + - WHITE_STAINED_GLASS_PANE + - ORANGE_STAINED_GLASS_PANE + - MAGENTA_STAINED_GLASS_PANE + - LIGHT_BLUE_STAINED_GLASS_PANE + - YELLOW_STAINED_GLASS_PANE + - LIME_STAINED_GLASS_PANE + - PINK_STAINED_GLASS_PANE + - GRAY_STAINED_GLASS_PANE + - LIGHT_GRAY_STAINED_GLASS_PANE + - CYAN_STAINED_GLASS_PANE + - PURPLE_STAINED_GLASS_PANE + - BLUE_STAINED_GLASS_PANE + - BROWN_STAINED_GLASS_PANE + - GREEN_STAINED_GLASS_PANE + - RED_STAINED_GLASS_PANE + - BLACK_STAINED_GLASS_PANE + #interior + - BOOKSHELF + - BREWING_STAND + - CAULDRON + - IRON_BARS + - SIGN + - TORCH + - WALL_SIGN + - WALL_TORCH + #liquids + - LAVA + - WATER + #logs + - BIRCH_LOG + - JUNGLE_LOG + - OAK_LOG + - SPRUCE_LOG + - STRIPPED_BIRCH_LOG + - STRIPPED_JUNGLE_LOG + - STRIPPED_OAK_LOG + - STRIPPED_SPRUCE_LOG + #planks + - ACACIA_PLANKS + - BIRCH_PLANKS + - DARK_OAK_PLANKS + - JUNGLE_PLANKS + - OAK_PLANKS + - SPRUCE_PLANKS + #pressure plates + - ACACIA_PRESSURE_PLATE + - BIRCH_PRESSURE_PLATE + - DARK_OAK_PRESSURE_PLATE + - HEAVY_WEIGHTED_PRESSURE_PLATE + - JUNGLE_PRESSURE_PLATE + - LIGHT_WEIGHTED_PRESSURE_PLATE + - OAK_PRESSURE_PLATE + - SPRUCE_PRESSURE_PLATE + #redstone + - COMPARATOR + - NOTE_BLOCK + - PISTON + - PISTON_HEAD + - REDSTONE_BLOCK + - REDSTONE_WIRE + - REPEATER + - STICKY_PISTON + - TRIPWIRE_HOOK + #slabs + - ACACIA_SLAB + - BIRCH_SLAB + - BRICK_SLAB + - COBBLESTONE_SLAB + - DARK_OAK_SLAB + - DARK_PRISMARINE + - JUNGLE_SLAB + - NETHER_BRICK_SLAB + - OAK_SLAB + - PETRIFIED_OAK_SLAB + - PRISMARINE_SLAB + - PRISMARINE_BRICK_SLAB + - RED_SANDSTONE_SLAB + - QUARTZ_SLAB + - SPRUCE_SLAB + - STONE_SLAB + #stairs + - BIRCH_STAIRS + - JUNGLE_STAIRS + - OAK_STAIRS + - SMOOTH_STAIRS + - SPRUCE_STAIRS + #storage + - CHEST + - DISPENSER + - DROPPER + - HOPPER + - TRAPPED_CHEST + #terracotta + - GRAY_TERRACOTTA + - LIGHT_GRAY_TERRACOTTA + - BLACK_TERRACOTTA + #trapdoors + - ACACIA_TRAPDOOR + - BIRCH_TRAPDOOR + - DARK_OAK_TRAPDOOR + - JUNGLE_TRAPDOOR + - OAK_TRAPDOOR + - SPRUCE_TRAPDOOR + #weapon blocks + - COAL_BLOCK + #wood + - ACACIA_WOOD + - BIRCH_WOOD + - DARK_OAK_WOOD + - OAK_WOOD + - SPRUCE_WOOD + - STRIPPED_ACACIA_WOOD + - STRIPPED_BIRCH_WOOD + - STRIPPED_DARK_OAK_WOOD + - STRIPPED_OAK_WOOD + - STRIPPED_SPRUCE_WOOD + #wool + - LIGHT_GRAY_WOOL + +forbiddenBlocks: + - PISTON_HEAD + + +canFly: true +canCruise: false +maxHeightLimit: 144 +collisionExplosion: 0.0 +explodeOnCrash: 2.0 +allowHorizontalMovement: false +allowVerticalMovement: false +allowCannonDirectorSign: true +allowAADirectorSign: true +speed: 1.0 +tryNudge: false +sinkPercent: 99.0 +flyblocks: + LIGHT_GRAY_WOOL: + - 0.0 + - 100.0 diff --git a/modules/Movecraft/src/main/resources/types/1_14/airship.craft b/modules/Movecraft/src/main/resources/types/1_14/airship.craft new file mode 100644 index 000000000..cc67fada7 --- /dev/null +++ b/modules/Movecraft/src/main/resources/types/1_14/airship.craft @@ -0,0 +1,302 @@ +name: Airship +maxSize: 5000 +minSize: 1000 +allowedBlocks: + #beds + - WHITE_BED + - ORANGE_BED + - MAGENTA_BED + - LIGHT_BLUE_BED + - YELLOW_BED + - LIME_BED + - PINK_BED + - GRAY_BED + - LIGHT_BED + - CYAN_BED + - PURPLE_BED + - BLUE_BED + - BROWN_BED + - GREEN_BED + - RED_BED + - BLACK_BED + #buttons + - ACACIA_BUTTON + - BIRCH_BUTTON + - DARK_OAK_BUTTON + - JUNGLE_BUTTON + - OAK_BUTTON + - SPRUCE_BUTTON + - STONE_BUTTON + #carpets + - WHITE_CARPET + - ORANGE_CARPET + - MAGENTA_CARPET + - LIGHT_BLUE_CARPET + - YELLOW_CARPET + - LIME_CARPET + - PINK_CARPET + - GRAY_CARPET + - LIGHT_CARPET + - CYAN_CARPET + - PURPLE_CARPET + - BLUE_CARPET + - BROWN_CARPET + - GREEN_CARPET + - RED_CARPET + - BLACK_CARPET + #doors + - ACACIA_DOOR + - BIRCH_DOOR + - DARK_OAK_DOOR + - IRON_DOOR + - JUNGLE_DOOR + - OAK_DOOR + - SPRUCE_DOOR + #fences + - ACACIA_FENCE + - BIRCH_FENCE + - DARK_OAK_FENCE + - JUNGLE_FENCE + - OAK_FENCE + - NETHER_BRICK_FENCE + - SPRUCE_FENCE + #fence gates + - ACACIA_FENCE_GATE + - BIRCH_FENCE_GATE + - DARK_OAK_FENCE_GATE + - JUNGLE_FENCE_GATE + - OAK_FENCE_GATE + - SPRUCE_FENCE_GATE + #glass + - GLASS + - WHITE_STAINED_GLASS + - ORANGE_STAINED_GLASS + - MAGENTA_STAINED_GLASS + - LIGHT_BLUE_STAINED_GLASS + - YELLOW_STAINED_GLASS + - LIME_STAINED_GLASS + - PINK_STAINED_GLASS + - GRAY_STAINED_GLASS + - LIGHT_GRAY_STAINED_GLASS + - CYAN_STAINED_GLASS + - PURPLE_STAINED_GLASS + - BLUE_STAINED_GLASS + - BROWN_STAINED_GLASS + - GREEN_STAINED_GLASS + - RED_STAINED_GLASS + - BLACK_STAINED_GLASS + #glass pane + - GLASS_PANE + - WHITE_STAINED_GLASS_PANE + - ORANGE_STAINED_GLASS_PANE + - MAGENTA_STAINED_GLASS_PANE + - LIGHT_BLUE_STAINED_GLASS_PANE + - YELLOW_STAINED_GLASS_PANE + - LIME_STAINED_GLASS_PANE + - PINK_STAINED_GLASS_PANE + - GRAY_STAINED_GLASS_PANE + - LIGHT_GRAY_STAINED_GLASS_PANE + - CYAN_STAINED_GLASS_PANE + - PURPLE_STAINED_GLASS_PANE + - BLUE_STAINED_GLASS_PANE + - BROWN_STAINED_GLASS_PANE + - GREEN_STAINED_GLASS_PANE + - RED_STAINED_GLASS_PANE + - BLACK_STAINED_GLASS_PANE + #liquids + - LAVA + - WATER + #logs + - BIRCH_LOG + - JUNGLE_LOG + - OAK_LOG + - SPRUCE_LOG + - STRIPPED_BIRCH_LOG + - STRIPPED_JUNGLE_LOG + - STRIPPED_OAK_LOG + - STRIPPED_SPRUCE_LOG + #misc + - BOOKSHELF + - BREWING_STAND + - CRAFTING_TABLE + - CAULDRON + - FURNACE + - GLOWSTONE + - IRON_BARS + - LADDER + - NETHER_BRICKS + - TORCH + - WALL_TORCH + #planks + - ACACIA_PLANKS + - BIRCH_PLANKS + - DARK_OAK_PLANKS + - JUNGLE_PLANKS + - OAK_PLANKS + - SPRUCE_PLANKS + #pressure plates + - ACACIA_PRESSURE_PLATE + - BIRCH_PRESSURE_PLATE + - DARK_OAK_PRESSURE_PLATE + - HEAVY_WEIGHTED_PRESSURE_PLATE + - JUNGLE_PRESSURE_PLATE + - LIGHT_WEIGHTED_PRESSURE_PLATE + - OAK_PRESSURE_PLATE + - SPRUCE_PRESSURE_PLATE + - STONE_PRESSURE_PLATE + #redstone + - COMPARATOR + - LEVER + - NOTE_BLOCK + - PISTON + - PISTON_HEAD + - REDSTONE_BLOCK + - REDSTONE_WIRE + - REPEATER + - REDSTONE_TORCH + - REDSTONE_WALL_TORCH + - STICKY_PISTON + - TRIPWIRE_HOOK + #signs + - ACACIA_SIGN + - ACACIA_WALL_SIGN + - BIRCH_SIGN + - BIRCH_WALL_SIGN + - DARK_OAK_SIGN + - DARK_OAK_WALL_SIGN + - JUNGLE_SIGN + - JUNGLE_WALL_SIGN + - OAK_SIGN + - OAK_WALL_SIGN + - SPRUCE_SIGN + - SPRUCE_WALL_SIGN + #slabs + - ACACIA_SLAB + - BIRCH_SLAB + - BRICK_SLAB + - COBBLESTONE_SLAB + - DARK_OAK_SLAB + - DARK_PRISMARINE + - JUNGLE_SLAB + - NETHER_BRICK_SLAB + - OAK_SLAB + - PETRIFIED_OAK_SLAB + - PRISMARINE_SLAB + - PRISMARINE_BRICK_SLAB + - RED_SANDSTONE_SLAB + - QUARTZ_SLAB + - SPRUCE_SLAB + - STONE_SLAB + #stairs + - BIRCH_STAIRS + - JUNGLE_STAIRS + - OAK_STAIRS + - NETHER_BRICK_STAIRS + - SMOOTH_STAIRS + - SPRUCE_STAIRS + - STONE_BRICK_STAIRS + #storage + - CHEST + - DISPENSER + - DROPPER + - HOPPER + - TRAPPED_CHEST + #terracotta + - WHITE_TERRACOTTA + - ORANGE_TERRACOTTA + - MAGENTA_TERRACOTTA + - LIGHT_BLUE_TERRACOTTA + - YELLOW_TERRACOTTA + - LIME_TERRACOTTA + - PINK_TERRACOTTA + - GRAY_TERRACOTTA + - LIGHT_GRAY_TERRACOTTA + - CYAN_TERRACOTTA + - PURPLE_TERRACOTTA + - BLUE_TERRACOTTA + - BROWN_TERRACOTTA + - GREEN_TERRACOTTA + - RED_TERRACOTTA + - BLACK_TERRACOTTA + #trapdoors + - ACACIA_TRAPDOOR + - BIRCH_TRAPDOOR + - DARK_OAK_TRAPDOOR + - JUNGLE_TRAPDOOR + - OAK_TRAPDOOR + - SPRUCE_TRAPDOOR + #weapon blocks + - COAL_BLOCK + #wood + - ACACIA_WOOD + - BIRCH_WOOD + - DARK_OAK_WOOD + - OAK_WOOD + - SPRUCE_WOOD + - STRIPPED_ACACIA_WOOD + - STRIPPED_BIRCH_WOOD + - STRIPPED_DARK_OAK_WOOD + - STRIPPED_OAK_WOOD + - STRIPPED_SPRUCE_WOOD + #wool + - WHITE_WOOL + - ORANGE_WOOL + - MAGENTA_WOOL + - LIGHT_BLUE_WOOL + - YELLOW_WOOL + - LIME_WOOL + - PINK_WOOL + - GRAY_WOOL + - LIGHT_GRAY_WOOL + - CYAN_WOOL + - PURPLE_WOOL + - BLUE_WOOL + - BROWN_WOOL + - GREEN_WOOL + - RED_WOOL + - BLACK_WOOL + +canCruise: true +rotateAtMidpoint: true +canFly: true +maxHeightLimit: 135 +maxHeightAboveGround: 50 +vertCruiseSkipBlocks: 1 +collisionExplosion: 0.0 +detectionMultiplier: 10.0 +underwaterDetectionMultiplier: 1.0 +speed: 1.0 +cruiseSkipBlocks: 4 +cruiseSpeed: 0.5 +fuelBurnRate: 2.0 +sinkPercent: 99.0 +overallSinkPercent: 60.0 +tryNudge: false +canStaticMove: true +maxStaticMove: 2 +moveblocks: + 152: # redstone represents engines + - 1.0 + - 100.0 +flyblocks: + [WHITE_WOOL, ORANGE_WOOL, MAGENTA_WOOL,LIGHT_BLUE_WOOL,YELLOW_WOOL,LIME_WOOL,PINK_WOOL,GRAY_WOOL,LIGHT_GRAY_WOOL,CYAN_WOOL,PURPLE_WOOL,BLUE_WOOL,BROWN_WOOL, GREEN_WOOL, RED_WOOL, BLACK_WOOL]: #wool represents lift + - 50.0 + - 100.0 + [CHEST,TRAPPED_CHEST]: # limit chests to make big airships important for merchant missions + - 0.0 + - 1.0 + [DISPENSER,DROPPER,HOPPER]: # dispensers and hoppers can be used for inventory too, so limit them as well + - 0.0 + - 2.0 + FURNACE: # Furnaces for cargo? really guys? + - 0.0 + - N50 + ANVIL: # anvils are OP armor, so limit it + - 0.0 + - 1.0 + OBSIDIAN: # so is obsidian + - 0.0 + - 1.0 + WATER: # so is water + - 0.0 + - 1.0 diff --git a/modules/Movecraft/src/main/resources/types/1_14/airskiff.craft b/modules/Movecraft/src/main/resources/types/1_14/airskiff.craft new file mode 100644 index 000000000..2b60ac25d --- /dev/null +++ b/modules/Movecraft/src/main/resources/types/1_14/airskiff.craft @@ -0,0 +1,260 @@ +name: Airskiff +maxSize: 80 +minSize: 10 +allowedBlocks: + #beds + - WHITE_BED + - ORANGE_BED + - MAGENTA_BED + - LIGHT_BLUE_BED + - YELLOW_BED + - LIME_BED + - PINK_BED + - GRAY_BED + - LIGHT_BED + - CYAN_BED + - PURPLE_BED + - BLUE_BED + - BROWN_BED + - GREEN_BED + - RED_BED + - BLACK_BED + #buttons + - ACACIA_BUTTON + - BIRCH_BUTTON + - DARK_OAK_BUTTON + - JUNGLE_BUTTON + - OAK_BUTTON + - SPRUCE_BUTTON + - STONE_BUTTON + #doors + - ACACIA_DOOR + - BIRCH_DOOR + - DARK_OAK_DOOR + - IRON_DOOR + - JUNGLE_DOOR + - OAK_DOOR + - SPRUCE_DOOR + #fences + - ACACIA_FENCE + - BIRCH_FENCE + - DARK_OAK_FENCE + - JUNGLE_FENCE + - OAK_FENCE + - SPRUCE_FENCE + #fence gates + - ACACIA_FENCE_GATE + - BIRCH_FENCE_GATE + - DARK_OAK_FENCE_GATE + - JUNGLE_FENCE_GATE + - OAK_FENCE_GATE + - SPRUCE_FENCE_GATE + #glass + - GLASS + - WHITE_STAINED_GLASS + - ORANGE_STAINED_GLASS + - MAGENTA_STAINED_GLASS + - LIGHT_BLUE_STAINED_GLASS + - YELLOW_STAINED_GLASS + - LIME_STAINED_GLASS + - PINK_STAINED_GLASS + - GRAY_STAINED_GLASS + - LIGHT_GRAY_STAINED_GLASS + - CYAN_STAINED_GLASS + - PURPLE_STAINED_GLASS + - BLUE_STAINED_GLASS + - BROWN_STAINED_GLASS + - GREEN_STAINED_GLASS + - RED_STAINED_GLASS + - BLACK_STAINED_GLASS + #glass pane + - GLASS_PANE + - WHITE_STAINED_GLASS_PANE + - ORANGE_STAINED_GLASS_PANE + - MAGENTA_STAINED_GLASS_PANE + - LIGHT_BLUE_STAINED_GLASS_PANE + - YELLOW_STAINED_GLASS_PANE + - LIME_STAINED_GLASS_PANE + - PINK_STAINED_GLASS_PANE + - GRAY_STAINED_GLASS_PANE + - LIGHT_GRAY_STAINED_GLASS_PANE + - CYAN_STAINED_GLASS_PANE + - PURPLE_STAINED_GLASS_PANE + - BLUE_STAINED_GLASS_PANE + - BROWN_STAINED_GLASS_PANE + - GREEN_STAINED_GLASS_PANE + - RED_STAINED_GLASS_PANE + - BLACK_STAINED_GLASS_PANE + #interior + - BOOKSHELF + - BREWING_STAND + - CAULDRON + - IRON_BARS + - TORCH + - WALL_TORCH + #liquids + - LAVA + - WATER + #logs + - BIRCH_LOG + - JUNGLE_LOG + - OAK_LOG + - SPRUCE_LOG + - STRIPPED_BIRCH_LOG + - STRIPPED_JUNGLE_LOG + - STRIPPED_OAK_LOG + - STRIPPED_SPRUCE_LOG + #planks + - ACACIA_PLANKS + - BIRCH_PLANKS + - DARK_OAK_PLANKS + - JUNGLE_PLANKS + - OAK_PLANKS + - SPRUCE_PLANKS + #pressure plates + - ACACIA_PRESSURE_PLATE + - BIRCH_PRESSURE_PLATE + - DARK_OAK_PRESSURE_PLATE + - HEAVY_WEIGHTED_PRESSURE_PLATE + - JUNGLE_PRESSURE_PLATE + - LIGHT_WEIGHTED_PRESSURE_PLATE + - OAK_PRESSURE_PLATE + - SPRUCE_PRESSURE_PLATE + #redstone + - COMPARATOR + - NOTE_BLOCK + - PISTON + - PISTON_HEAD + - REDSTONE_BLOCK + - REDSTONE_WIRE + - REPEATER + - REDSTONE_TORCH + - REDSTONE_WALL_TORCH + - STICKY_PISTON + - TRIPWIRE_HOOK + #signs + - ACACIA_SIGN + - ACACIA_WALL_SIGN + - BIRCH_SIGN + - BIRCH_WALL_SIGN + - DARK_OAK_SIGN + - DARK_OAK_WALL_SIGN + - JUNGLE_SIGN + - JUNGLE_WALL_SIGN + - OAK_SIGN + - OAK_WALL_SIGN + - SPRUCE_SIGN + - SPRUCE_WALL_SIGN + #slabs + - ACACIA_SLAB + - BIRCH_SLAB + - BRICK_SLAB + - COBBLESTONE_SLAB + - DARK_OAK_SLAB + - DARK_PRISMARINE + - JUNGLE_SLAB + - NETHER_BRICK_SLAB + - OAK_SLAB + - PETRIFIED_OAK_SLAB + - PRISMARINE_SLAB + - PRISMARINE_BRICK_SLAB + - RED_SANDSTONE_SLAB + - QUARTZ_SLAB + - SPRUCE_SLAB + - STONE_SLAB + #stairs + - BIRCH_STAIRS + - JUNGLE_STAIRS + - OAK_STAIRS + - SMOOTH_STAIRS + - SPRUCE_STAIRS + #storage + - CHEST + - DISPENSER + - DROPPER + - HOPPER + - TRAPPED_CHEST + #trapdoors + - ACACIA_TRAPDOOR + - BIRCH_TRAPDOOR + - DARK_OAK_TRAPDOOR + - JUNGLE_TRAPDOOR + - OAK_TRAPDOOR + - SPRUCE_TRAPDOOR + #weapon blocks + - COAL_BLOCK + #wood + - ACACIA_WOOD + - BIRCH_WOOD + - DARK_OAK_WOOD + - OAK_WOOD + - SPRUCE_WOOD + - STRIPPED_ACACIA_WOOD + - STRIPPED_BIRCH_WOOD + - STRIPPED_DARK_OAK_WOOD + - STRIPPED_OAK_WOOD + - STRIPPED_SPRUCE_WOOD + #wool + - WHITE_WOOL + - ORANGE_WOOL + - MAGENTA_WOOL + - LIGHT_BLUE_WOOL + - YELLOW_WOOL + - LIME_WOOL + - PINK_WOOL + - GRAY_WOOL + - LIGHT_GRAY_WOOL + - CYAN_WOOL + - PURPLE_WOOL + - BLUE_WOOL + - BROWN_WOOL + - GREEN_WOOL + - RED_WOOL + - BLACK_WOOL + +forbiddenBlocks: + - PISTON_HEAD + +canFly: true +rotateAtMidpoint: true +allowCannonDirectorSign: false +allowAADirectorSign: false +canCruise: true +cruiseSpeed: 1.5 +cruiseSkipBlocks: 1 +maxHeightLimit: 130 +maxHeightAboveGround: 46 +collisionExplosion: 0.0 +fuelBurnRate: 1.0 +explodeOnCrash: 2.0 +sinkSpeed: 3.0 +overallSinkPercent: 97.0 +detectionMultiplier: 20.0 +underwaterDetectionMultiplier: 2.0 +smokeOnSink: 1 +keepMovingOnSink: true +speed: 3.0 +tryNudge: false +sinkPercent: 99.0 +flyblocks: + [WHITE_WOOL, ORANGE_WOOL, MAGENTA_WOOL,LIGHT_BLUE_WOOL,YELLOW_WOOL,LIME_WOOL,PINK_WOOL,GRAY_WOOL,LIGHT_GRAY_WOOL,CYAN_WOOL,PURPLE_WOOL,BLUE_WOOL,BROWN_WOOL, GREEN_WOOL, RED_WOOL, BLACK_WOOL]: #wool represents lift + - 50.0 + - 100.0 + [CHEST,TRAPPED_CHEST]: # limit chests to make big airships important for merchant missions + - 0.0 + - N2 + [DISPENSER,HOPPER]: # dispensers and hoppers can be used for inventory too, so limit them as well + - 0.0 + - 6.0 + REDSTONE_BLOCK: # redstone represents engines + - 8.0 + - 100.0 + ANVIL: # anvils are OP armor, so limit it + - 0.0 + - 1.0 + OBSIDIAN: # so is obsidian + - 0.0 + - 1.0 + WATER: # so is water + - 0.0 + - 1.0 diff --git a/modules/Movecraft/src/main/resources/types/1_14/elevator.craft b/modules/Movecraft/src/main/resources/types/1_14/elevator.craft new file mode 100644 index 000000000..8ebe8d222 --- /dev/null +++ b/modules/Movecraft/src/main/resources/types/1_14/elevator.craft @@ -0,0 +1,223 @@ +name: elevator +maxSize: 1000 +minSize: 10 +allowedBlocks: + #beds + - WHITE_BED + - ORANGE_BED + - MAGENTA_BED + - LIGHT_BLUE_BED + - YELLOW_BED + - LIME_BED + - PINK_BED + - GRAY_BED + - LIGHT_BED + - CYAN_BED + - PURPLE_BED + - BLUE_BED + - BROWN_BED + - GREEN_BED + - RED_BED + - BLACK_BED + #buttons + - ACACIA_BUTTON + - BIRCH_BUTTON + - DARK_OAK_BUTTON + - JUNGLE_BUTTON + - OAK_BUTTON + - SPRUCE_BUTTON + - STONE_BUTTON + #doors + - ACACIA_DOOR + - BIRCH_DOOR + - DARK_OAK_DOOR + - IRON_DOOR + - JUNGLE_DOOR + - OAK_DOOR + - SPRUCE_DOOR + #fences + - ACACIA_FENCE + - BIRCH_FENCE + - DARK_OAK_FENCE + - JUNGLE_FENCE + - OAK_FENCE + - SPRUCE_FENCE + #fence gates + - ACACIA_FENCE_GATE + - BIRCH_FENCE_GATE + - DARK_OAK_FENCE_GATE + - JUNGLE_FENCE_GATE + - OAK_FENCE_GATE + - SPRUCE_FENCE_GATE + #glass + - GLASS + - WHITE_STAINED_GLASS + - ORANGE_STAINED_GLASS + - MAGENTA_STAINED_GLASS + - LIGHT_BLUE_STAINED_GLASS + - YELLOW_STAINED_GLASS + - LIME_STAINED_GLASS + - PINK_STAINED_GLASS + - GRAY_STAINED_GLASS + - LIGHT_GRAY_STAINED_GLASS + - CYAN_STAINED_GLASS + - PURPLE_STAINED_GLASS + - BLUE_STAINED_GLASS + - BROWN_STAINED_GLASS + - GREEN_STAINED_GLASS + - RED_STAINED_GLASS + - BLACK_STAINED_GLASS + #glass pane + - GLASS_PANE + - WHITE_STAINED_GLASS_PANE + - ORANGE_STAINED_GLASS_PANE + - MAGENTA_STAINED_GLASS_PANE + - LIGHT_BLUE_STAINED_GLASS_PANE + - YELLOW_STAINED_GLASS_PANE + - LIME_STAINED_GLASS_PANE + - PINK_STAINED_GLASS_PANE + - GRAY_STAINED_GLASS_PANE + - LIGHT_GRAY_STAINED_GLASS_PANE + - CYAN_STAINED_GLASS_PANE + - PURPLE_STAINED_GLASS_PANE + - BLUE_STAINED_GLASS_PANE + - BROWN_STAINED_GLASS_PANE + - GREEN_STAINED_GLASS_PANE + - RED_STAINED_GLASS_PANE + - BLACK_STAINED_GLASS_PANE + #interior + - BOOKSHELF + - BREWING_STAND + - CAULDRON + - IRON_BARS + - SIGN + - TORCH + - WALL_SIGN + - WALL_TORCH + #liquids + - LAVA + - WATER + #logs + - BIRCH_LOG + - JUNGLE_LOG + - OAK_LOG + - SPRUCE_LOG + - STRIPPED_BIRCH_LOG + - STRIPPED_JUNGLE_LOG + - STRIPPED_OAK_LOG + - STRIPPED_SPRUCE_LOG + #planks + - ACACIA_PLANKS + - BIRCH_PLANKS + - DARK_OAK_PLANKS + - JUNGLE_PLANKS + - OAK_PLANKS + - SPRUCE_PLANKS + #pressure plates + - ACACIA_PRESSURE_PLATE + - BIRCH_PRESSURE_PLATE + - DARK_OAK_PRESSURE_PLATE + - HEAVY_WEIGHTED_PRESSURE_PLATE + - JUNGLE_PRESSURE_PLATE + - LIGHT_WEIGHTED_PRESSURE_PLATE + - OAK_PRESSURE_PLATE + - SPRUCE_PRESSURE_PLATE + #redstone + - COMPARATOR + - NOTE_BLOCK + - PISTON + - PISTON_HEAD + - REDSTONE_BLOCK + - REDSTONE_WIRE + - REPEATER + - REDSTONE_TORCH + - REDSTONE_WALL_TORCH + - STICKY_PISTON + - TRIPWIRE_HOOK + #slabs + - ACACIA_SLAB + - BIRCH_SLAB + - BRICK_SLAB + - COBBLESTONE_SLAB + - DARK_OAK_SLAB + - DARK_PRISMARINE + - JUNGLE_SLAB + - NETHER_BRICK_SLAB + - OAK_SLAB + - PETRIFIED_OAK_SLAB + - PRISMARINE_SLAB + - PRISMARINE_BRICK_SLAB + - RED_SANDSTONE_SLAB + - QUARTZ_SLAB + - SPRUCE_SLAB + - STONE_SLAB + #stairs + - BIRCH_STAIRS + - JUNGLE_STAIRS + - OAK_STAIRS + - SMOOTH_STAIRS + - SPRUCE_STAIRS + #storage + - CHEST + - DISPENSER + - DROPPER + - HOPPER + - TRAPPED_CHEST + #trapdoors + - ACACIA_TRAPDOOR + - BIRCH_TRAPDOOR + - DARK_OAK_TRAPDOOR + - JUNGLE_TRAPDOOR + - OAK_TRAPDOOR + - SPRUCE_TRAPDOOR + #weapon blocks + - COAL_BLOCK + #wood + - ACACIA_WOOD + - BIRCH_WOOD + - DARK_OAK_WOOD + - OAK_WOOD + - SPRUCE_WOOD + - STRIPPED_ACACIA_WOOD + - STRIPPED_BIRCH_WOOD + - STRIPPED_DARK_OAK_WOOD + - STRIPPED_OAK_WOOD + - STRIPPED_SPRUCE_WOOD + #wool + - WHITE_WOOL + - ORANGE_WOOL + - MAGENTA_WOOL + - LIGHT_BLUE_WOOL + - YELLOW_WOOL + - LIME_WOOL + - PINK_WOOL + - GRAY_WOOL + - LIGHT_GRAY_WOOL + - CYAN_WOOL + - PURPLE_WOOL + - BLUE_WOOL + - BROWN_WOOL + - GREEN_WOOL + - RED_WOOL + - BLACK_WOOL + +forbiddenBlocks: + - PISTON_HEAD + +canFly: true +canCruise: false +collisionExplosion: 0.0 +allowHorizontalMovement: false +canStaticMove: true +maxStaticMove: 2 +allowCannonDirectorSign: false +detectionMultiplier: 30.0 +underwaterDetectionMultiplier: 3.0 +allowAADirectorSign: false +speed: 1.0 +tryNudge: false +sinkPercent: 99.0 +flyblocks: + [WHITE_WOOL, ORANGE_WOOL, MAGENTA_WOOL,LIGHT_BLUE_WOOL,YELLOW_WOOL,LIME_WOOL,PINK_WOOL,GRAY_WOOL,LIGHT_GRAY_WOOL,CYAN_WOOL,PURPLE_WOOL,BLUE_WOOL,BROWN_WOOL, GREEN_WOOL, RED_WOOL, BLACK_WOOL]: #wool represents lift + - 0.0 + - 100.0 \ No newline at end of file diff --git a/modules/Movecraft/src/main/resources/types/BigAirship.craft b/modules/Movecraft/src/main/resources/types/BigAirship.craft index 34b029b58..3ac283a8a 100644 --- a/modules/Movecraft/src/main/resources/types/BigAirship.craft +++ b/modules/Movecraft/src/main/resources/types/BigAirship.craft @@ -2,225 +2,249 @@ name: BigAirship maxSize: 20000 minSize: 10000 allowedBlocks: - #beds - - WHITE_BED - - ORANGE_BED - - MAGENTA_BED - - LIGHT_BLUE_BED - - YELLOW_BED - - LIME_BED - - PINK_BED - - GRAY_BED - - LIGHT_BED - - CYAN_BED - - PURPLE_BED - - BLUE_BED - - BROWN_BED - - GREEN_BED - - RED_BED - - BLACK_BED - #buttons - - ACACIA_BUTTON - - BIRCH_BUTTON - - DARK_OAK_BUTTON - - JUNGLE_BUTTON - - OAK_BUTTON - - SPRUCE_BUTTON - - STONE_BUTTON - #doors - - ACACIA_DOOR - - BIRCH_DOOR - - DARK_OAK_DOOR - - IRON_DOOR - - JUNGLE_DOOR - - OAK_DOOR - - SPRUCE_DOOR - #fences - - ACACIA_FENCE - - BIRCH_FENCE - - DARK_OAK_FENCE - - JUNGLE_FENCE - - OAK_FENCE - - SPRUCE_FENCE - #fence gates - - ACACIA_FENCE_GATE - - BIRCH_FENCE_GATE - - DARK_OAK_FENCE_GATE - - JUNGLE_FENCE_GATE - - OAK_FENCE_GATE - - SPRUCE_FENCE_GATE - #glass - - GLASS - - WHITE_STAINED_GLASS - - ORANGE_STAINED_GLASS - - MAGENTA_STAINED_GLASS - - LIGHT_BLUE_STAINED_GLASS - - YELLOW_STAINED_GLASS - - LIME_STAINED_GLASS - - PINK_STAINED_GLASS - - GRAY_STAINED_GLASS - - LIGHT_GRAY_STAINED_GLASS - - CYAN_STAINED_GLASS - - PURPLE_STAINED_GLASS - - BLUE_STAINED_GLASS - - BROWN_STAINED_GLASS - - GREEN_STAINED_GLASS - - RED_STAINED_GLASS - - BLACK_STAINED_GLASS - #glass pane - - GLASS_PANE - - WHITE_STAINED_GLASS_PANE - - ORANGE_STAINED_GLASS_PANE - - MAGENTA_STAINED_GLASS_PANE - - LIGHT_BLUE_STAINED_GLASS_PANE - - YELLOW_STAINED_GLASS_PANE - - LIME_STAINED_GLASS_PANE - - PINK_STAINED_GLASS_PANE - - GRAY_STAINED_GLASS_PANE - - LIGHT_GRAY_STAINED_GLASS_PANE - - CYAN_STAINED_GLASS_PANE - - PURPLE_STAINED_GLASS_PANE - - BLUE_STAINED_GLASS_PANE - - BROWN_STAINED_GLASS_PANE - - GREEN_STAINED_GLASS_PANE - - RED_STAINED_GLASS_PANE - - BLACK_STAINED_GLASS_PANE - #interior - - BOOKSHELF - - BREWING_STAND - - CAULDRON - - IRON_BARS - - SIGN - - TORCH - - WALL_SIGN - - WALL_TORCH - #liquids - - LAVA - - WATER - #logs - - BIRCH_LOG - - JUNGLE_LOG - - OAK_LOG - - SPRUCE_LOG - - STRIPPED_BIRCH_LOG - - STRIPPED_JUNGLE_LOG - - STRIPPED_OAK_LOG - - STRIPPED_SPRUCE_LOG - #planks - - ACACIA_PLANKS - - BIRCH_PLANKS - - DARK_OAK_PLANKS - - JUNGLE_PLANKS - - OAK_PLANKS - - SPRUCE_PLANKS - #pressure plates - - ACACIA_PRESSURE_PLATE - - BIRCH_PRESSURE_PLATE - - DARK_OAK_PRESSURE_PLATE - - HEAVY_WEIGHTED_PRESSURE_PLATE - - JUNGLE_PRESSURE_PLATE - - LIGHT_WEIGHTED_PRESSURE_PLATE - - OAK_PRESSURE_PLATE - - SPRUCE_PRESSURE_PLATE - #redstone - - COMPARATOR - - NOTE_BLOCK - - PISTON - - PISTON_HEAD - - REDSTONE_BLOCK - - REDSTONE_WIRE - - REPEATER - - REDSTONE_TORCH - - REDSTONE_WALL_TORCH - - STICKY_PISTON - - TRIPWIRE_HOOK - #slabs - - ACACIA_SLAB - - BIRCH_SLAB - - BRICK_SLAB - - COBBLESTONE_SLAB - - DARK_OAK_SLAB - - DARK_PRISMARINE - - JUNGLE_SLAB - - NETHER_BRICK_SLAB - - OAK_SLAB - - PETRIFIED_OAK_SLAB - - PRISMARINE_SLAB - - PRISMARINE_BRICK_SLAB - - RED_SANDSTONE_SLAB - - QUARTZ_SLAB - - SPRUCE_SLAB - - STONE_SLAB - #stairs - - BIRCH_STAIRS - - JUNGLE_STAIRS - - OAK_STAIRS - - SMOOTH_STAIRS - - SPRUCE_STAIRS - #storage - - CHEST - - DISPENSER - - DROPPER - - HOPPER - - TRAPPED_CHEST - #terracotta - - TERRACOTTA - - WHITE_TERRACOTTA - - ORANGE_TERRACOTTA - - MAGENTA_TERRACOTTA - - LIGHT_BLUE_TERRACOTTA - - YELLOW_TERRACOTTA - - LIME_TERRACOTTA - - PINK_TERRACOTTA - - GRAY_TERRACOTTA - - LIGHT_TERRACOTTA - - CYAN_TERRACOTTA - - PURPLE_TERRACOTTA - - BLUE_TERRACOTTA - - BROWN_TERRACOTTA - - GREEN_TERRACOTTA - - RED_TERRACOTTA - - BLACK_TERRACOTTA - #trapdoors - - ACACIA_TRAPDOOR - - BIRCH_TRAPDOOR - - DARK_OAK_TRAPDOOR - - JUNGLE_TRAPDOOR - - OAK_TRAPDOOR - - SPRUCE_TRAPDOOR - #weapon blocks - - COAL_BLOCK - #wood - - ACACIA_WOOD - - BIRCH_WOOD - - DARK_OAK_WOOD - - OAK_WOOD - - SPRUCE_WOOD - - STRIPPED_ACACIA_WOOD - - STRIPPED_BIRCH_WOOD - - STRIPPED_DARK_OAK_WOOD - - STRIPPED_OAK_WOOD - - STRIPPED_SPRUCE_WOOD - #wool - - WHITE_WOOL - - ORANGE_WOOL - - MAGENTA_WOOL - - LIGHT_BLUE_WOOL - - YELLOW_WOOL - - LIME_WOOL - - PINK_WOOL - - GRAY_WOOL - - LIGHT_GRAY_WOOL - - CYAN_WOOL - - PURPLE_WOOL - - BLUE_WOOL - - BROWN_WOOL - - GREEN_WOOL - - RED_WOOL - - BLACK_WOOL + #beds + - WHITE_BED + - ORANGE_BED + - MAGENTA_BED + - LIGHT_BLUE_BED + - YELLOW_BED + - LIME_BED + - PINK_BED + - GRAY_BED + - LIGHT_BED + - CYAN_BED + - PURPLE_BED + - BLUE_BED + - BROWN_BED + - GREEN_BED + - RED_BED + - BLACK_BED + #buttons + - ACACIA_BUTTON + - BIRCH_BUTTON + - DARK_OAK_BUTTON + - JUNGLE_BUTTON + - OAK_BUTTON + - SPRUCE_BUTTON + - STONE_BUTTON + #carpets + - WHITE_CARPET + - ORANGE_CARPET + - MAGENTA_CARPET + - LIGHT_BLUE_CARPET + - YELLOW_CARPET + - LIME_CARPET + - PINK_CARPET + - GRAY_CARPET + - LIGHT_CARPET + - CYAN_CARPET + - PURPLE_CARPET + - BLUE_CARPET + - BROWN_CARPET + - GREEN_CARPET + - RED_CARPET + - BLACK_CARPET + #doors + - ACACIA_DOOR + - BIRCH_DOOR + - DARK_OAK_DOOR + - IRON_DOOR + - JUNGLE_DOOR + - OAK_DOOR + - SPRUCE_DOOR + #fences + - ACACIA_FENCE + - BIRCH_FENCE + - DARK_OAK_FENCE + - JUNGLE_FENCE + - OAK_FENCE + - NETHER_BRICK_FENCE + - SPRUCE_FENCE + #fence gates + - ACACIA_FENCE_GATE + - BIRCH_FENCE_GATE + - DARK_OAK_FENCE_GATE + - JUNGLE_FENCE_GATE + - OAK_FENCE_GATE + - SPRUCE_FENCE_GATE + #glass + - GLASS + - WHITE_STAINED_GLASS + - ORANGE_STAINED_GLASS + - MAGENTA_STAINED_GLASS + - LIGHT_BLUE_STAINED_GLASS + - YELLOW_STAINED_GLASS + - LIME_STAINED_GLASS + - PINK_STAINED_GLASS + - GRAY_STAINED_GLASS + - LIGHT_GRAY_STAINED_GLASS + - CYAN_STAINED_GLASS + - PURPLE_STAINED_GLASS + - BLUE_STAINED_GLASS + - BROWN_STAINED_GLASS + - GREEN_STAINED_GLASS + - RED_STAINED_GLASS + - BLACK_STAINED_GLASS + #glass pane + - GLASS_PANE + - WHITE_STAINED_GLASS_PANE + - ORANGE_STAINED_GLASS_PANE + - MAGENTA_STAINED_GLASS_PANE + - LIGHT_BLUE_STAINED_GLASS_PANE + - YELLOW_STAINED_GLASS_PANE + - LIME_STAINED_GLASS_PANE + - PINK_STAINED_GLASS_PANE + - GRAY_STAINED_GLASS_PANE + - LIGHT_GRAY_STAINED_GLASS_PANE + - CYAN_STAINED_GLASS_PANE + - PURPLE_STAINED_GLASS_PANE + - BLUE_STAINED_GLASS_PANE + - BROWN_STAINED_GLASS_PANE + - GREEN_STAINED_GLASS_PANE + - RED_STAINED_GLASS_PANE + - BLACK_STAINED_GLASS_PANE + #liquids + - LAVA + - WATER + #logs + - BIRCH_LOG + - JUNGLE_LOG + - OAK_LOG + - SPRUCE_LOG + - STRIPPED_BIRCH_LOG + - STRIPPED_JUNGLE_LOG + - STRIPPED_OAK_LOG + - STRIPPED_SPRUCE_LOG + #misc + - BOOKSHELF + - BREWING_STAND + - CRAFTING_TABLE + - CAULDRON + - FURNACE + - GLOWSTONE + - IRON_BARS + - LADDER + - NETHER_BRICKS + - SIGN + - TORCH + - WALL_SIGN + - WALL_TORCH + #planks + - ACACIA_PLANKS + - BIRCH_PLANKS + - DARK_OAK_PLANKS + - JUNGLE_PLANKS + - OAK_PLANKS + - SPRUCE_PLANKS + #pressure plates + - ACACIA_PRESSURE_PLATE + - BIRCH_PRESSURE_PLATE + - DARK_OAK_PRESSURE_PLATE + - HEAVY_WEIGHTED_PRESSURE_PLATE + - JUNGLE_PRESSURE_PLATE + - LIGHT_WEIGHTED_PRESSURE_PLATE + - OAK_PRESSURE_PLATE + - SPRUCE_PRESSURE_PLATE + - STONE_PRESSURE_PLATE + #redstone + - COMPARATOR + - LEVER + - NOTE_BLOCK + - PISTON + - PISTON_HEAD + - REDSTONE_BLOCK + - REDSTONE_WIRE + - REPEATER + - REDSTONE_TORCH + - REDSTONE_WALL_TORCH + - STICKY_PISTON + - TRIPWIRE_HOOK + #slabs + - ACACIA_SLAB + - BIRCH_SLAB + - BRICK_SLAB + - COBBLESTONE_SLAB + - DARK_OAK_SLAB + - DARK_PRISMARINE + - JUNGLE_SLAB + - NETHER_BRICK_SLAB + - OAK_SLAB + - PETRIFIED_OAK_SLAB + - PRISMARINE_SLAB + - PRISMARINE_BRICK_SLAB + - RED_SANDSTONE_SLAB + - QUARTZ_SLAB + - SPRUCE_SLAB + - STONE_SLAB + #stairs + - BIRCH_STAIRS + - JUNGLE_STAIRS + - OAK_STAIRS + - NETHER_BRICK_STAIRS + - SMOOTH_STAIRS + - SPRUCE_STAIRS + - STONE_BRICK_STAIRS + #storage + - CHEST + - DISPENSER + - DROPPER + - HOPPER + - TRAPPED_CHEST + #terracotta + - WHITE_TERRACOTTA + - ORANGE_TERRACOTTA + - MAGENTA_TERRACOTTA + - LIGHT_BLUE_TERRACOTTA + - YELLOW_TERRACOTTA + - LIME_TERRACOTTA + - PINK_TERRACOTTA + - GRAY_TERRACOTTA + - LIGHT_GRAY_TERRACOTTA + - CYAN_TERRACOTTA + - PURPLE_TERRACOTTA + - BLUE_TERRACOTTA + - BROWN_TERRACOTTA + - GREEN_TERRACOTTA + - RED_TERRACOTTA + - BLACK_TERRACOTTA + #trapdoors + - ACACIA_TRAPDOOR + - BIRCH_TRAPDOOR + - DARK_OAK_TRAPDOOR + - JUNGLE_TRAPDOOR + - OAK_TRAPDOOR + - SPRUCE_TRAPDOOR + #weapon blocks + - COAL_BLOCK + #wood + - ACACIA_WOOD + - BIRCH_WOOD + - DARK_OAK_WOOD + - OAK_WOOD + - SPRUCE_WOOD + - STRIPPED_ACACIA_WOOD + - STRIPPED_BIRCH_WOOD + - STRIPPED_DARK_OAK_WOOD + - STRIPPED_OAK_WOOD + - STRIPPED_SPRUCE_WOOD + #wool + - WHITE_WOOL + - ORANGE_WOOL + - MAGENTA_WOOL + - LIGHT_BLUE_WOOL + - YELLOW_WOOL + - LIME_WOOL + - PINK_WOOL + - GRAY_WOOL + - LIGHT_GRAY_WOOL + - CYAN_WOOL + - PURPLE_WOOL + - BLUE_WOOL + - BROWN_WOOL + - GREEN_WOOL + - RED_WOOL + - BLACK_WOOL -forbiddenBlocks: - - PISTON_HEAD canCruise: true diff --git a/modules/Movecraft/src/main/resources/types/BigSubAirship.craft b/modules/Movecraft/src/main/resources/types/BigSubAirship.craft index d25ff6e98..2409fd51d 100644 --- a/modules/Movecraft/src/main/resources/types/BigSubAirship.craft +++ b/modules/Movecraft/src/main/resources/types/BigSubAirship.craft @@ -2,225 +2,248 @@ name: BigSubAirship maxSize: 20000 minSize: 10000 allowedBlocks: - #beds - - WHITE_BED - - ORANGE_BED - - MAGENTA_BED - - LIGHT_BLUE_BED - - YELLOW_BED - - LIME_BED - - PINK_BED - - GRAY_BED - - LIGHT_BED - - CYAN_BED - - PURPLE_BED - - BLUE_BED - - BROWN_BED - - GREEN_BED - - RED_BED - - BLACK_BED - #buttons - - ACACIA_BUTTON - - BIRCH_BUTTON - - DARK_OAK_BUTTON - - JUNGLE_BUTTON - - OAK_BUTTON - - SPRUCE_BUTTON - - STONE_BUTTON - #doors - - ACACIA_DOOR - - BIRCH_DOOR - - DARK_OAK_DOOR - - IRON_DOOR - - JUNGLE_DOOR - - OAK_DOOR - - SPRUCE_DOOR - #fences - - ACACIA_FENCE - - BIRCH_FENCE - - DARK_OAK_FENCE - - JUNGLE_FENCE - - OAK_FENCE - - SPRUCE_FENCE - #fence gates - - ACACIA_FENCE_GATE - - BIRCH_FENCE_GATE - - DARK_OAK_FENCE_GATE - - JUNGLE_FENCE_GATE - - OAK_FENCE_GATE - - SPRUCE_FENCE_GATE - #glass - - GLASS - - WHITE_STAINED_GLASS - - ORANGE_STAINED_GLASS - - MAGENTA_STAINED_GLASS - - LIGHT_BLUE_STAINED_GLASS - - YELLOW_STAINED_GLASS - - LIME_STAINED_GLASS - - PINK_STAINED_GLASS - - GRAY_STAINED_GLASS - - LIGHT_GRAY_STAINED_GLASS - - CYAN_STAINED_GLASS - - PURPLE_STAINED_GLASS - - BLUE_STAINED_GLASS - - BROWN_STAINED_GLASS - - GREEN_STAINED_GLASS - - RED_STAINED_GLASS - - BLACK_STAINED_GLASS - #glass pane - - GLASS_PANE - - WHITE_STAINED_GLASS_PANE - - ORANGE_STAINED_GLASS_PANE - - MAGENTA_STAINED_GLASS_PANE - - LIGHT_BLUE_STAINED_GLASS_PANE - - YELLOW_STAINED_GLASS_PANE - - LIME_STAINED_GLASS_PANE - - PINK_STAINED_GLASS_PANE - - GRAY_STAINED_GLASS_PANE - - LIGHT_GRAY_STAINED_GLASS_PANE - - CYAN_STAINED_GLASS_PANE - - PURPLE_STAINED_GLASS_PANE - - BLUE_STAINED_GLASS_PANE - - BROWN_STAINED_GLASS_PANE - - GREEN_STAINED_GLASS_PANE - - RED_STAINED_GLASS_PANE - - BLACK_STAINED_GLASS_PANE - #interior - - BOOKSHELF - - BREWING_STAND - - CAULDRON - - IRON_BARS - - SIGN - - TORCH - - WALL_SIGN - - WALL_TORCH - #liquids - - LAVA - - WATER - #logs - - BIRCH_LOG - - JUNGLE_LOG - - OAK_LOG - - SPRUCE_LOG - - STRIPPED_BIRCH_LOG - - STRIPPED_JUNGLE_LOG - - STRIPPED_OAK_LOG - - STRIPPED_SPRUCE_LOG - #planks - - ACACIA_PLANKS - - BIRCH_PLANKS - - DARK_OAK_PLANKS - - JUNGLE_PLANKS - - OAK_PLANKS - - SPRUCE_PLANKS - #pressure plates - - ACACIA_PRESSURE_PLATE - - BIRCH_PRESSURE_PLATE - - DARK_OAK_PRESSURE_PLATE - - HEAVY_WEIGHTED_PRESSURE_PLATE - - JUNGLE_PRESSURE_PLATE - - LIGHT_WEIGHTED_PRESSURE_PLATE - - OAK_PRESSURE_PLATE - - SPRUCE_PRESSURE_PLATE - #redstone - - COMPARATOR - - NOTE_BLOCK - - PISTON - - PISTON_HEAD - - REDSTONE_BLOCK - - REDSTONE_WIRE - - REPEATER - - REDSTONE_TORCH - - REDSTONE_WALL_TORCH - - STICKY_PISTON - - TRIPWIRE_HOOK - #slabs - - ACACIA_SLAB - - BIRCH_SLAB - - BRICK_SLAB - - COBBLESTONE_SLAB - - DARK_OAK_SLAB - - DARK_PRISMARINE - - JUNGLE_SLAB - - NETHER_BRICK_SLAB - - OAK_SLAB - - PETRIFIED_OAK_SLAB - - PRISMARINE_SLAB - - PRISMARINE_BRICK_SLAB - - RED_SANDSTONE_SLAB - - QUARTZ_SLAB - - SPRUCE_SLAB - - STONE_SLAB - #stairs - - BIRCH_STAIRS - - JUNGLE_STAIRS - - OAK_STAIRS - - SMOOTH_STAIRS - - SPRUCE_STAIRS - #storage - - CHEST - - DISPENSER - - DROPPER - - HOPPER - - TRAPPED_CHEST - #terracotta - - TERRACOTTA - - WHITE_TERRACOTTA - - ORANGE_TERRACOTTA - - MAGENTA_TERRACOTTA - - LIGHT_BLUE_TERRACOTTA - - YELLOW_TERRACOTTA - - LIME_TERRACOTTA - - PINK_TERRACOTTA - - GRAY_TERRACOTTA - - LIGHT_TERRACOTTA - - CYAN_TERRACOTTA - - PURPLE_TERRACOTTA - - BLUE_TERRACOTTA - - BROWN_TERRACOTTA - - GREEN_TERRACOTTA - - RED_TERRACOTTA - - BLACK_TERRACOTTA - #trapdoors - - ACACIA_TRAPDOOR - - BIRCH_TRAPDOOR - - DARK_OAK_TRAPDOOR - - JUNGLE_TRAPDOOR - - OAK_TRAPDOOR - - SPRUCE_TRAPDOOR - #weapon blocks - - COAL_BLOCK - #wood - - ACACIA_WOOD - - BIRCH_WOOD - - DARK_OAK_WOOD - - OAK_WOOD - - SPRUCE_WOOD - - STRIPPED_ACACIA_WOOD - - STRIPPED_BIRCH_WOOD - - STRIPPED_DARK_OAK_WOOD - - STRIPPED_OAK_WOOD - - STRIPPED_SPRUCE_WOOD - #wool - - WHITE_WOOL - - ORANGE_WOOL - - MAGENTA_WOOL - - LIGHT_BLUE_WOOL - - YELLOW_WOOL - - LIME_WOOL - - PINK_WOOL - - GRAY_WOOL - - LIGHT_GRAY_WOOL - - CYAN_WOOL - - PURPLE_WOOL - - BLUE_WOOL - - BROWN_WOOL - - GREEN_WOOL - - RED_WOOL - - BLACK_WOOL - -forbiddenBlocks: - - PISTON_HEAD + #beds + - WHITE_BED + - ORANGE_BED + - MAGENTA_BED + - LIGHT_BLUE_BED + - YELLOW_BED + - LIME_BED + - PINK_BED + - GRAY_BED + - LIGHT_BED + - CYAN_BED + - PURPLE_BED + - BLUE_BED + - BROWN_BED + - GREEN_BED + - RED_BED + - BLACK_BED + #buttons + - ACACIA_BUTTON + - BIRCH_BUTTON + - DARK_OAK_BUTTON + - JUNGLE_BUTTON + - OAK_BUTTON + - SPRUCE_BUTTON + - STONE_BUTTON + #carpets + - WHITE_CARPET + - ORANGE_CARPET + - MAGENTA_CARPET + - LIGHT_BLUE_CARPET + - YELLOW_CARPET + - LIME_CARPET + - PINK_CARPET + - GRAY_CARPET + - LIGHT_CARPET + - CYAN_CARPET + - PURPLE_CARPET + - BLUE_CARPET + - BROWN_CARPET + - GREEN_CARPET + - RED_CARPET + - BLACK_CARPET + #doors + - ACACIA_DOOR + - BIRCH_DOOR + - DARK_OAK_DOOR + - IRON_DOOR + - JUNGLE_DOOR + - OAK_DOOR + - SPRUCE_DOOR + #fences + - ACACIA_FENCE + - BIRCH_FENCE + - DARK_OAK_FENCE + - JUNGLE_FENCE + - OAK_FENCE + - NETHER_BRICK_FENCE + - SPRUCE_FENCE + #fence gates + - ACACIA_FENCE_GATE + - BIRCH_FENCE_GATE + - DARK_OAK_FENCE_GATE + - JUNGLE_FENCE_GATE + - OAK_FENCE_GATE + - SPRUCE_FENCE_GATE + #glass + - GLASS + - WHITE_STAINED_GLASS + - ORANGE_STAINED_GLASS + - MAGENTA_STAINED_GLASS + - LIGHT_BLUE_STAINED_GLASS + - YELLOW_STAINED_GLASS + - LIME_STAINED_GLASS + - PINK_STAINED_GLASS + - GRAY_STAINED_GLASS + - LIGHT_GRAY_STAINED_GLASS + - CYAN_STAINED_GLASS + - PURPLE_STAINED_GLASS + - BLUE_STAINED_GLASS + - BROWN_STAINED_GLASS + - GREEN_STAINED_GLASS + - RED_STAINED_GLASS + - BLACK_STAINED_GLASS + #glass pane + - GLASS_PANE + - WHITE_STAINED_GLASS_PANE + - ORANGE_STAINED_GLASS_PANE + - MAGENTA_STAINED_GLASS_PANE + - LIGHT_BLUE_STAINED_GLASS_PANE + - YELLOW_STAINED_GLASS_PANE + - LIME_STAINED_GLASS_PANE + - PINK_STAINED_GLASS_PANE + - GRAY_STAINED_GLASS_PANE + - LIGHT_GRAY_STAINED_GLASS_PANE + - CYAN_STAINED_GLASS_PANE + - PURPLE_STAINED_GLASS_PANE + - BLUE_STAINED_GLASS_PANE + - BROWN_STAINED_GLASS_PANE + - GREEN_STAINED_GLASS_PANE + - RED_STAINED_GLASS_PANE + - BLACK_STAINED_GLASS_PANE + #liquids + - LAVA + - WATER + #logs + - BIRCH_LOG + - JUNGLE_LOG + - OAK_LOG + - SPRUCE_LOG + - STRIPPED_BIRCH_LOG + - STRIPPED_JUNGLE_LOG + - STRIPPED_OAK_LOG + - STRIPPED_SPRUCE_LOG + #misc + - BOOKSHELF + - BREWING_STAND + - CRAFTING_TABLE + - CAULDRON + - FURNACE + - GLOWSTONE + - IRON_BARS + - LADDER + - NETHER_BRICKS + - SIGN + - TORCH + - WALL_SIGN + - WALL_TORCH + #planks + - ACACIA_PLANKS + - BIRCH_PLANKS + - DARK_OAK_PLANKS + - JUNGLE_PLANKS + - OAK_PLANKS + - SPRUCE_PLANKS + #pressure plates + - ACACIA_PRESSURE_PLATE + - BIRCH_PRESSURE_PLATE + - DARK_OAK_PRESSURE_PLATE + - HEAVY_WEIGHTED_PRESSURE_PLATE + - JUNGLE_PRESSURE_PLATE + - LIGHT_WEIGHTED_PRESSURE_PLATE + - OAK_PRESSURE_PLATE + - SPRUCE_PRESSURE_PLATE + - STONE_PRESSURE_PLATE + #redstone + - COMPARATOR + - LEVER + - NOTE_BLOCK + - PISTON + - PISTON_HEAD + - REDSTONE_BLOCK + - REDSTONE_WIRE + - REPEATER + - REDSTONE_TORCH + - REDSTONE_WALL_TORCH + - STICKY_PISTON + - TRIPWIRE_HOOK + #slabs + - ACACIA_SLAB + - BIRCH_SLAB + - BRICK_SLAB + - COBBLESTONE_SLAB + - DARK_OAK_SLAB + - DARK_PRISMARINE + - JUNGLE_SLAB + - NETHER_BRICK_SLAB + - OAK_SLAB + - PETRIFIED_OAK_SLAB + - PRISMARINE_SLAB + - PRISMARINE_BRICK_SLAB + - RED_SANDSTONE_SLAB + - QUARTZ_SLAB + - SPRUCE_SLAB + - STONE_SLAB + #stairs + - BIRCH_STAIRS + - JUNGLE_STAIRS + - OAK_STAIRS + - NETHER_BRICK_STAIRS + - SMOOTH_STAIRS + - SPRUCE_STAIRS + - STONE_BRICK_STAIRS + #storage + - CHEST + - DISPENSER + - DROPPER + - HOPPER + - TRAPPED_CHEST + #terracotta + - WHITE_TERRACOTTA + - ORANGE_TERRACOTTA + - MAGENTA_TERRACOTTA + - LIGHT_BLUE_TERRACOTTA + - YELLOW_TERRACOTTA + - LIME_TERRACOTTA + - PINK_TERRACOTTA + - GRAY_TERRACOTTA + - LIGHT_GRAY_TERRACOTTA + - CYAN_TERRACOTTA + - PURPLE_TERRACOTTA + - BLUE_TERRACOTTA + - BROWN_TERRACOTTA + - GREEN_TERRACOTTA + - RED_TERRACOTTA + - BLACK_TERRACOTTA + #trapdoors + - ACACIA_TRAPDOOR + - BIRCH_TRAPDOOR + - DARK_OAK_TRAPDOOR + - JUNGLE_TRAPDOOR + - OAK_TRAPDOOR + - SPRUCE_TRAPDOOR + #weapon blocks + - COAL_BLOCK + #wood + - ACACIA_WOOD + - BIRCH_WOOD + - DARK_OAK_WOOD + - OAK_WOOD + - SPRUCE_WOOD + - STRIPPED_ACACIA_WOOD + - STRIPPED_BIRCH_WOOD + - STRIPPED_DARK_OAK_WOOD + - STRIPPED_OAK_WOOD + - STRIPPED_SPRUCE_WOOD + #wool + - WHITE_WOOL + - ORANGE_WOOL + - MAGENTA_WOOL + - LIGHT_BLUE_WOOL + - YELLOW_WOOL + - LIME_WOOL + - PINK_WOOL + - GRAY_WOOL + - LIGHT_GRAY_WOOL + - CYAN_WOOL + - PURPLE_WOOL + - BLUE_WOOL + - BROWN_WOOL + - GREEN_WOOL + - RED_WOOL + - BLACK_WOOL canCruise: true rotateAtMidpoint: true diff --git a/modules/Movecraft/src/main/resources/types/Ship.craft b/modules/Movecraft/src/main/resources/types/Ship.craft index 2533840bf..a153f92a3 100644 --- a/modules/Movecraft/src/main/resources/types/Ship.craft +++ b/modules/Movecraft/src/main/resources/types/Ship.craft @@ -2,225 +2,248 @@ name: Ship maxSize: 100000 minSize: 10 allowedBlocks: - #beds - - WHITE_BED - - ORANGE_BED - - MAGENTA_BED - - LIGHT_BLUE_BED - - YELLOW_BED - - LIME_BED - - PINK_BED - - GRAY_BED - - LIGHT_BED - - CYAN_BED - - PURPLE_BED - - BLUE_BED - - BROWN_BED - - GREEN_BED - - RED_BED - - BLACK_BED - #buttons - - ACACIA_BUTTON - - BIRCH_BUTTON - - DARK_OAK_BUTTON - - JUNGLE_BUTTON - - OAK_BUTTON - - SPRUCE_BUTTON - - STONE_BUTTON - #doors - - ACACIA_DOOR - - BIRCH_DOOR - - DARK_OAK_DOOR - - IRON_DOOR - - JUNGLE_DOOR - - OAK_DOOR - - SPRUCE_DOOR - #fences - - ACACIA_FENCE - - BIRCH_FENCE - - DARK_OAK_FENCE - - JUNGLE_FENCE - - OAK_FENCE - - SPRUCE_FENCE - #fence gates - - ACACIA_FENCE_GATE - - BIRCH_FENCE_GATE - - DARK_OAK_FENCE_GATE - - JUNGLE_FENCE_GATE - - OAK_FENCE_GATE - - SPRUCE_FENCE_GATE - #glass - - GLASS - - WHITE_STAINED_GLASS - - ORANGE_STAINED_GLASS - - MAGENTA_STAINED_GLASS - - LIGHT_BLUE_STAINED_GLASS - - YELLOW_STAINED_GLASS - - LIME_STAINED_GLASS - - PINK_STAINED_GLASS - - GRAY_STAINED_GLASS - - LIGHT_GRAY_STAINED_GLASS - - CYAN_STAINED_GLASS - - PURPLE_STAINED_GLASS - - BLUE_STAINED_GLASS - - BROWN_STAINED_GLASS - - GREEN_STAINED_GLASS - - RED_STAINED_GLASS - - BLACK_STAINED_GLASS - #glass pane - - GLASS_PANE - - WHITE_STAINED_GLASS_PANE - - ORANGE_STAINED_GLASS_PANE - - MAGENTA_STAINED_GLASS_PANE - - LIGHT_BLUE_STAINED_GLASS_PANE - - YELLOW_STAINED_GLASS_PANE - - LIME_STAINED_GLASS_PANE - - PINK_STAINED_GLASS_PANE - - GRAY_STAINED_GLASS_PANE - - LIGHT_GRAY_STAINED_GLASS_PANE - - CYAN_STAINED_GLASS_PANE - - PURPLE_STAINED_GLASS_PANE - - BLUE_STAINED_GLASS_PANE - - BROWN_STAINED_GLASS_PANE - - GREEN_STAINED_GLASS_PANE - - RED_STAINED_GLASS_PANE - - BLACK_STAINED_GLASS_PANE - #interior - - BOOKSHELF - - BREWING_STAND - - CAULDRON - - IRON_BARS - - SIGN - - TORCH - - WALL_SIGN - - WALL_TORCH - #liquids - - LAVA - - WATER - #logs - - BIRCH_LOG - - JUNGLE_LOG - - OAK_LOG - - SPRUCE_LOG - - STRIPPED_BIRCH_LOG - - STRIPPED_JUNGLE_LOG - - STRIPPED_OAK_LOG - - STRIPPED_SPRUCE_LOG - #planks - - ACACIA_PLANKS - - BIRCH_PLANKS - - DARK_OAK_PLANKS - - JUNGLE_PLANKS - - OAK_PLANKS - - SPRUCE_PLANKS - #pressure plates - - ACACIA_PRESSURE_PLATE - - BIRCH_PRESSURE_PLATE - - DARK_OAK_PRESSURE_PLATE - - HEAVY_WEIGHTED_PRESSURE_PLATE - - JUNGLE_PRESSURE_PLATE - - LIGHT_WEIGHTED_PRESSURE_PLATE - - OAK_PRESSURE_PLATE - - SPRUCE_PRESSURE_PLATE - #redstone - - COMPARATOR - - NOTE_BLOCK - - PISTON - - PISTON_HEAD - - REDSTONE_BLOCK - - REDSTONE_WIRE - - REPEATER - - REDSTONE_TORCH - - REDSTONE_WALL_TORCH - - STICKY_PISTON - - TRIPWIRE_HOOK - #slabs - - ACACIA_SLAB - - BIRCH_SLAB - - BRICK_SLAB - - COBBLESTONE_SLAB - - DARK_OAK_SLAB - - DARK_PRISMARINE - - JUNGLE_SLAB - - NETHER_BRICK_SLAB - - OAK_SLAB - - PETRIFIED_OAK_SLAB - - PRISMARINE_SLAB - - PRISMARINE_BRICK_SLAB - - RED_SANDSTONE_SLAB - - QUARTZ_SLAB - - SPRUCE_SLAB - - STONE_SLAB - #stairs - - BIRCH_STAIRS - - JUNGLE_STAIRS - - OAK_STAIRS - - SMOOTH_STAIRS - - SPRUCE_STAIRS - #storage - - CHEST - - DISPENSER - - DROPPER - - HOPPER - - TRAPPED_CHEST - #terracotta - - TERRACOTTA - - WHITE_TERRACOTTA - - ORANGE_TERRACOTTA - - MAGENTA_TERRACOTTA - - LIGHT_BLUE_TERRACOTTA - - YELLOW_TERRACOTTA - - LIME_TERRACOTTA - - PINK_TERRACOTTA - - GRAY_TERRACOTTA - - LIGHT_TERRACOTTA - - CYAN_TERRACOTTA - - PURPLE_TERRACOTTA - - BLUE_TERRACOTTA - - BROWN_TERRACOTTA - - GREEN_TERRACOTTA - - RED_TERRACOTTA - - BLACK_TERRACOTTA - #trapdoors - - ACACIA_TRAPDOOR - - BIRCH_TRAPDOOR - - DARK_OAK_TRAPDOOR - - JUNGLE_TRAPDOOR - - OAK_TRAPDOOR - - SPRUCE_TRAPDOOR - #weapon blocks - - COAL_BLOCK - #wood - - ACACIA_WOOD - - BIRCH_WOOD - - DARK_OAK_WOOD - - OAK_WOOD - - SPRUCE_WOOD - - STRIPPED_ACACIA_WOOD - - STRIPPED_BIRCH_WOOD - - STRIPPED_DARK_OAK_WOOD - - STRIPPED_OAK_WOOD - - STRIPPED_SPRUCE_WOOD - #wool - - WHITE_WOOL - - ORANGE_WOOL - - MAGENTA_WOOL - - LIGHT_BLUE_WOOL - - YELLOW_WOOL - - LIME_WOOL - - PINK_WOOL - - GRAY_WOOL - - LIGHT_GRAY_WOOL - - CYAN_WOOL - - PURPLE_WOOL - - BLUE_WOOL - - BROWN_WOOL - - GREEN_WOOL - - RED_WOOL - - BLACK_WOOL - -forbiddenBlocks: - - PISTON_HEAD + #beds + - WHITE_BED + - ORANGE_BED + - MAGENTA_BED + - LIGHT_BLUE_BED + - YELLOW_BED + - LIME_BED + - PINK_BED + - GRAY_BED + - LIGHT_BED + - CYAN_BED + - PURPLE_BED + - BLUE_BED + - BROWN_BED + - GREEN_BED + - RED_BED + - BLACK_BED + #buttons + - ACACIA_BUTTON + - BIRCH_BUTTON + - DARK_OAK_BUTTON + - JUNGLE_BUTTON + - OAK_BUTTON + - SPRUCE_BUTTON + - STONE_BUTTON + #carpets + - WHITE_CARPET + - ORANGE_CARPET + - MAGENTA_CARPET + - LIGHT_BLUE_CARPET + - YELLOW_CARPET + - LIME_CARPET + - PINK_CARPET + - GRAY_CARPET + - LIGHT_CARPET + - CYAN_CARPET + - PURPLE_CARPET + - BLUE_CARPET + - BROWN_CARPET + - GREEN_CARPET + - RED_CARPET + - BLACK_CARPET + #doors + - ACACIA_DOOR + - BIRCH_DOOR + - DARK_OAK_DOOR + - IRON_DOOR + - JUNGLE_DOOR + - OAK_DOOR + - SPRUCE_DOOR + #fences + - ACACIA_FENCE + - BIRCH_FENCE + - DARK_OAK_FENCE + - JUNGLE_FENCE + - OAK_FENCE + - NETHER_BRICK_FENCE + - SPRUCE_FENCE + #fence gates + - ACACIA_FENCE_GATE + - BIRCH_FENCE_GATE + - DARK_OAK_FENCE_GATE + - JUNGLE_FENCE_GATE + - OAK_FENCE_GATE + - SPRUCE_FENCE_GATE + #glass + - GLASS + - WHITE_STAINED_GLASS + - ORANGE_STAINED_GLASS + - MAGENTA_STAINED_GLASS + - LIGHT_BLUE_STAINED_GLASS + - YELLOW_STAINED_GLASS + - LIME_STAINED_GLASS + - PINK_STAINED_GLASS + - GRAY_STAINED_GLASS + - LIGHT_GRAY_STAINED_GLASS + - CYAN_STAINED_GLASS + - PURPLE_STAINED_GLASS + - BLUE_STAINED_GLASS + - BROWN_STAINED_GLASS + - GREEN_STAINED_GLASS + - RED_STAINED_GLASS + - BLACK_STAINED_GLASS + #glass pane + - GLASS_PANE + - WHITE_STAINED_GLASS_PANE + - ORANGE_STAINED_GLASS_PANE + - MAGENTA_STAINED_GLASS_PANE + - LIGHT_BLUE_STAINED_GLASS_PANE + - YELLOW_STAINED_GLASS_PANE + - LIME_STAINED_GLASS_PANE + - PINK_STAINED_GLASS_PANE + - GRAY_STAINED_GLASS_PANE + - LIGHT_GRAY_STAINED_GLASS_PANE + - CYAN_STAINED_GLASS_PANE + - PURPLE_STAINED_GLASS_PANE + - BLUE_STAINED_GLASS_PANE + - BROWN_STAINED_GLASS_PANE + - GREEN_STAINED_GLASS_PANE + - RED_STAINED_GLASS_PANE + - BLACK_STAINED_GLASS_PANE + #liquids + - LAVA + - WATER + #logs + - BIRCH_LOG + - JUNGLE_LOG + - OAK_LOG + - SPRUCE_LOG + - STRIPPED_BIRCH_LOG + - STRIPPED_JUNGLE_LOG + - STRIPPED_OAK_LOG + - STRIPPED_SPRUCE_LOG + #misc + - BOOKSHELF + - BREWING_STAND + - CRAFTING_TABLE + - CAULDRON + - FURNACE + - GLOWSTONE + - IRON_BARS + - LADDER + - NETHER_BRICKS + - SIGN + - TORCH + - WALL_SIGN + - WALL_TORCH + #planks + - ACACIA_PLANKS + - BIRCH_PLANKS + - DARK_OAK_PLANKS + - JUNGLE_PLANKS + - OAK_PLANKS + - SPRUCE_PLANKS + #pressure plates + - ACACIA_PRESSURE_PLATE + - BIRCH_PRESSURE_PLATE + - DARK_OAK_PRESSURE_PLATE + - HEAVY_WEIGHTED_PRESSURE_PLATE + - JUNGLE_PRESSURE_PLATE + - LIGHT_WEIGHTED_PRESSURE_PLATE + - OAK_PRESSURE_PLATE + - SPRUCE_PRESSURE_PLATE + - STONE_PRESSURE_PLATE + #redstone + - COMPARATOR + - LEVER + - NOTE_BLOCK + - PISTON + - PISTON_HEAD + - REDSTONE_BLOCK + - REDSTONE_WIRE + - REPEATER + - REDSTONE_TORCH + - REDSTONE_WALL_TORCH + - STICKY_PISTON + - TRIPWIRE_HOOK + #slabs + - ACACIA_SLAB + - BIRCH_SLAB + - BRICK_SLAB + - COBBLESTONE_SLAB + - DARK_OAK_SLAB + - DARK_PRISMARINE + - JUNGLE_SLAB + - NETHER_BRICK_SLAB + - OAK_SLAB + - PETRIFIED_OAK_SLAB + - PRISMARINE_SLAB + - PRISMARINE_BRICK_SLAB + - RED_SANDSTONE_SLAB + - QUARTZ_SLAB + - SPRUCE_SLAB + - STONE_SLAB + #stairs + - BIRCH_STAIRS + - JUNGLE_STAIRS + - OAK_STAIRS + - NETHER_BRICK_STAIRS + - SMOOTH_STAIRS + - SPRUCE_STAIRS + - STONE_BRICK_STAIRS + #storage + - CHEST + - DISPENSER + - DROPPER + - HOPPER + - TRAPPED_CHEST + #terracotta + - WHITE_TERRACOTTA + - ORANGE_TERRACOTTA + - MAGENTA_TERRACOTTA + - LIGHT_BLUE_TERRACOTTA + - YELLOW_TERRACOTTA + - LIME_TERRACOTTA + - PINK_TERRACOTTA + - GRAY_TERRACOTTA + - LIGHT_GRAY_TERRACOTTA + - CYAN_TERRACOTTA + - PURPLE_TERRACOTTA + - BLUE_TERRACOTTA + - BROWN_TERRACOTTA + - GREEN_TERRACOTTA + - RED_TERRACOTTA + - BLACK_TERRACOTTA + #trapdoors + - ACACIA_TRAPDOOR + - BIRCH_TRAPDOOR + - DARK_OAK_TRAPDOOR + - JUNGLE_TRAPDOOR + - OAK_TRAPDOOR + - SPRUCE_TRAPDOOR + #weapon blocks + - COAL_BLOCK + #wood + - ACACIA_WOOD + - BIRCH_WOOD + - DARK_OAK_WOOD + - OAK_WOOD + - SPRUCE_WOOD + - STRIPPED_ACACIA_WOOD + - STRIPPED_BIRCH_WOOD + - STRIPPED_DARK_OAK_WOOD + - STRIPPED_OAK_WOOD + - STRIPPED_SPRUCE_WOOD + #wool + - WHITE_WOOL + - ORANGE_WOOL + - MAGENTA_WOOL + - LIGHT_BLUE_WOOL + - YELLOW_WOOL + - LIME_WOOL + - PINK_WOOL + - GRAY_WOOL + - LIGHT_GRAY_WOOL + - CYAN_WOOL + - PURPLE_WOOL + - BLUE_WOOL + - BROWN_WOOL + - GREEN_WOOL + - RED_WOOL + - BLACK_WOOL canCruise: true cruiseSkipBlocks: 4 diff --git a/modules/Movecraft/src/main/resources/types/SubAirship.craft b/modules/Movecraft/src/main/resources/types/SubAirship.craft index 2b008d39e..07075d0ea 100644 --- a/modules/Movecraft/src/main/resources/types/SubAirship.craft +++ b/modules/Movecraft/src/main/resources/types/SubAirship.craft @@ -2,225 +2,248 @@ name: SubAirship maxSize: 5000 minSize: 1000 allowedBlocks: - #beds - - WHITE_BED - - ORANGE_BED - - MAGENTA_BED - - LIGHT_BLUE_BED - - YELLOW_BED - - LIME_BED - - PINK_BED - - GRAY_BED - - LIGHT_BED - - CYAN_BED - - PURPLE_BED - - BLUE_BED - - BROWN_BED - - GREEN_BED - - RED_BED - - BLACK_BED - #buttons - - ACACIA_BUTTON - - BIRCH_BUTTON - - DARK_OAK_BUTTON - - JUNGLE_BUTTON - - OAK_BUTTON - - SPRUCE_BUTTON - - STONE_BUTTON - #doors - - ACACIA_DOOR - - BIRCH_DOOR - - DARK_OAK_DOOR - - IRON_DOOR - - JUNGLE_DOOR - - OAK_DOOR - - SPRUCE_DOOR - #fences - - ACACIA_FENCE - - BIRCH_FENCE - - DARK_OAK_FENCE - - JUNGLE_FENCE - - OAK_FENCE - - SPRUCE_FENCE - #fence gates - - ACACIA_FENCE_GATE - - BIRCH_FENCE_GATE - - DARK_OAK_FENCE_GATE - - JUNGLE_FENCE_GATE - - OAK_FENCE_GATE - - SPRUCE_FENCE_GATE - #glass - - GLASS - - WHITE_STAINED_GLASS - - ORANGE_STAINED_GLASS - - MAGENTA_STAINED_GLASS - - LIGHT_BLUE_STAINED_GLASS - - YELLOW_STAINED_GLASS - - LIME_STAINED_GLASS - - PINK_STAINED_GLASS - - GRAY_STAINED_GLASS - - LIGHT_GRAY_STAINED_GLASS - - CYAN_STAINED_GLASS - - PURPLE_STAINED_GLASS - - BLUE_STAINED_GLASS - - BROWN_STAINED_GLASS - - GREEN_STAINED_GLASS - - RED_STAINED_GLASS - - BLACK_STAINED_GLASS - #glass pane - - GLASS_PANE - - WHITE_STAINED_GLASS_PANE - - ORANGE_STAINED_GLASS_PANE - - MAGENTA_STAINED_GLASS_PANE - - LIGHT_BLUE_STAINED_GLASS_PANE - - YELLOW_STAINED_GLASS_PANE - - LIME_STAINED_GLASS_PANE - - PINK_STAINED_GLASS_PANE - - GRAY_STAINED_GLASS_PANE - - LIGHT_GRAY_STAINED_GLASS_PANE - - CYAN_STAINED_GLASS_PANE - - PURPLE_STAINED_GLASS_PANE - - BLUE_STAINED_GLASS_PANE - - BROWN_STAINED_GLASS_PANE - - GREEN_STAINED_GLASS_PANE - - RED_STAINED_GLASS_PANE - - BLACK_STAINED_GLASS_PANE - #interior - - BOOKSHELF - - BREWING_STAND - - CAULDRON - - IRON_BARS - - SIGN - - TORCH - - WALL_SIGN - - WALL_TORCH - #liquids - - LAVA - - WATER - #logs - - BIRCH_LOG - - JUNGLE_LOG - - OAK_LOG - - SPRUCE_LOG - - STRIPPED_BIRCH_LOG - - STRIPPED_JUNGLE_LOG - - STRIPPED_OAK_LOG - - STRIPPED_SPRUCE_LOG - #planks - - ACACIA_PLANKS - - BIRCH_PLANKS - - DARK_OAK_PLANKS - - JUNGLE_PLANKS - - OAK_PLANKS - - SPRUCE_PLANKS - #pressure plates - - ACACIA_PRESSURE_PLATE - - BIRCH_PRESSURE_PLATE - - DARK_OAK_PRESSURE_PLATE - - HEAVY_WEIGHTED_PRESSURE_PLATE - - JUNGLE_PRESSURE_PLATE - - LIGHT_WEIGHTED_PRESSURE_PLATE - - OAK_PRESSURE_PLATE - - SPRUCE_PRESSURE_PLATE - #redstone - - COMPARATOR - - NOTE_BLOCK - - PISTON - - PISTON_HEAD - - REDSTONE_BLOCK - - REDSTONE_WIRE - - REPEATER - - REDSTONE_TORCH - - REDSTONE_WALL_TORCH - - STICKY_PISTON - - TRIPWIRE_HOOK - #slabs - - ACACIA_SLAB - - BIRCH_SLAB - - BRICK_SLAB - - COBBLESTONE_SLAB - - DARK_OAK_SLAB - - DARK_PRISMARINE - - JUNGLE_SLAB - - NETHER_BRICK_SLAB - - OAK_SLAB - - PETRIFIED_OAK_SLAB - - PRISMARINE_SLAB - - PRISMARINE_BRICK_SLAB - - RED_SANDSTONE_SLAB - - QUARTZ_SLAB - - SPRUCE_SLAB - - STONE_SLAB - #stairs - - BIRCH_STAIRS - - JUNGLE_STAIRS - - OAK_STAIRS - - SMOOTH_STAIRS - - SPRUCE_STAIRS - #storage - - CHEST - - DISPENSER - - DROPPER - - HOPPER - - TRAPPED_CHEST - #terracotta - - TERRACOTTA - - WHITE_TERRACOTTA - - ORANGE_TERRACOTTA - - MAGENTA_TERRACOTTA - - LIGHT_BLUE_TERRACOTTA - - YELLOW_TERRACOTTA - - LIME_TERRACOTTA - - PINK_TERRACOTTA - - GRAY_TERRACOTTA - - LIGHT_TERRACOTTA - - CYAN_TERRACOTTA - - PURPLE_TERRACOTTA - - BLUE_TERRACOTTA - - BROWN_TERRACOTTA - - GREEN_TERRACOTTA - - RED_TERRACOTTA - - BLACK_TERRACOTTA - #trapdoors - - ACACIA_TRAPDOOR - - BIRCH_TRAPDOOR - - DARK_OAK_TRAPDOOR - - JUNGLE_TRAPDOOR - - OAK_TRAPDOOR - - SPRUCE_TRAPDOOR - #weapon blocks - - COAL_BLOCK - #wood - - ACACIA_WOOD - - BIRCH_WOOD - - DARK_OAK_WOOD - - OAK_WOOD - - SPRUCE_WOOD - - STRIPPED_ACACIA_WOOD - - STRIPPED_BIRCH_WOOD - - STRIPPED_DARK_OAK_WOOD - - STRIPPED_OAK_WOOD - - STRIPPED_SPRUCE_WOOD - #wool - - WHITE_WOOL - - ORANGE_WOOL - - MAGENTA_WOOL - - LIGHT_BLUE_WOOL - - YELLOW_WOOL - - LIME_WOOL - - PINK_WOOL - - GRAY_WOOL - - LIGHT_GRAY_WOOL - - CYAN_WOOL - - PURPLE_WOOL - - BLUE_WOOL - - BROWN_WOOL - - GREEN_WOOL - - RED_WOOL - - BLACK_WOOL - -forbiddenBlocks: - - PISTON_HEAD + #beds + - WHITE_BED + - ORANGE_BED + - MAGENTA_BED + - LIGHT_BLUE_BED + - YELLOW_BED + - LIME_BED + - PINK_BED + - GRAY_BED + - LIGHT_BED + - CYAN_BED + - PURPLE_BED + - BLUE_BED + - BROWN_BED + - GREEN_BED + - RED_BED + - BLACK_BED + #buttons + - ACACIA_BUTTON + - BIRCH_BUTTON + - DARK_OAK_BUTTON + - JUNGLE_BUTTON + - OAK_BUTTON + - SPRUCE_BUTTON + - STONE_BUTTON + #carpets + - WHITE_CARPET + - ORANGE_CARPET + - MAGENTA_CARPET + - LIGHT_BLUE_CARPET + - YELLOW_CARPET + - LIME_CARPET + - PINK_CARPET + - GRAY_CARPET + - LIGHT_CARPET + - CYAN_CARPET + - PURPLE_CARPET + - BLUE_CARPET + - BROWN_CARPET + - GREEN_CARPET + - RED_CARPET + - BLACK_CARPET + #doors + - ACACIA_DOOR + - BIRCH_DOOR + - DARK_OAK_DOOR + - IRON_DOOR + - JUNGLE_DOOR + - OAK_DOOR + - SPRUCE_DOOR + #fences + - ACACIA_FENCE + - BIRCH_FENCE + - DARK_OAK_FENCE + - JUNGLE_FENCE + - OAK_FENCE + - NETHER_BRICK_FENCE + - SPRUCE_FENCE + #fence gates + - ACACIA_FENCE_GATE + - BIRCH_FENCE_GATE + - DARK_OAK_FENCE_GATE + - JUNGLE_FENCE_GATE + - OAK_FENCE_GATE + - SPRUCE_FENCE_GATE + #glass + - GLASS + - WHITE_STAINED_GLASS + - ORANGE_STAINED_GLASS + - MAGENTA_STAINED_GLASS + - LIGHT_BLUE_STAINED_GLASS + - YELLOW_STAINED_GLASS + - LIME_STAINED_GLASS + - PINK_STAINED_GLASS + - GRAY_STAINED_GLASS + - LIGHT_GRAY_STAINED_GLASS + - CYAN_STAINED_GLASS + - PURPLE_STAINED_GLASS + - BLUE_STAINED_GLASS + - BROWN_STAINED_GLASS + - GREEN_STAINED_GLASS + - RED_STAINED_GLASS + - BLACK_STAINED_GLASS + #glass pane + - GLASS_PANE + - WHITE_STAINED_GLASS_PANE + - ORANGE_STAINED_GLASS_PANE + - MAGENTA_STAINED_GLASS_PANE + - LIGHT_BLUE_STAINED_GLASS_PANE + - YELLOW_STAINED_GLASS_PANE + - LIME_STAINED_GLASS_PANE + - PINK_STAINED_GLASS_PANE + - GRAY_STAINED_GLASS_PANE + - LIGHT_GRAY_STAINED_GLASS_PANE + - CYAN_STAINED_GLASS_PANE + - PURPLE_STAINED_GLASS_PANE + - BLUE_STAINED_GLASS_PANE + - BROWN_STAINED_GLASS_PANE + - GREEN_STAINED_GLASS_PANE + - RED_STAINED_GLASS_PANE + - BLACK_STAINED_GLASS_PANE + #liquids + - LAVA + - WATER + #logs + - BIRCH_LOG + - JUNGLE_LOG + - OAK_LOG + - SPRUCE_LOG + - STRIPPED_BIRCH_LOG + - STRIPPED_JUNGLE_LOG + - STRIPPED_OAK_LOG + - STRIPPED_SPRUCE_LOG + #misc + - BOOKSHELF + - BREWING_STAND + - CRAFTING_TABLE + - CAULDRON + - FURNACE + - GLOWSTONE + - IRON_BARS + - LADDER + - NETHER_BRICKS + - SIGN + - TORCH + - WALL_SIGN + - WALL_TORCH + #planks + - ACACIA_PLANKS + - BIRCH_PLANKS + - DARK_OAK_PLANKS + - JUNGLE_PLANKS + - OAK_PLANKS + - SPRUCE_PLANKS + #pressure plates + - ACACIA_PRESSURE_PLATE + - BIRCH_PRESSURE_PLATE + - DARK_OAK_PRESSURE_PLATE + - HEAVY_WEIGHTED_PRESSURE_PLATE + - JUNGLE_PRESSURE_PLATE + - LIGHT_WEIGHTED_PRESSURE_PLATE + - OAK_PRESSURE_PLATE + - SPRUCE_PRESSURE_PLATE + - STONE_PRESSURE_PLATE + #redstone + - COMPARATOR + - LEVER + - NOTE_BLOCK + - PISTON + - PISTON_HEAD + - REDSTONE_BLOCK + - REDSTONE_WIRE + - REPEATER + - REDSTONE_TORCH + - REDSTONE_WALL_TORCH + - STICKY_PISTON + - TRIPWIRE_HOOK + #slabs + - ACACIA_SLAB + - BIRCH_SLAB + - BRICK_SLAB + - COBBLESTONE_SLAB + - DARK_OAK_SLAB + - DARK_PRISMARINE + - JUNGLE_SLAB + - NETHER_BRICK_SLAB + - OAK_SLAB + - PETRIFIED_OAK_SLAB + - PRISMARINE_SLAB + - PRISMARINE_BRICK_SLAB + - RED_SANDSTONE_SLAB + - QUARTZ_SLAB + - SPRUCE_SLAB + - STONE_SLAB + #stairs + - BIRCH_STAIRS + - JUNGLE_STAIRS + - OAK_STAIRS + - NETHER_BRICK_STAIRS + - SMOOTH_STAIRS + - SPRUCE_STAIRS + - STONE_BRICK_STAIRS + #storage + - CHEST + - DISPENSER + - DROPPER + - HOPPER + - TRAPPED_CHEST + #terracotta + - WHITE_TERRACOTTA + - ORANGE_TERRACOTTA + - MAGENTA_TERRACOTTA + - LIGHT_BLUE_TERRACOTTA + - YELLOW_TERRACOTTA + - LIME_TERRACOTTA + - PINK_TERRACOTTA + - GRAY_TERRACOTTA + - LIGHT_GRAY_TERRACOTTA + - CYAN_TERRACOTTA + - PURPLE_TERRACOTTA + - BLUE_TERRACOTTA + - BROWN_TERRACOTTA + - GREEN_TERRACOTTA + - RED_TERRACOTTA + - BLACK_TERRACOTTA + #trapdoors + - ACACIA_TRAPDOOR + - BIRCH_TRAPDOOR + - DARK_OAK_TRAPDOOR + - JUNGLE_TRAPDOOR + - OAK_TRAPDOOR + - SPRUCE_TRAPDOOR + #weapon blocks + - COAL_BLOCK + #wood + - ACACIA_WOOD + - BIRCH_WOOD + - DARK_OAK_WOOD + - OAK_WOOD + - SPRUCE_WOOD + - STRIPPED_ACACIA_WOOD + - STRIPPED_BIRCH_WOOD + - STRIPPED_DARK_OAK_WOOD + - STRIPPED_OAK_WOOD + - STRIPPED_SPRUCE_WOOD + #wool + - WHITE_WOOL + - ORANGE_WOOL + - MAGENTA_WOOL + - LIGHT_BLUE_WOOL + - YELLOW_WOOL + - LIME_WOOL + - PINK_WOOL + - GRAY_WOOL + - LIGHT_GRAY_WOOL + - CYAN_WOOL + - PURPLE_WOOL + - BLUE_WOOL + - BROWN_WOOL + - GREEN_WOOL + - RED_WOOL + - BLACK_WOOL canCruise: true rotateAtMidpoint: true diff --git a/modules/Movecraft/src/main/resources/types/Submarine.craft b/modules/Movecraft/src/main/resources/types/Submarine.craft index 6047c661f..222eedb87 100644 --- a/modules/Movecraft/src/main/resources/types/Submarine.craft +++ b/modules/Movecraft/src/main/resources/types/Submarine.craft @@ -27,6 +27,23 @@ allowedBlocks: - OAK_BUTTON - SPRUCE_BUTTON - STONE_BUTTON + #carpets + - WHITE_CARPET + - ORANGE_CARPET + - MAGENTA_CARPET + - LIGHT_BLUE_CARPET + - YELLOW_CARPET + - LIME_CARPET + - PINK_CARPET + - GRAY_CARPET + - LIGHT_CARPET + - CYAN_CARPET + - PURPLE_CARPET + - BLUE_CARPET + - BROWN_CARPET + - GREEN_CARPET + - RED_CARPET + - BLACK_CARPET #doors - ACACIA_DOOR - BIRCH_DOOR @@ -41,6 +58,7 @@ allowedBlocks: - DARK_OAK_FENCE - JUNGLE_FENCE - OAK_FENCE + - NETHER_BRICK_FENCE - SPRUCE_FENCE #fence gates - ACACIA_FENCE_GATE @@ -85,15 +103,6 @@ allowedBlocks: - GREEN_STAINED_GLASS_PANE - RED_STAINED_GLASS_PANE - BLACK_STAINED_GLASS_PANE - #interior - - BOOKSHELF - - BREWING_STAND - - CAULDRON - - IRON_BARS - - SIGN - - TORCH - - WALL_SIGN - - WALL_TORCH #liquids - LAVA - WATER @@ -106,6 +115,20 @@ allowedBlocks: - STRIPPED_JUNGLE_LOG - STRIPPED_OAK_LOG - STRIPPED_SPRUCE_LOG + #misc + - BOOKSHELF + - BREWING_STAND + - CRAFTING_TABLE + - CAULDRON + - FURNACE + - GLOWSTONE + - IRON_BARS + - LADDER + - NETHER_BRICKS + - SIGN + - TORCH + - WALL_SIGN + - WALL_TORCH #planks - ACACIA_PLANKS - BIRCH_PLANKS @@ -122,8 +145,10 @@ allowedBlocks: - LIGHT_WEIGHTED_PRESSURE_PLATE - OAK_PRESSURE_PLATE - SPRUCE_PRESSURE_PLATE + - STONE_PRESSURE_PLATE #redstone - COMPARATOR + - LEVER - NOTE_BLOCK - PISTON - PISTON_HEAD @@ -155,8 +180,10 @@ allowedBlocks: - BIRCH_STAIRS - JUNGLE_STAIRS - OAK_STAIRS + - NETHER_BRICK_STAIRS - SMOOTH_STAIRS - SPRUCE_STAIRS + - STONE_BRICK_STAIRS #storage - CHEST - DISPENSER @@ -164,7 +191,6 @@ allowedBlocks: - HOPPER - TRAPPED_CHEST #terracotta - - TERRACOTTA - WHITE_TERRACOTTA - ORANGE_TERRACOTTA - MAGENTA_TERRACOTTA @@ -173,7 +199,7 @@ allowedBlocks: - LIME_TERRACOTTA - PINK_TERRACOTTA - GRAY_TERRACOTTA - - LIGHT_TERRACOTTA + - LIGHT_GRAY_TERRACOTTA - CYAN_TERRACOTTA - PURPLE_TERRACOTTA - BLUE_TERRACOTTA @@ -219,10 +245,6 @@ allowedBlocks: - RED_WOOL - BLACK_WOOL -forbiddenBlocks: - - BEDROCK - - canCruise: true cruiseSkipBlocks: 4 canFly: false diff --git a/modules/Movecraft/src/main/resources/types/airship.craft b/modules/Movecraft/src/main/resources/types/airship.craft index 2fbca116a..4ae6a0256 100644 --- a/modules/Movecraft/src/main/resources/types/airship.craft +++ b/modules/Movecraft/src/main/resources/types/airship.craft @@ -2,225 +2,248 @@ name: Airship maxSize: 5000 minSize: 1000 allowedBlocks: - #beds - - WHITE_BED - - ORANGE_BED - - MAGENTA_BED - - LIGHT_BLUE_BED - - YELLOW_BED - - LIME_BED - - PINK_BED - - GRAY_BED - - LIGHT_BED - - CYAN_BED - - PURPLE_BED - - BLUE_BED - - BROWN_BED - - GREEN_BED - - RED_BED - - BLACK_BED - #buttons - - ACACIA_BUTTON - - BIRCH_BUTTON - - DARK_OAK_BUTTON - - JUNGLE_BUTTON - - OAK_BUTTON - - SPRUCE_BUTTON - - STONE_BUTTON - #doors - - ACACIA_DOOR - - BIRCH_DOOR - - DARK_OAK_DOOR - - IRON_DOOR - - JUNGLE_DOOR - - OAK_DOOR - - SPRUCE_DOOR - #fences - - ACACIA_FENCE - - BIRCH_FENCE - - DARK_OAK_FENCE - - JUNGLE_FENCE - - OAK_FENCE - - SPRUCE_FENCE - #fence gates - - ACACIA_FENCE_GATE - - BIRCH_FENCE_GATE - - DARK_OAK_FENCE_GATE - - JUNGLE_FENCE_GATE - - OAK_FENCE_GATE - - SPRUCE_FENCE_GATE - #glass - - GLASS - - WHITE_STAINED_GLASS - - ORANGE_STAINED_GLASS - - MAGENTA_STAINED_GLASS - - LIGHT_BLUE_STAINED_GLASS - - YELLOW_STAINED_GLASS - - LIME_STAINED_GLASS - - PINK_STAINED_GLASS - - GRAY_STAINED_GLASS - - LIGHT_GRAY_STAINED_GLASS - - CYAN_STAINED_GLASS - - PURPLE_STAINED_GLASS - - BLUE_STAINED_GLASS - - BROWN_STAINED_GLASS - - GREEN_STAINED_GLASS - - RED_STAINED_GLASS - - BLACK_STAINED_GLASS - #glass pane - - GLASS_PANE - - WHITE_STAINED_GLASS_PANE - - ORANGE_STAINED_GLASS_PANE - - MAGENTA_STAINED_GLASS_PANE - - LIGHT_BLUE_STAINED_GLASS_PANE - - YELLOW_STAINED_GLASS_PANE - - LIME_STAINED_GLASS_PANE - - PINK_STAINED_GLASS_PANE - - GRAY_STAINED_GLASS_PANE - - LIGHT_GRAY_STAINED_GLASS_PANE - - CYAN_STAINED_GLASS_PANE - - PURPLE_STAINED_GLASS_PANE - - BLUE_STAINED_GLASS_PANE - - BROWN_STAINED_GLASS_PANE - - GREEN_STAINED_GLASS_PANE - - RED_STAINED_GLASS_PANE - - BLACK_STAINED_GLASS_PANE - #interior - - BOOKSHELF - - BREWING_STAND - - CAULDRON - - IRON_BARS - - SIGN - - TORCH - - WALL_SIGN - - WALL_TORCH - #liquids - - LAVA - - WATER - #logs - - BIRCH_LOG - - JUNGLE_LOG - - OAK_LOG - - SPRUCE_LOG - - STRIPPED_BIRCH_LOG - - STRIPPED_JUNGLE_LOG - - STRIPPED_OAK_LOG - - STRIPPED_SPRUCE_LOG - #planks - - ACACIA_PLANKS - - BIRCH_PLANKS - - DARK_OAK_PLANKS - - JUNGLE_PLANKS - - OAK_PLANKS - - SPRUCE_PLANKS - #pressure plates - - ACACIA_PRESSURE_PLATE - - BIRCH_PRESSURE_PLATE - - DARK_OAK_PRESSURE_PLATE - - HEAVY_WEIGHTED_PRESSURE_PLATE - - JUNGLE_PRESSURE_PLATE - - LIGHT_WEIGHTED_PRESSURE_PLATE - - OAK_PRESSURE_PLATE - - SPRUCE_PRESSURE_PLATE - #redstone - - COMPARATOR - - NOTE_BLOCK - - PISTON - - PISTON_HEAD - - REDSTONE_BLOCK - - REDSTONE_WIRE - - REPEATER - - REDSTONE_TORCH - - REDSTONE_WALL_TORCH - - STICKY_PISTON - - TRIPWIRE_HOOK - #slabs - - ACACIA_SLAB - - BIRCH_SLAB - - BRICK_SLAB - - COBBLESTONE_SLAB - - DARK_OAK_SLAB - - DARK_PRISMARINE - - JUNGLE_SLAB - - NETHER_BRICK_SLAB - - OAK_SLAB - - PETRIFIED_OAK_SLAB - - PRISMARINE_SLAB - - PRISMARINE_BRICK_SLAB - - RED_SANDSTONE_SLAB - - QUARTZ_SLAB - - SPRUCE_SLAB - - STONE_SLAB - #stairs - - BIRCH_STAIRS - - JUNGLE_STAIRS - - OAK_STAIRS - - SMOOTH_STAIRS - - SPRUCE_STAIRS - #storage - - CHEST - - DISPENSER - - DROPPER - - HOPPER - - TRAPPED_CHEST - #terracotta - - TERRACOTTA - - WHITE_TERRACOTTA - - ORANGE_TERRACOTTA - - MAGENTA_TERRACOTTA - - LIGHT_BLUE_TERRACOTTA - - YELLOW_TERRACOTTA - - LIME_TERRACOTTA - - PINK_TERRACOTTA - - GRAY_TERRACOTTA - - LIGHT_TERRACOTTA - - CYAN_TERRACOTTA - - PURPLE_TERRACOTTA - - BLUE_TERRACOTTA - - BROWN_TERRACOTTA - - GREEN_TERRACOTTA - - RED_TERRACOTTA - - BLACK_TERRACOTTA - #trapdoors - - ACACIA_TRAPDOOR - - BIRCH_TRAPDOOR - - DARK_OAK_TRAPDOOR - - JUNGLE_TRAPDOOR - - OAK_TRAPDOOR - - SPRUCE_TRAPDOOR - #weapon blocks - - COAL_BLOCK - #wood - - ACACIA_WOOD - - BIRCH_WOOD - - DARK_OAK_WOOD - - OAK_WOOD - - SPRUCE_WOOD - - STRIPPED_ACACIA_WOOD - - STRIPPED_BIRCH_WOOD - - STRIPPED_DARK_OAK_WOOD - - STRIPPED_OAK_WOOD - - STRIPPED_SPRUCE_WOOD - #wool - - WHITE_WOOL - - ORANGE_WOOL - - MAGENTA_WOOL - - LIGHT_BLUE_WOOL - - YELLOW_WOOL - - LIME_WOOL - - PINK_WOOL - - GRAY_WOOL - - LIGHT_GRAY_WOOL - - CYAN_WOOL - - PURPLE_WOOL - - BLUE_WOOL - - BROWN_WOOL - - GREEN_WOOL - - RED_WOOL - - BLACK_WOOL - -forbiddenBlocks: - - PISTON_HEAD + #beds + - WHITE_BED + - ORANGE_BED + - MAGENTA_BED + - LIGHT_BLUE_BED + - YELLOW_BED + - LIME_BED + - PINK_BED + - GRAY_BED + - LIGHT_BED + - CYAN_BED + - PURPLE_BED + - BLUE_BED + - BROWN_BED + - GREEN_BED + - RED_BED + - BLACK_BED + #buttons + - ACACIA_BUTTON + - BIRCH_BUTTON + - DARK_OAK_BUTTON + - JUNGLE_BUTTON + - OAK_BUTTON + - SPRUCE_BUTTON + - STONE_BUTTON + #carpets + - WHITE_CARPET + - ORANGE_CARPET + - MAGENTA_CARPET + - LIGHT_BLUE_CARPET + - YELLOW_CARPET + - LIME_CARPET + - PINK_CARPET + - GRAY_CARPET + - LIGHT_CARPET + - CYAN_CARPET + - PURPLE_CARPET + - BLUE_CARPET + - BROWN_CARPET + - GREEN_CARPET + - RED_CARPET + - BLACK_CARPET + #doors + - ACACIA_DOOR + - BIRCH_DOOR + - DARK_OAK_DOOR + - IRON_DOOR + - JUNGLE_DOOR + - OAK_DOOR + - SPRUCE_DOOR + #fences + - ACACIA_FENCE + - BIRCH_FENCE + - DARK_OAK_FENCE + - JUNGLE_FENCE + - OAK_FENCE + - NETHER_BRICK_FENCE + - SPRUCE_FENCE + #fence gates + - ACACIA_FENCE_GATE + - BIRCH_FENCE_GATE + - DARK_OAK_FENCE_GATE + - JUNGLE_FENCE_GATE + - OAK_FENCE_GATE + - SPRUCE_FENCE_GATE + #glass + - GLASS + - WHITE_STAINED_GLASS + - ORANGE_STAINED_GLASS + - MAGENTA_STAINED_GLASS + - LIGHT_BLUE_STAINED_GLASS + - YELLOW_STAINED_GLASS + - LIME_STAINED_GLASS + - PINK_STAINED_GLASS + - GRAY_STAINED_GLASS + - LIGHT_GRAY_STAINED_GLASS + - CYAN_STAINED_GLASS + - PURPLE_STAINED_GLASS + - BLUE_STAINED_GLASS + - BROWN_STAINED_GLASS + - GREEN_STAINED_GLASS + - RED_STAINED_GLASS + - BLACK_STAINED_GLASS + #glass pane + - GLASS_PANE + - WHITE_STAINED_GLASS_PANE + - ORANGE_STAINED_GLASS_PANE + - MAGENTA_STAINED_GLASS_PANE + - LIGHT_BLUE_STAINED_GLASS_PANE + - YELLOW_STAINED_GLASS_PANE + - LIME_STAINED_GLASS_PANE + - PINK_STAINED_GLASS_PANE + - GRAY_STAINED_GLASS_PANE + - LIGHT_GRAY_STAINED_GLASS_PANE + - CYAN_STAINED_GLASS_PANE + - PURPLE_STAINED_GLASS_PANE + - BLUE_STAINED_GLASS_PANE + - BROWN_STAINED_GLASS_PANE + - GREEN_STAINED_GLASS_PANE + - RED_STAINED_GLASS_PANE + - BLACK_STAINED_GLASS_PANE + #liquids + - LAVA + - WATER + #logs + - BIRCH_LOG + - JUNGLE_LOG + - OAK_LOG + - SPRUCE_LOG + - STRIPPED_BIRCH_LOG + - STRIPPED_JUNGLE_LOG + - STRIPPED_OAK_LOG + - STRIPPED_SPRUCE_LOG + #misc + - BOOKSHELF + - BREWING_STAND + - CRAFTING_TABLE + - CAULDRON + - FURNACE + - GLOWSTONE + - IRON_BARS + - LADDER + - NETHER_BRICKS + - SIGN + - TORCH + - WALL_SIGN + - WALL_TORCH + #planks + - ACACIA_PLANKS + - BIRCH_PLANKS + - DARK_OAK_PLANKS + - JUNGLE_PLANKS + - OAK_PLANKS + - SPRUCE_PLANKS + #pressure plates + - ACACIA_PRESSURE_PLATE + - BIRCH_PRESSURE_PLATE + - DARK_OAK_PRESSURE_PLATE + - HEAVY_WEIGHTED_PRESSURE_PLATE + - JUNGLE_PRESSURE_PLATE + - LIGHT_WEIGHTED_PRESSURE_PLATE + - OAK_PRESSURE_PLATE + - SPRUCE_PRESSURE_PLATE + - STONE_PRESSURE_PLATE + #redstone + - COMPARATOR + - LEVER + - NOTE_BLOCK + - PISTON + - PISTON_HEAD + - REDSTONE_BLOCK + - REDSTONE_WIRE + - REPEATER + - REDSTONE_TORCH + - REDSTONE_WALL_TORCH + - STICKY_PISTON + - TRIPWIRE_HOOK + #slabs + - ACACIA_SLAB + - BIRCH_SLAB + - BRICK_SLAB + - COBBLESTONE_SLAB + - DARK_OAK_SLAB + - DARK_PRISMARINE + - JUNGLE_SLAB + - NETHER_BRICK_SLAB + - OAK_SLAB + - PETRIFIED_OAK_SLAB + - PRISMARINE_SLAB + - PRISMARINE_BRICK_SLAB + - RED_SANDSTONE_SLAB + - QUARTZ_SLAB + - SPRUCE_SLAB + - STONE_SLAB + #stairs + - BIRCH_STAIRS + - JUNGLE_STAIRS + - OAK_STAIRS + - NETHER_BRICK_STAIRS + - SMOOTH_STAIRS + - SPRUCE_STAIRS + - STONE_BRICK_STAIRS + #storage + - CHEST + - DISPENSER + - DROPPER + - HOPPER + - TRAPPED_CHEST + #terracotta + - WHITE_TERRACOTTA + - ORANGE_TERRACOTTA + - MAGENTA_TERRACOTTA + - LIGHT_BLUE_TERRACOTTA + - YELLOW_TERRACOTTA + - LIME_TERRACOTTA + - PINK_TERRACOTTA + - GRAY_TERRACOTTA + - LIGHT_GRAY_TERRACOTTA + - CYAN_TERRACOTTA + - PURPLE_TERRACOTTA + - BLUE_TERRACOTTA + - BROWN_TERRACOTTA + - GREEN_TERRACOTTA + - RED_TERRACOTTA + - BLACK_TERRACOTTA + #trapdoors + - ACACIA_TRAPDOOR + - BIRCH_TRAPDOOR + - DARK_OAK_TRAPDOOR + - JUNGLE_TRAPDOOR + - OAK_TRAPDOOR + - SPRUCE_TRAPDOOR + #weapon blocks + - COAL_BLOCK + #wood + - ACACIA_WOOD + - BIRCH_WOOD + - DARK_OAK_WOOD + - OAK_WOOD + - SPRUCE_WOOD + - STRIPPED_ACACIA_WOOD + - STRIPPED_BIRCH_WOOD + - STRIPPED_DARK_OAK_WOOD + - STRIPPED_OAK_WOOD + - STRIPPED_SPRUCE_WOOD + #wool + - WHITE_WOOL + - ORANGE_WOOL + - MAGENTA_WOOL + - LIGHT_BLUE_WOOL + - YELLOW_WOOL + - LIME_WOOL + - PINK_WOOL + - GRAY_WOOL + - LIGHT_GRAY_WOOL + - CYAN_WOOL + - PURPLE_WOOL + - BLUE_WOOL + - BROWN_WOOL + - GREEN_WOOL + - RED_WOOL + - BLACK_WOOL canCruise: true rotateAtMidpoint: true diff --git a/modules/api/src/main/java/net/countercraft/movecraft/MovecraftRepair.java b/modules/api/src/main/java/net/countercraft/movecraft/MovecraftRepair.java index 09c89218b..830db6cdf 100644 --- a/modules/api/src/main/java/net/countercraft/movecraft/MovecraftRepair.java +++ b/modules/api/src/main/java/net/countercraft/movecraft/MovecraftRepair.java @@ -12,6 +12,7 @@ import org.bukkit.util.Vector; import java.io.File; +import java.util.ArrayDeque; import java.util.HashMap; import java.util.HashSet; import java.util.LinkedList; @@ -20,14 +21,14 @@ public abstract class MovecraftRepair { public abstract boolean saveCraftRepairState(Craft craft, Sign sign, Plugin plugin, String repairStateName); public abstract boolean saveRegionRepairState(Plugin plugin, World world, ProtectedRegion region); public abstract boolean repairRegion(World world, String regionName); - public abstract Clipboard loadCraftRepairStateClipboard(Plugin plugin, Sign sign, String repairStateName, World bukkitWorld); + public abstract Clipboard loadCraftRepairStateClipboard(Plugin plugin, Craft craft, Sign sign, String repairStateName, World bukkitWorld); public abstract Clipboard loadRegionRepairStateClipboard(Plugin plugin, String repairStateName, World bukkitWorld); public abstract HashMap getMissingBlocks(String repairName); - public abstract LinkedList getMissingBlockLocations(String repairName); + public abstract ArrayDeque getMissingBlockLocations(String repairName); public abstract long getNumDiffBlocks(String repairName); - public abstract org.bukkit.util.Vector getDistanceFromSignToLowestPoint(Clipboard clipboard, String repairName); - public abstract org.bukkit.util.Vector getDistanceFromClipboardToWorldOffset(org.bukkit.util.Vector offset, Clipboard clipboard); - public abstract void setFawePlugin(Plugin fawePlugin); + public abstract org.bukkit.util.Vector getDistanceFromSignToLowestPoint(Clipboard clipboard); + public abstract org.bukkit.util.Vector getDistance(String repairName); + } diff --git a/modules/api/src/main/java/net/countercraft/movecraft/RepairLocation.java b/modules/api/src/main/java/net/countercraft/movecraft/RepairLocation.java deleted file mode 100644 index b18106cd0..000000000 --- a/modules/api/src/main/java/net/countercraft/movecraft/RepairLocation.java +++ /dev/null @@ -1,20 +0,0 @@ -package net.countercraft.movecraft; - -import org.bukkit.block.Block; - -public final class RepairLocation implements Comparable { - private final int x; - private final int y; - private final int z; - private final Block block; - public RepairLocation(int x, int y, int z, Block block){ - this.x = x; - this.y = y; - this.z = z; - this.block = block; - } - @Override - public int compareTo(RepairLocation other) { - return 0; - } -} diff --git a/modules/api/src/main/java/net/countercraft/movecraft/config/Settings.java b/modules/api/src/main/java/net/countercraft/movecraft/config/Settings.java index 128822ecc..1ec05dd25 100644 --- a/modules/api/src/main/java/net/countercraft/movecraft/config/Settings.java +++ b/modules/api/src/main/java/net/countercraft/movecraft/config/Settings.java @@ -92,4 +92,5 @@ public class Settings { public static boolean SiegeEnable; public static String SiegeTimeZone; + public static boolean KOTHSiege = false; } diff --git a/modules/api/src/main/java/net/countercraft/movecraft/craft/Craft.java b/modules/api/src/main/java/net/countercraft/movecraft/craft/Craft.java index 71679bf60..4e4f9bca4 100644 --- a/modules/api/src/main/java/net/countercraft/movecraft/craft/Craft.java +++ b/modules/api/src/main/java/net/countercraft/movecraft/craft/Craft.java @@ -43,6 +43,7 @@ public abstract class Craft { //protected int[][][] hitBox; //protected MovecraftLocation[] blockList; @NotNull protected HashHitBox hitBox; + @NotNull protected final HashHitBox collapsedHitBox; @NotNull protected World w; @NotNull private final AtomicBoolean processing = new AtomicBoolean(); @@ -70,12 +71,13 @@ public abstract class Craft { private int numMoves; @NotNull private final Map phaseBlocks = new HashMap<>(); @NotNull private final HashMap crewSigns = new HashMap<>(); - @NotNull private String uniqueName = ""; + @NotNull private String name = ""; public Craft(@NotNull CraftType type, @NotNull World world) { this.type = type; this.w = world; this.hitBox = new HashHitBox(); + this.collapsedHitBox = new HashHitBox(); if (type.getMaxHeightLimit() > w.getMaxHeight() - 1) { this.maxHeightLimit = w.getMaxHeight() - 1; } else { @@ -412,6 +414,10 @@ public Map getPhaseBlocks(){ return phaseBlocks; } + @NotNull + public final HashHitBox getCollapsedHitBox(){ + return collapsedHitBox; + } @NotNull public Map getCrewSigns(){ return crewSigns; @@ -419,9 +425,9 @@ public Map getCrewSigns(){ @NotNull public String getUniqueName(){ - return uniqueName; + return name; } - public void setUniqueName(String uniqueName){ - this.uniqueName = uniqueName; + public void setUniqueName(String name){ + this.name = name; } } \ No newline at end of file diff --git a/modules/v1_12_R1/src/main/java/net/countercraft/movecraft/compat/v1_12_R1/IWorldHandler.java b/modules/v1_12_R1/src/main/java/net/countercraft/movecraft/compat/v1_12_R1/IWorldHandler.java index 1e736633b..feccc8f46 100644 --- a/modules/v1_12_R1/src/main/java/net/countercraft/movecraft/compat/v1_12_R1/IWorldHandler.java +++ b/modules/v1_12_R1/src/main/java/net/countercraft/movecraft/compat/v1_12_R1/IWorldHandler.java @@ -8,6 +8,7 @@ import net.countercraft.movecraft.WorldHandler; import net.countercraft.movecraft.craft.Craft; import net.minecraft.server.v1_12_R1.*; +import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.craftbukkit.v1_12_R1.CraftWorld; @@ -15,6 +16,7 @@ import org.bukkit.craftbukkit.v1_12_R1.entity.CraftPlayer; import org.bukkit.craftbukkit.v1_12_R1.util.CraftMagicNumbers; import org.bukkit.entity.Player; +import org.bukkit.event.player.PlayerMoveEvent; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -60,7 +62,10 @@ public void addPlayerLocation(Player player, double x, double y, double z, float return; } try { + final Location oldLoc = player.getLocation().clone(); + final Location newLoc = player.getLocation().add(x,y,z); internalTeleportMH.invoke(ePlayer.playerConnection, x, y, z, yaw, pitch, EnumSet.allOf(PacketPlayOutPosition.EnumPlayerTeleportFlags.class)); + Bukkit.getServer().getPluginManager().callEvent(new PlayerMoveEvent(player,oldLoc,newLoc)); } catch (Throwable throwable) { throwable.printStackTrace(); } diff --git a/modules/v1_13_R2/pom.xml b/modules/v1_13_R2/pom.xml index a4f0b8f6a..3d0367264 100644 --- a/modules/v1_13_R2/pom.xml +++ b/modules/v1_13_R2/pom.xml @@ -20,31 +20,13 @@ ../../ - - - - sk89q-repo - http://maven.sk89q.com/repo/ - - - - com.sk89q.worldedit - worldedit-bukkit - 7.0.0-SNAPSHOT - net.countercraft movecraft-api API jar - - net.countercraft - movecraft-FAWEUtils - FAWEUtils - jar - org.jetbrains annotations-java5 diff --git a/modules/v1_14_R1/pom.xml b/modules/v1_14_R1/pom.xml new file mode 100644 index 000000000..5748feec0 --- /dev/null +++ b/modules/v1_14_R1/pom.xml @@ -0,0 +1,69 @@ + + + 4.0.0 + movecraft-v1_14_R1 + jar + Movecraft-v1_14_R1 + http://github.com/eirikh1996/Movecraft + v1_14_R1 + + + UTF-8 + + + + movecraft-parent + net.countercraft + parent + ../../ + + + + + net.countercraft + movecraft-api + API + jar + + + org.jetbrains + annotations-java5 + RELEASE + + + org.bukkit + craftbukkit + 1.14-pre5-SNAPSHOT + + + + src/main/java + + + org.apache.maven.plugins + maven-compiler-plugin + 3.7.0 + + + net/countercraft/movecraft/compat/v1_14_R1/** + + 1.8 + 1.8 + + + + org.apache.maven.plugins + maven-jar-plugin + 2.4 + + + net/countercraft/movecraft/compat/v1_14_R1/** + + + + + + + \ No newline at end of file diff --git a/modules/v1_14_R1/src/main/java/net/countercraft/movecraft/compat/v1_14_R1/IWorldHandler.java b/modules/v1_14_R1/src/main/java/net/countercraft/movecraft/compat/v1_14_R1/IWorldHandler.java new file mode 100644 index 000000000..885506dbd --- /dev/null +++ b/modules/v1_14_R1/src/main/java/net/countercraft/movecraft/compat/v1_14_R1/IWorldHandler.java @@ -0,0 +1,366 @@ +package net.countercraft.movecraft.compat.v1_14_R1; + +import net.countercraft.movecraft.MovecraftLocation; +import net.countercraft.movecraft.Rotation; +import net.countercraft.movecraft.WorldHandler; +import net.countercraft.movecraft.config.Settings; +import net.countercraft.movecraft.craft.Craft; +import net.countercraft.movecraft.utils.CollectionUtils; +import net.countercraft.movecraft.utils.MathUtils; + +import net.minecraft.server.v1_14_R1.*; + +import org.bukkit.craftbukkit.v1_14_R1.CraftWorld; +import org.bukkit.craftbukkit.v1_14_R1.block.CraftBlockState; +import org.bukkit.craftbukkit.v1_14_R1.util.CraftMagicNumbers; + +import org.bukkit.Location; +import org.bukkit.Material; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.*; + +public class IWorldHandler extends WorldHandler { + private static final EnumBlockRotation ROTATION[]; + static { + ROTATION = new EnumBlockRotation[3]; + ROTATION[Rotation.NONE.ordinal()] = EnumBlockRotation.NONE; + ROTATION[Rotation.CLOCKWISE.ordinal()] = EnumBlockRotation.CLOCKWISE_90; + ROTATION[Rotation.ANTICLOCKWISE.ordinal()] = EnumBlockRotation.COUNTERCLOCKWISE_90; + } + private final NextTickProvider tickProvider = new NextTickProvider(); + private final HashMap> bMap = new HashMap<>(); + private MethodHandle internalTeleportMH; + + public IWorldHandler() { + MethodHandles.Lookup lookup = MethodHandles.lookup(); + Method teleport = null; + try { + teleport = PlayerConnection.class.getDeclaredMethod("internalTeleport", double.class, double.class, double.class, float.class, float.class, Set.class); + teleport.setAccessible(true); + internalTeleportMH = lookup.unreflect(teleport); + + } catch (NoSuchMethodException | IllegalAccessException e) { + e.printStackTrace(); + } + } + + @Override + public void rotateCraft(@NotNull Craft craft, @NotNull MovecraftLocation originPoint, @NotNull Rotation rotation) { + //******************************************* + //* Step one: Convert to Positions * + //******************************************* + HashMap rotatedPositions = new HashMap<>(); + Rotation counterRotation = rotation == Rotation.CLOCKWISE ? Rotation.ANTICLOCKWISE : Rotation.CLOCKWISE; + for(MovecraftLocation newLocation : craft.getHitBox()){ + rotatedPositions.put(locationToPosition(MathUtils.rotateVec(counterRotation, newLocation.subtract(originPoint)).add(originPoint)),locationToPosition(newLocation)); + } + //******************************************* + //* Step two: Get the tiles * + //******************************************* + World nativeWorld = ((CraftWorld) craft.getW()).getHandle(); + List tiles = new ArrayList<>(); + //get the tiles + for(BlockPosition position : rotatedPositions.keySet()){ + //TileEntity tile = nativeWorld.removeTileEntity(position); + TileEntity tile = removeTileEntity(nativeWorld,position); + if(tile == null) + continue; + tile.a(ROTATION[rotation.ordinal()]); + //get the nextTick to move with the tile + tiles.add(new TileHolder(tile, tickProvider.getNextTick((WorldServer)nativeWorld,position), position)); + } + + //******************************************* + //* Step three: Translate all the blocks * + //******************************************* + // blockedByWater=false means an ocean-going vessel + //TODO: Simplify + //TODO: go by chunks + //TODO: Don't move unnecessary blocks + //get the blocks and rotate them + HashMap blockData = new HashMap<>(); + for(BlockPosition position : rotatedPositions.keySet()){ + blockData.put(position,nativeWorld.getType(position).a(ROTATION[rotation.ordinal()])); + } + //create the new block + for(Map.Entry entry : blockData.entrySet()) { + setBlockFast(nativeWorld, rotatedPositions.get(entry.getKey()), entry.getValue()); + } + + + //******************************************* + //* Step four: replace all the tiles * + //******************************************* + //TODO: go by chunks + for(TileHolder tileHolder : tiles){ + moveTileEntity(nativeWorld, rotatedPositions.get(tileHolder.getTilePosition()),tileHolder.getTile()); + if(tileHolder.getNextTick()==null) + continue; + final long currentTime = nativeWorld.worldData.getTime(); + //nativeWorld.b(rotatedPositions.get(tileHolder.getNextTick().a), tileHolder.getNextTick().a(), (int) (tileHolder.getNextTick().b - currentTime), tileHolder.getNextTick().c); + //BlockPosition, Object, int, TickListPriority + nativeWorld.b(rotatedPositions.get(tileHolder.getNextTick().a), tileHolder.getTile()); + } + + //******************************************* + //* Step five: Destroy the leftovers * + //******************************************* + //TODO: add support for pass-through + Collection deletePositions = CollectionUtils.filter(rotatedPositions.keySet(),rotatedPositions.values()); + for(BlockPosition position : deletePositions){ + setBlockFast(nativeWorld, position, Blocks.AIR.getBlockData()); + } + + //******************************************* + //* Step six: Update the blocks * + //******************************************* + for(BlockPosition newPosition : rotatedPositions.values()) { + // CraftBlockState.getBlockState(nativeWorld,newPosition.getX(), newPosition.getY(), newPosition.getZ()).update(false,false); + CraftBlockState.getBlockState(nativeWorld, newPosition, 3).update(false, false); + } + for(BlockPosition deletedPosition : deletePositions){ + // CraftBlockState.getBlockState(nativeWorld,deletedPosition.getX(), deletedPosition.getY(), deletedPosition.getZ()).update(false,false); + CraftBlockState.getBlockState(nativeWorld, deletedPosition, 3).update(false, false); + } + //******************************************* + //* Step seven: Send to players * + //******************************************* + List chunks = new ArrayList<>(); + for(BlockPosition position : rotatedPositions.values()){ + Chunk chunk = nativeWorld.getChunkAtWorldCoords(position); + if(!chunks.contains(chunk)){ + chunks.add(chunk); + } + } + for(BlockPosition position : deletePositions){ + Chunk chunk = nativeWorld.getChunkAtWorldCoords(position); + if(!chunks.contains(chunk)){ + chunks.add(chunk); + } + } + } + + @Override + public void translateCraft(@NotNull Craft craft, @NotNull MovecraftLocation displacement) { + //TODO: Add supourt for rotations + //A craftTranslateCommand should only occur if the craft is moving to a valid position + //******************************************* + //* Step one: Convert to Positions * + //******************************************* + BlockPosition translateVector = locationToPosition(displacement); + List positions = new ArrayList<>(); + for(MovecraftLocation movecraftLocation : craft.getHitBox()) { + positions.add(locationToPosition((movecraftLocation)).b(translateVector)); + + } + //******************************************* + //* Step two: Get the tiles * + //******************************************* + World nativeWorld = ((CraftWorld) craft.getW()).getHandle(); + List tiles = new ArrayList<>(); + //get the tiles + for(BlockPosition position : positions){ + if(nativeWorld.getType(position) == Blocks.AIR.getBlockData()) + continue; + //TileEntity tile = nativeWorld.removeTileEntity(position); + TileEntity tile = removeTileEntity(nativeWorld,position); + if(tile == null) + continue; + //get the nextTick to move with the tile + + //nativeWorld.capturedTileEntities.remove(position); + //nativeWorld.getChunkAtWorldCoords(position).getTileEntities().remove(position); + tiles.add(new TileHolder(tile, tickProvider.getNextTick((WorldServer)nativeWorld,position), position)); + + } + //******************************************* + //* Step three: Translate all the blocks * + //******************************************* + // blockedByWater=false means an ocean-going vessel + //TODO: Simplify + //TODO: go by chunks + //TODO: Don't move unnecessary blocks + //get the blocks + List blockData = new ArrayList<>(); + for(BlockPosition position : positions){ + blockData.add(nativeWorld.getType(position)); + } + //translate the positions + List newPositions = new ArrayList<>(); + for(BlockPosition position : positions){ + newPositions.add(position.a(translateVector)); + } + //create the new block + for(int i = 0; i deletePositions = CollectionUtils.filter(positions,newPositions); + for(BlockPosition position : deletePositions){ + setBlockFast(nativeWorld, position, Blocks.AIR.getBlockData()); + } + + //******************************************* + //* Step six: Update the blocks * + //******************************************* + for(BlockPosition newPosition : newPositions) { + CraftBlockState.getBlockState(nativeWorld, newPosition, 3).update(false,false); + } + for(BlockPosition deletedPosition : deletePositions){ + CraftBlockState.getBlockState(nativeWorld, deletedPosition, 3).update(false,false); + } + //******************************************* + //* Step seven: Send to players * + //******************************************* + List chunks = new ArrayList<>(); + for(BlockPosition position : newPositions){ + Chunk chunk = nativeWorld.getChunkAtWorldCoords(position); + if(!chunks.contains(chunk)){ + chunks.add(chunk); + } + } + for(BlockPosition position : deletePositions){ + Chunk chunk = nativeWorld.getChunkAtWorldCoords(position); + if(!chunks.contains(chunk)){ + chunks.add(chunk); + } + } + //sendToPlayers(chunks.toArray(new Chunk[0])); + } + + @Nullable + private TileEntity removeTileEntity(@NotNull World world, @NotNull BlockPosition position){ + TileEntity tile = world.getTileEntity(position); + if(tile == null) + return null; + //cleanup + world.capturedTileEntities.remove(position); + world.getChunkAtWorldCoords(position).getTileEntities().remove(position); + if(!Settings.IsPaper) + world.tileEntityList.remove(tile); + world.tileEntityListTick.remove(tile); + if(!bMap.containsKey(world)){ + try { + Field bField = World.class.getDeclaredField("c"); + bField.setAccessible(true); + bMap.put(world, (List) bField.get(world));//TODO bug fix + } catch (IllegalAccessException | IllegalArgumentException | NoSuchFieldException | SecurityException e1) { + e1.printStackTrace(); + } + } + bMap.get(world).remove(tile); + return tile; + } + + @NotNull + private BlockPosition locationToPosition(@NotNull MovecraftLocation loc) { + return new BlockPosition(loc.getX(), loc.getY(), loc.getZ()); + } + + private void setBlockFast(@NotNull World world, @NotNull BlockPosition position,@NotNull IBlockData data) { + Chunk chunk = world.getChunkAtWorldCoords(position); + ChunkSection chunkSection = chunk.getSections()[position.getY()>>4]; + if (chunkSection == null) { + // Put a GLASS block to initialize the section. It will be replaced next with the real block. + chunk.setType(position, Blocks.GLASS.getBlockData(), true); + chunkSection = chunk.getSections()[position.getY() >> 4]; + + } + + chunkSection.setType(position.getX()&15, position.getY()&15, position.getZ()&15, data); + } + + @Override + public void setBlockFast(@NotNull Location location, @NotNull Material material, byte data){ + setBlockFast(location, Rotation.NONE, material, data); + } + + @Override + public void setBlockFast(@NotNull Location location, @NotNull Rotation rotation, @NotNull Material material, byte data) { + IBlockData blockData = CraftMagicNumbers.getBlock(material).getBlockData(); + blockData = blockData.a(ROTATION[rotation.ordinal()]); + World world = ((CraftWorld)(location.getWorld())).getHandle(); + BlockPosition blockPosition = locationToPosition(bukkit2MovecraftLoc(location)); + setBlockFast(world,blockPosition,blockData); + } + + @Override + public void disableShadow(@NotNull Material type) { + Method method; + //try { + Block tempBlock = CraftMagicNumbers.getBlock(type); + //method = Block.class.getDeclaredMethod("d", int.class); + //method.setAccessible(true); + //method.invoke(tempBlock, 0); + //} catch (NoSuchMethodException | InvocationTargetException | IllegalArgumentException | IllegalAccessException | SecurityException e1) { + // TODO Auto-generated catch block + // e1.printStackTrace(); + //} + } + + private static MovecraftLocation bukkit2MovecraftLoc(Location l) { + return new MovecraftLocation(l.getBlockX(), l.getBlockY(), l.getBlockZ()); + } + + private void moveTileEntity(@NotNull World nativeWorld, @NotNull BlockPosition newPosition, @NotNull TileEntity tile){ + Chunk chunk = nativeWorld.getChunkAtWorldCoords(newPosition); + tile.invalidateBlockCache(); + if(nativeWorld.captureBlockStates) { + tile.setWorld(nativeWorld); + tile.setPosition(newPosition); + nativeWorld.capturedTileEntities.put(newPosition, tile); + return; + } + tile.setPosition(newPosition); + chunk.tileEntities.put(newPosition, tile); + } + + private class TileHolder{ + @NotNull private final TileEntity tile; + @Nullable + private final NextTickListEntry nextTick; + @NotNull private final BlockPosition tilePosition; + + public TileHolder(@NotNull TileEntity tile, @Nullable NextTickListEntry nextTick, @NotNull BlockPosition tilePosition){ + this.tile = tile; + this.nextTick = nextTick; + this.tilePosition = tilePosition; + } + + + @NotNull + public TileEntity getTile() { + return tile; + } + + @Nullable + public NextTickListEntry getNextTick() { + return nextTick; + } + + @NotNull + public BlockPosition getTilePosition() { + return tilePosition; + } + } +} diff --git a/modules/v1_14_R1/src/main/java/net/countercraft/movecraft/compat/v1_14_R1/NextTickProvider.java b/modules/v1_14_R1/src/main/java/net/countercraft/movecraft/compat/v1_14_R1/NextTickProvider.java new file mode 100644 index 000000000..221adcf48 --- /dev/null +++ b/modules/v1_14_R1/src/main/java/net/countercraft/movecraft/compat/v1_14_R1/NextTickProvider.java @@ -0,0 +1,60 @@ +package net.countercraft.movecraft.compat.v1_14_R1; + +import org.apache.commons.lang3.tuple.ImmutablePair; +import org.bukkit.craftbukkit.v1_14_R1.util.HashTreeSet; + +import net.minecraft.server.v1_14_R1.*; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.lang.reflect.Field; +import java.util.*; + +public class NextTickProvider { + private Map,List>> tickMap = new HashMap<>(); + + private boolean isRegistered(@NotNull WorldServer world){ + return tickMap.containsKey(world); + } + + @SuppressWarnings("unchecked") + private void registerWorld(@NotNull WorldServer world){ + List W = new ArrayList<>(); + HashTreeSet nextTickList = new HashTreeSet<>(); + TickListServer blockTickListServer = world.getBlockTickList(); + try { + Field gField = TickListServer.class.getDeclaredField("g"); + gField.setAccessible(true); + W = (List) gField.get(blockTickListServer); + Field ntlField = TickListServer.class.getDeclaredField("nextTickList"); + ntlField.setAccessible(true); + nextTickList = (HashTreeSet) ntlField.get(blockTickListServer); + } catch (IllegalAccessException | IllegalArgumentException | NoSuchFieldException | SecurityException e1) { + e1.printStackTrace(); + } + tickMap.put(world, new ImmutablePair<>(nextTickList,W)); + } + + @Nullable + public NextTickListEntry getNextTick(@NotNull WorldServer world,@NotNull BlockPosition position){ + if(!isRegistered(world)) + registerWorld(world); + ImmutablePair, List> listPair = tickMap.get(world); + for(Iterator iterator = listPair.left.iterator(); iterator.hasNext();) { + NextTickListEntry listEntry = iterator.next(); + if (position.equals(listEntry.a)) { + iterator.remove(); + return listEntry; + } + } + for(Iterator iterator = listPair.right.iterator(); iterator.hasNext();) { + NextTickListEntry listEntry = iterator.next(); + if (position.equals(listEntry.a)) { + iterator.remove(); + return listEntry; + } + } + return null; + + } +} diff --git a/modules/worldedit/WE6Utils/src/main/java/net/countercraft/movecraft/compat/we6/IMovecraftRepair.java b/modules/worldedit/WE6Utils/src/main/java/net/countercraft/movecraft/compat/we6/IMovecraftRepair.java index a3662f9e8..5461797c5 100644 --- a/modules/worldedit/WE6Utils/src/main/java/net/countercraft/movecraft/compat/we6/IMovecraftRepair.java +++ b/modules/worldedit/WE6Utils/src/main/java/net/countercraft/movecraft/compat/we6/IMovecraftRepair.java @@ -7,6 +7,7 @@ import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.blocks.BaseBlock; import com.sk89q.worldedit.bukkit.BukkitWorld; +import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard; import com.sk89q.worldedit.extent.clipboard.Clipboard; @@ -39,15 +40,13 @@ import org.bukkit.util.Vector; import java.io.*; -import java.util.HashMap; -import java.util.HashSet; -import java.util.LinkedList; -import java.util.Set; +import java.util.*; public class IMovecraftRepair extends MovecraftRepair { - private HashMap> locMissingBlocksMap = new HashMap<>(); + private HashMap> locMissingBlocksMap = new HashMap<>(); private HashMap numDiffBlocksMap = new HashMap<>(); private HashMap> missingBlocksMap = new HashMap<>(); + private final HashMap distanceMap = new HashMap<>(); @Override public boolean saveCraftRepairState (Craft craft, Sign sign, Plugin plugin, String s) { @@ -59,6 +58,7 @@ public boolean saveCraftRepairState (Craft craft, Sign sign, Plugin plugin, Stri if (!saveDirectory.exists()){ saveDirectory.mkdirs(); } + com.sk89q.worldedit.Vector origin = new com.sk89q.worldedit.Vector(sign.getX(),sign.getY(),sign.getZ()); com.sk89q.worldedit.Vector minPos = new com.sk89q.worldedit.Vector(hitBox.getMinX(), hitBox.getMinY(), hitBox.getMinZ()); com.sk89q.worldedit.Vector maxPos = new com.sk89q.worldedit.Vector(hitBox.getMaxX(), hitBox.getMaxY(), hitBox.getMaxZ()); CuboidRegion cRegion = new CuboidRegion(minPos, maxPos); @@ -69,7 +69,7 @@ public boolean saveCraftRepairState (Craft craft, Sign sign, Plugin plugin, Stri BlockArrayClipboard clipboard = new BlockArrayClipboard(cRegion); Extent source = WorldEdit.getInstance().getEditSessionFactory().getEditSession(weWorld, -1); Extent destination = clipboard; - ForwardExtentCopy copy = new ForwardExtentCopy(source, cRegion, clipboard.getOrigin(), destination, minPos); + ForwardExtentCopy copy = new ForwardExtentCopy(source, cRegion, clipboard.getOrigin(), destination, clipboard.getOrigin()); BlockMask mask = new BlockMask(source, blockSet); copy.setSourceMask(mask); Operations.completeLegacy(copy); @@ -148,12 +148,13 @@ public boolean repairRegion(World world, String s) { } @Override - public Clipboard loadCraftRepairStateClipboard(Plugin plugin, Sign sign, String repairStateFile, World world) { + public Clipboard loadCraftRepairStateClipboard(Plugin plugin,Craft craft, Sign sign, String repairStateFile, World world) { File dataDirectory = new File(plugin.getDataFolder(), "CraftRepairStates"); File file = new File(dataDirectory, repairStateFile + ".schematic"); // The schematic file com.sk89q.worldedit.world.World weWorld = new BukkitWorld(world); WorldData worldData = weWorld.getWorldData(); Clipboard clipboard; + HashHitBox hitBox = craft.getHitBox(); try { clipboard = ClipboardFormat.SCHEMATIC.getReader(new FileInputStream(file)).read(worldData); @@ -164,11 +165,13 @@ public Clipboard loadCraftRepairStateClipboard(Plugin plugin, Sign sign, String if (clipboard != null){ long numDiffBlocks = 0; HashMap missingBlocks = new HashMap<>(); - LinkedList locMissingBlocks = new LinkedList<>(); - org.bukkit.util.Vector bukkitDistMP = getDistanceFromSignToLowestPoint(clipboard, sign.getLine(1)); - com.sk89q.worldedit.Vector distMP = new com.sk89q.worldedit.Vector(bukkitDistMP.getBlockX(),bukkitDistMP.getBlockY(),bukkitDistMP.getBlockZ()); - com.sk89q.worldedit.Vector minPos = new com.sk89q.worldedit.Vector(sign.getLocation().getBlockX() - distMP.getBlockX(), sign.getLocation().getBlockY() - distMP.getBlockY(), sign.getLocation().getBlockZ() - distMP.getBlockZ()); - com.sk89q.worldedit.Vector distance = new com.sk89q.worldedit.Vector(minPos.getBlockX() - clipboard.getMinimumPoint().getBlockX(), minPos.getBlockY() - clipboard.getMinimumPoint().getBlockY(), minPos.getBlockZ() - clipboard.getMinimumPoint().getBlockZ()); + ArrayDeque locMissingBlocks = new ArrayDeque<>(); + Vector distance = new Vector(sign.getX() - hitBox.getMinX(), sign.getY() - hitBox.getMinY(),sign.getZ() - hitBox.getMinZ()); + if (distanceMap.containsKey(repairStateFile)) { + distanceMap.replace(repairStateFile,distance); + } else { + distanceMap.put(repairStateFile,distance); + } for (int x = clipboard.getMinimumPoint().getBlockX(); x <= clipboard.getMaximumPoint().getBlockX(); x++){ for (int y = clipboard.getMinimumPoint().getBlockY(); y <= clipboard.getMaximumPoint().getBlockY(); y++){ for (int z = clipboard.getMinimumPoint().getBlockZ(); z <= clipboard.getMaximumPoint().getBlockZ(); z++){ @@ -316,7 +319,7 @@ public Clipboard loadCraftRepairStateClipboard(Plugin plugin, Sign sign, String num += qtyToConsume; missingBlocks.put(Material.getMaterial(itemToConsume), num); } - locMissingBlocks.push(new org.bukkit.util.Vector(x,y,z)); + locMissingBlocks.add(new Vector(x,y,z)); } } if (bukkitBlock.getType() == Material.DISPENSER && block.getType() == 23){ @@ -431,7 +434,7 @@ public HashMap getMissingBlocks(String repairName) { } @Override - public LinkedList getMissingBlockLocations(String repairName) { + public ArrayDeque getMissingBlockLocations(String repairName) { return locMissingBlocksMap.get(repairName); } @@ -441,9 +444,9 @@ public long getNumDiffBlocks(String s) { } @Override - public org.bukkit.util.Vector getDistanceFromSignToLowestPoint(Clipboard clipboard, String repairName) { - org.bukkit.util.Vector returnDistance = null; - for (int x = clipboard.getMinimumPoint().getBlockX(); x <= clipboard.getMaximumPoint().getBlockX(); x++) { + public Vector getDistanceFromSignToLowestPoint(Clipboard clipboard) { + return new Vector(clipboard.getOrigin().getBlockX() - clipboard.getMinimumPoint().getBlockX(),clipboard.getOrigin().getBlockY() - clipboard.getMinimumPoint().getBlockY(),clipboard.getOrigin().getBlockZ() - clipboard.getMinimumPoint().getBlockZ()); + /*for (int x = clipboard.getMinimumPoint().getBlockX(); x <= clipboard.getMaximumPoint().getBlockX(); x++) { for (int y = clipboard.getMinimumPoint().getBlockY(); y <= clipboard.getMaximumPoint().getBlockY(); y++) { for (int z = clipboard.getMinimumPoint().getBlockZ(); z <= clipboard.getMaximumPoint().getBlockZ(); z++) { com.sk89q.worldedit.Vector pos = new com.sk89q.worldedit.Vector(x,y,z); @@ -469,19 +472,15 @@ public org.bukkit.util.Vector getDistanceFromSignToLowestPoint(Clipboard clipboa } } } - } - return returnDistance; + }*/ } @Override - public org.bukkit.util.Vector getDistanceFromClipboardToWorldOffset(org.bukkit.util.Vector offset, Clipboard clipboard) { - return new org.bukkit.util.Vector(offset.getBlockX() - clipboard.getMinimumPoint().getBlockX(), offset.getBlockY() - clipboard.getMinimumPoint().getBlockY(), offset.getBlockZ() - clipboard.getMinimumPoint().getBlockZ()); + public Vector getDistance(String repairName) { + return distanceMap.get(repairName); } - @Override - public void setFawePlugin(Plugin fawePlugin) { - } private Set baseBlocksFromCraft(Craft craft){ HashSet returnSet = new HashSet<>(); diff --git a/modules/worldedit/WE7Utils/src/main/java/net/countercraft/movecraft/compat/we7/IMovecraftRepair.java b/modules/worldedit/WE7Utils/src/main/java/net/countercraft/movecraft/compat/we7/IMovecraftRepair.java index e802e0f89..82a6aa8f9 100644 --- a/modules/worldedit/WE7Utils/src/main/java/net/countercraft/movecraft/compat/we7/IMovecraftRepair.java +++ b/modules/worldedit/WE7Utils/src/main/java/net/countercraft/movecraft/compat/we7/IMovecraftRepair.java @@ -46,16 +46,14 @@ import org.bukkit.util.Vector; import java.io.*; -import java.util.HashMap; -import java.util.HashSet; -import java.util.LinkedList; -import java.util.Set; +import java.util.*; import java.util.logging.Logger; public class IMovecraftRepair extends MovecraftRepair { - private HashMap> locMissingBlocksMap = new HashMap<>(); - private HashMap numDiffBlocksMap = new HashMap<>(); - private HashMap> missingBlocksMap = new HashMap<>(); + private final HashMap> locMissingBlocksMap = new HashMap<>(); + private final HashMap numDiffBlocksMap = new HashMap<>(); + private final HashMap> missingBlocksMap = new HashMap<>(); + private final HashMap distanceMap = new HashMap<>(); @Override public boolean saveCraftRepairState(Craft craft, Sign sign, Plugin plugin, String s) { HashHitBox hitBox = craft.getHitBox(); @@ -64,14 +62,16 @@ public boolean saveCraftRepairState(Craft craft, Sign sign, Plugin plugin, Strin if (!saveDirectory.exists()){ saveDirectory.mkdirs(); } + BlockVector3 origin = BlockVector3.at(sign.getX(),sign.getY(),sign.getZ()); BlockVector3 minPos = BlockVector3.at(hitBox.getMinX(), hitBox.getMinY(), hitBox.getMinZ()); BlockVector3 maxPos = BlockVector3.at(hitBox.getMaxX(), hitBox.getMaxY(), hitBox.getMaxZ()); CuboidRegion region = new CuboidRegion(minPos, maxPos); com.sk89q.worldedit.world.World weWorld = new BukkitWorld(world); BlockArrayClipboard clipboard = new BlockArrayClipboard(region); + clipboard.setOrigin(origin); Extent source = WorldEdit.getInstance().getEditSessionFactory().getEditSession(weWorld, -1); Extent destination = clipboard; - ForwardExtentCopy copy = new ForwardExtentCopy(source, region, clipboard.getOrigin(), destination, minPos); + ForwardExtentCopy copy = new ForwardExtentCopy(source, region, clipboard.getOrigin(), destination, clipboard.getOrigin()); ExistingBlockMask mask = new ExistingBlockMask(source); copy.setSourceMask(mask); try { @@ -155,13 +155,12 @@ public boolean repairRegion(World world, String s) { } @Override - public Clipboard loadCraftRepairStateClipboard(Plugin plugin, Sign sign, String s, World world) { + public Clipboard loadCraftRepairStateClipboard(Plugin plugin,Craft craft, Sign sign, String s, World world) { File dataDirectory = new File(plugin.getDataFolder(), "CraftRepairStates"); File file = new File(dataDirectory, s + ".schematic"); // The schematic file - com.sk89q.worldedit.world.World weWorld = new BukkitWorld(world); Clipboard clipboard = null; ClipboardFormat format = ClipboardFormats.findByFile(file); - + HashHitBox hitBox = craft.getHitBox(); try { InputStream input = new FileInputStream(file); ClipboardReader reader = format.getReader(input); @@ -175,17 +174,26 @@ public Clipboard loadCraftRepairStateClipboard(Plugin plugin, Sign sign, String if (clipboard != null){ long numDiffBlocks = 0; HashMap missingBlocks = new HashMap<>(); - LinkedList locMissingBlocks = new LinkedList<>(); - org.bukkit.util.Vector distMP = getDistanceFromSignToLowestPoint(clipboard,s); - BlockVector3 minPos = BlockVector3.at(sign.getLocation().getBlockX() - distMP.getBlockX(),sign.getLocation().getBlockY() - distMP.getBlockY(),sign.getLocation().getBlockZ() - distMP.getBlockZ()); - BlockVector3 distance = BlockVector3.at(minPos.getBlockX() - clipboard.getMinimumPoint().getBlockX(), minPos.getBlockY() - clipboard.getMinimumPoint().getBlockY(),minPos.getBlockZ() - clipboard.getMinimumPoint().getBlockZ()); + ArrayDeque locMissingBlocks = new ArrayDeque<>(); + Vector distance = new Vector(sign.getX() - hitBox.getMinX(), sign.getY() - hitBox.getMinY(),sign.getZ() - hitBox.getMinZ()); + if (distanceMap.containsKey(s)) { + distanceMap.replace(s,distance); + } else { + distanceMap.put(s,distance); + } + Bukkit.broadcastMessage(distance.toString()); + + for (int y = clipboard.getMinimumPoint().getBlockY(); y <= clipboard.getMaximumPoint().getBlockY(); y++) { for (int z = clipboard.getMinimumPoint().getBlockZ(); z <= clipboard.getMaximumPoint().getBlockZ(); z++) { for (int x = clipboard.getMinimumPoint().getBlockX(); x <= clipboard.getMaximumPoint().getBlockX(); x++) { BlockVector3 position = BlockVector3.at(x,y,z); + int cx = x - distance.getBlockX(); + int cy = y - distance.getBlockY(); + int cz = z - distance.getBlockZ(); BaseBlock block = clipboard.getFullBlock(position); Material type = BukkitAdapter.adapt(block.getBlockType()); - Location loc = new Location(sign.getWorld(),x + distance.getBlockX(),y + distance.getBlockY(),z + distance.getBlockZ()); + Location loc = new Location(sign.getWorld(),x,y,z); Block bukkitBlock = sign.getWorld().getBlockAt(loc); boolean isImportant = true; @@ -291,7 +299,7 @@ public Clipboard loadCraftRepairStateClipboard(Plugin plugin, Sign sign, String } } } - locMissingBlocks.push(new Vector(x,y,z)); + locMissingBlocks.addLast(new Vector(cx,cy,cz)); numDiffBlocks++; if (missingBlocks.containsKey(typeToConsume)){ double count = missingBlocks.get(typeToConsume); @@ -374,7 +382,7 @@ public Clipboard loadCraftRepairStateClipboard(Plugin plugin, Sign sign, String needsReplace = true; } if (needsReplace){ - locMissingBlocks.push(new Vector(x,y,z)); + locMissingBlocks.addLast(new Vector(cx,cy,cz)); numDiffBlocks++; } } @@ -414,7 +422,7 @@ public HashMap getMissingBlocks(String s) { } @Override - public LinkedList getMissingBlockLocations(String s) { + public ArrayDeque getMissingBlockLocations(String s) { return locMissingBlocksMap.get(s); } @@ -425,9 +433,9 @@ public long getNumDiffBlocks(String s) { } @Override - public Vector getDistanceFromSignToLowestPoint(Clipboard clipboard, String s) { - org.bukkit.util.Vector returnDistance = null; - for (int x = clipboard.getMinimumPoint().getBlockX(); x <= clipboard.getMaximumPoint().getBlockX(); x++) { + public Vector getDistanceFromSignToLowestPoint(Clipboard clipboard) { + return new Vector(clipboard.getOrigin().getBlockX() - clipboard.getMinimumPoint().getBlockX(),clipboard.getOrigin().getBlockY() - clipboard.getMinimumPoint().getBlockY(),clipboard.getOrigin().getBlockZ() - clipboard.getMinimumPoint().getBlockZ()); + /*for (int x = clipboard.getMinimumPoint().getBlockX(); x <= clipboard.getMaximumPoint().getBlockX(); x++) { for (int y = clipboard.getMinimumPoint().getBlockY(); y <= clipboard.getMaximumPoint().getBlockY(); y++) { for (int z = clipboard.getMinimumPoint().getBlockZ(); z <= clipboard.getMaximumPoint().getBlockZ(); z++) { BlockVector3 pos = BlockVector3.at(x,y,z); @@ -456,17 +464,12 @@ public Vector getDistanceFromSignToLowestPoint(Clipboard clipboard, String s) { } if (returnDistance != null) break; } - return returnDistance; + return returnDistance;*/ } @Override - public org.bukkit.util.Vector getDistanceFromClipboardToWorldOffset(org.bukkit.util.Vector offset, Clipboard clipboard) { - return new org.bukkit.util.Vector(offset.getBlockX() - clipboard.getMinimumPoint().getBlockX(), offset.getBlockY() - clipboard.getMinimumPoint().getBlockY(), offset.getBlockZ() - clipboard.getMinimumPoint().getBlockZ()); - } - - @Override - public void setFawePlugin(Plugin fawePlugin) { - + public Vector getDistance(String repairName) { + return distanceMap.get(repairName); } } diff --git a/pom.xml b/pom.xml index 743dd6bb3..5d40b80cb 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ org.spigotmc spigot-api - 1.13.2-R0.1-SNAPSHOT + 1.14-pre5-SNAPSHOT Movecraft Parent Pom @@ -24,11 +24,13 @@ modules/v1_11_R1 modules/v1_12_R1 modules/v1_13_R2 + modules/v1_14_R1 modules/worldedit/WE6Utils modules/worldedit/WE7Utils modules/Movecraft + From 722b08fd76cfad34e5f560eb2cb52c2dd889804f Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Sat, 27 Apr 2019 16:36:33 +0200 Subject: [PATCH 014/304] Added getter to RepairTask --- .../java/net/countercraft/movecraft/repair/RepairTask.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/repair/RepairTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/repair/RepairTask.java index fdffdaba7..5e29fdf45 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/repair/RepairTask.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/repair/RepairTask.java @@ -15,7 +15,7 @@ import java.util.concurrent.atomic.AtomicBoolean; public class RepairTask extends BukkitRunnable { - private Repair repair; + private final Repair repair; public RepairTask(Repair repair){ this.repair = repair; @@ -62,4 +62,7 @@ public void run() { repair.setRunning(new AtomicBoolean(false)); } } + public Repair getRepair(){ + return repair; + } } From a09e3604aa4cf3cdbc83e41bc64eafe0d3d7e2d0 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Thu, 23 May 2019 22:14:44 +0200 Subject: [PATCH 015/304] Further fixes in 1.14 update (NOTE: does NOT work in 1.14, works in 1.14.1) --- modules/Movecraft/pom.xml | 7 ++ .../movecraft/async/AsyncManager.java | 20 +++-- .../async/detection/DetectionTask.java | 74 ++++++++++------ .../async/rotation/RotationTask.java | 33 +++---- .../async/translation/TranslationTask.java | 85 +++---------------- .../movecraft/commands/ContactsCommand.java | 4 +- .../movecraft/commands/CruiseCommand.java | 25 +++--- .../countercraft/movecraft/craft/ICraft.java | 65 +++++++++++++- .../update/FuelBurnUpdateCommand.java | 33 +++++++ .../countercraft/movecraft/repair/Repair.java | 11 +-- .../movecraft/repair/RepairTask.java | 20 ++++- .../movecraft/sign/AscendSign.java | 3 +- .../movecraft/sign/CraftSign.java | 27 +++++- .../movecraft/sign/CruiseSign.java | 39 +++++++-- .../movecraft/sign/DescendSign.java | 3 +- .../countercraft/movecraft/sign/NameSign.java | 2 +- .../movecraft/sign/PilotSign.java | 19 +++++ .../movecraft/sign/RepairSign.java | 3 +- .../movecraft/sign/StatusSign.java | 30 +++---- .../countercraft/movecraft/craft/Craft.java | 20 +++-- .../countercraft/movecraft/utils/Pair.java | 58 +++++++++++++ modules/v1_14_R1/pom.xml | 2 +- .../compat/v1_14_R1/IWorldHandler.java | 2 +- .../compat/v1_14_R1/NextTickProvider.java | 17 ++-- .../compat/we7/IMovecraftRepair.java | 21 +++-- pom.xml | 2 +- 26 files changed, 418 insertions(+), 207 deletions(-) create mode 100644 modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/FuelBurnUpdateCommand.java create mode 100644 modules/api/src/main/java/net/countercraft/movecraft/utils/Pair.java diff --git a/modules/Movecraft/pom.xml b/modules/Movecraft/pom.xml index 1f9a93593..413f88913 100644 --- a/modules/Movecraft/pom.xml +++ b/modules/Movecraft/pom.xml @@ -113,6 +113,13 @@ WE6Utils jar + + + org.apache.commons + commons-lang3 + LATEST + + at.pavlov Cannons diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java index d0a49c617..34f194d42 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java @@ -37,6 +37,7 @@ import net.countercraft.movecraft.utils.LegacyUtils; import org.bukkit.*; import org.bukkit.block.Block; +import org.bukkit.block.BlockFace; import org.bukkit.entity.Player; import org.bukkit.entity.TNTPrimed; import org.bukkit.scheduler.BukkitRunnable; @@ -377,11 +378,11 @@ private void processCruise() { int dy = 0; // ascend - if (pcraft.getCruiseDirection() == 0x42) { + if (pcraft.getCruiseDirection() == BlockFace.UP) { dy = 1 + pcraft.getType().getVertCruiseSkipBlocks(); } // descend - if (pcraft.getCruiseDirection() == 0x43) { + if (pcraft.getCruiseDirection() == BlockFace.DOWN) { dy = 0 - 1 - pcraft.getType().getVertCruiseSkipBlocks(); if (pcraft.getHitBox().getMinY() <= w.getSeaLevel()) { dy = -1; @@ -393,7 +394,7 @@ private void processCruise() { } } // ship faces west - if (pcraft.getCruiseDirection() == 0x5) { + if (pcraft.getCruiseDirection() == BlockFace.WEST) { dx = 0 - 1 - pcraft.getType().getCruiseSkipBlocks(); if (bankRight) { dz = (0 - 1 - pcraft.getType().getCruiseSkipBlocks()) >> 1; @@ -407,7 +408,7 @@ private void processCruise() { } } // ship faces east - if (pcraft.getCruiseDirection() == 0x4) { + if (pcraft.getCruiseDirection() == BlockFace.EAST) { dx = 1 + pcraft.getType().getCruiseSkipBlocks(); if (bankLeft) { dz = (0 - 1 - pcraft.getType().getCruiseSkipBlocks()) >> 1; @@ -417,7 +418,7 @@ private void processCruise() { } } // ship faces north - if (pcraft.getCruiseDirection() == 0x2) { + if (pcraft.getCruiseDirection() == BlockFace.NORTH) { dz = 1 + pcraft.getType().getCruiseSkipBlocks(); if (bankRight) { dx = (0 - 1 - pcraft.getType().getCruiseSkipBlocks()) >> 1; @@ -427,7 +428,7 @@ private void processCruise() { } } // ship faces south - if (pcraft.getCruiseDirection() == 0x3) { + if (pcraft.getCruiseDirection() == BlockFace.SOUTH) { dz = 0 - 1 - pcraft.getType().getCruiseSkipBlocks(); if (bankLeft) { dx = (0 - 1 - pcraft.getType().getCruiseSkipBlocks()) >> 1; @@ -439,6 +440,7 @@ private void processCruise() { if (pcraft.getType().getCruiseOnPilot()) { dy = pcraft.getType().getCruiseOnPilotVertMove(); } + Movecraft.getInstance().getLogger().info(String.format("(%d,%d,%d)",dx,dy,dz) + " Cruise direction: " + pcraft.getCruiseDirection()); pcraft.translate(dx, dy, dz); pcraft.setLastDX(dx); pcraft.setLastDZ(dz); @@ -989,12 +991,12 @@ private void processDetection() { - recentContactTracking.get(ccraft).get(tcraft) > 60000) { String notification = "New contact: "; - if (tcraft.getUniqueName() != null && tcraft.getUniqueName().length() >= 1){ - notification += tcraft.getUniqueName(); + if (tcraft.getName() != null && tcraft.getName().length() >= 1){ + notification += tcraft.getName(); notification += " ("; } notification += tcraft.getType().getCraftName(); - if (tcraft.getUniqueName() != null && tcraft.getUniqueName().length() >= 1){ + if (tcraft.getName() != null && tcraft.getName().length() >= 1){ notification += ")"; } notification += " commanded by "; diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/detection/DetectionTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/detection/DetectionTask.java index 60c0bdd24..13641d28b 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/detection/DetectionTask.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/detection/DetectionTask.java @@ -21,6 +21,7 @@ import net.countercraft.movecraft.Movecraft; import net.countercraft.movecraft.MovecraftLocation; import net.countercraft.movecraft.async.AsyncTask; +import net.countercraft.movecraft.sign.PilotSign; import net.countercraft.movecraft.utils.HashHitBox; import net.countercraft.movecraft.utils.LegacyUtils; import net.countercraft.movecraft.config.Settings; @@ -33,6 +34,7 @@ import org.bukkit.block.BlockState; import org.bukkit.block.Sign; import org.bukkit.entity.Player; +import org.bukkit.scheduler.BukkitRunnable; import java.util.*; @@ -119,33 +121,44 @@ private void detectBlock(int x, int y, int z) { data.setWaterContact(true); } if (testType.name().contains("SIGN")) { - BlockState state; - try { - state = data.getWorld().getBlockAt(x, y, z).getState(); - } catch (Exception e){ - return; - } - if (state instanceof Sign) { - Sign s = (Sign) state; - if (s.getLine(0).equalsIgnoreCase("Pilot:") && data.getPlayer() != null) { - String playerName = data.getPlayer().getName(); - boolean foundPilot = false; - if (s.getLine(1).equalsIgnoreCase(playerName) || s.getLine(2).equalsIgnoreCase(playerName) - || s.getLine(3).equalsIgnoreCase(playerName)) { - foundPilot = true; - } - if (!foundPilot && (!data.getPlayer().hasPermission("movecraft.bypasslock"))) { - fail(I18nSupport.getInternationalisedString( - "Not one of the registered pilots on this craft")); + new BukkitRunnable() { + @Override + public void run() { + Block block = data.getWorld().getBlockAt(x, y, z); + if (data.getPlayer() != null) { + if (!PilotSign.containsPilot(data.getPlayer().getName(), block) && (!data.getPlayer().hasPermission("movecraft.bypasslock"))) { + fail(I18nSupport.getInternationalisedString( + "Not one of the registered pilots on this craft")); + } + if (containsForbiddenSignString(block)){ + fail(I18nSupport.getInternationalisedString( + "Detection - Forbidden sign string found")); + } + data.getPlayer().sendMessage("test"); } } - for (int i = 0; i < 4; i++) { - if (isForbiddenSignString(s.getLine(i))) { - fail(I18nSupport.getInternationalisedString( - "Detection - Forbidden sign string found")); + }.runTask(Movecraft.getInstance()); + + /*BlockState state = block.getState(); + if (state instanceof Sign) { + Sign s = (Sign) state; + if (s.getLine(0).equalsIgnoreCase("Pilot:") && data.getPlayer() != null) { + String playerName = data.getPlayer().getName(); + boolean foundPilot = false; + if (s.getLine(1).equalsIgnoreCase(playerName) || s.getLine(2).equalsIgnoreCase(playerName) + || s.getLine(3).equalsIgnoreCase(playerName)) { + foundPilot = true; + } + if (!foundPilot && (!data.getPlayer().hasPermission("movecraft.bypasslock"))) { + + } } - } - } + for (int i = 0; i < 4; i++) { + if (isForbiddenSignString(s.getLine(i))) { + + } + } + }*/ } if (isForbiddenBlock(testType, testData)) { fail(I18nSupport.getInternationalisedString("Detection - Forbidden block found")); @@ -315,11 +328,16 @@ private boolean isForbiddenBlock(Material test, int testData) { return false; } - private boolean isForbiddenSignString(String testString) { + private synchronized boolean containsForbiddenSignString(Block testBlock) { + Sign s = (Sign) testBlock.getState(); - for (String s : data.getForbiddenSignStrings()) { - if (testString.equals(s)) { - return true; + for (String str : s.getLines()) { + for (String forbidden : data.getForbiddenSignStrings()) { + if (forbidden == null) + continue; + if (forbidden.equalsIgnoreCase(str)){ + return true; + } } } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/rotation/RotationTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/rotation/RotationTask.java index 326dbf4a5..374697d00 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/rotation/RotationTask.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/rotation/RotationTask.java @@ -40,6 +40,7 @@ import org.bukkit.Material; import org.bukkit.World; import org.bukkit.block.Block; +import org.bukkit.block.BlockFace; import org.bukkit.block.Furnace; import org.bukkit.entity.Entity; import org.bukkit.entity.EntityType; @@ -249,39 +250,39 @@ protected void execute() { if (rotation == Rotation.ANTICLOCKWISE) { // ship faces west switch (getCraft().getCruiseDirection()) { - case 0x5: - getCraft().setCruiseDirection((byte) 0x2); + case WEST: + getCraft().setCruiseDirection(BlockFace.SOUTH); break; // ship faces east - case 0x4: - getCraft().setCruiseDirection((byte) 0x3); + case EAST: + getCraft().setCruiseDirection(BlockFace.NORTH); break; // ship faces north - case 0x2: - getCraft().setCruiseDirection((byte) 0x4); + case NORTH: + getCraft().setCruiseDirection(BlockFace.WEST); break; // ship faces south - case 0x3: - getCraft().setCruiseDirection((byte) 0x5); + case SOUTH: + getCraft().setCruiseDirection(BlockFace.EAST); break; } } else if (rotation == Rotation.CLOCKWISE) { // ship faces west switch (getCraft().getCruiseDirection()) { - case 0x5: - getCraft().setCruiseDirection((byte) 0x3); + case WEST: + getCraft().setCruiseDirection(BlockFace.SOUTH); break; // ship faces east - case 0x4: - getCraft().setCruiseDirection((byte) 0x2); + case EAST: + getCraft().setCruiseDirection(BlockFace.NORTH); break; // ship faces north - case 0x2: - getCraft().setCruiseDirection((byte) 0x5); + case NORTH: + getCraft().setCruiseDirection(BlockFace.WEST); break; // ship faces south - case 0x3: - getCraft().setCruiseDirection((byte) 0x4); + case SOUTH: + getCraft().setCruiseDirection(BlockFace.EAST); break; } } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java index 389cf4102..125c9267c 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java @@ -29,6 +29,8 @@ import org.bukkit.inventory.InventoryHolder; import org.bukkit.inventory.ItemStack; import org.bukkit.potion.PotionEffect; +import org.bukkit.scheduler.BukkitRunnable; +import org.bukkit.scheduler.BukkitTask; import java.util.*; import java.util.concurrent.ThreadLocalRandom; @@ -122,6 +124,11 @@ protected void execute() { fail(I18nSupport.getInternationalisedString("Craft is disabled!")); return; } + + if (getCraft().isRepairing()){ + fail("You cannot move a repairing craft!"); + return; + } final int minY = oldHitBox.getMinY(); final int maxY = oldHitBox.getMaxY(); @@ -151,10 +158,10 @@ protected void execute() { } //TODO: Check fuel - if (!checkFuel()) { - fail(I18nSupport.getInternationalisedString("Translation - Failed Craft out of fuel")); - return; - } + //if (!checkFuel()) { + //fail(I18nSupport.getInternationalisedString("Translation - Failed Craft out of fuel")); + //return; + //} //TODO: Add and handle event for towny and factions final List harvestBlocks = craft.getType().getHarvestBlocks(); @@ -429,77 +436,7 @@ private ItemStack putInToChests(ItemStack stack, ArrayList inventorie return stack; } - private boolean checkFuel(){ - // check for fuel, burn some from a furnace if needed. Blocks of coal are supported, in addition to coal and charcoal - double fuelBurnRate = craft.getType().getFuelBurnRate(); - // going down doesn't require fuel - if (dy == -1 && dx == 0 && dz == 0) - fuelBurnRate = 0.0; - - if (fuelBurnRate == 0.0 || craft.getSinking()) { - return true; - } - if (craft.getBurningFuel() >= fuelBurnRate) { - craft.setBurningFuel(craft.getBurningFuel() - fuelBurnRate); - return true; - } - Block fuelHolder = null; - for (MovecraftLocation bTest : oldHitBox) { - Block b = craft.getW().getBlockAt(bTest.getX(), bTest.getY(), bTest.getZ()); - if (b.getState() instanceof Furnace) { - InventoryHolder inventoryHolder = (InventoryHolder) b.getState(); - for (Material fuelType : Settings.FuelTypes.keySet()){ - Movecraft.getInstance().getLogger().info(b.getLocation().toString()); - if (inventoryHolder.getInventory().contains(fuelType)){ - fuelHolder = b; - } - } - //if (furnace.getInventory().contains(Material.COAL) || furnace.getInventory().contains(Material.COAL_BLOCK) || furnace.getInventory().contains(Material.CHARCOAL)) { - // fuelHolder = b; - //} - } - } - if (fuelHolder == null) { - fail(I18nSupport.getInternationalisedString("Translation - Failed Craft out of fuel")); - return false; - } - InventoryHolder inventoryHolder = (InventoryHolder) fuelHolder.getState(); - for (Material fuel : Settings.FuelTypes.keySet()){ - if (inventoryHolder.getInventory().contains(fuel)){ - ItemStack iStack = inventoryHolder.getInventory().getItem(inventoryHolder.getInventory().first(fuel)); - int amount = iStack.getAmount(); - if (amount == 1) { - inventoryHolder.getInventory().remove(iStack); - } else { - iStack.setAmount(amount - 1); - } - craft.setBurningFuel(craft.getBurningFuel() + Settings.FuelTypes.get(fuel)); - } - } - /*if (inventoryHolder.getInventory().contains(Material.COAL)) { - ItemStack iStack = inventoryHolder.getInventory().getItem(inventoryHolder.getInventory().first(Material.COAL)); - int amount = iStack.getAmount(); - if (amount == 1) { - inventoryHolder.getInventory().remove(iStack); - } else { - iStack.setAmount(amount - 1); - } - craft.setBurningFuel(craft.getBurningFuel() + 7.0); - } else { - ItemStack iStack = inventoryHolder.getInventory().getItem(inventoryHolder.getInventory().first(Material.COAL_BLOCK)); - int amount = iStack.getAmount(); - if (amount == 1) { - inventoryHolder.getInventory().remove(iStack); - } else { - iStack.setAmount(amount - 1); - } - craft.setBurningFuel(craft.getBurningFuel() + 79.0); - - }*/ - - return true; - } private void processWaterlogging(){ HitBox hitBox = craft.getHitBox(); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/ContactsCommand.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/ContactsCommand.java index eabe1e8b6..d34e79faf 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/ContactsCommand.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/ContactsCommand.java @@ -69,9 +69,9 @@ public boolean onCommand(CommandSender commandSender, Command command, String s, if (distsquared < detectionRangeSquared && tcraft.getNotificationPlayer() != ccraft.getNotificationPlayer()) { String notification = "Contact: "; notification += tcraft.getSinking() ? ChatColor.RED : tcraft.getDisabled() ? ChatColor.BLUE : ""; - notification += tcraft.getUniqueName() != null && tcraft.getUniqueName().length() >= 1 ? tcraft.getUniqueName() + " (" : ""; + notification += tcraft.getName() != null && tcraft.getName().length() >= 1 ? tcraft.getName() + " (" : ""; notification += tcraft.getType().getCraftName(); - notification += tcraft.getUniqueName() != null && tcraft.getUniqueName().length() >= 1 ? ")" : ""; + notification += tcraft.getName() != null && tcraft.getName().length() >= 1 ? ")" : ""; notification += ChatColor.RESET; notification += " commanded by "; notification += tcraft.getNotificationPlayer() != null ? tcraft.getNotificationPlayer().getDisplayName() : "null"; diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/CruiseCommand.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/CruiseCommand.java index a53464749..879ba96a1 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/CruiseCommand.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/CruiseCommand.java @@ -3,6 +3,7 @@ import net.countercraft.movecraft.craft.Craft; import net.countercraft.movecraft.craft.CraftManager; import net.countercraft.movecraft.localisation.I18nSupport; +import org.bukkit.block.BlockFace; import org.bukkit.command.Command; import org.bukkit.command.CommandSender; import org.bukkit.command.TabExecutor; @@ -47,13 +48,13 @@ public boolean onCommand(CommandSender commandSender, Command command, String s, yaw %= 360.0f; } if (yaw >= 45 && yaw < 135) { // west - craft.setCruiseDirection((byte)0x5); + craft.setCruiseDirection(BlockFace.WEST); } else if (yaw >= 135 && yaw < 225) { // north - craft.setCruiseDirection((byte)0x3); + craft.setCruiseDirection(BlockFace.NORTH); } else if (yaw >= 225 && yaw <= 315){ // east - craft.setCruiseDirection((byte)0x4); + craft.setCruiseDirection(BlockFace.EAST); } else { // default south - craft.setCruiseDirection((byte)0x2); + craft.setCruiseDirection(BlockFace.SOUTH); } craft.setCruising(true); return true; @@ -94,34 +95,34 @@ public boolean onCommand(CommandSender commandSender, Command command, String s, yaw %= 360.0f; } if (yaw >= 45 && yaw < 135) { // west - craft.setCruiseDirection((byte)0x5); + craft.setCruiseDirection(BlockFace.WEST); } else if (yaw >= 135 && yaw < 225) { // north - craft.setCruiseDirection((byte)0x3); + craft.setCruiseDirection(BlockFace.NORTH); } else if (yaw >= 225 && yaw <= 315){ // east - craft.setCruiseDirection((byte)0x4); + craft.setCruiseDirection(BlockFace.EAST); } else { // default south - craft.setCruiseDirection((byte)0x2); + craft.setCruiseDirection(BlockFace.SOUTH); } craft.setCruising(true); return true; } if (args[0].equalsIgnoreCase("north") || args[0].equalsIgnoreCase("n")) { - craft.setCruiseDirection((byte) 0x3); + craft.setCruiseDirection(BlockFace.NORTH); craft.setCruising(true); return true; } if (args[0].equalsIgnoreCase("south") || args[0].equalsIgnoreCase("s")) { - craft.setCruiseDirection((byte) 0x2); + craft.setCruiseDirection(BlockFace.SOUTH); craft.setCruising(true); return true; } if (args[0].equalsIgnoreCase("east") || args[0].equalsIgnoreCase("e")) { - craft.setCruiseDirection((byte) 0x4); + craft.setCruiseDirection(BlockFace.EAST); craft.setCruising(true); return true; } if (args[0].equalsIgnoreCase("west") || args[0].equalsIgnoreCase("w")) { - craft.setCruiseDirection((byte) 0x5); + craft.setCruiseDirection(BlockFace.WEST); craft.setCruising(true); return true; } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/ICraft.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/ICraft.java index a691e4c24..3da14bc21 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/ICraft.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/ICraft.java @@ -6,10 +6,22 @@ import net.countercraft.movecraft.async.detection.DetectionTask; import net.countercraft.movecraft.async.rotation.RotationTask; import net.countercraft.movecraft.async.translation.TranslationTask; -import org.bukkit.World; +import net.countercraft.movecraft.config.Settings; +import net.countercraft.movecraft.localisation.I18nSupport; +import net.countercraft.movecraft.mapUpdater.MapUpdateManager; +import net.countercraft.movecraft.mapUpdater.update.FuelBurnUpdateCommand; +import org.bukkit.*; +import org.bukkit.block.Block; import org.bukkit.entity.Player; +import org.bukkit.inventory.InventoryHolder; +import org.bukkit.inventory.ItemStack; +import org.bukkit.scheduler.BukkitRunnable; +import org.bukkit.scheduler.BukkitTask; import org.jetbrains.annotations.NotNull; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; import java.util.UUID; public class ICraft extends Craft { @@ -79,7 +91,11 @@ public void translate(int dx, int dy, int dz) { } } }*/ - + if (!checkFuel(dx,dy,dz)){ + getNotificationPlayer().playSound(getNotificationPlayer().getLocation(),Sound.BLOCK_ANVIL_LAND,1,0); + getNotificationPlayer().sendMessage(I18nSupport.getInternationalisedString("Translation - Failed Craft out of fuel")); + return; + } Movecraft.getInstance().getAsyncManager().submitTask(new TranslationTask(this, dx, dy, dz), this); } @@ -126,11 +142,19 @@ public void rotate(Rotation rotation, MovecraftLocation originPoint) { } } }*/ + if (!checkFuel(0,0,0)){ + getNotificationPlayer().sendMessage(I18nSupport.getInternationalisedString("Translation - Failed Craft out of fuel")); + return; + } Movecraft.getInstance().getAsyncManager().submitTask(new RotationTask(this, originPoint, rotation, this.getW()), this); } @Override public void rotate(Rotation rotation, MovecraftLocation originPoint, boolean isSubCraft) { + if (!checkFuel(0,0,0)){ + getNotificationPlayer().sendMessage(I18nSupport.getInternationalisedString("Translation - Failed Craft out of fuel")); + return; + } Movecraft.getInstance().getAsyncManager().submitTask(new RotationTask(this, originPoint, rotation, this.getW(), isSubCraft), this); } @@ -146,4 +170,41 @@ public boolean equals(Object obj) { public int hashCode() { return id.hashCode(); } + private boolean checkFuel(int dx, int dy, int dz){ + // check for fuel, burn some from a furnace if needed. Blocks of coal are supported, in addition to coal and charcoal + double fuelBurnRate = getType().getFuelBurnRate(); + // going down doesn't require fuel + if (dy == -1 && dx == 0 && dz == 0) + fuelBurnRate = 0.0; + + if (fuelBurnRate == 0.0 || getSinking()) { + return true; + } + if (getBurningFuel() >= fuelBurnRate) { + setBurningFuel(getBurningFuel() - fuelBurnRate); + return true; + } + final List fuelHolders = new ArrayList<>(); + Block fuelHolder = null; + for (MovecraftLocation bTest : getHitBox()) { + Block b = getW().getBlockAt(bTest.getX(), bTest.getY(), bTest.getZ()); + //Get all fuel holders + if (b.getType() == Material.FURNACE) { + InventoryHolder holder = (InventoryHolder) b.getState(); + for (Material fuel : Settings.FuelTypes.keySet()){ + if (holder.getInventory().contains(fuel)){ + fuelHolder = b; + break; + } + } + } + if (fuelHolder != null) break; + + } + if (fuelHolder == null){ + return false; + } + MapUpdateManager.getInstance().scheduleUpdate(new FuelBurnUpdateCommand(this,fuelHolder)); + return true; + } } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/FuelBurnUpdateCommand.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/FuelBurnUpdateCommand.java new file mode 100644 index 000000000..e0813ff7c --- /dev/null +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/FuelBurnUpdateCommand.java @@ -0,0 +1,33 @@ +package net.countercraft.movecraft.mapUpdater.update; + +import net.countercraft.movecraft.config.Settings; +import net.countercraft.movecraft.craft.Craft; +import org.bukkit.Material; +import org.bukkit.block.Block; +import org.bukkit.block.Furnace; +import org.bukkit.inventory.ItemStack; + +public class FuelBurnUpdateCommand extends UpdateCommand { + private final Block block; + private final Craft craft; + public FuelBurnUpdateCommand(Craft craft, Block furnace){ + this.block = furnace; + this.craft = craft; + } + @Override + public void doUpdate() { + Furnace furnace = (Furnace) block.getState(); + for (Material fuel : Settings.FuelTypes.keySet()){ + if (furnace.getInventory().contains(fuel)){ + ItemStack item = furnace.getInventory().getItem(furnace.getInventory().first(fuel)); + int amount = item.getAmount(); + if (amount == 1) { + furnace.getInventory().remove(item); + } else { + item.setAmount(amount - 1); + } + craft.setBurningFuel(craft.getBurningFuel() + Settings.FuelTypes.get(item.getType())); + } + } + } +} diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/repair/Repair.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/repair/Repair.java index 50d79381a..77d6bbae3 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/repair/Repair.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/repair/Repair.java @@ -3,6 +3,7 @@ import net.countercraft.movecraft.config.Settings; import net.countercraft.movecraft.craft.Craft; import net.countercraft.movecraft.mapUpdater.update.UpdateCommand; +import net.countercraft.movecraft.utils.HitBox; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.boss.BarColor; @@ -16,16 +17,16 @@ public class Repair { private String name; - private Craft craft; + private HitBox hitBox; private LinkedList updateCommands, fragileBlockUpdateCommands; private UUID playerUUID; private long missingBlocks, durationInTicks, ticksSinceStart; private BossBar progressBar; private Location signLoc; private AtomicBoolean running = new AtomicBoolean(true); - public Repair(String name, Craft craft, LinkedList updateCommands, LinkedList fragileBlockUpdateCommands, UUID playerUUID, long missingBlocks, Location signLoc){ + public Repair(String name, HitBox hitBox, LinkedList updateCommands, LinkedList fragileBlockUpdateCommands, UUID playerUUID, long missingBlocks, Location signLoc){ this.name = name; - this.craft = craft; + this.hitBox = hitBox; this.updateCommands = updateCommands; this.fragileBlockUpdateCommands = fragileBlockUpdateCommands; this.durationInTicks = missingBlocks * Settings.RepairTicksPerBlock; @@ -85,8 +86,8 @@ public void setSignLoc(Location signLoc) { this.signLoc = signLoc; } - public Craft getCraft() { - return craft; + public HitBox getHitBox() { + return hitBox; } public BossBar getProgressBar() { diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/repair/RepairTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/repair/RepairTask.java index 5e29fdf45..a3beb291d 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/repair/RepairTask.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/repair/RepairTask.java @@ -2,16 +2,20 @@ import com.sk89q.worldedit.Vector; import net.countercraft.movecraft.Movecraft; +import net.countercraft.movecraft.MovecraftLocation; import net.countercraft.movecraft.MovecraftRepair; import net.countercraft.movecraft.config.Settings; +import net.countercraft.movecraft.craft.Craft; import net.countercraft.movecraft.craft.CraftManager; import net.countercraft.movecraft.localisation.I18nSupport; import net.countercraft.movecraft.mapUpdater.MapUpdateManager; +import net.countercraft.movecraft.utils.HashHitBox; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.entity.Player; import org.bukkit.scheduler.BukkitRunnable; +import java.util.Collections; import java.util.concurrent.atomic.AtomicBoolean; public class RepairTask extends BukkitRunnable { @@ -22,6 +26,19 @@ public RepairTask(Repair repair){ } @Override public void run() { + Craft repairCraft = null; + for (Craft craft : CraftManager.getInstance()){ + if (craft == null) + continue; + for (MovecraftLocation location : repair.getHitBox()){ + if (craft.getHitBox().contains(location)) { + repairCraft = craft; + break; + } + } + } + if (repairCraft != null) + repairCraft.setRepairing(true); long ticksFromStart = repair.getTicksSinceStart(); Player p = Bukkit.getPlayer(repair.getPlayerUUID()); if (p != null) { @@ -56,10 +73,11 @@ public void run() { if ((ticksFromStart >= repair.getDurationInTicks()) && repair.getUpdateCommands().isEmpty() && repair.getFragileBlockUpdateCommands().isEmpty()){ if (p != null && repair.getRunning().get()) { p.sendMessage(I18nSupport.getInternationalisedString("Repairs complete. You may now pilot the craft")); - CraftManager.getInstance().removeCraft(repair.getCraft()); } repair.getProgressBar().setVisible(false); repair.setRunning(new AtomicBoolean(false)); + if (repairCraft != null) + repairCraft.setRepairing(false); } } public Repair getRepair(){ diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/AscendSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/AscendSign.java index b34480478..630f45701 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/AscendSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/AscendSign.java @@ -10,6 +10,7 @@ import org.bukkit.Material; import org.bukkit.World; import org.bukkit.block.Block; +import org.bukkit.block.BlockFace; import org.bukkit.block.Sign; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; @@ -56,7 +57,7 @@ public void onSignClickEvent(PlayerInteractEvent event){ sign.setLine(0, "Ascend: ON"); sign.update(true); - CraftManager.getInstance().getCraftByPlayer(event.getPlayer()).setCruiseDirection((byte) 0x42); + CraftManager.getInstance().getCraftByPlayer(event.getPlayer()).setCruiseDirection(BlockFace.UP); CraftManager.getInstance().getCraftByPlayer(event.getPlayer()).setLastCruisUpdate(System.currentTimeMillis()); CraftManager.getInstance().getCraftByPlayer(event.getPlayer()).setCruising(true); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CraftSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CraftSign.java index 89e219c29..1a17b4d8c 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CraftSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CraftSign.java @@ -13,7 +13,9 @@ import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.block.Block; +import org.bukkit.block.BlockFace; import org.bukkit.block.Sign; +import org.bukkit.block.data.type.WallSign; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; import org.bukkit.event.block.Action; @@ -64,7 +66,30 @@ public final void onSignClick(PlayerInteractEvent event) { if (c.getType().getCruiseOnPilot()) { c.detect(null, event.getPlayer(), startPoint); - c.setCruiseDirection(sign.getRawData()); + final BlockFace direction; + if (Settings.IsLegacy){ + if (sign.getData() instanceof org.bukkit.material.Sign){ + org.bukkit.material.Sign signData = (org.bukkit.material.Sign) sign.getData(); + if (signData.isWallSign()) { + direction = signData.getAttachedFace(); + } else { + direction = signData.getFacing().getOppositeFace(); + } + }else { + direction = null; + } + } else { + if (sign.getBlockData() instanceof org.bukkit.block.data.type.Sign){ + org.bukkit.block.data.type.Sign signData = (org.bukkit.block.data.type.Sign)sign.getBlockData(); + direction = signData.getRotation().getOppositeFace(); + }else if (sign.getBlockData() instanceof org.bukkit.block.data.type.WallSign){ + WallSign signData = (WallSign)sign.getBlockData(); + direction = signData.getFacing().getOppositeFace(); + } else { + direction = null; + } + } + c.setCruiseDirection(direction); c.setLastCruisUpdate(System.currentTimeMillis()); c.setCruising(true); new BukkitRunnable() { diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CruiseSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CruiseSign.java index 140bfdd9f..78ab3e1c4 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CruiseSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CruiseSign.java @@ -1,5 +1,6 @@ package net.countercraft.movecraft.sign; +import net.countercraft.movecraft.Movecraft; import net.countercraft.movecraft.MovecraftLocation; import net.countercraft.movecraft.config.Settings; import net.countercraft.movecraft.craft.Craft; @@ -11,7 +12,9 @@ import org.bukkit.Material; import org.bukkit.World; import org.bukkit.block.Block; +import org.bukkit.block.BlockFace; import org.bukkit.block.Sign; +import org.bukkit.block.data.type.WallSign; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; @@ -47,11 +50,12 @@ public final void onSignClick(PlayerInteractEvent event) { return; } Sign sign = (Sign) event.getClickedBlock().getState(); + Craft c = CraftManager.getInstance().getCraftByPlayer(event.getPlayer()); if (ChatColor.stripColor(sign.getLine(0)).equalsIgnoreCase("Cruise: OFF")) { if (CraftManager.getInstance().getCraftByPlayer(event.getPlayer()) == null) { return; } - Craft c = CraftManager.getInstance().getCraftByPlayer(event.getPlayer()); + if (!c.getType().getCanCruise()) { return; } @@ -59,8 +63,30 @@ public final void onSignClick(PlayerInteractEvent event) { sign.setLine(0, "Cruise: ON"); sign.update(true); - - c.setCruiseDirection(sign.getRawData()); + final BlockFace direction; + if (Settings.IsLegacy){ + if (sign.getData() instanceof org.bukkit.material.Sign){ + org.bukkit.material.Sign signData = (org.bukkit.material.Sign) sign.getData(); + if (signData.isWallSign()) { + direction = signData.getAttachedFace(); + } else { + direction = signData.getFacing().getOppositeFace(); + } + }else { + direction = null; + } + } else { + if (sign.getBlockData() instanceof org.bukkit.block.data.type.Sign){ + org.bukkit.block.data.type.Sign signData = (org.bukkit.block.data.type.Sign)sign.getBlockData(); + direction = signData.getRotation().getOppositeFace(); + }else if (sign.getBlockData() instanceof org.bukkit.block.data.type.WallSign){ + WallSign signData = (WallSign)sign.getBlockData(); + direction = signData.getFacing().getOppositeFace(); + } else { + direction = null; + } + } + c.setCruiseDirection(direction); c.setLastCruisUpdate(System.currentTimeMillis()); c.setCruising(true); if (!c.getType().getMoveEntities()) { @@ -69,12 +95,15 @@ public final void onSignClick(PlayerInteractEvent event) { return; } if (ChatColor.stripColor(sign.getLine(0)).equalsIgnoreCase("Cruise: ON") - && CraftManager.getInstance().getCraftByPlayer(event.getPlayer()) != null - && CraftManager.getInstance().getCraftByPlayer(event.getPlayer()).getType().getCanCruise()) { + && c != null + && c.getType().getCanCruise()) { sign.setLine(0, "Cruise: OFF"); sign.update(true); CraftManager.getInstance().getCraftByPlayer(event.getPlayer()).setCruising(false); } + if (c == null) + return; + Movecraft.getInstance().getLogger().info("Cruising: " + c.getCruising()); } @EventHandler(priority = EventPriority.NORMAL) diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/DescendSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/DescendSign.java index 8da3fdde0..827c1f0c2 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/DescendSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/DescendSign.java @@ -10,6 +10,7 @@ import org.bukkit.Material; import org.bukkit.World; import org.bukkit.block.Block; +import org.bukkit.block.BlockFace; import org.bukkit.block.Sign; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; @@ -55,7 +56,7 @@ public final void onSignClick(PlayerInteractEvent event) { sign.setLine(0, "Descend: ON"); sign.update(true); - c.setCruiseDirection((byte) 0x43); + c.setCruiseDirection(BlockFace.DOWN); c.setLastCruisUpdate(System.currentTimeMillis()); c.setCruising(true); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/NameSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/NameSign.java index 6853a7b02..9e589c724 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/NameSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/NameSign.java @@ -40,7 +40,7 @@ public void onCraftDetect(@NotNull CraftDetectEvent event){ if (s.getLine(3) != null){ name += s.getLine(3); } - c.setUniqueName(name); + c.setName(name); } } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/PilotSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/PilotSign.java index 6233a00e5..96e955e3d 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/PilotSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/PilotSign.java @@ -1,6 +1,8 @@ package net.countercraft.movecraft.sign; import org.bukkit.ChatColor; +import org.bukkit.block.Block; +import org.bukkit.block.Sign; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; import org.bukkit.event.block.SignChangeEvent; @@ -16,4 +18,21 @@ public final void onSignChange(SignChangeEvent event){ } } } + + public static synchronized boolean containsPilot(String name, Block signBlock){ + if (!(signBlock.getState() instanceof Sign)){ + throw new IllegalArgumentException("Block must be a sign!"); + } + Sign sign = (Sign) signBlock.getState(); + boolean contains = false; + if (sign.getLine(0).equalsIgnoreCase(HEADER)){ + for (int i = 1; i <= 3; i++){ + if (sign.getLine(i).equals(name)){ + contains = true; + break; + } + } + } + return contains; + } } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RepairSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RepairSign.java index 80508d74f..9012e90e7 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RepairSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RepairSign.java @@ -270,10 +270,9 @@ private void signRightClick(PlayerInteractEvent event){ } if (updateCommands.size() > 0) { - final Craft releaseCraft = pCraft; CraftManager.getInstance().removePlayerFromCraft(pCraft); RepairManager repairManager = Movecraft.getInstance().getRepairManager(); - repairManager.getRepairs().add(new Repair(sign.getLine(1), releaseCraft, updateCommands, updateCommandsFragileBlocks, p.getUniqueId(), numDifferentBlocks, sign.getLocation())); + repairManager.getRepairs().add(new Repair(sign.getLine(1), pCraft.getHitBox(), updateCommands, updateCommandsFragileBlocks, p.getUniqueId(), numDifferentBlocks, sign.getLocation())); } } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/StatusSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/StatusSign.java index e3bf5370d..da4d5ffe4 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/StatusSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/StatusSign.java @@ -52,33 +52,25 @@ public final void onSignTranslate(SignTranslateEvent event) { Material blockType = craft.getW().getBlockAt(ml.getX(), ml.getY(), ml.getZ()).getType(); if (foundBlocks.containsKey(blockType)) { - Integer count = foundBlocks.get(blockType); - if (count == null) { - foundBlocks.put(blockType, 1); - } else { - foundBlocks.put(blockType, count + 1); - } + foundBlocks.merge(blockType, 1, (a, b) -> a + b); } else { foundBlocks.put(blockType, 1); } if (blockType == Material.FURNACE) { InventoryHolder inventoryHolder = (InventoryHolder) craft.getW().getBlockAt(ml.getX(), ml.getY(), ml.getZ()).getState(); - if (inventoryHolder.getInventory().contains(Material.COAL) - || inventoryHolder.getInventory().contains(Material.COAL_BLOCK) - || inventoryHolder.getInventory().contains(Material.CHARCOAL)) { - ItemStack[] istack=inventoryHolder.getInventory().getContents(); - for(ItemStack i : istack) { - if(i!=null) { - if(i.getType()== Material.COAL || i.getType() == Material.CHARCOAL) { - fuel+=i.getAmount()*8; - } - if(i.getType()==Material.COAL_BLOCK) { - fuel+=i.getAmount()*80; - } - } + for (Material fuelType : Settings.FuelTypes.keySet()){ + if (!inventoryHolder.getInventory().contains(fuelType)){ + continue; + } + ItemStack[] content = inventoryHolder.getInventory().getContents(); + for (ItemStack item : content){ + if (item == null) + continue; + fuel += item.getAmount() * Settings.FuelTypes.get(fuelType); } } + } if (blockType != Material.AIR || blockType != Material.CAVE_AIR || blockType != Material.VOID_AIR) { totalBlocks++; diff --git a/modules/api/src/main/java/net/countercraft/movecraft/craft/Craft.java b/modules/api/src/main/java/net/countercraft/movecraft/craft/Craft.java index 4e4f9bca4..162f4a651 100644 --- a/modules/api/src/main/java/net/countercraft/movecraft/craft/Craft.java +++ b/modules/api/src/main/java/net/countercraft/movecraft/craft/Craft.java @@ -28,6 +28,7 @@ import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.World; +import org.bukkit.block.BlockFace; import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -51,7 +52,8 @@ public abstract class Craft { private boolean cruising; private boolean sinking; private boolean disabled; - private byte cruiseDirection; + private boolean repairing; + private BlockFace cruiseDirection; private long lastCruiseUpdate; private long lastBlockCheck; private long lastRotateTime=0; @@ -170,11 +172,11 @@ public void setDisabled(boolean disabled) { this.disabled = disabled; } - public byte getCruiseDirection() { + public BlockFace getCruiseDirection() { return cruiseDirection; } - public void setCruiseDirection(byte cruiseDirection) { + public void setCruiseDirection(BlockFace cruiseDirection) { this.cruiseDirection = cruiseDirection; } @@ -424,10 +426,18 @@ public Map getCrewSigns(){ } @NotNull - public String getUniqueName(){ + public String getName(){ return name; } - public void setUniqueName(String name){ + public void setName(@NotNull String name){ this.name = name; } + + public boolean isRepairing() { + return repairing; + } + + public void setRepairing(boolean repairing) { + this.repairing = repairing; + } } \ No newline at end of file diff --git a/modules/api/src/main/java/net/countercraft/movecraft/utils/Pair.java b/modules/api/src/main/java/net/countercraft/movecraft/utils/Pair.java new file mode 100644 index 000000000..561b4403e --- /dev/null +++ b/modules/api/src/main/java/net/countercraft/movecraft/utils/Pair.java @@ -0,0 +1,58 @@ +package net.countercraft.movecraft.utils; + +import org.jetbrains.annotations.NotNull; + +import java.io.Serializable; +import java.util.Map; +import java.util.UUID; + +public final class Pair implements Serializable, Map.Entry { + private final UUID id = UUID.randomUUID(); + private final L left; + private final R right; + + public Pair(L left, R right){ + this.left = left; + this.right = right; + } + + public L getLeft() { + return left; + } + + public R getRight() { + return right; + } + + + @Override + public L getKey() { + return left; + } + + @Override + public R getValue() { + return right; + } + + @Override + public R setValue(R value) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof Pair)){ + return false; + } + Pair pair = (Pair) obj; + return getLeft().equals(pair.getLeft())&&getRight().equals(pair.getRight()); + } + + @Override + public int hashCode() { + return id.hashCode(); + } + + +} diff --git a/modules/v1_14_R1/pom.xml b/modules/v1_14_R1/pom.xml index 5748feec0..3801214de 100644 --- a/modules/v1_14_R1/pom.xml +++ b/modules/v1_14_R1/pom.xml @@ -35,7 +35,7 @@ org.bukkit craftbukkit - 1.14-pre5-SNAPSHOT + 1.14.1-R0.1-SNAPSHOT diff --git a/modules/v1_14_R1/src/main/java/net/countercraft/movecraft/compat/v1_14_R1/IWorldHandler.java b/modules/v1_14_R1/src/main/java/net/countercraft/movecraft/compat/v1_14_R1/IWorldHandler.java index 885506dbd..2ef8114be 100644 --- a/modules/v1_14_R1/src/main/java/net/countercraft/movecraft/compat/v1_14_R1/IWorldHandler.java +++ b/modules/v1_14_R1/src/main/java/net/countercraft/movecraft/compat/v1_14_R1/IWorldHandler.java @@ -261,7 +261,7 @@ private TileEntity removeTileEntity(@NotNull World world, @NotNull BlockPosition world.tileEntityListTick.remove(tile); if(!bMap.containsKey(world)){ try { - Field bField = World.class.getDeclaredField("c"); + Field bField = World.class.getDeclaredField("tileEntityListPending"); bField.setAccessible(true); bMap.put(world, (List) bField.get(world));//TODO bug fix } catch (IllegalAccessException | IllegalArgumentException | NoSuchFieldException | SecurityException e1) { diff --git a/modules/v1_14_R1/src/main/java/net/countercraft/movecraft/compat/v1_14_R1/NextTickProvider.java b/modules/v1_14_R1/src/main/java/net/countercraft/movecraft/compat/v1_14_R1/NextTickProvider.java index 221adcf48..58bedaa72 100644 --- a/modules/v1_14_R1/src/main/java/net/countercraft/movecraft/compat/v1_14_R1/NextTickProvider.java +++ b/modules/v1_14_R1/src/main/java/net/countercraft/movecraft/compat/v1_14_R1/NextTickProvider.java @@ -1,7 +1,6 @@ package net.countercraft.movecraft.compat.v1_14_R1; -import org.apache.commons.lang3.tuple.ImmutablePair; -import org.bukkit.craftbukkit.v1_14_R1.util.HashTreeSet; +import net.countercraft.movecraft.utils.Pair; import net.minecraft.server.v1_14_R1.*; import org.jetbrains.annotations.NotNull; @@ -11,7 +10,7 @@ import java.util.*; public class NextTickProvider { - private Map,List>> tickMap = new HashMap<>(); + private Map,List>> tickMap = new HashMap<>(); private boolean isRegistered(@NotNull WorldServer world){ return tickMap.containsKey(world); @@ -20,7 +19,7 @@ private boolean isRegistered(@NotNull WorldServer world){ @SuppressWarnings("unchecked") private void registerWorld(@NotNull WorldServer world){ List W = new ArrayList<>(); - HashTreeSet nextTickList = new HashTreeSet<>(); + Set nextTickList = new HashSet<>(); TickListServer blockTickListServer = world.getBlockTickList(); try { Field gField = TickListServer.class.getDeclaredField("g"); @@ -28,26 +27,26 @@ private void registerWorld(@NotNull WorldServer world){ W = (List) gField.get(blockTickListServer); Field ntlField = TickListServer.class.getDeclaredField("nextTickList"); ntlField.setAccessible(true); - nextTickList = (HashTreeSet) ntlField.get(blockTickListServer); + nextTickList = (Set) ntlField.get(blockTickListServer); } catch (IllegalAccessException | IllegalArgumentException | NoSuchFieldException | SecurityException e1) { e1.printStackTrace(); } - tickMap.put(world, new ImmutablePair<>(nextTickList,W)); + tickMap.put(world, new Pair<>(nextTickList,W)); } @Nullable public NextTickListEntry getNextTick(@NotNull WorldServer world,@NotNull BlockPosition position){ if(!isRegistered(world)) registerWorld(world); - ImmutablePair, List> listPair = tickMap.get(world); - for(Iterator iterator = listPair.left.iterator(); iterator.hasNext();) { + Pair, List> listPair = tickMap.get(world); + for(Iterator iterator = listPair.getLeft().iterator(); iterator.hasNext();) { NextTickListEntry listEntry = iterator.next(); if (position.equals(listEntry.a)) { iterator.remove(); return listEntry; } } - for(Iterator iterator = listPair.right.iterator(); iterator.hasNext();) { + for(Iterator iterator = listPair.getRight().iterator(); iterator.hasNext();) { NextTickListEntry listEntry = iterator.next(); if (position.equals(listEntry.a)) { iterator.remove(); diff --git a/modules/worldedit/WE7Utils/src/main/java/net/countercraft/movecraft/compat/we7/IMovecraftRepair.java b/modules/worldedit/WE7Utils/src/main/java/net/countercraft/movecraft/compat/we7/IMovecraftRepair.java index 82a6aa8f9..982949cdf 100644 --- a/modules/worldedit/WE7Utils/src/main/java/net/countercraft/movecraft/compat/we7/IMovecraftRepair.java +++ b/modules/worldedit/WE7Utils/src/main/java/net/countercraft/movecraft/compat/we7/IMovecraftRepair.java @@ -175,25 +175,24 @@ public Clipboard loadCraftRepairStateClipboard(Plugin plugin,Craft craft, Sign s long numDiffBlocks = 0; HashMap missingBlocks = new HashMap<>(); ArrayDeque locMissingBlocks = new ArrayDeque<>(); - Vector distance = new Vector(sign.getX() - hitBox.getMinX(), sign.getY() - hitBox.getMinY(),sign.getZ() - hitBox.getMinZ()); + BlockVector3 length = clipboard.getMaximumPoint().subtract(clipboard.getMinimumPoint()); + BlockVector3 distance = clipboard.getOrigin().subtract(clipboard.getMinimumPoint()); + Vector offset = new Vector(sign.getX()-distance.getBlockX(),sign.getY()-distance.getBlockY(),sign.getZ()-distance.getBlockZ()); if (distanceMap.containsKey(s)) { - distanceMap.replace(s,distance); + distanceMap.replace(s,offset); } else { - distanceMap.put(s,distance); + distanceMap.put(s,offset); } - Bukkit.broadcastMessage(distance.toString()); - - - for (int y = clipboard.getMinimumPoint().getBlockY(); y <= clipboard.getMaximumPoint().getBlockY(); y++) { - for (int z = clipboard.getMinimumPoint().getBlockZ(); z <= clipboard.getMaximumPoint().getBlockZ(); z++) { - for (int x = clipboard.getMinimumPoint().getBlockX(); x <= clipboard.getMaximumPoint().getBlockX(); x++) { - BlockVector3 position = BlockVector3.at(x,y,z); + for (int y = 0; y <= length.getBlockY(); y++) { + for (int z = 0; z <= length.getBlockZ(); z++) { + for (int x = 0; x <= length.getBlockX(); x++) { + BlockVector3 position = BlockVector3.at(x+clipboard.getMinimumPoint().getBlockX(),y+clipboard.getMinimumPoint().getBlockY(),z+clipboard.getMinimumPoint().getBlockZ()); int cx = x - distance.getBlockX(); int cy = y - distance.getBlockY(); int cz = z - distance.getBlockZ(); BaseBlock block = clipboard.getFullBlock(position); Material type = BukkitAdapter.adapt(block.getBlockType()); - Location loc = new Location(sign.getWorld(),x,y,z); + Location loc = new Location(sign.getWorld(),offset.getBlockX()+x,offset.getBlockY()+y,offset.getBlockZ()+z); Block bukkitBlock = sign.getWorld().getBlockAt(loc); boolean isImportant = true; diff --git a/pom.xml b/pom.xml index 5d40b80cb..754a7944c 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ org.spigotmc spigot-api - 1.14-pre5-SNAPSHOT + 1.14-R0.1-SNAPSHOT Movecraft Parent Pom From 16e6526a82261694ad83ab60042cbbf92f2acc15 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Sun, 2 Jun 2019 17:09:32 +0200 Subject: [PATCH 016/304] Bug fixes --- modules/Movecraft/pom.xml | 7 ++ .../net/countercraft/movecraft/Movecraft.java | 58 ++++++++- .../movecraft/async/AsyncManager.java | 24 ++-- .../async/detection/DetectionTask.java | 25 ++-- .../async/rotation/RotationTask.java | 81 +------------ .../async/translation/TranslationTask.java | 48 ++------ .../compatmanager/FactionsCompatManager.java | 101 ++++++++++++++++ .../GriefPreventionCompatManager.java | 6 +- .../compatmanager/KingdomsCompatManager.java | 75 ++++++++++++ .../RedProtectCompatManager.java | 112 ++++++++++++++++++ .../countercraft/movecraft/craft/ICraft.java | 18 +-- .../movecraft/listener/InteractListener.java | 9 +- .../movecraft/repair/RepairManager.java | 3 - .../movecraft/repair/RepairTask.java | 15 +-- .../movecraft/sign/AscendSign.java | 5 +- .../movecraft/sign/DescendSign.java | 5 +- .../localisation/movecraftlang_en.properties | 2 + .../movecraft/config/Settings.java | 8 ++ .../countercraft/movecraft/craft/Craft.java | 16 +++ .../movecraft/events/CraftSinkEvent.java | 10 ++ .../movecraft/localisation/I18nSupport.java | 15 ++- modules/v1_14_R1/pom.xml | 2 +- .../compat/v1_14_R1/NextTickProvider.java | 8 +- 23 files changed, 461 insertions(+), 192 deletions(-) create mode 100644 modules/Movecraft/src/main/java/net/countercraft/movecraft/compatmanager/KingdomsCompatManager.java rename modules/{Movecraft => api}/src/main/java/net/countercraft/movecraft/localisation/I18nSupport.java (82%) diff --git a/modules/Movecraft/pom.xml b/modules/Movecraft/pom.xml index 413f88913..e3dfc8112 100644 --- a/modules/Movecraft/pom.xml +++ b/modules/Movecraft/pom.xml @@ -208,6 +208,13 @@ system ${project.basedir}/../../libs/RedProtect-7.5.5-b129-Universal.jar + + com.dre + Brewery + 1.7.1 + system + ${project.basedir}/../../libs/Brewery-1.7.1.jar + org.jetbrains annotations-java5 diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java index 0e19416ae..326876175 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java @@ -18,7 +18,9 @@ package net.countercraft.movecraft; import at.pavlov.cannons.Cannons; +import br.net.fabiozumbi12.RedProtect.Bukkit.RedProtect; import com.daemitus.deadbolt.DeadboltPlugin; +import com.dre.brewery.P; import com.earth2me.essentials.Essentials; import com.massivecraft.factions.Factions; import com.mewin.WGCustomFlags.WGCustomFlagsPlugin; @@ -26,10 +28,11 @@ import com.sk89q.worldedit.bukkit.WorldEditPlugin; import com.sk89q.worldguard.bukkit.WorldGuardPlugin; import com.sk89q.worldguard.protection.flags.StateFlag; +import com.songoda.kingdoms.main.Kingdoms; import me.ryanhamshire.GriefPrevention.GriefPrevention; import net.countercraft.movecraft.async.AsyncManager; import net.countercraft.movecraft.commands.*; -import net.countercraft.movecraft.compatmanager.GriefPreventionCompatManager; +import net.countercraft.movecraft.compatmanager.*; import net.countercraft.movecraft.config.Settings; import net.countercraft.movecraft.craft.CraftManager; import net.countercraft.movecraft.listener.BlockListener; @@ -44,7 +47,6 @@ import net.countercraft.movecraft.warfare.assault.AssaultManager; import net.countercraft.movecraft.warfare.siege.Siege; import net.countercraft.movecraft.warfare.siege.SiegeManager; -import net.countercraft.movecraft.compatmanager.WorldGuardCompatManager; import net.milkbowl.vault.economy.Economy; import org.bukkit.Material; import org.bukkit.configuration.file.FileConfiguration; @@ -76,6 +78,9 @@ public class Movecraft extends JavaPlugin { private static Factions factionsPlugin; private static DeadboltPlugin deadboltPlugin; private static GriefPrevention griefPreventionPlugin; + private static Kingdoms kingdomsPlugin; + private static RedProtect redProtectPlugin; + private static P breweryPlugin; /*public HashMap blockFadeTimeMap = new HashMap<>(); public HashMap blockFadeTypeMap = new HashMap<>(); public HashMap blockFadeWaterMap = new HashMap<>(); @@ -219,7 +224,9 @@ public void onEnable() { Settings.ForbiddenRemoteSigns = new HashSet<>(getConfig().getStringList("ForbiddenRemoteSigns")); Settings.SiegeEnable = getConfig().getBoolean("SiegeEnable", false); Settings.SiegeTimeZone = getConfig().getString("SiegeTimeZone", "UTC"); - + Settings.FactionsBlockMoveInSafezone = getConfig().getBoolean("FactionsBlockMoveInSafezone",false); + Settings.FactionsBlockSinkInSafezone = getConfig().getBoolean("FactionsBlockSinkInSafezone",false); + Settings.FactionsBlockMoveInWarzone = getConfig().getBoolean("FactionsBlockMoveInWarzone",false); @@ -368,12 +375,24 @@ public void onEnable() { if (tempFactionsPlugin != null){ if (tempFactionsPlugin instanceof Factions){ factionsPlugin = (Factions) tempFactionsPlugin; + getServer().getPluginManager().registerEvents(new FactionsCompatManager(),this); logger.info("Movecraft found a compatible version of Factions. Enabling Factions integration."); } } if (factionsPlugin == null){ logger.info("Movecraft did not find a compatible version of Factions. Disabling Factions integration"); } + //Kingdoms + Plugin tempKingdomsPlugin = getServer().getPluginManager().getPlugin("Kingdoms"); + if (tempKingdomsPlugin != null){ + if (tempKingdomsPlugin instanceof Kingdoms){ + getServer().getPluginManager().registerEvents(new KingdomsCompatManager(),this); + kingdomsPlugin = (Kingdoms) tempKingdomsPlugin; + } + } + if (kingdomsPlugin == null){ + logger.info("Movecraft did not find a compatible version of Kingdoms. Disabling Kingdoms integration"); + } //GriefPrevention Plugin gpPlugin = getServer().getPluginManager().getPlugin("GriefPrevention"); if (gpPlugin != null){ @@ -383,6 +402,21 @@ public void onEnable() { griefPreventionPlugin = (GriefPrevention) gpPlugin; } } + if (griefPreventionPlugin == null){ + logger.info("Movecraft did not find a compatible version of GriefPrevention. Disabling GriefPrevention integration"); + } + //RedProtect + Plugin rpPlugin = getServer().getPluginManager().getPlugin("RedProtect"); + if (rpPlugin != null){ + if (rpPlugin instanceof RedProtect){ + logger.info("Found a compatible version of RedProtect. Enabling RedProtect integration"); + getServer().getPluginManager().registerEvents(new RedProtectCompatManager(),this); + redProtectPlugin = (RedProtect) rpPlugin; + } + } + if (redProtectPlugin == null){ + logger.info("Movecraft did not find a compatible version of RedProtect. Disabling RedProtect integration"); + } // Deadbolt Plugin tempDeadboltPlugin = getServer().getPluginManager().getPlugin("Deadbolt"); if (tempDeadboltPlugin != null){ @@ -394,6 +428,14 @@ public void onEnable() { if (deadboltPlugin == null){ logger.info("Movecraft did not find a compatible version of Deadbolt. Disabling Deadbolt integration"); } + //Brewery + Plugin brewery = getServer().getPluginManager().getPlugin("Brewery"); + if (brewery != null){ + if (brewery instanceof P){ + breweryPlugin = (P) brewery; + logger.info("Movecraft found a compatible version of Brewery. Enabling Brewery integration"); + } + } // and now Vault if (getServer().getPluginManager().getPlugin("Vault") != null) { RegisteredServiceProvider rsp = getServer().getServicesManager().getRegistration(Economy.class); @@ -420,7 +462,7 @@ public void onEnable() { } } - I18nSupport.init(); + I18nSupport.init(this); if (shuttingDown && Settings.IGNORE_RESET) { logger.log( Level.SEVERE, @@ -616,5 +658,13 @@ public GriefPrevention getGriefPreventionPlugin() { public DeadboltPlugin getDeadboltPlugin(){ return deadboltPlugin; } + + public Kingdoms getKingdomsPlugin() { + return kingdomsPlugin; + } + + public RedProtect getRedProtectPlugin() { + return redProtectPlugin; + } } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java index 34f194d42..cc3ec0c1d 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java @@ -63,7 +63,6 @@ public class AsyncManager extends BukkitRunnable { private long lastFadeCheck = 0; private long lastContactCheck = 0; private HashSet transparent = null; - private boolean climb = false; public AsyncManager() { transparent = new HashSet<>(); @@ -360,6 +359,7 @@ private void processCruise() { boolean bankLeft = false; boolean bankRight = false; boolean dive = false; + boolean climb = pcraft.isClimbing(); if (pcraft.getPilotLocked()) { if (pcraft.getNotificationPlayer().isSneaking()) dive = true; @@ -381,6 +381,9 @@ private void processCruise() { if (pcraft.getCruiseDirection() == BlockFace.UP) { dy = 1 + pcraft.getType().getVertCruiseSkipBlocks(); } + else if (climb){ + dy = (1 + pcraft.getType().getCruiseSkipBlocks()) >> 1; + } // descend if (pcraft.getCruiseDirection() == BlockFace.DOWN) { dy = 0 - 1 - pcraft.getType().getVertCruiseSkipBlocks(); @@ -402,10 +405,7 @@ private void processCruise() { if (bankLeft) { dz = (1 + pcraft.getType().getCruiseSkipBlocks()) >> 1; } - if (climb){ - dy = (1 + pcraft.getType().getCruiseSkipBlocks()) >> 1; - climb = false; - } + } // ship faces east if (pcraft.getCruiseDirection() == BlockFace.EAST) { @@ -419,7 +419,7 @@ private void processCruise() { } // ship faces north if (pcraft.getCruiseDirection() == BlockFace.NORTH) { - dz = 1 + pcraft.getType().getCruiseSkipBlocks(); + dz = 0 - 1 - pcraft.getType().getCruiseSkipBlocks(); if (bankRight) { dx = (0 - 1 - pcraft.getType().getCruiseSkipBlocks()) >> 1; } @@ -429,7 +429,7 @@ private void processCruise() { } // ship faces south if (pcraft.getCruiseDirection() == BlockFace.SOUTH) { - dz = 0 - 1 - pcraft.getType().getCruiseSkipBlocks(); + dz = 1 + pcraft.getType().getCruiseSkipBlocks(); if (bankLeft) { dx = (0 - 1 - pcraft.getType().getCruiseSkipBlocks()) >> 1; } @@ -440,7 +440,6 @@ private void processCruise() { if (pcraft.getType().getCruiseOnPilot()) { dy = pcraft.getType().getCruiseOnPilotVertMove(); } - Movecraft.getInstance().getLogger().info(String.format("(%d,%d,%d)",dx,dy,dz) + " Cruise direction: " + pcraft.getCruiseDirection()); pcraft.translate(dx, dy, dz); pcraft.setLastDX(dx); pcraft.setLastDZ(dz); @@ -555,9 +554,6 @@ private void detectSinking(){ // update the time for the next check if (isSinking && pcraft.isNotProcessing()) { Player notifyP = pcraft.getNotificationPlayer(); - if (notifyP != null) { - notifyP.sendMessage(I18nSupport.getInternationalisedString("Player- Craft is sinking")); - } pcraft.setCruising(false); pcraft.sink(); CraftManager.getInstance().removePlayerFromCraft(pcraft); @@ -749,7 +745,9 @@ private void processFireballs() { } private void processWaterlogging(){ + for (Craft c : CraftManager.getInstance()){ + } } private Craft fastNearestCraftToLoc(Location loc) { @@ -1094,6 +1092,7 @@ public void run() { processTracers(); processFireballs(); processTNTContactExplosives(); + processWaterlogging(); if (!Settings.IsLegacy) { processWaterlogging(); } @@ -1134,7 +1133,4 @@ private void clearAll() { clearanceSet.clear(); } - public void setClimb(boolean climb){ - this.climb = climb; - } } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/detection/DetectionTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/detection/DetectionTask.java index 13641d28b..dfe0f10b1 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/detection/DetectionTask.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/detection/DetectionTask.java @@ -21,17 +21,14 @@ import net.countercraft.movecraft.Movecraft; import net.countercraft.movecraft.MovecraftLocation; import net.countercraft.movecraft.async.AsyncTask; -import net.countercraft.movecraft.sign.PilotSign; -import net.countercraft.movecraft.utils.HashHitBox; -import net.countercraft.movecraft.utils.LegacyUtils; -import net.countercraft.movecraft.config.Settings; import net.countercraft.movecraft.craft.Craft; import net.countercraft.movecraft.localisation.I18nSupport; +import net.countercraft.movecraft.utils.HashHitBox; +import net.countercraft.movecraft.utils.LegacyUtils; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.World; import org.bukkit.block.Block; -import org.bukkit.block.BlockState; import org.bukkit.block.Sign; import org.bukkit.entity.Player; import org.bukkit.scheduler.BukkitRunnable; @@ -125,16 +122,26 @@ private void detectBlock(int x, int y, int z) { @Override public void run() { Block block = data.getWorld().getBlockAt(x, y, z); + Sign sign = (Sign) block.getState(); if (data.getPlayer() != null) { - if (!PilotSign.containsPilot(data.getPlayer().getName(), block) && (!data.getPlayer().hasPermission("movecraft.bypasslock"))) { - fail(I18nSupport.getInternationalisedString( - "Not one of the registered pilots on this craft")); + if (sign.getLine(0).equalsIgnoreCase("Pilot:")) { + boolean foundPilot = false; + for (String line : sign.getLines()){ + if (line.equals(data.getPlayer().getName())){ + foundPilot = true; + break; + } + } + + if (!foundPilot &&(!data.getPlayer().hasPermission("movecraft.bypasslock"))){ + fail(I18nSupport.getInternationalisedString( + "Not one of the registered pilots on this craft")); + } } if (containsForbiddenSignString(block)){ fail(I18nSupport.getInternationalisedString( "Detection - Forbidden sign string found")); } - data.getPlayer().sendMessage("test"); } } }.runTask(Movecraft.getInstance()); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/rotation/RotationTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/rotation/RotationTask.java index 374697d00..fecd6621e 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/rotation/RotationTask.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/rotation/RotationTask.java @@ -25,28 +25,24 @@ import net.countercraft.movecraft.Movecraft; import net.countercraft.movecraft.MovecraftLocation; import net.countercraft.movecraft.Rotation; -import net.countercraft.movecraft.craft.Craft; -import net.countercraft.movecraft.events.CraftRotateEvent; -import net.countercraft.movecraft.utils.*; import net.countercraft.movecraft.async.AsyncTask; import net.countercraft.movecraft.config.Settings; +import net.countercraft.movecraft.craft.Craft; import net.countercraft.movecraft.craft.CraftManager; +import net.countercraft.movecraft.events.CraftRotateEvent; import net.countercraft.movecraft.localisation.I18nSupport; import net.countercraft.movecraft.mapUpdater.update.CraftRotateCommand; import net.countercraft.movecraft.mapUpdater.update.EntityUpdateCommand; import net.countercraft.movecraft.mapUpdater.update.UpdateCommand; +import net.countercraft.movecraft.utils.*; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.World; -import org.bukkit.block.Block; import org.bukkit.block.BlockFace; -import org.bukkit.block.Furnace; import org.bukkit.entity.Entity; import org.bukkit.entity.EntityType; import org.bukkit.entity.Player; -import org.bukkit.inventory.InventoryHolder; -import org.bukkit.inventory.ItemStack; import java.util.HashSet; import java.util.Set; @@ -97,76 +93,7 @@ protected void execute() { failMessage = I18nSupport.getInternationalisedString("Craft is disabled!"); } - // check for fuel, burn some from a furnace if needed. Blocks of coal are supported, in addition to coal and charcoal - double fuelBurnRate = getCraft().getType().getFuelBurnRate(); - if (fuelBurnRate != 0.0 && !getCraft().getSinking()) { - if (getCraft().getBurningFuel() < fuelBurnRate) { - Block fuelHolder = null; - for (MovecraftLocation bTest : oldHitBox) { - Block b = getCraft().getW().getBlockAt(bTest.getX(), bTest.getY(), bTest.getZ()); - if (b.getState() instanceof Furnace) { - InventoryHolder inventoryHolder = (InventoryHolder) b.getState(); - for (Material fuelType : Settings.FuelTypes.keySet()){ - if (inventoryHolder.getInventory().contains(fuelType)){ - fuelHolder = b; - } - } - /*if ((!Settings.IsLegacy ? (inventoryHolder.getInventory().contains(Material.COAL) || inventoryHolder.getInventory().contains(Material.CHARCOAL)) || inventoryHolder.getInventory().contains(Material.COAL_BLOCK): (inventoryHolder.getInventory().contains(Material.COAL)) || inventoryHolder.getInventory().contains(Material.COAL_BLOCK))) { - fuelHolder = b; - }*/ - } - } - if (fuelHolder == null) { - failed = true; - failMessage = I18nSupport.getInternationalisedString("Translation - Failed Craft out of fuel"); - } else { - InventoryHolder inventoryHolder = (InventoryHolder) fuelHolder.getState(); - for (Material fuel : Settings.FuelTypes.keySet()){ - if (inventoryHolder.getInventory().contains(fuel)){ - ItemStack iStack = inventoryHolder.getInventory().getItem(inventoryHolder.getInventory().first(fuel)); - int amount = iStack.getAmount(); - if (amount == 1) { - inventoryHolder.getInventory().remove(iStack); - } else { - iStack.setAmount(amount - 1); - } - craft.setBurningFuel(craft.getBurningFuel() + Settings.FuelTypes.get(fuel)); - } - } - /*if (inventoryHolder.getInventory().contains(Material.COAL)) { - ItemStack iStack = inventoryHolder.getInventory().getItem(inventoryHolder.getInventory().first(Material.COAL)); - int amount = iStack.getAmount(); - if (amount == 1) { - inventoryHolder.getInventory().remove(iStack); - } else { - iStack.setAmount(amount - 1); - } - getCraft().setBurningFuel(getCraft().getBurningFuel() + 7.0); - } else if (inventoryHolder.getInventory().contains(Material.COAL_BLOCK)){ - ItemStack iStack = inventoryHolder.getInventory().getItem(inventoryHolder.getInventory().first(Material.COAL_BLOCK)); - int amount = iStack.getAmount(); - if (amount == 1) { - inventoryHolder.getInventory().remove(iStack); - } else { - iStack.setAmount(amount - 1); - } - getCraft().setBurningFuel(getCraft().getBurningFuel() + 79.0); - - } else { - ItemStack iStack = inventoryHolder.getInventory().getItem(inventoryHolder.getInventory().first(Material.CHARCOAL)); - int amount = iStack.getAmount(); - if (amount == 1) { - inventoryHolder.getInventory().remove(iStack); - } else { - iStack.setAmount(amount - 1); - } - getCraft().setBurningFuel(getCraft().getBurningFuel() + 7.0); - }*/ - } - } else { - getCraft().setBurningFuel(getCraft().getBurningFuel() - fuelBurnRate); - } - } + // if a subcraft, find the parent craft. If not a subcraft, it is it's own parent Set craftsInWorld = CraftManager.getInstance().getCraftsInWorld(getCraft().getW()); Craft parentCraft = getCraft(); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java index 125c9267c..41468cf16 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java @@ -1,6 +1,5 @@ package net.countercraft.movecraft.async.translation; -import net.countercraft.movecraft.Movecraft; import net.countercraft.movecraft.MovecraftLocation; import net.countercraft.movecraft.async.AsyncTask; import net.countercraft.movecraft.config.Settings; @@ -17,11 +16,8 @@ import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.Sound; -import org.bukkit.block.*; -import org.bukkit.block.data.Bisected; -import org.bukkit.block.data.BlockData; -import org.bukkit.block.data.Waterlogged; -import org.bukkit.block.data.type.TrapDoor; +import org.bukkit.block.Block; +import org.bukkit.block.Chest; import org.bukkit.entity.Entity; import org.bukkit.entity.EntityType; import org.bukkit.entity.Player; @@ -29,8 +25,6 @@ import org.bukkit.inventory.InventoryHolder; import org.bukkit.inventory.ItemStack; import org.bukkit.potion.PotionEffect; -import org.bukkit.scheduler.BukkitRunnable; -import org.bukkit.scheduler.BukkitTask; import java.util.*; import java.util.concurrent.ThreadLocalRandom; @@ -138,12 +132,17 @@ protected void execute() { }else if(craft.getType().getMaxHeightAboveGround() > 0){ final MovecraftLocation middle = oldHitBox.getMidPoint(); int testY = minY; - while (testY > 0){ - testY -= 1; - if (craft.getW().getBlockAt(middle.getX(),testY,middle.getZ()).getType() != Material.AIR || !Settings.IsLegacy &&(craft.getW().getBlockAt(middle.getX(),testY,middle.getZ()).getType() != Material.CAVE_AIR || craft.getW().getBlockAt(middle.getX(),testY,middle.getZ()).getType() != Material.VOID_AIR)) - break; + for (int y = minY;y > 0;y--) { + if (y == minY) + continue; + if (craft.getW().getBlockAt(middle.getX(), y, middle.getZ()).getType() == Material.AIR || !Settings.IsLegacy && (craft.getW().getBlockAt(middle.getX(), y, middle.getZ()).getType() == Material.CAVE_AIR || craft.getW().getBlockAt(middle.getX(), y, middle.getZ()).getType() == Material.VOID_AIR)){ + continue; + } + testY = y; + break; } if (minY - testY > craft.getType().getMaxHeightAboveGround()) { + dy = 0; dy -= 1; } } @@ -438,31 +437,6 @@ private ItemStack putInToChests(ItemStack stack, ArrayList inventorie - private void processWaterlogging(){ - HitBox hitBox = craft.getHitBox(); - for (MovecraftLocation moveLoc : hitBox){ - Block b = moveLoc.toBukkit(craft.getW()).getBlock(); - BlockData data = b.getBlockData(); - if (!(data instanceof Waterlogged)){ - continue; - } - if (b.getLocation().getY() > craft.getWaterLine()){ - Waterlogged wLog = (Waterlogged) data; - wLog.setWaterlogged(false); - continue; - } - if (data instanceof TrapDoor){ - TrapDoor tDoor = (TrapDoor) data; - if (tDoor.getHalf() == Bisected.Half.TOP && b.getRelative(BlockFace.DOWN).getType() == Material.WATER){ - tDoor.setWaterlogged(true); - } else if (tDoor.getHalf() == Bisected.Half.BOTTOM && b.getRelative(BlockFace.UP).getType() == Material.WATER){ - tDoor.setWaterlogged(true); - } else if (b.getRelative(tDoor.getFacing().getOppositeFace()).getType() == Material.WATER){ - tDoor.setWaterlogged(true); - } - } - } - } public boolean failed(){ return failed; diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/compatmanager/FactionsCompatManager.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/compatmanager/FactionsCompatManager.java index 3a6b4092b..a201dbb49 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/compatmanager/FactionsCompatManager.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/compatmanager/FactionsCompatManager.java @@ -1,14 +1,26 @@ package net.countercraft.movecraft.compatmanager; import com.massivecraft.factions.Factions; +import com.massivecraft.factions.TerritoryAccess; +import com.massivecraft.factions.entity.BoardColl; +import com.massivecraft.factions.entity.Faction; +import com.massivecraft.factions.entity.FactionColl; import com.massivecraft.factions.entity.MPlayer; +import com.massivecraft.massivecore.ps.PS; import net.countercraft.movecraft.Movecraft; +import net.countercraft.movecraft.MovecraftLocation; +import net.countercraft.movecraft.config.Settings; +import net.countercraft.movecraft.events.CraftRotateEvent; import net.countercraft.movecraft.events.CraftTranslateEvent; +import net.countercraft.movecraft.localisation.I18nSupport; +import org.bukkit.ChatColor; import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; public class FactionsCompatManager implements Listener { + @EventHandler public void onCraftTranslate(CraftTranslateEvent event){ if (Movecraft.getInstance().getFactionsPlugin() == null){ return; @@ -16,6 +28,95 @@ public void onCraftTranslate(CraftTranslateEvent event){ Factions factions = Movecraft.getInstance().getFactionsPlugin(); Player player = event.getCraft().getNotificationPlayer(); MPlayer mPlayer = MPlayer.get(player); + PS ps = null; + Faction faction = FactionColl.get().getNone(); + for (MovecraftLocation location : event.getNewHitBox()) { + ps = PS.valueOf(location.toBukkit(event.getCraft().getW())); + faction = BoardColl.get().getFactionAt(ps); + if (faction != FactionColl.get().getNone()){ + break; + } + } + if (faction == FactionColl.get().getNone()){ + return; + } + if (faction.equals(FactionColl.get().getWarzone())){ + if (Settings.FactionsBlockMoveInWarzone ){ + event.setFailMessage(I18nSupport.getInternationalisedString("Factions - Translation Failed Player not permitted to move in warzone")); + event.setCancelled(true); + } + } + if (faction.equals(FactionColl.get().getSafezone())){ + if (Settings.FactionsBlockMoveInSafezone ){ + event.setFailMessage(I18nSupport.getInternationalisedString("Factions - Translation Failed Player not permitted to move in safezone")); + event.setCancelled(true); + } + + } + if (ps == null){ + return; + } + TerritoryAccess tAccess = BoardColl.get().getTerritoryAccessAt(ps); + Faction pFaction = mPlayer.getFaction(); + if (!tAccess.isFactionGranted(pFaction)){ + event.setFailMessage(I18nSupport.getInternationalisedString("Factions - Translation Failed Faction Has No Access").replace("{FACTION}",faction.getColorTo(pFaction) + faction.getName() + ChatColor.RESET)); + event.setCancelled(true); + return; + } + if (!tAccess.isMPlayerGranted(mPlayer)){ + event.setFailMessage(I18nSupport.getInternationalisedString("Factions - Translation Failed Player Has No Access").replace("{FACTION}",faction.getColorTo(pFaction) + faction.getName() + ChatColor.RESET)); + event.setCancelled(true); + } + } + @EventHandler + public void onCraftRotate(CraftRotateEvent event){ + if (Movecraft.getInstance().getFactionsPlugin() == null){ + return; + } + Factions factions = Movecraft.getInstance().getFactionsPlugin(); + Player player = event.getCraft().getNotificationPlayer(); + MPlayer mPlayer = MPlayer.get(player); + PS ps = null; + Faction faction = FactionColl.get().getNone(); + for (MovecraftLocation location : event.getNewHitBox()) { + ps = PS.valueOf(location.toBukkit(event.getCraft().getW())); + faction = BoardColl.get().getFactionAt(ps); + if (faction != FactionColl.get().getNone()){ + break; + } + } + if (ps == null){ + return; + } + if (faction == FactionColl.get().getNone()){ + return; + } + if (faction.equals(FactionColl.get().getWarzone())){ + if (Settings.FactionsBlockMoveInWarzone ){ + event.setFailMessage(I18nSupport.getInternationalisedString("Factions - Translation Failed Player not permitted to move in warzone")); + event.setCancelled(true); + } + } + if (faction.equals(FactionColl.get().getSafezone())){ + if (Settings.FactionsBlockMoveInSafezone ){ + event.setFailMessage(I18nSupport.getInternationalisedString("Factions - Translation Failed Player not permitted to move in safezone")); + event.setCancelled(true); + } + + } + + TerritoryAccess tAccess = BoardColl.get().getTerritoryAccessAt(ps); + + Faction pFaction = mPlayer.getFaction(); + if (!tAccess.isFactionGranted(pFaction)){ + event.setFailMessage(I18nSupport.getInternationalisedString("Factions - Translation Failed Faction Has No Access").replace("{FACTION}",faction.getColorTo(pFaction) + faction.getName() + ChatColor.RESET)); + event.setCancelled(true); + return; + } + if (!tAccess.isMPlayerGranted(mPlayer)){ + event.setFailMessage(I18nSupport.getInternationalisedString("Factions - Translation Failed Player Has No Access").replace("{FACTION}",faction.getColorTo(pFaction) + faction.getName() + ChatColor.RESET)); + event.setCancelled(true); + } } } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/compatmanager/GriefPreventionCompatManager.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/compatmanager/GriefPreventionCompatManager.java index fbb8feb22..3313821af 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/compatmanager/GriefPreventionCompatManager.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/compatmanager/GriefPreventionCompatManager.java @@ -1,12 +1,12 @@ package net.countercraft.movecraft.compatmanager; -import me.ryanhamshire.GriefPrevention.DataStore; import me.ryanhamshire.GriefPrevention.GriefPrevention; import me.ryanhamshire.GriefPrevention.Messages; import net.countercraft.movecraft.Movecraft; import net.countercraft.movecraft.MovecraftLocation; import net.countercraft.movecraft.craft.Craft; import net.countercraft.movecraft.events.CraftRotateEvent; +import net.countercraft.movecraft.events.CraftSinkEvent; import net.countercraft.movecraft.events.CraftTranslateEvent; import net.countercraft.movecraft.localisation.I18nSupport; import org.bukkit.Location; @@ -53,4 +53,8 @@ public void onCraftRotate(CraftRotateEvent event){ } } } + @EventHandler + public void onCraftSink(CraftSinkEvent event){ + + } } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/compatmanager/KingdomsCompatManager.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/compatmanager/KingdomsCompatManager.java new file mode 100644 index 000000000..f3f22c688 --- /dev/null +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/compatmanager/KingdomsCompatManager.java @@ -0,0 +1,75 @@ +package net.countercraft.movecraft.compatmanager; + +import com.songoda.kingdoms.constants.kingdom.Kingdom; +import com.songoda.kingdoms.constants.land.Land; +import com.songoda.kingdoms.constants.land.SimpleChunkLocation; +import com.songoda.kingdoms.constants.player.KingdomPlayer; +import com.songoda.kingdoms.main.Kingdoms; +import com.songoda.kingdoms.manager.game.GameManagement; +import com.songoda.kingdoms.manager.game.LandManager; +import net.countercraft.movecraft.Movecraft; +import net.countercraft.movecraft.MovecraftLocation; +import net.countercraft.movecraft.craft.Craft; +import net.countercraft.movecraft.events.CraftRotateEvent; +import net.countercraft.movecraft.events.CraftTranslateEvent; +import net.countercraft.movecraft.localisation.I18nSupport; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; + +public class KingdomsCompatManager implements Listener { + @EventHandler + public void onCraftTranslate(CraftTranslateEvent event){ + if (Movecraft.getInstance().getKingdomsPlugin() == null){ + return; + } + Craft craft = event.getCraft(); + Land foreignLand = null; + for (MovecraftLocation moveLoc : event.getNewHitBox()) { + LandManager lm = GameManagement.getLandManager(); + SimpleChunkLocation c = new SimpleChunkLocation(moveLoc.toBukkit(craft.getW()).getChunk()); + Land land = lm.getOrLoadLand(c); + KingdomPlayer kp = Kingdoms.getInstance().getManagers().getPlayerManager().getSession(craft.getNotificationPlayer()); + Kingdom k = kp.getKingdom(); + if (land.getOwnerUUID() == null){ + continue; + } + if (land.getOwnerUUID() != k.getKingdomUuid()){ + foreignLand = land; + break; + } + } + if (foreignLand == null){ + return; + } + event.setFailMessage(I18nSupport.getInternationalisedString("Translation - Kingdoms Player not allowed to build")); + event.setCancelled(true); + } + + @EventHandler + public void onCraftRotate(CraftRotateEvent event){ + if (Movecraft.getInstance().getKingdomsPlugin() == null){ + return; + } + Craft craft = event.getCraft(); + Land foreignLand = null; + for (MovecraftLocation moveLoc : event.getNewHitBox()) { + LandManager lm = GameManagement.getLandManager(); + SimpleChunkLocation c = new SimpleChunkLocation(moveLoc.toBukkit(craft.getW()).getChunk()); + Land land = lm.getOrLoadLand(c); + KingdomPlayer kp = Kingdoms.getInstance().getManagers().getPlayerManager().getSession(craft.getNotificationPlayer()); + Kingdom k = kp.getKingdom(); + if (land.getOwnerUUID() == null){ + continue; + } + if (land.getOwnerUUID() != k.getKingdomUuid()){ + foreignLand = land; + break; + } + } + if (foreignLand == null){ + return; + } + event.setFailMessage(I18nSupport.getInternationalisedString("Rotation - Kingdoms Player not allowed to build")); + event.setCancelled(true); + } +} diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/compatmanager/RedProtectCompatManager.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/compatmanager/RedProtectCompatManager.java index 5f906ec9e..ee58a549b 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/compatmanager/RedProtectCompatManager.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/compatmanager/RedProtectCompatManager.java @@ -1,12 +1,124 @@ package net.countercraft.movecraft.compatmanager; +import br.net.fabiozumbi12.RedProtect.Bukkit.API.RedProtectAPI; +import br.net.fabiozumbi12.RedProtect.Bukkit.Region; +import net.countercraft.movecraft.MovecraftLocation; +import net.countercraft.movecraft.config.Settings; +import net.countercraft.movecraft.craft.Craft; +import net.countercraft.movecraft.events.CraftRotateEvent; +import net.countercraft.movecraft.events.CraftSinkEvent; import net.countercraft.movecraft.events.CraftTranslateEvent; +import net.countercraft.movecraft.localisation.I18nSupport; +import net.countercraft.movecraft.utils.HashHitBox; +import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; public class RedProtectCompatManager implements Listener { @EventHandler public void onCraftTranslate(CraftTranslateEvent event){ + Craft craft = event.getCraft(); + Player p = craft.getNotificationPlayer(); + RedProtectAPI redProtectAPI = new RedProtectAPI(); + Region toEnter = null; + Region toExit = null; + for (MovecraftLocation loc : event.getOldHitBox()){ + toExit = redProtectAPI.getRegion(loc.toBukkit(craft.getW())); + if (toExit != null){ + break; + } + } + for (MovecraftLocation loc : event.getNewHitBox()){ + toEnter = redProtectAPI.getRegion(loc.toBukkit(craft.getW())); + if (toEnter != null){ + break; + } + } + if (toEnter != null) { + if (!toEnter.canBuild(p)&& Settings.RedProtectBlockMoveOnNoBuild) { + event.setFailMessage("RedProtect - Translation Failed Player cannot build"); + event.setCancelled(true); + } + if (!toEnter.canEnter(p) && Settings.RedProtectBlockMoveOnNoEntry){ + event.setFailMessage("RedProtect - Translation Failed Player cannot enter"); + event.setCancelled(true); + } + } + if (toExit != null){ + if (!toExit.canExit(p) && Settings.RedProtectBlockMoveOnNoExit){ + for (MovecraftLocation loc : event.getNewHitBox()) { + Region foundRegion = redProtectAPI.getRegion(loc.toBukkit(craft.getW())); + if (foundRegion == null || !foundRegion.equals(toExit)) { + event.setFailMessage("RedProtect - Translation Failed Player cannot exit"); + event.setCancelled(true); + break; + } + } + } + } + + } + @EventHandler + public void onCraftRotate (CraftRotateEvent event){ + Craft craft = event.getCraft(); + Player p = craft.getNotificationPlayer(); + RedProtectAPI redProtectAPI = new RedProtectAPI(); + + Region toEnter = null; + Region toExit = null; + for (MovecraftLocation loc : event.getOldHitBox()){ + toExit = redProtectAPI.getRegion(loc.toBukkit(craft.getW())); + if (toExit != null){ + break; + } + } + for (MovecraftLocation loc : event.getNewHitBox()){ + toEnter = redProtectAPI.getRegion(loc.toBukkit(craft.getW())); + if (toEnter != null){ + break; + } + } + if (toEnter != null) { + if (!toEnter.canBuild(p)&& Settings.RedProtectBlockMoveOnNoBuild) { + event.setFailMessage("RedProtect - Translation Failed Player cannot build"); + event.setCancelled(true); + } + if (!toEnter.canEnter(p) && Settings.RedProtectBlockMoveOnNoEntry){ + event.setFailMessage("RedProtect - Translation Failed Player cannot enter"); + event.setCancelled(true); + } + } + if (toExit != null){ + if (!toExit.canExit(p) && Settings.RedProtectBlockMoveOnNoExit){ + for (MovecraftLocation loc : event.getNewHitBox()) { + Region foundRegion = redProtectAPI.getRegion(loc.toBukkit(craft.getW())); + if (foundRegion == null || !foundRegion.equals(toExit)) { + event.setFailMessage("RedProtect - Translation Failed Player cannot exit"); + event.setCancelled(true); + break; + } + } + } + } + + } + @EventHandler + public void onCraftSink(CraftSinkEvent event){ + HashHitBox hitBox = event.getCraft().getHitBox(); + Region foundRegion = null; + RedProtectAPI redProtectAPI = new RedProtectAPI(); + for (MovecraftLocation loc : hitBox){ + foundRegion = redProtectAPI.getRegion(loc.toBukkit(event.getCraft().getW())); + if (foundRegion != null){ + break; + } + } + if (foundRegion == null){ + return; + } + if (!foundRegion.canPVP(event.getCraft().getNotificationPlayer(),null) && Settings.RedProtectBlockSinkOnNoPvP){ + event.setFailMessage(I18nSupport.getInternationalisedString("RedProtect - Craft should sink but PvP is disabled")); + } } } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/ICraft.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/ICraft.java index 3da14bc21..590030f5d 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/ICraft.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/ICraft.java @@ -10,18 +10,14 @@ import net.countercraft.movecraft.localisation.I18nSupport; import net.countercraft.movecraft.mapUpdater.MapUpdateManager; import net.countercraft.movecraft.mapUpdater.update.FuelBurnUpdateCommand; -import org.bukkit.*; +import org.bukkit.Material; +import org.bukkit.Sound; +import org.bukkit.World; import org.bukkit.block.Block; import org.bukkit.entity.Player; import org.bukkit.inventory.InventoryHolder; -import org.bukkit.inventory.ItemStack; -import org.bukkit.scheduler.BukkitRunnable; -import org.bukkit.scheduler.BukkitTask; import org.jetbrains.annotations.NotNull; -import java.util.ArrayList; -import java.util.Iterator; -import java.util.List; import java.util.UUID; public class ICraft extends Craft { @@ -91,11 +87,15 @@ public void translate(int dx, int dy, int dz) { } } }*/ + if (!checkFuel(dx,dy,dz)){ getNotificationPlayer().playSound(getNotificationPlayer().getLocation(),Sound.BLOCK_ANVIL_LAND,1,0); getNotificationPlayer().sendMessage(I18nSupport.getInternationalisedString("Translation - Failed Craft out of fuel")); return; } + if (isClimbing()){ + setClimbing(false); + } Movecraft.getInstance().getAsyncManager().submitTask(new TranslationTask(this, dx, dy, dz), this); } @@ -176,7 +176,8 @@ private boolean checkFuel(int dx, int dy, int dz){ // going down doesn't require fuel if (dy == -1 && dx == 0 && dz == 0) fuelBurnRate = 0.0; - + if (dy > 0) + fuelBurnRate *= 2; if (fuelBurnRate == 0.0 || getSinking()) { return true; } @@ -184,7 +185,6 @@ private boolean checkFuel(int dx, int dy, int dz){ setBurningFuel(getBurningFuel() - fuelBurnRate); return true; } - final List fuelHolders = new ArrayList<>(); Block fuelHolder = null; for (MovecraftLocation bTest : getHitBox()) { Block b = getW().getBlockAt(bTest.getX(), bTest.getY(), bTest.getZ()); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/InteractListener.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/InteractListener.java index 6b61bf200..affc70f28 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/InteractListener.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/InteractListener.java @@ -17,13 +17,12 @@ package net.countercraft.movecraft.listener; -import net.countercraft.movecraft.Movecraft; -import net.countercraft.movecraft.utils.LegacyUtils; -import net.countercraft.movecraft.utils.MathUtils; -import net.countercraft.movecraft.craft.Craft; import net.countercraft.movecraft.config.Settings; +import net.countercraft.movecraft.craft.Craft; import net.countercraft.movecraft.craft.CraftManager; import net.countercraft.movecraft.localisation.I18nSupport; +import net.countercraft.movecraft.utils.LegacyUtils; +import net.countercraft.movecraft.utils.MathUtils; import org.bukkit.Material; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; @@ -109,7 +108,7 @@ public void onPlayerInteractStick(PlayerInteractEvent event) { // right click moves up or down if using direct // control if (craft.getCruising()){ - Movecraft.getInstance().getAsyncManager().setClimb(true); + craft.setClimbing(true); return; } int DY = 1; diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/repair/RepairManager.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/repair/RepairManager.java index 51af511de..22830c32b 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/repair/RepairManager.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/repair/RepairManager.java @@ -1,11 +1,8 @@ package net.countercraft.movecraft.repair; import net.countercraft.movecraft.Movecraft; -import org.bukkit.Bukkit; -import org.bukkit.plugin.Plugin; import org.bukkit.scheduler.BukkitRunnable; -import java.util.Iterator; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/repair/RepairTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/repair/RepairTask.java index a3beb291d..d6090d685 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/repair/RepairTask.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/repair/RepairTask.java @@ -1,21 +1,14 @@ package net.countercraft.movecraft.repair; -import com.sk89q.worldedit.Vector; -import net.countercraft.movecraft.Movecraft; -import net.countercraft.movecraft.MovecraftLocation; -import net.countercraft.movecraft.MovecraftRepair; import net.countercraft.movecraft.config.Settings; import net.countercraft.movecraft.craft.Craft; import net.countercraft.movecraft.craft.CraftManager; import net.countercraft.movecraft.localisation.I18nSupport; import net.countercraft.movecraft.mapUpdater.MapUpdateManager; -import net.countercraft.movecraft.utils.HashHitBox; import org.bukkit.Bukkit; -import org.bukkit.Location; import org.bukkit.entity.Player; import org.bukkit.scheduler.BukkitRunnable; -import java.util.Collections; import java.util.concurrent.atomic.AtomicBoolean; public class RepairTask extends BukkitRunnable { @@ -30,11 +23,9 @@ public void run() { for (Craft craft : CraftManager.getInstance()){ if (craft == null) continue; - for (MovecraftLocation location : repair.getHitBox()){ - if (craft.getHitBox().contains(location)) { - repairCraft = craft; - break; - } + if (craft.getHitBox().containsAll(repair.getHitBox().asSet())) { + repairCraft = craft; + break; } } if (repairCraft != null) diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/AscendSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/AscendSign.java index 630f45701..37cac3e6e 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/AscendSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/AscendSign.java @@ -1,13 +1,10 @@ package net.countercraft.movecraft.sign; import net.countercraft.movecraft.MovecraftLocation; -import net.countercraft.movecraft.config.Settings; import net.countercraft.movecraft.craft.Craft; import net.countercraft.movecraft.craft.CraftManager; import net.countercraft.movecraft.events.CraftDetectEvent; -import net.countercraft.movecraft.utils.LegacyUtils; import org.bukkit.ChatColor; -import org.bukkit.Material; import org.bukkit.World; import org.bukkit.block.Block; import org.bukkit.block.BlockFace; @@ -41,7 +38,7 @@ public void onSignClickEvent(PlayerInteractEvent event){ return; } Block block = event.getClickedBlock(); - if (block.getType() != (Settings.IsLegacy ? LegacyUtils.SIGN_POST : Material.SIGN) && block.getType() != Material.WALL_SIGN){ + if (!(event.getClickedBlock().getState() instanceof Sign)){ return; } Sign sign = (Sign) event.getClickedBlock().getState(); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/DescendSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/DescendSign.java index 827c1f0c2..25cd8a5dd 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/DescendSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/DescendSign.java @@ -1,13 +1,10 @@ package net.countercraft.movecraft.sign; import net.countercraft.movecraft.MovecraftLocation; -import net.countercraft.movecraft.config.Settings; import net.countercraft.movecraft.craft.Craft; import net.countercraft.movecraft.craft.CraftManager; import net.countercraft.movecraft.events.CraftDetectEvent; -import net.countercraft.movecraft.utils.LegacyUtils; import org.bukkit.ChatColor; -import org.bukkit.Material; import org.bukkit.World; import org.bukkit.block.Block; import org.bukkit.block.BlockFace; @@ -40,7 +37,7 @@ public final void onSignClick(PlayerInteractEvent event) { return; } Block block = event.getClickedBlock(); - if (block.getType() != (Settings.IsLegacy ? LegacyUtils.SIGN_POST : Material.SIGN) && block.getType() != Material.WALL_SIGN) { + if (!(event.getClickedBlock().getState() instanceof Sign)){ return; } Sign sign = (Sign) event.getClickedBlock().getState(); diff --git a/modules/Movecraft/src/main/resources/localisation/movecraftlang_en.properties b/modules/Movecraft/src/main/resources/localisation/movecraftlang_en.properties index 0dd9abc7f..5b78248c3 100644 --- a/modules/Movecraft/src/main/resources/localisation/movecraftlang_en.properties +++ b/modules/Movecraft/src/main/resources/localisation/movecraftlang_en.properties @@ -84,3 +84,5 @@ WGCustomFlags\ -\ Translation\ Failed=Translation Failed - You are not permitted WGCustomFlags\ -\ Rotation\ Failed=Rotation Failed - You are not permitterd to rotate a craft in this WorldGuard region WGCustomFlags\ -\ Detection\ Failed=Detection Failed - You are not permitted to pilot a craft in this WorldGuard region WGCustomFlags\ -\ Sinking\ a\ craft\ is\ not\ allowed\ in\ this\ WorldGuard\ region=Sinking is not allowed in this WorldGuard region\! +Factions\ -\ Translation\ Failed\ Faction\ Has\ No\ Access=Translation Failed - Your faction is not permitted to move a craft in the territory of {FACTION}\! +Factions\ -\ Translation\ Failed\ Player\ Has\ No\ Access=Translation Failed - Your are not permitted to move a craft in the territory of {FACTION}\! \ No newline at end of file diff --git a/modules/api/src/main/java/net/countercraft/movecraft/config/Settings.java b/modules/api/src/main/java/net/countercraft/movecraft/config/Settings.java index 1ec05dd25..07a277065 100644 --- a/modules/api/src/main/java/net/countercraft/movecraft/config/Settings.java +++ b/modules/api/src/main/java/net/countercraft/movecraft/config/Settings.java @@ -62,11 +62,19 @@ public class Settings { public static boolean TownyBlockMoveOnSwitchPerm = false; public static boolean TownyBlockSinkOnNoPVP = false; public static boolean FactionsBlockMoveInSafezone = false; + public static boolean FactionsBlockSinkInSafezone = false; public static boolean FactionsBlockMoveInWarzone = false; public static boolean FactionsBlockMoveInAllyTerritory = false; public static boolean FactionsBlockMoveInTruceTerritory = false; public static boolean FactionsBlockMoveInEnemyTerritory = false; public static boolean FactionsBlockSinkOnNoPVP = false; + public static boolean GriefPreventionSinkOnNoPvP = false; + + //RedProtect Settings + public static boolean RedProtectBlockMoveOnNoEntry = false; + public static boolean RedProtectBlockMoveOnNoBuild = false; + public static boolean RedProtectBlockMoveOnNoExit = false; + public static boolean RedProtectBlockSinkOnNoPvP = false; public static Map TownProtectionHeightLimits; public static Map DurabilityOverride; public static boolean IsPaper = false; diff --git a/modules/api/src/main/java/net/countercraft/movecraft/craft/Craft.java b/modules/api/src/main/java/net/countercraft/movecraft/craft/Craft.java index 162f4a651..47d29ff15 100644 --- a/modules/api/src/main/java/net/countercraft/movecraft/craft/Craft.java +++ b/modules/api/src/main/java/net/countercraft/movecraft/craft/Craft.java @@ -21,6 +21,7 @@ import net.countercraft.movecraft.Rotation; import net.countercraft.movecraft.config.Settings; import net.countercraft.movecraft.events.CraftSinkEvent; +import net.countercraft.movecraft.localisation.I18nSupport; import net.countercraft.movecraft.utils.HashHitBox; import net.md_5.bungee.api.ChatMessageType; import net.md_5.bungee.api.chat.TextComponent; @@ -49,6 +50,7 @@ public abstract class Craft { @NotNull protected World w; @NotNull private final AtomicBoolean processing = new AtomicBoolean(); private int maxHeightLimit; + private boolean climbing; private boolean cruising; private boolean sinking; private boolean disabled; @@ -92,8 +94,10 @@ public Craft(@NotNull CraftType type, @NotNull World world) { this.cannonDirector = null; this.AADirector = null; this.lastCruiseUpdate = System.currentTimeMillis() - 10000; + this.climbing = false; this.cruising = false; this.sinking = false; + this.repairing = false; this.disabled = false; this.origPilotTime = System.currentTimeMillis(); numMoves = 0; @@ -158,8 +162,12 @@ public void sink(){ CraftSinkEvent event = new CraftSinkEvent(this); Bukkit.getServer().getPluginManager().callEvent(event); if(event.isCancelled()){ + notificationPlayer.sendMessage(event.getFailMessage()); return; } + if (notificationPlayer != null) { + notificationPlayer.sendMessage(I18nSupport.getInternationalisedString("Player- Craft is sinking")); + } this.sinking = true; } @@ -440,4 +448,12 @@ public boolean isRepairing() { public void setRepairing(boolean repairing) { this.repairing = repairing; } + + public boolean isClimbing() { + return climbing; + } + + public void setClimbing(boolean climbing) { + this.climbing = climbing; + } } \ No newline at end of file diff --git a/modules/api/src/main/java/net/countercraft/movecraft/events/CraftSinkEvent.java b/modules/api/src/main/java/net/countercraft/movecraft/events/CraftSinkEvent.java index 40770c59d..9064bc789 100644 --- a/modules/api/src/main/java/net/countercraft/movecraft/events/CraftSinkEvent.java +++ b/modules/api/src/main/java/net/countercraft/movecraft/events/CraftSinkEvent.java @@ -8,6 +8,7 @@ public class CraftSinkEvent extends CraftEvent implements Cancellable { private static final HandlerList HANDLERS = new HandlerList(); private boolean cancelled = false; + @NotNull private String failMessage = ""; public CraftSinkEvent(@NotNull Craft craft) { super(craft); @@ -32,4 +33,13 @@ public boolean isCancelled() { public void setCancelled(boolean cancel) { this.cancelled = cancel; } + + @NotNull + public String getFailMessage(){ + return failMessage; + } + + public void setFailMessage(@NotNull String failMessage) { + this.failMessage = failMessage; + } } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/localisation/I18nSupport.java b/modules/api/src/main/java/net/countercraft/movecraft/localisation/I18nSupport.java similarity index 82% rename from modules/Movecraft/src/main/java/net/countercraft/movecraft/localisation/I18nSupport.java rename to modules/api/src/main/java/net/countercraft/movecraft/localisation/I18nSupport.java index cd6d42ac5..c6ec7ee38 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/localisation/I18nSupport.java +++ b/modules/api/src/main/java/net/countercraft/movecraft/localisation/I18nSupport.java @@ -17,22 +17,22 @@ package net.countercraft.movecraft.localisation; -import net.countercraft.movecraft.Movecraft; import net.countercraft.movecraft.config.Settings; +import org.bukkit.plugin.Plugin; import java.io.*; import java.util.Arrays; import java.util.Properties; import java.util.logging.Level; -public class I18nSupport { +public final class I18nSupport { private static Properties languageFile; private static boolean hasOtherScript = false; private static final String[] otherScriptLangs = {"el", "ar", "ur", "he", "zh", "jp"}; - public static void init() { + public static void init(Plugin plugin) { languageFile = new Properties(); - File localisationDirectory = new File(Movecraft.getInstance().getDataFolder().getAbsolutePath() + "/localisation"); + File localisationDirectory = new File(plugin.getDataFolder().getAbsolutePath() + "/localisation"); if (!localisationDirectory.exists()) { localisationDirectory.mkdirs(); @@ -47,8 +47,8 @@ public static void init() { if (is == null) { - Movecraft.getInstance().getLogger().log(Level.SEVERE, "Critical Error in Localisation System"); - Movecraft.getInstance().getServer().shutdown(); + plugin.getLogger().log(Level.SEVERE, "Critical Error in Localisation System"); + plugin.getServer().shutdown(); return; } @@ -62,8 +62,7 @@ public static void init() { } public static boolean writtenFromRightToLeft(){ - boolean ret = (boolean) languageFile.getOrDefault("writtenFromRightToLeft", false); - return ret; + return (boolean) languageFile.getOrDefault("writtenFromRightToLeft", false); } public static String getInternationalisedString(String key) { String ret; diff --git a/modules/v1_14_R1/pom.xml b/modules/v1_14_R1/pom.xml index 3801214de..1e95a4d85 100644 --- a/modules/v1_14_R1/pom.xml +++ b/modules/v1_14_R1/pom.xml @@ -35,7 +35,7 @@ org.bukkit craftbukkit - 1.14.1-R0.1-SNAPSHOT + 1.14.2-R0.1-SNAPSHOT diff --git a/modules/v1_14_R1/src/main/java/net/countercraft/movecraft/compat/v1_14_R1/NextTickProvider.java b/modules/v1_14_R1/src/main/java/net/countercraft/movecraft/compat/v1_14_R1/NextTickProvider.java index 58bedaa72..a74ff7623 100644 --- a/modules/v1_14_R1/src/main/java/net/countercraft/movecraft/compat/v1_14_R1/NextTickProvider.java +++ b/modules/v1_14_R1/src/main/java/net/countercraft/movecraft/compat/v1_14_R1/NextTickProvider.java @@ -10,7 +10,7 @@ import java.util.*; public class NextTickProvider { - private Map,List>> tickMap = new HashMap<>(); + private Map,Collection>> tickMap = new HashMap<>(); private boolean isRegistered(@NotNull WorldServer world){ return tickMap.containsKey(world); @@ -18,13 +18,13 @@ private boolean isRegistered(@NotNull WorldServer world){ @SuppressWarnings("unchecked") private void registerWorld(@NotNull WorldServer world){ - List W = new ArrayList<>(); + Collection W = new ArrayList<>(); Set nextTickList = new HashSet<>(); TickListServer blockTickListServer = world.getBlockTickList(); try { Field gField = TickListServer.class.getDeclaredField("g"); gField.setAccessible(true); - W = (List) gField.get(blockTickListServer); + W = (Collection) gField.get(blockTickListServer); Field ntlField = TickListServer.class.getDeclaredField("nextTickList"); ntlField.setAccessible(true); nextTickList = (Set) ntlField.get(blockTickListServer); @@ -38,7 +38,7 @@ private void registerWorld(@NotNull WorldServer world){ public NextTickListEntry getNextTick(@NotNull WorldServer world,@NotNull BlockPosition position){ if(!isRegistered(world)) registerWorld(world); - Pair, List> listPair = tickMap.get(world); + Pair, Collection> listPair = tickMap.get(world); for(Iterator iterator = listPair.getLeft().iterator(); iterator.hasNext();) { NextTickListEntry listEntry = iterator.next(); if (position.equals(listEntry.a)) { From 18099fe1a6780a59f07c6594a0c240fd0bd233b6 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Sun, 2 Jun 2019 20:03:31 +0200 Subject: [PATCH 017/304] Fixed fuel being consumed while craft is obstructed --- .../async/rotation/RotationTask.java | 56 +++++++++++++++++- .../async/translation/TranslationTask.java | 57 +++++++++++++++++++ .../countercraft/movecraft/craft/ICraft.java | 50 +--------------- .../mapUpdater/update/CraftRotateCommand.java | 1 - .../update/CraftTranslateCommand.java | 10 ++-- 5 files changed, 117 insertions(+), 57 deletions(-) diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/rotation/RotationTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/rotation/RotationTask.java index fecd6621e..302d02f01 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/rotation/RotationTask.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/rotation/RotationTask.java @@ -39,10 +39,15 @@ import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.World; +import org.bukkit.block.Block; import org.bukkit.block.BlockFace; +import org.bukkit.block.Furnace; import org.bukkit.entity.Entity; import org.bukkit.entity.EntityType; import org.bukkit.entity.Player; +import org.bukkit.inventory.InventoryHolder; +import org.bukkit.inventory.ItemStack; +import org.bukkit.scheduler.BukkitRunnable; import java.util.HashSet; import java.util.Set; @@ -92,8 +97,57 @@ protected void execute() { failed = true; failMessage = I18nSupport.getInternationalisedString("Craft is disabled!"); } + double fuelBurnRate = craft.getType().getFuelBurnRate(); + if (fuelBurnRate > 0.0) { + new BukkitRunnable() { + @Override + public void run() { + // check for fuel, burn some from a furnace if needed. Blocks of coal are supported, in addition to coal and charcoal + + if (fuelBurnRate == 0.0 || craft.getSinking()) { + return; + } + if (craft.getBurningFuel() >= fuelBurnRate) { + craft.setBurningFuel(craft.getBurningFuel() - fuelBurnRate); + return; + } + Block fuelHolder = null; + for (MovecraftLocation bTest : craft.getHitBox()) { + Block b = craft.getW().getBlockAt(bTest.getX(), bTest.getY(), bTest.getZ()); + //Get all fuel holders + if (b.getType() == Material.FURNACE) { + InventoryHolder holder = (InventoryHolder) b.getState(); + for (Material fuel : Settings.FuelTypes.keySet()) { + if (holder.getInventory().contains(fuel)) { + fuelHolder = b; + break; + } + } + } + if (fuelHolder != null) break; - + } + if (fuelHolder == null) { + failMessage = I18nSupport.getInternationalisedString("Translation - Failed Craft out of fuel"); + failed = true; + return; + } + Furnace furnace = (Furnace) fuelHolder.getState(); + for (Material fuel : Settings.FuelTypes.keySet()) { + if (furnace.getInventory().contains(fuel)) { + ItemStack item = furnace.getInventory().getItem(furnace.getInventory().first(fuel)); + int amount = item.getAmount(); + if (amount == 1) { + furnace.getInventory().remove(item); + } else { + item.setAmount(amount - 1); + } + craft.setBurningFuel(craft.getBurningFuel() + Settings.FuelTypes.get(item.getType())); + } + } + } + }.runTask(Movecraft.getInstance()); + } // if a subcraft, find the parent craft. If not a subcraft, it is it's own parent Set craftsInWorld = CraftManager.getInstance().getCraftsInWorld(getCraft().getW()); Craft parentCraft = getCraft(); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java index 41468cf16..8b61f6b1e 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java @@ -1,5 +1,6 @@ package net.countercraft.movecraft.async.translation; +import net.countercraft.movecraft.Movecraft; import net.countercraft.movecraft.MovecraftLocation; import net.countercraft.movecraft.async.AsyncTask; import net.countercraft.movecraft.config.Settings; @@ -18,6 +19,7 @@ import org.bukkit.Sound; import org.bukkit.block.Block; import org.bukkit.block.Chest; +import org.bukkit.block.Furnace; import org.bukkit.entity.Entity; import org.bukkit.entity.EntityType; import org.bukkit.entity.Player; @@ -25,6 +27,7 @@ import org.bukkit.inventory.InventoryHolder; import org.bukkit.inventory.ItemStack; import org.bukkit.potion.PotionEffect; +import org.bukkit.scheduler.BukkitRunnable; import java.util.*; import java.util.concurrent.ThreadLocalRandom; @@ -113,6 +116,60 @@ protected void execute() { if(oldHitBox.isEmpty()){ return; } + if (craft.getType().getFuelBurnRate() > 0.0) { + new BukkitRunnable() { + @Override + public void run() { + // check for fuel, burn some from a furnace if needed. Blocks of coal are supported, in addition to coal and charcoal + double fuelBurnRate = craft.getType().getFuelBurnRate(); + // going down doesn't require fuel + if (dy == -1 && dx == 0 && dz == 0) + fuelBurnRate = 0.0; + if (dy > 0) + fuelBurnRate *= 2; + if (fuelBurnRate == 0.0 || craft.getSinking()) { + return; + } + if (craft.getBurningFuel() >= fuelBurnRate) { + craft.setBurningFuel(craft.getBurningFuel() - fuelBurnRate); + return; + } + Block fuelHolder = null; + for (MovecraftLocation bTest : craft.getHitBox()) { + Block b = craft.getW().getBlockAt(bTest.getX(), bTest.getY(), bTest.getZ()); + //Get all fuel holders + if (b.getType() == Material.FURNACE) { + InventoryHolder holder = (InventoryHolder) b.getState(); + for (Material fuel : Settings.FuelTypes.keySet()) { + if (holder.getInventory().contains(fuel)) { + fuelHolder = b; + break; + } + } + } + if (fuelHolder != null) break; + + } + if (fuelHolder == null) { + fail(I18nSupport.getInternationalisedString("Translation - Failed Craft out of fuel")); + return; + } + Furnace furnace = (Furnace) fuelHolder.getState(); + for (Material fuel : Settings.FuelTypes.keySet()) { + if (furnace.getInventory().contains(fuel)) { + ItemStack item = furnace.getInventory().getItem(furnace.getInventory().first(fuel)); + int amount = item.getAmount(); + if (amount == 1) { + furnace.getInventory().remove(item); + } else { + item.setAmount(amount - 1); + } + craft.setBurningFuel(craft.getBurningFuel() + Settings.FuelTypes.get(item.getType())); + } + } + } + }.runTask(Movecraft.getInstance()); + } //Prevent disabled crafts from moving if (getCraft().getDisabled() && (!getCraft().getSinking())) { fail(I18nSupport.getInternationalisedString("Craft is disabled!")); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/ICraft.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/ICraft.java index 590030f5d..63b99f86a 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/ICraft.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/ICraft.java @@ -88,11 +88,7 @@ public void translate(int dx, int dy, int dz) { } }*/ - if (!checkFuel(dx,dy,dz)){ - getNotificationPlayer().playSound(getNotificationPlayer().getLocation(),Sound.BLOCK_ANVIL_LAND,1,0); - getNotificationPlayer().sendMessage(I18nSupport.getInternationalisedString("Translation - Failed Craft out of fuel")); - return; - } + if (isClimbing()){ setClimbing(false); } @@ -142,19 +138,11 @@ public void rotate(Rotation rotation, MovecraftLocation originPoint) { } } }*/ - if (!checkFuel(0,0,0)){ - getNotificationPlayer().sendMessage(I18nSupport.getInternationalisedString("Translation - Failed Craft out of fuel")); - return; - } Movecraft.getInstance().getAsyncManager().submitTask(new RotationTask(this, originPoint, rotation, this.getW()), this); } @Override public void rotate(Rotation rotation, MovecraftLocation originPoint, boolean isSubCraft) { - if (!checkFuel(0,0,0)){ - getNotificationPlayer().sendMessage(I18nSupport.getInternationalisedString("Translation - Failed Craft out of fuel")); - return; - } Movecraft.getInstance().getAsyncManager().submitTask(new RotationTask(this, originPoint, rotation, this.getW(), isSubCraft), this); } @@ -170,41 +158,5 @@ public boolean equals(Object obj) { public int hashCode() { return id.hashCode(); } - private boolean checkFuel(int dx, int dy, int dz){ - // check for fuel, burn some from a furnace if needed. Blocks of coal are supported, in addition to coal and charcoal - double fuelBurnRate = getType().getFuelBurnRate(); - // going down doesn't require fuel - if (dy == -1 && dx == 0 && dz == 0) - fuelBurnRate = 0.0; - if (dy > 0) - fuelBurnRate *= 2; - if (fuelBurnRate == 0.0 || getSinking()) { - return true; - } - if (getBurningFuel() >= fuelBurnRate) { - setBurningFuel(getBurningFuel() - fuelBurnRate); - return true; - } - Block fuelHolder = null; - for (MovecraftLocation bTest : getHitBox()) { - Block b = getW().getBlockAt(bTest.getX(), bTest.getY(), bTest.getZ()); - //Get all fuel holders - if (b.getType() == Material.FURNACE) { - InventoryHolder holder = (InventoryHolder) b.getState(); - for (Material fuel : Settings.FuelTypes.keySet()){ - if (holder.getInventory().contains(fuel)){ - fuelHolder = b; - break; - } - } - } - if (fuelHolder != null) break; - } - if (fuelHolder == null){ - return false; - } - MapUpdateManager.getInstance().scheduleUpdate(new FuelBurnUpdateCommand(this,fuelHolder)); - return true; - } } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftRotateCommand.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftRotateCommand.java index 896e00c5b..4d05e52b1 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftRotateCommand.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftRotateCommand.java @@ -4,7 +4,6 @@ import net.countercraft.movecraft.MovecraftLocation; import net.countercraft.movecraft.Rotation; import net.countercraft.movecraft.WorldHandler; -import net.countercraft.movecraft.compat.fawe.*; import net.countercraft.movecraft.config.Settings; import net.countercraft.movecraft.craft.Craft; import net.countercraft.movecraft.craft.CraftManager; diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftTranslateCommand.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftTranslateCommand.java index 15d4d8c51..802aa7183 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftTranslateCommand.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftTranslateCommand.java @@ -7,7 +7,6 @@ import net.countercraft.movecraft.craft.Craft; import net.countercraft.movecraft.craft.CraftManager; import net.countercraft.movecraft.events.SignTranslateEvent; -import net.countercraft.movecraft.mapUpdater.MapUpdateManager; import net.countercraft.movecraft.utils.*; import org.bukkit.Bukkit; import org.bukkit.Material; @@ -15,11 +14,7 @@ import org.bukkit.block.Sign; import org.jetbrains.annotations.NotNull; -import java.util.HashSet; -import java.util.LinkedList; -import java.util.Objects; -import java.util.Queue; -import java.util.Set; +import java.util.*; import java.util.logging.Logger; public class CraftTranslateCommand extends UpdateCommand { @@ -77,6 +72,7 @@ public void doUpdate() { } } + if(passthroughBlocks.isEmpty()){ //translate the craft Movecraft.getInstance().getWorldHandler().translateCraft(craft,displacement); @@ -228,4 +224,6 @@ public boolean equals(Object obj) { public int hashCode() { return Objects.hash(craft, displacement); } + + } From 2678c82bdba8768de05417c63671b9e2a55dce3c Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Wed, 5 Jun 2019 11:50:50 +0200 Subject: [PATCH 018/304] Fixed repair and implemented 1.14 API --- modules/Movecraft/pom.xml | 12 +-- .../movecraft/async/AsyncManager.java | 20 +++- .../async/translation/TranslationTask.java | 18 +++- .../movecraft/listener/BlockListener.java | 6 +- .../mapUpdater/update/CraftRotateCommand.java | 4 +- .../update/WorldEdit7UpdateCommand.java | 4 +- .../update/WorldEditUpdateCommand.java | 6 +- .../movecraft/sign/RepairSign.java | 48 ++-------- .../warfare/assault/AssaultTask.java | 3 +- .../warfare/assault/AssaultUtils.java | 16 +--- .../movecraft/MovecraftLocation.java | 4 + .../movecraft/MovecraftRepair.java | 11 +-- .../movecraft/utils/MathUtils.java | 2 + .../countercraft/movecraft/utils/Pair.java | 8 +- .../compat/we6/IMovecraftRepair.java | 57 +++-------- .../compat/we7/IMovecraftRepair.java | 96 +++++++------------ pom.xml | 2 +- 17 files changed, 125 insertions(+), 192 deletions(-) diff --git a/modules/Movecraft/pom.xml b/modules/Movecraft/pom.xml index e3dfc8112..0974d368b 100644 --- a/modules/Movecraft/pom.xml +++ b/modules/Movecraft/pom.xml @@ -35,11 +35,7 @@ - - com.sk89q.worldedit - worldedit-bukkit - 7.0.0-SNAPSHOT - + net.countercraft movecraft-v1_14_R1 @@ -79,7 +75,11 @@ - + + com.sk89q.worldedit + worldedit-bukkit + 7.0.0-SNAPSHOT + com.sk89q worldguard diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java index cc3ec0c1d..0690d7c2d 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java @@ -74,8 +74,7 @@ public AsyncManager() { transparent.add(Material.NETHER_BRICK_STAIRS); transparent.add(Material.LEVER); transparent.add(Material.STONE_BUTTON); - transparent.add(Material.SIGN); - transparent.add(Material.WALL_SIGN); + if (Settings.IsLegacy){ transparent.add(LegacyUtils.THIN_GLASS); transparent.add(LegacyUtils.STAINED_GLASS); @@ -87,6 +86,23 @@ public AsyncManager() { transparent.add(LegacyUtils.SMOOTH_STAIRS); transparent.add(LegacyUtils.SIGN_POST); } else { + if (Settings.is1_14){ + transparent.add(Material.BIRCH_SIGN); + transparent.add(Material.OAK_SIGN); + transparent.add(Material.DARK_OAK_SIGN); + transparent.add(Material.JUNGLE_SIGN); + transparent.add(Material.SPRUCE_SIGN); + transparent.add(Material.ACACIA_SIGN); + transparent.add(Material.BIRCH_WALL_SIGN); + transparent.add(Material.OAK_WALL_SIGN); + transparent.add(Material.DARK_OAK_WALL_SIGN); + transparent.add(Material.JUNGLE_WALL_SIGN); + transparent.add(Material.SPRUCE_WALL_SIGN); + transparent.add(Material.ACACIA_WALL_SIGN); + } else { + transparent.add(Material.getMaterial("SIGN")); + transparent.add(Material.getMaterial("WALL_SIGN")); + } transparent.add(Material.GLASS_PANE); transparent.add(Material.BLACK_STAINED_GLASS_PANE); transparent.add(Material.WHITE_STAINED_GLASS_PANE); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java index 8b61f6b1e..4014ff6c1 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java @@ -75,7 +75,23 @@ public TranslationTask(Craft c, int dx, int dy, int dz) { FALL_THROUGH_BLOCKS.add(Material.FIRE); FALL_THROUGH_BLOCKS.add(Material.REDSTONE_WIRE); FALL_THROUGH_BLOCKS.add(Material.LADDER); - FALL_THROUGH_BLOCKS.add(Material.WALL_SIGN); + if (Settings.is1_14){ + FALL_THROUGH_BLOCKS.add(Material.BIRCH_SIGN); + FALL_THROUGH_BLOCKS.add(Material.OAK_SIGN); + FALL_THROUGH_BLOCKS.add(Material.DARK_OAK_SIGN); + FALL_THROUGH_BLOCKS.add(Material.JUNGLE_SIGN); + FALL_THROUGH_BLOCKS.add(Material.SPRUCE_SIGN); + FALL_THROUGH_BLOCKS.add(Material.ACACIA_SIGN); + FALL_THROUGH_BLOCKS.add(Material.BIRCH_WALL_SIGN); + FALL_THROUGH_BLOCKS.add(Material.OAK_WALL_SIGN); + FALL_THROUGH_BLOCKS.add(Material.DARK_OAK_WALL_SIGN); + FALL_THROUGH_BLOCKS.add(Material.JUNGLE_WALL_SIGN); + FALL_THROUGH_BLOCKS.add(Material.SPRUCE_WALL_SIGN); + FALL_THROUGH_BLOCKS.add(Material.ACACIA_WALL_SIGN); + } else { + FALL_THROUGH_BLOCKS.add(Material.getMaterial("SIGN")); + FALL_THROUGH_BLOCKS.add(Material.getMaterial("WALL_SIGN")); + } FALL_THROUGH_BLOCKS.add(Material.LEVER); FALL_THROUGH_BLOCKS.add(Material.STONE_BUTTON); FALL_THROUGH_BLOCKS.add(Material.SNOW); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/BlockListener.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/BlockListener.java index bf2f0c51c..2436fd853 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/BlockListener.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/BlockListener.java @@ -98,7 +98,7 @@ public void onBlockBreak(final BlockBreakEvent e) { if (e.isCancelled()) { return; } - if (e.getBlock().getType() == Material.WALL_SIGN) { + if (e.getBlock().getType().name().endsWith("WALL_SIGN")) { Sign s = (Sign) e.getBlock().getState(); if (s.getLine(0).equalsIgnoreCase(ChatColor.RED + "REGION DAMAGED!")) { e.setCancelled(true); @@ -222,7 +222,7 @@ public void onPhysics(BlockPhysicsEvent event) { Block block = event.getBlock(); - final Material[] fragileBlocks = Settings.IsLegacy ? new Material[]{LegacyUtils.BED_BLOCK, LegacyUtils.PISTON_EXTENSION, Material.TORCH, Material.REDSTONE_WIRE, LegacyUtils.SIGN_POST, LegacyUtils.WOOD_DOOR, Material.LADDER, Material.WALL_SIGN, Material.LEVER, LegacyUtils.STONE_PLATE, LegacyUtils.IRON_DOOR_BLOCK, LegacyUtils.WOOD_PLATE, LegacyUtils.REDSTONE_TORCH_OFF, LegacyUtils.REDSTONE_TORCH_ON, Material.STONE_BUTTON, LegacyUtils.DIODE_BLOCK_OFF, LegacyUtils.DIODE_BLOCK_ON, LegacyUtils.TRAP_DOOR, Material.TRIPWIRE_HOOK, + final Material[] fragileBlocks = Settings.IsLegacy ? new Material[]{LegacyUtils.BED_BLOCK, LegacyUtils.PISTON_EXTENSION, Material.TORCH, Material.REDSTONE_WIRE, LegacyUtils.SIGN_POST, LegacyUtils.WOOD_DOOR, Material.LADDER, Material.getMaterial("WALL_SIGN"), Material.LEVER, LegacyUtils.STONE_PLATE, LegacyUtils.IRON_DOOR_BLOCK, LegacyUtils.WOOD_PLATE, LegacyUtils.REDSTONE_TORCH_OFF, LegacyUtils.REDSTONE_TORCH_ON, Material.STONE_BUTTON, LegacyUtils.DIODE_BLOCK_OFF, LegacyUtils.DIODE_BLOCK_ON, LegacyUtils.TRAP_DOOR, Material.TRIPWIRE_HOOK, Material.TRIPWIRE, LegacyUtils.WOOD_BUTTON, LegacyUtils.GOLD_PLATE, LegacyUtils.IRON_PLATE, LegacyUtils.REDSTONE_COMPARATOR_OFF, LegacyUtils.REDSTONE_COMPARATOR_ON, Material.DAYLIGHT_DETECTOR, LegacyUtils.CARPET, LegacyUtils.DAYLIGHT_DETECTOR_INVERTED, Material.SPRUCE_DOOR, Material.BIRCH_DOOR, Material.JUNGLE_DOOR, Material.ACACIA_DOOR, Material.DARK_OAK_DOOR} : null; CraftManager.getInstance().getCraftsInWorld(block.getWorld()); @@ -361,7 +361,7 @@ public void run() { } for (Block b : e.blockList()){ - if (b.getType() == Material.WALL_SIGN || b.getType() == (Settings.IsLegacy ? LegacyUtils.SIGN_POST : Material.SIGN)){ + if (b.getState() instanceof Sign){ Sign sign = (Sign) b.getState(); if (sign.getLine(0).equals(ChatColor.RED + "REGION DAMAGED!")){ diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftRotateCommand.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftRotateCommand.java index 4d05e52b1..ce56ae699 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftRotateCommand.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftRotateCommand.java @@ -149,7 +149,7 @@ public void doUpdate() { //trigger sign events for (MovecraftLocation location : craft.getHitBox()) { Block block = location.toBukkit(craft.getW()).getBlock(); - if (block.getType() == Material.WALL_SIGN || block.getType() == (Settings.IsLegacy ? LegacyUtils.SIGN_POST : Material.SIGN)) { + if (block.getState() instanceof Sign) { Sign sign = (Sign) block.getState(); Bukkit.getServer().getPluginManager().callEvent(new SignTranslateEvent(block, craft, sign.getLines())); sign.update(); @@ -185,7 +185,7 @@ public void doUpdate() { //trigger sign events for (MovecraftLocation location : craft.getHitBox()) { Block block = location.toBukkit(craft.getW()).getBlock(); - if (block.getType() == Material.WALL_SIGN || block.getType() == (Settings.IsLegacy ? LegacyUtils.SIGN_POST : Material.SIGN)) { + if (block.getState() instanceof Sign) { Sign sign = (Sign) block.getState(); Bukkit.getServer().getPluginManager().callEvent(new SignTranslateEvent(block, craft, sign.getLines())); sign.update(); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/WorldEdit7UpdateCommand.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/WorldEdit7UpdateCommand.java index 9c5902040..a69b4486b 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/WorldEdit7UpdateCommand.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/WorldEdit7UpdateCommand.java @@ -30,11 +30,13 @@ public WorldEdit7UpdateCommand(com.sk89q.worldedit.world.block.BaseBlock worldEd @Override public void doUpdate() { Block block = world.getBlockAt(location.getX(), location.getY(), location.getZ()); - Bukkit.broadcastMessage(type.name()); block.setType(type); assert worldEdit7BaseBlock != null; BlockData bData = BukkitAdapter.adapt(worldEdit7BaseBlock); block.setBlockData(bData); + if (Settings.Debug){ + Bukkit.broadcastMessage(String.format("Material: %s, Location: %s",type.name().toLowerCase().replace("_", " "),location.toString())); + } Material weType = BukkitAdapter.adapt(worldEdit7BaseBlock.getBlockType()); if (type == Material.DISPENSER){ Tag t = worldEdit7BaseBlock.getNbtData().getValue().get("Items"); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/WorldEditUpdateCommand.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/WorldEditUpdateCommand.java index 74fe0f2e2..30826acbf 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/WorldEditUpdateCommand.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/WorldEditUpdateCommand.java @@ -4,9 +4,7 @@ import com.sk89q.jnbt.ListTag; import com.sk89q.jnbt.Tag; import com.sk89q.worldedit.blocks.BaseBlock; -import com.sk89q.worldedit.bukkit.BukkitAdapter; import net.countercraft.movecraft.MovecraftLocation; -import net.countercraft.movecraft.config.Settings; import net.countercraft.movecraft.utils.LegacyUtils; import org.bukkit.Material; import org.bukkit.World; @@ -14,7 +12,6 @@ import org.bukkit.block.BlockState; import org.bukkit.block.Dispenser; import org.bukkit.block.Sign; -import org.bukkit.block.data.BlockData; import org.bukkit.inventory.ItemStack; public class WorldEditUpdateCommand extends UpdateCommand { @@ -160,7 +157,6 @@ public void doUpdate() { } private boolean isSign(Material type){ - if (Settings.IsLegacy) return type.equals(LegacyUtils.SIGN_POST) || type.equals(Material.WALL_SIGN); - else return type.equals(Material.SIGN) || type.equals(Material.WALL_SIGN); + return type.name().endsWith("SIGN"); } } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RepairSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RepairSign.java index 9012e90e7..af7321c0a 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RepairSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RepairSign.java @@ -17,8 +17,8 @@ import net.countercraft.movecraft.repair.RepairManager; import net.countercraft.movecraft.repair.RepairUtils; import net.countercraft.movecraft.utils.LegacyUtils; +import net.countercraft.movecraft.utils.Pair; import net.countercraft.movecraft.utils.WorldEditUtils; -import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.Material; import org.bukkit.World; @@ -40,36 +40,8 @@ public class RepairSign implements Listener{ private String HEADER = "Repair:"; private HashMap playerInteractTimeMap = new HashMap<>();//Players must be assigned by the UUID, or NullPointerExceptions are thrown - private final Material[] fragileBlocks = new Material[]{ Material.TORCH, Material.LADDER, Material.WALL_SIGN, Material.LEVER, Material.STONE_BUTTON, LegacyUtils.TRAP_DOOR, Material.TRIPWIRE_HOOK, LegacyUtils.WOOD_BUTTON, Material.IRON_TRAPDOOR, }; - private static final Material[] wallBlocks; - static { - Set types = new HashSet<>(); - for (Material type : Material.values()){ - int index = 0; - boolean add = false; - if (type.name().startsWith("WALL_")) { - types.add(type); - } - if (type.name().contains("_WALL_")){ - types.add(type); - } - if (type.name().endsWith("_BUTTON")){ - types.add(type); - } - if (type.name().endsWith("_TRAPDOOR")){ - types.add(type); - } + private final Material[] fragileBlocks = new Material[]{ Material.TORCH, Material.LADDER, Material.getMaterial("WALL_SIGN"), Material.LEVER, Material.STONE_BUTTON, LegacyUtils.TRAP_DOOR, Material.TRIPWIRE_HOOK, LegacyUtils.WOOD_BUTTON, Material.IRON_TRAPDOOR, }; - } - Material[] typeArr = new Material[types.size()]; - int index = 0; - for (Material type : types){ - typeArr[index] = type; - index++; - } - - wallBlocks = typeArr; - } @EventHandler public void onSignChange(SignChangeEvent event){ if (!event.getLine(0).equalsIgnoreCase(HEADER)){ @@ -172,7 +144,7 @@ private void signRightClick(PlayerInteractEvent event){ } } HashMap numMissingItems = movecraftRepair.getMissingBlocks(repairName); - ArrayDeque locMissingBlocks = movecraftRepair.getMissingBlockLocations(repairName); + ArrayDeque> locMissingBlocks = movecraftRepair.getMissingBlockLocations(repairName); int totalSize = locMissingBlocks.size() + pCraft.getHitBox().size(); if (secondClick){ @@ -185,7 +157,7 @@ private void signRightClick(PlayerInteractEvent event){ ArrayList chests = new ArrayList<>(); for (MovecraftLocation loc : pCraft.getHitBox()) { Block b = pCraft.getW().getBlockAt(loc.getX(), loc.getY(), loc.getZ()); - if ((b.getType() == Material.CHEST) || (b.getType() == Material.TRAPPED_CHEST)) { + if ((b.getType() == Material.CHEST) || (b.getType() == Material.TRAPPED_CHEST) || (b.getType() == Material.BARREL)) { InventoryHolder inventoryHolder = (InventoryHolder) b.getState(); if (inventoryHolder.getInventory().contains(type) && remainingQty > 0) { HashMap foundItems = inventoryHolder.getInventory().all(type); @@ -238,14 +210,12 @@ private void signRightClick(PlayerInteractEvent event){ Movecraft.getInstance().getLogger().info(event.getPlayer().getName() + " has begun a repair with the cost of " + Cost); final LinkedList updateCommands = new LinkedList<>(); final LinkedList updateCommandsFragileBlocks = new LinkedList<>(); - final org.bukkit.util.Vector distToOffset = movecraftRepair.getDistanceFromSignToLowestPoint(clipboard); - final org.bukkit.util.Vector offsetFromSign = new org.bukkit.util.Vector(sign.getLocation().getBlockX() - distToOffset.getBlockX(), sign.getLocation().getBlockY() - distToOffset.getBlockY(), sign.getLocation().getBlockZ() - distToOffset.getBlockZ()); - final org.bukkit.util.Vector distance = movecraftRepair.getDistance(repairName); - Bukkit.broadcastMessage(distToOffset.toString()); while (!locMissingBlocks.isEmpty()){ - Vector cLoc = locMissingBlocks.pollFirst(); - Vector clipBoardLoc = cLoc.add(movecraftRepair.getDistance(repairName)); - MovecraftLocation moveLoc = new MovecraftLocation(cLoc.getBlockX(), cLoc.getBlockY(), cLoc.getBlockZ()); + Pair cLocs = locMissingBlocks.pollFirst(); + assert cLocs != null; + Vector cLoc = cLocs.getLeft(); + Vector clipBoardLoc = cLocs.getRight(); + MovecraftLocation moveLoc = MovecraftLocation.fromVector(cLoc); //To avoid any issues during the repair, keep certain blocks in different linked lists if (Settings.IsLegacy) { BaseBlock baseBlock = RepairUtils.getBlock(clipboard, WorldEditUtils.toWeVector(clipBoardLoc)); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/assault/AssaultTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/assault/AssaultTask.java index 53becbe9a..c6b39d494 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/assault/AssaultTask.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/assault/AssaultTask.java @@ -8,7 +8,6 @@ import com.sk89q.worldguard.protection.regions.ProtectedRegion; import net.countercraft.movecraft.Movecraft; import net.countercraft.movecraft.config.Settings; -import net.countercraft.movecraft.repair.RepairUtils; import net.countercraft.movecraft.sign.RegionDamagedSign; import net.countercraft.movecraft.utils.WorldguardUtils; import org.bukkit.*; @@ -148,7 +147,7 @@ public void run() { w.getBlockAt(beaconX + 2, beaconY + 2, beaconZ + 2).setType(Material.BEACON); w.getBlockAt(beaconX + 2, beaconY + 3, beaconZ + 2).setType(Material.BEDROCK); // finally the sign on the beacon - w.getBlockAt(beaconX + 2, beaconY + 3, beaconZ + 1).setType(Material.WALL_SIGN); + w.getBlockAt(beaconX + 2, beaconY + 3, beaconZ + 1).setType(Settings.is1_14 ? Material.OAK_WALL_SIGN : Material.getMaterial("WALL_SIGN")); Sign s = (Sign) w.getBlockAt(beaconX + 2, beaconY + 3, beaconZ + 1).getState(); s.setLine(0, ChatColor.RED + "REGION DAMAGED!"); s.setLine(1, "Region:" + assault.getRegionName()); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/assault/AssaultUtils.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/assault/AssaultUtils.java index 0d4716c4f..dec470e3d 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/assault/AssaultUtils.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/assault/AssaultUtils.java @@ -1,36 +1,26 @@ package net.countercraft.movecraft.warfare.assault; -import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldguard.bukkit.WorldGuardPlugin; import com.sk89q.worldguard.protection.ApplicableRegionSet; -import com.sk89q.worldguard.protection.flags.DefaultFlag; -import com.sk89q.worldguard.protection.flags.Flag; -import com.sk89q.worldguard.protection.flags.Flags; -import com.sk89q.worldguard.protection.flags.StateFlag; import com.sk89q.worldguard.protection.regions.ProtectedRegion; import net.countercraft.movecraft.Movecraft; -import net.countercraft.movecraft.MovecraftRepair; import net.countercraft.movecraft.config.Settings; -import net.countercraft.movecraft.localisation.I18nSupport; import net.countercraft.movecraft.utils.LegacyUtils; -import net.countercraft.movecraft.utils.WorldEditUtils; import net.countercraft.movecraft.utils.WorldguardUtils; -import net.countercraft.movecraft.utils.weVectorUtils; import org.bukkit.*; import org.bukkit.block.Block; import org.bukkit.block.BlockFace; import org.bukkit.entity.Player; import org.bukkit.event.entity.EntityExplodeEvent; import org.bukkit.scheduler.BukkitRunnable; -import org.bukkit.util.Vector; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; import java.util.*; public class AssaultUtils { private static long lastDamagesUpdate = 0; - final static Material[] fragileBlocks = Settings.IsLegacy ? new Material[]{LegacyUtils.BED_BLOCK, LegacyUtils.PISTON_EXTENSION, Material.TORCH, Material.REDSTONE_WIRE, LegacyUtils.SIGN_POST, LegacyUtils.WOOD_DOOR, Material.LADDER, Material.WALL_SIGN, Material.LEVER, LegacyUtils.STONE_PLATE, LegacyUtils.IRON_DOOR_BLOCK, LegacyUtils.WOOD_PLATE, LegacyUtils.REDSTONE_TORCH_OFF, LegacyUtils.REDSTONE_TORCH_ON, Material.STONE_BUTTON, LegacyUtils.DIODE_BLOCK_OFF, LegacyUtils.DIODE_BLOCK_ON, LegacyUtils.TRAP_DOOR, Material.TRIPWIRE_HOOK, + final static Material[] fragileBlocks = Settings.IsLegacy ? new Material[]{LegacyUtils.BED_BLOCK, LegacyUtils.PISTON_EXTENSION, Material.TORCH, Material.REDSTONE_WIRE, LegacyUtils.SIGN_POST, LegacyUtils.WOOD_DOOR, Material.LADDER, Material.getMaterial("WALL_SIGN"), + Material.BIRCH_SIGN,Material.OAK_SIGN,Material.DARK_OAK_SIGN,Material.JUNGLE_SIGN,Material.SPRUCE_SIGN,Material.ACACIA_SIGN,Material.BIRCH_WALL_SIGN + ,Material.OAK_WALL_SIGN,Material.DARK_OAK_WALL_SIGN, Material.JUNGLE_WALL_SIGN, Material.SPRUCE_WALL_SIGN, Material.ACACIA_WALL_SIGN, Material.LEVER, LegacyUtils.STONE_PLATE, LegacyUtils.IRON_DOOR_BLOCK, LegacyUtils.WOOD_PLATE, LegacyUtils.REDSTONE_TORCH_OFF, LegacyUtils.REDSTONE_TORCH_ON, Material.STONE_BUTTON, LegacyUtils.DIODE_BLOCK_OFF, LegacyUtils.DIODE_BLOCK_ON, LegacyUtils.TRAP_DOOR, Material.TRIPWIRE_HOOK, Material.TRIPWIRE, LegacyUtils.WOOD_BUTTON, LegacyUtils.GOLD_PLATE, LegacyUtils.IRON_PLATE, LegacyUtils.REDSTONE_COMPARATOR_OFF, LegacyUtils.REDSTONE_COMPARATOR_ON, Material.DAYLIGHT_DETECTOR, LegacyUtils.CARPET, LegacyUtils.DAYLIGHT_DETECTOR_INVERTED, Material.SPRUCE_DOOR, Material.BIRCH_DOOR, Material.JUNGLE_DOOR, Material.ACACIA_DOOR, Material.DARK_OAK_DOOR} : new Material[] diff --git a/modules/api/src/main/java/net/countercraft/movecraft/MovecraftLocation.java b/modules/api/src/main/java/net/countercraft/movecraft/MovecraftLocation.java index cda847a52..f3add2bc9 100644 --- a/modules/api/src/main/java/net/countercraft/movecraft/MovecraftLocation.java +++ b/modules/api/src/main/java/net/countercraft/movecraft/MovecraftLocation.java @@ -19,6 +19,7 @@ import org.bukkit.Location; import org.bukkit.World; +import org.bukkit.util.Vector; /** * Represents a Block aligned coordinate triplet. @@ -87,6 +88,9 @@ public Location toBukkit(World world){ public static Location toBukkit(World world, MovecraftLocation location){ return new Location(world, location.x, location.y, location.z); } + public static MovecraftLocation fromVector(Vector vector){ + return new MovecraftLocation(vector.getBlockX(),vector.getBlockY(),vector.getBlockZ()); + } @Override public String toString(){ diff --git a/modules/api/src/main/java/net/countercraft/movecraft/MovecraftRepair.java b/modules/api/src/main/java/net/countercraft/movecraft/MovecraftRepair.java index 830db6cdf..d9ac1e545 100644 --- a/modules/api/src/main/java/net/countercraft/movecraft/MovecraftRepair.java +++ b/modules/api/src/main/java/net/countercraft/movecraft/MovecraftRepair.java @@ -1,33 +1,28 @@ package net.countercraft.movecraft; -import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard; import com.sk89q.worldedit.extent.clipboard.Clipboard; import com.sk89q.worldguard.protection.regions.ProtectedRegion; import net.countercraft.movecraft.craft.Craft; +import net.countercraft.movecraft.utils.Pair; import org.bukkit.Material; import org.bukkit.World; import org.bukkit.block.Sign; -import org.bukkit.entity.Player; import org.bukkit.plugin.Plugin; import org.bukkit.util.Vector; -import java.io.File; import java.util.ArrayDeque; import java.util.HashMap; -import java.util.HashSet; -import java.util.LinkedList; public abstract class MovecraftRepair { public abstract boolean saveCraftRepairState(Craft craft, Sign sign, Plugin plugin, String repairStateName); public abstract boolean saveRegionRepairState(Plugin plugin, World world, ProtectedRegion region); - public abstract boolean repairRegion(World world, String regionName); public abstract Clipboard loadCraftRepairStateClipboard(Plugin plugin, Craft craft, Sign sign, String repairStateName, World bukkitWorld); public abstract Clipboard loadRegionRepairStateClipboard(Plugin plugin, String repairStateName, World bukkitWorld); public abstract HashMap getMissingBlocks(String repairName); - public abstract ArrayDeque getMissingBlockLocations(String repairName); + public abstract ArrayDeque> getMissingBlockLocations(String repairName); public abstract long getNumDiffBlocks(String repairName); - public abstract org.bukkit.util.Vector getDistanceFromSignToLowestPoint(Clipboard clipboard); public abstract org.bukkit.util.Vector getDistance(String repairName); + public abstract org.bukkit.util.Vector getOffset(String repairName); diff --git a/modules/api/src/main/java/net/countercraft/movecraft/utils/MathUtils.java b/modules/api/src/main/java/net/countercraft/movecraft/utils/MathUtils.java index d294e7add..396975c54 100644 --- a/modules/api/src/main/java/net/countercraft/movecraft/utils/MathUtils.java +++ b/modules/api/src/main/java/net/countercraft/movecraft/utils/MathUtils.java @@ -106,6 +106,8 @@ public static MovecraftLocation bukkit2MovecraftLoc(@NotNull final Location bukk return new MovecraftLocation(bukkitLocation.getBlockX(), bukkitLocation.getBlockY(), bukkitLocation.getBlockZ()); } + + /** * Rotates a MovecraftLocation towards a supplied Rotation. * The resulting MovecraftRotation is based on a center of (0,0,0). diff --git a/modules/api/src/main/java/net/countercraft/movecraft/utils/Pair.java b/modules/api/src/main/java/net/countercraft/movecraft/utils/Pair.java index 561b4403e..c164cdd9e 100644 --- a/modules/api/src/main/java/net/countercraft/movecraft/utils/Pair.java +++ b/modules/api/src/main/java/net/countercraft/movecraft/utils/Pair.java @@ -1,12 +1,10 @@ package net.countercraft.movecraft.utils; -import org.jetbrains.annotations.NotNull; - import java.io.Serializable; import java.util.Map; import java.util.UUID; -public final class Pair implements Serializable, Map.Entry { +public final class Pair implements Serializable, Map.Entry{ private final UUID id = UUID.randomUUID(); private final L left; private final R right; @@ -46,13 +44,11 @@ public boolean equals(Object obj) { return false; } Pair pair = (Pair) obj; - return getLeft().equals(pair.getLeft())&&getRight().equals(pair.getRight()); + return getLeft().equals(pair.getLeft()) && getRight().equals(pair.getRight()); } @Override public int hashCode() { return id.hashCode(); } - - } diff --git a/modules/worldedit/WE6Utils/src/main/java/net/countercraft/movecraft/compat/we6/IMovecraftRepair.java b/modules/worldedit/WE6Utils/src/main/java/net/countercraft/movecraft/compat/we6/IMovecraftRepair.java index 5461797c5..ea7733cb6 100644 --- a/modules/worldedit/WE6Utils/src/main/java/net/countercraft/movecraft/compat/we6/IMovecraftRepair.java +++ b/modules/worldedit/WE6Utils/src/main/java/net/countercraft/movecraft/compat/we6/IMovecraftRepair.java @@ -7,7 +7,6 @@ import com.sk89q.worldedit.WorldEdit; import com.sk89q.worldedit.blocks.BaseBlock; import com.sk89q.worldedit.bukkit.BukkitWorld; -import com.sk89q.worldedit.bukkit.adapter.BukkitImplAdapter; import com.sk89q.worldedit.extent.Extent; import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard; import com.sk89q.worldedit.extent.clipboard.Clipboard; @@ -28,6 +27,7 @@ import net.countercraft.movecraft.config.Settings; import net.countercraft.movecraft.craft.Craft; import net.countercraft.movecraft.utils.HashHitBox; +import net.countercraft.movecraft.utils.Pair; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.Material; @@ -40,10 +40,13 @@ import org.bukkit.util.Vector; import java.io.*; -import java.util.*; +import java.util.ArrayDeque; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Set; public class IMovecraftRepair extends MovecraftRepair { - private HashMap> locMissingBlocksMap = new HashMap<>(); + private HashMap>> locMissingBlocksMap = new HashMap<>(); private HashMap numDiffBlocksMap = new HashMap<>(); private HashMap> missingBlocksMap = new HashMap<>(); private final HashMap distanceMap = new HashMap<>(); @@ -142,10 +145,7 @@ public boolean saveRegionRepairState(Plugin plugin, World world, ProtectedRegion } } - @Override - public boolean repairRegion(World world, String s) { - return false; - } + @Override public Clipboard loadCraftRepairStateClipboard(Plugin plugin,Craft craft, Sign sign, String repairStateFile, World world) { @@ -165,7 +165,7 @@ public Clipboard loadCraftRepairStateClipboard(Plugin plugin,Craft craft, Sign s if (clipboard != null){ long numDiffBlocks = 0; HashMap missingBlocks = new HashMap<>(); - ArrayDeque locMissingBlocks = new ArrayDeque<>(); + ArrayDeque> locMissingBlocks = new ArrayDeque<>(); Vector distance = new Vector(sign.getX() - hitBox.getMinX(), sign.getY() - hitBox.getMinY(),sign.getZ() - hitBox.getMinZ()); if (distanceMap.containsKey(repairStateFile)) { distanceMap.replace(repairStateFile,distance); @@ -319,7 +319,7 @@ public Clipboard loadCraftRepairStateClipboard(Plugin plugin,Craft craft, Sign s num += qtyToConsume; missingBlocks.put(Material.getMaterial(itemToConsume), num); } - locMissingBlocks.add(new Vector(x,y,z)); + locMissingBlocks.add(new Pair<>(new org.bukkit.util.Vector(x,y,z),null)); } } if (bukkitBlock.getType() == Material.DISPENSER && block.getType() == 23){ @@ -397,7 +397,7 @@ public Clipboard loadCraftRepairStateClipboard(Plugin plugin,Craft craft, Sign s } if (needReplace){ numDiffBlocks++; - locMissingBlocks.push(new org.bukkit.util.Vector(x,y,z)); + locMissingBlocks.addLast(new Pair<>(new org.bukkit.util.Vector(x,y,z),null)); } } } @@ -434,7 +434,7 @@ public HashMap getMissingBlocks(String repairName) { } @Override - public ArrayDeque getMissingBlockLocations(String repairName) { + public ArrayDeque> getMissingBlockLocations(String repairName) { return locMissingBlocksMap.get(repairName); } @@ -443,43 +443,16 @@ public long getNumDiffBlocks(String s) { return numDiffBlocksMap.get(s); } - @Override - public Vector getDistanceFromSignToLowestPoint(Clipboard clipboard) { - return new Vector(clipboard.getOrigin().getBlockX() - clipboard.getMinimumPoint().getBlockX(),clipboard.getOrigin().getBlockY() - clipboard.getMinimumPoint().getBlockY(),clipboard.getOrigin().getBlockZ() - clipboard.getMinimumPoint().getBlockZ()); - /*for (int x = clipboard.getMinimumPoint().getBlockX(); x <= clipboard.getMaximumPoint().getBlockX(); x++) { - for (int y = clipboard.getMinimumPoint().getBlockY(); y <= clipboard.getMaximumPoint().getBlockY(); y++) { - for (int z = clipboard.getMinimumPoint().getBlockZ(); z <= clipboard.getMaximumPoint().getBlockZ(); z++) { - com.sk89q.worldedit.Vector pos = new com.sk89q.worldedit.Vector(x,y,z); - BaseBlock block = clipboard.getBlock(pos); - if (block.getType() == 68 || block.getType() == 63) { - String firstLine = block.getNbtData().getString("Text1"); - firstLine = firstLine.substring(2); - if (firstLine.substring(0, 5).equalsIgnoreCase("extra")){ - firstLine = firstLine.substring(17); - String[] parts = firstLine.split("\""); - firstLine = parts[0]; - } - String secondLine = block.getNbtData().getString("Text2"); - secondLine = secondLine.substring(2); - if (secondLine.substring(0, 5).equalsIgnoreCase("extra")){ - secondLine = secondLine.substring(17); - String[] parts = secondLine.split("\""); - secondLine = parts[0]; - } - if (firstLine.equalsIgnoreCase("Repair:")&& secondLine.contains(repairName)){ - returnDistance = new org.bukkit.util.Vector(x - clipboard.getMinimumPoint().getBlockX(), y - clipboard.getMinimumPoint().getBlockY(), z - clipboard.getMinimumPoint().getBlockZ()); - } - } - } - } - }*/ - } @Override public Vector getDistance(String repairName) { return distanceMap.get(repairName); } + @Override + public Vector getOffset(String repairName) { + return null; + } private Set baseBlocksFromCraft(Craft craft){ diff --git a/modules/worldedit/WE7Utils/src/main/java/net/countercraft/movecraft/compat/we7/IMovecraftRepair.java b/modules/worldedit/WE7Utils/src/main/java/net/countercraft/movecraft/compat/we7/IMovecraftRepair.java index 982949cdf..a1a86e5e9 100644 --- a/modules/worldedit/WE7Utils/src/main/java/net/countercraft/movecraft/compat/we7/IMovecraftRepair.java +++ b/modules/worldedit/WE7Utils/src/main/java/net/countercraft/movecraft/compat/we7/IMovecraftRepair.java @@ -12,7 +12,6 @@ import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard; import com.sk89q.worldedit.extent.clipboard.Clipboard; import com.sk89q.worldedit.extent.clipboard.io.*; -import com.sk89q.worldedit.function.mask.BlockMask; import com.sk89q.worldedit.function.mask.BlockTypeMask; import com.sk89q.worldedit.function.mask.ExistingBlockMask; import com.sk89q.worldedit.function.operation.ForwardExtentCopy; @@ -25,7 +24,6 @@ import com.sk89q.worldedit.registry.state.Property; import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldedit.world.block.BlockType; -import com.sk89q.worldedit.world.registry.WorldData; import com.sk89q.worldguard.protection.regions.ProtectedCuboidRegion; import com.sk89q.worldguard.protection.regions.ProtectedPolygonalRegion; import com.sk89q.worldguard.protection.regions.ProtectedRegion; @@ -33,24 +31,27 @@ import net.countercraft.movecraft.config.Settings; import net.countercraft.movecraft.craft.Craft; import net.countercraft.movecraft.utils.HashHitBox; -import org.bukkit.Bukkit; +import net.countercraft.movecraft.utils.Pair; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.World; import org.bukkit.block.Block; -import org.bukkit.block.Sign; import org.bukkit.block.Dispenser; +import org.bukkit.block.Sign; import org.bukkit.block.data.type.Slab; import org.bukkit.inventory.ItemStack; import org.bukkit.plugin.Plugin; import org.bukkit.util.Vector; import java.io.*; -import java.util.*; -import java.util.logging.Logger; +import java.util.ArrayDeque; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Set; public class IMovecraftRepair extends MovecraftRepair { - private final HashMap> locMissingBlocksMap = new HashMap<>(); + private final HashMap>> locMissingBlocksMap = new HashMap<>(); + private final HashMap offsetMap = new HashMap<>(); private final HashMap numDiffBlocksMap = new HashMap<>(); private final HashMap> missingBlocksMap = new HashMap<>(); private final HashMap distanceMap = new HashMap<>(); @@ -148,19 +149,12 @@ public boolean saveRegionRepairState(Plugin plugin, World world, ProtectedRegion } } - - @Override - public boolean repairRegion(World world, String s) { - return false; - } - @Override public Clipboard loadCraftRepairStateClipboard(Plugin plugin,Craft craft, Sign sign, String s, World world) { File dataDirectory = new File(plugin.getDataFolder(), "CraftRepairStates"); File file = new File(dataDirectory, s + ".schematic"); // The schematic file Clipboard clipboard = null; ClipboardFormat format = ClipboardFormats.findByFile(file); - HashHitBox hitBox = craft.getHitBox(); try { InputStream input = new FileInputStream(file); ClipboardReader reader = format.getReader(input); @@ -174,25 +168,34 @@ public Clipboard loadCraftRepairStateClipboard(Plugin plugin,Craft craft, Sign s if (clipboard != null){ long numDiffBlocks = 0; HashMap missingBlocks = new HashMap<>(); - ArrayDeque locMissingBlocks = new ArrayDeque<>(); - BlockVector3 length = clipboard.getMaximumPoint().subtract(clipboard.getMinimumPoint()); + ArrayDeque> locMissingBlocks = new ArrayDeque<>(); + HashMap materials = new HashMap<>(); + BlockVector3 minPoint = clipboard.getMinimumPoint(); + BlockVector3 length = clipboard.getDimensions(); BlockVector3 distance = clipboard.getOrigin().subtract(clipboard.getMinimumPoint()); + Vector offset = new Vector(sign.getX()-distance.getBlockX(),sign.getY()-distance.getBlockY(),sign.getZ()-distance.getBlockZ()); + Vector difference = new Vector(minPoint.getBlockX() - offset.getBlockX(),minPoint.getBlockY() - offset.getBlockY(), minPoint.getBlockZ() - offset.getBlockZ()); + if (offsetMap.containsKey(s)){ + offsetMap.replace(s,offset); + } else { + offsetMap.put(s,offset); + } if (distanceMap.containsKey(s)) { - distanceMap.replace(s,offset); + distanceMap.replace(s,difference); } else { - distanceMap.put(s,offset); + distanceMap.put(s,difference); } for (int y = 0; y <= length.getBlockY(); y++) { for (int z = 0; z <= length.getBlockZ(); z++) { for (int x = 0; x <= length.getBlockX(); x++) { BlockVector3 position = BlockVector3.at(x+clipboard.getMinimumPoint().getBlockX(),y+clipboard.getMinimumPoint().getBlockY(),z+clipboard.getMinimumPoint().getBlockZ()); - int cx = x - distance.getBlockX(); - int cy = y - distance.getBlockY(); - int cz = z - distance.getBlockZ(); + int cx = offset.getBlockX() + x; + int cy = offset.getBlockY() + y; + int cz = offset.getBlockZ() + z; BaseBlock block = clipboard.getFullBlock(position); Material type = BukkitAdapter.adapt(block.getBlockType()); - Location loc = new Location(sign.getWorld(),offset.getBlockX()+x,offset.getBlockY()+y,offset.getBlockZ()+z); + Location loc = new Location(sign.getWorld(),cx,cy,cz); Block bukkitBlock = sign.getWorld().getBlockAt(loc); boolean isImportant = true; @@ -202,7 +205,6 @@ public Clipboard loadCraftRepairStateClipboard(Plugin plugin,Craft craft, Sign s boolean blockMissing = isImportant && type != bukkitBlock.getType(); //Check if single slabs are at locations where double slabs should be located and vice versa if (type.name().endsWith("_SLAB")){ - plugin.getLogger().info(type.name()); for (Property property : block.getStates().keySet()){ if (!(property instanceof EnumProperty)){ continue; @@ -298,7 +300,7 @@ public Clipboard loadCraftRepairStateClipboard(Plugin plugin,Craft craft, Sign s } } } - locMissingBlocks.addLast(new Vector(cx,cy,cz)); + locMissingBlocks.addLast(new Pair<>(new Vector(cx,cy,cz),new Vector(position.getBlockX(),position.getBlockY(),position.getBlockZ()))); numDiffBlocks++; if (missingBlocks.containsKey(typeToConsume)){ double count = missingBlocks.get(typeToConsume); @@ -381,8 +383,9 @@ public Clipboard loadCraftRepairStateClipboard(Plugin plugin,Craft craft, Sign s needsReplace = true; } if (needsReplace){ - locMissingBlocks.addLast(new Vector(cx,cy,cz)); + locMissingBlocks.addLast(new Pair<>(new Vector(cx,cy,cz),new Vector(position.getBlockX(),position.getBlockY(),position.getBlockZ()))); numDiffBlocks++; + } } @@ -391,6 +394,7 @@ public Clipboard loadCraftRepairStateClipboard(Plugin plugin,Craft craft, Sign s } locMissingBlocksMap.put(s, locMissingBlocks); missingBlocksMap.put(s, missingBlocks); + numDiffBlocksMap.put(s, numDiffBlocks); } return clipboard; @@ -421,7 +425,7 @@ public HashMap getMissingBlocks(String s) { } @Override - public ArrayDeque getMissingBlockLocations(String s) { + public ArrayDeque> getMissingBlockLocations(String s) { return locMissingBlocksMap.get(s); } @@ -431,44 +435,14 @@ public long getNumDiffBlocks(String s) { return numDiffBlocksMap.get(s); } - @Override - public Vector getDistanceFromSignToLowestPoint(Clipboard clipboard) { - return new Vector(clipboard.getOrigin().getBlockX() - clipboard.getMinimumPoint().getBlockX(),clipboard.getOrigin().getBlockY() - clipboard.getMinimumPoint().getBlockY(),clipboard.getOrigin().getBlockZ() - clipboard.getMinimumPoint().getBlockZ()); - /*for (int x = clipboard.getMinimumPoint().getBlockX(); x <= clipboard.getMaximumPoint().getBlockX(); x++) { - for (int y = clipboard.getMinimumPoint().getBlockY(); y <= clipboard.getMaximumPoint().getBlockY(); y++) { - for (int z = clipboard.getMinimumPoint().getBlockZ(); z <= clipboard.getMaximumPoint().getBlockZ(); z++) { - BlockVector3 pos = BlockVector3.at(x,y,z); - BaseBlock block = clipboard.getFullBlock(pos); - if (block.getBlockType().getId().equals("minecraft:sign")||block.getBlockType().getId().equals("minecraft:wall_sign")) { - Logger log = Bukkit.getLogger(); - String firstLine = block.getNbtData().getString("Text1"); - firstLine = firstLine.substring(2); - if (firstLine.startsWith("extra")) { - firstLine = firstLine.substring(17); - firstLine = firstLine.replace("\"}],\"text\":\"\"}", ""); - } - String secondLine = block.getNbtData().getString("Text2"); - secondLine = secondLine.substring(2); - if (secondLine.startsWith("extra")) { - secondLine = secondLine.substring(17); - secondLine = secondLine.replace("\"}],\"text\":\"\"}", ""); - } - if (firstLine.equalsIgnoreCase("Repair:") && s.endsWith(secondLine)) { - returnDistance = new Vector(x - clipboard.getMinimumPoint().getBlockX(), y - clipboard.getMinimumPoint().getBlockY(), z - clipboard.getMinimumPoint().getBlockZ()); - break; - } - } - } - if (returnDistance != null) break; - } - if (returnDistance != null) break; - } - return returnDistance;*/ - } - @Override public Vector getDistance(String repairName) { return distanceMap.get(repairName); } + + @Override + public Vector getOffset(String repairName) { + return offsetMap.get(repairName); + } } diff --git a/pom.xml b/pom.xml index 754a7944c..8e7eb5ac5 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ org.spigotmc spigot-api - 1.14-R0.1-SNAPSHOT + 1.14.2-R0.1-SNAPSHOT Movecraft Parent Pom From 3ff059261b48c027e47d22d6f2fc3e35d6385c2e Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Sun, 9 Jun 2019 15:17:23 +0200 Subject: [PATCH 019/304] Reverted api-version to 1.13 and removing redundant classes --- .../update/WorldEdit7UpdateCommand.java | 50 +- .../movecraft/utils/ArrayUtils.java | 21 - .../movecraft/utils/BlockUtils.java | 857 ------------------ .../movecraft/utils/BoundingBoxUtils.java | 82 -- .../Movecraft/src/main/resources/plugin.yml | 2 +- .../countercraft/movecraft/utils/Pair.java | 28 +- 6 files changed, 70 insertions(+), 970 deletions(-) delete mode 100644 modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/ArrayUtils.java delete mode 100644 modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/BlockUtils.java delete mode 100644 modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/BoundingBoxUtils.java diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/WorldEdit7UpdateCommand.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/WorldEdit7UpdateCommand.java index a69b4486b..12e5812a1 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/WorldEdit7UpdateCommand.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/WorldEdit7UpdateCommand.java @@ -4,6 +4,7 @@ import com.sk89q.jnbt.ListTag; import com.sk89q.jnbt.Tag; import com.sk89q.worldedit.bukkit.BukkitAdapter; +import com.sk89q.worldedit.world.block.BaseBlock; import net.countercraft.movecraft.MovecraftLocation; import net.countercraft.movecraft.config.Settings; import org.bukkit.Bukkit; @@ -16,13 +17,15 @@ import org.bukkit.block.data.BlockData; import org.bukkit.inventory.ItemStack; +import java.util.Objects; + public class WorldEdit7UpdateCommand extends UpdateCommand { - private final com.sk89q.worldedit.world.block.BaseBlock worldEdit7BaseBlock; + private final BaseBlock baseBlock; private World world; private MovecraftLocation location; private Material type; - public WorldEdit7UpdateCommand(com.sk89q.worldedit.world.block.BaseBlock worldEditBlockState, World world, MovecraftLocation location, Material type){ - this.worldEdit7BaseBlock = worldEditBlockState; + public WorldEdit7UpdateCommand(BaseBlock baseBlock, World world, MovecraftLocation location, Material type){ + this.baseBlock = baseBlock; this.world = world; this.location = location; this.type = type; @@ -31,15 +34,15 @@ public WorldEdit7UpdateCommand(com.sk89q.worldedit.world.block.BaseBlock worldEd public void doUpdate() { Block block = world.getBlockAt(location.getX(), location.getY(), location.getZ()); block.setType(type); - assert worldEdit7BaseBlock != null; - BlockData bData = BukkitAdapter.adapt(worldEdit7BaseBlock); + assert baseBlock != null; + BlockData bData = BukkitAdapter.adapt(baseBlock); block.setBlockData(bData); if (Settings.Debug){ Bukkit.broadcastMessage(String.format("Material: %s, Location: %s",type.name().toLowerCase().replace("_", " "),location.toString())); } - Material weType = BukkitAdapter.adapt(worldEdit7BaseBlock.getBlockType()); + Material weType = BukkitAdapter.adapt(baseBlock.getBlockType()); if (type == Material.DISPENSER){ - Tag t = worldEdit7BaseBlock.getNbtData().getValue().get("Items"); + Tag t = baseBlock.getNbtData().getValue().get("Items"); ListTag lt = null; if (t instanceof ListTag) { lt = (ListTag) t; @@ -96,7 +99,7 @@ public void doUpdate() { BlockState state = block.getState(); if (state instanceof Sign) { Sign s = (Sign) state; - CompoundTag nbtData = worldEdit7BaseBlock.getNbtData(); + CompoundTag nbtData = baseBlock.getNbtData(); //first line String firstLine = nbtData.getString("Text1"); firstLine = firstLine.substring(2); @@ -154,4 +157,35 @@ public void doUpdate() { } } } + + public BaseBlock getBaseBlock() { + return baseBlock; + } + + public MovecraftLocation getLocation() { + return location; + } + + public World getWorld() { + return world; + } + + public Material getType() { + return type; + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof WorldEdit7UpdateCommand)){ + return false; + } + WorldEdit7UpdateCommand weUp = (WorldEdit7UpdateCommand) obj; + + return weUp.getBaseBlock() == getBaseBlock() && weUp.getLocation() == getLocation() && weUp.getWorld() == getWorld() && weUp.getType() == getType(); + } + + @Override + public int hashCode() { + return Objects.hash(baseBlock, location, world, type); + } } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/ArrayUtils.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/ArrayUtils.java deleted file mode 100644 index 9fa4a2d2a..000000000 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/ArrayUtils.java +++ /dev/null @@ -1,21 +0,0 @@ -package net.countercraft.movecraft.utils; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; - -public class ArrayUtils { - public static List subtractAsList(T[] array1, T[] array2){ - List list = new ArrayList<>(Arrays.asList(array1)); - list.removeAll(Arrays.asList(array2)); - return list; - } - - public static T[] subtract(T[] array1, T[] array2){ - List list = new ArrayList<>(Arrays.asList(array1)); - list.removeAll(Arrays.asList(array2)); - return list.toArray(array1.clone()); - } - - -} diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/BlockUtils.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/BlockUtils.java deleted file mode 100644 index 7fede7848..000000000 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/BlockUtils.java +++ /dev/null @@ -1,857 +0,0 @@ -/* - * This file is part of Movecraft. - * - * Movecraft is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Movecraft is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Movecraft. If not, see . - */ - -package net.countercraft.movecraft.utils; - -import net.countercraft.movecraft.Rotation; - -import java.util.Arrays; - -public class BlockUtils { - private static final int[] dataBlocks = new int[]{2, 3, 5, 6, 8, 9, 10, 11, 17, 18, 23, 24, 25, 26, 27, 28, 29, 31, 33, 34, 35, 43, 44, 46, 50, 51, 52, 53, 55, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 75, 76, 77, 78, 81, 83, 84, 86, 91, 92, 93, 94, 96, 98, 99, 100, 104, 105, 106, 107, 108, 109, 114, 115, 116, 117, 118, 120, 125, 126, 127, 128, 130, 131, 132, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146, 147, 148, 149, 150, 151, 154, 155, 156, 157, 158, 159, 170, 171}; - - private static final int[] rotationBlocks = new int[]{17, 50, 54, 75, 76, 26, 29, 33, 34, 53, 67, 108, 109, 114, 128, 134, 135, 136, 156, 63, 64, 71, 66, 27, 28, 65, 68, 61, 23, 69, 77, 143, 93, 94, 96, 107, 120, 131, 144, 145, 62, 99, 100, 106, 127, 130, 145, 149, 150, 154, 157, 158, 170, 86, 91, 163, 164, 203}; - - static { - Arrays.sort(dataBlocks); - Arrays.sort(rotationBlocks); - } - - public static boolean blockHasNoData(int id) { - return Arrays.binarySearch(dataBlocks, id) == -1; - } - - public static boolean blockRequiresRotation(int id) { - return Arrays.binarySearch(rotationBlocks, id) != -1; - } - - public static boolean arrayContainsOverlap(Object[] array1, Object[] array2) { - for (Object o : array1) { - - for (Object o1 : array2) { - if (o.equals(o1)) { - return true; - } - } - - } - - return false; - } - - public static byte rotate(byte data, int typeID, Rotation rotation) { - switch (typeID) { - case 17: - case 170: - boolean side1 = ((data & 0x4) == 0x4); - boolean side2 = ((data & 0x8) == 0x8); - - if (side1 || side2) { - data = (byte) (data ^ 0xC); - } - return data; - - case 50: - case 75: - case 76: - boolean nonDirectional = data == 0x5 || data == 0x6; - - if (!nonDirectional) { - switch (data) { - case 0x1: - if (rotation == Rotation.CLOCKWISE) { - data = 0x3; - } else { - data = 0x4; - } - break; - - case 0x2: - if (rotation == Rotation.CLOCKWISE) { - data = 0x4; - } else { - data = 0x3; - } - break; - - case 0x3: - if (rotation == Rotation.CLOCKWISE) { - data = 0x02; - } else { - data = 0x1; - } - break; - - case 0x4: - if (rotation == Rotation.CLOCKWISE) { - data = 0x1; - } else { - data = 0x2; - } - break; - } - } - - return data; - - case 26: - case 127: - case 149: - case 150: - byte direction = (byte) (data & 0x3); - - byte constant = 1; - - if (rotation == Rotation.ANTICLOCKWISE) { - constant = -1; - } - - direction = (byte) (MathUtils.positiveMod((direction + constant) % 4, 4)); - data = (byte) ((data & 0xC) | direction); - - return data; - - case 29: - case 33: - case 34: - direction = (byte) (data & 0x7); - - nonDirectional = direction == 0x0 || direction == 0x1 || direction == 0x6; - - if (!nonDirectional) { - switch (direction) { - case 0x2: - // North - if (rotation == Rotation.CLOCKWISE) { - direction = 0x5; - } else { - direction = 0x4; - } - break; - - case 0x3: - // South - if (rotation == Rotation.CLOCKWISE) { - direction = 0x4; - } else { - direction = 0x5; - } - break; - - case 0x4: - // West - if (rotation == Rotation.CLOCKWISE) { - direction = 0x2; - } else { - direction = 0x3; - } - break; - - case 0x5: - //East - if (rotation == Rotation.CLOCKWISE) { - direction = 0x3; - } else { - direction = 0x2; - } - break; - } - - data = (byte) ((data & 0x8) | direction); - } - - return data; - - case 53: - case 67: - case 108: - case 109: - case 114: - case 128: - case 134: - case 135: - case 136: - case 156: - case 163: - case 164: - case 203: - - direction = (byte) (data & 0x3); - - - switch (direction) { - case 0x0: - // East - if (rotation == Rotation.CLOCKWISE) { - direction = 0x2; - } else { - direction = 0x3; - } - break; - - case 0x1: - // West - if (rotation == Rotation.CLOCKWISE) { - direction = 0x3; - } else { - direction = 0x2; - } - break; - - case 0x2: - // South - if (rotation == Rotation.CLOCKWISE) { - direction = 0x1; - } else { - direction = 0x0; - } - break; - - case 0x3: - // North - if (rotation == Rotation.CLOCKWISE) { - direction = 0x0; - } else { - direction = 0x1; - } - break; - } - data = (byte) ((data & 0x4) | direction); - return data; - - case 63: - - constant = 4; - - if (rotation == Rotation.ANTICLOCKWISE) { - constant = -4; - } - - data = (byte) (MathUtils.positiveMod((data + constant) % 16, 16)); - - return data; - - case 64: - case 71: - case 193: - case 194: - case 195: - case 196: - case 197: - boolean isRealDoor = (data & 0x8) == 0; - - if (isRealDoor) { - direction = (byte) (data & 0x3); - int newDirection; - if (rotation == Rotation.CLOCKWISE) - newDirection = direction + 1; - else - newDirection = direction - 1; - if (newDirection == 4) - newDirection = 0; - if (newDirection == -1) - newDirection = 3; - - data = (byte) ((data & 0xC) | newDirection); - } - - return data; - - case 66: - direction = (byte) (data & 0x5); - boolean flat = direction == 0x0 || direction == 0x1; - - if (flat) { - - constant = 1; - - if (rotation == Rotation.ANTICLOCKWISE) { - constant = -1; - } - - direction = (byte) (MathUtils.positiveMod((direction + constant) % 2, 2)); - - data = direction; - - } else { - - if (data >= 0x6) { - // Is a corner piece - constant = 1; - - if (rotation == Rotation.ANTICLOCKWISE) { - constant = -1; - } - - direction = (byte) (MathUtils.positiveMod(((data >> 4) + constant) % 4, 4)); - - data = (byte) (direction << 4); - - } else { - // Is a rising piece - switch (direction) { - case 0x2: - // East - if (rotation == Rotation.CLOCKWISE) { - direction = 0x4; - } else { - direction = 0x5; - } - break; - - case 0x3: - // West - if (rotation == Rotation.CLOCKWISE) { - direction = 0x5; - } else { - direction = 0x4; - } - break; - - case 0x4: - // South - if (rotation == Rotation.CLOCKWISE) { - direction = 0x3; - } else { - direction = 0x2; - } - break; - - case 0x5: - // North - if (rotation == Rotation.CLOCKWISE) { - direction = 0x2; - } else { - direction = 0x3; - } - break; - } - - data = direction; - } - - } - - return data; - - - case 27: - case 28: - case 157: - direction = (byte) (data & 0x5); - flat = direction == 0x0 || direction == 0x1; - - if (flat) { - - constant = 1; - - if (rotation == Rotation.ANTICLOCKWISE) { - constant = -1; - } - - direction = (byte) (MathUtils.positiveMod((direction + constant) % 2, 2)); - - data = direction; - - } else { - - // Is a rising piece - switch (direction) { - case 0x2: - // East - if (rotation == Rotation.CLOCKWISE) { - direction = 0x4; - } else { - direction = 0x5; - } - break; - - case 0x3: - // West - if (rotation == Rotation.CLOCKWISE) { - direction = 0x5; - } else { - direction = 0x4; - } - break; - - case 0x4: - // South - if (rotation == Rotation.CLOCKWISE) { - direction = 0x3; - } else { - direction = 0x2; - } - break; - - case 0x5: - // North - if (rotation == Rotation.CLOCKWISE) { - direction = 0x2; - } else { - direction = 0x3; - } - break; - } - - data = direction; - - - } - - return data; - - case 65: - case 68: - case 61: - case 62: - case 23: - case 130: - case 154: - case 158: - if (data == 0x0 || data == 0x1) { - return data; - } - - direction = (byte) (data & 0x7); - switch (direction) { - case 0x5: - // East - if (rotation == Rotation.CLOCKWISE) { - direction = 0x3; - } else { - direction = 0x2; - } - break; - - case 0x4: - // West - if (rotation == Rotation.CLOCKWISE) { - direction = 0x2; - } else { - direction = 0x3; - } - break; - - case 0x3: - // South - if (rotation == Rotation.CLOCKWISE) { - direction = 0x4; - } else { - direction = 0x5; - } - break; - - case 0x2: - // North - if (rotation == Rotation.CLOCKWISE) { - direction = 0x5; - } else { - direction = 0x4; - } - break; - } - - data = direction; - return data; - - case 69: - direction = (byte) (data & 0x7); - if (direction >= 0x1 && direction <= 0x4) { - - switch (direction) { - case 0x1: - // East - if (rotation == Rotation.CLOCKWISE) { - direction = 0x3; - } else { - direction = 0x4; - } - break; - - case 0x2: - // West - if (rotation == Rotation.CLOCKWISE) { - direction = 0x4; - } else { - direction = 0x3; - } - break; - - case 0x3: - // South - if (rotation == Rotation.CLOCKWISE) { - direction = 0x2; - } else { - direction = 0x1; - } - break; - - case 0x4: - // North - if (rotation == Rotation.CLOCKWISE) { - direction = 0x1; - } else { - direction = 0x2; - } - break; - } - - data = (byte) ((data & 0x8) | direction); - - } else { - switch (direction) { - case 0x5: - data = (byte) ((data & 0x8) | 0x6); - break; - case 0x6: - data = (byte) ((data & 0x8) | 0x5); - break; - case 0x7: - data = (byte) ((data & 0x8)); - break; - case 0x0: - data = (byte) ((data & 0x8) | 0x7); - break; - } - } - - return data; - - case 77: - case 143: - direction = (byte) (data & 0x7); - switch (direction) { - case 0x1: - // East - if (rotation == Rotation.CLOCKWISE) { - direction = 0x3; - } else { - direction = 0x4; - } - break; - - case 0x2: - // West - if (rotation == Rotation.CLOCKWISE) { - direction = 0x4; - } else { - direction = 0x3; - } - break; - - case 0x3: - // South - if (rotation == Rotation.CLOCKWISE) { - direction = 0x2; - } else { - direction = 0x1; - } - break; - - case 0x4: - // North - if (rotation == Rotation.CLOCKWISE) { - direction = 0x1; - } else { - direction = 0x2; - } - break; - } - - data = (byte) ((data & 0x8) | direction); - - return data; - - case 86: - case 91: - direction = (byte) (data & 0x3); - - if (data == 0x4) { - data = 0x4; - } else { - constant = 1; - - if (rotation == Rotation.ANTICLOCKWISE) { - constant = -1; - } - - direction = (byte) (MathUtils.positiveMod((direction + constant) % 4, 4)); - - data = direction; - } - - return data; - - case 93: - case 94: - direction = (byte) (data & 0x3); - - constant = 1; - - if (rotation == Rotation.ANTICLOCKWISE) { - constant = -1; - } - - direction = (byte) (MathUtils.positiveMod((direction + constant) % 4, 4)); - - data = (byte) ((data & 0xC) | direction); - - return data; - - case 96: - case 167: - direction = (byte) (data & 0x3); - switch (direction) { - case 0x2: - // East - if (rotation == Rotation.CLOCKWISE) { - direction = 0x0; - } else { - direction = 0x1; - } - break; - - case 0x3: - // West - if (rotation == Rotation.CLOCKWISE) { - direction = 0x1; - } else { - direction = 0x0; - } - break; - - case 0x0: - // South - if (rotation == Rotation.CLOCKWISE) { - direction = 0x3; - } else { - direction = 0x2; - } - break; - - case 0x1: - // North - if (rotation == Rotation.CLOCKWISE) { - direction = 0x2; - } else { - direction = 0x3; - } - break; - } - - data = (byte) ((data & 0xfc) | direction); - - return data; - case 106: - if (data != 0x0) { - if (rotation == Rotation.CLOCKWISE) { - data = (byte) (data << 1); - } else { - data = (byte) (data >> 1); - } - - if (data > 8) { - data = 1; - } else if (data == 0x0) { - data = 8; - } - - return data; - } else { - return data; - } - - case 107: - case 183: - case 184: - case 185: - case 186: - case 187: - case 120: - direction = (byte) (data & 0x3); - - constant = 1; - - if (rotation == Rotation.ANTICLOCKWISE) { - constant = -1; - } - - direction = (byte) (MathUtils.positiveMod((direction + constant) % 4, 4)); - - data = (byte) ((data & 0x4) | direction); - - return data; - - case 131: - direction = (byte) (data & 0x3); - - constant = 1; - - if (rotation == Rotation.ANTICLOCKWISE) { - constant = -1; - } - - direction = (byte) (MathUtils.positiveMod((direction + constant) % 4, 4)); - - data = (byte) ((data & 0xC) | direction); - - return data; - - case 144: - direction = data; - switch (direction) { - case 0x1: - return data; - case 0x4: - // East - if (rotation == Rotation.CLOCKWISE) { - direction = 0x3; - } else { - direction = 0x2; - } - break; - - case 0x5: - // West - if (rotation == Rotation.CLOCKWISE) { - direction = 0x2; - } else { - direction = 0x3; - } - break; - - case 0x3: - // South - if (rotation == Rotation.CLOCKWISE) { - direction = 0x5; - } else { - direction = 0x4; - } - break; - - case 0x2: - // North - if (rotation == Rotation.CLOCKWISE) { - direction = 0x4; - } else { - direction = 0x5; - } - break; - } - - return direction; - - case 145: - direction = (byte) (data & 0x1); - constant = 1; - - if (rotation == Rotation.ANTICLOCKWISE) { - constant = -1; - } - - direction = (byte) (MathUtils.positiveMod((direction + constant) % 2, 2)); - - data = (byte) ((data & 0xC) | direction); - - return data; - - case 99: - case 100: - direction = data; - switch (direction) { - case 0x0: - case 0x5: - case 0xA: - case 0xE: - case 0xF: - return data; - case 0x2: - //North - if (rotation == Rotation.CLOCKWISE) { - direction = 0x6; - } else { - direction = 0x4; - } - break; - case 0x4: - //East - if (rotation == Rotation.CLOCKWISE) { - direction = 0x2; - } else { - direction = 0x8; - } - break; - case 0x6: - //West - if (rotation == Rotation.CLOCKWISE) { - direction = 0x8; - } else { - direction = 0x2; - } - break; - case 0x8: - //South - if (rotation == Rotation.CLOCKWISE) { - direction = 0x4; - } else { - direction = 0x6; - } - break; - case 0x1: - //North and West - if (rotation == Rotation.CLOCKWISE) { - direction = 0x3; - } else { - direction = 0x7; - } - break; - case 0x3: - //North and East - if (rotation == Rotation.CLOCKWISE) { - direction = 0x9; - } else { - direction = 0x1; - } - break; - case 0x7: - //South and West - if (rotation == Rotation.CLOCKWISE) { - direction = 0x1; - } else { - direction = 0x9; - } - break; - case 0x9: - //South and East - if (rotation == Rotation.CLOCKWISE) { - direction = 0x7; - } else { - direction = 0x3; - } - break; - } - - return direction; - - default: - return data; - } - - - } -} diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/BoundingBoxUtils.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/BoundingBoxUtils.java deleted file mode 100644 index d64af2b72..000000000 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/BoundingBoxUtils.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * This file is part of Movecraft. - * - * Movecraft is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Movecraft is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Movecraft. If not, see . - */ - -package net.countercraft.movecraft.utils; - -import net.countercraft.movecraft.MovecraftLocation; - -public class BoundingBoxUtils { - - public static int[][][] formBoundingBox(MovecraftLocation[] blockList, Integer minX, Integer maxX, Integer minZ, Integer maxZ) { - int sizeX = (maxX - minX) + 1; - int sizeZ = (maxZ - minZ) + 1; - - int[][][] polygonalBox = new int[sizeX][][]; - - for (MovecraftLocation l : blockList) { - if (polygonalBox[l.getX() - minX] == null) { - polygonalBox[l.getX() - minX] = new int[sizeZ][]; - } - - int minY, maxY; - - if (polygonalBox[l.getX() - minX][l.getZ() - minZ] == null) { - - polygonalBox[l.getX() - minX][l.getZ() - minZ] = new int[2]; - polygonalBox[l.getX() - minX][l.getZ() - minZ][0] = l.getY(); - polygonalBox[l.getX() - minX][l.getZ() - minZ][1] = l.getY(); - - } else { - minY = polygonalBox[l.getX() - minX][l.getZ() - minZ][0]; - maxY = polygonalBox[l.getX() - minX][l.getZ() - minZ][1]; - - if (l.getY() < minY) { - polygonalBox[l.getX() - minX][l.getZ() - minZ][0] = l.getY(); - } - if (l.getY() > maxY) { - polygonalBox[l.getX() - minX][l.getZ() - minZ][1] = l.getY(); - } - - } - } - - return polygonalBox; - } - - public static int[][][] translateBoundingBoxVertically(int[][][] hitbox, int dy) { - int[][][] newHitbox = new int[hitbox.length][][]; - - for (int x = 0; x < hitbox.length; x++) { - newHitbox[x] = new int[hitbox[x].length][]; - - for (int z = 0; z < hitbox[x].length; z++) { - - if (hitbox[x][z] != null) { - newHitbox[x][z] = new int[2]; - newHitbox[x][z][0] = hitbox[x][z][0] + dy; - newHitbox[x][z][1] = hitbox[x][z][1] + dy; - } - - } - - } - - - return newHitbox; - } - -} diff --git a/modules/Movecraft/src/main/resources/plugin.yml b/modules/Movecraft/src/main/resources/plugin.yml index aafa4ef7e..408f5470b 100644 --- a/modules/Movecraft/src/main/resources/plugin.yml +++ b/modules/Movecraft/src/main/resources/plugin.yml @@ -1,7 +1,7 @@ name: Movecraft softdepend: [WorldGuard, WorldEdit, FastAsyncWorldEdit, Cannons, Vault ,Essentials, WGCustomFlags, Towny] version: ${project.version} -api-version: 1.14 +api-version: 1.13 #version: ${env.BUILD_NUMBER} description: The original flight and movement plugin for minecraft. author: BaccaYarro diff --git a/modules/api/src/main/java/net/countercraft/movecraft/utils/Pair.java b/modules/api/src/main/java/net/countercraft/movecraft/utils/Pair.java index c164cdd9e..fda31e5f8 100644 --- a/modules/api/src/main/java/net/countercraft/movecraft/utils/Pair.java +++ b/modules/api/src/main/java/net/countercraft/movecraft/utils/Pair.java @@ -2,8 +2,14 @@ import java.io.Serializable; import java.util.Map; +import java.util.Objects; import java.util.UUID; +/** + * Represents a single immutable pair of objects + * @param The left object + * @param The right object + */ public final class Pair implements Serializable, Map.Entry{ private final UUID id = UUID.randomUUID(); private final L left; @@ -14,6 +20,10 @@ public Pair(L left, R right){ this.right = right; } + /** + * + * @return + */ public L getLeft() { return left; } @@ -49,6 +59,22 @@ public boolean equals(Object obj) { @Override public int hashCode() { - return id.hashCode(); + return Objects.hash(left,right); + } + + @Override + public String toString() { + return "Pair{Left: " + getLeft().toString() + ", Right: " + getRight().toString() + "}"; + } + + @Override + public Pair clone(){ + Object clone = null; + try { + clone = super.clone(); + } catch (CloneNotSupportedException e) { + e.printStackTrace(); + } + return (Pair) clone; } } From 68356754c0628237dc9222fe52890dc546d65605 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Mon, 10 Jun 2019 22:53:29 +0200 Subject: [PATCH 020/304] Reverted api-version to 1.13 and removing redundant classes --- .../movecraft/commands/AssaultCommand.java | 6 -- .../countercraft/movecraft/craft/ICraft.java | 8 -- .../update/WaterlogUpdateCommand.java | 1 - .../movecraft/repair/RepairUtils.java | 3 - .../movecraft/sign/ContactsSign.java | 3 - .../movecraft/sign/CraftSign.java | 2 - .../movecraft/sign/CruiseSign.java | 2 - .../countercraft/movecraft/sign/HelmSign.java | 3 - .../countercraft/movecraft/sign/NameSign.java | 2 - .../movecraft/sign/RegionDamagedSign.java | 2 - .../movecraft/sign/RemoteSign.java | 2 - .../movecraft/sign/SpeedSign.java | 3 - .../movecraft/sign/StatusSign.java | 1 - .../movecraft/sign/SubcraftRotateSign.java | 3 - .../movecraft/utils/WorldguardUtils.java | 4 - .../movecraft/MovecraftLocation.java | 99 ------------------- .../movecraft/MovecraftRepair.java | 29 ------ .../countercraft/movecraft/RegionUtils.java | 8 -- .../net/countercraft/movecraft/Rotation.java | 22 ----- .../countercraft/movecraft/WorldHandler.java | 19 ---- .../movecraft/SolidHitBoxTest.java | 74 -------------- .../compat/v1_13_R2/IWorldHandler.java | 1 - 22 files changed, 297 deletions(-) delete mode 100644 modules/api/src/main/java/net/countercraft/movecraft/MovecraftLocation.java delete mode 100644 modules/api/src/main/java/net/countercraft/movecraft/MovecraftRepair.java delete mode 100644 modules/api/src/main/java/net/countercraft/movecraft/RegionUtils.java delete mode 100644 modules/api/src/main/java/net/countercraft/movecraft/Rotation.java delete mode 100644 modules/api/src/main/java/net/countercraft/movecraft/WorldHandler.java delete mode 100644 modules/api/src/test/net/countercraft/movecraft/SolidHitBoxTest.java diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/AssaultCommand.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/AssaultCommand.java index 371764343..5a7c04914 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/AssaultCommand.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/AssaultCommand.java @@ -1,6 +1,5 @@ package net.countercraft.movecraft.commands; -import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldguard.LocalPlayer; import com.sk89q.worldguard.protection.flags.DefaultFlag; import com.sk89q.worldguard.protection.flags.Flag; @@ -10,10 +9,8 @@ import com.sk89q.worldguard.protection.regions.ProtectedRegion; import net.countercraft.movecraft.Movecraft; import net.countercraft.movecraft.MovecraftRepair; -import net.countercraft.movecraft.compat.we7.IMovecraftRepair; import net.countercraft.movecraft.config.Settings; import net.countercraft.movecraft.localisation.I18nSupport; -import net.countercraft.movecraft.utils.WorldEditUtils; import net.countercraft.movecraft.utils.WorldguardUtils; import net.countercraft.movecraft.utils.weVectorUtils; import net.countercraft.movecraft.warfare.assault.Assault; @@ -26,10 +23,7 @@ import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; import org.bukkit.scheduler.BukkitRunnable; -import org.bukkit.util.Vector; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; import java.util.Map; import static net.countercraft.movecraft.utils.ChatUtils.MOVECRAFT_COMMAND_PREFIX; diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/ICraft.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/ICraft.java index 63b99f86a..1d455d869 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/ICraft.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/ICraft.java @@ -6,16 +6,8 @@ import net.countercraft.movecraft.async.detection.DetectionTask; import net.countercraft.movecraft.async.rotation.RotationTask; import net.countercraft.movecraft.async.translation.TranslationTask; -import net.countercraft.movecraft.config.Settings; -import net.countercraft.movecraft.localisation.I18nSupport; -import net.countercraft.movecraft.mapUpdater.MapUpdateManager; -import net.countercraft.movecraft.mapUpdater.update.FuelBurnUpdateCommand; -import org.bukkit.Material; -import org.bukkit.Sound; import org.bukkit.World; -import org.bukkit.block.Block; import org.bukkit.entity.Player; -import org.bukkit.inventory.InventoryHolder; import org.jetbrains.annotations.NotNull; import java.util.UUID; diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/WaterlogUpdateCommand.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/WaterlogUpdateCommand.java index 0dbdaee1e..e29c80ae8 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/WaterlogUpdateCommand.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/WaterlogUpdateCommand.java @@ -4,7 +4,6 @@ import net.countercraft.movecraft.MovecraftLocation; import net.countercraft.movecraft.craft.Craft; import net.countercraft.movecraft.utils.HashHitBox; -import net.countercraft.movecraft.utils.HitBox; import org.bukkit.Material; import org.bukkit.block.Block; import org.bukkit.block.data.Bisected; diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/repair/RepairUtils.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/repair/RepairUtils.java index 80c617ea3..5cf733fcf 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/repair/RepairUtils.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/repair/RepairUtils.java @@ -4,10 +4,7 @@ import com.sk89q.worldedit.blocks.BaseBlock; import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard; import com.sk89q.worldedit.extent.clipboard.Clipboard; -import com.sk89q.worldedit.math.BlockVector3; -import net.countercraft.movecraft.Movecraft; import net.countercraft.movecraft.MovecraftLocation; -import net.countercraft.movecraft.MovecraftRepair; import net.countercraft.movecraft.config.Settings; import net.countercraft.movecraft.mapUpdater.MapUpdateManager; import net.countercraft.movecraft.mapUpdater.update.WorldEditUpdateCommand; diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/ContactsSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/ContactsSign.java index bea89f9e1..5321a1c56 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/ContactsSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/ContactsSign.java @@ -1,14 +1,11 @@ package net.countercraft.movecraft.sign; import net.countercraft.movecraft.MovecraftLocation; -import net.countercraft.movecraft.config.Settings; import net.countercraft.movecraft.craft.Craft; import net.countercraft.movecraft.events.CraftDetectEvent; import net.countercraft.movecraft.events.SignTranslateEvent; import net.countercraft.movecraft.craft.CraftManager; -import net.countercraft.movecraft.utils.LegacyUtils; import org.bukkit.ChatColor; -import org.bukkit.Material; import org.bukkit.World; import org.bukkit.block.Block; import org.bukkit.block.Sign; diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CraftSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CraftSign.java index 1a17b4d8c..919e1fb0b 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CraftSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CraftSign.java @@ -8,10 +8,8 @@ import net.countercraft.movecraft.craft.CraftManager; import net.countercraft.movecraft.craft.ICraft; import net.countercraft.movecraft.localisation.I18nSupport; -import net.countercraft.movecraft.utils.LegacyUtils; import org.bukkit.ChatColor; import org.bukkit.Location; -import org.bukkit.Material; import org.bukkit.block.Block; import org.bukkit.block.BlockFace; import org.bukkit.block.Sign; diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CruiseSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CruiseSign.java index 78ab3e1c4..58490238a 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CruiseSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CruiseSign.java @@ -7,9 +7,7 @@ import net.countercraft.movecraft.craft.CraftManager; import net.countercraft.movecraft.events.CraftDetectEvent; import net.countercraft.movecraft.localisation.I18nSupport; -import net.countercraft.movecraft.utils.LegacyUtils; import org.bukkit.ChatColor; -import org.bukkit.Material; import org.bukkit.World; import org.bukkit.block.Block; import org.bukkit.block.BlockFace; diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/HelmSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/HelmSign.java index b328d49c8..990942ce2 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/HelmSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/HelmSign.java @@ -1,14 +1,11 @@ package net.countercraft.movecraft.sign; import net.countercraft.movecraft.Rotation; -import net.countercraft.movecraft.config.Settings; import net.countercraft.movecraft.craft.Craft; -import net.countercraft.movecraft.utils.LegacyUtils; import net.countercraft.movecraft.utils.MathUtils; import net.countercraft.movecraft.craft.CraftManager; import net.countercraft.movecraft.localisation.I18nSupport; import org.bukkit.ChatColor; -import org.bukkit.Material; import org.bukkit.block.Block; import org.bukkit.block.Sign; import org.bukkit.event.EventHandler; diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/NameSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/NameSign.java index 9e589c724..21184bcf4 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/NameSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/NameSign.java @@ -5,8 +5,6 @@ import net.countercraft.movecraft.craft.Craft; import net.countercraft.movecraft.events.CraftDetectEvent; import net.countercraft.movecraft.utils.ChatUtils; -import net.countercraft.movecraft.utils.LegacyUtils; -import org.bukkit.Material; import org.bukkit.World; import org.bukkit.block.Block; import org.bukkit.block.Sign; diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RegionDamagedSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RegionDamagedSign.java index 094c965b0..81a810ed6 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RegionDamagedSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RegionDamagedSign.java @@ -1,7 +1,6 @@ package net.countercraft.movecraft.sign; import com.sk89q.worldedit.bukkit.BukkitAdapter; -import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard; import com.sk89q.worldedit.extent.clipboard.Clipboard; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.world.block.BaseBlock; @@ -14,7 +13,6 @@ import net.countercraft.movecraft.localisation.I18nSupport; import net.countercraft.movecraft.mapUpdater.MapUpdateManager; import net.countercraft.movecraft.mapUpdater.update.WorldEdit7UpdateCommand; -import net.countercraft.movecraft.mapUpdater.update.WorldEditUpdateCommand; import net.countercraft.movecraft.repair.RepairUtils; import net.countercraft.movecraft.utils.WorldguardUtils; import org.bukkit.*; diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RemoteSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RemoteSign.java index d8d1e62ae..f731d7dc0 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RemoteSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RemoteSign.java @@ -1,7 +1,6 @@ package net.countercraft.movecraft.sign; import net.countercraft.movecraft.config.Settings; -import net.countercraft.movecraft.utils.LegacyUtils; import net.countercraft.movecraft.utils.MathUtils; import net.countercraft.movecraft.MovecraftLocation; import net.countercraft.movecraft.craft.Craft; @@ -9,7 +8,6 @@ import net.countercraft.movecraft.localisation.I18nSupport; import org.bukkit.Bukkit; import org.bukkit.ChatColor; -import org.bukkit.Material; import org.bukkit.block.Block; import org.bukkit.block.Sign; import org.bukkit.event.EventHandler; diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/SpeedSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/SpeedSign.java index e0331c97a..c47ed5e3c 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/SpeedSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/SpeedSign.java @@ -1,13 +1,10 @@ package net.countercraft.movecraft.sign; import net.countercraft.movecraft.MovecraftLocation; -import net.countercraft.movecraft.config.Settings; import net.countercraft.movecraft.craft.Craft; import net.countercraft.movecraft.events.CraftDetectEvent; import net.countercraft.movecraft.events.SignTranslateEvent; -import net.countercraft.movecraft.utils.LegacyUtils; import org.bukkit.ChatColor; -import org.bukkit.Material; import org.bukkit.World; import org.bukkit.block.Block; import org.bukkit.block.Sign; diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/StatusSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/StatusSign.java index da4d5ffe4..12f1a03f1 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/StatusSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/StatusSign.java @@ -5,7 +5,6 @@ import net.countercraft.movecraft.craft.Craft; import net.countercraft.movecraft.events.CraftDetectEvent; import net.countercraft.movecraft.events.SignTranslateEvent; -import net.countercraft.movecraft.utils.LegacyUtils; import org.bukkit.ChatColor; import org.bukkit.Material; import org.bukkit.World; diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/SubcraftRotateSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/SubcraftRotateSign.java index 83b7ef63d..f94f16b0e 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/SubcraftRotateSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/SubcraftRotateSign.java @@ -3,16 +3,13 @@ import net.countercraft.movecraft.Movecraft; import net.countercraft.movecraft.MovecraftLocation; import net.countercraft.movecraft.Rotation; -import net.countercraft.movecraft.config.Settings; import net.countercraft.movecraft.craft.Craft; import net.countercraft.movecraft.craft.CraftManager; import net.countercraft.movecraft.craft.CraftType; import net.countercraft.movecraft.craft.ICraft; import net.countercraft.movecraft.localisation.I18nSupport; -import net.countercraft.movecraft.utils.LegacyUtils; import org.bukkit.ChatColor; import org.bukkit.Location; -import org.bukkit.Material; import org.bukkit.block.Block; import org.bukkit.block.Sign; import org.bukkit.event.EventHandler; diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/WorldguardUtils.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/WorldguardUtils.java index bc0ccdaec..d71a57362 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/WorldguardUtils.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/WorldguardUtils.java @@ -1,8 +1,6 @@ package net.countercraft.movecraft.utils; -import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.bukkit.BukkitWorld; -import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldguard.WorldGuard; import com.sk89q.worldguard.protection.ApplicableRegionSet; import com.sk89q.worldguard.protection.flags.DefaultFlag; @@ -21,8 +19,6 @@ import org.bukkit.World; import org.bukkit.entity.Player; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; import java.util.UUID; public class WorldguardUtils { diff --git a/modules/api/src/main/java/net/countercraft/movecraft/MovecraftLocation.java b/modules/api/src/main/java/net/countercraft/movecraft/MovecraftLocation.java deleted file mode 100644 index f3add2bc9..000000000 --- a/modules/api/src/main/java/net/countercraft/movecraft/MovecraftLocation.java +++ /dev/null @@ -1,99 +0,0 @@ -/* - * This file is part of Movecraft. - * - * Movecraft is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Movecraft is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Movecraft. If not, see . - */ - -package net.countercraft.movecraft; - -import org.bukkit.Location; -import org.bukkit.World; -import org.bukkit.util.Vector; - -/** - * Represents a Block aligned coordinate triplet. - */ -final public class MovecraftLocation { - private final int x, y, z; - - public MovecraftLocation(int x, int y, int z) { - this.x = x; - this.y = y; - this.z = z; - } - - public int getX() { - return x; - } - - public int getY() { - return y; - } - - public int getZ() { - return z; - } - - /** - * Returns a MovecraftLocation that has undergone the given translation. - *

- * This does not change the MovecraftLocation that it is called upon and that should be accounted for in terms of Garbage Collection. - * - * @param dx - X translation - * @param dy - Y translation - * @param dz - Z translation - * @return New MovecraftLocation shifted by specified amount - */ - public MovecraftLocation translate(int dx, int dy, int dz) { - return new MovecraftLocation(x + dx, y + dy, z + dz); - } - - @Override - public boolean equals(Object o) { - if (o instanceof MovecraftLocation) { - MovecraftLocation location = (MovecraftLocation) o; - return location.x==this.x && location.y==this.y && location.z == this.z; - } - return false; - } - - @Override - public int hashCode() { - return (x ^ (z << 12)) ^ (y << 24); - } - - public MovecraftLocation add(MovecraftLocation l) { - return new MovecraftLocation(getX() + l.getX(), getY() + l.getY(), getZ() + l.getZ()); - } - - public MovecraftLocation subtract(MovecraftLocation l) { - return new MovecraftLocation(getX() - l.getX(), getY() - l.getY(), getZ() - l.getZ()); - } - - public Location toBukkit(World world){ - return new Location(world, this.x, this.y, this.z); - } - - public static Location toBukkit(World world, MovecraftLocation location){ - return new Location(world, location.x, location.y, location.z); - } - public static MovecraftLocation fromVector(Vector vector){ - return new MovecraftLocation(vector.getBlockX(),vector.getBlockY(),vector.getBlockZ()); - } - - @Override - public String toString(){ - return "(" + x + "," + y + "," + z +")"; - } -} diff --git a/modules/api/src/main/java/net/countercraft/movecraft/MovecraftRepair.java b/modules/api/src/main/java/net/countercraft/movecraft/MovecraftRepair.java deleted file mode 100644 index d9ac1e545..000000000 --- a/modules/api/src/main/java/net/countercraft/movecraft/MovecraftRepair.java +++ /dev/null @@ -1,29 +0,0 @@ -package net.countercraft.movecraft; - -import com.sk89q.worldedit.extent.clipboard.Clipboard; -import com.sk89q.worldguard.protection.regions.ProtectedRegion; -import net.countercraft.movecraft.craft.Craft; -import net.countercraft.movecraft.utils.Pair; -import org.bukkit.Material; -import org.bukkit.World; -import org.bukkit.block.Sign; -import org.bukkit.plugin.Plugin; -import org.bukkit.util.Vector; - -import java.util.ArrayDeque; -import java.util.HashMap; - -public abstract class MovecraftRepair { - public abstract boolean saveCraftRepairState(Craft craft, Sign sign, Plugin plugin, String repairStateName); - public abstract boolean saveRegionRepairState(Plugin plugin, World world, ProtectedRegion region); - public abstract Clipboard loadCraftRepairStateClipboard(Plugin plugin, Craft craft, Sign sign, String repairStateName, World bukkitWorld); - public abstract Clipboard loadRegionRepairStateClipboard(Plugin plugin, String repairStateName, World bukkitWorld); - public abstract HashMap getMissingBlocks(String repairName); - public abstract ArrayDeque> getMissingBlockLocations(String repairName); - public abstract long getNumDiffBlocks(String repairName); - public abstract org.bukkit.util.Vector getDistance(String repairName); - public abstract org.bukkit.util.Vector getOffset(String repairName); - - - -} diff --git a/modules/api/src/main/java/net/countercraft/movecraft/RegionUtils.java b/modules/api/src/main/java/net/countercraft/movecraft/RegionUtils.java deleted file mode 100644 index bf3935869..000000000 --- a/modules/api/src/main/java/net/countercraft/movecraft/RegionUtils.java +++ /dev/null @@ -1,8 +0,0 @@ -package net.countercraft.movecraft; - -import com.sk89q.worldguard.protection.regions.ProtectedRegion; -import org.bukkit.util.Vector; - -public abstract class RegionUtils { - public abstract Vector getRegionPoint(ProtectedRegion region, boolean minPoint); -} diff --git a/modules/api/src/main/java/net/countercraft/movecraft/Rotation.java b/modules/api/src/main/java/net/countercraft/movecraft/Rotation.java deleted file mode 100644 index e12d74a0a..000000000 --- a/modules/api/src/main/java/net/countercraft/movecraft/Rotation.java +++ /dev/null @@ -1,22 +0,0 @@ -/* - * This file is part of Movecraft. - * - * Movecraft is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Movecraft is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Movecraft. If not, see . - */ - -package net.countercraft.movecraft; - -public enum Rotation { - CLOCKWISE, NONE, ANTICLOCKWISE -} diff --git a/modules/api/src/main/java/net/countercraft/movecraft/WorldHandler.java b/modules/api/src/main/java/net/countercraft/movecraft/WorldHandler.java deleted file mode 100644 index 4c81c798b..000000000 --- a/modules/api/src/main/java/net/countercraft/movecraft/WorldHandler.java +++ /dev/null @@ -1,19 +0,0 @@ -package net.countercraft.movecraft; - -import net.countercraft.movecraft.craft.Craft; -import org.bukkit.Location; -import org.bukkit.Material; -import org.bukkit.entity.Player; -import org.jetbrains.annotations.NotNull; - -public abstract class WorldHandler { - public abstract void rotateCraft(@NotNull Craft craft, @NotNull MovecraftLocation originLocation, @NotNull Rotation rotation); - public abstract void translateCraft(@NotNull Craft craft, @NotNull MovecraftLocation newLocation); - public abstract void setBlockFast(@NotNull Location location, @NotNull Material material, byte data); - public abstract void setBlockFast(@NotNull Location location, @NotNull Rotation rotation, @NotNull Material material, byte data); - public abstract void disableShadow(@NotNull Material type); - public void addPlayerLocation(Player player, double x, double y, double z, float yaw, float pitch){ - Location playerLoc = player.getLocation(); - player.teleport(new Location(player.getWorld(), x + playerLoc.getX(),y + playerLoc.getY(),z + playerLoc.getZ(),yaw + playerLoc.getYaw(),pitch + playerLoc.getPitch())); - } -} diff --git a/modules/api/src/test/net/countercraft/movecraft/SolidHitBoxTest.java b/modules/api/src/test/net/countercraft/movecraft/SolidHitBoxTest.java deleted file mode 100644 index 0a6930b4e..000000000 --- a/modules/api/src/test/net/countercraft/movecraft/SolidHitBoxTest.java +++ /dev/null @@ -1,74 +0,0 @@ -package net.countercraft.movecraft; - -import net.countercraft.movecraft.utils.HitBox; -import net.countercraft.movecraft.utils.SolidHitBox; -import org.junit.Test; - -import java.util.ArrayList; -import java.util.List; - -import static org.hamcrest.MatcherAssert.assertThat; -import static org.hamcrest.Matchers.containsInAnyOrder; -import static org.hamcrest.Matchers.iterableWithSize; -import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.junit.jupiter.api.Assertions.assertIterableEquals; -import static org.junit.jupiter.api.Assertions.assertTrue; - - -public class SolidHitBoxTest { - - final private MovecraftLocation minimum = new MovecraftLocation(0,0,0); - final private MovecraftLocation maximum = new MovecraftLocation(3,3,3); - final private HitBox hitBox = new SolidHitBox(minimum, maximum); - - @Test - public void testBounds(){ - assertEquals(minimum.getX(), hitBox.getMinX()); - assertEquals(minimum.getY(), hitBox.getMinY()); - assertEquals(minimum.getZ(), hitBox.getMinZ()); - assertEquals(maximum.getX(), hitBox.getMaxX()); - assertEquals(maximum.getY(), hitBox.getMaxY()); - assertEquals(maximum.getZ(), hitBox.getMaxZ()); - } - - @Test - public void testSize(){ - assertEquals(64, hitBox.size()); - assertThat(hitBox, iterableWithSize(64)); - } - - - @Test - public void testContents(){ - final List locations = new ArrayList<>(64); - for(int x = minimum.getX(); x <= maximum.getX(); x++){ - for(int y = minimum.getY(); y <= maximum.getY(); y++){ - for(int z = minimum.getX(); z <= maximum.getY(); z++){ - locations.add(new MovecraftLocation(x,y,z)); - } - } - } - assertThat(locations,containsInAnyOrder(hitBox.asSet().toArray())); - } - - @Test - public void testBoundingHitBox(){ - assertIterableEquals(hitBox, hitBox.boundingHitBox()); - } - - @Test - public void testContainsAll(){ - final List locations = new ArrayList<>(64); - for(int x = minimum.getX(); x <= maximum.getX(); x++){ - for(int y = minimum.getY(); y <= maximum.getY(); y++){ - for(int z = minimum.getX(); z <= maximum.getY(); z++){ - locations.add(new MovecraftLocation(x,y,z)); - } - } - } - assertTrue(hitBox.containsAll(locations)); - } - - - -} diff --git a/modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/IWorldHandler.java b/modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/IWorldHandler.java index b57dfa9db..3f584a586 100644 --- a/modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/IWorldHandler.java +++ b/modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/IWorldHandler.java @@ -19,7 +19,6 @@ import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; import java.lang.reflect.Field; -import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.*; From 2c7a68d3523504bc87c033ecddc763bfac9d44ad Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Thu, 27 Jun 2019 13:21:44 +0200 Subject: [PATCH 021/304] Re-added ability to disallow sink where PvP is disabled --- modules/Movecraft/pom.xml | 9 ++- .../net/countercraft/movecraft/Movecraft.java | 9 ++- .../movecraft/async/AsyncManager.java | 33 ++++++++++- .../async/rotation/RotationTask.java | 4 +- .../async/translation/TranslationTask.java | 9 ++- .../GriefPreventionCompatManager.java | 12 +++- .../movecraft/listener/BlockListener.java | 13 ++--- .../movecraft/localisation/I18nSupport.java | 11 ++-- ...mand.java => EntityMoveUpdateCommand.java} | 9 ++- .../update/EntitySpawnUpdateCommand.java | 55 +++++++++++++++++++ .../movecraft/sign/CraftSign.java | 2 +- .../movecraft/sign/RepairSign.java | 2 +- .../src/main/resources/types/airship.craft | 2 +- .../countercraft/movecraft/craft/Craft.java | 12 ++-- .../movecraft/craft/CraftType.java | 24 ++++++++ .../movecraft/utils/MathUtils.java | 21 +++++++ 16 files changed, 188 insertions(+), 39 deletions(-) rename modules/{api => Movecraft}/src/main/java/net/countercraft/movecraft/localisation/I18nSupport.java (86%) rename modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/{EntityUpdateCommand.java => EntityMoveUpdateCommand.java} (88%) create mode 100644 modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/EntitySpawnUpdateCommand.java diff --git a/modules/Movecraft/pom.xml b/modules/Movecraft/pom.xml index 0974d368b..15b825779 100644 --- a/modules/Movecraft/pom.xml +++ b/modules/Movecraft/pom.xml @@ -119,7 +119,7 @@ commons-lang3 LATEST - + at.pavlov Cannons @@ -135,17 +135,20 @@ + org.yaml snakeyaml 1.10 + net.milkbowl.vault VaultAPI 1.7 provided + net.ess3 Essentials @@ -188,8 +191,8 @@ ${project.basedir}/../../libs/Deadbolt-1.0-SNAPSHOT.jar - sun.jdk - gp + me.ryanhamshire + GriefPrevention 1.5.0 system ${project.basedir}/../../libs/GriefPrevention.jar diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java index 326876175..7f23ae735 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java @@ -56,7 +56,6 @@ import org.bukkit.plugin.java.JavaPlugin; import org.yaml.snakeyaml.Yaml; - import java.io.*; import java.util.*; import java.util.logging.Level; @@ -462,7 +461,7 @@ public void onEnable() { } } - I18nSupport.init(this); + I18nSupport.init(); if (shuttingDown && Settings.IGNORE_RESET) { logger.log( Level.SEVERE, @@ -666,5 +665,11 @@ public Kingdoms getKingdomsPlugin() { public RedProtect getRedProtectPlugin() { return redProtectPlugin; } + + + public P getBreweryPlugin() { + return breweryPlugin; + } + } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java index 0690d7c2d..bc224286d 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java @@ -19,6 +19,12 @@ import at.pavlov.cannons.cannon.Cannon; import com.google.common.collect.Lists; +import com.sk89q.worldguard.bukkit.WorldGuardPlugin; +import com.sk89q.worldguard.protection.ApplicableRegionSet; +import com.sk89q.worldguard.protection.flags.Flags; +import com.sk89q.worldguard.protection.flags.StateFlag; +import com.sk89q.worldguard.protection.managers.RegionManager; +import com.sk89q.worldguard.protection.regions.ProtectedRegion; import net.countercraft.movecraft.Movecraft; import net.countercraft.movecraft.MovecraftLocation; import net.countercraft.movecraft.Rotation; @@ -568,8 +574,33 @@ private void detectSinking(){ // if the craft is sinking, let the player // know and release the craft. Otherwise // update the time for the next check + Player notifyP = pcraft.getNotificationPlayer(); + if (Movecraft.getInstance().getWorldGuardPlugin() != null){ + WorldGuardPlugin wgPlugin = Movecraft.getInstance().getWorldGuardPlugin(); + ProtectedRegion region = null; + RegionManager regionManager = wgPlugin.getRegionManager(pcraft.getW()); + for (MovecraftLocation location : pcraft.getHitBox()){ + ApplicableRegionSet regions = regionManager.getApplicableRegions(location.toBukkit(pcraft.getW())); + for (ProtectedRegion pr : regions.getRegions()){ + if (pr.getFlag(Flags.PVP).equals(StateFlag.State.DENY)){ + region = pr; + break; + } + } + if (region != null){ + break; + } + } + if (region != null && Settings.WorldGuardBlockSinkOnPVPPerm){ + notifyP.sendMessage(I18nSupport.getInternationalisedString("Player- Craft should sink but PVP is not allowed in this WorldGuard region")); + isSinking = false; + } + } if (isSinking && pcraft.isNotProcessing()) { - Player notifyP = pcraft.getNotificationPlayer(); + + if (notifyP != null) { + notifyP.sendMessage(I18nSupport.getInternationalisedString("Player- Craft is sinking")); + } pcraft.setCruising(false); pcraft.sink(); CraftManager.getInstance().removePlayerFromCraft(pcraft); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/rotation/RotationTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/rotation/RotationTask.java index 302d02f01..0ababaf4a 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/rotation/RotationTask.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/rotation/RotationTask.java @@ -32,7 +32,7 @@ import net.countercraft.movecraft.events.CraftRotateEvent; import net.countercraft.movecraft.localisation.I18nSupport; import net.countercraft.movecraft.mapUpdater.update.CraftRotateCommand; -import net.countercraft.movecraft.mapUpdater.update.EntityUpdateCommand; +import net.countercraft.movecraft.mapUpdater.update.EntityMoveUpdateCommand; import net.countercraft.movecraft.mapUpdater.update.UpdateCommand; import net.countercraft.movecraft.utils.*; import org.bukkit.Bukkit; @@ -221,7 +221,7 @@ public void run() { double[] rotatedCoords = MathUtils.rotateVecNoRound(rotation, adjustedPLoc.getX(), adjustedPLoc.getZ()); float newYaw = rotation == Rotation.CLOCKWISE ? 90F : -90F; - EntityUpdateCommand eUp = new EntityUpdateCommand(entity, rotatedCoords[0] + tOP.getX() - entity.getLocation().getX(), 0, rotatedCoords[1] + tOP.getZ() - entity.getLocation().getZ(), newYaw, 0); + EntityMoveUpdateCommand eUp = new EntityMoveUpdateCommand(entity, rotatedCoords[0] + tOP.getX() - entity.getLocation().getX(), 0, rotatedCoords[1] + tOP.getZ() - entity.getLocation().getZ(), newYaw, 0); updates.add(eUp); } } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java index 4014ff6c1..ee43a7f02 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java @@ -343,11 +343,16 @@ public void run() { Location loc = location.toBukkit(craft.getW()); int potEffRange = craft.getType().getEffectRange(); Map potionEffects = craft.getType().getPotionEffectsToApply(); + Set entityTypes = craft.getType().getEntitiesToSpawn(); + int maxEntitiesToBeSpawned = craft.getType().getMaxEntitiesToBeSpawned(); if (!loc.getBlock().getType().equals(Material.AIR)) { updates.add(new ExplosionUpdateCommand(loc, explosionKey)); collisionExplosion = true; if (potEffRange != 0 && !potionEffects.isEmpty()) updates.add(new PotionEffectsUpdateCommand(loc,potEffRange,potionEffects)); + if (potEffRange != 0 && !entityTypes.isEmpty()){ + updates.add(new EntitySpawnUpdateCommand(potEffRange,maxEntitiesToBeSpawned,loc,entityTypes)); + } } if (craft.getType().getFocusedExplosion()) { // don't handle any further collisions if it is set to focusedexplosion break; @@ -371,10 +376,10 @@ public void run() { if (entity.getType() == EntityType.PLAYER && !craft.getSinking()) { Player player = (Player) entity; craft.getMovedPlayers().put(player, System.currentTimeMillis()); - EntityUpdateCommand eUp = new EntityUpdateCommand(entity, dx, dy, dz, 0, 0); + EntityMoveUpdateCommand eUp = new EntityMoveUpdateCommand(entity, dx, dy, dz, 0, 0); updates.add(eUp); } else if (!craft.getType().getOnlyMovePlayers() || entity.getType() == EntityType.PRIMED_TNT) { - EntityUpdateCommand eUp = new EntityUpdateCommand(entity, dx, dy, dz, 0, 0); + EntityMoveUpdateCommand eUp = new EntityMoveUpdateCommand(entity, dx, dy, dz, 0, 0); updates.add(eUp); } } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/compatmanager/GriefPreventionCompatManager.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/compatmanager/GriefPreventionCompatManager.java index 3313821af..7fe60d5f1 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/compatmanager/GriefPreventionCompatManager.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/compatmanager/GriefPreventionCompatManager.java @@ -9,6 +9,7 @@ import net.countercraft.movecraft.events.CraftSinkEvent; import net.countercraft.movecraft.events.CraftTranslateEvent; import net.countercraft.movecraft.localisation.I18nSupport; +import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; @@ -19,19 +20,24 @@ public void onCraftTranslate(CraftTranslateEvent event){ if (Movecraft.getInstance().getGriefPreventionPlugin() == null){ return; } + GriefPrevention gp = Movecraft.getInstance().getGriefPreventionPlugin(); Craft craft = event.getCraft(); + String gpMessage = null; for (MovecraftLocation mLoc : event.getNewHitBox()){ Location loc = mLoc.toBukkit(craft.getW()); - GriefPrevention gp = Movecraft.getInstance().getGriefPreventionPlugin(); - String gpMessage = gp.allowBuild(craft.getNotificationPlayer(), loc); + + gpMessage = gp.allowBuild(craft.getNotificationPlayer(), loc); + if (gpMessage != null) break; + } if (gpMessage == null){ return; } + Bukkit.getLogger().info(gpMessage); if (gpMessage.contains(gp.dataStore.getMessage(Messages.NoBuildPermission).replace("{0}", ""))){ event.setFailMessage(I18nSupport.getInternationalisedString("Translation - Failed GriefPrevention")); event.setCancelled(true); } - } + } @EventHandler diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/BlockListener.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/BlockListener.java index 2436fd853..e3c717dc2 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/BlockListener.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/BlockListener.java @@ -43,14 +43,7 @@ import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; import org.bukkit.event.Listener; -import org.bukkit.event.block.BlockBreakEvent; -import org.bukkit.event.block.BlockDispenseEvent; -import org.bukkit.event.block.BlockFromToEvent; -import org.bukkit.event.block.BlockIgniteEvent; -import org.bukkit.event.block.BlockPhysicsEvent; -import org.bukkit.event.block.BlockPistonExtendEvent; -import org.bukkit.event.block.BlockPlaceEvent; -import org.bukkit.event.block.BlockRedstoneEvent; +import org.bukkit.event.block.*; import org.bukkit.event.entity.EntityExplodeEvent; import org.bukkit.event.entity.ItemSpawnEvent; import org.bukkit.event.inventory.InventoryMoveItemEvent; @@ -182,10 +175,14 @@ public void onRedstoneEvent(BlockRedstoneEvent event) { } } + public void onPistonRetract(BlockPistonRetractEvent event){ + + } // prevent pistons on cruising crafts @EventHandler(priority = EventPriority.HIGHEST) public void onPistonEvent(BlockPistonExtendEvent event) { Block block = event.getBlock(); + CraftManager.getInstance().getCraftsInWorld(block.getWorld()); for (Craft tcraft : CraftManager.getInstance().getCraftsInWorld(block.getWorld())) { MovecraftLocation mloc = new MovecraftLocation(block.getX(), block.getY(), block.getZ()); diff --git a/modules/api/src/main/java/net/countercraft/movecraft/localisation/I18nSupport.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/localisation/I18nSupport.java similarity index 86% rename from modules/api/src/main/java/net/countercraft/movecraft/localisation/I18nSupport.java rename to modules/Movecraft/src/main/java/net/countercraft/movecraft/localisation/I18nSupport.java index c6ec7ee38..aedb0de5e 100644 --- a/modules/api/src/main/java/net/countercraft/movecraft/localisation/I18nSupport.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/localisation/I18nSupport.java @@ -17,8 +17,8 @@ package net.countercraft.movecraft.localisation; +import net.countercraft.movecraft.Movecraft; import net.countercraft.movecraft.config.Settings; -import org.bukkit.plugin.Plugin; import java.io.*; import java.util.Arrays; @@ -29,10 +29,11 @@ public final class I18nSupport { private static Properties languageFile; private static boolean hasOtherScript = false; private static final String[] otherScriptLangs = {"el", "ar", "ur", "he", "zh", "jp"}; - public static void init(Plugin plugin) { + private static Movecraft movecraft = Movecraft.getInstance(); + public static void init() { languageFile = new Properties(); - File localisationDirectory = new File(plugin.getDataFolder().getAbsolutePath() + "/localisation"); + File localisationDirectory = new File(movecraft.getDataFolder().getAbsolutePath() + "/localisation"); if (!localisationDirectory.exists()) { localisationDirectory.mkdirs(); @@ -47,8 +48,8 @@ public static void init(Plugin plugin) { if (is == null) { - plugin.getLogger().log(Level.SEVERE, "Critical Error in Localisation System"); - plugin.getServer().shutdown(); + movecraft.getLogger().log(Level.SEVERE, "Critical Error in Localisation System"); + movecraft.getServer().shutdown(); return; } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/EntityUpdateCommand.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/EntityMoveUpdateCommand.java similarity index 88% rename from modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/EntityUpdateCommand.java rename to modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/EntityMoveUpdateCommand.java index e416dd7b2..6e4fca7aa 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/EntityUpdateCommand.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/EntityMoveUpdateCommand.java @@ -18,7 +18,6 @@ package net.countercraft.movecraft.mapUpdater.update; import net.countercraft.movecraft.Movecraft; -import net.countercraft.movecraft.config.Settings; import org.bukkit.Location; import org.bukkit.entity.Entity; import org.bukkit.entity.Player; @@ -28,7 +27,7 @@ /** * Class that stores the data about a single blocks changes to the map in an unspecified world. The world is retrieved contextually from the submitting craft. */ -public class EntityUpdateCommand extends UpdateCommand { +public class EntityMoveUpdateCommand extends UpdateCommand { private final Entity entity; private final double x; private final double y; @@ -36,7 +35,7 @@ public class EntityUpdateCommand extends UpdateCommand { private final float yaw; private final float pitch; - public EntityUpdateCommand(Entity entity, double x, double y, double z, float yaw, float pitch) { + public EntityMoveUpdateCommand(Entity entity, double x, double y, double z, float yaw, float pitch) { this.entity = entity; this.x = x; this.y = y; @@ -67,10 +66,10 @@ public int hashCode() { @Override public boolean equals(Object obj) { - if(!(obj instanceof EntityUpdateCommand)){ + if(!(obj instanceof EntityMoveUpdateCommand)){ return false; } - EntityUpdateCommand other = (EntityUpdateCommand) obj; + EntityMoveUpdateCommand other = (EntityMoveUpdateCommand) obj; return this.x == other.x && this.y == other.y && this.z == other.z && diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/EntitySpawnUpdateCommand.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/EntitySpawnUpdateCommand.java new file mode 100644 index 000000000..de2d7a88a --- /dev/null +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/EntitySpawnUpdateCommand.java @@ -0,0 +1,55 @@ +package net.countercraft.movecraft.mapUpdater.update; + +import net.countercraft.movecraft.utils.MathUtils; +import org.bukkit.Location; +import org.bukkit.entity.EntityType; +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayDeque; +import java.util.Set; + +public class EntitySpawnUpdateCommand extends UpdateCommand { + @NotNull private final int spawnRange; + @NotNull private final int maxEntities; + @NotNull private final Location loc; + @NotNull private final Set entitiesToSpawn; + + public EntitySpawnUpdateCommand(@NotNull int spawnRange, @NotNull int maxEntities, @NotNull Location loc, @NotNull Set entitiesToSpawn){ + this.spawnRange = spawnRange; + this.maxEntities = maxEntities; + this.loc = loc; + this.entitiesToSpawn = entitiesToSpawn; + } + @Override + public void doUpdate() { + //Get locations where entities can be spawned + @NotNull ArrayDeque spawnLocs = new ArrayDeque<>(); + int minX = loc.getBlockX() - spawnRange; + int minZ = loc.getBlockZ() - spawnRange; + int maxX = loc.getBlockX() + spawnRange; + int maxZ = loc.getBlockZ() + spawnRange; + for (int i = 1 ; i <= maxEntities; i++){ + final int randX = MathUtils.randomInteger(minX,maxX); + final int randZ = MathUtils.randomInteger(minZ,maxZ); + final int y =loc.getBlockY(); + @NotNull final Location spawnLoc = new Location(loc.getWorld(),randX,y,randZ); + for (int dy = 0 ; dy <= 255 - y; dy++){ + if (loc.getWorld().getBlockAt(randX,y + dy, randZ).getType().name().endsWith("AIR")){ + spawnLoc.add(0,dy,0); + break; + } + + } + spawnLocs.addLast(spawnLoc); + } + //Spawn entities at the determined locations + while (!spawnLocs.isEmpty()){ + for (EntityType entity : entitiesToSpawn){ + @NotNull Location poll = spawnLocs.pollFirst(); + if (poll == null) + continue; + loc.getWorld().spawnEntity(poll,entity); + } + } + } +} diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CraftSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CraftSign.java index 919e1fb0b..0f6e859d6 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CraftSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CraftSign.java @@ -93,7 +93,7 @@ public final void onSignClick(PlayerInteractEvent event) { new BukkitRunnable() { @Override public void run() { - CraftManager.getInstance().removeCraft(c); + c.sink(); } }.runTaskLater(Movecraft.getInstance(), (20 * 15)); } else { diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RepairSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RepairSign.java index af7321c0a..5523f59af 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RepairSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RepairSign.java @@ -37,7 +37,7 @@ import java.util.*; -public class RepairSign implements Listener{ +public final class RepairSign implements Listener{ private String HEADER = "Repair:"; private HashMap playerInteractTimeMap = new HashMap<>();//Players must be assigned by the UUID, or NullPointerExceptions are thrown private final Material[] fragileBlocks = new Material[]{ Material.TORCH, Material.LADDER, Material.getMaterial("WALL_SIGN"), Material.LEVER, Material.STONE_BUTTON, LegacyUtils.TRAP_DOOR, Material.TRIPWIRE_HOOK, LegacyUtils.WOOD_BUTTON, Material.IRON_TRAPDOOR, }; diff --git a/modules/Movecraft/src/main/resources/types/airship.craft b/modules/Movecraft/src/main/resources/types/airship.craft index 4ae6a0256..12b6beb50 100644 --- a/modules/Movecraft/src/main/resources/types/airship.craft +++ b/modules/Movecraft/src/main/resources/types/airship.craft @@ -264,7 +264,7 @@ tryNudge: false canStaticMove: true maxStaticMove: 2 moveblocks: - 152: # redstone represents engines + REDSTONE_BLOCK: # redstone represents engines - 1.0 - 100.0 flyblocks: diff --git a/modules/api/src/main/java/net/countercraft/movecraft/craft/Craft.java b/modules/api/src/main/java/net/countercraft/movecraft/craft/Craft.java index 47d29ff15..2f06aa806 100644 --- a/modules/api/src/main/java/net/countercraft/movecraft/craft/Craft.java +++ b/modules/api/src/main/java/net/countercraft/movecraft/craft/Craft.java @@ -21,7 +21,6 @@ import net.countercraft.movecraft.Rotation; import net.countercraft.movecraft.config.Settings; import net.countercraft.movecraft.events.CraftSinkEvent; -import net.countercraft.movecraft.localisation.I18nSupport; import net.countercraft.movecraft.utils.HashHitBox; import net.md_5.bungee.api.ChatMessageType; import net.md_5.bungee.api.chat.TextComponent; @@ -165,10 +164,9 @@ public void sink(){ notificationPlayer.sendMessage(event.getFailMessage()); return; } - if (notificationPlayer != null) { - notificationPlayer.sendMessage(I18nSupport.getInternationalisedString("Player- Craft is sinking")); - } - this.sinking = true; + + + sinking = true; } @@ -456,4 +454,8 @@ public boolean isClimbing() { public void setClimbing(boolean climbing) { this.climbing = climbing; } + + public enum SinkReason{ + NONE, DAMAGE, RANGE + } } \ No newline at end of file diff --git a/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java b/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java index e3df6b053..21c1b4f73 100644 --- a/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java +++ b/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java @@ -20,6 +20,7 @@ import net.countercraft.movecraft.config.Settings; import org.bukkit.Material; import org.bukkit.block.Block; +import org.bukkit.entity.EntityType; import org.bukkit.potion.PotionEffect; import org.bukkit.potion.PotionEffectType; import org.jetbrains.annotations.NotNull; @@ -99,6 +100,8 @@ final public class CraftType { @NotNull private final int effectRange; @NotNull private final Map potionEffectsToApply; @NotNull private final Map potionEffectDelays = Collections.emptyMap(); + @NotNull private final Set entitiesToSpawn; + @NotNull private final int maxEntitiesToBeSpawned; public CraftType(File f) { final Map data; @@ -445,6 +448,18 @@ public CraftType(File f) { chestPenalty = data.containsKey("chestPenalty") ? doubleFromObject(data.get("chestPenalty")) : 0d; effectRange = data.containsKey("effectRange") ? integerFromObject(data.get("effectRange")) : 0; potionEffectsToApply = data.containsKey("potionEffectsToApply") ? effectListFromObject(data.get("potionEffectsToApply")) : Collections.emptyMap(); + if (data.containsKey("entitiesToSpawn")){ + entitiesToSpawn = new HashSet<>(); + ArrayList entries = (ArrayList) data.get("entitiesToSpawn"); + for (Object o : entries){ + if (o instanceof String){ + entitiesToSpawn.add(EntityType.valueOf(((String) o).toUpperCase())); + } + } + } else { + entitiesToSpawn = Collections.emptySet(); + } + maxEntitiesToBeSpawned = data.containsKey("maxEntitiesToBeSpawned") ? (int) data.get("maxEntitiesToBeSpawned") : 0; } private Integer integerFromObject(Object obj) { @@ -1080,6 +1095,15 @@ public Map getPotionEffectDelays() { return potionEffectDelays; } + @NotNull + public Set getEntitiesToSpawn() { + return entitiesToSpawn; + } + + public int getMaxEntitiesToBeSpawned() { + return maxEntitiesToBeSpawned; + } + private class TypeNotFoundException extends RuntimeException { public TypeNotFoundException(String s) { super(s); diff --git a/modules/api/src/main/java/net/countercraft/movecraft/utils/MathUtils.java b/modules/api/src/main/java/net/countercraft/movecraft/utils/MathUtils.java index 396975c54..f80bf1f8d 100644 --- a/modules/api/src/main/java/net/countercraft/movecraft/utils/MathUtils.java +++ b/modules/api/src/main/java/net/countercraft/movecraft/utils/MathUtils.java @@ -24,6 +24,9 @@ import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; +import java.util.ArrayList; +import java.util.Random; + public class MathUtils { @@ -170,4 +173,22 @@ public static int positiveMod(int mod, int divisor) { } return mod; } + + /** + * Returns a random integer between two integers + * @param min the lowest permitted number + * @param max the highest permitted number + * @return a random number between min and max + */ + public static int randomInteger(int min, int max){ + ArrayList integers = new ArrayList<>(); + for (int i = min ; i <= max ; i++){ + integers.add(i); + } + int bound = max - min; + Random random = new Random(); + int r = random.nextInt(bound); + + return integers.get(r); + } } From 4b276dd8865f0b253d8a0c234c87b16e29f93630 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Thu, 27 Jun 2019 13:23:04 +0200 Subject: [PATCH 022/304] Added files not added to Git --- .../movecraft/MovecraftLocation.java | 105 ++++++++++++++++++ .../movecraft/MovecraftRepair.java | 29 +++++ .../countercraft/movecraft/RegionUtils.java | 8 ++ .../net/countercraft/movecraft/Rotation.java | 22 ++++ .../countercraft/movecraft/WorldHandler.java | 19 ++++ .../movecraft/SolidHitBoxTest.java | 74 ++++++++++++ 6 files changed, 257 insertions(+) create mode 100644 modules/api/src/main/java/net/countercraft/movecraft/MovecraftLocation.java create mode 100644 modules/api/src/main/java/net/countercraft/movecraft/MovecraftRepair.java create mode 100644 modules/api/src/main/java/net/countercraft/movecraft/RegionUtils.java create mode 100644 modules/api/src/main/java/net/countercraft/movecraft/Rotation.java create mode 100644 modules/api/src/main/java/net/countercraft/movecraft/WorldHandler.java create mode 100644 modules/api/src/test/net/countercraft/movecraft/SolidHitBoxTest.java diff --git a/modules/api/src/main/java/net/countercraft/movecraft/MovecraftLocation.java b/modules/api/src/main/java/net/countercraft/movecraft/MovecraftLocation.java new file mode 100644 index 000000000..b071b3240 --- /dev/null +++ b/modules/api/src/main/java/net/countercraft/movecraft/MovecraftLocation.java @@ -0,0 +1,105 @@ +/* + * This file is part of Movecraft. + * + * Movecraft is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Movecraft is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Movecraft. If not, see . + */ + +package net.countercraft.movecraft; + +import org.bukkit.Location; +import org.bukkit.World; +import org.bukkit.util.Vector; +import org.jetbrains.annotations.NotNull; + +/** + * Represents a Block aligned coordinate triplet. + */ +final public class MovecraftLocation implements Comparable { + private final int x, y, z; + + public MovecraftLocation(int x, int y, int z) { + this.x = x; + this.y = y; + this.z = z; + } + + public int getX() { + return x; + } + + public int getY() { + return y; + } + + public int getZ() { + return z; + } + + /** + * Returns a MovecraftLocation that has undergone the given translation. + *

+ * This does not change the MovecraftLocation that it is called upon and that should be accounted for in terms of Garbage Collection. + * + * @param dx - X translation + * @param dy - Y translation + * @param dz - Z translation + * @return New MovecraftLocation shifted by specified amount + */ + public MovecraftLocation translate(int dx, int dy, int dz) { + return new MovecraftLocation(x + dx, y + dy, z + dz); + } + + @Override + public boolean equals(Object o) { + if (o instanceof MovecraftLocation) { + MovecraftLocation location = (MovecraftLocation) o; + return location.x==this.x && location.y==this.y && location.z == this.z; + } + return false; + } + + @Override + public int hashCode() { + return (x ^ (z << 12)) ^ (y << 24); + } + + public MovecraftLocation add(MovecraftLocation l) { + return new MovecraftLocation(getX() + l.getX(), getY() + l.getY(), getZ() + l.getZ()); + } + + public MovecraftLocation subtract(MovecraftLocation l) { + return new MovecraftLocation(getX() - l.getX(), getY() - l.getY(), getZ() - l.getZ()); + } + + public Location toBukkit(World world){ + return new Location(world, this.x, this.y, this.z); + } + + public static Location toBukkit(World world, MovecraftLocation location){ + return new Location(world, location.x, location.y, location.z); + } + public static MovecraftLocation fromVector(Vector vector){ + return new MovecraftLocation(vector.getBlockX(),vector.getBlockY(),vector.getBlockZ()); + } + + @Override + public String toString(){ + return "(" + x + "," + y + "," + z +")"; + } + + @Override + public int compareTo(@NotNull MovecraftLocation o) { + return getX() - o.getX() + getY() - o.getY() + getZ() - o.getZ(); + } +} diff --git a/modules/api/src/main/java/net/countercraft/movecraft/MovecraftRepair.java b/modules/api/src/main/java/net/countercraft/movecraft/MovecraftRepair.java new file mode 100644 index 000000000..d9ac1e545 --- /dev/null +++ b/modules/api/src/main/java/net/countercraft/movecraft/MovecraftRepair.java @@ -0,0 +1,29 @@ +package net.countercraft.movecraft; + +import com.sk89q.worldedit.extent.clipboard.Clipboard; +import com.sk89q.worldguard.protection.regions.ProtectedRegion; +import net.countercraft.movecraft.craft.Craft; +import net.countercraft.movecraft.utils.Pair; +import org.bukkit.Material; +import org.bukkit.World; +import org.bukkit.block.Sign; +import org.bukkit.plugin.Plugin; +import org.bukkit.util.Vector; + +import java.util.ArrayDeque; +import java.util.HashMap; + +public abstract class MovecraftRepair { + public abstract boolean saveCraftRepairState(Craft craft, Sign sign, Plugin plugin, String repairStateName); + public abstract boolean saveRegionRepairState(Plugin plugin, World world, ProtectedRegion region); + public abstract Clipboard loadCraftRepairStateClipboard(Plugin plugin, Craft craft, Sign sign, String repairStateName, World bukkitWorld); + public abstract Clipboard loadRegionRepairStateClipboard(Plugin plugin, String repairStateName, World bukkitWorld); + public abstract HashMap getMissingBlocks(String repairName); + public abstract ArrayDeque> getMissingBlockLocations(String repairName); + public abstract long getNumDiffBlocks(String repairName); + public abstract org.bukkit.util.Vector getDistance(String repairName); + public abstract org.bukkit.util.Vector getOffset(String repairName); + + + +} diff --git a/modules/api/src/main/java/net/countercraft/movecraft/RegionUtils.java b/modules/api/src/main/java/net/countercraft/movecraft/RegionUtils.java new file mode 100644 index 000000000..bf3935869 --- /dev/null +++ b/modules/api/src/main/java/net/countercraft/movecraft/RegionUtils.java @@ -0,0 +1,8 @@ +package net.countercraft.movecraft; + +import com.sk89q.worldguard.protection.regions.ProtectedRegion; +import org.bukkit.util.Vector; + +public abstract class RegionUtils { + public abstract Vector getRegionPoint(ProtectedRegion region, boolean minPoint); +} diff --git a/modules/api/src/main/java/net/countercraft/movecraft/Rotation.java b/modules/api/src/main/java/net/countercraft/movecraft/Rotation.java new file mode 100644 index 000000000..e12d74a0a --- /dev/null +++ b/modules/api/src/main/java/net/countercraft/movecraft/Rotation.java @@ -0,0 +1,22 @@ +/* + * This file is part of Movecraft. + * + * Movecraft is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Movecraft is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Movecraft. If not, see . + */ + +package net.countercraft.movecraft; + +public enum Rotation { + CLOCKWISE, NONE, ANTICLOCKWISE +} diff --git a/modules/api/src/main/java/net/countercraft/movecraft/WorldHandler.java b/modules/api/src/main/java/net/countercraft/movecraft/WorldHandler.java new file mode 100644 index 000000000..4c81c798b --- /dev/null +++ b/modules/api/src/main/java/net/countercraft/movecraft/WorldHandler.java @@ -0,0 +1,19 @@ +package net.countercraft.movecraft; + +import net.countercraft.movecraft.craft.Craft; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; + +public abstract class WorldHandler { + public abstract void rotateCraft(@NotNull Craft craft, @NotNull MovecraftLocation originLocation, @NotNull Rotation rotation); + public abstract void translateCraft(@NotNull Craft craft, @NotNull MovecraftLocation newLocation); + public abstract void setBlockFast(@NotNull Location location, @NotNull Material material, byte data); + public abstract void setBlockFast(@NotNull Location location, @NotNull Rotation rotation, @NotNull Material material, byte data); + public abstract void disableShadow(@NotNull Material type); + public void addPlayerLocation(Player player, double x, double y, double z, float yaw, float pitch){ + Location playerLoc = player.getLocation(); + player.teleport(new Location(player.getWorld(), x + playerLoc.getX(),y + playerLoc.getY(),z + playerLoc.getZ(),yaw + playerLoc.getYaw(),pitch + playerLoc.getPitch())); + } +} diff --git a/modules/api/src/test/net/countercraft/movecraft/SolidHitBoxTest.java b/modules/api/src/test/net/countercraft/movecraft/SolidHitBoxTest.java new file mode 100644 index 000000000..0a6930b4e --- /dev/null +++ b/modules/api/src/test/net/countercraft/movecraft/SolidHitBoxTest.java @@ -0,0 +1,74 @@ +package net.countercraft.movecraft; + +import net.countercraft.movecraft.utils.HitBox; +import net.countercraft.movecraft.utils.SolidHitBox; +import org.junit.Test; + +import java.util.ArrayList; +import java.util.List; + +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.containsInAnyOrder; +import static org.hamcrest.Matchers.iterableWithSize; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertIterableEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + + +public class SolidHitBoxTest { + + final private MovecraftLocation minimum = new MovecraftLocation(0,0,0); + final private MovecraftLocation maximum = new MovecraftLocation(3,3,3); + final private HitBox hitBox = new SolidHitBox(minimum, maximum); + + @Test + public void testBounds(){ + assertEquals(minimum.getX(), hitBox.getMinX()); + assertEquals(minimum.getY(), hitBox.getMinY()); + assertEquals(minimum.getZ(), hitBox.getMinZ()); + assertEquals(maximum.getX(), hitBox.getMaxX()); + assertEquals(maximum.getY(), hitBox.getMaxY()); + assertEquals(maximum.getZ(), hitBox.getMaxZ()); + } + + @Test + public void testSize(){ + assertEquals(64, hitBox.size()); + assertThat(hitBox, iterableWithSize(64)); + } + + + @Test + public void testContents(){ + final List locations = new ArrayList<>(64); + for(int x = minimum.getX(); x <= maximum.getX(); x++){ + for(int y = minimum.getY(); y <= maximum.getY(); y++){ + for(int z = minimum.getX(); z <= maximum.getY(); z++){ + locations.add(new MovecraftLocation(x,y,z)); + } + } + } + assertThat(locations,containsInAnyOrder(hitBox.asSet().toArray())); + } + + @Test + public void testBoundingHitBox(){ + assertIterableEquals(hitBox, hitBox.boundingHitBox()); + } + + @Test + public void testContainsAll(){ + final List locations = new ArrayList<>(64); + for(int x = minimum.getX(); x <= maximum.getX(); x++){ + for(int y = minimum.getY(); y <= maximum.getY(); y++){ + for(int z = minimum.getX(); z <= maximum.getY(); z++){ + locations.add(new MovecraftLocation(x,y,z)); + } + } + } + assertTrue(hitBox.containsAll(locations)); + } + + + +} From 27d504eb01f615df7680861aeff1473ccb3304b0 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Fri, 28 Jun 2019 16:29:29 +0200 Subject: [PATCH 023/304] Re-added Gravity, blocking sink on no PvP and improved multi-targeting on remote sign --- .../movecraft/async/AsyncManager.java | 5 +- .../async/translation/TranslationTask.java | 58 +++++++++++- .../movecraft/listener/BlockListener.java | 4 +- .../movecraft/sign/RemoteSign.java | 89 +++++++++++-------- .../movecraft/sign/StatusSign.java | 6 +- .../movecraft/utils/WorldguardUtils.java | 7 +- 6 files changed, 121 insertions(+), 48 deletions(-) diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java index bc224286d..276eb8ea3 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java @@ -21,8 +21,6 @@ import com.google.common.collect.Lists; import com.sk89q.worldguard.bukkit.WorldGuardPlugin; import com.sk89q.worldguard.protection.ApplicableRegionSet; -import com.sk89q.worldguard.protection.flags.Flags; -import com.sk89q.worldguard.protection.flags.StateFlag; import com.sk89q.worldguard.protection.managers.RegionManager; import com.sk89q.worldguard.protection.regions.ProtectedRegion; import net.countercraft.movecraft.Movecraft; @@ -41,6 +39,7 @@ import net.countercraft.movecraft.utils.CollectionUtils; import net.countercraft.movecraft.utils.HashHitBox; import net.countercraft.movecraft.utils.LegacyUtils; +import net.countercraft.movecraft.utils.WorldguardUtils; import org.bukkit.*; import org.bukkit.block.Block; import org.bukkit.block.BlockFace; @@ -582,7 +581,7 @@ private void detectSinking(){ for (MovecraftLocation location : pcraft.getHitBox()){ ApplicableRegionSet regions = regionManager.getApplicableRegions(location.toBukkit(pcraft.getW())); for (ProtectedRegion pr : regions.getRegions()){ - if (pr.getFlag(Flags.PVP).equals(StateFlag.State.DENY)){ + if (!WorldguardUtils.pvpAllowed(pr)){ region = pr; break; } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java index ee43a7f02..b2ed7cda1 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java @@ -13,10 +13,7 @@ import net.countercraft.movecraft.utils.HitBox; import net.countercraft.movecraft.utils.LegacyUtils; import net.countercraft.movecraft.utils.MutableHitBox; -import org.bukkit.Bukkit; -import org.bukkit.Location; -import org.bukkit.Material; -import org.bukkit.Sound; +import org.bukkit.*; import org.bukkit.block.Block; import org.bukkit.block.Chest; import org.bukkit.block.Furnace; @@ -218,6 +215,59 @@ public void run() { dy = 0; dy -= 1; } + } if (craft.getType().getUseGravity()){ + boolean supported = false; + boolean inclined = false; + World w = craft.getW(); + for (MovecraftLocation ml : oldHitBox){ + if (ml.getY() > minY){ + continue; + } + Location loc = ml.toBukkit(craft.getW()); + if (!w.getBlockAt(loc).getRelative(0,-1,0).getType().name().endsWith("AIR") && !craft.getType().getPassthroughBlocks().contains(w.getBlockAt(loc).getRelative(0,-1,0).getType())){ + supported = true; + break; + } + } + int minX = oldHitBox.getMinX(); + int maxX = oldHitBox.getMaxX(); + int minZ = oldHitBox.getMinZ(); + int maxZ = oldHitBox.getMaxZ(); + Block collisionBlock = null; + if (dx > 0){ + for (int z = minZ; z <= maxZ ; z++){ + collisionBlock = w.getBlockAt(maxX + dx,minY,z); + } + } + if (dx < 0){ + for (int z = minZ; z <= maxZ ; z++){ + collisionBlock = w.getBlockAt(minX + dx,minY,z); + } + } + if (dz > 0){ + for (int x = minX; x <= maxX ; x++){ + collisionBlock = w.getBlockAt(x,minY,maxZ+dz); + } + } + if (dz < 0){ + for (int x = minX; x <= maxX ; x++){ + collisionBlock = w.getBlockAt(x,minY,minZ+dz); + } + } + if (collisionBlock != null){ + if (!collisionBlock.getType().name().endsWith("AIR") && !craft.getType().getPassthroughBlocks().contains(collisionBlock.getType())){ + inclined = true; + } + + } + Movecraft.getInstance().getLogger().info("supported: " + supported); + if (!supported){ + dy = -1; + } + if (inclined){ + dy = 1; + } + } //Fail the movement if the craft is too high diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/BlockListener.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/BlockListener.java index e3c717dc2..ad4922d26 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/BlockListener.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/BlockListener.java @@ -323,7 +323,9 @@ public void explodeEvent(EntityExplodeEvent e) { (new Random(b.getX() + b.getY() + b.getZ() + (System.currentTimeMillis() >> 12))) .nextInt(100) < Settings.DurabilityOverride.get(b.getType())); } - AssaultUtils.processAssault(e); + if (Settings.AssaultEnable) { + AssaultUtils.processAssault(e); + } if (e.getEntity() == null) return; for (Player p : e.getEntity().getWorld().getPlayers()) { diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RemoteSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RemoteSign.java index f731d7dc0..cddd58f21 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RemoteSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RemoteSign.java @@ -1,11 +1,12 @@ package net.countercraft.movecraft.sign; -import net.countercraft.movecraft.config.Settings; -import net.countercraft.movecraft.utils.MathUtils; +import net.countercraft.movecraft.Movecraft; import net.countercraft.movecraft.MovecraftLocation; +import net.countercraft.movecraft.config.Settings; import net.countercraft.movecraft.craft.Craft; import net.countercraft.movecraft.craft.CraftManager; import net.countercraft.movecraft.localisation.I18nSupport; +import net.countercraft.movecraft.utils.MathUtils; import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.block.Block; @@ -15,8 +16,8 @@ import org.bukkit.event.block.Action; import org.bukkit.event.block.SignChangeEvent; import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.scheduler.BukkitRunnable; -import java.util.LinkedHashMap; import java.util.LinkedList; public final class RemoteSign implements Listener{ @@ -87,7 +88,6 @@ public final void onSignClick(PlayerInteractEvent event) { return; } LinkedList foundLocations = new LinkedList(); - LinkedHashMap foundLocs = new LinkedHashMap<>(); boolean firstError = true; for (MovecraftLocation tloc : foundCraft.getHitBox()) { Block tb = event.getClickedBlock().getWorld().getBlockAt(tloc.getX(), tloc.getY(), tloc.getZ()); @@ -113,49 +113,66 @@ public final void onSignClick(PlayerInteractEvent event) { event.getPlayer().sendMessage(I18nSupport.getInternationalisedString("ERROR: Could not find target sign!")); return; } + new BukkitRunnable() + { + @Override + public void run() { - for (MovecraftLocation foundLoc : foundLocations) { - Block newBlock = event.getClickedBlock().getWorld().getBlockAt(foundLoc.getX(), foundLoc.getY(), foundLoc.getZ()); - Sign foundSign = (Sign) newBlock.getState(); - boolean inverted = false;//set to true if target name has an ! in front of the text - //check Remote sign if the target strings are inverted - for (String line : foundSign.getLines()){ - if (line == null) - continue; - if (!line.equals("!" + targetText)) - continue; - inverted = true; - break; - } - PlayerInteractEvent newEvent = null; + MovecraftLocation foundLoc = foundLocations.poll(); + Block newBlock = event.getClickedBlock().getWorld().getBlockAt(foundLoc.getX(), foundLoc.getY(), foundLoc.getZ()); + Sign foundSign = (Sign) newBlock.getState(); + boolean inverted = false;//set to true if target name has an ! in front of the text + //check Remote sign if the target strings are inverted + for (String line : foundSign.getLines()){ + if (line == null) + continue; + //if target line is prefixed with an exclamation point, it will invert the action of the Remote sign + if (!line.equals("!" + targetText)) + continue; + inverted = true; + break; + } + PlayerInteractEvent newEvent = null; - if (inverted) { - Action action = null; - if (event.getAction() == Action.RIGHT_CLICK_BLOCK){ - action = Action.LEFT_CLICK_BLOCK; - } else if (event.getAction() == Action.LEFT_CLICK_BLOCK){ - action = Action.RIGHT_CLICK_BLOCK; + //Now invert the action to the opposite one if set to invert + if (inverted) { + Action action = null; + if (event.getAction() == Action.RIGHT_CLICK_BLOCK){ + action = Action.LEFT_CLICK_BLOCK; + } else if (event.getAction() == Action.LEFT_CLICK_BLOCK){ + action = Action.RIGHT_CLICK_BLOCK; + } + if (action != null){ + newEvent = new PlayerInteractEvent(event.getPlayer(), action, event.getItem(), newBlock, event.getBlockFace()); + } + } + //Otherwise use the same action as on the clicked remote sign + else { + newEvent = new PlayerInteractEvent(event.getPlayer(), event.getAction(), event.getItem(), newBlock, event.getBlockFace()); } - if (action != null){ - newEvent = new PlayerInteractEvent(event.getPlayer(), action, event.getItem(), newBlock, event.getBlockFace()); + //TODO: DON'T DO THIS + Bukkit.getServer().getPluginManager().callEvent(newEvent); + if (foundLocations.isEmpty()){ + cancel(); } - } else { - newEvent = new PlayerInteractEvent(event.getPlayer(), event.getAction(), event.getItem(), newBlock, event.getBlockFace()); } - //TODO: DON'T DO THIS - Bukkit.getServer().getPluginManager().callEvent(newEvent); - } + + + }.runTaskTimer(Movecraft.getInstance(),0,11); event.setCancelled(true); } private boolean isEqualSign(Sign test, String target) { - if (target.charAt(0) == '!'){ - target = target.substring(1); - } - return !ChatColor.stripColor(test.getLine(0)).equalsIgnoreCase(HEADER) && ( ChatColor.stripColor(test.getLine(0)).equalsIgnoreCase(target) + + return !ChatColor.stripColor(test.getLine(0)).equalsIgnoreCase(HEADER) && ( + ChatColor.stripColor(test.getLine(0)).equalsIgnoreCase(target) || ChatColor.stripColor(test.getLine(1)).equalsIgnoreCase(target) || ChatColor.stripColor(test.getLine(2)).equalsIgnoreCase(target) - || ChatColor.stripColor(test.getLine(3)).equalsIgnoreCase(target)); + || ChatColor.stripColor(test.getLine(3)).equalsIgnoreCase(target) + ||ChatColor.stripColor(test.getLine(0)).equalsIgnoreCase("!"+target) + || ChatColor.stripColor(test.getLine(1)).equalsIgnoreCase("!"+target) + || ChatColor.stripColor(test.getLine(2)).equalsIgnoreCase("!"+target) + || ChatColor.stripColor(test.getLine(3)).equalsIgnoreCase("!"+target)); } private boolean isForbidden(Sign test) { for (int i = 0; i < 4; i++) { diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/StatusSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/StatusSign.java index 12f1a03f1..32346e7b8 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/StatusSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/StatusSign.java @@ -49,9 +49,9 @@ public final void onSignTranslate(SignTranslateEvent event) { Map foundBlocks = new HashMap<>(); for (MovecraftLocation ml : craft.getHitBox()) { Material blockType = craft.getW().getBlockAt(ml.getX(), ml.getY(), ml.getZ()).getType(); - + Integer count = foundBlocks.get(blockType); if (foundBlocks.containsKey(blockType)) { - foundBlocks.merge(blockType, 1, (a, b) -> a + b); + foundBlocks.put(blockType, count + 1); } else { foundBlocks.put(blockType, 1); } @@ -78,7 +78,7 @@ public final void onSignTranslate(SignTranslateEvent event) { int signLine=1; int signColumn=0; for(Map> alFlyBlock : craft.getType().getFlyBlocks().keySet()) { - Material flyBlock = alFlyBlock.keySet().iterator().next(); + Material flyBlock = (Material) alFlyBlock.keySet().toArray()[0]; Double minimum=craft.getType().getFlyBlocks().get(alFlyBlock).get(0); if(foundBlocks.containsKey(flyBlock) && minimum>0) { // if it has a minimum, it should be considered for sinking consideration int amount=foundBlocks.get(flyBlock); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/WorldguardUtils.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/WorldguardUtils.java index d71a57362..2164318e9 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/WorldguardUtils.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/WorldguardUtils.java @@ -51,7 +51,12 @@ public static String getRegionOwnerList(ProtectedRegion tRegion) { } return output.toString(); } - + public static boolean pvpAllowed(ProtectedRegion region){ + if (Settings.IsLegacy) { + return region.getFlag(DefaultFlag.PVP).equals(StateFlag.State.ALLOW); + } + return region.getFlag(Flags.PVP).equals(StateFlag.State.ALLOW); + } public static boolean canBuild(World world, MovecraftLocation location, Player player){ return Movecraft.getInstance().getWorldGuardPlugin().canBuild(player, location.toBukkit(world)); } From 60b0ce82c1764cdc4404b54da21bc98894e6fc1c Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Fri, 28 Jun 2019 17:30:03 +0200 Subject: [PATCH 024/304] Fixed a revert occurring after upstream changes were implemented --- .../async/translation/TranslationTask.java | 79 ++++++++++--------- 1 file changed, 42 insertions(+), 37 deletions(-) diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java index e6a79dd34..c547dfb3b 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java @@ -3,6 +3,7 @@ import net.countercraft.movecraft.Movecraft; import net.countercraft.movecraft.MovecraftLocation; import net.countercraft.movecraft.async.AsyncTask; +import net.countercraft.movecraft.config.Settings; import net.countercraft.movecraft.craft.Craft; import net.countercraft.movecraft.craft.CraftManager; import net.countercraft.movecraft.events.CraftTranslateEvent; @@ -69,7 +70,7 @@ protected void execute() { int testY = minY; while (testY > 0){ testY -= 1; - if (craft.getW().getBlockTypeIdAt(middle.getX(),testY,middle.getZ()) != 0) + if (!craft.getW().getBlockAt(middle.getX(),testY,middle.getZ()).getType().name().endsWith("AIR")) break; } if (minY - testY > craft.getType().getMaxHeightAboveGround()) { @@ -227,10 +228,10 @@ protected void execute() { } Player player = (Player) entity; craft.getMovedPlayers().put(player, System.currentTimeMillis()); - EntityUpdateCommand eUp = new EntityUpdateCommand(entity, dx, dy, dz, 0, 0); + EntityMoveUpdateCommand eUp = new EntityMoveUpdateCommand(entity, dx, dy, dz, 0, 0); updates.add(eUp); } else if (!craft.getType().getOnlyMovePlayers() || entity.getType() == EntityType.PRIMED_TNT) { - EntityUpdateCommand eUp = new EntityUpdateCommand(entity, dx, dy, dz, 0, 0); + EntityMoveUpdateCommand eUp = new EntityMoveUpdateCommand(entity, dx, dy, dz, 0, 0); updates.add(eUp); } } @@ -261,7 +262,7 @@ private void fail(String message) { craft.getW().playSound(location, Sound.BLOCK_ANVIL_LAND, 1.0f, 0.25f); //craft.setCurTickCooldown(craft.getType().getCruiseTickCooldown()); } else { - craft.getW().playSound(location, Sound.ENTITY_IRONGOLEM_DEATH, 5.0f, 5.0f); + craft.getW().playSound(location, Settings.IsLegacy ? Sound.valueOf("ENTITY_IRONGOLEM_DEATH") :Sound.ENTITY_IRON_GOLEM_DEATH, 5.0f, 5.0f); //craft.setCurTickCooldown(craft.getType().getCruiseTickCooldown()); } } @@ -300,11 +301,11 @@ private void captureYield(List harvestedBlocks) { Block block = craft.getW().getBlockAt(harvestedBlock.getX(), harvestedBlock.getY(), harvestedBlock.getZ()); List drops = new ArrayList<>(block.getDrops()); //generate seed drops - if (block.getType() == Material.CROPS) { + if (block.getType() == Material.WHEAT) { Random rand = new Random(); int amount = rand.nextInt(4); if (amount > 0) { - ItemStack seeds = new ItemStack(Material.SEEDS, amount); + ItemStack seeds = new ItemStack(Material.WHEAT_SEEDS, amount); drops.add(seeds); } } @@ -367,40 +368,44 @@ private boolean checkFuel(){ craft.setBurningFuel(craft.getBurningFuel() - fuelBurnRate); return true; } - Block fuelHolder = null; - for (MovecraftLocation bTest : oldHitBox) { - Block b = craft.getW().getBlockAt(bTest.getX(), bTest.getY(), bTest.getZ()); - if (b.getTypeId() == 61) { - InventoryHolder inventoryHolder = (InventoryHolder) b.getState(); - if (inventoryHolder.getInventory().contains(263) || inventoryHolder.getInventory().contains(173)) { - fuelHolder = b; + new BukkitRunnable() { + @Override + public void run() { + Block fuelHolder = null; + for (MovecraftLocation bTest : oldHitBox) { + Block b = craft.getW().getBlockAt(bTest.getX(), bTest.getY(), bTest.getZ()); + if (b.getType() == Material.FURNACE) { + InventoryHolder inventoryHolder = (InventoryHolder) b.getState(); + for (Material fuel : Settings.FuelTypes.keySet()){ + if (inventoryHolder.getInventory().contains(fuel)) { + fuelHolder = b; + } + } + + } + } + if (fuelHolder == null) { + fail(I18nSupport.getInternationalisedString("Translation - Failed Craft out of fuel")); + return; + } + InventoryHolder inventoryHolder = (InventoryHolder) fuelHolder.getState(); + for (Material fuel : Settings.FuelTypes.keySet()){ + if (inventoryHolder.getInventory().contains(fuel)) { + ItemStack iStack = inventoryHolder.getInventory().getItem(inventoryHolder.getInventory().first(fuel)); + int amount = iStack.getAmount(); + if (amount == 1) { + inventoryHolder.getInventory().remove(iStack); + } else { + iStack.setAmount(amount - 1); + } + craft.setBurningFuel(craft.getBurningFuel() + Settings.FuelTypes.get(fuel)); + } } } - } - if (fuelHolder == null) { - fail(I18nSupport.getInternationalisedString("Translation - Failed Craft out of fuel")); - return false; - } - InventoryHolder inventoryHolder = (InventoryHolder) fuelHolder.getState(); - if (inventoryHolder.getInventory().contains(263)) { - ItemStack iStack = inventoryHolder.getInventory().getItem(inventoryHolder.getInventory().first(263)); - int amount = iStack.getAmount(); - if (amount == 1) { - inventoryHolder.getInventory().remove(iStack); - } else { - iStack.setAmount(amount - 1); - } - craft.setBurningFuel(craft.getBurningFuel() + 7.0); - } else { - ItemStack iStack = inventoryHolder.getInventory().getItem(inventoryHolder.getInventory().first(173)); - int amount = iStack.getAmount(); - if (amount == 1) { - inventoryHolder.getInventory().remove(iStack); - } else { - iStack.setAmount(amount - 1); - } - craft.setBurningFuel(craft.getBurningFuel() + 79.0); + }.runTask(Movecraft.getInstance()); + if (failed){ + return false; } return true; } From c26e1c90871d65c0bb3e2040e2317086539afb91 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Fri, 28 Jun 2019 20:02:30 +0200 Subject: [PATCH 025/304] Fixed a revert occurring after upstream changes were implemented --- .../async/translation/TranslationTask.java | 115 +++++++++--------- 1 file changed, 55 insertions(+), 60 deletions(-) diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java index c547dfb3b..50cfd3970 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java @@ -18,6 +18,7 @@ import org.bukkit.Sound; import org.bukkit.block.Block; import org.bukkit.block.Chest; +import org.bukkit.block.Furnace; import org.bukkit.entity.Entity; import org.bukkit.entity.EntityType; import org.bukkit.entity.Player; @@ -50,7 +51,6 @@ public TranslationTask(Craft c, int dx, int dy, int dz) { @Override protected void execute() { - //Check if theres anything to move if(oldHitBox.isEmpty()){ return; @@ -59,6 +59,7 @@ protected void execute() { fail(I18nSupport.getInternationalisedString("Craft is disabled!")); return; } + final int minY = oldHitBox.getMinY(); final int maxY = oldHitBox.getMaxY(); @@ -88,9 +89,59 @@ protected void execute() { } //TODO: Check fuel - if (!checkFuel()) { - fail(I18nSupport.getInternationalisedString("Translation - Failed Craft out of fuel")); - return; + if (craft.getType().getFuelBurnRate() > 0.0) { + new BukkitRunnable() { + @Override + public void run() { + // check for fuel, burn some from a furnace if needed. Blocks of coal are supported, in addition to coal and charcoal + double fuelBurnRate = craft.getType().getFuelBurnRate(); + // going down doesn't require fuel + if (dy == -1 && dx == 0 && dz == 0) + fuelBurnRate = 0.0; + if (dy > 0) + fuelBurnRate *= 2; + if (fuelBurnRate == 0.0 || craft.getSinking()) { + return; + } + if (craft.getBurningFuel() >= fuelBurnRate) { + craft.setBurningFuel(craft.getBurningFuel() - fuelBurnRate); + return; + } + Block fuelHolder = null; + for (MovecraftLocation bTest : craft.getHitBox()) { + Block b = craft.getW().getBlockAt(bTest.getX(), bTest.getY(), bTest.getZ()); + //Get all fuel holders + if (b.getType() == Material.FURNACE) { + InventoryHolder holder = (InventoryHolder) b.getState(); + for (Material fuel : Settings.FuelTypes.keySet()) { + if (holder.getInventory().contains(fuel)) { + fuelHolder = b; + break; + } + } + } + if (fuelHolder != null) break; + + } + if (fuelHolder == null) { + fail(I18nSupport.getInternationalisedString("Translation - Failed Craft out of fuel")); + return; + } + Furnace furnace = (Furnace) fuelHolder.getState(); + for (Material fuel : Settings.FuelTypes.keySet()) { + if (furnace.getInventory().contains(fuel)) { + ItemStack item = furnace.getInventory().getItem(furnace.getInventory().first(fuel)); + int amount = item.getAmount(); + if (amount == 1) { + furnace.getInventory().remove(item); + } else { + item.setAmount(amount - 1); + } + craft.setBurningFuel(craft.getBurningFuel() + Settings.FuelTypes.get(item.getType())); + } + } + } + }.runTask(Movecraft.getInstance()); } //TODO: Add and handle event for towny and factions @@ -354,62 +405,6 @@ private ItemStack putInToChests(ItemStack stack, ArrayList inventorie return stack; } - private boolean checkFuel(){ - // check for fuel, burn some from a furnace if needed. Blocks of coal are supported, in addition to coal and charcoal - double fuelBurnRate = craft.getType().getFuelBurnRate(); - // going down doesn't require fuel - if (dy == -1 && dx == 0 && dz == 0) - fuelBurnRate = 0.0; - - if (fuelBurnRate == 0.0 || craft.getSinking()) { - return true; - } - if (craft.getBurningFuel() >= fuelBurnRate) { - craft.setBurningFuel(craft.getBurningFuel() - fuelBurnRate); - return true; - } - new BukkitRunnable() { - @Override - public void run() { - Block fuelHolder = null; - for (MovecraftLocation bTest : oldHitBox) { - Block b = craft.getW().getBlockAt(bTest.getX(), bTest.getY(), bTest.getZ()); - if (b.getType() == Material.FURNACE) { - InventoryHolder inventoryHolder = (InventoryHolder) b.getState(); - for (Material fuel : Settings.FuelTypes.keySet()){ - if (inventoryHolder.getInventory().contains(fuel)) { - fuelHolder = b; - } - } - - } - } - if (fuelHolder == null) { - fail(I18nSupport.getInternationalisedString("Translation - Failed Craft out of fuel")); - return; - } - InventoryHolder inventoryHolder = (InventoryHolder) fuelHolder.getState(); - for (Material fuel : Settings.FuelTypes.keySet()){ - if (inventoryHolder.getInventory().contains(fuel)) { - ItemStack iStack = inventoryHolder.getInventory().getItem(inventoryHolder.getInventory().first(fuel)); - int amount = iStack.getAmount(); - if (amount == 1) { - inventoryHolder.getInventory().remove(iStack); - } else { - iStack.setAmount(amount - 1); - } - craft.setBurningFuel(craft.getBurningFuel() + Settings.FuelTypes.get(fuel)); - } - } - } - - }.runTask(Movecraft.getInstance()); - if (failed){ - return false; - } - return true; - } - public boolean failed(){ return failed; } From 1ccc0cdcdb36d8ea16587db0b4cc11527f49708d Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Sat, 29 Jun 2019 00:01:03 +0200 Subject: [PATCH 026/304] Revert "Re-added Gravity, blocking sink on no PvP and improved multi-targeting on remote sign" This reverts commit 27d504eb01f615df7680861aeff1473ccb3304b0. --- .../movecraft/async/AsyncManager.java | 290 ++++++++++++------ .../async/translation/TranslationTask.java | 223 ++++++++++---- .../movecraft/utils/LegacyWEUtils.java | 25 ++ .../warfare/assault/AssaultTask.java | 11 +- .../warfare/assault/AssaultUtils.java | 67 ++++ .../movecraft/utils/LegacyUtils.java | 1 - 6 files changed, 465 insertions(+), 152 deletions(-) diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java index f71626199..3da1494d0 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java @@ -19,10 +19,15 @@ import at.pavlov.cannons.cannon.Cannon; import com.google.common.collect.Lists; +import com.sk89q.worldguard.bukkit.WorldGuardPlugin; +import com.sk89q.worldguard.protection.ApplicableRegionSet; +import com.sk89q.worldguard.protection.flags.Flags; +import com.sk89q.worldguard.protection.flags.StateFlag; +import com.sk89q.worldguard.protection.managers.RegionManager; +import com.sk89q.worldguard.protection.regions.ProtectedRegion; import net.countercraft.movecraft.Movecraft; import net.countercraft.movecraft.MovecraftLocation; import net.countercraft.movecraft.Rotation; -import net.countercraft.movecraft.WorldHandler; import net.countercraft.movecraft.async.detection.DetectionTask; import net.countercraft.movecraft.async.detection.DetectionTaskData; import net.countercraft.movecraft.async.rotation.RotationTask; @@ -35,11 +40,11 @@ import net.countercraft.movecraft.mapUpdater.MapUpdateManager; import net.countercraft.movecraft.utils.CollectionUtils; import net.countercraft.movecraft.utils.HashHitBox; -import net.countercraft.movecraft.utils.HitBox; +import net.countercraft.movecraft.utils.LegacyUtils; import org.bukkit.*; import org.bukkit.block.Block; +import org.bukkit.block.BlockFace; import org.bukkit.entity.Player; -import org.bukkit.entity.SmallFireball; import org.bukkit.entity.TNTPrimed; import org.bukkit.scheduler.BukkitRunnable; import org.bukkit.util.Vector; @@ -57,11 +62,7 @@ public class AsyncManager extends BukkitRunnable { private final HashMap> recentContactTracking = new HashMap<>(); private final BlockingQueue finishedAlgorithms = new LinkedBlockingQueue<>(); private final HashSet clearanceSet = new HashSet<>(); - private HashMap FireballTracking = new HashMap<>(); - private HashMap wrecks = new HashMap<>(); - private HashMap wreckWorlds = new HashMap<>(); - private HashMap> wreckPhases = new HashMap<>(); - + private HashMap FireballTracking = new HashMap<>(); private long lastTracerUpdate = 0; private long lastFireballCheck = 0; private long lastTNTContactCheck = 0; @@ -71,24 +72,49 @@ public class AsyncManager extends BukkitRunnable { public AsyncManager() { transparent = new HashSet<>(); + //These materials exists in both 1.12 and 1.13 APIs transparent.add(Material.AIR); transparent.add(Material.GLASS); - transparent.add(Material.THIN_GLASS); - transparent.add(Material.STAINED_GLASS); - transparent.add(Material.STAINED_GLASS_PANE); - transparent.add(Material.IRON_FENCE); transparent.add(Material.REDSTONE_WIRE); transparent.add(Material.IRON_TRAPDOOR); - transparent.add(Material.TRAP_DOOR); transparent.add(Material.NETHER_BRICK_STAIRS); transparent.add(Material.LEVER); transparent.add(Material.STONE_BUTTON); - transparent.add(Material.WOOD_BUTTON); - transparent.add(Material.STEP); - transparent.add(Material.SMOOTH_STAIRS); - transparent.add(Material.SIGN); - transparent.add(Material.SIGN_POST); - transparent.add(Material.WALL_SIGN); + + if (Settings.IsLegacy){ + transparent.add(LegacyUtils.THIN_GLASS); + transparent.add(LegacyUtils.STAINED_GLASS); + transparent.add(LegacyUtils.STAINED_GLASS_PANE); + transparent.add(LegacyUtils.IRON_FENCE); + transparent.add(LegacyUtils.TRAP_DOOR); + transparent.add(LegacyUtils.WOOD_BUTTON); + transparent.add(LegacyUtils.STEP); + transparent.add(LegacyUtils.SMOOTH_STAIRS); + transparent.add(LegacyUtils.SIGN_POST); + } else { + if (Settings.is1_14){ + transparent.add(Material.BIRCH_SIGN); + transparent.add(Material.OAK_SIGN); + transparent.add(Material.DARK_OAK_SIGN); + transparent.add(Material.JUNGLE_SIGN); + transparent.add(Material.SPRUCE_SIGN); + transparent.add(Material.ACACIA_SIGN); + transparent.add(Material.BIRCH_WALL_SIGN); + transparent.add(Material.OAK_WALL_SIGN); + transparent.add(Material.DARK_OAK_WALL_SIGN); + transparent.add(Material.JUNGLE_WALL_SIGN); + transparent.add(Material.SPRUCE_WALL_SIGN); + transparent.add(Material.ACACIA_WALL_SIGN); + } else { + transparent.add(Material.getMaterial("SIGN")); + transparent.add(Material.getMaterial("WALL_SIGN")); + } + transparent.add(Material.GLASS_PANE); + transparent.add(Material.BLACK_STAINED_GLASS_PANE); + transparent.add(Material.WHITE_STAINED_GLASS_PANE); + transparent.add(Material.GRAY_STAINED_GLASS_PANE); + transparent.add(Material.GREEN_STAINED_GLASS_PANE); + } } /* public static AsyncManager getInstance() { @@ -107,15 +133,6 @@ public void submitCompletedTask(AsyncTask task) { finishedAlgorithms.add(task); } - public void addWreck(Craft craft){ - if(craft.getCollapsedHitBox().isEmpty() || Settings.FadeWrecksAfter == 0){ - return; - } - wrecks.put(craft.getCollapsedHitBox(), System.currentTimeMillis()); - wreckWorlds.put(craft.getCollapsedHitBox(), craft.getW()); - wreckPhases.put(craft.getCollapsedHitBox(), craft.getPhaseBlocks()); - } - private void processAlgorithmQueue() { int runLength = 10; int queueLength = finishedAlgorithms.size(); @@ -195,6 +212,7 @@ private void processAlgorithmQueue() { c.getPhaseBlocks().put(location, Material.WATER); } } + } if (notifyP != null) { @@ -363,6 +381,7 @@ private void processCruise() { boolean bankLeft = false; boolean bankRight = false; boolean dive = false; + boolean climb = pcraft.isClimbing(); if (pcraft.getPilotLocked()) { if (pcraft.getNotificationPlayer().isSneaking()) dive = true; @@ -370,6 +389,7 @@ private void processCruise() { bankLeft = true; if (pcraft.getNotificationPlayer().getInventory().getHeldItemSlot() == 5) bankRight = true; + } if (Math.abs(ticksElapsed) < pcraft.getTickCooldown()) { @@ -380,11 +400,14 @@ private void processCruise() { int dy = 0; // ascend - if (pcraft.getCruiseDirection() == 0x42) { + if (pcraft.getCruiseDirection() == BlockFace.UP) { dy = 1 + pcraft.getType().getVertCruiseSkipBlocks(); } + else if (climb){ + dy = (1 + pcraft.getType().getCruiseSkipBlocks()) >> 1; + } // descend - if (pcraft.getCruiseDirection() == 0x43) { + if (pcraft.getCruiseDirection() == BlockFace.DOWN) { dy = 0 - 1 - pcraft.getType().getVertCruiseSkipBlocks(); if (pcraft.getHitBox().getMinY() <= w.getSeaLevel()) { dy = -1; @@ -396,7 +419,7 @@ private void processCruise() { } } // ship faces west - if (pcraft.getCruiseDirection() == 0x5) { + if (pcraft.getCruiseDirection() == BlockFace.WEST) { dx = 0 - 1 - pcraft.getType().getCruiseSkipBlocks(); if (bankRight) { dz = (0 - 1 - pcraft.getType().getCruiseSkipBlocks()) >> 1; @@ -404,9 +427,10 @@ private void processCruise() { if (bankLeft) { dz = (1 + pcraft.getType().getCruiseSkipBlocks()) >> 1; } + } // ship faces east - if (pcraft.getCruiseDirection() == 0x4) { + if (pcraft.getCruiseDirection() == BlockFace.EAST) { dx = 1 + pcraft.getType().getCruiseSkipBlocks(); if (bankLeft) { dz = (0 - 1 - pcraft.getType().getCruiseSkipBlocks()) >> 1; @@ -416,8 +440,8 @@ private void processCruise() { } } // ship faces north - if (pcraft.getCruiseDirection() == 0x2) { - dz = 1 + pcraft.getType().getCruiseSkipBlocks(); + if (pcraft.getCruiseDirection() == BlockFace.NORTH) { + dz = 0 - 1 - pcraft.getType().getCruiseSkipBlocks(); if (bankRight) { dx = (0 - 1 - pcraft.getType().getCruiseSkipBlocks()) >> 1; } @@ -426,8 +450,8 @@ private void processCruise() { } } // ship faces south - if (pcraft.getCruiseDirection() == 0x3) { - dz = 0 - 1 - pcraft.getType().getCruiseSkipBlocks(); + if (pcraft.getCruiseDirection() == BlockFace.SOUTH) { + dz = 1 + pcraft.getType().getCruiseSkipBlocks(); if (bankLeft) { dx = (0 - 1 - pcraft.getType().getCruiseSkipBlocks()) >> 1; } @@ -466,40 +490,39 @@ private void detectSinking(){ final World w = pcraft.getW(); int totalNonAirBlocks = 0; int totalNonAirWaterBlocks = 0; - HashMap, Integer> foundFlyBlocks = new HashMap<>(); - HashMap, Integer> foundMoveBlocks = new HashMap<>(); + HashMap>, Integer> foundFlyBlocks = new HashMap<>(); + HashMap>, Integer> foundMoveBlocks = new HashMap<>(); // go through each block in the blocklist, and // if its in the FlyBlocks, total up the number // of them for (MovecraftLocation l : pcraft.getHitBox()) { - int blockID = w.getBlockAt(l.getX(), l.getY(), l.getZ()).getTypeId(); - int dataID = (int) w.getBlockAt(l.getX(), l.getY(), l.getZ()).getData(); - int shiftedID = (blockID << 4) + dataID + 10000; - for (List flyBlockDef : pcraft.getType().getFlyBlocks().keySet()) { - if (flyBlockDef.contains(blockID) || flyBlockDef.contains(shiftedID)) { + Material blockType = w.getBlockAt(l.getX(), l.getY(), l.getZ()).getType(); + byte dataID = w.getBlockAt(l.getX(), l.getY(), l.getZ()).getData(); + for (Map> flyBlockDef : pcraft.getType().getFlyBlocks().keySet()) { + if ((flyBlockDef.containsKey(blockType) && flyBlockDef.get(blockType).isEmpty())|| (flyBlockDef.containsKey(blockType) && flyBlockDef.get(blockType).contains(dataID))) { foundFlyBlocks.merge(flyBlockDef, 1, (a, b) -> a + b); } } - for (List moveBlockDef : pcraft.getType().getMoveBlocks().keySet()) { - if (moveBlockDef.contains(blockID) || moveBlockDef.contains(shiftedID)) { + for (Map> moveBlockDef : pcraft.getType().getMoveBlocks().keySet()) { + if ((moveBlockDef.containsKey(blockType) && moveBlockDef.get(blockType).isEmpty())|| (moveBlockDef.containsKey(blockType) && moveBlockDef.get(blockType).contains(dataID))) { foundMoveBlocks.merge(moveBlockDef, 1, (a, b) -> a + b); } } - if (blockID != 0) { + if (blockType != Material.AIR) { totalNonAirBlocks++; } - if (blockID != 0 && blockID != 8 && blockID != 9) { + if (blockType != Material.AIR && blockType != Material.WATER && blockType != LegacyUtils.STATIONARY_WATER) { totalNonAirWaterBlocks++; } } - // now see if any of the resulting percentagesit + // now see if any of the resulting percentages // are below the threshold specified in // SinkPercent boolean isSinking = false; - for (List i : pcraft.getType().getFlyBlocks().keySet()) { + for (Map> i : pcraft.getType().getFlyBlocks().keySet()) { int numfound = 0; if (foundFlyBlocks.get(i) != null) { numfound = foundFlyBlocks.get(i); @@ -512,7 +535,7 @@ private void detectSinking(){ } } - for (List i : pcraft.getType().getMoveBlocks().keySet()) { + for (Map> i : pcraft.getType().getMoveBlocks().keySet()) { int numfound = 0; if (foundMoveBlocks.get(i) != null) { numfound = foundMoveBlocks.get(i); @@ -524,7 +547,7 @@ private void detectSinking(){ pcraft.setDisabled(true); if (pcraft.getNotificationPlayer() != null) { Location loc = pcraft.getNotificationPlayer().getLocation(); - pcraft.getW().playSound(loc, Sound.ENTITY_IRONGOLEM_DEATH, 5.0f, 5.0f); + pcraft.getW().playSound(loc, Settings.IsLegacy ? LegacyUtils.ENITIY_IRONGOLEM_DEATH : Sound.ENTITY_IRON_GOLEM_DEATH , 5.0f, 5.0f); } } } @@ -551,8 +574,30 @@ private void detectSinking(){ // if the craft is sinking, let the player // know and release the craft. Otherwise // update the time for the next check + Player notifyP = pcraft.getNotificationPlayer(); + if (Movecraft.getInstance().getWorldGuardPlugin() != null){ + WorldGuardPlugin wgPlugin = Movecraft.getInstance().getWorldGuardPlugin(); + ProtectedRegion region = null; + RegionManager regionManager = wgPlugin.getRegionManager(pcraft.getW()); + for (MovecraftLocation location : pcraft.getHitBox()){ + ApplicableRegionSet regions = regionManager.getApplicableRegions(location.toBukkit(pcraft.getW())); + for (ProtectedRegion pr : regions.getRegions()){ + if (pr.getFlag(Flags.PVP).equals(StateFlag.State.DENY)){ + region = pr; + break; + } + } + if (region != null){ + break; + } + } + if (region != null && Settings.WorldGuardBlockSinkOnPVPPerm){ + notifyP.sendMessage(I18nSupport.getInternationalisedString("Player- Craft should sink but PVP is not allowed in this WorldGuard region")); + isSinking = false; + } + } if (isSinking && pcraft.isNotProcessing()) { - Player notifyP = pcraft.getNotificationPlayer(); + if (notifyP != null) { notifyP.sendMessage(I18nSupport.getInternationalisedString("Player- Craft is sinking")); } @@ -622,7 +667,7 @@ private void processTracers() { new BukkitRunnable() { @Override public void run() { - fp.sendBlockChange(loc, 30, (byte) 0); + fp.sendBlockChange(loc, Settings.IsLegacy ? LegacyUtils.WEB :Material.COBWEB, (byte) 0); } }.runTaskLater(Movecraft.getInstance(), 5); // then remove it @@ -632,7 +677,7 @@ public void run() { // fp.sendBlockChange(loc, // fw.getBlockAt(loc).getType(), // fw.getBlockAt(loc).getData()); - fp.sendBlockChange(loc, 0, (byte) 0); + fp.sendBlockChange(loc, Material.AIR, (byte) 0); } }.runTaskLater(Movecraft.getInstance(), 160); } @@ -651,8 +696,8 @@ private void processFireballs() { if (ticksElapsed > 3) { for (World w : Bukkit.getWorlds()) { if (w != null) { - for (SmallFireball fireball : w - .getEntitiesByClass(SmallFireball.class)) { + for (org.bukkit.entity.SmallFireball fireball : w + .getEntitiesByClass(org.bukkit.entity.SmallFireball.class)) { if (!(fireball.getShooter() instanceof org.bukkit.entity.LivingEntity)) { // means // it // was @@ -678,7 +723,7 @@ private void processFireballs() { boolean inRange = (distX < 50) && (distY < 50) && (distZ < 50); if ((c.getAADirector() != null) && inRange) { p = c.getAADirector(); - if (p.getItemInHand().getTypeId() == Settings.PilotTool) { + if (p.getItemInHand().getType() == Settings.PilotTool) { Vector fv = fireball.getVelocity(); double speed = fv.length(); // store the speed to add it back in later, since all the values we will be using are "normalized", IE: have a speed of 1 fv = fv.normalize(); // you normalize it for comparison with the new direction to see if we are trying to steer too far @@ -732,9 +777,9 @@ private void processFireballs() { int timelimit = 20 * Settings.FireballLifespan * 50; // then, removed any exploded TNT from tracking - Iterator fireballI = FireballTracking.keySet().iterator(); + Iterator fireballI = FireballTracking.keySet().iterator(); while (fireballI.hasNext()) { - SmallFireball fireball = fireballI.next(); + org.bukkit.entity.SmallFireball fireball = fireballI.next(); if (fireball != null) if (System.currentTimeMillis() - FireballTracking.get(fireball) > timelimit) { fireball.remove(); @@ -746,6 +791,12 @@ private void processFireballs() { } } + private void processWaterlogging(){ + for (Craft c : CraftManager.getInstance()){ + + } + } + private Craft fastNearestCraftToLoc(Location loc) { Craft ret = null; long closestDistSquared = 1000000000L; @@ -788,7 +839,7 @@ private void processTNTContactExplosives() { boolean inRange = (distX < 100) && (distY < 100) && (distZ < 100); if ((c.getCannonDirector() != null) && inRange) { Player p = c.getCannonDirector(); - if (p.getInventory().getItemInMainHand().getTypeId() == Settings.PilotTool) { + if (p.getInventory().getItemInMainHand().getType() == Settings.PilotTool) { Vector tv = tnt.getVelocity(); double speed = tv.length(); // store the speed to add it back in later, since all the values we will be using are "normalized", IE: have a speed of 1 tv = tv.normalize(); // you normalize it for comparison with the new direction to see if we are trying to steer too far @@ -847,35 +898,95 @@ private void processTNTContactExplosives() { } } - private void processFadingBlocks() { + /*private void processFadingBlocks() { if (Settings.FadeWrecksAfter == 0) return; long ticksElapsed = (System.currentTimeMillis() - lastFadeCheck) / 50; - if (ticksElapsed <= 20) { - return; - } - List processed = new ArrayList<>(); - final WorldHandler handler = Movecraft.getInstance().getWorldHandler(); - for(Map.Entry entry : wrecks.entrySet()){ - if (entry.getValue() + Settings.FadeWrecksAfter <= System.currentTimeMillis()) { - continue; - } - final HitBox hitBox = entry.getKey(); - final Map phaseBlocks = wreckPhases.get(hitBox); - final World world = wreckWorlds.get(hitBox); - for (MovecraftLocation location : hitBox){ - handler.setBlockFast(location.toBukkit(world), phaseBlocks.getOrDefault(location, Material.AIR),(byte) 0); + if (ticksElapsed > 20) { + for (World w : Bukkit.getWorlds()) { + if (w != null) { + ArrayList updateCommands = new ArrayList<>(); + CopyOnWriteArrayList locations = null; + + // I know this is horrible, but I honestly don't see another + // way to do this... + int numTries = 0; + while ((locations == null) && (numTries < 100)) { + try { + locations = new CopyOnWriteArrayList<>( + Movecraft.getInstance().blockFadeTimeMap.keySet()); + } catch (java.util.ConcurrentModificationException e) { + numTries++; + } catch (java.lang.NegativeArraySizeException e) { + Movecraft.getInstance().blockFadeTimeMap = new HashMap<>(); + Movecraft.getInstance().blockFadeTypeMap = new HashMap<>(); + Movecraft.getInstance().blockFadeWaterMap = new HashMap<>(); + Movecraft.getInstance().blockFadeWorldMap = new HashMap<>(); + locations = new CopyOnWriteArrayList<>( + Movecraft.getInstance().blockFadeTimeMap.keySet()); + } + } + + for (MovecraftLocation loc : locations) { + if (Movecraft.getInstance().blockFadeWorldMap.get(loc) == w) { + Long time = Movecraft.getInstance().blockFadeTimeMap.get(loc); + Integer type = Movecraft.getInstance().blockFadeTypeMap.get(loc); + Boolean water = Movecraft.getInstance().blockFadeWaterMap.get(loc); + if (time != null && type != null && water != null) { + long secsElapsed = (System.currentTimeMillis() + - Movecraft.getInstance().blockFadeTimeMap.get(loc)) / 1000; + // has enough time passed to fade the block? + boolean timeElapsed; + // make containers take longer to fade so their loot can be recovered + if (w.getBlockTypeIdAt(loc.getX(), loc.getY(), loc.getZ()) == 54) { + timeElapsed = secsElapsed > Settings.FadeWrecksAfter * 5; + } else if (w.getBlockTypeIdAt(loc.getX(), loc.getY(), loc.getZ()) == 146) { + timeElapsed = secsElapsed > Settings.FadeWrecksAfter * 5; + } else if (w.getBlockTypeIdAt(loc.getX(), loc.getY(), loc.getZ()) == 158) { + timeElapsed = secsElapsed > Settings.FadeWrecksAfter * 5; + } else if (w.getBlockTypeIdAt(loc.getX(), loc.getY(), loc.getZ()) == 23) { + timeElapsed = secsElapsed > Settings.FadeWrecksAfter * 5; + } else { + timeElapsed = secsElapsed > Settings.FadeWrecksAfter; + } + if (timeElapsed) { + // load the chunk if it hasn't been already + int cx = loc.getX() >> 4; + int cz = loc.getZ() >> 4; + if (!w.isChunkLoaded(cx, cz)) { + w.loadChunk(cx, cz); + } + // check to see if the block type has + // changed, if so don't fade it + if (w.getBlockTypeIdAt(loc.getX(), loc.getY(), + loc.getZ()) == Movecraft.getInstance().blockFadeTypeMap.get(loc)) { + // should it become water? if not, then + // air + if (Movecraft.getInstance().blockFadeWaterMap.get(loc)) { + BlockCreateCommand updateCom = new BlockCreateCommand(w, loc, Material.STATIONARY_WATER, (byte) 0); + updateCommands.add(updateCom); + } else { + BlockCreateCommand updateCom = new BlockCreateCommand(w, loc, Material.AIR, (byte) 0); + updateCommands.add(updateCom); + } + } + Movecraft.getInstance().blockFadeTimeMap.remove(loc); + Movecraft.getInstance().blockFadeTypeMap.remove(loc); + Movecraft.getInstance().blockFadeWorldMap.remove(loc); + Movecraft.getInstance().blockFadeWaterMap.remove(loc); + } + } + } + } + if (updateCommands.size() > 0) { + MapUpdateManager.getInstance().scheduleUpdates(updateCommands); + } + } } - processed.add(hitBox); - } - for(HitBox hitBox : processed){ - wrecks.remove(hitBox); - wreckPhases.remove(hitBox); - wreckWorlds.remove(hitBox); - } - lastFadeCheck = System.currentTimeMillis(); - } + lastFadeCheck = System.currentTimeMillis(); + } + }*/ private void processDetection() { long ticksElapsed = (System.currentTimeMillis() - lastContactCheck) / 50; @@ -925,12 +1036,12 @@ private void processDetection() { - recentContactTracking.get(ccraft).get(tcraft) > 60000) { String notification = "New contact: "; - if (tcraft.getName().length() >= 1){ + if (tcraft.getName() != null && tcraft.getName().length() >= 1){ notification += tcraft.getName(); notification += " ("; } notification += tcraft.getType().getCraftName(); - if (tcraft.getName().length() >= 1){ + if (tcraft.getName() != null && tcraft.getName().length() >= 1){ notification += ")"; } notification += " commanded by "; @@ -1028,7 +1139,11 @@ public void run() { processTracers(); processFireballs(); processTNTContactExplosives(); - processFadingBlocks(); + processWaterlogging(); + if (!Settings.IsLegacy) { + processWaterlogging(); + } + //processFadingBlocks(); processDetection(); processAlgorithmQueue(); //processScheduledBlockChanges(); @@ -1064,4 +1179,5 @@ private void clearAll() { clearanceSet.clear(); } + } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java index 50cfd3970..ee43a7f02 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java @@ -11,6 +11,7 @@ import net.countercraft.movecraft.mapUpdater.update.*; import net.countercraft.movecraft.utils.HashHitBox; import net.countercraft.movecraft.utils.HitBox; +import net.countercraft.movecraft.utils.LegacyUtils; import net.countercraft.movecraft.utils.MutableHitBox; import org.bukkit.Bukkit; import org.bukkit.Location; @@ -25,13 +26,30 @@ import org.bukkit.inventory.Inventory; import org.bukkit.inventory.InventoryHolder; import org.bukkit.inventory.ItemStack; +import org.bukkit.potion.PotionEffect; import org.bukkit.scheduler.BukkitRunnable; import java.util.*; import java.util.concurrent.ThreadLocalRandom; public class TranslationTask extends AsyncTask { - private static final int[] FALL_THROUGH_BLOCKS = {0, 8, 9, 10, 11, 31, 37, 38, 39, 40, 50, 51, 55, 59, 63, 65, 68, 69, 70, 72, 75, 76, 77, 78, 83, 85, 93, 94, 111, 141, 142, 143, 171}; + private static final Set FALL_THROUGH_BLOCKS = new HashSet<>();//Settings.IsLegacy ? new Material[]{}:new Material[]{Material.AIR, + /*Material.WATER, + Material.LAVA, + Material.BROWN_MUSHROOM, + Material.RED_MUSHROOM, + Material.TORCH, + Material.FIRE, + Material.REDSTONE_WIRE, + Material.LADDER, + Material.WALL_SIGN, + Material.LEVER, + Material.STONE_BUTTON, + Material.SNOW, + Material.CARROT, + Material.POTATO, + };*/ + //private static final int[] FALL_THROUGH_BLOCKS = {0, 8, 9, 10, 11, 31, 37, 38, 39, 40, 50, 51, 55, 59, 63, 65, 68, 69, 70, 72, 75, 76, 77, 78, 83, 85, 93, 94, 111, 141, 142, 143, 171}; private int dx, dy, dz; private HashHitBox newHitBox, oldHitBox; @@ -47,48 +65,73 @@ public TranslationTask(Craft c, int dx, int dy, int dz) { this.dz = dz; newHitBox = new HashHitBox(); oldHitBox = new HashHitBox(c.getHitBox()); + + FALL_THROUGH_BLOCKS.add(Material.AIR); + FALL_THROUGH_BLOCKS.add(Material.WATER); + FALL_THROUGH_BLOCKS.add(Material.LAVA); + FALL_THROUGH_BLOCKS.add(Material.BROWN_MUSHROOM); + FALL_THROUGH_BLOCKS.add(Material.RED_MUSHROOM); + FALL_THROUGH_BLOCKS.add(Material.TORCH); + FALL_THROUGH_BLOCKS.add(Material.FIRE); + FALL_THROUGH_BLOCKS.add(Material.REDSTONE_WIRE); + FALL_THROUGH_BLOCKS.add(Material.LADDER); + if (Settings.is1_14){ + FALL_THROUGH_BLOCKS.add(Material.BIRCH_SIGN); + FALL_THROUGH_BLOCKS.add(Material.OAK_SIGN); + FALL_THROUGH_BLOCKS.add(Material.DARK_OAK_SIGN); + FALL_THROUGH_BLOCKS.add(Material.JUNGLE_SIGN); + FALL_THROUGH_BLOCKS.add(Material.SPRUCE_SIGN); + FALL_THROUGH_BLOCKS.add(Material.ACACIA_SIGN); + FALL_THROUGH_BLOCKS.add(Material.BIRCH_WALL_SIGN); + FALL_THROUGH_BLOCKS.add(Material.OAK_WALL_SIGN); + FALL_THROUGH_BLOCKS.add(Material.DARK_OAK_WALL_SIGN); + FALL_THROUGH_BLOCKS.add(Material.JUNGLE_WALL_SIGN); + FALL_THROUGH_BLOCKS.add(Material.SPRUCE_WALL_SIGN); + FALL_THROUGH_BLOCKS.add(Material.ACACIA_WALL_SIGN); + } else { + FALL_THROUGH_BLOCKS.add(Material.getMaterial("SIGN")); + FALL_THROUGH_BLOCKS.add(Material.getMaterial("WALL_SIGN")); + } + FALL_THROUGH_BLOCKS.add(Material.LEVER); + FALL_THROUGH_BLOCKS.add(Material.STONE_BUTTON); + FALL_THROUGH_BLOCKS.add(Material.SNOW); + FALL_THROUGH_BLOCKS.add(Material.CARROT); + FALL_THROUGH_BLOCKS.add(Material.POTATO); + if (Settings.IsLegacy) { + FALL_THROUGH_BLOCKS.add(LegacyUtils.STATIONARY_WATER); + FALL_THROUGH_BLOCKS.add(LegacyUtils.STATIONARY_LAVA); + FALL_THROUGH_BLOCKS.add(LegacyUtils.LONG_GRASS); + FALL_THROUGH_BLOCKS.add(LegacyUtils.YELLOW_FLOWER); + FALL_THROUGH_BLOCKS.add(LegacyUtils.RED_ROSE); + FALL_THROUGH_BLOCKS.add(LegacyUtils.CROPS); + FALL_THROUGH_BLOCKS.add(LegacyUtils.SIGN_POST); + FALL_THROUGH_BLOCKS.add(LegacyUtils.STONE_PLATE); + FALL_THROUGH_BLOCKS.add(LegacyUtils.REDSTONE_TORCH_ON); + FALL_THROUGH_BLOCKS.add(LegacyUtils.REDSTONE_TORCH_OFF); + FALL_THROUGH_BLOCKS.add(LegacyUtils.SUGAR_CANE_BLOCK); + FALL_THROUGH_BLOCKS.add(LegacyUtils.FENCE); + FALL_THROUGH_BLOCKS.add(LegacyUtils.DIODE_BLOCK_OFF); + FALL_THROUGH_BLOCKS.add(LegacyUtils.DIODE_BLOCK_ON); + FALL_THROUGH_BLOCKS.add(LegacyUtils.WATER_LILY); + FALL_THROUGH_BLOCKS.add(LegacyUtils.WOOD_BUTTON); + FALL_THROUGH_BLOCKS.add(LegacyUtils.CARPET); + } else { + FALL_THROUGH_BLOCKS.add(Material.BUBBLE_COLUMN); + FALL_THROUGH_BLOCKS.add(Material.KELP); + FALL_THROUGH_BLOCKS.add(Material.KELP_PLANT); + FALL_THROUGH_BLOCKS.add(Material.SEAGRASS); + FALL_THROUGH_BLOCKS.add(Material.TALL_SEAGRASS); + + } } @Override protected void execute() { + //Check if theres anything to move if(oldHitBox.isEmpty()){ return; } - if (getCraft().getDisabled() && (!getCraft().getSinking())) { - fail(I18nSupport.getInternationalisedString("Craft is disabled!")); - return; - } - - final int minY = oldHitBox.getMinY(); - final int maxY = oldHitBox.getMaxY(); - - //Check if the craft is too high - if(craft.getType().getMaxHeightLimit() < craft.getHitBox().getMinY()){ - dy = -Math.abs(dy); - }else if(craft.getType().getMaxHeightAboveGround() > 0){ - final MovecraftLocation middle = oldHitBox.getMidPoint(); - int testY = minY; - while (testY > 0){ - testY -= 1; - if (!craft.getW().getBlockAt(middle.getX(),testY,middle.getZ()).getType().name().endsWith("AIR")) - break; - } - if (minY - testY > craft.getType().getMaxHeightAboveGround()) { - dy = -Math.abs(dy); - } - } - - //Fail the movement if the craft is too high - if (dy>0 && maxY + dy > craft.getType().getMaxHeightLimit()) { - fail(I18nSupport.getInternationalisedString("Translation - Failed Craft hit height limit")); - return; - } else if (minY + dy < craft.getType().getMinHeightLimit() && dy < 0 && !craft.getSinking()) { - fail(I18nSupport.getInternationalisedString("Translation - Failed Craft hit minimum height limit")); - return; - } - - //TODO: Check fuel if (craft.getType().getFuelBurnRate() > 0.0) { new BukkitRunnable() { @Override @@ -143,6 +186,54 @@ public void run() { } }.runTask(Movecraft.getInstance()); } + //Prevent disabled crafts from moving + if (getCraft().getDisabled() && (!getCraft().getSinking())) { + fail(I18nSupport.getInternationalisedString("Craft is disabled!")); + return; + } + + if (getCraft().isRepairing()){ + fail("You cannot move a repairing craft!"); + return; + } + final int minY = oldHitBox.getMinY(); + final int maxY = oldHitBox.getMaxY(); + + //Check if the craft is too high + if(craft.getType().getMaxHeightLimit() < craft.getHitBox().getMinY()){ + dy-=1; + }else if(craft.getType().getMaxHeightAboveGround() > 0){ + final MovecraftLocation middle = oldHitBox.getMidPoint(); + int testY = minY; + for (int y = minY;y > 0;y--) { + if (y == minY) + continue; + if (craft.getW().getBlockAt(middle.getX(), y, middle.getZ()).getType() == Material.AIR || !Settings.IsLegacy && (craft.getW().getBlockAt(middle.getX(), y, middle.getZ()).getType() == Material.CAVE_AIR || craft.getW().getBlockAt(middle.getX(), y, middle.getZ()).getType() == Material.VOID_AIR)){ + continue; + } + testY = y; + break; + } + if (minY - testY > craft.getType().getMaxHeightAboveGround()) { + dy = 0; + dy -= 1; + } + } + + //Fail the movement if the craft is too high + if (dy>0 && maxY + dy > craft.getType().getMaxHeightLimit()) { + fail(I18nSupport.getInternationalisedString("Translation - Failed Craft hit height limit")); + return; + } else if (minY + dy < craft.getType().getMinHeightLimit() && dy < 0 && !craft.getSinking()) { + fail(I18nSupport.getInternationalisedString("Translation - Failed Craft hit minimum height limit")); + return; + } + + //TODO: Check fuel + //if (!checkFuel()) { + //fail(I18nSupport.getInternationalisedString("Translation - Failed Craft out of fuel")); + //return; + //} //TODO: Add and handle event for towny and factions final List harvestBlocks = craft.getType().getHarvestBlocks(); @@ -167,9 +258,13 @@ public void run() { boolean blockObstructed; if (craft.getSinking()) { - blockObstructed = !(Arrays.binarySearch(FALL_THROUGH_BLOCKS, testMaterial.getId()) >= 0); + blockObstructed = !FALL_THROUGH_BLOCKS.contains(testMaterial); } else { - blockObstructed = !craft.getType().getPassthroughBlocks().contains(testMaterial) && !testMaterial.equals(Material.AIR); + if (Settings.IsLegacy) { + blockObstructed = !craft.getType().getPassthroughBlocks().contains(testMaterial) && !testMaterial.equals(Material.AIR); + } else { //1.13 has more than just one air type + blockObstructed = !craft.getType().getPassthroughBlocks().contains(testMaterial) && (!testMaterial.toString().endsWith("AIR")); + } } boolean ignoreBlock = false; @@ -227,8 +322,9 @@ public void run() { }while (newHitBox.contains(next)); craft.getCollapsedHitBox().addAll(toRemove); newHitBox.removeAll(toRemove); - } + } + Bukkit.getLogger().info("Collapsed hitbox: "+craft.getCollapsedHitBox().size() + ", New hitbox: " + newHitBox.size()); }else{ for(MovecraftLocation location : collisionBox){ if (!(craft.getType().getCollisionExplosion() != 0.0F) || System.currentTimeMillis() - craft.getOrigPilotTime() <= 1000) { @@ -245,9 +341,18 @@ public void run() { }*/ explosionKey = explosionForce; Location loc = location.toBukkit(craft.getW()); + int potEffRange = craft.getType().getEffectRange(); + Map potionEffects = craft.getType().getPotionEffectsToApply(); + Set entityTypes = craft.getType().getEntitiesToSpawn(); + int maxEntitiesToBeSpawned = craft.getType().getMaxEntitiesToBeSpawned(); if (!loc.getBlock().getType().equals(Material.AIR)) { updates.add(new ExplosionUpdateCommand(loc, explosionKey)); collisionExplosion = true; + if (potEffRange != 0 && !potionEffects.isEmpty()) + updates.add(new PotionEffectsUpdateCommand(loc,potEffRange,potionEffects)); + if (potEffRange != 0 && !entityTypes.isEmpty()){ + updates.add(new EntitySpawnUpdateCommand(potEffRange,maxEntitiesToBeSpawned,loc,entityTypes)); + } } if (craft.getType().getFocusedExplosion()) { // don't handle any further collisions if it is set to focusedexplosion break; @@ -267,16 +372,8 @@ public void run() { //prevents torpedo and rocket pilots if (craft.getType().getMoveEntities() && !(craft.getSinking() && craft.getType().getOnlyMovePlayers())) { - Location midpoint = new Location( - craft.getW(), - (oldHitBox.getMaxX() + oldHitBox.getMinX())/2.0, - (oldHitBox.getMaxY() + oldHitBox.getMinY())/2.0, - (oldHitBox.getMaxZ() + oldHitBox.getMinZ())/2.0); - for (Entity entity : craft.getW().getNearbyEntities(midpoint, oldHitBox.getXLength() / 2.0 + 1, oldHitBox.getYLength() / 2.0 + 2, oldHitBox.getZLength() / 2.0 + 1)) { - if (entity.getType() == EntityType.PLAYER) { - if(craft.getSinking()){ - continue; - } + for (Entity entity : craft.getW().getNearbyEntities(craft.getHitBox().getMidPoint().toBukkit(craft.getW()), craft.getHitBox().getXLength() / 2.0 + 1, craft.getHitBox().getYLength() / 2.0 + 1, craft.getHitBox().getZLength() / 2.0 + 1)) { + if (entity.getType() == EntityType.PLAYER && !craft.getSinking()) { Player player = (Player) entity; craft.getMovedPlayers().put(player, System.currentTimeMillis()); EntityMoveUpdateCommand eUp = new EntityMoveUpdateCommand(entity, dx, dy, dz, 0, 0); @@ -313,7 +410,7 @@ private void fail(String message) { craft.getW().playSound(location, Sound.BLOCK_ANVIL_LAND, 1.0f, 0.25f); //craft.setCurTickCooldown(craft.getType().getCruiseTickCooldown()); } else { - craft.getW().playSound(location, Settings.IsLegacy ? Sound.valueOf("ENTITY_IRONGOLEM_DEATH") :Sound.ENTITY_IRON_GOLEM_DEATH, 5.0f, 5.0f); + craft.getW().playSound(location, Settings.IsLegacy ? LegacyUtils.ENITIY_IRONGOLEM_DEATH : Sound.ENTITY_IRON_GOLEM_DEATH, 5.0f, 5.0f); //craft.setCurTickCooldown(craft.getType().getCruiseTickCooldown()); } } @@ -351,13 +448,24 @@ private void captureYield(List harvestedBlocks) { for (MovecraftLocation harvestedBlock : harvestedBlocks) { Block block = craft.getW().getBlockAt(harvestedBlock.getX(), harvestedBlock.getY(), harvestedBlock.getZ()); List drops = new ArrayList<>(block.getDrops()); - //generate seed drops - if (block.getType() == Material.WHEAT) { - Random rand = new Random(); - int amount = rand.nextInt(4); - if (amount > 0) { - ItemStack seeds = new ItemStack(Material.WHEAT_SEEDS, amount); - drops.add(seeds); + if (Settings.IsLegacy) { + //generate seed drops + if (block.getType() == LegacyUtils.CROPS) { + Random rand = new Random(); + int amount = rand.nextInt(4); + if (amount > 0) { + ItemStack seeds = new ItemStack(LegacyUtils.SEEDS, amount); + drops.add(seeds); + } + } + } else { + if (block.getType() == Material.WHEAT){ + Random rand = new Random(); + int amount = rand.nextInt(4); + if (amount > 0){ + ItemStack seeds = new ItemStack(Material.WHEAT_SEEDS, amount); + drops.add(seeds); + } } } //get contents of inventories before deposting @@ -405,6 +513,9 @@ private ItemStack putInToChests(ItemStack stack, ArrayList inventorie return stack; } + + + public boolean failed(){ return failed; } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/LegacyWEUtils.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/LegacyWEUtils.java index 43cf53474..790e90069 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/LegacyWEUtils.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/LegacyWEUtils.java @@ -1,9 +1,23 @@ package net.countercraft.movecraft.utils; +import com.sk89q.worldedit.blocks.BaseBlock; +import com.sk89q.worldedit.extent.clipboard.Clipboard; import com.sk89q.worldguard.protection.regions.ProtectedRegion; import org.bukkit.util.Vector; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + public class LegacyWEUtils { + private static Method GET_BLOCK; + static { + try { + GET_BLOCK = Clipboard.class.getDeclaredMethod("getBlock", com.sk89q.worldedit.Vector.class); + } catch (NoSuchMethodException e) { + GET_BLOCK = null; + e.printStackTrace(); + } + } public static Vector getMinimumPoint(ProtectedRegion region){ com.sk89q.worldedit.Vector weMin = region.getMaximumPoint(); return WorldEditUtils.toBukkitVector(weMin); @@ -12,4 +26,15 @@ public static Vector getMaximumPoint(ProtectedRegion region){ com.sk89q.worldedit.Vector weMax = region.getMaximumPoint(); return WorldEditUtils.toBukkitVector(weMax); } + + public static BaseBlock getBlock(Clipboard clipboard, com.sk89q.worldedit.Vector pos){ + try { + return GET_BLOCK != null ? (BaseBlock) GET_BLOCK.invoke(clipboard, pos) : null; + } catch (IllegalAccessException | InvocationTargetException e) { + e.printStackTrace(); + return null; + } + } + + } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/assault/AssaultTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/assault/AssaultTask.java index e64b8f3fb..321e8fea9 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/assault/AssaultTask.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/assault/AssaultTask.java @@ -5,12 +5,7 @@ import com.sk89q.worldguard.protection.regions.ProtectedRegion; import net.countercraft.movecraft.Movecraft; import net.countercraft.movecraft.config.Settings; -import net.countercraft.movecraft.listener.WorldEditInteractListener; -import org.bukkit.Bukkit; -import org.bukkit.ChatColor; -import org.bukkit.Material; -import org.bukkit.OfflinePlayer; -import org.bukkit.World; +import org.bukkit.*; import org.bukkit.block.Sign; import org.bukkit.scheduler.BukkitRunnable; @@ -90,7 +85,7 @@ public void run() { w.getBlockAt(beaconX + 2, beaconY + 2, beaconZ + 2).setType(Material.BEACON); w.getBlockAt(beaconX + 2, beaconY + 3, beaconZ + 2).setType(Material.BEDROCK); // finally the sign on the beacon - w.getBlockAt(beaconX + 2, beaconY + 3, beaconZ + 1).setType(Material.WALL_SIGN); + w.getBlockAt(beaconX + 2, beaconY + 3, beaconZ + 1).setType(Material.OAK_WALL_SIGN); Sign s = (Sign) w.getBlockAt(beaconX + 2, beaconY + 3, beaconZ + 1).getState(); s.setLine(0, ChatColor.RED + "REGION DAMAGED!"); s.setLine(1, "Region:" + assault.getRegionName()); @@ -109,7 +104,7 @@ public void run() { assert tRegion != null; tRegion.setFlag(DefaultFlag.TNT, StateFlag.State.DENY); // repair the damages that have occurred so far - if (!new WorldEditInteractListener().repairRegion(assault.getWorld(), assault.getRegionName())) { + if (!AssaultUtils.repairRegion(assault.getWorld(), assault.getRegionName())) { Bukkit.getServer().broadcastMessage(String.format("REPAIR OF %s FAILED, CONTACT AN ADMIN", assault.getRegionName().toUpperCase())); } } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/assault/AssaultUtils.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/assault/AssaultUtils.java index ed64d6709..8df683296 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/assault/AssaultUtils.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/assault/AssaultUtils.java @@ -1,12 +1,29 @@ package net.countercraft.movecraft.warfare.assault; +import com.sk89q.worldedit.Vector; +import com.sk89q.worldedit.bukkit.BukkitAdapter; +import com.sk89q.worldedit.extent.clipboard.Clipboard; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldedit.world.block.BaseBlock; import com.sk89q.worldguard.protection.regions.ProtectedRegion; import net.countercraft.movecraft.Movecraft; +import net.countercraft.movecraft.MovecraftLocation; import net.countercraft.movecraft.config.Settings; +import net.countercraft.movecraft.mapUpdater.MapUpdateManager; +import net.countercraft.movecraft.mapUpdater.update.UpdateCommand; +import net.countercraft.movecraft.mapUpdater.update.WorldEdit7UpdateCommand; +import net.countercraft.movecraft.mapUpdater.update.WorldEditUpdateCommand; +import net.countercraft.movecraft.utils.LegacyUtils; +import net.countercraft.movecraft.utils.LegacyWEUtils; import org.bukkit.Bukkit; +import org.bukkit.Material; import org.bukkit.OfflinePlayer; +import org.bukkit.World; +import org.bukkit.block.Block; +import org.bukkit.block.data.BlockData; import java.util.HashSet; +import java.util.LinkedList; import java.util.UUID; public class AssaultUtils { @@ -91,4 +108,54 @@ private static double getMemberBalance(ProtectedRegion tRegion) { } return total * (Settings.AssaultMemberWeightPercent / 100.0); } + + public static boolean repairRegion(World world, String regionName) { + Clipboard clipboard = Movecraft.getInstance().getMovecraftRepair().loadRegionRepairStateClipboard(Movecraft.getInstance(),regionName,world); + if (clipboard == null){ + return false; + } + int minX = clipboard.getMinimumPoint().getX(); + int minY = clipboard.getMinimumPoint().getY(); + int minZ = clipboard.getMinimumPoint().getZ(); + int maxX = clipboard.getMaximumPoint().getX(); + int maxY = clipboard.getMaximumPoint().getY(); + int maxZ = clipboard.getMaximumPoint().getZ(); + LinkedList updateCommands = new LinkedList<>(); + for (int x = minX; x <= maxX ; x++){ + for (int y = minY; y <= maxY; y++){ + for (int z = minZ ; z <= maxZ ; z++){ + Material type; + if (Settings.IsLegacy){ + Vector position = new Vector(x,y,z); + com.sk89q.worldedit.blocks.BaseBlock bb = LegacyWEUtils.getBlock(clipboard,position); + type = LegacyUtils.getMaterial(bb.getType()); + byte data = (byte) bb.getData(); + if (type.name().endsWith("AIR")) { + continue; + } + Block b = world.getBlockAt(x, y, z); + if (b.getType() != type){ + updateCommands.add(new WorldEditUpdateCommand(bb,world,new MovecraftLocation(x,y,z),type,data)); + } + } else { + BlockVector3 position = BlockVector3.at(x, y, z); + BaseBlock bb = clipboard.getFullBlock(position); + type = BukkitAdapter.adapt(bb.getBlockType()); + BlockData bdata = BukkitAdapter.adapt(bb); + if (type.name().endsWith("AIR")) { + continue; + } + Block b = world.getBlockAt(x, y, z); + if (b.getType() != type){ + updateCommands.add(new WorldEdit7UpdateCommand(bb,world,new MovecraftLocation(x,y,z),type)); + } + } + } + } + } + if (!updateCommands.isEmpty()){ + MapUpdateManager.getInstance().scheduleUpdates(updateCommands); + } + return true; + } } diff --git a/modules/api/src/main/java/net/countercraft/movecraft/utils/LegacyUtils.java b/modules/api/src/main/java/net/countercraft/movecraft/utils/LegacyUtils.java index 934eb0725..f2f43d487 100644 --- a/modules/api/src/main/java/net/countercraft/movecraft/utils/LegacyUtils.java +++ b/modules/api/src/main/java/net/countercraft/movecraft/utils/LegacyUtils.java @@ -120,5 +120,4 @@ private String getColorFromData(byte data){ } return color; } - } From 4372fb55fe60494ccae6ca45693c59d184d2d4d9 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Sat, 29 Jun 2019 00:57:28 +0200 Subject: [PATCH 027/304] Commited more upstream changes --- .../movecraft/async/AsyncManager.java | 129 ++++++------------ .../update/CraftTranslateCommand.java | 48 +++++-- .../movecraft/sign/AscendSign.java | 2 +- .../movecraft/sign/CruiseSign.java | 2 +- .../movecraft/sign/DescendSign.java | 2 +- .../countercraft/movecraft/sign/NameSign.java | 3 +- .../warfare/assault/AssaultUtils.java | 112 +++++++++++++-- 7 files changed, 183 insertions(+), 115 deletions(-) diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java index 3da1494d0..c814986d8 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java @@ -28,6 +28,7 @@ import net.countercraft.movecraft.Movecraft; import net.countercraft.movecraft.MovecraftLocation; import net.countercraft.movecraft.Rotation; +import net.countercraft.movecraft.WorldHandler; import net.countercraft.movecraft.async.detection.DetectionTask; import net.countercraft.movecraft.async.detection.DetectionTaskData; import net.countercraft.movecraft.async.rotation.RotationTask; @@ -40,11 +41,13 @@ import net.countercraft.movecraft.mapUpdater.MapUpdateManager; import net.countercraft.movecraft.utils.CollectionUtils; import net.countercraft.movecraft.utils.HashHitBox; +import net.countercraft.movecraft.utils.HitBox; import net.countercraft.movecraft.utils.LegacyUtils; import org.bukkit.*; import org.bukkit.block.Block; import org.bukkit.block.BlockFace; import org.bukkit.entity.Player; +import org.bukkit.entity.SmallFireball; import org.bukkit.entity.TNTPrimed; import org.bukkit.scheduler.BukkitRunnable; import org.bukkit.util.Vector; @@ -62,7 +65,10 @@ public class AsyncManager extends BukkitRunnable { private final HashMap> recentContactTracking = new HashMap<>(); private final BlockingQueue finishedAlgorithms = new LinkedBlockingQueue<>(); private final HashSet clearanceSet = new HashSet<>(); - private HashMap FireballTracking = new HashMap<>(); + private HashMap FireballTracking = new HashMap<>(); + private HashMap wrecks = new HashMap<>(); + private HashMap wreckWorlds = new HashMap<>(); + private HashMap> wreckPhases = new HashMap<>(); private long lastTracerUpdate = 0; private long lastFireballCheck = 0; private long lastTNTContactCheck = 0; @@ -116,6 +122,14 @@ public AsyncManager() { transparent.add(Material.GREEN_STAINED_GLASS_PANE); } } + public void addWreck(Craft craft){ + if(craft.getCollapsedHitBox().isEmpty() || Settings.FadeWrecksAfter == 0){ + return; + } + wrecks.put(craft.getCollapsedHitBox(), System.currentTimeMillis()); + wreckWorlds.put(craft.getCollapsedHitBox(), craft.getW()); + wreckPhases.put(craft.getCollapsedHitBox(), craft.getPhaseBlocks()); + } /* public static AsyncManager getInstance() { return instance; @@ -897,96 +911,36 @@ private void processTNTContactExplosives() { lastTNTContactCheck = System.currentTimeMillis(); } } - - /*private void processFadingBlocks() { + private void processFadingBlocks() { if (Settings.FadeWrecksAfter == 0) return; long ticksElapsed = (System.currentTimeMillis() - lastFadeCheck) / 50; - if (ticksElapsed > 20) { - for (World w : Bukkit.getWorlds()) { - if (w != null) { - ArrayList updateCommands = new ArrayList<>(); - CopyOnWriteArrayList locations = null; - - // I know this is horrible, but I honestly don't see another - // way to do this... - int numTries = 0; - while ((locations == null) && (numTries < 100)) { - try { - locations = new CopyOnWriteArrayList<>( - Movecraft.getInstance().blockFadeTimeMap.keySet()); - } catch (java.util.ConcurrentModificationException e) { - numTries++; - } catch (java.lang.NegativeArraySizeException e) { - Movecraft.getInstance().blockFadeTimeMap = new HashMap<>(); - Movecraft.getInstance().blockFadeTypeMap = new HashMap<>(); - Movecraft.getInstance().blockFadeWaterMap = new HashMap<>(); - Movecraft.getInstance().blockFadeWorldMap = new HashMap<>(); - locations = new CopyOnWriteArrayList<>( - Movecraft.getInstance().blockFadeTimeMap.keySet()); - } - } - - for (MovecraftLocation loc : locations) { - if (Movecraft.getInstance().blockFadeWorldMap.get(loc) == w) { - Long time = Movecraft.getInstance().blockFadeTimeMap.get(loc); - Integer type = Movecraft.getInstance().blockFadeTypeMap.get(loc); - Boolean water = Movecraft.getInstance().blockFadeWaterMap.get(loc); - if (time != null && type != null && water != null) { - long secsElapsed = (System.currentTimeMillis() - - Movecraft.getInstance().blockFadeTimeMap.get(loc)) / 1000; - // has enough time passed to fade the block? - boolean timeElapsed; - // make containers take longer to fade so their loot can be recovered - if (w.getBlockTypeIdAt(loc.getX(), loc.getY(), loc.getZ()) == 54) { - timeElapsed = secsElapsed > Settings.FadeWrecksAfter * 5; - } else if (w.getBlockTypeIdAt(loc.getX(), loc.getY(), loc.getZ()) == 146) { - timeElapsed = secsElapsed > Settings.FadeWrecksAfter * 5; - } else if (w.getBlockTypeIdAt(loc.getX(), loc.getY(), loc.getZ()) == 158) { - timeElapsed = secsElapsed > Settings.FadeWrecksAfter * 5; - } else if (w.getBlockTypeIdAt(loc.getX(), loc.getY(), loc.getZ()) == 23) { - timeElapsed = secsElapsed > Settings.FadeWrecksAfter * 5; - } else { - timeElapsed = secsElapsed > Settings.FadeWrecksAfter; - } - if (timeElapsed) { - // load the chunk if it hasn't been already - int cx = loc.getX() >> 4; - int cz = loc.getZ() >> 4; - if (!w.isChunkLoaded(cx, cz)) { - w.loadChunk(cx, cz); - } - // check to see if the block type has - // changed, if so don't fade it - if (w.getBlockTypeIdAt(loc.getX(), loc.getY(), - loc.getZ()) == Movecraft.getInstance().blockFadeTypeMap.get(loc)) { - // should it become water? if not, then - // air - if (Movecraft.getInstance().blockFadeWaterMap.get(loc)) { - BlockCreateCommand updateCom = new BlockCreateCommand(w, loc, Material.STATIONARY_WATER, (byte) 0); - updateCommands.add(updateCom); - } else { - BlockCreateCommand updateCom = new BlockCreateCommand(w, loc, Material.AIR, (byte) 0); - updateCommands.add(updateCom); - } - } - Movecraft.getInstance().blockFadeTimeMap.remove(loc); - Movecraft.getInstance().blockFadeTypeMap.remove(loc); - Movecraft.getInstance().blockFadeWorldMap.remove(loc); - Movecraft.getInstance().blockFadeWaterMap.remove(loc); - } - } - } - } - if (updateCommands.size() > 0) { - MapUpdateManager.getInstance().scheduleUpdates(updateCommands); - } - } + if (ticksElapsed <= 20) { + return; + } + List processed = new ArrayList<>(); + final WorldHandler handler = Movecraft.getInstance().getWorldHandler(); + for(Map.Entry entry : wrecks.entrySet()){ + if (entry.getValue() + Settings.FadeWrecksAfter <= System.currentTimeMillis()) { + continue; } - - lastFadeCheck = System.currentTimeMillis(); + final HitBox hitBox = entry.getKey(); + final Map phaseBlocks = wreckPhases.get(hitBox); + final World world = wreckWorlds.get(hitBox); + for (MovecraftLocation location : hitBox){ + handler.setBlockFast(location.toBukkit(world), phaseBlocks.getOrDefault(location, Material.AIR),(byte) 0); + } + processed.add(hitBox); } - }*/ + for(HitBox hitBox : processed){ + wrecks.remove(hitBox); + wreckPhases.remove(hitBox); + wreckWorlds.remove(hitBox); + } + lastFadeCheck = System.currentTimeMillis(); + + } + private void processDetection() { long ticksElapsed = (System.currentTimeMillis() - lastContactCheck) / 50; @@ -1139,11 +1093,10 @@ public void run() { processTracers(); processFireballs(); processTNTContactExplosives(); - processWaterlogging(); if (!Settings.IsLegacy) { processWaterlogging(); } - //processFadingBlocks(); + processFadingBlocks(); processDetection(); processAlgorithmQueue(); //processScheduledBlockChanges(); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftTranslateCommand.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftTranslateCommand.java index bd60f9fbd..a82f81101 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftTranslateCommand.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftTranslateCommand.java @@ -1,6 +1,5 @@ package net.countercraft.movecraft.mapUpdater.update; -import com.google.common.collect.Sets; import net.countercraft.movecraft.Movecraft; import net.countercraft.movecraft.MovecraftLocation; import net.countercraft.movecraft.WorldHandler; @@ -8,11 +7,7 @@ import net.countercraft.movecraft.craft.Craft; import net.countercraft.movecraft.craft.CraftManager; import net.countercraft.movecraft.events.SignTranslateEvent; -import net.countercraft.movecraft.utils.CollectionUtils; -import net.countercraft.movecraft.utils.HashHitBox; -import net.countercraft.movecraft.utils.HitBox; -import net.countercraft.movecraft.utils.MutableHitBox; -import net.countercraft.movecraft.utils.SolidHitBox; +import net.countercraft.movecraft.utils.*; import org.bukkit.Bukkit; import org.bukkit.Material; import org.bukkit.block.Block; @@ -42,12 +37,37 @@ public void doUpdate() { long time = System.nanoTime(); final Set passthroughBlocks = new HashSet<>(craft.getType().getPassthroughBlocks()); if(craft.getSinking()){ - passthroughBlocks.add(Material.STATIONARY_WATER); - passthroughBlocks.add(Material.WATER); - passthroughBlocks.add(Material.LEAVES); - passthroughBlocks.add(Material.LEAVES_2); - passthroughBlocks.add(Material.LONG_GRASS); - passthroughBlocks.add(Material.DOUBLE_PLANT); + passthroughBlocks.add(Material.WATER);//Same in the 1.13 API, but other values are different + if (Settings.IsLegacy){ //use pre-1.13 values if running on 1.12.2 or lower + passthroughBlocks.add(LegacyUtils.STATIONARY_WATER); + passthroughBlocks.add(LegacyUtils.LEAVES); + passthroughBlocks.add(LegacyUtils.LEAVES_2); + passthroughBlocks.add(LegacyUtils.LONG_GRASS); + passthroughBlocks.add(LegacyUtils.DOUBLE_PLANT); + } else {//otherwise, use 1.13+ types + //Leaves + passthroughBlocks.add(Material.ACACIA_LEAVES); + passthroughBlocks.add(Material.BIRCH_LEAVES); + passthroughBlocks.add(Material.DARK_OAK_LEAVES); + passthroughBlocks.add(Material.JUNGLE_LEAVES); + passthroughBlocks.add(Material.OAK_LEAVES); + passthroughBlocks.add(Material.SPRUCE_LEAVES); + //Grass + passthroughBlocks.add(Material.GRASS); + //Double plants + passthroughBlocks.add(Material.ROSE_BUSH); + passthroughBlocks.add(Material.SUNFLOWER); + passthroughBlocks.add(Material.LILAC); + passthroughBlocks.add(Material.PEONY); + passthroughBlocks.add(Material.KELP); + passthroughBlocks.add(Material.KELP_PLANT); + passthroughBlocks.add(Material.TALL_SEAGRASS); + passthroughBlocks.add(Material.SEA_PICKLE); + passthroughBlocks.add(Material.SEAGRASS); + + passthroughBlocks.add(Material.BUBBLE_COLUMN); + + } } if(passthroughBlocks.isEmpty()){ //translate the craft @@ -55,7 +75,7 @@ public void doUpdate() { //trigger sign events for(MovecraftLocation location : craft.getHitBox()){ Block block = location.toBukkit(craft.getW()).getBlock(); - if(block.getType() == Material.WALL_SIGN || block.getType() == Material.SIGN_POST){ + if(block.getState() instanceof Sign){ Sign sign = (Sign) block.getState(); Bukkit.getServer().getPluginManager().callEvent(new SignTranslateEvent(block, craft, sign.getLines())); sign.update(); @@ -141,7 +161,7 @@ public void doUpdate() { //trigger sign events for (MovecraftLocation location : craft.getHitBox()) { Block block = location.toBukkit(craft.getW()).getBlock(); - if (block.getType() == Material.WALL_SIGN || block.getType() == Material.SIGN_POST) { + if (block.getState() instanceof Sign) { Sign sign = (Sign) block.getState(); Bukkit.getServer().getPluginManager().callEvent(new SignTranslateEvent(block, craft, sign.getLines())); sign.update(); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/AscendSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/AscendSign.java index 37cac3e6e..b7a8a1ed4 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/AscendSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/AscendSign.java @@ -55,7 +55,7 @@ public void onSignClickEvent(PlayerInteractEvent event){ sign.update(true); CraftManager.getInstance().getCraftByPlayer(event.getPlayer()).setCruiseDirection(BlockFace.UP); - CraftManager.getInstance().getCraftByPlayer(event.getPlayer()).setLastCruisUpdate(System.currentTimeMillis()); + CraftManager.getInstance().getCraftByPlayer(event.getPlayer()).setLastCruiseUpdate(System.currentTimeMillis()); CraftManager.getInstance().getCraftByPlayer(event.getPlayer()).setCruising(true); if (!c.getType().getMoveEntities()) { diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CruiseSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CruiseSign.java index 58490238a..7028b0294 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CruiseSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CruiseSign.java @@ -85,7 +85,7 @@ public final void onSignClick(PlayerInteractEvent event) { } } c.setCruiseDirection(direction); - c.setLastCruisUpdate(System.currentTimeMillis()); + c.setLastCruiseUpdate(System.currentTimeMillis()); c.setCruising(true); if (!c.getType().getMoveEntities()) { CraftManager.getInstance().addReleaseTask(c); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/DescendSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/DescendSign.java index 25cd8a5dd..95a57a3f2 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/DescendSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/DescendSign.java @@ -54,7 +54,7 @@ public final void onSignClick(PlayerInteractEvent event) { sign.update(true); c.setCruiseDirection(BlockFace.DOWN); - c.setLastCruisUpdate(System.currentTimeMillis()); + c.setLastCruiseUpdate(System.currentTimeMillis()); c.setCruising(true); if (!c.getType().getMoveEntities()) { diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/NameSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/NameSign.java index 3ada0b639..78ad827fa 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/NameSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/NameSign.java @@ -5,7 +5,6 @@ import net.countercraft.movecraft.craft.Craft; import net.countercraft.movecraft.events.CraftDetectEvent; import net.countercraft.movecraft.utils.ChatUtils; -import org.bukkit.Material; import org.bukkit.World; import org.bukkit.block.Block; import org.bukkit.block.Sign; @@ -29,7 +28,7 @@ public void onCraftDetect(@NotNull CraftDetectEvent event) { for (MovecraftLocation location : c.getHitBox()) { Block b = location.toBukkit(w).getBlock(); - if (b.getType() == Material.SIGN_POST || b.getType() == Material.WALL_SIGN) { + if (b.getState() instanceof Sign) { Sign s = (Sign) b.getState(); String name = ""; if (s.getLine(0).equalsIgnoreCase(HEADER)) { diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/assault/AssaultUtils.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/assault/AssaultUtils.java index 8df683296..a12e92cfc 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/assault/AssaultUtils.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/assault/AssaultUtils.java @@ -5,6 +5,8 @@ import com.sk89q.worldedit.extent.clipboard.Clipboard; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.world.block.BaseBlock; +import com.sk89q.worldguard.bukkit.WorldGuardPlugin; +import com.sk89q.worldguard.protection.ApplicableRegionSet; import com.sk89q.worldguard.protection.regions.ProtectedRegion; import net.countercraft.movecraft.Movecraft; import net.countercraft.movecraft.MovecraftLocation; @@ -15,19 +17,39 @@ import net.countercraft.movecraft.mapUpdater.update.WorldEditUpdateCommand; import net.countercraft.movecraft.utils.LegacyUtils; import net.countercraft.movecraft.utils.LegacyWEUtils; -import org.bukkit.Bukkit; -import org.bukkit.Material; -import org.bukkit.OfflinePlayer; -import org.bukkit.World; +import net.countercraft.movecraft.utils.WorldguardUtils; +import org.bukkit.*; 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.entity.EntityExplodeEvent; +import org.bukkit.scheduler.BukkitRunnable; -import java.util.HashSet; -import java.util.LinkedList; -import java.util.UUID; +import java.util.*; public class AssaultUtils { - + private static long lastDamagesUpdate = 0; + final static Material[] fragileBlocks = Settings.IsLegacy ? new Material[]{LegacyUtils.BED_BLOCK, LegacyUtils.PISTON_EXTENSION, Material.TORCH, Material.REDSTONE_WIRE, LegacyUtils.SIGN_POST, LegacyUtils.WOOD_DOOR, Material.LADDER, Material.getMaterial("WALL_SIGN"), + Material.BIRCH_SIGN,Material.OAK_SIGN,Material.DARK_OAK_SIGN,Material.JUNGLE_SIGN,Material.SPRUCE_SIGN,Material.ACACIA_SIGN,Material.BIRCH_WALL_SIGN + ,Material.OAK_WALL_SIGN,Material.DARK_OAK_WALL_SIGN, Material.JUNGLE_WALL_SIGN, Material.SPRUCE_WALL_SIGN, Material.ACACIA_WALL_SIGN, Material.LEVER, LegacyUtils.STONE_PLATE, LegacyUtils.IRON_DOOR_BLOCK, LegacyUtils.WOOD_PLATE, LegacyUtils.REDSTONE_TORCH_OFF, LegacyUtils.REDSTONE_TORCH_ON, Material.STONE_BUTTON, LegacyUtils.DIODE_BLOCK_OFF, LegacyUtils.DIODE_BLOCK_ON, LegacyUtils.TRAP_DOOR, Material.TRIPWIRE_HOOK, + Material.TRIPWIRE, LegacyUtils.WOOD_BUTTON, LegacyUtils.GOLD_PLATE, LegacyUtils.IRON_PLATE, LegacyUtils.REDSTONE_COMPARATOR_OFF, LegacyUtils.REDSTONE_COMPARATOR_ON, Material.DAYLIGHT_DETECTOR, LegacyUtils.CARPET, LegacyUtils.DAYLIGHT_DETECTOR_INVERTED, Material.SPRUCE_DOOR, Material.BIRCH_DOOR, Material.JUNGLE_DOOR, Material.ACACIA_DOOR, Material.DARK_OAK_DOOR} + : + new Material[] + //Beds + {Material.CYAN_BED, Material.BLACK_BED, Material.BLUE_BED, + Material.BROWN_BED, Material.GRAY_BED, Material.GREEN_BED, Material.LIGHT_BLUE_BED, Material.LIGHT_GRAY_BED, Material.LIME_BED, Material.MAGENTA_BED, + Material.ORANGE_BED, Material.PINK_BED, Material.PURPLE_BED, Material.RED_BED, Material.WHITE_BED, Material.YELLOW_BED, + //Redstone components + Material.REDSTONE_WIRE, Material.REPEATER, Material.COMPARATOR, Material.REDSTONE_TORCH, Material.REDSTONE_WALL_TORCH, Material.TRIPWIRE_HOOK, + //Pressure plates + Material.STONE_PRESSURE_PLATE, Material.ACACIA_PRESSURE_PLATE, Material.BIRCH_PRESSURE_PLATE, Material.DARK_OAK_PRESSURE_PLATE, Material.HEAVY_WEIGHTED_PRESSURE_PLATE, Material.LIGHT_WEIGHTED_PRESSURE_PLATE, Material.JUNGLE_PRESSURE_PLATE, Material.OAK_PRESSURE_PLATE, Material.SPRUCE_PRESSURE_PLATE, + //Buttons + Material.STONE_BUTTON, Material.BIRCH_BUTTON, Material.ACACIA_BUTTON, Material.DARK_OAK_BUTTON, Material.JUNGLE_BUTTON, Material.OAK_BUTTON, Material.SPRUCE_BUTTON, + //Doors + Material.SPRUCE_DOOR, Material.BIRCH_DOOR, Material.JUNGLE_DOOR, Material.ACACIA_DOOR, Material.DARK_OAK_DOOR, Material.OAK_DOOR, Material.IRON_DOOR, + //Trapdoors + Material.IRON_TRAPDOOR, Material.ACACIA_TRAPDOOR, Material.BIRCH_TRAPDOOR}; public static boolean areDefendersOnline(ProtectedRegion tRegion) { int numOnline = 0; @@ -158,4 +180,78 @@ public static boolean repairRegion(World world, String regionName) { } return true; } + + public static void processAssault(EntityExplodeEvent e){ + List assaults = Movecraft.getInstance().getAssaultManager() != null ? Movecraft.getInstance().getAssaultManager().getAssaults() : null; + if (assaults == null || assaults.size() == 0) { + return; + } + WorldGuardPlugin worldGuard = Movecraft.getInstance().getWorldGuardPlugin(); + for (final Assault assault : assaults) { + Iterator i = e.blockList().iterator(); + while (i.hasNext()) { + Block b = i.next(); + if (b.getWorld() != assault.getWorld()) + continue; + ApplicableRegionSet regions = WorldguardUtils.getRegionsAt(b.getLocation()); + boolean isInAssaultRegion = false; + for (com.sk89q.worldguard.protection.regions.ProtectedRegion tregion : regions.getRegions()) { + if (assault.getRegionName().equals(tregion.getId())) { + isInAssaultRegion = true; + } + } + if (!isInAssaultRegion) + continue; + // first see if it is outside the destroyable area + org.bukkit.util.Vector min = assault.getMinPos(); + org.bukkit.util.Vector max = assault.getMaxPos(); + + if (b.getLocation().getBlockX() < min.getBlockX() || + b.getLocation().getBlockX() > max.getBlockX() || + b.getLocation().getBlockZ() < min.getBlockZ() || + b.getLocation().getBlockZ() > max.getBlockZ() || + !Settings.AssaultDestroyableBlocks.contains(b.getType()) || + Arrays.binarySearch(fragileBlocks, b.getRelative(BlockFace.SOUTH).getType()) >= 0 || + Arrays.binarySearch(fragileBlocks, b.getRelative(BlockFace.DOWN).getType()) >= 0 || + Arrays.binarySearch(fragileBlocks, b.getRelative(BlockFace.UP).getType()) >= 0 || + Arrays.binarySearch(fragileBlocks, b.getRelative(BlockFace.EAST).getType()) >= 0 || + Arrays.binarySearch(fragileBlocks, b.getRelative(BlockFace.WEST).getType()) >= 0 || + Arrays.binarySearch(fragileBlocks, b.getRelative(BlockFace.NORTH).getType()) >= 0 ) { + i.remove(); + } + + + // whether or not you actually destroyed the block, add to damages + long damages = assault.getDamages() + Settings.AssaultDamagesPerBlock; + if (damages < assault.getMaxDamages()) { + assault.setDamages(damages); + } else { + assault.setDamages(assault.getMaxDamages()); + } + + // notify nearby players of the damages, do this 1 second later so all damages from this volley will be included + if (System.currentTimeMillis() < lastDamagesUpdate + 4000) { + continue; + } + final Location floc = b.getLocation(); + final World fworld = b.getWorld(); + new BukkitRunnable() { + @Override + public void run() { + long fdamages = assault.getDamages(); + for (Player p : fworld.getPlayers()) { + if (Math.round(p.getLocation().getBlockX() / 1000.0) == Math.round(floc.getBlockX() / 1000.0) && + Math.round(p.getLocation().getBlockZ() / 1000.0) == Math.round(floc.getBlockZ() / 1000.0)) { + p.sendMessage("Damages: " + fdamages); + + } + } + } + }.runTaskLater(Movecraft.getInstance(), 20); + lastDamagesUpdate = System.currentTimeMillis(); + + } + } + + } } From cc52a16155904653aa3b4c36c6ae68a76cc2eafd Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Sat, 29 Jun 2019 13:09:49 +0200 Subject: [PATCH 028/304] Further fixes --- .../net/countercraft/movecraft/async/AsyncManager.java | 9 ++------- .../countercraft/movecraft/utils/WorldguardUtils.java | 8 ++++++++ 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java index c814986d8..7053e44e3 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java @@ -21,8 +21,6 @@ import com.google.common.collect.Lists; import com.sk89q.worldguard.bukkit.WorldGuardPlugin; import com.sk89q.worldguard.protection.ApplicableRegionSet; -import com.sk89q.worldguard.protection.flags.Flags; -import com.sk89q.worldguard.protection.flags.StateFlag; import com.sk89q.worldguard.protection.managers.RegionManager; import com.sk89q.worldguard.protection.regions.ProtectedRegion; import net.countercraft.movecraft.Movecraft; @@ -39,10 +37,7 @@ import net.countercraft.movecraft.events.CraftDetectEvent; import net.countercraft.movecraft.localisation.I18nSupport; import net.countercraft.movecraft.mapUpdater.MapUpdateManager; -import net.countercraft.movecraft.utils.CollectionUtils; -import net.countercraft.movecraft.utils.HashHitBox; -import net.countercraft.movecraft.utils.HitBox; -import net.countercraft.movecraft.utils.LegacyUtils; +import net.countercraft.movecraft.utils.*; import org.bukkit.*; import org.bukkit.block.Block; import org.bukkit.block.BlockFace; @@ -596,7 +591,7 @@ private void detectSinking(){ for (MovecraftLocation location : pcraft.getHitBox()){ ApplicableRegionSet regions = regionManager.getApplicableRegions(location.toBukkit(pcraft.getW())); for (ProtectedRegion pr : regions.getRegions()){ - if (pr.getFlag(Flags.PVP).equals(StateFlag.State.DENY)){ + if (WorldguardUtils.pvpAllowed(pr)){ region = pr; break; } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/WorldguardUtils.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/WorldguardUtils.java index 2164318e9..8c6f0eceb 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/WorldguardUtils.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/WorldguardUtils.java @@ -112,4 +112,12 @@ public static RegionManager getRegionManager(World world){ public Flag flag(String string){ return null; } + + public static boolean pvpAllowed(ProtectedRegion region){ + if (Settings.IsLegacy){ + return region.getFlag(DefaultFlag.PVP).equals(StateFlag.State.ALLOW); + } else { + return region.getFlag(Flags.PVP).equals(StateFlag.State.ALLOW); + } + } } From 0b9c052bfc4e383eeb4233411e9719f66b10acd6 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Sat, 29 Jun 2019 13:11:53 +0200 Subject: [PATCH 029/304] Further fixes --- .../java/net/countercraft/movecraft/sign/RemoteSign.java | 1 + .../java/net/countercraft/movecraft/sign/StatusSign.java | 6 +----- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RemoteSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RemoteSign.java index cddd58f21..91eae6c84 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RemoteSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RemoteSign.java @@ -23,6 +23,7 @@ public final class RemoteSign implements Listener{ private static final String HEADER = "Remote Sign"; + @EventHandler public final void onSignChange(SignChangeEvent event) { if (!event.getLine(0).equalsIgnoreCase(HEADER)) { diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/StatusSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/StatusSign.java index 32346e7b8..f61118f30 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/StatusSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/StatusSign.java @@ -83,11 +83,7 @@ public final void onSignTranslate(SignTranslateEvent event) { if(foundBlocks.containsKey(flyBlock) && minimum>0) { // if it has a minimum, it should be considered for sinking consideration int amount=foundBlocks.get(flyBlock); Double percentPresent=(double) (amount*100/totalBlocks); - /* - int deshiftedID=flyBlockID; - if(deshiftedID>10000) { - deshiftedID=(deshiftedID-10000)>>4; - }*/ + String signText=""; if(percentPresent>minimum*1.04) { signText+= ChatColor.GREEN; From 95e6f25678126a0fd498c0871007ff705e9143b2 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Sat, 29 Jun 2019 13:12:29 +0200 Subject: [PATCH 030/304] Further fixes --- .../main/java/net/countercraft/movecraft/sign/RemoteSign.java | 1 + .../java/net/countercraft/movecraft/utils/WorldguardUtils.java | 1 + 2 files changed, 2 insertions(+) diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RemoteSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RemoteSign.java index 91eae6c84..286f06da8 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RemoteSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RemoteSign.java @@ -24,6 +24,7 @@ public final class RemoteSign implements Listener{ private static final String HEADER = "Remote Sign"; + @EventHandler public final void onSignChange(SignChangeEvent event) { if (!event.getLine(0).equalsIgnoreCase(HEADER)) { diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/WorldguardUtils.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/WorldguardUtils.java index 8c6f0eceb..df445dd05 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/WorldguardUtils.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/WorldguardUtils.java @@ -120,4 +120,5 @@ public static boolean pvpAllowed(ProtectedRegion region){ return region.getFlag(Flags.PVP).equals(StateFlag.State.ALLOW); } } + } From 5d9e800d767770ed861e3846f71810459299a0e2 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Sat, 29 Jun 2019 22:42:58 +0200 Subject: [PATCH 031/304] Reworking gravity --- .../movecraft/async/AsyncManager.java | 31 +++++++++++++++++++ .../movecraft/utils/WorldguardUtils.java | 8 ----- 2 files changed, 31 insertions(+), 8 deletions(-) diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java index 7053e44e3..4b06ce0c3 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java @@ -1041,6 +1041,37 @@ public void run() { } } + private void processGravity(){ + boolean onGround = false; + for (Craft pCraft : CraftManager.getInstance()){ + if (!pCraft.getType().getUseGravity()){ + continue; + } + int minX = pCraft.getHitBox().getMinX() - 1; + int maxX = pCraft.getHitBox().getMaxX() + 1; + int minY = pCraft.getHitBox().getMinY() - 1; + int minZ = pCraft.getHitBox().getMinX() - 1; + int maxZ = pCraft.getHitBox().getMaxX() + 1; + + //Check if there are any solid blocks below the craft + for (int x = minX ; x <= maxX ; x++){ + for (int z = minZ ; z <= maxZ ; z++){ + if (pCraft.getW().getBlockAt(x,minY,z).getType().isSolid()){ + onGround = true; + break; + } + } + if (onGround) + break; + } + if (onGround){ + return; + } + pCraft.translate(0,-1,0); + + } + } + //Removed for refactor /*private void processScheduledBlockChanges() { for (World w : Bukkit.getWorlds()) { diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/WorldguardUtils.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/WorldguardUtils.java index df445dd05..2edfe94f8 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/WorldguardUtils.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/WorldguardUtils.java @@ -113,12 +113,4 @@ public Flag flag(String string){ return null; } - public static boolean pvpAllowed(ProtectedRegion region){ - if (Settings.IsLegacy){ - return region.getFlag(DefaultFlag.PVP).equals(StateFlag.State.ALLOW); - } else { - return region.getFlag(Flags.PVP).equals(StateFlag.State.ALLOW); - } - } - } From 5661afbd2d3292edc3678bad6af22fcae175ed87 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Sat, 6 Jul 2019 10:33:56 +0200 Subject: [PATCH 032/304] Fixing how example craft files are saved --- .../countercraft/movecraft/craft/CraftManager.java | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/CraftManager.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/CraftManager.java index 252598e6e..bb516c16c 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/CraftManager.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/CraftManager.java @@ -20,7 +20,6 @@ import net.countercraft.movecraft.Movecraft; import net.countercraft.movecraft.config.Settings; import net.countercraft.movecraft.localisation.I18nSupport; -import org.bukkit.Material; import org.bukkit.World; import org.bukkit.entity.Player; import org.bukkit.scheduler.BukkitRunnable; @@ -29,7 +28,6 @@ import org.jetbrains.annotations.Nullable; import java.io.File; -import java.io.FileWriter; import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; @@ -75,8 +73,15 @@ private Set loadCraftTypes(){ Movecraft.getInstance().saveResource("types/legacy/SubAirship.craft", false); Movecraft.getInstance().saveResource("types/legacy/Submarine.craft", false); Movecraft.getInstance().saveResource("types/legacy/Turret.craft", false); + final File legacydir = new File(craftsFile,"legacy"); + for (File craftFile : legacydir.listFiles()){ + final String fileName = craftFile.getName(); + if (!craftFile.renameTo(new File(craftFile, fileName))) continue; + craftFile.delete(); + } + if (legacydir.listFiles().length == 0) + legacydir.delete(); } else if (Settings.is1_14){ //if 1.14, save 1.14 files - Movecraft.getInstance().getResource("types/1_14/airship.craft"); Movecraft.getInstance().saveResource("types/1_14/airship.craft", false); Movecraft.getInstance().saveResource("types/1_14/airskiff.craft", false); Movecraft.getInstance().saveResource("types/1_14/BigAirship.craft", false); From 71b0b213a657aa0a4bc668dbabbb30c1ef8d5516 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Sat, 3 Aug 2019 20:33:27 +0200 Subject: [PATCH 033/304] Implemented WG/WE 7.0.1, fixing some siege bugs and made this fork mostly even with upstream --- modules/Movecraft/pom.xml | 66 +++----------- .../net/countercraft/movecraft/Movecraft.java | 27 ++---- .../movecraft/async/AsyncManager.java | 19 ++++- .../async/rotation/RotationTask.java | 11 ++- .../movecraft/commands/MovecraftCommand.java | 4 +- .../movecraft/commands/SiegeCommand.java | 64 ++++++++++---- .../WorldGuardCompatManager.java | 3 +- .../movecraft/listener/BlockListener.java | 29 ++++++- .../movecraft/repair/RepairManager.java | 75 +++++++++++++++- .../movecraft/sign/RegionDamagedSign.java | 23 +++-- .../movecraft/sign/RepairSign.java | 1 - .../movecraft/utils/LegacyWEUtils.java | 10 --- .../movecraft/utils/WGCustomFlagsUtils.java | 4 +- .../movecraft/utils/WorldguardUtils.java | 20 ++--- .../movecraft/utils/weVectorUtils.java | 60 ------------- .../warfare/assault/AssaultTask.java | 26 +++++- .../movecraft/warfare/siege/Siege.java | 24 +++--- .../warfare/siege/SiegePaymentTask.java | 12 ++- .../warfare/siege/SiegePreparationTask.java | 3 + .../warfare/siege/SiegeProgressTask.java | 38 ++++++--- .../movecraft/warfare/siege/SiegeTask.java | 11 ++- .../localisation/movecraftlang_en.properties | 12 +-- .../localisation/movecraftlang_he.properties | 85 ------------------- .../movecraft/utils/LegacyUtils.java | 35 ++++++++ modules/worldedit/WE7Utils/pom.xml | 10 +-- 25 files changed, 344 insertions(+), 328 deletions(-) delete mode 100644 modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/weVectorUtils.java delete mode 100644 modules/Movecraft/src/main/resources/localisation/movecraftlang_he.properties diff --git a/modules/Movecraft/pom.xml b/modules/Movecraft/pom.xml index ceb8a38bf..6d92e56f5 100644 --- a/modules/Movecraft/pom.xml +++ b/modules/Movecraft/pom.xml @@ -81,19 +81,24 @@ 7.0.0-SNAPSHOT - com.sk89q - worldguard - LATEST + com.sk89q.worldguard + worldguard-core + 7.0.1-SNAPSHOT com.sk89q.worldguard - worldguard-core - 7.0.0-SNAPSHOT + worldguard-bukkit + 7.0.1-SNAPSHOT + + + com.sk89q + worldguard + 6.1.1-SNAPSHOT com.sk89q worldedit - LATEST + 6.0.0-SNAPSHOT net.countercraft @@ -170,55 +175,6 @@ system ${project.basedir}/../../libs/WGCustomFlags.jar - - com.massivecraft - Factions - LATEST - system - ${project.basedir}/../../libs/Factions.jar - - - com.massivecraft - MassiveCore - LATEST - system - ${project.basedir}/../../libs/MassiveCore.jar - - - com.daemitus - Deadbolt - 1.0 - system - ${project.basedir}/../../libs/Deadbolt-1.0-SNAPSHOT.jar - - - me.ryanhamshire - GriefPrevention - 1.5.0 - system - ${project.basedir}/../../libs/GriefPrevention.jar - - - sun.jdk - kingdoms - 1.5.0 - system - ${project.basedir}/../../libs/FabledKingdoms.jar - - - sun.jdk - redprotect - 1.5.0 - system - ${project.basedir}/../../libs/RedProtect-7.5.5-b129-Universal.jar - - - com.dre - Brewery - 1.7.1 - system - ${project.basedir}/../../libs/Brewery-1.7.1.jar - org.jetbrains annotations-java5 diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java index fb5f39791..8138bcbb7 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java @@ -18,21 +18,15 @@ package net.countercraft.movecraft; import at.pavlov.cannons.Cannons; -import br.net.fabiozumbi12.RedProtect.Bukkit.RedProtect; -import com.daemitus.deadbolt.DeadboltPlugin; -import com.dre.brewery.P; import com.earth2me.essentials.Essentials; -import com.massivecraft.factions.Factions; import com.mewin.WGCustomFlags.WGCustomFlagsPlugin; import com.palmergames.bukkit.towny.Towny; import com.sk89q.worldedit.bukkit.WorldEditPlugin; import com.sk89q.worldguard.bukkit.WorldGuardPlugin; import com.sk89q.worldguard.protection.flags.StateFlag; -import com.songoda.kingdoms.main.Kingdoms; -import me.ryanhamshire.GriefPrevention.GriefPrevention; import net.countercraft.movecraft.async.AsyncManager; import net.countercraft.movecraft.commands.*; -import net.countercraft.movecraft.compatmanager.*; +import net.countercraft.movecraft.compatmanager.WorldGuardCompatManager; import net.countercraft.movecraft.config.Settings; import net.countercraft.movecraft.craft.CraftManager; import net.countercraft.movecraft.listener.BlockListener; @@ -74,16 +68,6 @@ public class Movecraft extends JavaPlugin { private static Cannons cannonsPlugin = null; private static Towny townyPlugin = null; private static Essentials essentialsPlugin = null; - private static Factions factionsPlugin; - private static DeadboltPlugin deadboltPlugin; - private static GriefPrevention griefPreventionPlugin; - private static Kingdoms kingdomsPlugin; - private static RedProtect redProtectPlugin; - private static P breweryPlugin; - /*public HashMap blockFadeTimeMap = new HashMap<>(); - public HashMap blockFadeTypeMap = new HashMap<>(); - public HashMap blockFadeWaterMap = new HashMap<>(); - public HashMap blockFadeWorldMap = new HashMap<>();*/ private Logger logger; private boolean shuttingDown; private WorldHandler worldHandler; @@ -106,6 +90,7 @@ public void onDisable() { @Override public void onEnable() { + saveLocaleFiles(); String packageName = this.getServer().getClass().getPackage().getName(); String version = packageName.substring(packageName.lastIndexOf('.') + 1); String[] parts = version.split("_"); @@ -129,6 +114,7 @@ public void onEnable() { Settings.LOCALE = getConfig().getString("Locale"); + I18nSupport.init(); Settings.RestrictSiBsToRegions = getConfig().getBoolean("RestrictSiBsToRegions", false); Settings.Debug = getConfig().getBoolean("Debug", false); Settings.DisableSpillProtection = getConfig().getBoolean("DisableSpillProtection", false); @@ -517,7 +503,12 @@ private void saveLegacyConfig(){ e.printStackTrace(); } } - + private void saveLocaleFiles(){ + final String[] LOCALES = {"en", "cz", "nl"}; + for (String locale : LOCALES){ + saveResource("localisation/movecraftlang_" + locale + ".properties", false); + } + } public WorldGuardPlugin getWorldGuardPlugin() { diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java index 22ca2c001..39ad6dd30 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java @@ -19,10 +19,14 @@ import at.pavlov.cannons.cannon.Cannon; import com.google.common.collect.Lists; +import com.sk89q.worldedit.bukkit.BukkitAdapter; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldguard.WorldGuard; import com.sk89q.worldguard.bukkit.WorldGuardPlugin; import com.sk89q.worldguard.protection.ApplicableRegionSet; import com.sk89q.worldguard.protection.managers.RegionManager; import com.sk89q.worldguard.protection.regions.ProtectedRegion; +import com.sk89q.worldguard.protection.regions.RegionContainer; import net.countercraft.movecraft.Movecraft; import net.countercraft.movecraft.MovecraftLocation; import net.countercraft.movecraft.Rotation; @@ -582,9 +586,20 @@ private void detectSinking(){ if (Movecraft.getInstance().getWorldGuardPlugin() != null){ WorldGuardPlugin wgPlugin = Movecraft.getInstance().getWorldGuardPlugin(); ProtectedRegion region = null; - RegionManager regionManager = wgPlugin.getRegionManager(pcraft.getW()); + RegionManager regionManager; + if (Settings.IsLegacy){ + regionManager = LegacyUtils.getRegionManager(wgPlugin, pcraft.getW()); + } else { + RegionContainer container = WorldGuard.getInstance().getPlatform().getRegionContainer(); + regionManager = container.get(BukkitAdapter.adapt(pcraft.getW())); + } for (MovecraftLocation location : pcraft.getHitBox()){ - ApplicableRegionSet regions = regionManager.getApplicableRegions(location.toBukkit(pcraft.getW())); + ApplicableRegionSet regions; + if (Settings.IsLegacy) + regions = LegacyUtils.getApplicableRegions(regionManager, location.toBukkit(pcraft.getW())); + else { + regions = regionManager.getApplicableRegions(BlockVector3.at(location.getX(), location.getY(), location.getZ())); + } for (ProtectedRegion pr : regions.getRegions()){ if (WorldguardUtils.pvpAllowed(pr)){ region = pr; diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/rotation/RotationTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/rotation/RotationTask.java index d877ab82e..373f04e65 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/rotation/RotationTask.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/rotation/RotationTask.java @@ -20,7 +20,10 @@ import com.palmergames.bukkit.towny.object.Town; import com.palmergames.bukkit.towny.object.TownBlock; import com.palmergames.bukkit.towny.object.TownyWorld; +import com.sk89q.worldedit.bukkit.BukkitAdapter; +import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldguard.LocalPlayer; +import com.sk89q.worldguard.WorldGuard; import com.sk89q.worldguard.protection.ApplicableRegionSet; import net.countercraft.movecraft.Movecraft; import net.countercraft.movecraft.MovecraftLocation; @@ -395,7 +398,13 @@ private void isTownyBlock(Location plugLoc, Player craftPilot){ if (failed) { if (Movecraft.getInstance().getWorldGuardPlugin() != null && Movecraft.getInstance().getWGCustomFlagsPlugin() != null && Settings.WGCustomFlagsUsePilotFlag) { LocalPlayer lp = Movecraft.getInstance().getWorldGuardPlugin().wrapPlayer(p); - ApplicableRegionSet regions = Movecraft.getInstance().getWorldGuardPlugin().getRegionManager(plugLoc.getWorld()).getApplicableRegions(plugLoc); + ApplicableRegionSet regions; + if (Settings.IsLegacy){ + regions = LegacyUtils.getApplicableRegions(LegacyUtils.getRegionManager(Movecraft.getInstance().getWorldGuardPlugin(), plugLoc.getWorld()), plugLoc);//.getApplicableRegions(); + } else { + regions = WorldGuard.getInstance().getPlatform().getRegionContainer().get(BukkitAdapter.adapt(plugLoc.getWorld())).getApplicableRegions(BlockVector3.at(plugLoc.getBlockX(), plugLoc.getBlockY(), plugLoc.getBlockZ())); + } + if (regions.size() != 0) { WGCustomFlagsUtils WGCFU = new WGCustomFlagsUtils(); if (WGCFU.validateFlag(plugLoc, Movecraft.FLAG_ROTATE, lp)) { diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/MovecraftCommand.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/MovecraftCommand.java index c037b44ef..8e3bc0ed5 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/MovecraftCommand.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/MovecraftCommand.java @@ -3,6 +3,7 @@ import net.countercraft.movecraft.Movecraft; import net.countercraft.movecraft.craft.CraftManager; import net.countercraft.movecraft.localisation.I18nSupport; +import org.bukkit.Bukkit; import org.bukkit.command.Command; import org.bukkit.command.CommandSender; import org.bukkit.command.TabExecutor; @@ -39,7 +40,8 @@ public boolean onCommand(CommandSender commandSender, Command command, String s, if (args.length == 1 && args[0].equalsIgnoreCase("reloadplugin") && commandSender.hasPermission("movecraft.commands.movecraft.reloadconfig")){ Movecraft.getInstance().reloadConfig(); Movecraft.getInstance().getLogger().info("Reloading Movecraft"); - Movecraft.getInstance().onEnable(); + Bukkit.getServer().getPluginManager().disablePlugin(Movecraft.getInstance()); + Bukkit.getServer().getPluginManager().enablePlugin(Movecraft.getInstance()); commandSender.sendMessage(MOVECRAFT_COMMAND_PREFIX + "Reloaded Movecraft"); return true; } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/SiegeCommand.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/SiegeCommand.java index 03fb9d970..96853a9bd 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/SiegeCommand.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/SiegeCommand.java @@ -1,44 +1,35 @@ package net.countercraft.movecraft.commands; +import com.sk89q.worldedit.bukkit.BukkitAdapter; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldguard.WorldGuard; import com.sk89q.worldguard.protection.ApplicableRegionSet; import com.sk89q.worldguard.protection.regions.ProtectedRegion; import net.countercraft.movecraft.Movecraft; -import net.countercraft.movecraft.config.Settings; import net.countercraft.movecraft.MovecraftLocation; +import net.countercraft.movecraft.config.Settings; import net.countercraft.movecraft.craft.Craft; import net.countercraft.movecraft.craft.CraftManager; import net.countercraft.movecraft.localisation.I18nSupport; +import net.countercraft.movecraft.utils.LegacyUtils; import net.countercraft.movecraft.utils.TopicPaginator; -import net.countercraft.movecraft.utils.WorldguardUtils; import net.countercraft.movecraft.warfare.siege.Siege; import net.countercraft.movecraft.warfare.siege.SiegeManager; import net.countercraft.movecraft.warfare.siege.SiegeStage; import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.Sound; -import org.bukkit.World; -import org.bukkit.boss.BarColor; -import org.bukkit.boss.BarFlag; -import org.bukkit.boss.BarStyle; import org.bukkit.command.Command; import org.bukkit.command.CommandExecutor; import org.bukkit.command.CommandSender; -import org.bukkit.command.TabExecutor; import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.text.NumberFormat; import java.util.*; -import java.util.Arrays; -import java.util.List; -import java.util.Calendar; -import java.util.TimeZone; import java.util.logging.Level; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - import static net.countercraft.movecraft.utils.ChatUtils.MOVECRAFT_COMMAND_PREFIX; public class SiegeCommand implements CommandExecutor { @@ -170,7 +161,13 @@ private boolean beginCommand(CommandSender commandSender){ return true; } MovecraftLocation mid = siegeCraft.getHitBox().getMidPoint(); - if(!Movecraft.getInstance().getWorldGuardPlugin().getRegionManager(player.getWorld()).getRegion(siege.getAttackRegion()).contains(mid.getX(), mid.getY(), mid.getZ())) { + ProtectedRegion siegeRegion; + if (Settings.IsLegacy){ + siegeRegion = LegacyUtils.getRegionManager(Movecraft.getInstance().getWorldGuardPlugin(), player.getWorld()).getRegion(siege.getAttackRegion()); + } else { + siegeRegion = WorldGuard.getInstance().getPlatform().getRegionContainer().get(BukkitAdapter.adapt(player.getWorld())).getRegion(siege.getAttackRegion()); + } + if(!siegeRegion.contains(mid.getX(), mid.getY(), mid.getZ())) { player.sendMessage(MOVECRAFT_COMMAND_PREFIX + I18nSupport.getInternationalisedString("You must be piloting a craft in the siege region!")); return true; } @@ -185,7 +182,7 @@ private void startSiege(Siege siege, Player player, long cost) { Bukkit.getServer().dispatchCommand(Bukkit.getServer().getConsoleSender(), startCommand.replaceAll("%r", siege.getAttackRegion()).replaceAll("%c", "" + siege.getCost())); } Bukkit.getServer().broadcastMessage(String.format(I18nSupport.getInternationalisedString("Siege - Siege About To Begin") - , player.getDisplayName(), siege.getName(), siege.getDelayBeforeStart() / 60)); + , player.getDisplayName(), siege.getName()) + formatMinutes(siege.getDelayBeforeStart())); for (Player p : Bukkit.getOnlinePlayers()) { p.playSound(p.getLocation(), Sound.ENTITY_WITHER_DEATH, 1, 0.25F); } @@ -211,7 +208,12 @@ private int getDayOfWeek() { @Nullable private Siege getSiege(Player player, SiegeManager siegeManager) { - ApplicableRegionSet regions = Movecraft.getInstance().getWorldGuardPlugin().getRegionManager(player.getWorld()).getApplicableRegions(player.getLocation()); + ApplicableRegionSet regions; + if (Settings.IsLegacy){ + regions = LegacyUtils.getApplicableRegions(LegacyUtils.getRegionManager(Movecraft.getInstance().getWorldGuardPlugin(), player.getWorld()), player.getLocation());//.getApplicableRegions(); + } else { + regions = WorldGuard.getInstance().getPlatform().getRegionContainer().get(BukkitAdapter.adapt(player.getWorld())).getApplicableRegions(BlockVector3.at(player.getLocation().getBlockX(), player.getLocation().getBlockY(), player.getLocation().getBlockZ())); + } for (ProtectedRegion tRegion : regions.getRegions()) { for (Siege tempSiege : siegeManager.getSieges()) { if (tRegion.getId().equalsIgnoreCase(tempSiege.getAttackRegion())) { @@ -225,7 +227,12 @@ private Siege getSiege(Player player, SiegeManager siegeManager) { private long calcSiegeCost(Siege siege, SiegeManager siegeManager, Player player) { long cost = siege.getCost(); for (Siege tempSiege : siegeManager.getSieges()) { - ProtectedRegion tRegion = Movecraft.getInstance().getWorldGuardPlugin().getRegionManager(player.getWorld()).getRegion(tempSiege.getCaptureRegion()); + ProtectedRegion tRegion; + if (Settings.IsLegacy){ + tRegion = LegacyUtils.getRegionManager(Movecraft.getInstance().getWorldGuardPlugin(), player.getWorld()).getRegion(tempSiege.getAttackRegion()); + } else { + tRegion = WorldGuard.getInstance().getPlatform().getRegionContainer().get(BukkitAdapter.adapt(player.getWorld())).getRegion(tempSiege.getAttackRegion()); + } assert tRegion != null; if (tempSiege.isDoubleCostPerOwnedSiegeRegion() && tRegion.getOwners().contains(player.getUniqueId())) cost *= 2; @@ -351,4 +358,25 @@ private void displayInfo(@NotNull CommandSender sender, @NotNull Siege siege) { sender.sendMessage(I18nSupport.getInternationalisedString("Siege - End Time") + end + militaryTimeIntToString(siege.getScheduleEnd()) + " " + Settings.SiegeTimeZone); sender.sendMessage(I18nSupport.getInternationalisedString("Siege - Duration") + ChatColor.WHITE + secondsIntToString(siege.getDuration())); } + + private String formatMinutes(int seconds) { + if (seconds < 60) { + if (seconds > 0) { + return String.format(I18nSupport.getInternationalisedString("Siege - Ending in X seconds"), seconds); + } else { + return I18nSupport.getInternationalisedString("Siege - Ending Soon"); + } + } + + int minutes = seconds / 60; + if (minutes == 1) { + return I18nSupport.getInternationalisedString("Siege - Ending In 1 Minute"); + } + else { + + return String.format(I18nSupport.getInternationalisedString("Siege - Ending In X Minutes"), minutes); + + + } + } } \ No newline at end of file diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/compatmanager/WorldGuardCompatManager.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/compatmanager/WorldGuardCompatManager.java index a48508fc1..f0ca7130f 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/compatmanager/WorldGuardCompatManager.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/compatmanager/WorldGuardCompatManager.java @@ -11,6 +11,7 @@ import net.countercraft.movecraft.events.CraftRotateEvent; import net.countercraft.movecraft.events.CraftTranslateEvent; import net.countercraft.movecraft.localisation.I18nSupport; +import net.countercraft.movecraft.utils.LegacyUtils; import org.bukkit.World; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; @@ -49,7 +50,7 @@ public void onCraftRotateEvent(CraftRotateEvent event){ } private boolean pilotHasAccessToRegion(Player player, MovecraftLocation location, World world){ if (Settings.IsLegacy){ - return Movecraft.getInstance().getWorldGuardPlugin().canBuild(player, location.toBukkit(world)); + return LegacyUtils.canBuild(Movecraft.getInstance().getWorldGuardPlugin(), world, location, player); } else { RegionQuery query = WorldGuard.getInstance().getPlatform().getRegionContainer().createQuery(); LocalPlayer lPlayer = Movecraft.getInstance().getWorldGuardPlugin().wrapPlayer(player); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/BlockListener.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/BlockListener.java index 3ee06b1ef..04bc30676 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/BlockListener.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/BlockListener.java @@ -17,8 +17,14 @@ package net.countercraft.movecraft.listener; +import com.sk89q.worldedit.bukkit.BukkitAdapter; +import com.sk89q.worldedit.math.BlockVector3; +import com.sk89q.worldguard.WorldGuard; import com.sk89q.worldguard.protection.ApplicableRegionSet; import com.sk89q.worldguard.protection.flags.DefaultFlag; +import com.sk89q.worldguard.protection.flags.Flags; +import com.sk89q.worldguard.protection.flags.StateFlag; +import com.sk89q.worldguard.protection.regions.ProtectedRegion; import net.countercraft.movecraft.Movecraft; import net.countercraft.movecraft.utils.LegacyUtils; import net.countercraft.movecraft.utils.MathUtils; @@ -77,7 +83,12 @@ public void onBlockPlace(final BlockPlaceEvent e) { return; } Location loc = e.getBlockPlaced().getLocation(); - ApplicableRegionSet regions = Movecraft.getInstance().getWorldGuardPlugin().getRegionManager(loc.getWorld()).getApplicableRegions(loc); + ApplicableRegionSet regions; + if (Settings.IsLegacy){ + regions = LegacyUtils.getApplicableRegions(LegacyUtils.getRegionManager(Movecraft.getInstance().getWorldGuardPlugin(), loc.getWorld()), loc);//.getApplicableRegions(); + } else { + regions = WorldGuard.getInstance().getPlatform().getRegionContainer().get(BukkitAdapter.adapt(loc.getWorld())).getApplicableRegions(BlockVector3.at(loc.getBlockX(), loc.getBlockY(), loc.getBlockZ())); + } if (regions.size() == 0) { e.getPlayer().sendMessage(I18nSupport.getInternationalisedString("SIB MUST BE PLACED IN REGION")); e.setCancelled(true); @@ -272,9 +283,19 @@ public void onBlockIgnite(BlockIgniteEvent event) { } // check to see if fire spread is allowed, don't check if compatmanager integration is not enabled if (Movecraft.getInstance().getWorldGuardPlugin() != null && (Settings.WorldGuardBlockMoveOnBuildPerm || Settings.WorldGuardBlockSinkOnPVPPerm)) { - ApplicableRegionSet set = Movecraft.getInstance().getWorldGuardPlugin().getRegionManager(testBlock.getWorld()).getApplicableRegions(testBlock.getLocation()); - if (!set.allows(DefaultFlag.FIRE_SPREAD)) { - return; + ApplicableRegionSet set; + Location loc = testBlock.getLocation(); + if (Settings.IsLegacy){ + set = LegacyUtils.getApplicableRegions(LegacyUtils.getRegionManager(Movecraft.getInstance().getWorldGuardPlugin(), loc.getWorld()), loc);//.getApplicableRegions(); + if (!LegacyUtils.allows(set, DefaultFlag.FIRE_SPREAD)) + return; + } else { + set = WorldGuard.getInstance().getPlatform().getRegionContainer().get(BukkitAdapter.adapt(testBlock.getWorld())).getApplicableRegions(BlockVector3.at(loc.getBlockX(), loc.getBlockY(), loc.getBlockZ())); + for (ProtectedRegion region : set){ + if (region.getFlag(Flags.FIRE_SPREAD) == StateFlag.State.DENY){ + return; + } + } } } testBlock.setType(org.bukkit.Material.AIR); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/repair/RepairManager.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/repair/RepairManager.java index 6c8ec82e7..8855d0a8a 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/repair/RepairManager.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/repair/RepairManager.java @@ -29,7 +29,8 @@ public void convertOldCraftRepairStates(){ LinkedList> confirmedSimilarPlayerNames = new LinkedList<>(); //Check in the old RepairStates folder File repairStateDir = new File(Movecraft.getInstance().getDataFolder(),"RepairStates"); - if (!repairStateDir.exists()){ + File craftRepairStateDir = new File(Movecraft.getInstance().getDataFolder(),"CraftRepairStates"); + if (!repairStateDir.exists()||!craftRepairStateDir.exists()){ return; } int convertedRepairStates = 0; @@ -70,6 +71,43 @@ public void convertOldCraftRepairStates(){ } + } + } + File[] craftRepairStates = craftRepairStateDir.listFiles(); + if (craftRepairStateDir.exists() && (craftRepairStates != null || craftRepairStates.length > 0)){ + for (File rs : craftRepairStates){ + List similarPlayerNames = new ArrayList<>(); + if (!rs.getName().contains(".schematic")){ + continue; + } + String fileName = rs.getName(); + OfflinePlayer owner = null; + + for (OfflinePlayer op : Bukkit.getOfflinePlayers()){ + if (fileName.startsWith(op.getName())){ + owner = op; + similarPlayerNames.add(op.getName()); + } + } + + if (similarPlayerNames.size() > 1) { + String warning = String.join(", ", similarPlayerNames); + Movecraft.getInstance().getLogger().warning(I18nSupport.getInternationalisedString("RepairStateConversion - Similar players found") + warning); + confirmedSimilarPlayerNames.push(similarPlayerNames); + continue; + } else if (similarPlayerNames.isEmpty() || owner == null){ + repairStatesWithUnknownOwner++; + Movecraft.getInstance().getLogger().warning(String.format(I18nSupport.getInternationalisedString("Repair - Invalid Player Name"), fileName)); + continue; + } + if (confirmedRepairStates.containsKey(owner.getUniqueId())) { + confirmedRepairStates.get(owner.getUniqueId()).add(rs); + } else { + confirmedRepairStates.put(owner.getUniqueId(), new ArrayList<>()); + confirmedRepairStates.get(owner.getUniqueId()).add(rs); + } + + } } //Move the repair states with confirmed owners to UUID dirs @@ -110,6 +148,41 @@ public void convertOldCraftRepairStates(){ continue; } + OfflinePlayer owner = null; + for (OfflinePlayer op : Bukkit.getOfflinePlayers()){ + if (!op.getName().equals(pName)){ + continue; + } + owner = op; + } + //If a player with that name is not found, add to count, make a log output and continue the loop + if (owner == null){ + repairStatesWithUnknownOwner++; + Movecraft.getInstance().getLogger().warning(String.format(I18nSupport.getInternationalisedString("Repair - Invalid Player Name"), fileName)); + continue; + } + //Remove player name from the file + fileName = fileName.substring(pName.length()); + //if it begins with an underscore, remove that too + if (fileName.startsWith("_")){ + fileName = fileName.substring(1); + } + File playerDir = new File(repairStateDir, owner.getUniqueId().toString()); + File dest = new File(playerDir, fileName); + if (rs.renameTo(dest)){ //If successfully moved to UUID directory, add to count + convertedRepairStates++; + continue; + } //Add failed attempts to move to count as well + Movecraft.getInstance().getLogger().severe(String.format(I18nSupport.getInternationalisedString("RepairStateConversion - Conversion Failed"), fileName)); + failedConversions++; + } + for (File rs : craftRepairStateDir.listFiles()){ + String fileName = rs.getName(); + //Continue if the file doen't start with the player name + if (!fileName.startsWith(pName)){ + continue; + } + OfflinePlayer owner = null; for (OfflinePlayer op : Bukkit.getOfflinePlayers()){ if (!op.getName().equals(pName)){ diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RegionDamagedSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RegionDamagedSign.java index 9b44566d9..9b4549b18 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RegionDamagedSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RegionDamagedSign.java @@ -1,29 +1,22 @@ package net.countercraft.movecraft.sign; +import com.sk89q.worldedit.Vector; import com.sk89q.worldedit.bukkit.BukkitAdapter; import com.sk89q.worldedit.extent.clipboard.Clipboard; import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.world.block.BaseBlock; +import com.sk89q.worldguard.WorldGuard; import com.sk89q.worldguard.protection.managers.RegionManager; -import com.sk89q.worldedit.Vector; -import com.sk89q.worldedit.extent.clipboard.Clipboard; import com.sk89q.worldguard.protection.regions.ProtectedRegion; import net.countercraft.movecraft.Movecraft; import net.countercraft.movecraft.MovecraftLocation; -import net.countercraft.movecraft.MovecraftRepair; import net.countercraft.movecraft.config.Settings; import net.countercraft.movecraft.localisation.I18nSupport; import net.countercraft.movecraft.mapUpdater.MapUpdateManager; import net.countercraft.movecraft.mapUpdater.update.WorldEdit7UpdateCommand; -import net.countercraft.movecraft.repair.RepairUtils; +import net.countercraft.movecraft.mapUpdater.update.WorldEditUpdateCommand; import net.countercraft.movecraft.utils.LegacyUtils; import net.countercraft.movecraft.utils.LegacyWEUtils; -import net.countercraft.movecraft.utils.WorldEditUtils; -import net.countercraft.movecraft.utils.WorldguardUtils; -import org.bukkit.*; -import org.bukkit.block.Sign; -import org.bukkit.entity.Player; -import net.countercraft.movecraft.mapUpdater.update.WorldEditUpdateCommand; import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.Material; @@ -45,7 +38,7 @@ public void onSignRightClick(PlayerInteractEvent event){ if (!event.getAction().equals(Action.RIGHT_CLICK_BLOCK)){ return; } - if (!event.getClickedBlock().getType().name().endsWith("WALL_SIGN")){ + if (event.getClickedBlock().getType() != (Settings.is1_14 ? Material.OAK_WALL_SIGN : LegacyUtils.WALL_SIGN)){ return; } Sign sign = (Sign) event.getClickedBlock().getState(); @@ -67,7 +60,13 @@ public void onSignRightClick(PlayerInteractEvent event){ event.getPlayer().sendMessage(I18nSupport.getInternationalisedString("Assault - Repairing Region")); Movecraft.getInstance().getEconomy().withdrawPlayer(event.getPlayer(), damages); World world = event.getClickedBlock().getWorld(); - ProtectedRegion aRegion = Movecraft.getInstance().getWorldGuardPlugin().getRegionManager(world).getRegion(regionName); + ProtectedRegion aRegion; + if (Settings.IsLegacy) { + RegionManager rm = LegacyUtils.getRegionManager(Movecraft.getInstance().getWorldGuardPlugin(), world); + aRegion = rm.getRegion(regionName); + } else { + aRegion = WorldGuard.getInstance().getPlatform().getRegionContainer().get(BukkitAdapter.adapt(world)).getRegion(regionName); + } for (String ownerName : owners) { if (ownerName.length() > 16) { aRegion.getOwners().addPlayer(UUID.fromString(ownerName)); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RepairSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RepairSign.java index 0fbddf376..251d816ce 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RepairSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RepairSign.java @@ -129,7 +129,6 @@ private void signRightClick(PlayerInteractEvent event){ return; } String repairName = event.getPlayer().getName(); - repairName += "_"; repairName += sign.getLine(1); MovecraftRepair movecraftRepair = Movecraft.getInstance().getMovecraftRepair(); Clipboard clipboard = movecraftRepair.loadCraftRepairStateClipboard(pCraft, sign); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/LegacyWEUtils.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/LegacyWEUtils.java index 790e90069..37d9b78f9 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/LegacyWEUtils.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/LegacyWEUtils.java @@ -2,8 +2,6 @@ import com.sk89q.worldedit.blocks.BaseBlock; import com.sk89q.worldedit.extent.clipboard.Clipboard; -import com.sk89q.worldguard.protection.regions.ProtectedRegion; -import org.bukkit.util.Vector; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; @@ -18,14 +16,6 @@ public class LegacyWEUtils { e.printStackTrace(); } } - public static Vector getMinimumPoint(ProtectedRegion region){ - com.sk89q.worldedit.Vector weMin = region.getMaximumPoint(); - return WorldEditUtils.toBukkitVector(weMin); - } - public static Vector getMaximumPoint(ProtectedRegion region){ - com.sk89q.worldedit.Vector weMax = region.getMaximumPoint(); - return WorldEditUtils.toBukkitVector(weMax); - } public static BaseBlock getBlock(Clipboard clipboard, com.sk89q.worldedit.Vector pos){ try { diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/WGCustomFlagsUtils.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/WGCustomFlagsUtils.java index 8980403d9..35df171c3 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/WGCustomFlagsUtils.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/WGCustomFlagsUtils.java @@ -74,7 +74,7 @@ public void init() { public boolean validateFlag(Location loc, Object flag) { if (flag != null) { - StateFlag.State state = (StateFlag.State) Movecraft.getInstance().getWorldGuardPlugin().getRegionManager(loc.getWorld()).getApplicableRegions(loc).getFlag((Flag) flag); + StateFlag.State state = LegacyUtils.getFlag(Movecraft.getInstance().getWorldGuardPlugin(), loc, flag); return state != null && state == StateFlag.State.ALLOW; } else { return true; @@ -83,7 +83,7 @@ public boolean validateFlag(Location loc, Object flag) { public boolean validateFlag(Location loc, Object flag, LocalPlayer lp) { if (flag != null) { - StateFlag.State state = (StateFlag.State) Movecraft.getInstance().getWorldGuardPlugin().getRegionManager(loc.getWorld()).getApplicableRegions(loc).getFlag((Flag) flag, lp); + StateFlag.State state = LegacyUtils.getFlag(Movecraft.getInstance().getWorldGuardPlugin(), loc, flag, lp); return state != null && state == StateFlag.State.ALLOW; } else { return true; diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/WorldguardUtils.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/WorldguardUtils.java index f72f1e7f6..8258bd1c2 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/WorldguardUtils.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/WorldguardUtils.java @@ -11,13 +11,11 @@ import com.sk89q.worldguard.protection.regions.ProtectedRegion; import com.sk89q.worldguard.protection.regions.RegionQuery; import net.countercraft.movecraft.Movecraft; -import net.countercraft.movecraft.MovecraftLocation; import net.countercraft.movecraft.config.Settings; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.OfflinePlayer; import org.bukkit.World; -import org.bukkit.entity.Player; import java.util.UUID; @@ -53,19 +51,18 @@ public static String getRegionOwnerList(ProtectedRegion tRegion) { } public static boolean pvpAllowed(ProtectedRegion region){ if (Settings.IsLegacy) { - return region.getFlag(DefaultFlag.PVP).equals(StateFlag.State.ALLOW); + return region.getFlag(DefaultFlag.PVP) == StateFlag.State.ALLOW; } - return region.getFlag(Flags.PVP).equals(StateFlag.State.ALLOW); - } - public static boolean canBuild(World world, MovecraftLocation location, Player player){ - return Movecraft.getInstance().getWorldGuardPlugin().canBuild(player, location.toBukkit(world)); + return region.getFlag(Flags.PVP) == StateFlag.State.ALLOW; } + public static boolean explosionsPermitted(Location loc){ ApplicableRegionSet set; if (Settings.IsLegacy) { - set = Movecraft.getInstance().getWorldGuardPlugin().getRegionManager(loc.getWorld()).getApplicableRegions(loc); - if (!set.allows(DefaultFlag.OTHER_EXPLOSION)) { + RegionManager rm = LegacyUtils.getRegionManager(Movecraft.getInstance().getWorldGuardPlugin(), loc.getWorld()); + set = LegacyUtils.getApplicableRegions(rm, loc); + if (!LegacyUtils.allows(set, DefaultFlag.OTHER_EXPLOSION)) { return false; } } else { @@ -86,7 +83,8 @@ public static ApplicableRegionSet getRegionsAt(Location loc){ World world = loc.getWorld(); ApplicableRegionSet regions; if (Settings.IsLegacy) { - regions = Movecraft.getInstance().getWorldGuardPlugin().getRegionManager(world).getApplicableRegions(loc); + RegionManager rm = LegacyUtils.getRegionManager(Movecraft.getInstance().getWorldGuardPlugin(), world); + regions = LegacyUtils.getApplicableRegions(rm, loc); } else { RegionQuery query = WorldGuard.getInstance().getPlatform().getRegionContainer().createQuery(); com.sk89q.worldedit.world.World weWorld = new BukkitWorld(world); @@ -99,7 +97,7 @@ public static RegionManager getRegionManager(World world){ RegionManager manager; if (Settings.IsLegacy){ try { - manager = Movecraft.getInstance().getWorldGuardPlugin().getRegionManager(world); + manager = LegacyUtils.getRegionManager(Movecraft.getInstance().getWorldGuardPlugin(), world); } catch (Throwable t){ manager = null; } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/weVectorUtils.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/weVectorUtils.java deleted file mode 100644 index f06052949..000000000 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/weVectorUtils.java +++ /dev/null @@ -1,60 +0,0 @@ -package net.countercraft.movecraft.utils; - -import com.sk89q.worldedit.math.BlockVector3; -import com.sk89q.worldguard.protection.regions.ProtectedRegion; -import net.countercraft.movecraft.config.Settings; -import org.bukkit.util.Vector; - -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; - -public class weVectorUtils { - private static Method getMinimumPoint; - private static Method getMaximumPoint; - static { - try { - getMinimumPoint = ProtectedRegion.class.getDeclaredMethod("getMinimumPoint"); - getMaximumPoint = ProtectedRegion.class.getDeclaredMethod("getMaximumPoint"); - } catch (NoSuchMethodException e) { - getMaximumPoint = null; - getMinimumPoint = null; - } - } - public static org.bukkit.util.Vector getMinimumPoint(ProtectedRegion region) { - org.bukkit.util.Vector ret = null; - if (Settings.IsLegacy) { - ret = LegacyWEUtils.getMinimumPoint(region); - - } else { - - try { - BlockVector3 min = getMinimumPoint != null ? (BlockVector3) getMinimumPoint.invoke(region) : null; - if (min != null) { - ret = new org.bukkit.util.Vector(min.getBlockX(), min.getBlockY(), min.getBlockZ()); - } - } catch (IllegalAccessException | InvocationTargetException e) { - e.printStackTrace(); - } - } - return ret; - } - - public static org.bukkit.util.Vector getMaximumPoint(ProtectedRegion region){ - org.bukkit.util.Vector ret = null; - if (Settings.IsLegacy) { - ret = LegacyWEUtils.getMaximumPoint(region); - - } else { - try { - BlockVector3 min = getMaximumPoint != null ? (BlockVector3) getMaximumPoint.invoke(region) : null; - if (min != null) { - ret = new Vector(min.getBlockX(), min.getBlockY(), min.getBlockZ()); - } - } catch (IllegalAccessException | InvocationTargetException e) { - e.printStackTrace(); - } - - } - return ret; - } -} diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/assault/AssaultTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/assault/AssaultTask.java index 04979c574..3c246399b 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/assault/AssaultTask.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/assault/AssaultTask.java @@ -1,12 +1,17 @@ package net.countercraft.movecraft.warfare.assault; +import com.sk89q.worldedit.bukkit.BukkitAdapter; +import com.sk89q.worldguard.WorldGuard; import com.sk89q.worldguard.protection.flags.DefaultFlag; +import com.sk89q.worldguard.protection.flags.Flag; +import com.sk89q.worldguard.protection.flags.Flags; import com.sk89q.worldguard.protection.flags.StateFlag; import com.sk89q.worldguard.protection.regions.ProtectedRegion; import net.countercraft.movecraft.Movecraft; import net.countercraft.movecraft.config.Settings; import net.countercraft.movecraft.localisation.I18nSupport; import net.countercraft.movecraft.sign.RegionDamagedSign; +import net.countercraft.movecraft.utils.LegacyUtils; import org.bukkit.*; import org.bukkit.block.Sign; import org.bukkit.scheduler.BukkitRunnable; @@ -33,9 +38,17 @@ public void run() { assault.getRunning().set(false); World w = assault.getWorld(); Bukkit.getServer().broadcastMessage(String.format(I18nSupport.getInternationalisedString("Assault - Assault Successful"), assault.getRegionName())); - ProtectedRegion tRegion = Movecraft.getInstance().getWorldGuardPlugin().getRegionManager(w).getRegion(assault.getRegionName()); + ProtectedRegion tRegion; + Flag flag; + if (Settings.IsLegacy){ + tRegion = LegacyUtils.getRegionManager(Movecraft.getInstance().getWorldGuardPlugin(), w).getRegion(assault.getRegionName()); + flag = DefaultFlag.TNT; + } else { + tRegion = WorldGuard.getInstance().getPlatform().getRegionContainer().get(BukkitAdapter.adapt(w)).getRegion(assault.getRegionName()); + flag = Flags.TNT; + } assert tRegion != null; - tRegion.setFlag(DefaultFlag.TNT, StateFlag.State.DENY); + tRegion.setFlag(flag, StateFlag.State.DENY); //first, find a position for the repair beacon int beaconX = assault.getMinPos().getBlockX(); @@ -89,7 +102,7 @@ public void run() { w.getBlockAt(beaconX + 2, beaconY + 2, beaconZ + 2).setType(Material.BEACON); w.getBlockAt(beaconX + 2, beaconY + 3, beaconZ + 2).setType(Material.BEDROCK); // finally the sign on the beacon - w.getBlockAt(beaconX + 2, beaconY + 3, beaconZ + 1).setType(Material.OAK_WALL_SIGN); + w.getBlockAt(beaconX + 2, beaconY + 3, beaconZ + 1).setType(Settings.is1_14 ? Material.OAK_WALL_SIGN : LegacyUtils.WALL_SIGN); Sign s = (Sign) w.getBlockAt(beaconX + 2, beaconY + 3, beaconZ + 1).getState(); s.setLine(0, ChatColor.RED + I18nSupport.getInternationalisedString("Region Damaged")); s.setLine(1, I18nSupport.getInternationalisedString("Region Name")+":" + assault.getRegionName()); @@ -104,7 +117,12 @@ public void run() { // assault has failed to reach damage cap within required time assault.getRunning().set(false); Bukkit.getServer().broadcastMessage(String.format(I18nSupport.getInternationalisedString("Assault - Assault Failed"), assault.getRegionName())); - ProtectedRegion tRegion = Movecraft.getInstance().getWorldGuardPlugin().getRegionManager(assault.getWorld()).getRegion(assault.getRegionName()); + ProtectedRegion tRegion; + if (Settings.IsLegacy){ + tRegion = LegacyUtils.getRegionManager(Movecraft.getInstance().getWorldGuardPlugin(), assault.getWorld()).getRegion(assault.getRegionName()); + } else { + tRegion = WorldGuard.getInstance().getPlatform().getRegionContainer().get(BukkitAdapter.adapt(assault.getWorld())).getRegion(assault.getRegionName()); + } assert tRegion != null; tRegion.setFlag(DefaultFlag.TNT, StateFlag.State.DENY); // repair the damages that have occurred so far diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/siege/Siege.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/siege/Siege.java index 9bdde542c..14cdb1dbc 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/siege/Siege.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/siege/Siege.java @@ -1,9 +1,10 @@ package net.countercraft.movecraft.warfare.siege; import org.bukkit.Bukkit; -import org.bukkit.scoreboard.DisplaySlot; -import org.bukkit.scoreboard.Objective; -import org.bukkit.scoreboard.Scoreboard; +import org.bukkit.boss.BarColor; +import org.bukkit.boss.BarFlag; +import org.bukkit.boss.BarStyle; +import org.bukkit.boss.BossBar; import org.jetbrains.annotations.NotNull; import java.util.List; @@ -20,7 +21,7 @@ public class Siege { private long lastPayout; private final boolean doubleCostPerOwnedSiegeRegion; private UUID playerUUID; - private final Scoreboard scoreboard; + private final BossBar progressBar; public Siege( @NotNull String name, @NotNull String captureRegion, @NotNull String attackRegion, @@ -48,14 +49,9 @@ public Siege( lastUpdate = 0; stage = new AtomicReference<>(); stage.set(SiegeStage.INACTIVE); - scoreboard = Bukkit.getScoreboardManager().getNewScoreboard(); - scoreboard.registerNewObjective(name, "dummy",name); - scoreboard.registerNewObjective("stage","dummy","Stage: " + stage.get().name().toLowerCase().replace("_", " ")); - scoreboard.registerNewObjective("timeLeft","dummy","Time left: "); - scoreboard.registerNewObjective("shipInRegion", "dummy", ""); - for (Objective objective : scoreboard.getObjectives()){ - objective.setDisplaySlot(DisplaySlot.SIDEBAR); - } + progressBar = Bukkit.createBossBar(name, BarColor.BLUE, BarStyle.SEGMENTED_20, BarFlag.DARKEN_SKY); + progressBar.setProgress(0.0); + progressBar.setVisible(false); } @NotNull @@ -168,4 +164,8 @@ public boolean isDoubleCostPerOwnedSiegeRegion() { public String toString() { return name; } + + public BossBar getProgressBar() { + return progressBar; + } } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/siege/SiegePaymentTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/siege/SiegePaymentTask.java index 749e4d49d..44b072349 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/siege/SiegePaymentTask.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/siege/SiegePaymentTask.java @@ -1,8 +1,12 @@ package net.countercraft.movecraft.warfare.siege; +import com.sk89q.worldedit.bukkit.BukkitAdapter; +import com.sk89q.worldguard.WorldGuard; import com.sk89q.worldguard.protection.regions.ProtectedRegion; import net.countercraft.movecraft.Movecraft; +import net.countercraft.movecraft.config.Settings; import net.countercraft.movecraft.localisation.I18nSupport; +import net.countercraft.movecraft.utils.LegacyUtils; import org.bukkit.OfflinePlayer; import org.bukkit.World; @@ -27,8 +31,12 @@ public void run() { int minute = rightNow.get(Calendar.MINUTE); if ((hour == 1) && (minute == 1)) { for (World tW : Movecraft.getInstance().getServer().getWorlds()) { - ProtectedRegion tRegion = Movecraft.getInstance().getWorldGuardPlugin().getRegionManager(tW).getRegion(siege.getCaptureRegion()); - + ProtectedRegion tRegion; + if (Settings.IsLegacy){ + tRegion = LegacyUtils.getRegionManager(Movecraft.getInstance().getWorldGuardPlugin(), tW).getRegion(siege.getCaptureRegion()); + } else { + tRegion = WorldGuard.getInstance().getPlatform().getRegionContainer().get(BukkitAdapter.adapt(tW)).getRegion(siege.getCaptureRegion()); + } if (tRegion != null) { payRegion(tRegion); return; diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/siege/SiegePreparationTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/siege/SiegePreparationTask.java index 2de3e9455..f3167e9cd 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/siege/SiegePreparationTask.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/siege/SiegePreparationTask.java @@ -17,7 +17,10 @@ public SiegePreparationTask(Siege siege) { public void run() { int timePassed = ((int)(System.currentTimeMillis() - siege.getStartTime())); //time passed in milliseconds int timePassedInSeconds = timePassed / 1000; + double progress = (double) timePassedInSeconds / (double) siege.getDelayBeforeStart(); + siege.getProgressBar().setProgress(Math.min(progress, 1.0)); if (timePassedInSeconds >= siege.getDelayBeforeStart()){ + siege.getProgressBar().setProgress(0.0); siege.setStage(SiegeStage.IN_PROGRESS); } if ((siege.getDelayBeforeStart() - timePassedInSeconds) % Settings.SiegeTaskSeconds != 0 || timePassed < 3000){ diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/siege/SiegeProgressTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/siege/SiegeProgressTask.java index f0a18c465..a02237021 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/siege/SiegeProgressTask.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/siege/SiegeProgressTask.java @@ -1,5 +1,7 @@ package net.countercraft.movecraft.warfare.siege; +import com.sk89q.worldedit.bukkit.BukkitAdapter; +import com.sk89q.worldguard.WorldGuard; import com.sk89q.worldguard.domains.DefaultDomain; import com.sk89q.worldguard.protection.regions.ProtectedRegion; import net.countercraft.movecraft.Movecraft; @@ -8,8 +10,10 @@ import net.countercraft.movecraft.craft.Craft; import net.countercraft.movecraft.craft.CraftManager; import net.countercraft.movecraft.localisation.I18nSupport; +import net.countercraft.movecraft.utils.LegacyUtils; import org.bukkit.Bukkit; import org.bukkit.Sound; +import org.bukkit.boss.BarColor; import org.bukkit.entity.Player; import java.util.List; @@ -22,18 +26,19 @@ public SiegeProgressTask(Siege siege) { //every 20 ticks = 1 second public void run() { - if ((siege.getDuration() - ((System.currentTimeMillis() - siege.getStartTime()) / 1000)) % Settings.SiegeTaskSeconds != 0) { - return; - } - - Player siegeLeader = Movecraft.getInstance().getServer().getPlayer(siege.getPlayerUUID()); + int timeLeft = siege.getDuration() - (((int) System.currentTimeMillis() - siege.getStartTime()) / 1000); + double progress = (double) (timeLeft - siege.getDelayBeforeStart()) / (double) (siege.getDuration() - siege.getDelayBeforeStart()); + siege.getProgressBar().setProgress(Math.min(progress, 1.0));Player siegeLeader = Movecraft.getInstance().getServer().getPlayer(siege.getPlayerUUID()); Craft siegeCraft = CraftManager.getInstance().getCraftByPlayer(siegeLeader); - int timeLeft = (siege.getDuration() - (((int)System.currentTimeMillis() - siege.getStartTime())/1000)); - double progress = (double) ((((int)System.currentTimeMillis() - siege.getStartTime())/1000) - siege.getDelayBeforeStart()) / (double) (siege.getDuration() - siege.getDelayBeforeStart()); - if (timeLeft % 60 != 0) { + BarColor bColor = leaderPilotingShip(siegeCraft) && leaderShipInRegion(siegeCraft, siegeLeader) ? BarColor.GREEN : BarColor.RED; + siege.getProgressBar().setColor(bColor); + if (timeLeft % Settings.SiegeTaskSeconds != 0) { return; } + + + if (timeLeft > 10) { if (!leaderPilotingShip(siegeCraft)) { return; @@ -54,6 +59,7 @@ public void run() { siege.getName(), siegeLeader.getDisplayName()) + formatMinutes(timeLeft)); } + return; } else { endSiege(siegeCraft, siegeLeader); } @@ -79,10 +85,17 @@ private void endSiege(Craft siegeCraft, Player siegeLeader) { else { failSiege(siegeLeader); } + siege.getProgressBar().setVisible(false); + siege.getProgressBar().setColor(BarColor.BLUE); } private void winSiege(Player siegeLeader) { - ProtectedRegion controlRegion = Movecraft.getInstance().getWorldGuardPlugin().getRegionManager(siegeLeader.getWorld()).getRegion(siege.getCaptureRegion()); + ProtectedRegion controlRegion; + if (Settings.IsLegacy){ + controlRegion = LegacyUtils.getRegionManager(Movecraft.getInstance().getWorldGuardPlugin(), siegeLeader.getWorld()).getRegion(siege.getCaptureRegion()); + } else { + controlRegion = WorldGuard.getInstance().getPlatform().getRegionContainer().get(BukkitAdapter.adapt(siegeLeader.getWorld())).getRegion(siege.getCaptureRegion()); + } DefaultDomain newOwner = new DefaultDomain(); newOwner.addPlayer(siege.getPlayerUUID()); controlRegion.setOwners(newOwner); @@ -128,7 +141,12 @@ private boolean leaderPilotingShip(Craft siegeCraft) { private boolean leaderShipInRegion(Craft siegeCraft, Player siegeLeader) { MovecraftLocation mid = siegeCraft.getHitBox().getMidPoint(); - ProtectedRegion r = Movecraft.getInstance().getWorldGuardPlugin().getRegionManager(siegeLeader.getWorld()).getRegion(siege.getAttackRegion()); + ProtectedRegion r; + if (Settings.IsLegacy){ + r = LegacyUtils.getRegionManager(Movecraft.getInstance().getWorldGuardPlugin(), siegeLeader.getWorld()).getRegion(siege.getAttackRegion()); + } else { + r = WorldGuard.getInstance().getPlatform().getRegionContainer().get(BukkitAdapter.adapt(siegeLeader.getWorld())).getRegion(siege.getAttackRegion()); + } return r.contains(mid.getX(), mid.getY(), mid.getZ()); } } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/siege/SiegeTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/siege/SiegeTask.java index 1f2527f72..ec5b295c8 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/siege/SiegeTask.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/siege/SiegeTask.java @@ -15,7 +15,11 @@ protected SiegeTask(Siege siege) { public String formatMinutes(int seconds) { if (seconds < 60) { - return I18nSupport.getInternationalisedString("Siege - Ending Soon"); + if (seconds > 0) { + return String.format(I18nSupport.getInternationalisedString("Siege - Ending in X seconds"), seconds); + } else { + return I18nSupport.getInternationalisedString("Siege - Ending Soon"); + } } int minutes = seconds / 60; @@ -23,7 +27,10 @@ public String formatMinutes(int seconds) { return I18nSupport.getInternationalisedString("Siege - Ending In 1 Minute"); } else { - return String.format(I18nSupport.getInternationalisedString("Siege - Ending In X Minutes"), minutes); + + return String.format(I18nSupport.getInternationalisedString("Siege - Ending In X Minutes"), minutes); + + } } } diff --git a/modules/Movecraft/src/main/resources/localisation/movecraftlang_en.properties b/modules/Movecraft/src/main/resources/localisation/movecraftlang_en.properties index bbac44070..d53e43fb6 100644 --- a/modules/Movecraft/src/main/resources/localisation/movecraftlang_en.properties +++ b/modules/Movecraft/src/main/resources/localisation/movecraftlang_en.properties @@ -63,7 +63,7 @@ Contacts=Contacts Contacts\ -\ Must\ be\ Player=Only Players may get Contacts. Contact=Contact New\ Contact=New Contact -Commanded By=commanded by +Commanded\ By=commanded by Size=size Range=range To\ The=to the @@ -134,12 +134,6 @@ Siege\ -\ Siege\ Already\ Underway=A Siege is already taking place\! Siege\ -\ Insufficient\ Funds=You do not have enough money. You need %d Siege\ -\ No\ Configuration\ Found=Could not find a siege configuration for the region you are in. Siege\ -\ Siege\ Region\ Not\ Found=Siege region not found. Use '/siege list' to find valid siege regions. -Siege\ Cost=Cost to Siege -Daily\ Income=Daily Income -Day\ Of\ Week=Day of Week -Start\ Time=Start Time -End\ Time=End Time -Duration=Siege Duration Siege\ -\ Ownership\ Payout\ Console=Player %s paid %d for their ownership in %s Monday=Monday @@ -186,11 +180,7 @@ Player\ -\ Error\ -\ Already\ piloting\ craft=You are already commanding a craft MCStats\ -\ \:(\ -\ Admin\ has\ opted\ out=You have selected to opt out of mcstats.org data submission. The developer of Movecraft would greatly appreciate you submitting your data. MCStats\ -\ Thank\ you\ message=Submitted statistics to mcstats.org succesfully. Thank you for your support. MCStats\ -\ Error\ -\ Unable\ to\ upload\ stats=Unable to upload statistics to mcstats.org. Please check your network connection. -<<<<<<< HEAD -Release\ -\ Player\ has\ left\ craft=You have left your craft\! You have 15 seconds to return to it or it will be automatically released. Release\ -\ Blocks\ may\ merge=WARNING\! There are blocks near your craft that may merge with the craft\! -======= ->>>>>>> c2e01d1046f1430b9658de2ec3493482af58bf06 Release\ -\ Craft\ has\ been\ released\ message=You have released your craft. Release\ -\ Player\ has\ released\ a\ craft\ console=Player %s has released a craft of type %s with size %d at coordinates \: %d x , %d z Release\ -\ Null\ Craft\ Release\ Console=NULL Player has released a craft of type %s with size %d at coordinates \: %d x , %d z diff --git a/modules/Movecraft/src/main/resources/localisation/movecraftlang_he.properties b/modules/Movecraft/src/main/resources/localisation/movecraftlang_he.properties deleted file mode 100644 index d7d42d1ac..000000000 --- a/modules/Movecraft/src/main/resources/localisation/movecraftlang_he.properties +++ /dev/null @@ -1,85 +0,0 @@ -# -# This file is part of Movecraft. -# -# Movecraft is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# Movecraft is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with Movecraft. If not, see . -# - -# Message returned when a craft is too small. One Integer which is the minimum size of that Craft Type -Detection\ -\ Craft\ too\ small=%d ????? ????\! ??? ???? ??? ??? ???. ??????? ???? ?? ??? -Detection\ -\ Craft\ too\ large=????? ????\! ??? ???? ??? ???? ???. ??????? ???? ?? ??? d% -Detection\ -\ Forbidden\ block\ found= -Detection\ -\ Failed\ -\ Already\ commanding\ a\ craft=You are already commanding a craft\! -Detection\ -\ Failed\ Craft\ is\ already\ being\ controlled=The craft is already being controlled\! -Detection\ -\ Successfully\ piloted\ craft=Succesfully piloted craft\! -Rotation\ -\ Craft\ is\ obstructed=Craft is obstructed -Rotation\ -\ Craft\ Collision=Craft Collision -Translation\ -\ Failed\ Craft\ hit\ height\ limit=Craft has hit the height limit -Translation\ -\ Failed\ Craft\ is\ obstructed=The craft cannot move because its path is obstructed\! -Translation\ -\ Failed\ Craft\ out\ of\ fuel=The craft is out of fuel\! -Translation\ -\ Failed\ Craft\ hit\ minimum\ height\ limit=Craft has hit the minimum height limit -Translation\\=-\\ Failed\\ Craft\\ over\\ water=This craft cannot move over water\\! -Translation\ -\ Craft\ collision=Craft Collision -Internal\ -\ Error\ -\ Proccessor\ thread\ encountered\ an\ error=Async Task generated an exception. -Startup\ -\ Number\ of\ craft\ files\ loaded=Loaded %d Craft files -Startup\ -\ Error\ parsing\ CraftType\ file=***ERROR PARSING CRAFT FILE FROM DIRECTORY \: %s*** -Startup\ -\ Error\ -\ Reload\ error=Movecraft is incompatible with the reload command. Movecraft has shut down and will restart when the server is restarted. -Startup\ -\ Error\ -\ Disable\ warning\ for\ reload=If you wish to use the reload command and Movecraft, you may disable this check inside the config.yml by setting 'safeReload \: false' -Startup\ -\ Enabled\ message=[V %S] has been enabled. -Item\ -\ Storage\ Crate\ name=Storage Crate -Player-\ Craft\ has\ been\ released=Your craft has been released\! -Player-\ Craft\ should\ sink\ but\ PVP\ is\ not\ allowed\ in\ this\ WorldGuard\ region=Player- Craft should sink but PVP is not allowed in this WorldGuard region -Player-\ Craft\ is\ sinking=Your craft has taken too much damage and is sinking\! ABANDON SHIP\! -Player-\ Error\ -\ You\ do\ not\ have\ a\ craft\ to\ release!=You do not have a craft to release\! -Player\ -\ Error\ -\ Already\ piloting\ craft=You are already commanding a craft\! -MCStats\ -\ \:(\ -\ Admin\ has\ opted\ out=You have selected to opt out of mcstats.org data submission. The developer of Movecraft would greatly appreciate you submitting your data. -MCStats\ -\ Thank\ you\ message=Submitted statistics to mcstats.org succesfully. Thank you for your support. -MCStats\ -\ Error\ -\ Unable\ to\ upload\ stats=Unable to upload statistics to mcstats.org. Please check your network connection. -Release\ -\ Player\ has\ left\ craft=You have left your craft\! You have 15 seconds to return to it or it will be automatically released. -Release\ -\ Craft\ has\ been\ released\ message=You have released your craft. -Release\ -\ Player\ has\ released\ a\ craft\ console=Player %s has released a craft of type %s with size %d at coordinates \: %d x , %d z -Detection\ -\ Success\ -\ Log\ Output=Player %s piloted a craft of type %s with size %d at location\: %d x, %d z -Not\ enough\ flyblock=Not enough flyblock -Too\ much\ flyblock=Too much flyblock -Detection\ -\ ERROR\:\ Double\ chest\ found=Detection failed\! ERROR \: Double chest found -Detection\ -\ Failed\ -\ Water\ contact\ required\ but\ not\ found=Detection failed\: Water contact required but not found -Rotation\ -\ Player\ is\ not\ permitted\ to\ build\ in\ this\ WorldGuard\ region=Rotation - Player is not permitted to build in this WorldGuard region -Translation\ -\ Failed\ Player\ is\ not\ permitted\ to\ build\ in\ this\ WorldGuard\ region=Translation Failed - Player is not permitted to build in this WorldGuard region -Parent\ Craft\ is\ busy=Parent Craft is busy -Insufficient\ Permissions=Insufficient Permissions -ERROR\:\ Remote\ Sign\ must\ be\ a\ part\ of\ a\ piloted\ craft\!=ERROR\: Remote Sign must be a part of a piloted craft\! -ERROR\:\ Remote\ Signs\ not\ allowed\ on\ this\ craft\!=ERROR\: Remote Signs not allowed on this craft\! -ERROR\:\ Could\ not\ find\ target\ sign\!=ERROR\: Could not find target sign\! -Entering\ Direct\ Control\ Mode=Entering Direct Control Mode -Leaving\ Direct\ Control\ Mode=Leaving Direct Control Mode -Craft\ is\ too\ big\ to\ check\ its\ borders\.\ Make\ sure\ this\ area\ is\ safe\ to\ release\ your\ craft\ in\.=Craft is too big to check its borders. Make sure this area is safe to release your craft in. -You\ have\ left\ your\ craft\.\ You\ may\ return\ to\ your\ craft\ by\ typing\ \/manoverboard\ any\ time\ before\ the\ timeout\ expires=You have left your craft. If you have fallen out of your craft, you man type /manoverboard before the timout expires and be returned to it. -WARNING\!\ There\ are\ blocks\ near\ your\ craft\ that\ may\ merge\ with\ the\ \craft\ "=WARNING\! There are blocks near your craft that may merge with the craft -You\ can\ only\ create\ a\ Crew\:\ sign\ for\ yourself=You can only create a Crew\: sign for yourself -Repair\ functionality\ is\ disabled\ or\ WorldEdit\ was\ not\ detected=Repair functionality is disabled or WorldEdit was not detected -You\ must\ be\ piloting\ a\ craft=You must be piloting a craft -Could\ not\ save\ file=Could not save file -State\ saved=State saved -REPAIR\ STATE\ NOT\ FOUND=REPAIR STATE NOT FOUND -Repairs\ underway=Repairs underway -Repairs\ complete\.\ You\ may\ now\ pilot\ the\ craft=Repairs complete. You may now pilot the craft -You\ do\ not\ have\ enough\ money=You do not have enough money -Need\ more\ of\ material=Need more of material -Towny\ -\ Detection\ Failed=Detection Failed - You are not permitted to pilot a craft on this plot in the town -Towny\ -\ Translation\ Failed=Translation Failed - You are not permitted to move a craft on this plot in the town -Towny\ -\ Rotation\ Failed=Rotation Failed - You are not permitted to rotate a craft on this plot in the town -Towny\ -\ Sinking\ a\ craft\ is\ not\ allowed\ in\ this\ town\ plot=Sinking a craft is not allowed in this town plot\! -WGCustomFlags\ -\ Translation\ Failed=Translation Failed - You are not permitted to move a craft in this WorldGuard region -WGCustomFlags\ -\ Rotation\ Failed=Rotation Failed - You are not permitterd to rotate a craft in this WorldGuard region -WGCustomFlags\ -\ Detection\ Failed=Detection Failed - You are not permitted to pilot a craft in this WorldGuard region -WGCustomFlags\ -\ Sinking\ a\ craft\ is\ not\ allowed\ in\ this\ WorldGuard\ region=Sinking is not allowed in this WorldGuard region\! diff --git a/modules/api/src/main/java/net/countercraft/movecraft/utils/LegacyUtils.java b/modules/api/src/main/java/net/countercraft/movecraft/utils/LegacyUtils.java index f2f43d487..22b6de7f5 100644 --- a/modules/api/src/main/java/net/countercraft/movecraft/utils/LegacyUtils.java +++ b/modules/api/src/main/java/net/countercraft/movecraft/utils/LegacyUtils.java @@ -1,12 +1,23 @@ package net.countercraft.movecraft.utils; +import com.sk89q.worldguard.LocalPlayer; +import com.sk89q.worldguard.bukkit.WorldGuardPlugin; +import com.sk89q.worldguard.protection.ApplicableRegionSet; +import com.sk89q.worldguard.protection.flags.Flag; +import com.sk89q.worldguard.protection.flags.StateFlag; +import com.sk89q.worldguard.protection.managers.RegionManager; +import net.countercraft.movecraft.MovecraftLocation; import net.countercraft.movecraft.config.Settings; +import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.Sound; +import org.bukkit.World; import org.bukkit.block.Block; +import org.bukkit.entity.Player; public class LegacyUtils { + public static final Material WALL_SIGN = Material.WALL_SIGN; //Materials removed in 1.13 public static Material BED_BLOCK = Settings.IsLegacy ? Material.BED_BLOCK : null; public static Material CARPET = Settings.IsLegacy ? Material.CARPET : null; @@ -120,4 +131,28 @@ private String getColorFromData(byte data){ } return color; } + + public static RegionManager getRegionManager(WorldGuardPlugin worldGuardPlugin, World world){ + return worldGuardPlugin.getRegionManager(world); + } + + public static ApplicableRegionSet getApplicableRegions(RegionManager regionManager, Location location){ + return regionManager.getApplicableRegions(location); + } + + public static boolean canBuild(WorldGuardPlugin worldGuardPlugin, World world, MovecraftLocation location, Player player){ + return worldGuardPlugin.canBuild(player, location.toBukkit(world)); + } + + public static boolean allows(ApplicableRegionSet applicableRegionSet, StateFlag stateFlag){ + return applicableRegionSet.allows(stateFlag); + } + + public static StateFlag.State getFlag(WorldGuardPlugin wgPlugin, Location loc, Object flag, LocalPlayer lp){ + return (StateFlag.State) wgPlugin.getRegionManager(loc.getWorld()).getApplicableRegions(loc).getFlag((Flag) flag, lp); + } + + public static StateFlag.State getFlag(WorldGuardPlugin wgPlugin, Location loc, Object flag){ + return (StateFlag.State) wgPlugin.getRegionManager(loc.getWorld()).getApplicableRegions(loc).getFlag((Flag) flag); + } } diff --git a/modules/worldedit/WE7Utils/pom.xml b/modules/worldedit/WE7Utils/pom.xml index 869f5e392..072cddd69 100644 --- a/modules/worldedit/WE7Utils/pom.xml +++ b/modules/worldedit/WE7Utils/pom.xml @@ -25,24 +25,24 @@ com.sk89q.worldedit worldedit-bukkit - 7.0.0-SNAPSHOT + 7.0.1-SNAPSHOT provided com.sk89q.worldedit worldedit-core - 7.0.0-SNAPSHOT + 7.0.1-SNAPSHOT provided com.sk89q.worldguard worldguard-core - 7.0.0-SNAPSHOT + 7.0.1-SNAPSHOT com.sk89q.worldguard - worldguard-legacy - 7.0.0-SNAPSHOT + worldguard-bukkit + 7.0.1-SNAPSHOT net.countercraft From c617b3080274518b05a4f883f479959ace73c0ea Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Sat, 3 Aug 2019 23:25:16 +0200 Subject: [PATCH 034/304] Added the ability to include all blocks of the same type with ALL_-prefix --- .../src/main/resources/types/BigAirship.craft | 313 ++++------------- .../main/resources/types/BigSubAirship.craft | 320 +++++------------ .../src/main/resources/types/Ship.craft | 326 +++++------------ .../src/main/resources/types/SubAirship.craft | 318 +++++------------ .../src/main/resources/types/Submarine.craft | 330 +++++------------- .../src/main/resources/types/Turret.craft | 254 ++++---------- .../src/main/resources/types/airship.craft | 313 ++++------------- .../src/main/resources/types/airskiff.craft | 269 ++++---------- .../src/main/resources/types/elevator.craft | 271 ++++---------- .../movecraft/craft/CraftType.java | 30 +- 10 files changed, 721 insertions(+), 2023 deletions(-) diff --git a/modules/Movecraft/src/main/resources/types/BigAirship.craft b/modules/Movecraft/src/main/resources/types/BigAirship.craft index 3ac283a8a..217639a78 100644 --- a/modules/Movecraft/src/main/resources/types/BigAirship.craft +++ b/modules/Movecraft/src/main/resources/types/BigAirship.craft @@ -2,248 +2,87 @@ name: BigAirship maxSize: 20000 minSize: 10000 allowedBlocks: - #beds - - WHITE_BED - - ORANGE_BED - - MAGENTA_BED - - LIGHT_BLUE_BED - - YELLOW_BED - - LIME_BED - - PINK_BED - - GRAY_BED - - LIGHT_BED - - CYAN_BED - - PURPLE_BED - - BLUE_BED - - BROWN_BED - - GREEN_BED - - RED_BED - - BLACK_BED - #buttons - - ACACIA_BUTTON - - BIRCH_BUTTON - - DARK_OAK_BUTTON - - JUNGLE_BUTTON - - OAK_BUTTON - - SPRUCE_BUTTON - - STONE_BUTTON - #carpets - - WHITE_CARPET - - ORANGE_CARPET - - MAGENTA_CARPET - - LIGHT_BLUE_CARPET - - YELLOW_CARPET - - LIME_CARPET - - PINK_CARPET - - GRAY_CARPET - - LIGHT_CARPET - - CYAN_CARPET - - PURPLE_CARPET - - BLUE_CARPET - - BROWN_CARPET - - GREEN_CARPET - - RED_CARPET - - BLACK_CARPET - #doors - - ACACIA_DOOR - - BIRCH_DOOR - - DARK_OAK_DOOR - - IRON_DOOR - - JUNGLE_DOOR - - OAK_DOOR - - SPRUCE_DOOR - #fences - - ACACIA_FENCE - - BIRCH_FENCE - - DARK_OAK_FENCE - - JUNGLE_FENCE - - OAK_FENCE - - NETHER_BRICK_FENCE - - SPRUCE_FENCE - #fence gates - - ACACIA_FENCE_GATE - - BIRCH_FENCE_GATE - - DARK_OAK_FENCE_GATE - - JUNGLE_FENCE_GATE - - OAK_FENCE_GATE - - SPRUCE_FENCE_GATE - #glass - - GLASS - - WHITE_STAINED_GLASS - - ORANGE_STAINED_GLASS - - MAGENTA_STAINED_GLASS - - LIGHT_BLUE_STAINED_GLASS - - YELLOW_STAINED_GLASS - - LIME_STAINED_GLASS - - PINK_STAINED_GLASS - - GRAY_STAINED_GLASS - - LIGHT_GRAY_STAINED_GLASS - - CYAN_STAINED_GLASS - - PURPLE_STAINED_GLASS - - BLUE_STAINED_GLASS - - BROWN_STAINED_GLASS - - GREEN_STAINED_GLASS - - RED_STAINED_GLASS - - BLACK_STAINED_GLASS - #glass pane - - GLASS_PANE - - WHITE_STAINED_GLASS_PANE - - ORANGE_STAINED_GLASS_PANE - - MAGENTA_STAINED_GLASS_PANE - - LIGHT_BLUE_STAINED_GLASS_PANE - - YELLOW_STAINED_GLASS_PANE - - LIME_STAINED_GLASS_PANE - - PINK_STAINED_GLASS_PANE - - GRAY_STAINED_GLASS_PANE - - LIGHT_GRAY_STAINED_GLASS_PANE - - CYAN_STAINED_GLASS_PANE - - PURPLE_STAINED_GLASS_PANE - - BLUE_STAINED_GLASS_PANE - - BROWN_STAINED_GLASS_PANE - - GREEN_STAINED_GLASS_PANE - - RED_STAINED_GLASS_PANE - - BLACK_STAINED_GLASS_PANE - #liquids - - LAVA + - ALL_WOOD - WATER - #logs - - BIRCH_LOG - - JUNGLE_LOG - - OAK_LOG - - SPRUCE_LOG - - STRIPPED_BIRCH_LOG - - STRIPPED_JUNGLE_LOG - - STRIPPED_OAK_LOG - - STRIPPED_SPRUCE_LOG - #misc + - LAVA + - ALL_LOG + - all_planks + - GLASS + - LAPIS_BLOCK + - DISPENSER + - NOTE_BLOCK + - ALL_BED + - sticky_piston + - piston_head + - all_wool + - GOLD_BLOCK + - IRON_BLOCK + - all_slab - BOOKSHELF - - BREWING_STAND - - CRAFTING_TABLE - - CAULDRON - - FURNACE - - GLOWSTONE - - IRON_BARS - - LADDER - - NETHER_BRICKS - - SIGN - TORCH - - WALL_SIGN - - WALL_TORCH - #planks - - ACACIA_PLANKS - - BIRCH_PLANKS - - DARK_OAK_PLANKS - - JUNGLE_PLANKS - - OAK_PLANKS - - SPRUCE_PLANKS - #pressure plates - - ACACIA_PRESSURE_PLATE - - BIRCH_PRESSURE_PLATE - - DARK_OAK_PRESSURE_PLATE - - HEAVY_WEIGHTED_PRESSURE_PLATE - - JUNGLE_PRESSURE_PLATE - - LIGHT_WEIGHTED_PRESSURE_PLATE - - OAK_PRESSURE_PLATE - - SPRUCE_PRESSURE_PLATE - - STONE_PRESSURE_PLATE - #redstone - - COMPARATOR - - LEVER - - NOTE_BLOCK - - PISTON - - PISTON_HEAD - - REDSTONE_BLOCK - - REDSTONE_WIRE - - REPEATER - - REDSTONE_TORCH - - REDSTONE_WALL_TORCH - - STICKY_PISTON + - FIRE + - oak_stairs + - birch_stairs + - jungle_stairs + - spruce_stairs + - stone_brick_stairs + - quartz_stairs + - nether_brick_stairs + - chest + - redstone_wire + - diamond_block + - nether_brick_stairs + - furnace + - all_sign + - ladder + - all_door + - lever + - all_pressure_plate + - redstone_torch + - redstone_wall_torch + - all_button + - clay + - all_fence + - netherrack + - glowstone + - cake + - redstone_repeater + - all_stained_glass + - all_trapdoor + - all_stone_bricks + - iron_bars + - glass_pane + - all_fence_gate + - nether_brick + - enchantment_table + - brewing_stand + - cauldron + - end_stone + - dragon_egg + - redstone_lamp + - ender chest - TRIPWIRE_HOOK - #slabs - - ACACIA_SLAB - - BIRCH_SLAB - - BRICK_SLAB - - COBBLESTONE_SLAB - - DARK_OAK_SLAB - - DARK_PRISMARINE - - JUNGLE_SLAB - - NETHER_BRICK_SLAB - - OAK_SLAB - - PETRIFIED_OAK_SLAB - - PRISMARINE_SLAB - - PRISMARINE_BRICK_SLAB - - RED_SANDSTONE_SLAB - - QUARTZ_SLAB - - SPRUCE_SLAB - - STONE_SLAB - #stairs - - BIRCH_STAIRS - - JUNGLE_STAIRS - - OAK_STAIRS - - NETHER_BRICK_STAIRS - - SMOOTH_STAIRS - - SPRUCE_STAIRS - - STONE_BRICK_STAIRS - #storage - - CHEST - - DISPENSER - - DROPPER - - HOPPER + - EMERALD_BLOCK + - BEACON + - cobblestone_wall + - mossy_cobblestone_wall + - FLOWER_POT + - SKULL + - all_ANVIL - TRAPPED_CHEST - #terracotta - - WHITE_TERRACOTTA - - ORANGE_TERRACOTTA - - MAGENTA_TERRACOTTA - - LIGHT_BLUE_TERRACOTTA - - YELLOW_TERRACOTTA - - LIME_TERRACOTTA - - PINK_TERRACOTTA - - GRAY_TERRACOTTA - - LIGHT_GRAY_TERRACOTTA - - CYAN_TERRACOTTA - - PURPLE_TERRACOTTA - - BLUE_TERRACOTTA - - BROWN_TERRACOTTA - - GREEN_TERRACOTTA - - RED_TERRACOTTA - - BLACK_TERRACOTTA - #trapdoors - - ACACIA_TRAPDOOR - - BIRCH_TRAPDOOR - - DARK_OAK_TRAPDOOR - - JUNGLE_TRAPDOOR - - OAK_TRAPDOOR - - SPRUCE_TRAPDOOR - #weapon blocks + - REDSTONE_COMPARATOR + - daylight_detector + - REDSTONE_BLOCK + - HOPPER + - all_QUARTZ_BLOCK + - all_rail + - DROPPER + - ALL_TERRACOTTA + - ALL_STAINED_GLASS_PANE + - SLIME_BLOCK + - ALL_CARPET - COAL_BLOCK - #wood - - ACACIA_WOOD - - BIRCH_WOOD - - DARK_OAK_WOOD - - OAK_WOOD - - SPRUCE_WOOD - - STRIPPED_ACACIA_WOOD - - STRIPPED_BIRCH_WOOD - - STRIPPED_DARK_OAK_WOOD - - STRIPPED_OAK_WOOD - - STRIPPED_SPRUCE_WOOD - #wool - - WHITE_WOOL - - ORANGE_WOOL - - MAGENTA_WOOL - - LIGHT_BLUE_WOOL - - YELLOW_WOOL - - LIME_WOOL - - PINK_WOOL - - GRAY_WOOL - - LIGHT_GRAY_WOOL - - CYAN_WOOL - - PURPLE_WOOL - - BLUE_WOOL - - BROWN_WOOL - - GREEN_WOOL - - RED_WOOL - - BLACK_WOOL + - END_STONE_BRICKS @@ -271,7 +110,7 @@ moveblocks: - 1.0 - 100.0 flyblocks: - [WHITE_WOOL, ORANGE_WOOL, MAGENTA_WOOL,LIGHT_BLUE_WOOL,YELLOW_WOOL,LIME_WOOL,PINK_WOOL,GRAY_WOOL,LIGHT_GRAY_WOOL,CYAN_WOOL,PURPLE_WOOL,BLUE_WOOL,BROWN_WOOL, GREEN_WOOL, RED_WOOL, BLACK_WOOL]: #wool represents lift + all_wool: #wool represents lift - 50.0 - 100.0 [CHEST,TRAPPED_CHEST]: # limit chests to make big airships important for merchant missions diff --git a/modules/Movecraft/src/main/resources/types/BigSubAirship.craft b/modules/Movecraft/src/main/resources/types/BigSubAirship.craft index 2409fd51d..15254a4a9 100644 --- a/modules/Movecraft/src/main/resources/types/BigSubAirship.craft +++ b/modules/Movecraft/src/main/resources/types/BigSubAirship.craft @@ -2,248 +2,87 @@ name: BigSubAirship maxSize: 20000 minSize: 10000 allowedBlocks: - #beds - - WHITE_BED - - ORANGE_BED - - MAGENTA_BED - - LIGHT_BLUE_BED - - YELLOW_BED - - LIME_BED - - PINK_BED - - GRAY_BED - - LIGHT_BED - - CYAN_BED - - PURPLE_BED - - BLUE_BED - - BROWN_BED - - GREEN_BED - - RED_BED - - BLACK_BED - #buttons - - ACACIA_BUTTON - - BIRCH_BUTTON - - DARK_OAK_BUTTON - - JUNGLE_BUTTON - - OAK_BUTTON - - SPRUCE_BUTTON - - STONE_BUTTON - #carpets - - WHITE_CARPET - - ORANGE_CARPET - - MAGENTA_CARPET - - LIGHT_BLUE_CARPET - - YELLOW_CARPET - - LIME_CARPET - - PINK_CARPET - - GRAY_CARPET - - LIGHT_CARPET - - CYAN_CARPET - - PURPLE_CARPET - - BLUE_CARPET - - BROWN_CARPET - - GREEN_CARPET - - RED_CARPET - - BLACK_CARPET - #doors - - ACACIA_DOOR - - BIRCH_DOOR - - DARK_OAK_DOOR - - IRON_DOOR - - JUNGLE_DOOR - - OAK_DOOR - - SPRUCE_DOOR - #fences - - ACACIA_FENCE - - BIRCH_FENCE - - DARK_OAK_FENCE - - JUNGLE_FENCE - - OAK_FENCE - - NETHER_BRICK_FENCE - - SPRUCE_FENCE - #fence gates - - ACACIA_FENCE_GATE - - BIRCH_FENCE_GATE - - DARK_OAK_FENCE_GATE - - JUNGLE_FENCE_GATE - - OAK_FENCE_GATE - - SPRUCE_FENCE_GATE - #glass - - GLASS - - WHITE_STAINED_GLASS - - ORANGE_STAINED_GLASS - - MAGENTA_STAINED_GLASS - - LIGHT_BLUE_STAINED_GLASS - - YELLOW_STAINED_GLASS - - LIME_STAINED_GLASS - - PINK_STAINED_GLASS - - GRAY_STAINED_GLASS - - LIGHT_GRAY_STAINED_GLASS - - CYAN_STAINED_GLASS - - PURPLE_STAINED_GLASS - - BLUE_STAINED_GLASS - - BROWN_STAINED_GLASS - - GREEN_STAINED_GLASS - - RED_STAINED_GLASS - - BLACK_STAINED_GLASS - #glass pane - - GLASS_PANE - - WHITE_STAINED_GLASS_PANE - - ORANGE_STAINED_GLASS_PANE - - MAGENTA_STAINED_GLASS_PANE - - LIGHT_BLUE_STAINED_GLASS_PANE - - YELLOW_STAINED_GLASS_PANE - - LIME_STAINED_GLASS_PANE - - PINK_STAINED_GLASS_PANE - - GRAY_STAINED_GLASS_PANE - - LIGHT_GRAY_STAINED_GLASS_PANE - - CYAN_STAINED_GLASS_PANE - - PURPLE_STAINED_GLASS_PANE - - BLUE_STAINED_GLASS_PANE - - BROWN_STAINED_GLASS_PANE - - GREEN_STAINED_GLASS_PANE - - RED_STAINED_GLASS_PANE - - BLACK_STAINED_GLASS_PANE - #liquids - - LAVA + - ALL_WOOD - WATER - #logs - - BIRCH_LOG - - JUNGLE_LOG - - OAK_LOG - - SPRUCE_LOG - - STRIPPED_BIRCH_LOG - - STRIPPED_JUNGLE_LOG - - STRIPPED_OAK_LOG - - STRIPPED_SPRUCE_LOG - #misc + - LAVA + - ALL_LOG + - all_planks + - GLASS + - LAPIS_BLOCK + - DISPENSER + - NOTE_BLOCK + - ALL_BED + - sticky_piston + - piston_head + - all_wool + - GOLD_BLOCK + - IRON_BLOCK + - all_slab - BOOKSHELF - - BREWING_STAND - - CRAFTING_TABLE - - CAULDRON - - FURNACE - - GLOWSTONE - - IRON_BARS - - LADDER - - NETHER_BRICKS - - SIGN - TORCH - - WALL_SIGN - - WALL_TORCH - #planks - - ACACIA_PLANKS - - BIRCH_PLANKS - - DARK_OAK_PLANKS - - JUNGLE_PLANKS - - OAK_PLANKS - - SPRUCE_PLANKS - #pressure plates - - ACACIA_PRESSURE_PLATE - - BIRCH_PRESSURE_PLATE - - DARK_OAK_PRESSURE_PLATE - - HEAVY_WEIGHTED_PRESSURE_PLATE - - JUNGLE_PRESSURE_PLATE - - LIGHT_WEIGHTED_PRESSURE_PLATE - - OAK_PRESSURE_PLATE - - SPRUCE_PRESSURE_PLATE - - STONE_PRESSURE_PLATE - #redstone - - COMPARATOR - - LEVER - - NOTE_BLOCK - - PISTON - - PISTON_HEAD - - REDSTONE_BLOCK - - REDSTONE_WIRE - - REPEATER - - REDSTONE_TORCH - - REDSTONE_WALL_TORCH - - STICKY_PISTON + - FIRE + - oak_stairs + - birch_stairs + - jungle_stairs + - spruce_stairs + - stone_brick_stairs + - quartz_stairs + - nether_brick_stairs + - chest + - redstone_wire + - diamond_block + - nether_brick_stairs + - furnace + - all_sign + - ladder + - all_door + - lever + - all_pressure_plate + - redstone_torch + - redstone_wall_torch + - all_button + - clay + - all_fence + - netherrack + - glowstone + - cake + - redstone_repeater + - all_stained_glass + - all_trapdoor + - all_stone_bricks + - iron_bars + - glass_pane + - all_fence_gate + - nether_brick + - enchantment_table + - brewing_stand + - cauldron + - end_stone + - dragon_egg + - redstone_lamp + - ender chest - TRIPWIRE_HOOK - #slabs - - ACACIA_SLAB - - BIRCH_SLAB - - BRICK_SLAB - - COBBLESTONE_SLAB - - DARK_OAK_SLAB - - DARK_PRISMARINE - - JUNGLE_SLAB - - NETHER_BRICK_SLAB - - OAK_SLAB - - PETRIFIED_OAK_SLAB - - PRISMARINE_SLAB - - PRISMARINE_BRICK_SLAB - - RED_SANDSTONE_SLAB - - QUARTZ_SLAB - - SPRUCE_SLAB - - STONE_SLAB - #stairs - - BIRCH_STAIRS - - JUNGLE_STAIRS - - OAK_STAIRS - - NETHER_BRICK_STAIRS - - SMOOTH_STAIRS - - SPRUCE_STAIRS - - STONE_BRICK_STAIRS - #storage - - CHEST - - DISPENSER - - DROPPER - - HOPPER + - EMERALD_BLOCK + - BEACON + - cobblestone_wall + - mossy_cobblestone_wall + - FLOWER_POT + - SKULL + - all_ANVIL - TRAPPED_CHEST - #terracotta - - WHITE_TERRACOTTA - - ORANGE_TERRACOTTA - - MAGENTA_TERRACOTTA - - LIGHT_BLUE_TERRACOTTA - - YELLOW_TERRACOTTA - - LIME_TERRACOTTA - - PINK_TERRACOTTA - - GRAY_TERRACOTTA - - LIGHT_GRAY_TERRACOTTA - - CYAN_TERRACOTTA - - PURPLE_TERRACOTTA - - BLUE_TERRACOTTA - - BROWN_TERRACOTTA - - GREEN_TERRACOTTA - - RED_TERRACOTTA - - BLACK_TERRACOTTA - #trapdoors - - ACACIA_TRAPDOOR - - BIRCH_TRAPDOOR - - DARK_OAK_TRAPDOOR - - JUNGLE_TRAPDOOR - - OAK_TRAPDOOR - - SPRUCE_TRAPDOOR - #weapon blocks + - REDSTONE_COMPARATOR + - daylight_detector + - REDSTONE_BLOCK + - HOPPER + - all_QUARTZ_BLOCK: + - all_rail + - DROPPER + - ALL_TERRACOTTA + - ALL_STAINED_GLASS_PANE + - SLIME_BLOCK + - ALL_CARPET - COAL_BLOCK - #wood - - ACACIA_WOOD - - BIRCH_WOOD - - DARK_OAK_WOOD - - OAK_WOOD - - SPRUCE_WOOD - - STRIPPED_ACACIA_WOOD - - STRIPPED_BIRCH_WOOD - - STRIPPED_DARK_OAK_WOOD - - STRIPPED_OAK_WOOD - - STRIPPED_SPRUCE_WOOD - #wool - - WHITE_WOOL - - ORANGE_WOOL - - MAGENTA_WOOL - - LIGHT_BLUE_WOOL - - YELLOW_WOOL - - LIME_WOOL - - PINK_WOOL - - GRAY_WOOL - - LIGHT_GRAY_WOOL - - CYAN_WOOL - - PURPLE_WOOL - - BLUE_WOOL - - BROWN_WOOL - - GREEN_WOOL - - RED_WOOL - - BLACK_WOOL + - END_STONE_BRICKS canCruise: true rotateAtMidpoint: true @@ -264,6 +103,13 @@ tryNudge: false sinkPercent: 99.0 overallSinkPercent: 60.0 halfSpeedUnderwater: true + +passthroughBlocks: + - kelp + - kelp_plant + - tall_seagrass + - seagrass + - bubble_column moveblocks: REDSTONE_BLOCK: # redstone represents engines - 1.0 @@ -272,7 +118,7 @@ flyblocks: IRON_BLOCK: # iron represents ballast tanks - 10.0 - 100.0 - [WHITE_WOOL, ORANGE_WOOL, MAGENTA_WOOL,LIGHT_BLUE_WOOL,YELLOW_WOOL,LIME_WOOL,PINK_WOOL,GRAY_WOOL,LIGHT_GRAY_WOOL,CYAN_WOOL,PURPLE_WOOL,BLUE_WOOL,BROWN_WOOL, GREEN_WOOL, RED_WOOL, BLACK_WOOL]: #wool represents lift + all_wool: #wool represents lift - 50.0 - 100.0 [CHEST,TRAPPED_CHEST]: # limit chests to make big airships important for merchant missions diff --git a/modules/Movecraft/src/main/resources/types/Ship.craft b/modules/Movecraft/src/main/resources/types/Ship.craft index a153f92a3..155e110e3 100644 --- a/modules/Movecraft/src/main/resources/types/Ship.craft +++ b/modules/Movecraft/src/main/resources/types/Ship.craft @@ -2,248 +2,87 @@ name: Ship maxSize: 100000 minSize: 10 allowedBlocks: - #beds - - WHITE_BED - - ORANGE_BED - - MAGENTA_BED - - LIGHT_BLUE_BED - - YELLOW_BED - - LIME_BED - - PINK_BED - - GRAY_BED - - LIGHT_BED - - CYAN_BED - - PURPLE_BED - - BLUE_BED - - BROWN_BED - - GREEN_BED - - RED_BED - - BLACK_BED - #buttons - - ACACIA_BUTTON - - BIRCH_BUTTON - - DARK_OAK_BUTTON - - JUNGLE_BUTTON - - OAK_BUTTON - - SPRUCE_BUTTON - - STONE_BUTTON - #carpets - - WHITE_CARPET - - ORANGE_CARPET - - MAGENTA_CARPET - - LIGHT_BLUE_CARPET - - YELLOW_CARPET - - LIME_CARPET - - PINK_CARPET - - GRAY_CARPET - - LIGHT_CARPET - - CYAN_CARPET - - PURPLE_CARPET - - BLUE_CARPET - - BROWN_CARPET - - GREEN_CARPET - - RED_CARPET - - BLACK_CARPET - #doors - - ACACIA_DOOR - - BIRCH_DOOR - - DARK_OAK_DOOR - - IRON_DOOR - - JUNGLE_DOOR - - OAK_DOOR - - SPRUCE_DOOR - #fences - - ACACIA_FENCE - - BIRCH_FENCE - - DARK_OAK_FENCE - - JUNGLE_FENCE - - OAK_FENCE - - NETHER_BRICK_FENCE - - SPRUCE_FENCE - #fence gates - - ACACIA_FENCE_GATE - - BIRCH_FENCE_GATE - - DARK_OAK_FENCE_GATE - - JUNGLE_FENCE_GATE - - OAK_FENCE_GATE - - SPRUCE_FENCE_GATE - #glass - - GLASS - - WHITE_STAINED_GLASS - - ORANGE_STAINED_GLASS - - MAGENTA_STAINED_GLASS - - LIGHT_BLUE_STAINED_GLASS - - YELLOW_STAINED_GLASS - - LIME_STAINED_GLASS - - PINK_STAINED_GLASS - - GRAY_STAINED_GLASS - - LIGHT_GRAY_STAINED_GLASS - - CYAN_STAINED_GLASS - - PURPLE_STAINED_GLASS - - BLUE_STAINED_GLASS - - BROWN_STAINED_GLASS - - GREEN_STAINED_GLASS - - RED_STAINED_GLASS - - BLACK_STAINED_GLASS - #glass pane - - GLASS_PANE - - WHITE_STAINED_GLASS_PANE - - ORANGE_STAINED_GLASS_PANE - - MAGENTA_STAINED_GLASS_PANE - - LIGHT_BLUE_STAINED_GLASS_PANE - - YELLOW_STAINED_GLASS_PANE - - LIME_STAINED_GLASS_PANE - - PINK_STAINED_GLASS_PANE - - GRAY_STAINED_GLASS_PANE - - LIGHT_GRAY_STAINED_GLASS_PANE - - CYAN_STAINED_GLASS_PANE - - PURPLE_STAINED_GLASS_PANE - - BLUE_STAINED_GLASS_PANE - - BROWN_STAINED_GLASS_PANE - - GREEN_STAINED_GLASS_PANE - - RED_STAINED_GLASS_PANE - - BLACK_STAINED_GLASS_PANE - #liquids - - LAVA + - ALL_WOOD - WATER - #logs - - BIRCH_LOG - - JUNGLE_LOG - - OAK_LOG - - SPRUCE_LOG - - STRIPPED_BIRCH_LOG - - STRIPPED_JUNGLE_LOG - - STRIPPED_OAK_LOG - - STRIPPED_SPRUCE_LOG - #misc + - LAVA + - ALL_LOG + - all_planks + - GLASS + - LAPIS_BLOCK + - DISPENSER + - NOTE_BLOCK + - ALL_BED + - sticky_piston + - piston_head + - all_wool + - GOLD_BLOCK + - IRON_BLOCK + - all_slab - BOOKSHELF - - BREWING_STAND - - CRAFTING_TABLE - - CAULDRON - - FURNACE - - GLOWSTONE - - IRON_BARS - - LADDER - - NETHER_BRICKS - - SIGN - TORCH - - WALL_SIGN - - WALL_TORCH - #planks - - ACACIA_PLANKS - - BIRCH_PLANKS - - DARK_OAK_PLANKS - - JUNGLE_PLANKS - - OAK_PLANKS - - SPRUCE_PLANKS - #pressure plates - - ACACIA_PRESSURE_PLATE - - BIRCH_PRESSURE_PLATE - - DARK_OAK_PRESSURE_PLATE - - HEAVY_WEIGHTED_PRESSURE_PLATE - - JUNGLE_PRESSURE_PLATE - - LIGHT_WEIGHTED_PRESSURE_PLATE - - OAK_PRESSURE_PLATE - - SPRUCE_PRESSURE_PLATE - - STONE_PRESSURE_PLATE - #redstone - - COMPARATOR - - LEVER - - NOTE_BLOCK - - PISTON - - PISTON_HEAD - - REDSTONE_BLOCK - - REDSTONE_WIRE - - REPEATER - - REDSTONE_TORCH - - REDSTONE_WALL_TORCH - - STICKY_PISTON + - FIRE + - oak_stairs + - birch_stairs + - jungle_stairs + - spruce_stairs + - stone_brick_stairs + - quartz_stairs + - nether_brick_stairs + - chest + - redstone_wire + - diamond_block + - nether_brick_stairs + - furnace + - all_sign + - ladder + - all_door + - lever + - all_pressure_plate + - redstone_torch + - redstone_wall_torch + - all_button + - clay + - all_fence + - netherrack + - glowstone + - cake + - redstone_repeater + - all_stained_glass + - all_trapdoor + - all_stone_bricks + - iron_bars + - glass_pane + - all_fence_gate + - nether_brick + - enchantment_table + - brewing_stand + - cauldron + - end_stone + - dragon_egg + - redstone_lamp + - ender chest - TRIPWIRE_HOOK - #slabs - - ACACIA_SLAB - - BIRCH_SLAB - - BRICK_SLAB - - COBBLESTONE_SLAB - - DARK_OAK_SLAB - - DARK_PRISMARINE - - JUNGLE_SLAB - - NETHER_BRICK_SLAB - - OAK_SLAB - - PETRIFIED_OAK_SLAB - - PRISMARINE_SLAB - - PRISMARINE_BRICK_SLAB - - RED_SANDSTONE_SLAB - - QUARTZ_SLAB - - SPRUCE_SLAB - - STONE_SLAB - #stairs - - BIRCH_STAIRS - - JUNGLE_STAIRS - - OAK_STAIRS - - NETHER_BRICK_STAIRS - - SMOOTH_STAIRS - - SPRUCE_STAIRS - - STONE_BRICK_STAIRS - #storage - - CHEST - - DISPENSER - - DROPPER - - HOPPER + - EMERALD_BLOCK + - BEACON + - cobblestone_wall + - mossy_cobblestone_wall + - FLOWER_POT + - SKULL + - all_ANVIL - TRAPPED_CHEST - #terracotta - - WHITE_TERRACOTTA - - ORANGE_TERRACOTTA - - MAGENTA_TERRACOTTA - - LIGHT_BLUE_TERRACOTTA - - YELLOW_TERRACOTTA - - LIME_TERRACOTTA - - PINK_TERRACOTTA - - GRAY_TERRACOTTA - - LIGHT_GRAY_TERRACOTTA - - CYAN_TERRACOTTA - - PURPLE_TERRACOTTA - - BLUE_TERRACOTTA - - BROWN_TERRACOTTA - - GREEN_TERRACOTTA - - RED_TERRACOTTA - - BLACK_TERRACOTTA - #trapdoors - - ACACIA_TRAPDOOR - - BIRCH_TRAPDOOR - - DARK_OAK_TRAPDOOR - - JUNGLE_TRAPDOOR - - OAK_TRAPDOOR - - SPRUCE_TRAPDOOR - #weapon blocks + - REDSTONE_COMPARATOR + - daylight_detector + - REDSTONE_BLOCK + - HOPPER + - all_QUARTZ_BLOCK + - all_rail + - DROPPER + - ALL_TERRACOTTA + - ALL_STAINED_GLASS_PANE + - SLIME_BLOCK + - ALL_CARPET - COAL_BLOCK - #wood - - ACACIA_WOOD - - BIRCH_WOOD - - DARK_OAK_WOOD - - OAK_WOOD - - SPRUCE_WOOD - - STRIPPED_ACACIA_WOOD - - STRIPPED_BIRCH_WOOD - - STRIPPED_DARK_OAK_WOOD - - STRIPPED_OAK_WOOD - - STRIPPED_SPRUCE_WOOD - #wool - - WHITE_WOOL - - ORANGE_WOOL - - MAGENTA_WOOL - - LIGHT_BLUE_WOOL - - YELLOW_WOOL - - LIME_WOOL - - PINK_WOOL - - GRAY_WOOL - - LIGHT_GRAY_WOOL - - CYAN_WOOL - - PURPLE_WOOL - - BLUE_WOOL - - BROWN_WOOL - - GREEN_WOOL - - RED_WOOL - - BLACK_WOOL + - END_STONE_BRICKS canCruise: true cruiseSkipBlocks: 4 @@ -256,16 +95,19 @@ requireWaterContact: true allowVerticalMovement: false speed: 0.5 tryNudge: false +passthroughBlocks: + - kelp + - kelp_plant + - tall_seagrass + - seagrass + - bubble_column flyblocks: - 5: + all_planks: - 25.0 - 100.0 - 145: # anvils are OP armor, so limit it - - 0.0 - - 1.0 - 49: # so is obsidian + all_anvils: # anvils are OP armor, so limit it - 0.0 - 1.0 - 8: # so is water + obsidian: # so is obsidian - 0.0 - 1.0 diff --git a/modules/Movecraft/src/main/resources/types/SubAirship.craft b/modules/Movecraft/src/main/resources/types/SubAirship.craft index 07075d0ea..776632c02 100644 --- a/modules/Movecraft/src/main/resources/types/SubAirship.craft +++ b/modules/Movecraft/src/main/resources/types/SubAirship.craft @@ -2,248 +2,87 @@ name: SubAirship maxSize: 5000 minSize: 1000 allowedBlocks: - #beds - - WHITE_BED - - ORANGE_BED - - MAGENTA_BED - - LIGHT_BLUE_BED - - YELLOW_BED - - LIME_BED - - PINK_BED - - GRAY_BED - - LIGHT_BED - - CYAN_BED - - PURPLE_BED - - BLUE_BED - - BROWN_BED - - GREEN_BED - - RED_BED - - BLACK_BED - #buttons - - ACACIA_BUTTON - - BIRCH_BUTTON - - DARK_OAK_BUTTON - - JUNGLE_BUTTON - - OAK_BUTTON - - SPRUCE_BUTTON - - STONE_BUTTON - #carpets - - WHITE_CARPET - - ORANGE_CARPET - - MAGENTA_CARPET - - LIGHT_BLUE_CARPET - - YELLOW_CARPET - - LIME_CARPET - - PINK_CARPET - - GRAY_CARPET - - LIGHT_CARPET - - CYAN_CARPET - - PURPLE_CARPET - - BLUE_CARPET - - BROWN_CARPET - - GREEN_CARPET - - RED_CARPET - - BLACK_CARPET - #doors - - ACACIA_DOOR - - BIRCH_DOOR - - DARK_OAK_DOOR - - IRON_DOOR - - JUNGLE_DOOR - - OAK_DOOR - - SPRUCE_DOOR - #fences - - ACACIA_FENCE - - BIRCH_FENCE - - DARK_OAK_FENCE - - JUNGLE_FENCE - - OAK_FENCE - - NETHER_BRICK_FENCE - - SPRUCE_FENCE - #fence gates - - ACACIA_FENCE_GATE - - BIRCH_FENCE_GATE - - DARK_OAK_FENCE_GATE - - JUNGLE_FENCE_GATE - - OAK_FENCE_GATE - - SPRUCE_FENCE_GATE - #glass - - GLASS - - WHITE_STAINED_GLASS - - ORANGE_STAINED_GLASS - - MAGENTA_STAINED_GLASS - - LIGHT_BLUE_STAINED_GLASS - - YELLOW_STAINED_GLASS - - LIME_STAINED_GLASS - - PINK_STAINED_GLASS - - GRAY_STAINED_GLASS - - LIGHT_GRAY_STAINED_GLASS - - CYAN_STAINED_GLASS - - PURPLE_STAINED_GLASS - - BLUE_STAINED_GLASS - - BROWN_STAINED_GLASS - - GREEN_STAINED_GLASS - - RED_STAINED_GLASS - - BLACK_STAINED_GLASS - #glass pane - - GLASS_PANE - - WHITE_STAINED_GLASS_PANE - - ORANGE_STAINED_GLASS_PANE - - MAGENTA_STAINED_GLASS_PANE - - LIGHT_BLUE_STAINED_GLASS_PANE - - YELLOW_STAINED_GLASS_PANE - - LIME_STAINED_GLASS_PANE - - PINK_STAINED_GLASS_PANE - - GRAY_STAINED_GLASS_PANE - - LIGHT_GRAY_STAINED_GLASS_PANE - - CYAN_STAINED_GLASS_PANE - - PURPLE_STAINED_GLASS_PANE - - BLUE_STAINED_GLASS_PANE - - BROWN_STAINED_GLASS_PANE - - GREEN_STAINED_GLASS_PANE - - RED_STAINED_GLASS_PANE - - BLACK_STAINED_GLASS_PANE - #liquids - - LAVA + - ALL_WOOD - WATER - #logs - - BIRCH_LOG - - JUNGLE_LOG - - OAK_LOG - - SPRUCE_LOG - - STRIPPED_BIRCH_LOG - - STRIPPED_JUNGLE_LOG - - STRIPPED_OAK_LOG - - STRIPPED_SPRUCE_LOG - #misc + - LAVA + - ALL_LOG + - all_planks + - GLASS + - LAPIS_BLOCK + - DISPENSER + - NOTE_BLOCK + - ALL_BED + - sticky_piston + - piston_head + - all_wool + - GOLD_BLOCK + - IRON_BLOCK + - all_slab - BOOKSHELF - - BREWING_STAND - - CRAFTING_TABLE - - CAULDRON - - FURNACE - - GLOWSTONE - - IRON_BARS - - LADDER - - NETHER_BRICKS - - SIGN - TORCH - - WALL_SIGN - - WALL_TORCH - #planks - - ACACIA_PLANKS - - BIRCH_PLANKS - - DARK_OAK_PLANKS - - JUNGLE_PLANKS - - OAK_PLANKS - - SPRUCE_PLANKS - #pressure plates - - ACACIA_PRESSURE_PLATE - - BIRCH_PRESSURE_PLATE - - DARK_OAK_PRESSURE_PLATE - - HEAVY_WEIGHTED_PRESSURE_PLATE - - JUNGLE_PRESSURE_PLATE - - LIGHT_WEIGHTED_PRESSURE_PLATE - - OAK_PRESSURE_PLATE - - SPRUCE_PRESSURE_PLATE - - STONE_PRESSURE_PLATE - #redstone - - COMPARATOR - - LEVER - - NOTE_BLOCK - - PISTON - - PISTON_HEAD - - REDSTONE_BLOCK - - REDSTONE_WIRE - - REPEATER - - REDSTONE_TORCH - - REDSTONE_WALL_TORCH - - STICKY_PISTON + - FIRE + - oak_stairs + - birch_stairs + - jungle_stairs + - spruce_stairs + - stone_brick_stairs + - quartz_stairs + - nether_brick_stairs + - chest + - redstone_wire + - diamond_block + - nether_brick_stairs + - furnace + - all_sign + - ladder + - all_door + - lever + - all_pressure_plate + - redstone_torch + - redstone_wall_torch + - all_button + - clay + - all_fence + - netherrack + - glowstone + - cake + - redstone_repeater + - all_stained_glass + - all_trapdoor + - all_stone_bricks + - iron_bars + - glass_pane + - all_fence_gate + - nether_brick + - enchantment_table + - brewing_stand + - cauldron + - end_stone + - dragon_egg + - redstone_lamp + - ender chest - TRIPWIRE_HOOK - #slabs - - ACACIA_SLAB - - BIRCH_SLAB - - BRICK_SLAB - - COBBLESTONE_SLAB - - DARK_OAK_SLAB - - DARK_PRISMARINE - - JUNGLE_SLAB - - NETHER_BRICK_SLAB - - OAK_SLAB - - PETRIFIED_OAK_SLAB - - PRISMARINE_SLAB - - PRISMARINE_BRICK_SLAB - - RED_SANDSTONE_SLAB - - QUARTZ_SLAB - - SPRUCE_SLAB - - STONE_SLAB - #stairs - - BIRCH_STAIRS - - JUNGLE_STAIRS - - OAK_STAIRS - - NETHER_BRICK_STAIRS - - SMOOTH_STAIRS - - SPRUCE_STAIRS - - STONE_BRICK_STAIRS - #storage - - CHEST - - DISPENSER - - DROPPER - - HOPPER + - EMERALD_BLOCK + - BEACON + - cobblestone_wall + - mossy_cobblestone_wall + - FLOWER_POT + - SKULL + - all_ANVIL - TRAPPED_CHEST - #terracotta - - WHITE_TERRACOTTA - - ORANGE_TERRACOTTA - - MAGENTA_TERRACOTTA - - LIGHT_BLUE_TERRACOTTA - - YELLOW_TERRACOTTA - - LIME_TERRACOTTA - - PINK_TERRACOTTA - - GRAY_TERRACOTTA - - LIGHT_GRAY_TERRACOTTA - - CYAN_TERRACOTTA - - PURPLE_TERRACOTTA - - BLUE_TERRACOTTA - - BROWN_TERRACOTTA - - GREEN_TERRACOTTA - - RED_TERRACOTTA - - BLACK_TERRACOTTA - #trapdoors - - ACACIA_TRAPDOOR - - BIRCH_TRAPDOOR - - DARK_OAK_TRAPDOOR - - JUNGLE_TRAPDOOR - - OAK_TRAPDOOR - - SPRUCE_TRAPDOOR - #weapon blocks + - REDSTONE_COMPARATOR + - daylight_detector + - REDSTONE_BLOCK + - HOPPER + - all_QUARTZ_BLOCK + - all_rail + - DROPPER + - ALL_TERRACOTTA + - ALL_STAINED_GLASS_PANE + - SLIME_BLOCK + - ALL_CARPET - COAL_BLOCK - #wood - - ACACIA_WOOD - - BIRCH_WOOD - - DARK_OAK_WOOD - - OAK_WOOD - - SPRUCE_WOOD - - STRIPPED_ACACIA_WOOD - - STRIPPED_BIRCH_WOOD - - STRIPPED_DARK_OAK_WOOD - - STRIPPED_OAK_WOOD - - STRIPPED_SPRUCE_WOOD - #wool - - WHITE_WOOL - - ORANGE_WOOL - - MAGENTA_WOOL - - LIGHT_BLUE_WOOL - - YELLOW_WOOL - - LIME_WOOL - - PINK_WOOL - - GRAY_WOOL - - LIGHT_GRAY_WOOL - - CYAN_WOOL - - PURPLE_WOOL - - BLUE_WOOL - - BROWN_WOOL - - GREEN_WOOL - - RED_WOOL - - BLACK_WOOL + - END_STONE_BRICKS canCruise: true rotateAtMidpoint: true @@ -263,6 +102,13 @@ tryNudge: false halfSpeedUnderwater: true sinkPercent: 99.0 overallSinkPercent: 60.0 + +passthroughBlocks: + - kelp + - kelp_plant + - tall_seagrass + - seagrass + - bubble_column moveblocks: 152: # redstone represents engines - 1.0 diff --git a/modules/Movecraft/src/main/resources/types/Submarine.craft b/modules/Movecraft/src/main/resources/types/Submarine.craft index 222eedb87..5576a938a 100644 --- a/modules/Movecraft/src/main/resources/types/Submarine.craft +++ b/modules/Movecraft/src/main/resources/types/Submarine.craft @@ -2,248 +2,87 @@ name: Submarine maxSize: 100000 minSize: 10 allowedBlocks: - #beds - - WHITE_BED - - ORANGE_BED - - MAGENTA_BED - - LIGHT_BLUE_BED - - YELLOW_BED - - LIME_BED - - PINK_BED - - GRAY_BED - - LIGHT_BED - - CYAN_BED - - PURPLE_BED - - BLUE_BED - - BROWN_BED - - GREEN_BED - - RED_BED - - BLACK_BED - #buttons - - ACACIA_BUTTON - - BIRCH_BUTTON - - DARK_OAK_BUTTON - - JUNGLE_BUTTON - - OAK_BUTTON - - SPRUCE_BUTTON - - STONE_BUTTON - #carpets - - WHITE_CARPET - - ORANGE_CARPET - - MAGENTA_CARPET - - LIGHT_BLUE_CARPET - - YELLOW_CARPET - - LIME_CARPET - - PINK_CARPET - - GRAY_CARPET - - LIGHT_CARPET - - CYAN_CARPET - - PURPLE_CARPET - - BLUE_CARPET - - BROWN_CARPET - - GREEN_CARPET - - RED_CARPET - - BLACK_CARPET - #doors - - ACACIA_DOOR - - BIRCH_DOOR - - DARK_OAK_DOOR - - IRON_DOOR - - JUNGLE_DOOR - - OAK_DOOR - - SPRUCE_DOOR - #fences - - ACACIA_FENCE - - BIRCH_FENCE - - DARK_OAK_FENCE - - JUNGLE_FENCE - - OAK_FENCE - - NETHER_BRICK_FENCE - - SPRUCE_FENCE - #fence gates - - ACACIA_FENCE_GATE - - BIRCH_FENCE_GATE - - DARK_OAK_FENCE_GATE - - JUNGLE_FENCE_GATE - - OAK_FENCE_GATE - - SPRUCE_FENCE_GATE - #glass - - GLASS - - WHITE_STAINED_GLASS - - ORANGE_STAINED_GLASS - - MAGENTA_STAINED_GLASS - - LIGHT_BLUE_STAINED_GLASS - - YELLOW_STAINED_GLASS - - LIME_STAINED_GLASS - - PINK_STAINED_GLASS - - GRAY_STAINED_GLASS - - LIGHT_GRAY_STAINED_GLASS - - CYAN_STAINED_GLASS - - PURPLE_STAINED_GLASS - - BLUE_STAINED_GLASS - - BROWN_STAINED_GLASS - - GREEN_STAINED_GLASS - - RED_STAINED_GLASS - - BLACK_STAINED_GLASS - #glass pane - - GLASS_PANE - - WHITE_STAINED_GLASS_PANE - - ORANGE_STAINED_GLASS_PANE - - MAGENTA_STAINED_GLASS_PANE - - LIGHT_BLUE_STAINED_GLASS_PANE - - YELLOW_STAINED_GLASS_PANE - - LIME_STAINED_GLASS_PANE - - PINK_STAINED_GLASS_PANE - - GRAY_STAINED_GLASS_PANE - - LIGHT_GRAY_STAINED_GLASS_PANE - - CYAN_STAINED_GLASS_PANE - - PURPLE_STAINED_GLASS_PANE - - BLUE_STAINED_GLASS_PANE - - BROWN_STAINED_GLASS_PANE - - GREEN_STAINED_GLASS_PANE - - RED_STAINED_GLASS_PANE - - BLACK_STAINED_GLASS_PANE - #liquids - - LAVA - - WATER - #logs - - BIRCH_LOG - - JUNGLE_LOG - - OAK_LOG - - SPRUCE_LOG - - STRIPPED_BIRCH_LOG - - STRIPPED_JUNGLE_LOG - - STRIPPED_OAK_LOG - - STRIPPED_SPRUCE_LOG - #misc - - BOOKSHELF - - BREWING_STAND - - CRAFTING_TABLE - - CAULDRON - - FURNACE - - GLOWSTONE - - IRON_BARS - - LADDER - - NETHER_BRICKS - - SIGN - - TORCH - - WALL_SIGN - - WALL_TORCH - #planks - - ACACIA_PLANKS - - BIRCH_PLANKS - - DARK_OAK_PLANKS - - JUNGLE_PLANKS - - OAK_PLANKS - - SPRUCE_PLANKS - #pressure plates - - ACACIA_PRESSURE_PLATE - - BIRCH_PRESSURE_PLATE - - DARK_OAK_PRESSURE_PLATE - - HEAVY_WEIGHTED_PRESSURE_PLATE - - JUNGLE_PRESSURE_PLATE - - LIGHT_WEIGHTED_PRESSURE_PLATE - - OAK_PRESSURE_PLATE - - SPRUCE_PRESSURE_PLATE - - STONE_PRESSURE_PLATE - #redstone - - COMPARATOR - - LEVER - - NOTE_BLOCK - - PISTON - - PISTON_HEAD - - REDSTONE_BLOCK - - REDSTONE_WIRE - - REPEATER - - REDSTONE_TORCH - - REDSTONE_WALL_TORCH - - STICKY_PISTON - - TRIPWIRE_HOOK - #slabs - - ACACIA_SLAB - - BIRCH_SLAB - - BRICK_SLAB - - COBBLESTONE_SLAB - - DARK_OAK_SLAB - - DARK_PRISMARINE - - JUNGLE_SLAB - - NETHER_BRICK_SLAB - - OAK_SLAB - - PETRIFIED_OAK_SLAB - - PRISMARINE_SLAB - - PRISMARINE_BRICK_SLAB - - RED_SANDSTONE_SLAB - - QUARTZ_SLAB - - SPRUCE_SLAB - - STONE_SLAB - #stairs - - BIRCH_STAIRS - - JUNGLE_STAIRS - - OAK_STAIRS - - NETHER_BRICK_STAIRS - - SMOOTH_STAIRS - - SPRUCE_STAIRS - - STONE_BRICK_STAIRS - #storage - - CHEST - - DISPENSER - - DROPPER - - HOPPER - - TRAPPED_CHEST - #terracotta - - WHITE_TERRACOTTA - - ORANGE_TERRACOTTA - - MAGENTA_TERRACOTTA - - LIGHT_BLUE_TERRACOTTA - - YELLOW_TERRACOTTA - - LIME_TERRACOTTA - - PINK_TERRACOTTA - - GRAY_TERRACOTTA - - LIGHT_GRAY_TERRACOTTA - - CYAN_TERRACOTTA - - PURPLE_TERRACOTTA - - BLUE_TERRACOTTA - - BROWN_TERRACOTTA - - GREEN_TERRACOTTA - - RED_TERRACOTTA - - BLACK_TERRACOTTA - #trapdoors - - ACACIA_TRAPDOOR - - BIRCH_TRAPDOOR - - DARK_OAK_TRAPDOOR - - JUNGLE_TRAPDOOR - - OAK_TRAPDOOR - - SPRUCE_TRAPDOOR - #weapon blocks - - COAL_BLOCK - #wood - - ACACIA_WOOD - - BIRCH_WOOD - - DARK_OAK_WOOD - - OAK_WOOD - - SPRUCE_WOOD - - STRIPPED_ACACIA_WOOD - - STRIPPED_BIRCH_WOOD - - STRIPPED_DARK_OAK_WOOD - - STRIPPED_OAK_WOOD - - STRIPPED_SPRUCE_WOOD - #wool - - WHITE_WOOL - - ORANGE_WOOL - - MAGENTA_WOOL - - LIGHT_BLUE_WOOL - - YELLOW_WOOL - - LIME_WOOL - - PINK_WOOL - - GRAY_WOOL - - LIGHT_GRAY_WOOL - - CYAN_WOOL - - PURPLE_WOOL - - BLUE_WOOL - - BROWN_WOOL - - GREEN_WOOL - - RED_WOOL - - BLACK_WOOL + - ALL_WOOD + - WATER + - LAVA + - ALL_LOG + - all_planks + - GLASS + - LAPIS_BLOCK + - DISPENSER + - NOTE_BLOCK + - ALL_BED + - sticky_piston + - piston_head + - all_wool + - GOLD_BLOCK + - IRON_BLOCK + - all_slab + - BOOKSHELF + - TORCH + - FIRE + - oak_stairs + - birch_stairs + - jungle_stairs + - spruce_stairs + - stone_brick_stairs + - quartz_stairs + - nether_brick_stairs + - chest + - redstone_wire + - diamond_block + - nether_brick_stairs + - furnace + - all_sign + - ladder + - all_door + - lever + - all_pressure_plate + - redstone_torch + - redstone_wall_torch + - all_button + - clay + - all_fence + - netherrack + - glowstone + - cake + - redstone_repeater + - all_stained_glass + - all_trapdoor + - all_stone_bricks + - iron_bars + - glass_pane + - all_fence_gate + - nether_brick + - enchantment_table + - brewing_stand + - cauldron + - end_stone + - dragon_egg + - redstone_lamp + - ender chest + - TRIPWIRE_HOOK + - EMERALD_BLOCK + - BEACON + - cobblestone_wall + - mossy_cobblestone_wall + - FLOWER_POT + - SKULL + - all_ANVIL + - TRAPPED_CHEST + - REDSTONE_COMPARATOR + - daylight_detector + - REDSTONE_BLOCK + - HOPPER + - all_QUARTZ_BLOCK + - all_rail + - DROPPER + - ALL_TERRACOTTA + - ALL_STAINED_GLASS_PANE + - SLIME_BLOCK + - ALL_CARPET + - COAL_BLOCK + - END_STONE_BRICKS canCruise: true cruiseSkipBlocks: 4 @@ -257,6 +96,13 @@ requireWaterContact: true allowVerticalMovement: true fuelBurnRate: 1.0 tryNudge: false + +passthroughBlocks: + - kelp + - kelp_plant + - tall_seagrass + - seagrass + - bubble_column flyblocks: [ACACIA_PLANKS, BIRCH_PLANKS, DARK_OAK_PLANKS, JUNGLE_PLANKS, OAK_PLANKS, SPRUCE_PLANKS]: - 25.0 diff --git a/modules/Movecraft/src/main/resources/types/Turret.craft b/modules/Movecraft/src/main/resources/types/Turret.craft index 15cc0d687..2fc12a8f2 100644 --- a/modules/Movecraft/src/main/resources/types/Turret.craft +++ b/modules/Movecraft/src/main/resources/types/Turret.craft @@ -2,191 +2,75 @@ name: Turret maxSize: 1000 minSize: 1 allowedBlocks: - #beds - - WHITE_BED - - ORANGE_BED - - MAGENTA_BED - - LIGHT_BLUE_BED - - YELLOW_BED - - LIME_BED - - PINK_BED - - GRAY_BED - - LIGHT_BED - - CYAN_BED - - PURPLE_BED - - BLUE_BED - - BROWN_BED - - GREEN_BED - - RED_BED - - BLACK_BED - #buttons - - ACACIA_BUTTON - - BIRCH_BUTTON - - DARK_OAK_BUTTON - - JUNGLE_BUTTON - - OAK_BUTTON - - SPRUCE_BUTTON - - STONE_BUTTON - #doors - - ACACIA_DOOR - - BIRCH_DOOR - - DARK_OAK_DOOR - - IRON_DOOR - - JUNGLE_DOOR - - OAK_DOOR - - SPRUCE_DOOR - #fences - - ACACIA_FENCE - - BIRCH_FENCE - - DARK_OAK_FENCE - - JUNGLE_FENCE - - OAK_FENCE - - SPRUCE_FENCE - #fence gates - - ACACIA_FENCE_GATE - - BIRCH_FENCE_GATE - - DARK_OAK_FENCE_GATE - - JUNGLE_FENCE_GATE - - OAK_FENCE_GATE - - SPRUCE_FENCE_GATE - #glass - - GLASS - - WHITE_STAINED_GLASS - - ORANGE_STAINED_GLASS - - MAGENTA_STAINED_GLASS - - LIGHT_BLUE_STAINED_GLASS - - YELLOW_STAINED_GLASS - - LIME_STAINED_GLASS - - PINK_STAINED_GLASS - - GRAY_STAINED_GLASS - - LIGHT_GRAY_STAINED_GLASS - - CYAN_STAINED_GLASS - - PURPLE_STAINED_GLASS - - BLUE_STAINED_GLASS - - BROWN_STAINED_GLASS - - GREEN_STAINED_GLASS - - RED_STAINED_GLASS - - BLACK_STAINED_GLASS - #glass pane - - GLASS_PANE - - WHITE_STAINED_GLASS_PANE - - ORANGE_STAINED_GLASS_PANE - - MAGENTA_STAINED_GLASS_PANE - - LIGHT_BLUE_STAINED_GLASS_PANE - - YELLOW_STAINED_GLASS_PANE - - LIME_STAINED_GLASS_PANE - - PINK_STAINED_GLASS_PANE - - GRAY_STAINED_GLASS_PANE - - LIGHT_GRAY_STAINED_GLASS_PANE - - CYAN_STAINED_GLASS_PANE - - PURPLE_STAINED_GLASS_PANE - - BLUE_STAINED_GLASS_PANE - - BROWN_STAINED_GLASS_PANE - - GREEN_STAINED_GLASS_PANE - - RED_STAINED_GLASS_PANE - - BLACK_STAINED_GLASS_PANE - #interior - - BOOKSHELF - - BREWING_STAND - - CAULDRON - - IRON_BARS - - SIGN - - TORCH - - WALL_SIGN - - WALL_TORCH - #liquids - - LAVA - - WATER - #logs - - BIRCH_LOG - - JUNGLE_LOG - - OAK_LOG - - SPRUCE_LOG - - STRIPPED_BIRCH_LOG - - STRIPPED_JUNGLE_LOG - - STRIPPED_OAK_LOG - - STRIPPED_SPRUCE_LOG - #planks - - ACACIA_PLANKS - - BIRCH_PLANKS - - DARK_OAK_PLANKS - - JUNGLE_PLANKS - - OAK_PLANKS - - SPRUCE_PLANKS - #pressure plates - - ACACIA_PRESSURE_PLATE - - BIRCH_PRESSURE_PLATE - - DARK_OAK_PRESSURE_PLATE - - HEAVY_WEIGHTED_PRESSURE_PLATE - - JUNGLE_PRESSURE_PLATE - - LIGHT_WEIGHTED_PRESSURE_PLATE - - OAK_PRESSURE_PLATE - - SPRUCE_PRESSURE_PLATE - #redstone - - COMPARATOR - - NOTE_BLOCK - - PISTON - - PISTON_HEAD - - REDSTONE_BLOCK - - REDSTONE_WIRE - - REPEATER - - STICKY_PISTON - - TRIPWIRE_HOOK - #slabs - - ACACIA_SLAB - - BIRCH_SLAB - - BRICK_SLAB - - COBBLESTONE_SLAB - - DARK_OAK_SLAB - - DARK_PRISMARINE - - JUNGLE_SLAB - - NETHER_BRICK_SLAB - - OAK_SLAB - - PETRIFIED_OAK_SLAB - - PRISMARINE_SLAB - - PRISMARINE_BRICK_SLAB - - RED_SANDSTONE_SLAB - - QUARTZ_SLAB - - SPRUCE_SLAB - - STONE_SLAB - #stairs - - BIRCH_STAIRS - - JUNGLE_STAIRS - - OAK_STAIRS - - SMOOTH_STAIRS - - SPRUCE_STAIRS - #storage - - CHEST - - DISPENSER - - DROPPER - - HOPPER - - TRAPPED_CHEST - #terracotta - - GRAY_TERRACOTTA - - LIGHT_GRAY_TERRACOTTA - - BLACK_TERRACOTTA - #trapdoors - - ACACIA_TRAPDOOR - - BIRCH_TRAPDOOR - - DARK_OAK_TRAPDOOR - - JUNGLE_TRAPDOOR - - OAK_TRAPDOOR - - SPRUCE_TRAPDOOR - #weapon blocks - - COAL_BLOCK - #wood - - ACACIA_WOOD - - BIRCH_WOOD - - DARK_OAK_WOOD - - OAK_WOOD - - SPRUCE_WOOD - - STRIPPED_ACACIA_WOOD - - STRIPPED_BIRCH_WOOD - - STRIPPED_DARK_OAK_WOOD - - STRIPPED_OAK_WOOD - - STRIPPED_SPRUCE_WOOD - #wool - - LIGHT_GRAY_WOOL + - ALL_WOOD + - WATER + - LAVA + - ALL_LOG + - all_planks + - GLASS + - DISPENSER + - NOTE_BLOCK + - ALL_BED + - sticky_piston + - piston_head + - light_gray_wool + - all_slab + - BOOKSHELF + - TORCH + - FIRE + - oak_stairs + - birch_stairs + - jungle_stairs + - spruce_stairs + - chest + - redstone_wire + - furnace + - all_sign + - ladder + - all_door + - lever + - all_pressure_plate + - redstone_torch + - redstone_wall_torch + - all_button + - all_fence + - netherrack + - glowstone + - cake + - redstone_repeater + - all_stained_glass + - all_trapdoor + - all_stone_bricks + - iron_bars + - glass_pane + - all_fence_gate + - enchantment_table + - brewing_stand + - cauldron + - dragon_egg + - redstone_lamp + - ender chest + - TRIPWIRE_HOOK + - EMERALD_BLOCK + - BEACON + - FLOWER_POT + - SKULL + - all_ANVIL + - TRAPPED_CHEST + - REDSTONE_COMPARATOR + - daylight_detector + - REDSTONE_BLOCK + - HOPPER + - all_rail + - DROPPER + - light_gray_terracotta + - gray_terracotta + - black_terracotta + - ALL_STAINED_GLASS_PANE + - SLIME_BLOCK + - ALL_CARPET + - COAL_BLOCK + - END_STONE_BRICKS forbiddenBlocks: - PISTON_HEAD diff --git a/modules/Movecraft/src/main/resources/types/airship.craft b/modules/Movecraft/src/main/resources/types/airship.craft index 12b6beb50..57c7c9e7d 100644 --- a/modules/Movecraft/src/main/resources/types/airship.craft +++ b/modules/Movecraft/src/main/resources/types/airship.craft @@ -2,248 +2,87 @@ name: Airship maxSize: 5000 minSize: 1000 allowedBlocks: - #beds - - WHITE_BED - - ORANGE_BED - - MAGENTA_BED - - LIGHT_BLUE_BED - - YELLOW_BED - - LIME_BED - - PINK_BED - - GRAY_BED - - LIGHT_BED - - CYAN_BED - - PURPLE_BED - - BLUE_BED - - BROWN_BED - - GREEN_BED - - RED_BED - - BLACK_BED - #buttons - - ACACIA_BUTTON - - BIRCH_BUTTON - - DARK_OAK_BUTTON - - JUNGLE_BUTTON - - OAK_BUTTON - - SPRUCE_BUTTON - - STONE_BUTTON - #carpets - - WHITE_CARPET - - ORANGE_CARPET - - MAGENTA_CARPET - - LIGHT_BLUE_CARPET - - YELLOW_CARPET - - LIME_CARPET - - PINK_CARPET - - GRAY_CARPET - - LIGHT_CARPET - - CYAN_CARPET - - PURPLE_CARPET - - BLUE_CARPET - - BROWN_CARPET - - GREEN_CARPET - - RED_CARPET - - BLACK_CARPET - #doors - - ACACIA_DOOR - - BIRCH_DOOR - - DARK_OAK_DOOR - - IRON_DOOR - - JUNGLE_DOOR - - OAK_DOOR - - SPRUCE_DOOR - #fences - - ACACIA_FENCE - - BIRCH_FENCE - - DARK_OAK_FENCE - - JUNGLE_FENCE - - OAK_FENCE - - NETHER_BRICK_FENCE - - SPRUCE_FENCE - #fence gates - - ACACIA_FENCE_GATE - - BIRCH_FENCE_GATE - - DARK_OAK_FENCE_GATE - - JUNGLE_FENCE_GATE - - OAK_FENCE_GATE - - SPRUCE_FENCE_GATE - #glass - - GLASS - - WHITE_STAINED_GLASS - - ORANGE_STAINED_GLASS - - MAGENTA_STAINED_GLASS - - LIGHT_BLUE_STAINED_GLASS - - YELLOW_STAINED_GLASS - - LIME_STAINED_GLASS - - PINK_STAINED_GLASS - - GRAY_STAINED_GLASS - - LIGHT_GRAY_STAINED_GLASS - - CYAN_STAINED_GLASS - - PURPLE_STAINED_GLASS - - BLUE_STAINED_GLASS - - BROWN_STAINED_GLASS - - GREEN_STAINED_GLASS - - RED_STAINED_GLASS - - BLACK_STAINED_GLASS - #glass pane - - GLASS_PANE - - WHITE_STAINED_GLASS_PANE - - ORANGE_STAINED_GLASS_PANE - - MAGENTA_STAINED_GLASS_PANE - - LIGHT_BLUE_STAINED_GLASS_PANE - - YELLOW_STAINED_GLASS_PANE - - LIME_STAINED_GLASS_PANE - - PINK_STAINED_GLASS_PANE - - GRAY_STAINED_GLASS_PANE - - LIGHT_GRAY_STAINED_GLASS_PANE - - CYAN_STAINED_GLASS_PANE - - PURPLE_STAINED_GLASS_PANE - - BLUE_STAINED_GLASS_PANE - - BROWN_STAINED_GLASS_PANE - - GREEN_STAINED_GLASS_PANE - - RED_STAINED_GLASS_PANE - - BLACK_STAINED_GLASS_PANE - #liquids - - LAVA + - ALL_WOOD - WATER - #logs - - BIRCH_LOG - - JUNGLE_LOG - - OAK_LOG - - SPRUCE_LOG - - STRIPPED_BIRCH_LOG - - STRIPPED_JUNGLE_LOG - - STRIPPED_OAK_LOG - - STRIPPED_SPRUCE_LOG - #misc + - LAVA + - ALL_LOG + - all_planks + - GLASS + - LAPIS_BLOCK + - DISPENSER + - NOTE_BLOCK + - ALL_BED + - sticky_piston + - piston_head + - all_wool + - GOLD_BLOCK + - IRON_BLOCK + - all_slab - BOOKSHELF - - BREWING_STAND - - CRAFTING_TABLE - - CAULDRON - - FURNACE - - GLOWSTONE - - IRON_BARS - - LADDER - - NETHER_BRICKS - - SIGN - TORCH - - WALL_SIGN - - WALL_TORCH - #planks - - ACACIA_PLANKS - - BIRCH_PLANKS - - DARK_OAK_PLANKS - - JUNGLE_PLANKS - - OAK_PLANKS - - SPRUCE_PLANKS - #pressure plates - - ACACIA_PRESSURE_PLATE - - BIRCH_PRESSURE_PLATE - - DARK_OAK_PRESSURE_PLATE - - HEAVY_WEIGHTED_PRESSURE_PLATE - - JUNGLE_PRESSURE_PLATE - - LIGHT_WEIGHTED_PRESSURE_PLATE - - OAK_PRESSURE_PLATE - - SPRUCE_PRESSURE_PLATE - - STONE_PRESSURE_PLATE - #redstone - - COMPARATOR - - LEVER - - NOTE_BLOCK - - PISTON - - PISTON_HEAD - - REDSTONE_BLOCK - - REDSTONE_WIRE - - REPEATER - - REDSTONE_TORCH - - REDSTONE_WALL_TORCH - - STICKY_PISTON + - FIRE + - oak_stairs + - birch_stairs + - jungle_stairs + - spruce_stairs + - stone_brick_stairs + - quartz_stairs + - nether_brick_stairs + - chest + - redstone_wire + - diamond_block + - nether_brick_stairs + - furnace + - all_sign + - ladder + - all_door + - lever + - all_pressure_plate + - redstone_torch + - redstone_wall_torch + - all_button + - clay + - all_fence + - netherrack + - glowstone + - cake + - redstone_repeater + - all_stained_glass + - all_trapdoor + - all_stone_bricks + - iron_bars + - glass_pane + - all_fence_gate + - nether_brick + - enchantment_table + - brewing_stand + - cauldron + - end_stone + - dragon_egg + - redstone_lamp + - ender chest - TRIPWIRE_HOOK - #slabs - - ACACIA_SLAB - - BIRCH_SLAB - - BRICK_SLAB - - COBBLESTONE_SLAB - - DARK_OAK_SLAB - - DARK_PRISMARINE - - JUNGLE_SLAB - - NETHER_BRICK_SLAB - - OAK_SLAB - - PETRIFIED_OAK_SLAB - - PRISMARINE_SLAB - - PRISMARINE_BRICK_SLAB - - RED_SANDSTONE_SLAB - - QUARTZ_SLAB - - SPRUCE_SLAB - - STONE_SLAB - #stairs - - BIRCH_STAIRS - - JUNGLE_STAIRS - - OAK_STAIRS - - NETHER_BRICK_STAIRS - - SMOOTH_STAIRS - - SPRUCE_STAIRS - - STONE_BRICK_STAIRS - #storage - - CHEST - - DISPENSER - - DROPPER - - HOPPER + - EMERALD_BLOCK + - BEACON + - cobblestone_wall + - mossy_cobblestone_wall + - FLOWER_POT + - SKULL + - all_ANVIL - TRAPPED_CHEST - #terracotta - - WHITE_TERRACOTTA - - ORANGE_TERRACOTTA - - MAGENTA_TERRACOTTA - - LIGHT_BLUE_TERRACOTTA - - YELLOW_TERRACOTTA - - LIME_TERRACOTTA - - PINK_TERRACOTTA - - GRAY_TERRACOTTA - - LIGHT_GRAY_TERRACOTTA - - CYAN_TERRACOTTA - - PURPLE_TERRACOTTA - - BLUE_TERRACOTTA - - BROWN_TERRACOTTA - - GREEN_TERRACOTTA - - RED_TERRACOTTA - - BLACK_TERRACOTTA - #trapdoors - - ACACIA_TRAPDOOR - - BIRCH_TRAPDOOR - - DARK_OAK_TRAPDOOR - - JUNGLE_TRAPDOOR - - OAK_TRAPDOOR - - SPRUCE_TRAPDOOR - #weapon blocks + - REDSTONE_COMPARATOR + - daylight_detector + - REDSTONE_BLOCK + - HOPPER + - all_QUARTZ_BLOCK + - all_rail + - DROPPER + - ALL_TERRACOTTA + - ALL_STAINED_GLASS_PANE + - SLIME_BLOCK + - ALL_CARPET - COAL_BLOCK - #wood - - ACACIA_WOOD - - BIRCH_WOOD - - DARK_OAK_WOOD - - OAK_WOOD - - SPRUCE_WOOD - - STRIPPED_ACACIA_WOOD - - STRIPPED_BIRCH_WOOD - - STRIPPED_DARK_OAK_WOOD - - STRIPPED_OAK_WOOD - - STRIPPED_SPRUCE_WOOD - #wool - - WHITE_WOOL - - ORANGE_WOOL - - MAGENTA_WOOL - - LIGHT_BLUE_WOOL - - YELLOW_WOOL - - LIME_WOOL - - PINK_WOOL - - GRAY_WOOL - - LIGHT_GRAY_WOOL - - CYAN_WOOL - - PURPLE_WOOL - - BLUE_WOOL - - BROWN_WOOL - - GREEN_WOOL - - RED_WOOL - - BLACK_WOOL + - END_STONE_BRICKS canCruise: true rotateAtMidpoint: true @@ -268,7 +107,7 @@ moveblocks: - 1.0 - 100.0 flyblocks: - [WHITE_WOOL, ORANGE_WOOL, MAGENTA_WOOL,LIGHT_BLUE_WOOL,YELLOW_WOOL,LIME_WOOL,PINK_WOOL,GRAY_WOOL,LIGHT_GRAY_WOOL,CYAN_WOOL,PURPLE_WOOL,BLUE_WOOL,BROWN_WOOL, GREEN_WOOL, RED_WOOL, BLACK_WOOL]: #wool represents lift + all_wool: #wool represents lift - 50.0 - 100.0 [CHEST,TRAPPED_CHEST]: # limit chests to make big airships important for merchant missions diff --git a/modules/Movecraft/src/main/resources/types/airskiff.craft b/modules/Movecraft/src/main/resources/types/airskiff.craft index f364ed910..255f01d15 100644 --- a/modules/Movecraft/src/main/resources/types/airskiff.craft +++ b/modules/Movecraft/src/main/resources/types/airskiff.craft @@ -2,205 +2,74 @@ name: Airskiff maxSize: 80 minSize: 10 allowedBlocks: - #beds - - WHITE_BED - - ORANGE_BED - - MAGENTA_BED - - LIGHT_BLUE_BED - - YELLOW_BED - - LIME_BED - - PINK_BED - - GRAY_BED - - LIGHT_BED - - CYAN_BED - - PURPLE_BED - - BLUE_BED - - BROWN_BED - - GREEN_BED - - RED_BED - - BLACK_BED - #buttons - - ACACIA_BUTTON - - BIRCH_BUTTON - - DARK_OAK_BUTTON - - JUNGLE_BUTTON - - OAK_BUTTON - - SPRUCE_BUTTON - - STONE_BUTTON - #doors - - ACACIA_DOOR - - BIRCH_DOOR - - DARK_OAK_DOOR - - IRON_DOOR - - JUNGLE_DOOR - - OAK_DOOR - - SPRUCE_DOOR - #fences - - ACACIA_FENCE - - BIRCH_FENCE - - DARK_OAK_FENCE - - JUNGLE_FENCE - - OAK_FENCE - - SPRUCE_FENCE - #fence gates - - ACACIA_FENCE_GATE - - BIRCH_FENCE_GATE - - DARK_OAK_FENCE_GATE - - JUNGLE_FENCE_GATE - - OAK_FENCE_GATE - - SPRUCE_FENCE_GATE - #glass - - GLASS - - WHITE_STAINED_GLASS - - ORANGE_STAINED_GLASS - - MAGENTA_STAINED_GLASS - - LIGHT_BLUE_STAINED_GLASS - - YELLOW_STAINED_GLASS - - LIME_STAINED_GLASS - - PINK_STAINED_GLASS - - GRAY_STAINED_GLASS - - LIGHT_GRAY_STAINED_GLASS - - CYAN_STAINED_GLASS - - PURPLE_STAINED_GLASS - - BLUE_STAINED_GLASS - - BROWN_STAINED_GLASS - - GREEN_STAINED_GLASS - - RED_STAINED_GLASS - - BLACK_STAINED_GLASS - #glass pane - - GLASS_PANE - - WHITE_STAINED_GLASS_PANE - - ORANGE_STAINED_GLASS_PANE - - MAGENTA_STAINED_GLASS_PANE - - LIGHT_BLUE_STAINED_GLASS_PANE - - YELLOW_STAINED_GLASS_PANE - - LIME_STAINED_GLASS_PANE - - PINK_STAINED_GLASS_PANE - - GRAY_STAINED_GLASS_PANE - - LIGHT_GRAY_STAINED_GLASS_PANE - - CYAN_STAINED_GLASS_PANE - - PURPLE_STAINED_GLASS_PANE - - BLUE_STAINED_GLASS_PANE - - BROWN_STAINED_GLASS_PANE - - GREEN_STAINED_GLASS_PANE - - RED_STAINED_GLASS_PANE - - BLACK_STAINED_GLASS_PANE - #interior - - BOOKSHELF - - BREWING_STAND - - CAULDRON - - IRON_BARS - - SIGN - - TORCH - - WALL_SIGN - - WALL_TORCH - #liquids - - LAVA - - WATER - #logs - - BIRCH_LOG - - JUNGLE_LOG - - OAK_LOG - - SPRUCE_LOG - - STRIPPED_BIRCH_LOG - - STRIPPED_JUNGLE_LOG - - STRIPPED_OAK_LOG - - STRIPPED_SPRUCE_LOG - #planks - - ACACIA_PLANKS - - BIRCH_PLANKS - - DARK_OAK_PLANKS - - JUNGLE_PLANKS - - OAK_PLANKS - - SPRUCE_PLANKS - #pressure plates - - ACACIA_PRESSURE_PLATE - - BIRCH_PRESSURE_PLATE - - DARK_OAK_PRESSURE_PLATE - - HEAVY_WEIGHTED_PRESSURE_PLATE - - JUNGLE_PRESSURE_PLATE - - LIGHT_WEIGHTED_PRESSURE_PLATE - - OAK_PRESSURE_PLATE - - SPRUCE_PRESSURE_PLATE - #redstone - - COMPARATOR - - NOTE_BLOCK - - PISTON - - PISTON_HEAD - - REDSTONE_BLOCK - - REDSTONE_WIRE - - REPEATER - - REDSTONE_TORCH - - REDSTONE_WALL_TORCH - - STICKY_PISTON - - TRIPWIRE_HOOK - #slabs - - ACACIA_SLAB - - BIRCH_SLAB - - BRICK_SLAB - - COBBLESTONE_SLAB - - DARK_OAK_SLAB - - DARK_PRISMARINE - - JUNGLE_SLAB - - NETHER_BRICK_SLAB - - OAK_SLAB - - PETRIFIED_OAK_SLAB - - PRISMARINE_SLAB - - PRISMARINE_BRICK_SLAB - - RED_SANDSTONE_SLAB - - QUARTZ_SLAB - - SPRUCE_SLAB - - STONE_SLAB - #stairs - - BIRCH_STAIRS - - JUNGLE_STAIRS - - OAK_STAIRS - - SMOOTH_STAIRS - - SPRUCE_STAIRS - #storage - - CHEST - - DISPENSER - - DROPPER - - HOPPER - - TRAPPED_CHEST - #trapdoors - - ACACIA_TRAPDOOR - - BIRCH_TRAPDOOR - - DARK_OAK_TRAPDOOR - - JUNGLE_TRAPDOOR - - OAK_TRAPDOOR - - SPRUCE_TRAPDOOR - #weapon blocks - - COAL_BLOCK - #wood - - ACACIA_WOOD - - BIRCH_WOOD - - DARK_OAK_WOOD - - OAK_WOOD - - SPRUCE_WOOD - - STRIPPED_ACACIA_WOOD - - STRIPPED_BIRCH_WOOD - - STRIPPED_DARK_OAK_WOOD - - STRIPPED_OAK_WOOD - - STRIPPED_SPRUCE_WOOD - #wool - - WHITE_WOOL - - ORANGE_WOOL - - MAGENTA_WOOL - - LIGHT_BLUE_WOOL - - YELLOW_WOOL - - LIME_WOOL - - PINK_WOOL - - GRAY_WOOL - - LIGHT_GRAY_WOOL - - CYAN_WOOL - - PURPLE_WOOL - - BLUE_WOOL - - BROWN_WOOL - - GREEN_WOOL - - RED_WOOL - - BLACK_WOOL - + - ALL_WOOD + - WATER + - LAVA + - ALL_LOG + - all_planks + - GLASS + - DISPENSER + - NOTE_BLOCK + - ALL_BED + - sticky_piston + - piston_head + - all_wool + - all_slab + - BOOKSHELF + - TORCH + - FIRE + - oak_stairs + - birch_stairs + - jungle_stairs + - spruce_stairs + - chest + - redstone_wire + - nether_brick_stairs + - furnace + - all_sign + - ladder + - all_door + - lever + - all_pressure_plate + - redstone_torch + - redstone_wall_torch + - all_button + - all_fence + - netherrack + - glowstone + - cake + - redstone_repeater + - all_stained_glass + - all_trapdoor + - all_stone_bricks + - iron_bars + - glass_pane + - all_fence_gate + - enchantment_table + - brewing_stand + - cauldron + - dragon_egg + - redstone_lamp + - ender chest + - TRIPWIRE_HOOK + - EMERALD_BLOCK + - BEACON + - FLOWER_POT + - SKULL + - all_ANVIL + - TRAPPED_CHEST + - REDSTONE_COMPARATOR + - daylight_detector + - REDSTONE_BLOCK + - HOPPER + - all_QUARTZ_BLOCK: + - all_rail + - DROPPER + - ALL_STAINED_GLASS_PANE + - SLIME_BLOCK + - ALL_CARPET + - COAL_BLOCK + - END_STONE_BRICKS forbiddenBlocks: - PISTON_HEAD @@ -226,7 +95,7 @@ speed: 3.0 tryNudge: false sinkPercent: 99.0 flyblocks: - [WHITE_WOOL, ORANGE_WOOL, MAGENTA_WOOL,LIGHT_BLUE_WOOL,YELLOW_WOOL,LIME_WOOL,PINK_WOOL,GRAY_WOOL,LIGHT_GRAY_WOOL,CYAN_WOOL,PURPLE_WOOL,BLUE_WOOL,BROWN_WOOL, GREEN_WOOL, RED_WOOL, BLACK_WOOL]: #wool represents lift + all_wool: #wool represents lift - 50.0 - 100.0 [CHEST,TRAPPED_CHEST]: # limit chests to make big airships important for merchant missions diff --git a/modules/Movecraft/src/main/resources/types/elevator.craft b/modules/Movecraft/src/main/resources/types/elevator.craft index 8ebe8d222..1b41424c1 100644 --- a/modules/Movecraft/src/main/resources/types/elevator.craft +++ b/modules/Movecraft/src/main/resources/types/elevator.craft @@ -2,207 +2,74 @@ name: elevator maxSize: 1000 minSize: 10 allowedBlocks: - #beds - - WHITE_BED - - ORANGE_BED - - MAGENTA_BED - - LIGHT_BLUE_BED - - YELLOW_BED - - LIME_BED - - PINK_BED - - GRAY_BED - - LIGHT_BED - - CYAN_BED - - PURPLE_BED - - BLUE_BED - - BROWN_BED - - GREEN_BED - - RED_BED - - BLACK_BED - #buttons - - ACACIA_BUTTON - - BIRCH_BUTTON - - DARK_OAK_BUTTON - - JUNGLE_BUTTON - - OAK_BUTTON - - SPRUCE_BUTTON - - STONE_BUTTON - #doors - - ACACIA_DOOR - - BIRCH_DOOR - - DARK_OAK_DOOR - - IRON_DOOR - - JUNGLE_DOOR - - OAK_DOOR - - SPRUCE_DOOR - #fences - - ACACIA_FENCE - - BIRCH_FENCE - - DARK_OAK_FENCE - - JUNGLE_FENCE - - OAK_FENCE - - SPRUCE_FENCE - #fence gates - - ACACIA_FENCE_GATE - - BIRCH_FENCE_GATE - - DARK_OAK_FENCE_GATE - - JUNGLE_FENCE_GATE - - OAK_FENCE_GATE - - SPRUCE_FENCE_GATE - #glass - - GLASS - - WHITE_STAINED_GLASS - - ORANGE_STAINED_GLASS - - MAGENTA_STAINED_GLASS - - LIGHT_BLUE_STAINED_GLASS - - YELLOW_STAINED_GLASS - - LIME_STAINED_GLASS - - PINK_STAINED_GLASS - - GRAY_STAINED_GLASS - - LIGHT_GRAY_STAINED_GLASS - - CYAN_STAINED_GLASS - - PURPLE_STAINED_GLASS - - BLUE_STAINED_GLASS - - BROWN_STAINED_GLASS - - GREEN_STAINED_GLASS - - RED_STAINED_GLASS - - BLACK_STAINED_GLASS - #glass pane - - GLASS_PANE - - WHITE_STAINED_GLASS_PANE - - ORANGE_STAINED_GLASS_PANE - - MAGENTA_STAINED_GLASS_PANE - - LIGHT_BLUE_STAINED_GLASS_PANE - - YELLOW_STAINED_GLASS_PANE - - LIME_STAINED_GLASS_PANE - - PINK_STAINED_GLASS_PANE - - GRAY_STAINED_GLASS_PANE - - LIGHT_GRAY_STAINED_GLASS_PANE - - CYAN_STAINED_GLASS_PANE - - PURPLE_STAINED_GLASS_PANE - - BLUE_STAINED_GLASS_PANE - - BROWN_STAINED_GLASS_PANE - - GREEN_STAINED_GLASS_PANE - - RED_STAINED_GLASS_PANE - - BLACK_STAINED_GLASS_PANE - #interior - - BOOKSHELF - - BREWING_STAND - - CAULDRON - - IRON_BARS - - SIGN - - TORCH - - WALL_SIGN - - WALL_TORCH - #liquids - - LAVA - - WATER - #logs - - BIRCH_LOG - - JUNGLE_LOG - - OAK_LOG - - SPRUCE_LOG - - STRIPPED_BIRCH_LOG - - STRIPPED_JUNGLE_LOG - - STRIPPED_OAK_LOG - - STRIPPED_SPRUCE_LOG - #planks - - ACACIA_PLANKS - - BIRCH_PLANKS - - DARK_OAK_PLANKS - - JUNGLE_PLANKS - - OAK_PLANKS - - SPRUCE_PLANKS - #pressure plates - - ACACIA_PRESSURE_PLATE - - BIRCH_PRESSURE_PLATE - - DARK_OAK_PRESSURE_PLATE - - HEAVY_WEIGHTED_PRESSURE_PLATE - - JUNGLE_PRESSURE_PLATE - - LIGHT_WEIGHTED_PRESSURE_PLATE - - OAK_PRESSURE_PLATE - - SPRUCE_PRESSURE_PLATE - #redstone - - COMPARATOR - - NOTE_BLOCK - - PISTON - - PISTON_HEAD - - REDSTONE_BLOCK - - REDSTONE_WIRE - - REPEATER - - REDSTONE_TORCH - - REDSTONE_WALL_TORCH - - STICKY_PISTON - - TRIPWIRE_HOOK - #slabs - - ACACIA_SLAB - - BIRCH_SLAB - - BRICK_SLAB - - COBBLESTONE_SLAB - - DARK_OAK_SLAB - - DARK_PRISMARINE - - JUNGLE_SLAB - - NETHER_BRICK_SLAB - - OAK_SLAB - - PETRIFIED_OAK_SLAB - - PRISMARINE_SLAB - - PRISMARINE_BRICK_SLAB - - RED_SANDSTONE_SLAB - - QUARTZ_SLAB - - SPRUCE_SLAB - - STONE_SLAB - #stairs - - BIRCH_STAIRS - - JUNGLE_STAIRS - - OAK_STAIRS - - SMOOTH_STAIRS - - SPRUCE_STAIRS - #storage - - CHEST - - DISPENSER - - DROPPER - - HOPPER - - TRAPPED_CHEST - #trapdoors - - ACACIA_TRAPDOOR - - BIRCH_TRAPDOOR - - DARK_OAK_TRAPDOOR - - JUNGLE_TRAPDOOR - - OAK_TRAPDOOR - - SPRUCE_TRAPDOOR - #weapon blocks - - COAL_BLOCK - #wood - - ACACIA_WOOD - - BIRCH_WOOD - - DARK_OAK_WOOD - - OAK_WOOD - - SPRUCE_WOOD - - STRIPPED_ACACIA_WOOD - - STRIPPED_BIRCH_WOOD - - STRIPPED_DARK_OAK_WOOD - - STRIPPED_OAK_WOOD - - STRIPPED_SPRUCE_WOOD - #wool - - WHITE_WOOL - - ORANGE_WOOL - - MAGENTA_WOOL - - LIGHT_BLUE_WOOL - - YELLOW_WOOL - - LIME_WOOL - - PINK_WOOL - - GRAY_WOOL - - LIGHT_GRAY_WOOL - - CYAN_WOOL - - PURPLE_WOOL - - BLUE_WOOL - - BROWN_WOOL - - GREEN_WOOL - - RED_WOOL - - BLACK_WOOL - -forbiddenBlocks: - - PISTON_HEAD + - ALL_WOOD + - WATER + - LAVA + - ALL_LOG + - all_planks + - GLASS + - DISPENSER + - NOTE_BLOCK + - ALL_BED + - sticky_piston + - piston_head + - all_wool + - all_slab + - BOOKSHELF + - TORCH + - FIRE + - oak_stairs + - birch_stairs + - jungle_stairs + - spruce_stairs + - chest + - redstone_wire + - nether_brick_stairs + - furnace + - all_sign + - ladder + - all_door + - lever + - all_pressure_plate + - redstone_torch + - redstone_wall_torch + - all_button + - all_fence + - netherrack + - glowstone + - cake + - redstone_repeater + - all_stained_glass + - all_trapdoor + - all_stone_bricks + - iron_bars + - glass_pane + - all_fence_gate + - enchantment_table + - brewing_stand + - cauldron + - dragon_egg + - redstone_lamp + - ender chest + - TRIPWIRE_HOOK + - EMERALD_BLOCK + - BEACON + - FLOWER_POT + - SKULL + - all_ANVIL + - TRAPPED_CHEST + - REDSTONE_COMPARATOR + - daylight_detector + - REDSTONE_BLOCK + - HOPPER + - all_QUARTZ_BLOCK: + - all_rail + - DROPPER + - ALL_STAINED_GLASS_PANE + - SLIME_BLOCK + - ALL_CARPET + - COAL_BLOCK + - END_STONE_BRICKS canFly: true canCruise: false @@ -218,6 +85,6 @@ speed: 1.0 tryNudge: false sinkPercent: 99.0 flyblocks: - [WHITE_WOOL, ORANGE_WOOL, MAGENTA_WOOL,LIGHT_BLUE_WOOL,YELLOW_WOOL,LIME_WOOL,PINK_WOOL,GRAY_WOOL,LIGHT_GRAY_WOOL,CYAN_WOOL,PURPLE_WOOL,BLUE_WOOL,BROWN_WOOL, GREEN_WOOL, RED_WOOL, BLACK_WOOL]: #wool represents lift + all_wool: #wool represents lift - 0.0 - 100.0 \ No newline at end of file diff --git a/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java b/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java index 21c1b4f73..f6d0f7969 100644 --- a/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java +++ b/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java @@ -374,7 +374,7 @@ public CraftType(File f) { ArrayList objList = (ArrayList) data.get("harvestBlocks"); for (Object i : objList) { if (i instanceof String) { - Material mat = Material.getMaterial((String) i); + Material mat = Material.getMaterial(((String) i).toUpperCase()); harvestBlocks.add(mat); } else { Material mat = Material.getMaterial((Integer) i); @@ -387,7 +387,7 @@ public CraftType(File f) { ArrayList objList = (ArrayList) data.get("harvesterBladeBlocks"); for (Object i : objList) { if (i instanceof String) { - Material mat = Material.getMaterial((String) i); + Material mat = Material.getMaterial(((String) i).toUpperCase()); harvesterBladeBlocks.add(mat); } else { Integer typeID = (Integer) i; @@ -401,7 +401,7 @@ public CraftType(File f) { ArrayList objList = (ArrayList) data.get("passthroughBlocks"); for (Object i : objList) { if (i instanceof String) { - Material mat = Material.getMaterial((String) i); + Material mat = Material.getMaterial(((String) i).toUpperCase()); passthroughBlocks.add(mat); } else { Material mat = Material.getMaterial((Integer) i); @@ -558,6 +558,7 @@ private Map> materialMapFromObject(Object obj){ returnMap.put(type, new ArrayList<>()); } else if (o instanceof String){ String string = (String) o; + string = string.toUpperCase(); if (string.contains(":")){ String[] parts = string.split(":"); Material type; @@ -575,8 +576,18 @@ private Map> materialMapFromObject(Object obj){ returnMap.put(type, new ArrayList<>(data)); } } else { - Material type = Material.getMaterial(string); - returnMap.put(type,new ArrayList<>()); + if (string.toUpperCase().startsWith("ALL_")){ + string = string.replace("ALL_", ""); + for (Material m : Material.values()){ + if (!m.name().endsWith(string)){ + continue; + } + returnMap.put(m, new ArrayList<>()); + } + } else { + Material type = Material.getMaterial(string); + returnMap.put(type, new ArrayList<>()); + } } } else { Material type = (Material) o; @@ -645,6 +656,7 @@ private Map>, List> materialMapListFromObjec materialMap.put(type, new ArrayList<>()); } else if (o instanceof String) { String string = (String) o; + string = string.toUpperCase(); if (string.contains(":")) { String[] parts = string.split(":"); Material type; @@ -666,6 +678,14 @@ private Map>, List> materialMapListFromObjec materialMap.put(type, dataList); } + } else if (string.toUpperCase().startsWith("ALL_")){ + string = string.replace("ALL_", ""); + for (Material m : Material.values()){ + if (!m.name().endsWith(string)){ + continue; + } + materialMap.put(m, new ArrayList<>()); + } } else { Material type; if (string.contains("0") || string.contains("1") || string.contains("2") || string.contains("3") || string.contains("4") || string.contains("5") || string.contains("6") || string.contains("7") || string.contains("8") || string.contains("9")) { From 8bab58f366a0d0e6c742c5ea08388cb02a7e4fe6 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Mon, 19 Aug 2019 14:54:33 +0200 Subject: [PATCH 035/304] fixes --- .../net/countercraft/movecraft/Movecraft.java | 1 + .../async/detection/DetectionTask.java | 88 ------------------- .../movecraft/commands/SiegeCommand.java | 6 +- .../movecraft/sign/StatusSign.java | 73 ++++++++------- .../movecraft/warfare/siege/Siege.java | 13 ++- .../warfare/siege/SiegePreparationTask.java | 1 + .../warfare/siege/SiegeProgressTask.java | 2 +- 7 files changed, 53 insertions(+), 131 deletions(-) diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java index 8138bcbb7..fba1e5824 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java @@ -89,6 +89,7 @@ public void onDisable() { } @Override + @SuppressWarnings("unchecked") public void onEnable() { saveLocaleFiles(); String packageName = this.getServer().getClass().getPackage().getName(); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/detection/DetectionTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/detection/DetectionTask.java index f3837d0d3..ba4bd471c 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/detection/DetectionTask.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/detection/DetectionTask.java @@ -164,94 +164,6 @@ public void run() { if (isForbiddenBlock(testType, testData)) { fail(I18nSupport.getInternationalisedString("Detection - Forbidden block found")); } else if (isAllowedBlock(testType, testData)) { - // check for double chests - /*if (testType == Material.CHEST) { - boolean foundDoubleChest = false; - if (data.getWorld().getBlockAt(x - 1, y, z).getType() == Material.CHEST) { - if (Settings.IsLegacy) - foundDoubleChest = true; - else { - Chest chest = (Chest) data.getWorld().getBlockAt(x - 1, y, z).getBlockData(); - if (chest.getType() != Chest.Type.SINGLE) - foundDoubleChest = true; - } - } - if (data.getWorld().getBlockAt(x + 1, y, z).getType() == Material.CHEST) { - if (Settings.IsLegacy) - foundDoubleChest = true; - else { - Chest chest = (Chest) data.getWorld().getBlockAt(x + 1, y, z).getBlockData(); - if (chest.getType() != Chest.Type.SINGLE) - foundDoubleChest = true; - } - } - if (data.getWorld().getBlockAt(x, y, z - 1).getType() == Material.CHEST) { - if (Settings.IsLegacy) - foundDoubleChest = true; - else { - Chest chest = (Chest) data.getWorld().getBlockAt(x , y, z - 1).getBlockData(); - if (chest.getType() != Chest.Type.SINGLE) - foundDoubleChest = true; - } - } - if (data.getWorld().getBlockAt(x, y, z + 1).getType() == Material.CHEST) { - if (Settings.IsLegacy) - foundDoubleChest = true; - else { - Chest chest = (Chest) data.getWorld().getBlockAt(x , y, z + 1).getBlockData(); - if (chest.getType() != Chest.Type.SINGLE) - foundDoubleChest = true; - } - } - if (foundDoubleChest) { - fail(I18nSupport.getInternationalisedString( - "Detection - ERROR: Double chest found")); - } - } - // check for double trapped chests - if (testType == Material.TRAPPED_CHEST) { - boolean foundDoubleChest = false; - if (data.getWorld().getBlockAt(x - 1, y, z).getType() == Material.TRAPPED_CHEST) { - if (Settings.IsLegacy) - foundDoubleChest = true; - else { - Chest chest = (Chest) data.getWorld().getBlockAt(x - 1, y, z).getBlockData(); - if (chest.getType() != Chest.Type.SINGLE) - foundDoubleChest = true; - } - } - if (data.getWorld().getBlockAt(x + 1, y, z).getType() == Material.TRAPPED_CHEST) { - if (Settings.IsLegacy) - foundDoubleChest = true; - else { - Chest chest = (Chest) data.getWorld().getBlockAt(x + 1, y, z).getBlockData(); - if (chest.getType() != Chest.Type.SINGLE) - foundDoubleChest = true; - } - } - if (data.getWorld().getBlockAt(x, y, z - 1).getType() == Material.TRAPPED_CHEST) { - if (Settings.IsLegacy) - foundDoubleChest = true; - else { - Chest chest = (Chest) data.getWorld().getBlockAt(x, y, z - 1).getBlockData(); - if (chest.getType() != Chest.Type.SINGLE) - foundDoubleChest = true; - } - } - if (data.getWorld().getBlockAt(x, y, z + 1).getType() == Material.TRAPPED_CHEST) { - if (Settings.IsLegacy) - foundDoubleChest = true; - else { - Chest chest = (Chest) data.getWorld().getBlockAt(x, y, z + 1).getBlockData(); - if (chest.getType() != Chest.Type.SINGLE) - foundDoubleChest = true; - } - } - if (foundDoubleChest) { - fail(I18nSupport.getInternationalisedString( - "Detection - ERROR: Double chest found")); - } - }*/ Location loc = new Location(data.getWorld(), x, y, z); Player p; diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/SiegeCommand.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/SiegeCommand.java index 96853a9bd..620dcab42 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/SiegeCommand.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/SiegeCommand.java @@ -19,6 +19,9 @@ import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.Sound; +import org.bukkit.boss.BarColor; +import org.bukkit.boss.BarFlag; +import org.bukkit.boss.BarStyle; import org.bukkit.command.Command; import org.bukkit.command.CommandExecutor; import org.bukkit.command.CommandSender; @@ -188,7 +191,8 @@ private void startSiege(Siege siege, Player player, long cost) { } Movecraft.getInstance().getLogger().log(Level.INFO, String.format(I18nSupport.getInternationalisedString("Siege - Log Siege Start"), siege.getName(), player.getName(), cost)); Movecraft.getInstance().getEconomy().withdrawPlayer(player, cost); - + siege.setProgressBar(Bukkit.createBossBar(siege.getName(), BarColor.BLUE, BarStyle.SEGMENTED_20, BarFlag.DARKEN_SKY)); + siege.getProgressBar().setProgress(0.0); siege.setPlayerUUID(player.getUniqueId()); siege.setStartTime((int)System.currentTimeMillis()); siege.setStage(SiegeStage.PREPERATION); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/StatusSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/StatusSign.java index ea1ef4b56..3bc19c340 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/StatusSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/StatusSign.java @@ -15,6 +15,7 @@ import org.bukkit.inventory.InventoryHolder; import org.bukkit.inventory.ItemStack; +import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -78,42 +79,48 @@ public final void onSignTranslate(SignTranslateEvent event) { int signLine=1; int signColumn=0; for(Map> alFlyBlock : craft.getType().getFlyBlocks().keySet()) { - Material flyBlock = (Material) alFlyBlock.keySet().toArray()[0]; + ArrayList flyBlocks = new ArrayList<>(alFlyBlock.keySet()); Double minimum=craft.getType().getFlyBlocks().get(alFlyBlock).get(0); - if(foundBlocks.containsKey(flyBlock) && minimum>0) { // if it has a minimum, it should be considered for sinking consideration - int amount=foundBlocks.get(flyBlock); - Double percentPresent=(double) (amount*100/totalBlocks); + for (Material flyBlock : flyBlocks) { + if (foundBlocks.containsKey(flyBlock) && minimum > 0) { // if it has a minimum, it should be considered for sinking consideration + int amount = foundBlocks.get(flyBlock); + Double percentPresent = (double) (amount * 100 / totalBlocks); - String signText=""; - if(percentPresent>minimum*1.04) { - signText+= ChatColor.GREEN; - } else if(percentPresent>minimum*1.02) { - signText+=ChatColor.YELLOW; - } else { - signText+=ChatColor.RED; - } - if(flyBlock == Material.REDSTONE_BLOCK) { - signText+="R"; - } else if(flyBlock == Material.IRON_BLOCK) { - signText+="I"; - } else { - signText+= flyBlock.toString().charAt(0); - } + String signText = ""; + if (percentPresent > minimum * 1.04) { + signText += ChatColor.GREEN; + } else if (percentPresent > minimum * 1.02) { + signText += ChatColor.YELLOW; + } else { + signText += ChatColor.RED; + } + if (flyBlock == Material.REDSTONE_BLOCK) { + signText += "R"; + } else if (flyBlock == Material.IRON_BLOCK) { + signText += "I"; + } else if (flyBlock.name().endsWith("_WOOL")){ + signText += "W"; + } + else { + signText += flyBlock.toString().charAt(0); + } - signText+=" "; - signText+=percentPresent.intValue(); - signText+="/"; - signText+=minimum.intValue(); - signText+=" "; - if(signColumn==0) { - event.setLine(signLine,signText); - signColumn++; - } else if(signLine < 3) { - String existingLine=event.getLine(signLine); - existingLine+=signText; - event.setLine(signLine, existingLine); - signLine++; - signColumn=0; + signText += " "; + signText += percentPresent.intValue(); + signText += "/"; + signText += minimum.intValue(); + signText += " "; + if (signColumn == 0) { + event.setLine(signLine, signText); + signColumn++; + } else if (signLine < 3) { + String existingLine = event.getLine(signLine); + existingLine += signText; + event.setLine(signLine, existingLine); + signLine++; + signColumn = 0; + } + break; } } } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/siege/Siege.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/siege/Siege.java index 14cdb1dbc..aeddadf9e 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/siege/Siege.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/siege/Siege.java @@ -1,9 +1,5 @@ package net.countercraft.movecraft.warfare.siege; -import org.bukkit.Bukkit; -import org.bukkit.boss.BarColor; -import org.bukkit.boss.BarFlag; -import org.bukkit.boss.BarStyle; import org.bukkit.boss.BossBar; import org.jetbrains.annotations.NotNull; @@ -21,7 +17,7 @@ public class Siege { private long lastPayout; private final boolean doubleCostPerOwnedSiegeRegion; private UUID playerUUID; - private final BossBar progressBar; + private BossBar progressBar; public Siege( @NotNull String name, @NotNull String captureRegion, @NotNull String attackRegion, @@ -49,9 +45,6 @@ public Siege( lastUpdate = 0; stage = new AtomicReference<>(); stage.set(SiegeStage.INACTIVE); - progressBar = Bukkit.createBossBar(name, BarColor.BLUE, BarStyle.SEGMENTED_20, BarFlag.DARKEN_SKY); - progressBar.setProgress(0.0); - progressBar.setVisible(false); } @NotNull @@ -168,4 +161,8 @@ public String toString() { public BossBar getProgressBar() { return progressBar; } + + public void setProgressBar(BossBar progressBar) { + this.progressBar = progressBar; + } } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/siege/SiegePreparationTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/siege/SiegePreparationTask.java index f3167e9cd..7035c06cc 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/siege/SiegePreparationTask.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/siege/SiegePreparationTask.java @@ -15,6 +15,7 @@ public SiegePreparationTask(Siege siege) { @Override public void run() { + siege.getProgressBar().setVisible(true); int timePassed = ((int)(System.currentTimeMillis() - siege.getStartTime())); //time passed in milliseconds int timePassedInSeconds = timePassed / 1000; double progress = (double) timePassedInSeconds / (double) siege.getDelayBeforeStart(); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/siege/SiegeProgressTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/siege/SiegeProgressTask.java index a02237021..ec689aa1f 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/siege/SiegeProgressTask.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/siege/SiegeProgressTask.java @@ -27,7 +27,7 @@ public SiegeProgressTask(Siege siege) { //every 20 ticks = 1 second public void run() { int timeLeft = siege.getDuration() - (((int) System.currentTimeMillis() - siege.getStartTime()) / 1000); - double progress = (double) (timeLeft - siege.getDelayBeforeStart()) / (double) (siege.getDuration() - siege.getDelayBeforeStart()); + double progress = (double) (siege.getDelayBeforeStart() - timeLeft) / (double) (siege.getDuration() - siege.getDelayBeforeStart()); siege.getProgressBar().setProgress(Math.min(progress, 1.0));Player siegeLeader = Movecraft.getInstance().getServer().getPlayer(siege.getPlayerUUID()); Craft siegeCraft = CraftManager.getInstance().getCraftByPlayer(siegeLeader); BarColor bColor = leaderPilotingShip(siegeCraft) && leaderShipInRegion(siegeCraft, siegeLeader) ? BarColor.GREEN : BarColor.RED; From 200152b5a49f0b65d48ceea804a634172e26eac5 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Tue, 20 Aug 2019 20:35:46 +0200 Subject: [PATCH 036/304] Fixed default airship crafttype --- .../movecraft/sign/StatusSign.java | 2 +- .../main/resources/types/1_14/airship.craft | 336 +++++------------- .../src/main/resources/types/BigAirship.craft | 165 +++++---- 3 files changed, 164 insertions(+), 339 deletions(-) diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/StatusSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/StatusSign.java index 3bc19c340..ffd716533 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/StatusSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/StatusSign.java @@ -98,7 +98,7 @@ public final void onSignTranslate(SignTranslateEvent event) { signText += "R"; } else if (flyBlock == Material.IRON_BLOCK) { signText += "I"; - } else if (flyBlock.name().endsWith("_WOOL")){ + } else if (flyBlock.name().endsWith("WOOL")){ signText += "W"; } else { diff --git a/modules/Movecraft/src/main/resources/types/1_14/airship.craft b/modules/Movecraft/src/main/resources/types/1_14/airship.craft index cc67fada7..c58da4450 100644 --- a/modules/Movecraft/src/main/resources/types/1_14/airship.craft +++ b/modules/Movecraft/src/main/resources/types/1_14/airship.craft @@ -2,259 +2,87 @@ name: Airship maxSize: 5000 minSize: 1000 allowedBlocks: - #beds - - WHITE_BED - - ORANGE_BED - - MAGENTA_BED - - LIGHT_BLUE_BED - - YELLOW_BED - - LIME_BED - - PINK_BED - - GRAY_BED - - LIGHT_BED - - CYAN_BED - - PURPLE_BED - - BLUE_BED - - BROWN_BED - - GREEN_BED - - RED_BED - - BLACK_BED - #buttons - - ACACIA_BUTTON - - BIRCH_BUTTON - - DARK_OAK_BUTTON - - JUNGLE_BUTTON - - OAK_BUTTON - - SPRUCE_BUTTON - - STONE_BUTTON - #carpets - - WHITE_CARPET - - ORANGE_CARPET - - MAGENTA_CARPET - - LIGHT_BLUE_CARPET - - YELLOW_CARPET - - LIME_CARPET - - PINK_CARPET - - GRAY_CARPET - - LIGHT_CARPET - - CYAN_CARPET - - PURPLE_CARPET - - BLUE_CARPET - - BROWN_CARPET - - GREEN_CARPET - - RED_CARPET - - BLACK_CARPET - #doors - - ACACIA_DOOR - - BIRCH_DOOR - - DARK_OAK_DOOR - - IRON_DOOR - - JUNGLE_DOOR - - OAK_DOOR - - SPRUCE_DOOR - #fences - - ACACIA_FENCE - - BIRCH_FENCE - - DARK_OAK_FENCE - - JUNGLE_FENCE - - OAK_FENCE - - NETHER_BRICK_FENCE - - SPRUCE_FENCE - #fence gates - - ACACIA_FENCE_GATE - - BIRCH_FENCE_GATE - - DARK_OAK_FENCE_GATE - - JUNGLE_FENCE_GATE - - OAK_FENCE_GATE - - SPRUCE_FENCE_GATE - #glass - - GLASS - - WHITE_STAINED_GLASS - - ORANGE_STAINED_GLASS - - MAGENTA_STAINED_GLASS - - LIGHT_BLUE_STAINED_GLASS - - YELLOW_STAINED_GLASS - - LIME_STAINED_GLASS - - PINK_STAINED_GLASS - - GRAY_STAINED_GLASS - - LIGHT_GRAY_STAINED_GLASS - - CYAN_STAINED_GLASS - - PURPLE_STAINED_GLASS - - BLUE_STAINED_GLASS - - BROWN_STAINED_GLASS - - GREEN_STAINED_GLASS - - RED_STAINED_GLASS - - BLACK_STAINED_GLASS - #glass pane - - GLASS_PANE - - WHITE_STAINED_GLASS_PANE - - ORANGE_STAINED_GLASS_PANE - - MAGENTA_STAINED_GLASS_PANE - - LIGHT_BLUE_STAINED_GLASS_PANE - - YELLOW_STAINED_GLASS_PANE - - LIME_STAINED_GLASS_PANE - - PINK_STAINED_GLASS_PANE - - GRAY_STAINED_GLASS_PANE - - LIGHT_GRAY_STAINED_GLASS_PANE - - CYAN_STAINED_GLASS_PANE - - PURPLE_STAINED_GLASS_PANE - - BLUE_STAINED_GLASS_PANE - - BROWN_STAINED_GLASS_PANE - - GREEN_STAINED_GLASS_PANE - - RED_STAINED_GLASS_PANE - - BLACK_STAINED_GLASS_PANE - #liquids - - LAVA - - WATER - #logs - - BIRCH_LOG - - JUNGLE_LOG - - OAK_LOG - - SPRUCE_LOG - - STRIPPED_BIRCH_LOG - - STRIPPED_JUNGLE_LOG - - STRIPPED_OAK_LOG - - STRIPPED_SPRUCE_LOG - #misc - - BOOKSHELF - - BREWING_STAND - - CRAFTING_TABLE - - CAULDRON - - FURNACE - - GLOWSTONE - - IRON_BARS - - LADDER - - NETHER_BRICKS - - TORCH - - WALL_TORCH - #planks - - ACACIA_PLANKS - - BIRCH_PLANKS - - DARK_OAK_PLANKS - - JUNGLE_PLANKS - - OAK_PLANKS - - SPRUCE_PLANKS - #pressure plates - - ACACIA_PRESSURE_PLATE - - BIRCH_PRESSURE_PLATE - - DARK_OAK_PRESSURE_PLATE - - HEAVY_WEIGHTED_PRESSURE_PLATE - - JUNGLE_PRESSURE_PLATE - - LIGHT_WEIGHTED_PRESSURE_PLATE - - OAK_PRESSURE_PLATE - - SPRUCE_PRESSURE_PLATE - - STONE_PRESSURE_PLATE - #redstone - - COMPARATOR - - LEVER - - NOTE_BLOCK - - PISTON - - PISTON_HEAD - - REDSTONE_BLOCK - - REDSTONE_WIRE - - REPEATER - - REDSTONE_TORCH - - REDSTONE_WALL_TORCH - - STICKY_PISTON - - TRIPWIRE_HOOK - #signs - - ACACIA_SIGN - - ACACIA_WALL_SIGN - - BIRCH_SIGN - - BIRCH_WALL_SIGN - - DARK_OAK_SIGN - - DARK_OAK_WALL_SIGN - - JUNGLE_SIGN - - JUNGLE_WALL_SIGN - - OAK_SIGN - - OAK_WALL_SIGN - - SPRUCE_SIGN - - SPRUCE_WALL_SIGN - #slabs - - ACACIA_SLAB - - BIRCH_SLAB - - BRICK_SLAB - - COBBLESTONE_SLAB - - DARK_OAK_SLAB - - DARK_PRISMARINE - - JUNGLE_SLAB - - NETHER_BRICK_SLAB - - OAK_SLAB - - PETRIFIED_OAK_SLAB - - PRISMARINE_SLAB - - PRISMARINE_BRICK_SLAB - - RED_SANDSTONE_SLAB - - QUARTZ_SLAB - - SPRUCE_SLAB - - STONE_SLAB - #stairs - - BIRCH_STAIRS - - JUNGLE_STAIRS - - OAK_STAIRS - - NETHER_BRICK_STAIRS - - SMOOTH_STAIRS - - SPRUCE_STAIRS - - STONE_BRICK_STAIRS - #storage - - CHEST - - DISPENSER - - DROPPER - - HOPPER - - TRAPPED_CHEST - #terracotta - - WHITE_TERRACOTTA - - ORANGE_TERRACOTTA - - MAGENTA_TERRACOTTA - - LIGHT_BLUE_TERRACOTTA - - YELLOW_TERRACOTTA - - LIME_TERRACOTTA - - PINK_TERRACOTTA - - GRAY_TERRACOTTA - - LIGHT_GRAY_TERRACOTTA - - CYAN_TERRACOTTA - - PURPLE_TERRACOTTA - - BLUE_TERRACOTTA - - BROWN_TERRACOTTA - - GREEN_TERRACOTTA - - RED_TERRACOTTA - - BLACK_TERRACOTTA - #trapdoors - - ACACIA_TRAPDOOR - - BIRCH_TRAPDOOR - - DARK_OAK_TRAPDOOR - - JUNGLE_TRAPDOOR - - OAK_TRAPDOOR - - SPRUCE_TRAPDOOR - #weapon blocks - - COAL_BLOCK - #wood - - ACACIA_WOOD - - BIRCH_WOOD - - DARK_OAK_WOOD - - OAK_WOOD - - SPRUCE_WOOD - - STRIPPED_ACACIA_WOOD - - STRIPPED_BIRCH_WOOD - - STRIPPED_DARK_OAK_WOOD - - STRIPPED_OAK_WOOD - - STRIPPED_SPRUCE_WOOD - #wool - - WHITE_WOOL - - ORANGE_WOOL - - MAGENTA_WOOL - - LIGHT_BLUE_WOOL - - YELLOW_WOOL - - LIME_WOOL - - PINK_WOOL - - GRAY_WOOL - - LIGHT_GRAY_WOOL - - CYAN_WOOL - - PURPLE_WOOL - - BLUE_WOOL - - BROWN_WOOL - - GREEN_WOOL - - RED_WOOL - - BLACK_WOOL + - ALL_WOOD + - WATER + - LAVA + - ALL_LOG + - all_planks + - GLASS + - LAPIS_BLOCK + - DISPENSER + - NOTE_BLOCK + - ALL_BED + - sticky_piston + - piston_head + - all_wool + - GOLD_BLOCK + - IRON_BLOCK + - all_slab + - BOOKSHELF + - TORCH + - FIRE + - oak_stairs + - birch_stairs + - jungle_stairs + - spruce_stairs + - stone_brick_stairs + - quartz_stairs + - nether_brick_stairs + - chest + - redstone_wire + - diamond_block + - nether_brick_stairs + - furnace + - all_sign + - ladder + - all_door + - lever + - all_pressure_plate + - redstone_torch + - redstone_wall_torch + - all_button + - clay + - all_fence + - netherrack + - glowstone + - cake + - redstone_repeater + - all_stained_glass + - all_trapdoor + - all_stone_bricks + - iron_bars + - glass_pane + - all_fence_gate + - nether_brick + - enchantment_table + - brewing_stand + - cauldron + - end_stone + - dragon_egg + - redstone_lamp + - ender chest + - TRIPWIRE_HOOK + - EMERALD_BLOCK + - BEACON + - cobblestone_wall + - mossy_cobblestone_wall + - FLOWER_POT + - SKULL + - all_ANVIL + - TRAPPED_CHEST + - REDSTONE_COMPARATOR + - daylight_detector + - REDSTONE_BLOCK + - HOPPER + - all_QUARTZ_BLOCK + - all_rail + - DROPPER + - ALL_TERRACOTTA + - ALL_STAINED_GLASS_PANE + - SLIME_BLOCK + - ALL_CARPET + - COAL_BLOCK + - END_STONE_BRICKS canCruise: true rotateAtMidpoint: true @@ -275,7 +103,7 @@ tryNudge: false canStaticMove: true maxStaticMove: 2 moveblocks: - 152: # redstone represents engines + redstone_block: # redstone represents engines - 1.0 - 100.0 flyblocks: diff --git a/modules/Movecraft/src/main/resources/types/BigAirship.craft b/modules/Movecraft/src/main/resources/types/BigAirship.craft index 217639a78..a10c2e04a 100644 --- a/modules/Movecraft/src/main/resources/types/BigAirship.craft +++ b/modules/Movecraft/src/main/resources/types/BigAirship.craft @@ -2,90 +2,87 @@ name: BigAirship maxSize: 20000 minSize: 10000 allowedBlocks: - - ALL_WOOD - - WATER - - LAVA - - ALL_LOG - - all_planks - - GLASS - - LAPIS_BLOCK - - DISPENSER - - NOTE_BLOCK - - ALL_BED - - sticky_piston - - piston_head - - all_wool - - GOLD_BLOCK - - IRON_BLOCK - - all_slab - - BOOKSHELF - - TORCH - - FIRE - - oak_stairs - - birch_stairs - - jungle_stairs - - spruce_stairs - - stone_brick_stairs - - quartz_stairs - - nether_brick_stairs - - chest - - redstone_wire - - diamond_block - - nether_brick_stairs - - furnace - - all_sign - - ladder - - all_door - - lever - - all_pressure_plate - - redstone_torch - - redstone_wall_torch - - all_button - - clay - - all_fence - - netherrack - - glowstone - - cake - - redstone_repeater - - all_stained_glass - - all_trapdoor - - all_stone_bricks - - iron_bars - - glass_pane - - all_fence_gate - - nether_brick - - enchantment_table - - brewing_stand - - cauldron - - end_stone - - dragon_egg - - redstone_lamp - - ender chest - - TRIPWIRE_HOOK - - EMERALD_BLOCK - - BEACON - - cobblestone_wall - - mossy_cobblestone_wall - - FLOWER_POT - - SKULL - - all_ANVIL - - TRAPPED_CHEST - - REDSTONE_COMPARATOR - - daylight_detector - - REDSTONE_BLOCK - - HOPPER - - all_QUARTZ_BLOCK - - all_rail - - DROPPER - - ALL_TERRACOTTA - - ALL_STAINED_GLASS_PANE - - SLIME_BLOCK - - ALL_CARPET - - COAL_BLOCK - - END_STONE_BRICKS - - - + - ALL_WOOD + - WATER + - LAVA + - ALL_LOG + - all_planks + - GLASS + - LAPIS_BLOCK + - DISPENSER + - NOTE_BLOCK + - ALL_BED + - sticky_piston + - piston_head + - all_wool + - GOLD_BLOCK + - IRON_BLOCK + - all_slab + - BOOKSHELF + - TORCH + - FIRE + - oak_stairs + - birch_stairs + - jungle_stairs + - spruce_stairs + - stone_brick_stairs + - quartz_stairs + - nether_brick_stairs + - chest + - redstone_wire + - diamond_block + - nether_brick_stairs + - furnace + - all_sign + - ladder + - all_door + - lever + - all_pressure_plate + - redstone_torch + - redstone_wall_torch + - all_button + - clay + - all_fence + - netherrack + - glowstone + - cake + - redstone_repeater + - all_stained_glass + - all_trapdoor + - all_stone_bricks + - iron_bars + - glass_pane + - all_fence_gate + - nether_brick + - enchantment_table + - brewing_stand + - cauldron + - end_stone + - dragon_egg + - redstone_lamp + - ender chest + - TRIPWIRE_HOOK + - EMERALD_BLOCK + - BEACON + - cobblestone_wall + - mossy_cobblestone_wall + - FLOWER_POT + - SKULL + - all_ANVIL + - TRAPPED_CHEST + - REDSTONE_COMPARATOR + - daylight_detector + - REDSTONE_BLOCK + - HOPPER + - all_QUARTZ_BLOCK + - all_rail + - DROPPER + - ALL_TERRACOTTA + - ALL_STAINED_GLASS_PANE + - SLIME_BLOCK + - ALL_CARPET + - COAL_BLOCK + - END_STONE_BRICKS canCruise: true rotateAtMidpoint: true blockRemoteRotate: true From 773d77082f0c04b7528579e3a9454e236de10b94 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Wed, 21 Aug 2019 20:47:03 +0200 Subject: [PATCH 037/304] Various bug fixes --- .../net/countercraft/movecraft/Movecraft.java | 37 ++ .../movecraft/async/AsyncManager.java | 8 +- .../movecraft/sign/StatusSign.java | 101 +++--- .../Movecraft/src/main/resources/config.yml | 6 +- .../resources/types/1_14/SubAirship.craft | 336 +++++------------- .../main/resources/types/1_14/airship.craft | 7 +- .../src/main/resources/types/BigAirship.craft | 7 +- .../main/resources/types/BigSubAirship.craft | 164 ++++----- .../src/main/resources/types/Ship.craft | 164 ++++----- .../src/main/resources/types/SubAirship.craft | 166 ++++----- .../src/main/resources/types/Submarine.craft | 164 ++++----- .../src/main/resources/types/airskiff.craft | 4 +- .../src/main/resources/types/elevator.craft | 5 +- .../movecraft/config/Settings.java | 8 +- .../movecraft/craft/CraftType.java | 1 + 15 files changed, 525 insertions(+), 653 deletions(-) diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java index fba1e5824..28af60401 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java @@ -36,6 +36,7 @@ import net.countercraft.movecraft.mapUpdater.MapUpdateManager; import net.countercraft.movecraft.repair.RepairManager; import net.countercraft.movecraft.sign.*; +import net.countercraft.movecraft.utils.LegacyUtils; import net.countercraft.movecraft.utils.TownyUtils; import net.countercraft.movecraft.utils.WGCustomFlagsUtils; import net.countercraft.movecraft.warfare.assault.AssaultManager; @@ -143,6 +144,42 @@ public void onEnable() { } this.getLogger().info(I18nSupport.getInternationalisedString("Startup - Loading Support") + " " + version); + Map tempStatusSignMarkers = getConfig().getConfigurationSection("StatusSignMarkers").getValues(false); + for (String s : tempStatusSignMarkers.keySet()){ + List materialList = new ArrayList<>(); + if (s.contains(",")){ + String[] split = s.split(","); + for (String str : split){ + materialList.add(Material.getMaterial(str.toUpperCase())); + } + } else if (s.toUpperCase().startsWith("ALL_")){ + String str = s.toUpperCase().replace("ALL_", ""); + for (Material type : Material.values()){ + if (type.name().endsWith(str)){ + materialList.add(type); + } + } + } else if (s.contains("0") || s.contains("1") || s.contains("2") || s.contains("3") || s.contains("4") || s.contains("5") || s.contains("6") || s.contains("7") || s.contains("8") || s.contains("9")) { + Material type; + try { + type = LegacyUtils.getMaterial(Integer.parseInt(s)); + } catch (Throwable t){ + throw new IllegalArgumentException("Startup - Numerical IDs not supported", t); + } + if (type != null){ + materialList.add(type); + } + } else { + materialList.add(Material.getMaterial(s.toUpperCase())); + } + Object obj = tempStatusSignMarkers.get(s); + if (!(obj instanceof String)){ + throw new IllegalArgumentException(String.format(I18nSupport.getInternationalisedString("Startup - Status sign marker must be string"), obj)); + } + Collections.sort(materialList); + String marker = (String) obj; + Settings.StatusSignMarkers.put(materialList, marker); + } Settings.SinkCheckTicks = getConfig().getDouble("SinkCheckTicks", 100.0); Settings.TracerRateTicks = getConfig().getDouble("TracerRateTicks", 5.0); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java index 39ad6dd30..faed063eb 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java @@ -24,6 +24,10 @@ import com.sk89q.worldguard.WorldGuard; import com.sk89q.worldguard.bukkit.WorldGuardPlugin; import com.sk89q.worldguard.protection.ApplicableRegionSet; +import com.sk89q.worldguard.protection.flags.DefaultFlag; +import com.sk89q.worldguard.protection.flags.Flag; +import com.sk89q.worldguard.protection.flags.Flags; +import com.sk89q.worldguard.protection.flags.StateFlag; import com.sk89q.worldguard.protection.managers.RegionManager; import com.sk89q.worldguard.protection.regions.ProtectedRegion; import com.sk89q.worldguard.protection.regions.RegionContainer; @@ -552,6 +556,7 @@ private void detectSinking(){ double movePercent = pcraft.getType().getMoveBlocks().get(i).get(0); double disablePercent = movePercent * pcraft.getType().getSinkPercent() / 100.0; if (percent < disablePercent && !pcraft.getDisabled() && pcraft.isNotProcessing()) { + Bukkit.broadcastMessage(String.valueOf(percent)); pcraft.setDisabled(true); if (pcraft.getNotificationPlayer() != null) { Location loc = pcraft.getNotificationPlayer().getLocation(); @@ -610,7 +615,8 @@ private void detectSinking(){ break; } } - if (region != null && Settings.WorldGuardBlockSinkOnPVPPerm){ + Flag pvpFlag = Settings.IsLegacy ? DefaultFlag.PVP : Flags.PVP; + if (region != null && Settings.WorldGuardBlockSinkOnPVPPerm && region.getFlag(pvpFlag).equals(StateFlag.State.DENY)){ notifyP.sendMessage(I18nSupport.getInternationalisedString("Player- Craft should sink but PVP is not allowed in this WorldGuard region")); isSinking = false; } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/StatusSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/StatusSign.java index ffd716533..df6d0fee3 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/StatusSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/StatusSign.java @@ -5,6 +5,7 @@ import net.countercraft.movecraft.craft.Craft; import net.countercraft.movecraft.events.CraftDetectEvent; import net.countercraft.movecraft.events.SignTranslateEvent; +import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.Material; import org.bukkit.World; @@ -15,10 +16,7 @@ import org.bukkit.inventory.InventoryHolder; import org.bukkit.inventory.ItemStack; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; public final class StatusSign implements Listener{ @@ -45,8 +43,8 @@ public final void onSignTranslate(SignTranslateEvent event) { if (!ChatColor.stripColor(event.getLine(0)).equalsIgnoreCase("Status:")) { return; } - int fuel=0; - int totalBlocks=0; + int fuel = 0; + int totalBlocks = 0; Map foundBlocks = new HashMap<>(); for (MovecraftLocation ml : craft.getHitBox()) { Material blockType = craft.getW().getBlockAt(ml.getX(), ml.getY(), ml.getZ()).getType(); @@ -59,12 +57,12 @@ public final void onSignTranslate(SignTranslateEvent event) { if (blockType == Material.FURNACE) { InventoryHolder inventoryHolder = (InventoryHolder) craft.getW().getBlockAt(ml.getX(), ml.getY(), ml.getZ()).getState(); - for (Material fuelType : Settings.FuelTypes.keySet()){ - if (!inventoryHolder.getInventory().contains(fuelType)){ + for (Material fuelType : Settings.FuelTypes.keySet()) { + if (!inventoryHolder.getInventory().contains(fuelType)) { continue; } ItemStack[] content = inventoryHolder.getInventory().getContents(); - for (ItemStack item : content){ + for (ItemStack item : content) { if (item == null) continue; fuel += item.getAmount() * Settings.FuelTypes.get(fuelType); @@ -76,53 +74,54 @@ public final void onSignTranslate(SignTranslateEvent event) { totalBlocks++; } } - int signLine=1; - int signColumn=0; - for(Map> alFlyBlock : craft.getType().getFlyBlocks().keySet()) { + int signLine = 1; + int signColumn = 0; + for (Map> alFlyBlock : craft.getType().getFlyBlocks().keySet()) { ArrayList flyBlocks = new ArrayList<>(alFlyBlock.keySet()); - Double minimum=craft.getType().getFlyBlocks().get(alFlyBlock).get(0); + Collections.sort(flyBlocks); + Double minimum = craft.getType().getFlyBlocks().get(alFlyBlock).get(0); + int amount = 0; + boolean addToStatus = false; for (Material flyBlock : flyBlocks) { if (foundBlocks.containsKey(flyBlock) && minimum > 0) { // if it has a minimum, it should be considered for sinking consideration - int amount = foundBlocks.get(flyBlock); - Double percentPresent = (double) (amount * 100 / totalBlocks); - - String signText = ""; - if (percentPresent > minimum * 1.04) { - signText += ChatColor.GREEN; - } else if (percentPresent > minimum * 1.02) { - signText += ChatColor.YELLOW; - } else { - signText += ChatColor.RED; - } - if (flyBlock == Material.REDSTONE_BLOCK) { - signText += "R"; - } else if (flyBlock == Material.IRON_BLOCK) { - signText += "I"; - } else if (flyBlock.name().endsWith("WOOL")){ - signText += "W"; - } - else { - signText += flyBlock.toString().charAt(0); - } - - signText += " "; - signText += percentPresent.intValue(); - signText += "/"; - signText += minimum.intValue(); - signText += " "; - if (signColumn == 0) { - event.setLine(signLine, signText); - signColumn++; - } else if (signLine < 3) { - String existingLine = event.getLine(signLine); - existingLine += signText; - event.setLine(signLine, existingLine); - signLine++; - signColumn = 0; - } - break; + amount += foundBlocks.get(flyBlock); + addToStatus = true; } } + Material flyBlock = flyBlocks.get(0); + if (addToStatus) { + Double percentPresent = (double) (amount * 100 / totalBlocks); + Bukkit.broadcastMessage("test"); + String signText = ""; + if (percentPresent > minimum * 1.04) { + signText += ChatColor.GREEN; + } else if (percentPresent > minimum * 1.02) { + signText += ChatColor.YELLOW; + } else { + signText += ChatColor.RED; + } + Bukkit.broadcastMessage(Settings.StatusSignMarkers.get(flyBlocks)); + signText += Settings.StatusSignMarkers.get(flyBlocks); + signText += " "; + signText += percentPresent.intValue(); + signText += "/"; + signText += minimum.intValue(); + signText += " "; + Bukkit.broadcastMessage(signLine + " " + signColumn + signText); + if (signColumn == 0) { + event.setLine(signLine, signText); + signColumn++; + } else if (signLine < 3) { + String existingLine = event.getLine(signLine); + existingLine += signText; + event.setLine(signLine, existingLine); + signLine++; + signColumn = 0; + } + } + } + if (signLine < 3 && signColumn == 0){ + signLine++; } String fuelText=""; int fuelRange=(int) ((fuel*(1+craft.getType().getCruiseSkipBlocks()))/craft.getType().getFuelBurnRate()); diff --git a/modules/Movecraft/src/main/resources/config.yml b/modules/Movecraft/src/main/resources/config.yml index 2d3e218d0..5c942c95f 100644 --- a/modules/Movecraft/src/main/resources/config.yml +++ b/modules/Movecraft/src/main/resources/config.yml @@ -119,4 +119,8 @@ ForbiddenRemoteSigns: # These strings will be ignored when searching for signs t - "Mounted" - "Denied" - "[private]" -RequireNamePerm: true # Require movecraft.name.place to place Name: signs and movecraft.name.use to use Name: signs \ No newline at end of file +RequireNamePerm: true # Require movecraft.name.place to place Name: signs and movecraft.name.use to use Name: signs +StatusSignMarkers: + all_wood: Wd + all_wool: Wl + iron_block: I \ No newline at end of file diff --git a/modules/Movecraft/src/main/resources/types/1_14/SubAirship.craft b/modules/Movecraft/src/main/resources/types/1_14/SubAirship.craft index 8fce88adf..702587eae 100644 --- a/modules/Movecraft/src/main/resources/types/1_14/SubAirship.craft +++ b/modules/Movecraft/src/main/resources/types/1_14/SubAirship.craft @@ -2,260 +2,88 @@ name: SubAirship maxSize: 5000 minSize: 1000 allowedBlocks: -#beds - - WHITE_BED - - ORANGE_BED - - MAGENTA_BED - - LIGHT_BLUE_BED - - YELLOW_BED - - LIME_BED - - PINK_BED - - GRAY_BED - - LIGHT_BED - - CYAN_BED - - PURPLE_BED - - BLUE_BED - - BROWN_BED - - GREEN_BED - - RED_BED - - BLACK_BED - #buttons - - ACACIA_BUTTON - - BIRCH_BUTTON - - DARK_OAK_BUTTON - - JUNGLE_BUTTON - - OAK_BUTTON - - SPRUCE_BUTTON - - STONE_BUTTON - #carpets - - WHITE_CARPET - - ORANGE_CARPET - - MAGENTA_CARPET - - LIGHT_BLUE_CARPET - - YELLOW_CARPET - - LIME_CARPET - - PINK_CARPET - - GRAY_CARPET - - LIGHT_CARPET - - CYAN_CARPET - - PURPLE_CARPET - - BLUE_CARPET - - BROWN_CARPET - - GREEN_CARPET - - RED_CARPET - - BLACK_CARPET - #doors - - ACACIA_DOOR - - BIRCH_DOOR - - DARK_OAK_DOOR - - IRON_DOOR - - JUNGLE_DOOR - - OAK_DOOR - - SPRUCE_DOOR - #fences - - ACACIA_FENCE - - BIRCH_FENCE - - DARK_OAK_FENCE - - JUNGLE_FENCE - - OAK_FENCE - - NETHER_BRICK_FENCE - - SPRUCE_FENCE - #fence gates - - ACACIA_FENCE_GATE - - BIRCH_FENCE_GATE - - DARK_OAK_FENCE_GATE - - JUNGLE_FENCE_GATE - - OAK_FENCE_GATE - - SPRUCE_FENCE_GATE - #glass - - GLASS - - WHITE_STAINED_GLASS - - ORANGE_STAINED_GLASS - - MAGENTA_STAINED_GLASS - - LIGHT_BLUE_STAINED_GLASS - - YELLOW_STAINED_GLASS - - LIME_STAINED_GLASS - - PINK_STAINED_GLASS - - GRAY_STAINED_GLASS - - LIGHT_GRAY_STAINED_GLASS - - CYAN_STAINED_GLASS - - PURPLE_STAINED_GLASS - - BLUE_STAINED_GLASS - - BROWN_STAINED_GLASS - - GREEN_STAINED_GLASS - - RED_STAINED_GLASS - - BLACK_STAINED_GLASS - #glass pane - - GLASS_PANE - - WHITE_STAINED_GLASS_PANE - - ORANGE_STAINED_GLASS_PANE - - MAGENTA_STAINED_GLASS_PANE - - LIGHT_BLUE_STAINED_GLASS_PANE - - YELLOW_STAINED_GLASS_PANE - - LIME_STAINED_GLASS_PANE - - PINK_STAINED_GLASS_PANE - - GRAY_STAINED_GLASS_PANE - - LIGHT_GRAY_STAINED_GLASS_PANE - - CYAN_STAINED_GLASS_PANE - - PURPLE_STAINED_GLASS_PANE - - BLUE_STAINED_GLASS_PANE - - BROWN_STAINED_GLASS_PANE - - GREEN_STAINED_GLASS_PANE - - RED_STAINED_GLASS_PANE - - BLACK_STAINED_GLASS_PANE - #liquids - - LAVA - - WATER - #logs - - BIRCH_LOG - - JUNGLE_LOG - - OAK_LOG - - SPRUCE_LOG - - STRIPPED_BIRCH_LOG - - STRIPPED_JUNGLE_LOG - - STRIPPED_OAK_LOG - - STRIPPED_SPRUCE_LOG - #misc - - BOOKSHELF - - BREWING_STAND - - CRAFTING_TABLE - - CAULDRON - - FURNACE - - GLOWSTONE - - IRON_BARS - - LADDER - - NETHER_BRICKS - - TORCH - - WALL_TORCH - #planks - - ACACIA_PLANKS - - BIRCH_PLANKS - - DARK_OAK_PLANKS - - JUNGLE_PLANKS - - OAK_PLANKS - - SPRUCE_PLANKS - #pressure plates - - ACACIA_PRESSURE_PLATE - - BIRCH_PRESSURE_PLATE - - DARK_OAK_PRESSURE_PLATE - - HEAVY_WEIGHTED_PRESSURE_PLATE - - JUNGLE_PRESSURE_PLATE - - LIGHT_WEIGHTED_PRESSURE_PLATE - - OAK_PRESSURE_PLATE - - SPRUCE_PRESSURE_PLATE - - STONE_PRESSURE_PLATE - #redstone - - COMPARATOR - - LEVER - - NOTE_BLOCK - - PISTON - - PISTON_HEAD - - REDSTONE_BLOCK - - REDSTONE_WIRE - - REPEATER - - REDSTONE_TORCH - - REDSTONE_WALL_TORCH - - STICKY_PISTON - - TRIPWIRE_HOOK - #signs - - ACACIA_SIGN - - ACACIA_WALL_SIGN - - BIRCH_SIGN - - BIRCH_WALL_SIGN - - DARK_OAK_SIGN - - DARK_OAK_WALL_SIGN - - JUNGLE_SIGN - - JUNGLE_WALL_SIGN - - OAK_SIGN - - OAK_WALL_SIGN - - SPRUCE_SIGN - - SPRUCE_WALL_SIGN - #slabs - - ACACIA_SLAB - - BIRCH_SLAB - - BRICK_SLAB - - COBBLESTONE_SLAB - - DARK_OAK_SLAB - - DARK_PRISMARINE - - JUNGLE_SLAB - - NETHER_BRICK_SLAB - - OAK_SLAB - - PETRIFIED_OAK_SLAB - - PRISMARINE_SLAB - - PRISMARINE_BRICK_SLAB - - RED_SANDSTONE_SLAB - - QUARTZ_SLAB - - SPRUCE_SLAB - - STONE_SLAB - #stairs - - BIRCH_STAIRS - - JUNGLE_STAIRS - - OAK_STAIRS - - NETHER_BRICK_STAIRS - - SMOOTH_STAIRS - - SPRUCE_STAIRS - - STONE_BRICK_STAIRS - #storage - - CHEST - - DISPENSER - - DROPPER - - HOPPER - - TRAPPED_CHEST - #terracotta - - WHITE_TERRACOTTA - - ORANGE_TERRACOTTA - - MAGENTA_TERRACOTTA - - LIGHT_BLUE_TERRACOTTA - - YELLOW_TERRACOTTA - - LIME_TERRACOTTA - - PINK_TERRACOTTA - - GRAY_TERRACOTTA - - LIGHT_GRAY_TERRACOTTA - - CYAN_TERRACOTTA - - PURPLE_TERRACOTTA - - BLUE_TERRACOTTA - - BROWN_TERRACOTTA - - GREEN_TERRACOTTA - - RED_TERRACOTTA - - BLACK_TERRACOTTA - #trapdoors - - ACACIA_TRAPDOOR - - BIRCH_TRAPDOOR - - DARK_OAK_TRAPDOOR - - JUNGLE_TRAPDOOR - - OAK_TRAPDOOR - - SPRUCE_TRAPDOOR - #weapon blocks - - COAL_BLOCK - #wood - - ACACIA_WOOD - - BIRCH_WOOD - - DARK_OAK_WOOD - - OAK_WOOD - - SPRUCE_WOOD - - STRIPPED_ACACIA_WOOD - - STRIPPED_BIRCH_WOOD - - STRIPPED_DARK_OAK_WOOD - - STRIPPED_OAK_WOOD - - STRIPPED_SPRUCE_WOOD - #wool - - WHITE_WOOL - - ORANGE_WOOL - - MAGENTA_WOOL - - LIGHT_BLUE_WOOL - - YELLOW_WOOL - - LIME_WOOL - - PINK_WOOL - - GRAY_WOOL - - LIGHT_GRAY_WOOL - - CYAN_WOOL - - PURPLE_WOOL - - BLUE_WOOL - - BROWN_WOOL - - GREEN_WOOL - - RED_WOOL - - BLACK_WOOL - + - crafting_table + - ALL_WOOD + - WATER + - LAVA + - ALL_LOG + - all_planks + - GLASS + - LAPIS_BLOCK + - DISPENSER + - NOTE_BLOCK + - ALL_BED + - sticky_piston + - piston + - all_wool + - GOLD_BLOCK + - IRON_BLOCK + - all_slab + - BOOKSHELF + - TORCH + - FIRE + - oak_stairs + - birch_stairs + - jungle_stairs + - spruce_stairs + - stone_brick_stairs + - quartz_stairs + - nether_brick_stairs + - chest + - redstone_wire + - diamond_block + - nether_brick_stairs + - furnace + - all_sign + - ladder + - all_door + - lever + - all_pressure_plate + - redstone_torch + - redstone_wall_torch + - all_button + - clay + - all_fence + - netherrack + - glowstone + - cake + - repeater + - all_stained_glass + - all_trapdoor + - all_stone_bricks + - iron_bars + - glass_pane + - all_fence_gate + - nether_brick + - enchantment_table + - brewing_stand + - cauldron + - end_stone + - dragon_egg + - redstone_lamp + - ender chest + - TRIPWIRE_HOOK + - EMERALD_BLOCK + - BEACON + - cobblestone_wall + - mossy_cobblestone_wall + - FLOWER_POT + - SKULL + - all_ANVIL + - TRAPPED_CHEST + - COMPARATOR + - daylight_detector + - REDSTONE_BLOCK + - HOPPER + - all_QUARTZ_BLOCK + - all_rail + - DROPPER + - ALL_TERRACOTTA + - ALL_STAINED_GLASS_PANE + - SLIME_BLOCK + - ALL_CARPET + - COAL_BLOCK + - END_STONE_BRICKS canCruise: true rotateAtMidpoint: true cruiseSkipBlocks: 4 diff --git a/modules/Movecraft/src/main/resources/types/1_14/airship.craft b/modules/Movecraft/src/main/resources/types/1_14/airship.craft index c58da4450..88f281e52 100644 --- a/modules/Movecraft/src/main/resources/types/1_14/airship.craft +++ b/modules/Movecraft/src/main/resources/types/1_14/airship.craft @@ -2,6 +2,7 @@ name: Airship maxSize: 5000 minSize: 1000 allowedBlocks: + - crafting_table - ALL_WOOD - WATER - LAVA @@ -13,7 +14,7 @@ allowedBlocks: - NOTE_BLOCK - ALL_BED - sticky_piston - - piston_head + - piston - all_wool - GOLD_BLOCK - IRON_BLOCK @@ -46,7 +47,7 @@ allowedBlocks: - netherrack - glowstone - cake - - redstone_repeater + - repeater - all_stained_glass - all_trapdoor - all_stone_bricks @@ -70,7 +71,7 @@ allowedBlocks: - SKULL - all_ANVIL - TRAPPED_CHEST - - REDSTONE_COMPARATOR + - COMPARATOR - daylight_detector - REDSTONE_BLOCK - HOPPER diff --git a/modules/Movecraft/src/main/resources/types/BigAirship.craft b/modules/Movecraft/src/main/resources/types/BigAirship.craft index a10c2e04a..d5dcef13f 100644 --- a/modules/Movecraft/src/main/resources/types/BigAirship.craft +++ b/modules/Movecraft/src/main/resources/types/BigAirship.craft @@ -2,6 +2,7 @@ name: BigAirship maxSize: 20000 minSize: 10000 allowedBlocks: + - crafting_table - ALL_WOOD - WATER - LAVA @@ -13,7 +14,7 @@ allowedBlocks: - NOTE_BLOCK - ALL_BED - sticky_piston - - piston_head + - piston - all_wool - GOLD_BLOCK - IRON_BLOCK @@ -46,7 +47,7 @@ allowedBlocks: - netherrack - glowstone - cake - - redstone_repeater + - repeater - all_stained_glass - all_trapdoor - all_stone_bricks @@ -70,7 +71,7 @@ allowedBlocks: - SKULL - all_ANVIL - TRAPPED_CHEST - - REDSTONE_COMPARATOR + - COMPARATOR - daylight_detector - REDSTONE_BLOCK - HOPPER diff --git a/modules/Movecraft/src/main/resources/types/BigSubAirship.craft b/modules/Movecraft/src/main/resources/types/BigSubAirship.craft index 15254a4a9..e0a43c22b 100644 --- a/modules/Movecraft/src/main/resources/types/BigSubAirship.craft +++ b/modules/Movecraft/src/main/resources/types/BigSubAirship.craft @@ -2,88 +2,88 @@ name: BigSubAirship maxSize: 20000 minSize: 10000 allowedBlocks: - - ALL_WOOD - - WATER - - LAVA - - ALL_LOG - - all_planks - - GLASS - - LAPIS_BLOCK - - DISPENSER - - NOTE_BLOCK - - ALL_BED - - sticky_piston - - piston_head - - all_wool - - GOLD_BLOCK - - IRON_BLOCK - - all_slab - - BOOKSHELF - - TORCH - - FIRE - - oak_stairs - - birch_stairs - - jungle_stairs - - spruce_stairs - - stone_brick_stairs - - quartz_stairs - - nether_brick_stairs - - chest - - redstone_wire - - diamond_block - - nether_brick_stairs - - furnace - - all_sign - - ladder - - all_door - - lever - - all_pressure_plate - - redstone_torch - - redstone_wall_torch - - all_button - - clay - - all_fence - - netherrack - - glowstone - - cake - - redstone_repeater - - all_stained_glass - - all_trapdoor - - all_stone_bricks - - iron_bars - - glass_pane - - all_fence_gate - - nether_brick - - enchantment_table - - brewing_stand - - cauldron - - end_stone - - dragon_egg - - redstone_lamp - - ender chest - - TRIPWIRE_HOOK - - EMERALD_BLOCK - - BEACON - - cobblestone_wall - - mossy_cobblestone_wall - - FLOWER_POT - - SKULL - - all_ANVIL - - TRAPPED_CHEST - - REDSTONE_COMPARATOR - - daylight_detector - - REDSTONE_BLOCK - - HOPPER - - all_QUARTZ_BLOCK: - - all_rail - - DROPPER - - ALL_TERRACOTTA - - ALL_STAINED_GLASS_PANE - - SLIME_BLOCK - - ALL_CARPET - - COAL_BLOCK - - END_STONE_BRICKS - + - crafting_table + - ALL_WOOD + - WATER + - LAVA + - ALL_LOG + - all_planks + - GLASS + - LAPIS_BLOCK + - DISPENSER + - NOTE_BLOCK + - ALL_BED + - sticky_piston + - piston + - all_wool + - GOLD_BLOCK + - IRON_BLOCK + - all_slab + - BOOKSHELF + - TORCH + - FIRE + - oak_stairs + - birch_stairs + - jungle_stairs + - spruce_stairs + - stone_brick_stairs + - quartz_stairs + - nether_brick_stairs + - chest + - redstone_wire + - diamond_block + - nether_brick_stairs + - furnace + - all_sign + - ladder + - all_door + - lever + - all_pressure_plate + - redstone_torch + - redstone_wall_torch + - all_button + - clay + - all_fence + - netherrack + - glowstone + - cake + - repeater + - all_stained_glass + - all_trapdoor + - all_stone_bricks + - iron_bars + - glass_pane + - all_fence_gate + - nether_brick + - enchantment_table + - brewing_stand + - cauldron + - end_stone + - dragon_egg + - redstone_lamp + - ender chest + - TRIPWIRE_HOOK + - EMERALD_BLOCK + - BEACON + - cobblestone_wall + - mossy_cobblestone_wall + - FLOWER_POT + - SKULL + - all_ANVIL + - TRAPPED_CHEST + - COMPARATOR + - daylight_detector + - REDSTONE_BLOCK + - HOPPER + - all_QUARTZ_BLOCK + - all_rail + - DROPPER + - ALL_TERRACOTTA + - ALL_STAINED_GLASS_PANE + - SLIME_BLOCK + - ALL_CARPET + - COAL_BLOCK + - END_STONE_BRICKS canCruise: true rotateAtMidpoint: true blockRemoteRotate: true diff --git a/modules/Movecraft/src/main/resources/types/Ship.craft b/modules/Movecraft/src/main/resources/types/Ship.craft index 155e110e3..4b7d96703 100644 --- a/modules/Movecraft/src/main/resources/types/Ship.craft +++ b/modules/Movecraft/src/main/resources/types/Ship.craft @@ -2,88 +2,88 @@ name: Ship maxSize: 100000 minSize: 10 allowedBlocks: - - ALL_WOOD - - WATER - - LAVA - - ALL_LOG - - all_planks - - GLASS - - LAPIS_BLOCK - - DISPENSER - - NOTE_BLOCK - - ALL_BED - - sticky_piston - - piston_head - - all_wool - - GOLD_BLOCK - - IRON_BLOCK - - all_slab - - BOOKSHELF - - TORCH - - FIRE - - oak_stairs - - birch_stairs - - jungle_stairs - - spruce_stairs - - stone_brick_stairs - - quartz_stairs - - nether_brick_stairs - - chest - - redstone_wire - - diamond_block - - nether_brick_stairs - - furnace - - all_sign - - ladder - - all_door - - lever - - all_pressure_plate - - redstone_torch - - redstone_wall_torch - - all_button - - clay - - all_fence - - netherrack - - glowstone - - cake - - redstone_repeater - - all_stained_glass - - all_trapdoor - - all_stone_bricks - - iron_bars - - glass_pane - - all_fence_gate - - nether_brick - - enchantment_table - - brewing_stand - - cauldron - - end_stone - - dragon_egg - - redstone_lamp - - ender chest - - TRIPWIRE_HOOK - - EMERALD_BLOCK - - BEACON - - cobblestone_wall - - mossy_cobblestone_wall - - FLOWER_POT - - SKULL - - all_ANVIL - - TRAPPED_CHEST - - REDSTONE_COMPARATOR - - daylight_detector - - REDSTONE_BLOCK - - HOPPER - - all_QUARTZ_BLOCK - - all_rail - - DROPPER - - ALL_TERRACOTTA - - ALL_STAINED_GLASS_PANE - - SLIME_BLOCK - - ALL_CARPET - - COAL_BLOCK - - END_STONE_BRICKS - + - crafting_table + - ALL_WOOD + - WATER + - LAVA + - ALL_LOG + - all_planks + - GLASS + - LAPIS_BLOCK + - DISPENSER + - NOTE_BLOCK + - ALL_BED + - sticky_piston + - piston + - all_wool + - GOLD_BLOCK + - IRON_BLOCK + - all_slab + - BOOKSHELF + - TORCH + - FIRE + - oak_stairs + - birch_stairs + - jungle_stairs + - spruce_stairs + - stone_brick_stairs + - quartz_stairs + - nether_brick_stairs + - chest + - redstone_wire + - diamond_block + - nether_brick_stairs + - furnace + - all_sign + - ladder + - all_door + - lever + - all_pressure_plate + - redstone_torch + - redstone_wall_torch + - all_button + - clay + - all_fence + - netherrack + - glowstone + - cake + - repeater + - all_stained_glass + - all_trapdoor + - all_stone_bricks + - iron_bars + - glass_pane + - all_fence_gate + - nether_brick + - enchantment_table + - brewing_stand + - cauldron + - end_stone + - dragon_egg + - redstone_lamp + - ender chest + - TRIPWIRE_HOOK + - EMERALD_BLOCK + - BEACON + - cobblestone_wall + - mossy_cobblestone_wall + - FLOWER_POT + - SKULL + - all_ANVIL + - TRAPPED_CHEST + - COMPARATOR + - daylight_detector + - REDSTONE_BLOCK + - HOPPER + - all_QUARTZ_BLOCK + - all_rail + - DROPPER + - ALL_TERRACOTTA + - ALL_STAINED_GLASS_PANE + - SLIME_BLOCK + - ALL_CARPET + - COAL_BLOCK + - END_STONE_BRICKS canCruise: true cruiseSkipBlocks: 4 canFly: false diff --git a/modules/Movecraft/src/main/resources/types/SubAirship.craft b/modules/Movecraft/src/main/resources/types/SubAirship.craft index 776632c02..6e04449ed 100644 --- a/modules/Movecraft/src/main/resources/types/SubAirship.craft +++ b/modules/Movecraft/src/main/resources/types/SubAirship.craft @@ -2,88 +2,88 @@ name: SubAirship maxSize: 5000 minSize: 1000 allowedBlocks: - - ALL_WOOD - - WATER - - LAVA - - ALL_LOG - - all_planks - - GLASS - - LAPIS_BLOCK - - DISPENSER - - NOTE_BLOCK - - ALL_BED - - sticky_piston - - piston_head - - all_wool - - GOLD_BLOCK - - IRON_BLOCK - - all_slab - - BOOKSHELF - - TORCH - - FIRE - - oak_stairs - - birch_stairs - - jungle_stairs - - spruce_stairs - - stone_brick_stairs - - quartz_stairs - - nether_brick_stairs - - chest - - redstone_wire - - diamond_block - - nether_brick_stairs - - furnace - - all_sign - - ladder - - all_door - - lever - - all_pressure_plate - - redstone_torch - - redstone_wall_torch - - all_button - - clay - - all_fence - - netherrack - - glowstone - - cake - - redstone_repeater - - all_stained_glass - - all_trapdoor - - all_stone_bricks - - iron_bars - - glass_pane - - all_fence_gate - - nether_brick - - enchantment_table - - brewing_stand - - cauldron - - end_stone - - dragon_egg - - redstone_lamp - - ender chest - - TRIPWIRE_HOOK - - EMERALD_BLOCK - - BEACON - - cobblestone_wall - - mossy_cobblestone_wall - - FLOWER_POT - - SKULL - - all_ANVIL - - TRAPPED_CHEST - - REDSTONE_COMPARATOR - - daylight_detector - - REDSTONE_BLOCK - - HOPPER - - all_QUARTZ_BLOCK - - all_rail - - DROPPER - - ALL_TERRACOTTA - - ALL_STAINED_GLASS_PANE - - SLIME_BLOCK - - ALL_CARPET - - COAL_BLOCK - - END_STONE_BRICKS - + - crafting_table + - ALL_WOOD + - WATER + - LAVA + - ALL_LOG + - all_planks + - GLASS + - LAPIS_BLOCK + - DISPENSER + - NOTE_BLOCK + - ALL_BED + - sticky_piston + - piston + - all_wool + - GOLD_BLOCK + - IRON_BLOCK + - all_slab + - BOOKSHELF + - TORCH + - FIRE + - oak_stairs + - birch_stairs + - jungle_stairs + - spruce_stairs + - stone_brick_stairs + - quartz_stairs + - nether_brick_stairs + - chest + - redstone_wire + - diamond_block + - nether_brick_stairs + - furnace + - all_sign + - ladder + - all_door + - lever + - all_pressure_plate + - redstone_torch + - redstone_wall_torch + - all_button + - clay + - all_fence + - netherrack + - glowstone + - cake + - repeater + - all_stained_glass + - all_trapdoor + - all_stone_bricks + - iron_bars + - glass_pane + - all_fence_gate + - nether_brick + - enchantment_table + - brewing_stand + - cauldron + - end_stone + - dragon_egg + - redstone_lamp + - ender chest + - TRIPWIRE_HOOK + - EMERALD_BLOCK + - BEACON + - cobblestone_wall + - mossy_cobblestone_wall + - FLOWER_POT + - SKULL + - all_ANVIL + - TRAPPED_CHEST + - COMPARATOR + - daylight_detector + - REDSTONE_BLOCK + - HOPPER + - all_QUARTZ_BLOCK + - all_rail + - DROPPER + - ALL_TERRACOTTA + - ALL_STAINED_GLASS_PANE + - SLIME_BLOCK + - ALL_CARPET + - COAL_BLOCK + - END_STONE_BRICKS canCruise: true rotateAtMidpoint: true cruiseSkipBlocks: 4 @@ -110,7 +110,7 @@ passthroughBlocks: - seagrass - bubble_column moveblocks: - 152: # redstone represents engines + redstone_block: # redstone represents engines - 1.0 - 100.0 flyblocks: diff --git a/modules/Movecraft/src/main/resources/types/Submarine.craft b/modules/Movecraft/src/main/resources/types/Submarine.craft index 5576a938a..c5f9d073a 100644 --- a/modules/Movecraft/src/main/resources/types/Submarine.craft +++ b/modules/Movecraft/src/main/resources/types/Submarine.craft @@ -2,88 +2,88 @@ name: Submarine maxSize: 100000 minSize: 10 allowedBlocks: - - ALL_WOOD - - WATER - - LAVA - - ALL_LOG - - all_planks - - GLASS - - LAPIS_BLOCK - - DISPENSER - - NOTE_BLOCK - - ALL_BED - - sticky_piston - - piston_head - - all_wool - - GOLD_BLOCK - - IRON_BLOCK - - all_slab - - BOOKSHELF - - TORCH - - FIRE - - oak_stairs - - birch_stairs - - jungle_stairs - - spruce_stairs - - stone_brick_stairs - - quartz_stairs - - nether_brick_stairs - - chest - - redstone_wire - - diamond_block - - nether_brick_stairs - - furnace - - all_sign - - ladder - - all_door - - lever - - all_pressure_plate - - redstone_torch - - redstone_wall_torch - - all_button - - clay - - all_fence - - netherrack - - glowstone - - cake - - redstone_repeater - - all_stained_glass - - all_trapdoor - - all_stone_bricks - - iron_bars - - glass_pane - - all_fence_gate - - nether_brick - - enchantment_table - - brewing_stand - - cauldron - - end_stone - - dragon_egg - - redstone_lamp - - ender chest - - TRIPWIRE_HOOK - - EMERALD_BLOCK - - BEACON - - cobblestone_wall - - mossy_cobblestone_wall - - FLOWER_POT - - SKULL - - all_ANVIL - - TRAPPED_CHEST - - REDSTONE_COMPARATOR - - daylight_detector - - REDSTONE_BLOCK - - HOPPER - - all_QUARTZ_BLOCK - - all_rail - - DROPPER - - ALL_TERRACOTTA - - ALL_STAINED_GLASS_PANE - - SLIME_BLOCK - - ALL_CARPET - - COAL_BLOCK - - END_STONE_BRICKS - + - crafting_table + - ALL_WOOD + - WATER + - LAVA + - ALL_LOG + - all_planks + - GLASS + - LAPIS_BLOCK + - DISPENSER + - NOTE_BLOCK + - ALL_BED + - sticky_piston + - piston + - all_wool + - GOLD_BLOCK + - IRON_BLOCK + - all_slab + - BOOKSHELF + - TORCH + - FIRE + - oak_stairs + - birch_stairs + - jungle_stairs + - spruce_stairs + - stone_brick_stairs + - quartz_stairs + - nether_brick_stairs + - chest + - redstone_wire + - diamond_block + - nether_brick_stairs + - furnace + - all_sign + - ladder + - all_door + - lever + - all_pressure_plate + - redstone_torch + - redstone_wall_torch + - all_button + - clay + - all_fence + - netherrack + - glowstone + - cake + - repeater + - all_stained_glass + - all_trapdoor + - all_stone_bricks + - iron_bars + - glass_pane + - all_fence_gate + - nether_brick + - enchantment_table + - brewing_stand + - cauldron + - end_stone + - dragon_egg + - redstone_lamp + - ender chest + - TRIPWIRE_HOOK + - EMERALD_BLOCK + - BEACON + - cobblestone_wall + - mossy_cobblestone_wall + - FLOWER_POT + - SKULL + - all_ANVIL + - TRAPPED_CHEST + - COMPARATOR + - daylight_detector + - REDSTONE_BLOCK + - HOPPER + - all_QUARTZ_BLOCK + - all_rail + - DROPPER + - ALL_TERRACOTTA + - ALL_STAINED_GLASS_PANE + - SLIME_BLOCK + - ALL_CARPET + - COAL_BLOCK + - END_STONE_BRICKS canCruise: true cruiseSkipBlocks: 4 canFly: false diff --git a/modules/Movecraft/src/main/resources/types/airskiff.craft b/modules/Movecraft/src/main/resources/types/airskiff.craft index 255f01d15..7cdea8794 100644 --- a/modules/Movecraft/src/main/resources/types/airskiff.craft +++ b/modules/Movecraft/src/main/resources/types/airskiff.craft @@ -38,7 +38,7 @@ allowedBlocks: - netherrack - glowstone - cake - - redstone_repeater + - repeater - all_stained_glass - all_trapdoor - all_stone_bricks @@ -58,7 +58,7 @@ allowedBlocks: - SKULL - all_ANVIL - TRAPPED_CHEST - - REDSTONE_COMPARATOR + - COMPARATOR - daylight_detector - REDSTONE_BLOCK - HOPPER diff --git a/modules/Movecraft/src/main/resources/types/elevator.craft b/modules/Movecraft/src/main/resources/types/elevator.craft index 1b41424c1..b1dcc0e7f 100644 --- a/modules/Movecraft/src/main/resources/types/elevator.craft +++ b/modules/Movecraft/src/main/resources/types/elevator.craft @@ -38,7 +38,7 @@ allowedBlocks: - netherrack - glowstone - cake - - redstone_repeater + - repeater - all_stained_glass - all_trapdoor - all_stone_bricks @@ -58,7 +58,7 @@ allowedBlocks: - SKULL - all_ANVIL - TRAPPED_CHEST - - REDSTONE_COMPARATOR + - COMPARATOR - daylight_detector - REDSTONE_BLOCK - HOPPER @@ -70,7 +70,6 @@ allowedBlocks: - ALL_CARPET - COAL_BLOCK - END_STONE_BRICKS - canFly: true canCruise: false collisionExplosion: 0.0 diff --git a/modules/api/src/main/java/net/countercraft/movecraft/config/Settings.java b/modules/api/src/main/java/net/countercraft/movecraft/config/Settings.java index 19d66a0c0..f8152391e 100644 --- a/modules/api/src/main/java/net/countercraft/movecraft/config/Settings.java +++ b/modules/api/src/main/java/net/countercraft/movecraft/config/Settings.java @@ -65,11 +65,6 @@ public class Settings { public static boolean TownyBlockMoveOnSwitchPerm = false; public static boolean TownyBlockSinkOnNoPVP = false; - //RedProtect Settings - public static boolean RedProtectBlockMoveOnNoEntry = false; - public static boolean RedProtectBlockMoveOnNoBuild = false; - public static boolean RedProtectBlockMoveOnNoExit = false; - public static boolean RedProtectBlockSinkOnNoPvP = false; public static Map TownProtectionHeightLimits; public static Map DurabilityOverride; public static boolean IsPaper = false; @@ -95,6 +90,7 @@ public class Settings { public static boolean SiegeEnable; public static String SiegeTimeZone; - public static boolean KOTHSiege = false; public static long TracerMinDistanceSqrd; + + public static Map, String> StatusSignMarkers = new HashMap<>(); } diff --git a/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java b/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java index f6d0f7969..2ecb6c6f0 100644 --- a/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java +++ b/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java @@ -722,6 +722,7 @@ private Map>, List> materialMapListFromObjec materialMap.put(type, new ArrayList<>()); } else if (i instanceof String) { String string = (String) i; + string = string.toUpperCase(); if (string.contains(":")) { String[] parts = string.split(":"); Material type; From c45c149a390ad275a28bec41c53b23deb412094e Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Thu, 22 Aug 2019 18:42:54 +0200 Subject: [PATCH 038/304] Fixed a bug in StatusSign + made event CraftCollisionEvent fire from the main server thread in TranslationTask --- .../movecraft/async/translation/TranslationTask.java | 8 +++++++- .../java/net/countercraft/movecraft/sign/StatusSign.java | 6 +----- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java index 1ff8ed8bf..2a354418a 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java @@ -376,7 +376,13 @@ public void run() { } if(!collisionBox.isEmpty()){ - Bukkit.getServer().getPluginManager().callEvent(new CraftCollisionEvent(craft, collisionBox)); + new BukkitRunnable() { + @Override + public void run() { + Bukkit.getServer().getPluginManager().callEvent(new CraftCollisionEvent(craft, collisionBox)); + } + }.runTask(Movecraft.getInstance()); + } updates.add(new CraftTranslateCommand(craft, new MovecraftLocation(dx, dy, dz))); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/StatusSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/StatusSign.java index df6d0fee3..ae768e3ff 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/StatusSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/StatusSign.java @@ -5,7 +5,6 @@ import net.countercraft.movecraft.craft.Craft; import net.countercraft.movecraft.events.CraftDetectEvent; import net.countercraft.movecraft.events.SignTranslateEvent; -import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.Material; import org.bukkit.World; @@ -91,7 +90,6 @@ public final void onSignTranslate(SignTranslateEvent event) { Material flyBlock = flyBlocks.get(0); if (addToStatus) { Double percentPresent = (double) (amount * 100 / totalBlocks); - Bukkit.broadcastMessage("test"); String signText = ""; if (percentPresent > minimum * 1.04) { signText += ChatColor.GREEN; @@ -100,14 +98,12 @@ public final void onSignTranslate(SignTranslateEvent event) { } else { signText += ChatColor.RED; } - Bukkit.broadcastMessage(Settings.StatusSignMarkers.get(flyBlocks)); signText += Settings.StatusSignMarkers.get(flyBlocks); signText += " "; signText += percentPresent.intValue(); signText += "/"; signText += minimum.intValue(); signText += " "; - Bukkit.broadcastMessage(signLine + " " + signColumn + signText); if (signColumn == 0) { event.setLine(signLine, signText); signColumn++; @@ -120,7 +116,7 @@ public final void onSignTranslate(SignTranslateEvent event) { } } } - if (signLine < 3 && signColumn == 0){ + if (signLine < 3 && signColumn == 1){ signLine++; } String fuelText=""; From 1b0abd3e20ea0c5967719597679ba0f6dba0d1e0 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Fri, 30 Aug 2019 16:35:59 +0200 Subject: [PATCH 039/304] Added debug message to detection --- .../movecraft/async/detection/DetectionTask.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/detection/DetectionTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/detection/DetectionTask.java index ba4bd471c..4e780be2b 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/detection/DetectionTask.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/detection/DetectionTask.java @@ -21,10 +21,12 @@ import net.countercraft.movecraft.Movecraft; import net.countercraft.movecraft.MovecraftLocation; import net.countercraft.movecraft.async.AsyncTask; +import net.countercraft.movecraft.config.Settings; import net.countercraft.movecraft.craft.Craft; import net.countercraft.movecraft.localisation.I18nSupport; import net.countercraft.movecraft.utils.HashHitBox; import net.countercraft.movecraft.utils.LegacyUtils; +import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.World; @@ -65,6 +67,7 @@ public DetectionTask(Craft c, MovecraftLocation startLocation, Player player) { @Override public void execute() { + long startTime = System.currentTimeMillis(); Map>, List> flyBlocks = getCraft().getType().getFlyBlocks(); dFlyBlocks = flyBlocks; blockStack.push(startLocation); @@ -97,6 +100,10 @@ public void execute() { } } + long endTime = System.currentTimeMillis(); + if (Settings.Debug){ + Bukkit.broadcastMessage("Detection took (ms): " + (endTime - startTime)); + } } private void detectBlock(int x, int y, int z) { From 4e82910712d15a95c4f0e1fe4b6d2c8323ee6a7a Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Thu, 12 Sep 2019 13:05:35 +0200 Subject: [PATCH 040/304] Entity processing now happens in a sync task besides TranslationTask due to API changes in 1.14.4 --- .../async/translation/TranslationTask.java | 27 +-------- .../countercraft/movecraft/craft/ICraft.java | 2 + .../movecraft/sync/EntityProcessor.java | 55 +++++++++++++++++++ 3 files changed, 59 insertions(+), 25 deletions(-) create mode 100644 modules/Movecraft/src/main/java/net/countercraft/movecraft/sync/EntityProcessor.java diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java index 2a354418a..3620af376 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java @@ -21,7 +21,6 @@ import org.bukkit.block.Block; import org.bukkit.block.Chest; import org.bukkit.block.Furnace; -import org.bukkit.entity.Entity; import org.bukkit.entity.EntityType; import org.bukkit.entity.Player; import org.bukkit.inventory.Inventory; @@ -387,30 +386,8 @@ public void run() { updates.add(new CraftTranslateCommand(craft, new MovecraftLocation(dx, dy, dz))); - //prevents torpedo and rocket pilots - if (craft.getType().getMoveEntities() && !(craft.getSinking() && craft.getType().getOnlyMovePlayers())) { - Location midpoint = new Location( - craft.getW(), - (oldHitBox.getMaxX() + oldHitBox.getMinX())/2.0, - (oldHitBox.getMaxY() + oldHitBox.getMinY())/2.0, - (oldHitBox.getMaxZ() + oldHitBox.getMinZ())/2.0); - for (Entity entity : craft.getW().getNearbyEntities(midpoint, oldHitBox.getXLength() / 2.0 + 1, oldHitBox.getYLength() / 2.0 + 2, oldHitBox.getZLength() / 2.0 + 1)) { - if (entity.getType() == EntityType.PLAYER) { - if(craft.getSinking()){ - continue; - } - EntityMoveUpdateCommand eUp = new EntityMoveUpdateCommand(entity, dx, dy, dz, 0, 0); - updates.add(eUp); - } else if (!craft.getType().getOnlyMovePlayers() || entity.getType() == EntityType.PRIMED_TNT) { - EntityMoveUpdateCommand eUp = new EntityMoveUpdateCommand(entity, dx, dy, dz, 0, 0); - updates.add(eUp); - } - } - } else { - //add releaseTask without playermove to manager - if (!craft.getType().getCruiseOnPilot() && !craft.getSinking()) // not necessary to release cruiseonpilot crafts, because they will already be released - CraftManager.getInstance().addReleaseTask(craft); - } + + captureYield(harvestedBlocks); } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/ICraft.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/ICraft.java index 729deacaf..4860988a2 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/ICraft.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/ICraft.java @@ -7,6 +7,7 @@ import net.countercraft.movecraft.async.rotation.RotationTask; import net.countercraft.movecraft.async.translation.TranslationTask; import net.countercraft.movecraft.localisation.I18nSupport; +import net.countercraft.movecraft.sync.EntityProcessor; import org.bukkit.World; import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; @@ -85,6 +86,7 @@ public void translate(int dx, int dy, int dz) { if (isClimbing()){ setClimbing(false); } + new EntityProcessor(this, new MovecraftLocation(dx, dy, dz)).runTask(Movecraft.getInstance()); Movecraft.getInstance().getAsyncManager().submitTask(new TranslationTask(this, dx, dy, dz), this); } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sync/EntityProcessor.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sync/EntityProcessor.java new file mode 100644 index 000000000..59b95840f --- /dev/null +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sync/EntityProcessor.java @@ -0,0 +1,55 @@ +package net.countercraft.movecraft.sync; + +import net.countercraft.movecraft.MovecraftLocation; +import net.countercraft.movecraft.craft.Craft; +import net.countercraft.movecraft.craft.CraftManager; +import net.countercraft.movecraft.mapUpdater.MapUpdateManager; +import net.countercraft.movecraft.mapUpdater.update.EntityMoveUpdateCommand; +import net.countercraft.movecraft.mapUpdater.update.UpdateCommand; +import net.countercraft.movecraft.utils.HashHitBox; +import org.bukkit.Location; +import org.bukkit.entity.Entity; +import org.bukkit.entity.EntityType; +import org.bukkit.scheduler.BukkitRunnable; + +import java.util.LinkedList; + +public class EntityProcessor extends BukkitRunnable { + private final Craft craft; + private final MovecraftLocation displacement; + + public EntityProcessor(Craft craft, MovecraftLocation displacement) { + this.craft = craft; + this.displacement = displacement; + } + + @Override + public void run() { + LinkedList updates = new LinkedList<>(); + HashHitBox oldHitBox = craft.getHitBox(); + if (craft.getType().getMoveEntities() && !(craft.getSinking() && craft.getType().getOnlyMovePlayers())) { + Location midpoint = new Location( + craft.getW(), + (oldHitBox.getMaxX() + oldHitBox.getMinX())/2.0, + (oldHitBox.getMaxY() + oldHitBox.getMinY())/2.0, + (oldHitBox.getMaxZ() + oldHitBox.getMinZ())/2.0); + for (Entity entity : craft.getW().getNearbyEntities(midpoint, oldHitBox.getXLength() / 2.0 + 1, oldHitBox.getYLength() / 2.0 + 2, oldHitBox.getZLength() / 2.0 + 1)) { + if (entity.getType() == EntityType.PLAYER) { + if(craft.getSinking()){ + continue; + } + EntityMoveUpdateCommand eUp = new EntityMoveUpdateCommand(entity, displacement.getX(), displacement.getY(), displacement.getZ(), 0, 0); + updates.add(eUp); + } else if (!craft.getType().getOnlyMovePlayers() || entity.getType() == EntityType.PRIMED_TNT) { + EntityMoveUpdateCommand eUp = new EntityMoveUpdateCommand(entity, displacement.getX(), displacement.getY(), displacement.getZ(), 0, 0); + updates.add(eUp); + } + } + } else { + //add releaseTask without playermove to manager + if (!craft.getType().getCruiseOnPilot() && !craft.getSinking()) // not necessary to release cruiseonpilot crafts, because they will already be released + CraftManager.getInstance().addReleaseTask(craft); + } + MapUpdateManager.getInstance().scheduleUpdates(updates); + } +} From 578cac50b9c84910ec6382a7913a99711bbe2c9c Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Fri, 13 Sep 2019 22:01:03 +0200 Subject: [PATCH 041/304] Fixed entity processing. Entities are now processed in the server thread --- .../async/rotation/RotationTask.java | 28 +---------- .../countercraft/movecraft/craft/ICraft.java | 13 +++-- .../movecraft/sync/EntityProcessor.java | 48 ++++++++++++++----- 3 files changed, 47 insertions(+), 42 deletions(-) diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/rotation/RotationTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/rotation/RotationTask.java index 373f04e65..a76b936fb 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/rotation/RotationTask.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/rotation/RotationTask.java @@ -35,7 +35,6 @@ import net.countercraft.movecraft.events.CraftRotateEvent; import net.countercraft.movecraft.localisation.I18nSupport; import net.countercraft.movecraft.mapUpdater.update.CraftRotateCommand; -import net.countercraft.movecraft.mapUpdater.update.EntityMoveUpdateCommand; import net.countercraft.movecraft.mapUpdater.update.UpdateCommand; import net.countercraft.movecraft.utils.*; import org.bukkit.Bukkit; @@ -45,8 +44,6 @@ import org.bukkit.block.Block; import org.bukkit.block.BlockFace; import org.bukkit.block.Furnace; -import org.bukkit.entity.Entity; -import org.bukkit.entity.EntityType; import org.bukkit.entity.Player; import org.bukkit.inventory.InventoryHolder; import org.bukkit.inventory.ItemStack; @@ -211,30 +208,7 @@ public void run() { updates.add(new CraftRotateCommand(getCraft(),originPoint, rotation)); - //rotate entities in the craft - Location tOP = new Location(getCraft().getW(), originPoint.getX(), originPoint.getY(), originPoint.getZ()); - tOP.setX(tOP.getBlockX() + 0.5); - tOP.setZ(tOP.getBlockZ() + 0.5); - - if (craft.getType().getMoveEntities() && !(craft.getSinking() && craft.getType().getOnlyMovePlayers())) { - Location midpoint = new Location( - craft.getW(), - (oldHitBox.getMaxX() + oldHitBox.getMinX())/2.0, - (oldHitBox.getMaxY() + oldHitBox.getMinY())/2.0, - (oldHitBox.getMaxZ() + oldHitBox.getMinZ())/2.0); - for(Entity entity : craft.getW().getNearbyEntities(midpoint, oldHitBox.getXLength()/2.0 + 1, oldHitBox.getYLength()/2.0 + 2, oldHitBox.getZLength()/2.0 + 1)){ - if ((entity.getType() == EntityType.PLAYER && !craft.getSinking()) || !craft.getType().getOnlyMovePlayers()) { - // Player is onboard this craft - - Location adjustedPLoc = entity.getLocation().subtract(tOP); - - double[] rotatedCoords = MathUtils.rotateVecNoRound(rotation, adjustedPLoc.getX(), adjustedPLoc.getZ()); - float newYaw = rotation == Rotation.CLOCKWISE ? 90F : -90F; - EntityMoveUpdateCommand eUp = new EntityMoveUpdateCommand(entity, rotatedCoords[0] + tOP.getX() - entity.getLocation().getX(), 0, rotatedCoords[1] + tOP.getZ() - entity.getLocation().getZ(), newYaw, 0); - updates.add(eUp); - } - } - } + if (getCraft().getCruising()) { if (rotation == Rotation.ANTICLOCKWISE) { diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/ICraft.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/ICraft.java index 4860988a2..7e8ac79de 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/ICraft.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/ICraft.java @@ -86,8 +86,9 @@ public void translate(int dx, int dy, int dz) { if (isClimbing()){ setClimbing(false); } - new EntityProcessor(this, new MovecraftLocation(dx, dy, dz)).runTask(Movecraft.getInstance()); - Movecraft.getInstance().getAsyncManager().submitTask(new TranslationTask(this, dx, dy, dz), this); + TranslationTask task = new TranslationTask(this, dx, dy, dz); + task.getUpdates().addAll(EntityProcessor.translateEntities(this, new MovecraftLocation(dx, dy, dz))); + Movecraft.getInstance().getAsyncManager().submitTask(task, this); } @Override @@ -133,12 +134,16 @@ public void rotate(Rotation rotation, MovecraftLocation originPoint) { } } }*/ - Movecraft.getInstance().getAsyncManager().submitTask(new RotationTask(this, originPoint, rotation, this.getW()), this); + RotationTask task = new RotationTask(this, originPoint, rotation, this.getW()); + task.getUpdates().addAll(EntityProcessor.rotateEntities(this, originPoint, rotation)); + Movecraft.getInstance().getAsyncManager().submitTask(task, this); } @Override public void rotate(Rotation rotation, MovecraftLocation originPoint, boolean isSubCraft) { - Movecraft.getInstance().getAsyncManager().submitTask(new RotationTask(this, originPoint, rotation, this.getW(), isSubCraft), this); + RotationTask task = new RotationTask(this, originPoint, rotation, this.getW(), isSubCraft); + task.getUpdates().addAll(EntityProcessor.rotateEntities(this, originPoint, rotation)); + Movecraft.getInstance().getAsyncManager().submitTask(task, this); } @Override diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sync/EntityProcessor.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sync/EntityProcessor.java index 59b95840f..d21012031 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sync/EntityProcessor.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sync/EntityProcessor.java @@ -1,30 +1,26 @@ package net.countercraft.movecraft.sync; import net.countercraft.movecraft.MovecraftLocation; +import net.countercraft.movecraft.Rotation; import net.countercraft.movecraft.craft.Craft; import net.countercraft.movecraft.craft.CraftManager; -import net.countercraft.movecraft.mapUpdater.MapUpdateManager; import net.countercraft.movecraft.mapUpdater.update.EntityMoveUpdateCommand; import net.countercraft.movecraft.mapUpdater.update.UpdateCommand; import net.countercraft.movecraft.utils.HashHitBox; +import net.countercraft.movecraft.utils.MathUtils; import org.bukkit.Location; import org.bukkit.entity.Entity; import org.bukkit.entity.EntityType; -import org.bukkit.scheduler.BukkitRunnable; import java.util.LinkedList; -public class EntityProcessor extends BukkitRunnable { - private final Craft craft; - private final MovecraftLocation displacement; +public class EntityProcessor { + + private EntityProcessor(){ - public EntityProcessor(Craft craft, MovecraftLocation displacement) { - this.craft = craft; - this.displacement = displacement; } - @Override - public void run() { + public static LinkedList translateEntities(Craft craft, MovecraftLocation displacement) { LinkedList updates = new LinkedList<>(); HashHitBox oldHitBox = craft.getHitBox(); if (craft.getType().getMoveEntities() && !(craft.getSinking() && craft.getType().getOnlyMovePlayers())) { @@ -50,6 +46,36 @@ public void run() { if (!craft.getType().getCruiseOnPilot() && !craft.getSinking()) // not necessary to release cruiseonpilot crafts, because they will already be released CraftManager.getInstance().addReleaseTask(craft); } - MapUpdateManager.getInstance().scheduleUpdates(updates); + return updates; + } + + public static LinkedList rotateEntities(Craft craft, MovecraftLocation originPoint, Rotation rotation){ + //rotate entities in the craft + LinkedList updates = new LinkedList<>(); + HashHitBox oldHitBox = craft.getHitBox(); + Location tOP = new Location(craft.getW(), originPoint.getX(), originPoint.getY(), originPoint.getZ()); + tOP.setX(tOP.getBlockX() + 0.5); + tOP.setZ(tOP.getBlockZ() + 0.5); + + if (craft.getType().getMoveEntities() && !(craft.getSinking() && craft.getType().getOnlyMovePlayers())) { + Location midpoint = new Location( + craft.getW(), + (oldHitBox.getMaxX() + oldHitBox.getMinX())/2.0, + (oldHitBox.getMaxY() + oldHitBox.getMinY())/2.0, + (oldHitBox.getMaxZ() + oldHitBox.getMinZ())/2.0); + for(Entity entity : craft.getW().getNearbyEntities(midpoint, oldHitBox.getXLength()/2.0 + 1, oldHitBox.getYLength()/2.0 + 2, oldHitBox.getZLength()/2.0 + 1)){ + if ((entity.getType() == EntityType.PLAYER && !craft.getSinking()) || !craft.getType().getOnlyMovePlayers()) { + // Player is onboard this craft + + Location adjustedPLoc = entity.getLocation().subtract(tOP); + + double[] rotatedCoords = MathUtils.rotateVecNoRound(rotation, adjustedPLoc.getX(), adjustedPLoc.getZ()); + float newYaw = rotation == Rotation.CLOCKWISE ? 90F : -90F; + EntityMoveUpdateCommand eUp = new EntityMoveUpdateCommand(entity, rotatedCoords[0] + tOP.getX() - entity.getLocation().getX(), 0, rotatedCoords[1] + tOP.getZ() - entity.getLocation().getZ(), newYaw, 0); + updates.add(eUp); + } + } + } + return updates; } } From e56fa3b5ceea2a6b74c08eb03e4c5c2334161407 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Fri, 13 Sep 2019 22:10:46 +0200 Subject: [PATCH 042/304] Fixed air pockets behind crafts --- .../mapUpdater/update/CraftTranslateCommand.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftTranslateCommand.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftTranslateCommand.java index 0be2d7d88..433373dde 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftTranslateCommand.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftTranslateCommand.java @@ -166,6 +166,15 @@ public void doUpdate() { } } + for (MovecraftLocation l : failed){ + MovecraftLocation orig = l.subtract(displacement); + if (craft.getHitBox().contains(orig) || failed.contains(orig)){ + continue; + } + confirmed.add(orig); + + } + //place confirmed blocks if they have been un-phased for (MovecraftLocation location : confirmed) { if (!craft.getPhaseBlocks().containsKey(location)) { From 4feb1452bb2a252b07a8438afc33d91037d42a64 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Sun, 15 Sep 2019 01:06:02 +0200 Subject: [PATCH 043/304] Fixed 1.14 craft types --- .../resources/types/1_14/BigAirship.craft | 340 +++++------------ .../resources/types/1_14/BigSubAirship.craft | 345 +++++------------ .../src/main/resources/types/1_14/Ship.craft | 350 +++++------------- .../resources/types/1_14/SubAirship.craft | 10 +- .../main/resources/types/1_14/Submarine.craft | 342 +++++------------ .../main/resources/types/1_14/Turret.craft | 257 ++++--------- .../main/resources/types/1_14/airship.craft | 170 ++++----- .../main/resources/types/1_14/airskiff.craft | 283 ++++---------- .../main/resources/types/1_14/elevator.craft | 272 ++++---------- 9 files changed, 653 insertions(+), 1716 deletions(-) diff --git a/modules/Movecraft/src/main/resources/types/1_14/BigAirship.craft b/modules/Movecraft/src/main/resources/types/1_14/BigAirship.craft index de85ebe12..d5dcef13f 100644 --- a/modules/Movecraft/src/main/resources/types/1_14/BigAirship.craft +++ b/modules/Movecraft/src/main/resources/types/1_14/BigAirship.craft @@ -2,262 +2,88 @@ name: BigAirship maxSize: 20000 minSize: 10000 allowedBlocks: - #beds - - WHITE_BED - - ORANGE_BED - - MAGENTA_BED - - LIGHT_BLUE_BED - - YELLOW_BED - - LIME_BED - - PINK_BED - - GRAY_BED - - LIGHT_BED - - CYAN_BED - - PURPLE_BED - - BLUE_BED - - BROWN_BED - - GREEN_BED - - RED_BED - - BLACK_BED - #buttons - - ACACIA_BUTTON - - BIRCH_BUTTON - - DARK_OAK_BUTTON - - JUNGLE_BUTTON - - OAK_BUTTON - - SPRUCE_BUTTON - - STONE_BUTTON - #carpets - - WHITE_CARPET - - ORANGE_CARPET - - MAGENTA_CARPET - - LIGHT_BLUE_CARPET - - YELLOW_CARPET - - LIME_CARPET - - PINK_CARPET - - GRAY_CARPET - - LIGHT_CARPET - - CYAN_CARPET - - PURPLE_CARPET - - BLUE_CARPET - - BROWN_CARPET - - GREEN_CARPET - - RED_CARPET - - BLACK_CARPET - #doors - - ACACIA_DOOR - - BIRCH_DOOR - - DARK_OAK_DOOR - - IRON_DOOR - - JUNGLE_DOOR - - OAK_DOOR - - SPRUCE_DOOR - #fences - - ACACIA_FENCE - - BIRCH_FENCE - - DARK_OAK_FENCE - - JUNGLE_FENCE - - OAK_FENCE - - NETHER_BRICK_FENCE - - SPRUCE_FENCE - #fence gates - - ACACIA_FENCE_GATE - - BIRCH_FENCE_GATE - - DARK_OAK_FENCE_GATE - - JUNGLE_FENCE_GATE - - OAK_FENCE_GATE - - SPRUCE_FENCE_GATE - #glass - - GLASS - - WHITE_STAINED_GLASS - - ORANGE_STAINED_GLASS - - MAGENTA_STAINED_GLASS - - LIGHT_BLUE_STAINED_GLASS - - YELLOW_STAINED_GLASS - - LIME_STAINED_GLASS - - PINK_STAINED_GLASS - - GRAY_STAINED_GLASS - - LIGHT_GRAY_STAINED_GLASS - - CYAN_STAINED_GLASS - - PURPLE_STAINED_GLASS - - BLUE_STAINED_GLASS - - BROWN_STAINED_GLASS - - GREEN_STAINED_GLASS - - RED_STAINED_GLASS - - BLACK_STAINED_GLASS - #glass pane - - GLASS_PANE - - WHITE_STAINED_GLASS_PANE - - ORANGE_STAINED_GLASS_PANE - - MAGENTA_STAINED_GLASS_PANE - - LIGHT_BLUE_STAINED_GLASS_PANE - - YELLOW_STAINED_GLASS_PANE - - LIME_STAINED_GLASS_PANE - - PINK_STAINED_GLASS_PANE - - GRAY_STAINED_GLASS_PANE - - LIGHT_GRAY_STAINED_GLASS_PANE - - CYAN_STAINED_GLASS_PANE - - PURPLE_STAINED_GLASS_PANE - - BLUE_STAINED_GLASS_PANE - - BROWN_STAINED_GLASS_PANE - - GREEN_STAINED_GLASS_PANE - - RED_STAINED_GLASS_PANE - - BLACK_STAINED_GLASS_PANE - #liquids - - LAVA - - WATER - #logs - - BIRCH_LOG - - JUNGLE_LOG - - OAK_LOG - - SPRUCE_LOG - - STRIPPED_BIRCH_LOG - - STRIPPED_JUNGLE_LOG - - STRIPPED_OAK_LOG - - STRIPPED_SPRUCE_LOG - #misc - - BOOKSHELF - - BREWING_STAND - - CRAFTING_TABLE - - CAULDRON - - FURNACE - - GLOWSTONE - - IRON_BARS - - LADDER - - NETHER_BRICKS - - TORCH - - WALL_TORCH - #planks - - ACACIA_PLANKS - - BIRCH_PLANKS - - DARK_OAK_PLANKS - - JUNGLE_PLANKS - - OAK_PLANKS - - SPRUCE_PLANKS - #pressure plates - - ACACIA_PRESSURE_PLATE - - BIRCH_PRESSURE_PLATE - - DARK_OAK_PRESSURE_PLATE - - HEAVY_WEIGHTED_PRESSURE_PLATE - - JUNGLE_PRESSURE_PLATE - - LIGHT_WEIGHTED_PRESSURE_PLATE - - OAK_PRESSURE_PLATE - - SPRUCE_PRESSURE_PLATE - - STONE_PRESSURE_PLATE - #redstone - - COMPARATOR - - LEVER - - NOTE_BLOCK - - PISTON - - PISTON_HEAD - - REDSTONE_BLOCK - - REDSTONE_WIRE - - REPEATER - - REDSTONE_TORCH - - REDSTONE_WALL_TORCH - - STICKY_PISTON - - TRIPWIRE_HOOK - #signs - - ACACIA_SIGN - - ACACIA_WALL_SIGN - - BIRCH_SIGN - - BIRCH_WALL_SIGN - - DARK_OAK_SIGN - - DARK_OAK_WALL_SIGN - - JUNGLE_SIGN - - JUNGLE_WALL_SIGN - - OAK_SIGN - - OAK_WALL_SIGN - - SPRUCE_SIGN - - SPRUCE_WALL_SIGN - #slabs - - ACACIA_SLAB - - BIRCH_SLAB - - BRICK_SLAB - - COBBLESTONE_SLAB - - DARK_OAK_SLAB - - DARK_PRISMARINE - - JUNGLE_SLAB - - NETHER_BRICK_SLAB - - OAK_SLAB - - PETRIFIED_OAK_SLAB - - PRISMARINE_SLAB - - PRISMARINE_BRICK_SLAB - - RED_SANDSTONE_SLAB - - QUARTZ_SLAB - - SPRUCE_SLAB - - STONE_SLAB - #stairs - - BIRCH_STAIRS - - JUNGLE_STAIRS - - OAK_STAIRS - - NETHER_BRICK_STAIRS - - SMOOTH_STAIRS - - SPRUCE_STAIRS - - STONE_BRICK_STAIRS - #storage - - CHEST - - DISPENSER - - DROPPER - - HOPPER - - TRAPPED_CHEST - #terracotta - - WHITE_TERRACOTTA - - ORANGE_TERRACOTTA - - MAGENTA_TERRACOTTA - - LIGHT_BLUE_TERRACOTTA - - YELLOW_TERRACOTTA - - LIME_TERRACOTTA - - PINK_TERRACOTTA - - GRAY_TERRACOTTA - - LIGHT_GRAY_TERRACOTTA - - CYAN_TERRACOTTA - - PURPLE_TERRACOTTA - - BLUE_TERRACOTTA - - BROWN_TERRACOTTA - - GREEN_TERRACOTTA - - RED_TERRACOTTA - - BLACK_TERRACOTTA - #trapdoors - - ACACIA_TRAPDOOR - - BIRCH_TRAPDOOR - - DARK_OAK_TRAPDOOR - - JUNGLE_TRAPDOOR - - OAK_TRAPDOOR - - SPRUCE_TRAPDOOR - #weapon blocks - - COAL_BLOCK - #wood - - ACACIA_WOOD - - BIRCH_WOOD - - DARK_OAK_WOOD - - OAK_WOOD - - SPRUCE_WOOD - - STRIPPED_ACACIA_WOOD - - STRIPPED_BIRCH_WOOD - - STRIPPED_DARK_OAK_WOOD - - STRIPPED_OAK_WOOD - - STRIPPED_SPRUCE_WOOD - #wool - - WHITE_WOOL - - ORANGE_WOOL - - MAGENTA_WOOL - - LIGHT_BLUE_WOOL - - YELLOW_WOOL - - LIME_WOOL - - PINK_WOOL - - GRAY_WOOL - - LIGHT_GRAY_WOOL - - CYAN_WOOL - - PURPLE_WOOL - - BLUE_WOOL - - BROWN_WOOL - - GREEN_WOOL - - RED_WOOL - - BLACK_WOOL - - - + - crafting_table + - ALL_WOOD + - WATER + - LAVA + - ALL_LOG + - all_planks + - GLASS + - LAPIS_BLOCK + - DISPENSER + - NOTE_BLOCK + - ALL_BED + - sticky_piston + - piston + - all_wool + - GOLD_BLOCK + - IRON_BLOCK + - all_slab + - BOOKSHELF + - TORCH + - FIRE + - oak_stairs + - birch_stairs + - jungle_stairs + - spruce_stairs + - stone_brick_stairs + - quartz_stairs + - nether_brick_stairs + - chest + - redstone_wire + - diamond_block + - nether_brick_stairs + - furnace + - all_sign + - ladder + - all_door + - lever + - all_pressure_plate + - redstone_torch + - redstone_wall_torch + - all_button + - clay + - all_fence + - netherrack + - glowstone + - cake + - repeater + - all_stained_glass + - all_trapdoor + - all_stone_bricks + - iron_bars + - glass_pane + - all_fence_gate + - nether_brick + - enchantment_table + - brewing_stand + - cauldron + - end_stone + - dragon_egg + - redstone_lamp + - ender chest + - TRIPWIRE_HOOK + - EMERALD_BLOCK + - BEACON + - cobblestone_wall + - mossy_cobblestone_wall + - FLOWER_POT + - SKULL + - all_ANVIL + - TRAPPED_CHEST + - COMPARATOR + - daylight_detector + - REDSTONE_BLOCK + - HOPPER + - all_QUARTZ_BLOCK + - all_rail + - DROPPER + - ALL_TERRACOTTA + - ALL_STAINED_GLASS_PANE + - SLIME_BLOCK + - ALL_CARPET + - COAL_BLOCK + - END_STONE_BRICKS canCruise: true rotateAtMidpoint: true blockRemoteRotate: true @@ -282,7 +108,7 @@ moveblocks: - 1.0 - 100.0 flyblocks: - [WHITE_WOOL, ORANGE_WOOL, MAGENTA_WOOL,LIGHT_BLUE_WOOL,YELLOW_WOOL,LIME_WOOL,PINK_WOOL,GRAY_WOOL,LIGHT_GRAY_WOOL,CYAN_WOOL,PURPLE_WOOL,BLUE_WOOL,BROWN_WOOL, GREEN_WOOL, RED_WOOL, BLACK_WOOL]: #wool represents lift + all_wool: #wool represents lift - 50.0 - 100.0 [CHEST,TRAPPED_CHEST]: # limit chests to make big airships important for merchant missions diff --git a/modules/Movecraft/src/main/resources/types/1_14/BigSubAirship.craft b/modules/Movecraft/src/main/resources/types/1_14/BigSubAirship.craft index d2eaac321..e0a43c22b 100644 --- a/modules/Movecraft/src/main/resources/types/1_14/BigSubAirship.craft +++ b/modules/Movecraft/src/main/resources/types/1_14/BigSubAirship.craft @@ -2,260 +2,88 @@ name: BigSubAirship maxSize: 20000 minSize: 10000 allowedBlocks: - #beds - - WHITE_BED - - ORANGE_BED - - MAGENTA_BED - - LIGHT_BLUE_BED - - YELLOW_BED - - LIME_BED - - PINK_BED - - GRAY_BED - - LIGHT_BED - - CYAN_BED - - PURPLE_BED - - BLUE_BED - - BROWN_BED - - GREEN_BED - - RED_BED - - BLACK_BED - #buttons - - ACACIA_BUTTON - - BIRCH_BUTTON - - DARK_OAK_BUTTON - - JUNGLE_BUTTON - - OAK_BUTTON - - SPRUCE_BUTTON - - STONE_BUTTON - #carpets - - WHITE_CARPET - - ORANGE_CARPET - - MAGENTA_CARPET - - LIGHT_BLUE_CARPET - - YELLOW_CARPET - - LIME_CARPET - - PINK_CARPET - - GRAY_CARPET - - LIGHT_CARPET - - CYAN_CARPET - - PURPLE_CARPET - - BLUE_CARPET - - BROWN_CARPET - - GREEN_CARPET - - RED_CARPET - - BLACK_CARPET - #doors - - ACACIA_DOOR - - BIRCH_DOOR - - DARK_OAK_DOOR - - IRON_DOOR - - JUNGLE_DOOR - - OAK_DOOR - - SPRUCE_DOOR - #fences - - ACACIA_FENCE - - BIRCH_FENCE - - DARK_OAK_FENCE - - JUNGLE_FENCE - - OAK_FENCE - - NETHER_BRICK_FENCE - - SPRUCE_FENCE - #fence gates - - ACACIA_FENCE_GATE - - BIRCH_FENCE_GATE - - DARK_OAK_FENCE_GATE - - JUNGLE_FENCE_GATE - - OAK_FENCE_GATE - - SPRUCE_FENCE_GATE - #glass - - GLASS - - WHITE_STAINED_GLASS - - ORANGE_STAINED_GLASS - - MAGENTA_STAINED_GLASS - - LIGHT_BLUE_STAINED_GLASS - - YELLOW_STAINED_GLASS - - LIME_STAINED_GLASS - - PINK_STAINED_GLASS - - GRAY_STAINED_GLASS - - LIGHT_GRAY_STAINED_GLASS - - CYAN_STAINED_GLASS - - PURPLE_STAINED_GLASS - - BLUE_STAINED_GLASS - - BROWN_STAINED_GLASS - - GREEN_STAINED_GLASS - - RED_STAINED_GLASS - - BLACK_STAINED_GLASS - #glass pane - - GLASS_PANE - - WHITE_STAINED_GLASS_PANE - - ORANGE_STAINED_GLASS_PANE - - MAGENTA_STAINED_GLASS_PANE - - LIGHT_BLUE_STAINED_GLASS_PANE - - YELLOW_STAINED_GLASS_PANE - - LIME_STAINED_GLASS_PANE - - PINK_STAINED_GLASS_PANE - - GRAY_STAINED_GLASS_PANE - - LIGHT_GRAY_STAINED_GLASS_PANE - - CYAN_STAINED_GLASS_PANE - - PURPLE_STAINED_GLASS_PANE - - BLUE_STAINED_GLASS_PANE - - BROWN_STAINED_GLASS_PANE - - GREEN_STAINED_GLASS_PANE - - RED_STAINED_GLASS_PANE - - BLACK_STAINED_GLASS_PANE - #liquids - - LAVA - - WATER - #logs - - BIRCH_LOG - - JUNGLE_LOG - - OAK_LOG - - SPRUCE_LOG - - STRIPPED_BIRCH_LOG - - STRIPPED_JUNGLE_LOG - - STRIPPED_OAK_LOG - - STRIPPED_SPRUCE_LOG - #misc - - BOOKSHELF - - BREWING_STAND - - CRAFTING_TABLE - - CAULDRON - - FURNACE - - GLOWSTONE - - IRON_BARS - - LADDER - - NETHER_BRICKS - - TORCH - - WALL_TORCH - #planks - - ACACIA_PLANKS - - BIRCH_PLANKS - - DARK_OAK_PLANKS - - JUNGLE_PLANKS - - OAK_PLANKS - - SPRUCE_PLANKS - #pressure plates - - ACACIA_PRESSURE_PLATE - - BIRCH_PRESSURE_PLATE - - DARK_OAK_PRESSURE_PLATE - - HEAVY_WEIGHTED_PRESSURE_PLATE - - JUNGLE_PRESSURE_PLATE - - LIGHT_WEIGHTED_PRESSURE_PLATE - - OAK_PRESSURE_PLATE - - SPRUCE_PRESSURE_PLATE - - STONE_PRESSURE_PLATE - #redstone - - COMPARATOR - - LEVER - - NOTE_BLOCK - - PISTON - - PISTON_HEAD - - REDSTONE_BLOCK - - REDSTONE_WIRE - - REPEATER - - REDSTONE_TORCH - - REDSTONE_WALL_TORCH - - STICKY_PISTON - - TRIPWIRE_HOOK - #signs - - ACACIA_SIGN - - ACACIA_WALL_SIGN - - BIRCH_SIGN - - BIRCH_WALL_SIGN - - DARK_OAK_SIGN - - DARK_OAK_WALL_SIGN - - JUNGLE_SIGN - - JUNGLE_WALL_SIGN - - OAK_SIGN - - OAK_WALL_SIGN - - SPRUCE_SIGN - - SPRUCE_WALL_SIGN - #slabs - - ACACIA_SLAB - - BIRCH_SLAB - - BRICK_SLAB - - COBBLESTONE_SLAB - - DARK_OAK_SLAB - - DARK_PRISMARINE - - JUNGLE_SLAB - - NETHER_BRICK_SLAB - - OAK_SLAB - - PETRIFIED_OAK_SLAB - - PRISMARINE_SLAB - - PRISMARINE_BRICK_SLAB - - RED_SANDSTONE_SLAB - - QUARTZ_SLAB - - SPRUCE_SLAB - - STONE_SLAB - #stairs - - BIRCH_STAIRS - - JUNGLE_STAIRS - - OAK_STAIRS - - NETHER_BRICK_STAIRS - - SMOOTH_STAIRS - - SPRUCE_STAIRS - - STONE_BRICK_STAIRS - #storage - - CHEST - - DISPENSER - - DROPPER - - HOPPER - - TRAPPED_CHEST - #terracotta - - WHITE_TERRACOTTA - - ORANGE_TERRACOTTA - - MAGENTA_TERRACOTTA - - LIGHT_BLUE_TERRACOTTA - - YELLOW_TERRACOTTA - - LIME_TERRACOTTA - - PINK_TERRACOTTA - - GRAY_TERRACOTTA - - LIGHT_GRAY_TERRACOTTA - - CYAN_TERRACOTTA - - PURPLE_TERRACOTTA - - BLUE_TERRACOTTA - - BROWN_TERRACOTTA - - GREEN_TERRACOTTA - - RED_TERRACOTTA - - BLACK_TERRACOTTA - #trapdoors - - ACACIA_TRAPDOOR - - BIRCH_TRAPDOOR - - DARK_OAK_TRAPDOOR - - JUNGLE_TRAPDOOR - - OAK_TRAPDOOR - - SPRUCE_TRAPDOOR - #weapon blocks - - COAL_BLOCK - #wood - - ACACIA_WOOD - - BIRCH_WOOD - - DARK_OAK_WOOD - - OAK_WOOD - - SPRUCE_WOOD - - STRIPPED_ACACIA_WOOD - - STRIPPED_BIRCH_WOOD - - STRIPPED_DARK_OAK_WOOD - - STRIPPED_OAK_WOOD - - STRIPPED_SPRUCE_WOOD - #wool - - WHITE_WOOL - - ORANGE_WOOL - - MAGENTA_WOOL - - LIGHT_BLUE_WOOL - - YELLOW_WOOL - - LIME_WOOL - - PINK_WOOL - - GRAY_WOOL - - LIGHT_GRAY_WOOL - - CYAN_WOOL - - PURPLE_WOOL - - BLUE_WOOL - - BROWN_WOOL - - GREEN_WOOL - - RED_WOOL - - BLACK_WOOL - + - crafting_table + - ALL_WOOD + - WATER + - LAVA + - ALL_LOG + - all_planks + - GLASS + - LAPIS_BLOCK + - DISPENSER + - NOTE_BLOCK + - ALL_BED + - sticky_piston + - piston + - all_wool + - GOLD_BLOCK + - IRON_BLOCK + - all_slab + - BOOKSHELF + - TORCH + - FIRE + - oak_stairs + - birch_stairs + - jungle_stairs + - spruce_stairs + - stone_brick_stairs + - quartz_stairs + - nether_brick_stairs + - chest + - redstone_wire + - diamond_block + - nether_brick_stairs + - furnace + - all_sign + - ladder + - all_door + - lever + - all_pressure_plate + - redstone_torch + - redstone_wall_torch + - all_button + - clay + - all_fence + - netherrack + - glowstone + - cake + - repeater + - all_stained_glass + - all_trapdoor + - all_stone_bricks + - iron_bars + - glass_pane + - all_fence_gate + - nether_brick + - enchantment_table + - brewing_stand + - cauldron + - end_stone + - dragon_egg + - redstone_lamp + - ender chest + - TRIPWIRE_HOOK + - EMERALD_BLOCK + - BEACON + - cobblestone_wall + - mossy_cobblestone_wall + - FLOWER_POT + - SKULL + - all_ANVIL + - TRAPPED_CHEST + - COMPARATOR + - daylight_detector + - REDSTONE_BLOCK + - HOPPER + - all_QUARTZ_BLOCK + - all_rail + - DROPPER + - ALL_TERRACOTTA + - ALL_STAINED_GLASS_PANE + - SLIME_BLOCK + - ALL_CARPET + - COAL_BLOCK + - END_STONE_BRICKS canCruise: true rotateAtMidpoint: true blockRemoteRotate: true @@ -275,6 +103,13 @@ tryNudge: false sinkPercent: 99.0 overallSinkPercent: 60.0 halfSpeedUnderwater: true + +passthroughBlocks: + - kelp + - kelp_plant + - tall_seagrass + - seagrass + - bubble_column moveblocks: REDSTONE_BLOCK: # redstone represents engines - 1.0 @@ -283,7 +118,7 @@ flyblocks: IRON_BLOCK: # iron represents ballast tanks - 10.0 - 100.0 - [WHITE_WOOL, ORANGE_WOOL, MAGENTA_WOOL,LIGHT_BLUE_WOOL,YELLOW_WOOL,LIME_WOOL,PINK_WOOL,GRAY_WOOL,LIGHT_GRAY_WOOL,CYAN_WOOL,PURPLE_WOOL,BLUE_WOOL,BROWN_WOOL, GREEN_WOOL, RED_WOOL, BLACK_WOOL]: #wool represents lift + all_wool: #wool represents lift - 50.0 - 100.0 [CHEST,TRAPPED_CHEST]: # limit chests to make big airships important for merchant missions diff --git a/modules/Movecraft/src/main/resources/types/1_14/Ship.craft b/modules/Movecraft/src/main/resources/types/1_14/Ship.craft index cdbc6145c..b4411d0d9 100644 --- a/modules/Movecraft/src/main/resources/types/1_14/Ship.craft +++ b/modules/Movecraft/src/main/resources/types/1_14/Ship.craft @@ -2,260 +2,87 @@ name: Ship maxSize: 100000 minSize: 10 allowedBlocks: -#beds - - WHITE_BED - - ORANGE_BED - - MAGENTA_BED - - LIGHT_BLUE_BED - - YELLOW_BED - - LIME_BED - - PINK_BED - - GRAY_BED - - LIGHT_BED - - CYAN_BED - - PURPLE_BED - - BLUE_BED - - BROWN_BED - - GREEN_BED - - RED_BED - - BLACK_BED - #buttons - - ACACIA_BUTTON - - BIRCH_BUTTON - - DARK_OAK_BUTTON - - JUNGLE_BUTTON - - OAK_BUTTON - - SPRUCE_BUTTON - - STONE_BUTTON - #carpets - - WHITE_CARPET - - ORANGE_CARPET - - MAGENTA_CARPET - - LIGHT_BLUE_CARPET - - YELLOW_CARPET - - LIME_CARPET - - PINK_CARPET - - GRAY_CARPET - - LIGHT_CARPET - - CYAN_CARPET - - PURPLE_CARPET - - BLUE_CARPET - - BROWN_CARPET - - GREEN_CARPET - - RED_CARPET - - BLACK_CARPET - #doors - - ACACIA_DOOR - - BIRCH_DOOR - - DARK_OAK_DOOR - - IRON_DOOR - - JUNGLE_DOOR - - OAK_DOOR - - SPRUCE_DOOR - #fences - - ACACIA_FENCE - - BIRCH_FENCE - - DARK_OAK_FENCE - - JUNGLE_FENCE - - OAK_FENCE - - NETHER_BRICK_FENCE - - SPRUCE_FENCE - #fence gates - - ACACIA_FENCE_GATE - - BIRCH_FENCE_GATE - - DARK_OAK_FENCE_GATE - - JUNGLE_FENCE_GATE - - OAK_FENCE_GATE - - SPRUCE_FENCE_GATE - #glass - - GLASS - - WHITE_STAINED_GLASS - - ORANGE_STAINED_GLASS - - MAGENTA_STAINED_GLASS - - LIGHT_BLUE_STAINED_GLASS - - YELLOW_STAINED_GLASS - - LIME_STAINED_GLASS - - PINK_STAINED_GLASS - - GRAY_STAINED_GLASS - - LIGHT_GRAY_STAINED_GLASS - - CYAN_STAINED_GLASS - - PURPLE_STAINED_GLASS - - BLUE_STAINED_GLASS - - BROWN_STAINED_GLASS - - GREEN_STAINED_GLASS - - RED_STAINED_GLASS - - BLACK_STAINED_GLASS - #glass pane - - GLASS_PANE - - WHITE_STAINED_GLASS_PANE - - ORANGE_STAINED_GLASS_PANE - - MAGENTA_STAINED_GLASS_PANE - - LIGHT_BLUE_STAINED_GLASS_PANE - - YELLOW_STAINED_GLASS_PANE - - LIME_STAINED_GLASS_PANE - - PINK_STAINED_GLASS_PANE - - GRAY_STAINED_GLASS_PANE - - LIGHT_GRAY_STAINED_GLASS_PANE - - CYAN_STAINED_GLASS_PANE - - PURPLE_STAINED_GLASS_PANE - - BLUE_STAINED_GLASS_PANE - - BROWN_STAINED_GLASS_PANE - - GREEN_STAINED_GLASS_PANE - - RED_STAINED_GLASS_PANE - - BLACK_STAINED_GLASS_PANE - #liquids - - LAVA - - WATER - #logs - - BIRCH_LOG - - JUNGLE_LOG - - OAK_LOG - - SPRUCE_LOG - - STRIPPED_BIRCH_LOG - - STRIPPED_JUNGLE_LOG - - STRIPPED_OAK_LOG - - STRIPPED_SPRUCE_LOG - #misc - - BOOKSHELF - - BREWING_STAND - - CRAFTING_TABLE - - CAULDRON - - FURNACE - - GLOWSTONE - - IRON_BARS - - LADDER - - NETHER_BRICKS - - TORCH - - WALL_TORCH - #planks - - ACACIA_PLANKS - - BIRCH_PLANKS - - DARK_OAK_PLANKS - - JUNGLE_PLANKS - - OAK_PLANKS - - SPRUCE_PLANKS - #pressure plates - - ACACIA_PRESSURE_PLATE - - BIRCH_PRESSURE_PLATE - - DARK_OAK_PRESSURE_PLATE - - HEAVY_WEIGHTED_PRESSURE_PLATE - - JUNGLE_PRESSURE_PLATE - - LIGHT_WEIGHTED_PRESSURE_PLATE - - OAK_PRESSURE_PLATE - - SPRUCE_PRESSURE_PLATE - - STONE_PRESSURE_PLATE - #redstone - - COMPARATOR - - LEVER - - NOTE_BLOCK - - PISTON - - PISTON_HEAD - - REDSTONE_BLOCK - - REDSTONE_WIRE - - REPEATER - - REDSTONE_TORCH - - REDSTONE_WALL_TORCH - - STICKY_PISTON - - TRIPWIRE_HOOK - #signs - - ACACIA_SIGN - - ACACIA_WALL_SIGN - - BIRCH_SIGN - - BIRCH_WALL_SIGN - - DARK_OAK_SIGN - - DARK_OAK_WALL_SIGN - - JUNGLE_SIGN - - JUNGLE_WALL_SIGN - - OAK_SIGN - - OAK_WALL_SIGN - - SPRUCE_SIGN - - SPRUCE_WALL_SIGN - #slabs - - ACACIA_SLAB - - BIRCH_SLAB - - BRICK_SLAB - - COBBLESTONE_SLAB - - DARK_OAK_SLAB - - DARK_PRISMARINE - - JUNGLE_SLAB - - NETHER_BRICK_SLAB - - OAK_SLAB - - PETRIFIED_OAK_SLAB - - PRISMARINE_SLAB - - PRISMARINE_BRICK_SLAB - - RED_SANDSTONE_SLAB - - QUARTZ_SLAB - - SPRUCE_SLAB - - STONE_SLAB - #stairs - - BIRCH_STAIRS - - JUNGLE_STAIRS - - OAK_STAIRS - - NETHER_BRICK_STAIRS - - SMOOTH_STAIRS - - SPRUCE_STAIRS - - STONE_BRICK_STAIRS - #storage - - CHEST - - DISPENSER - - DROPPER - - HOPPER - - TRAPPED_CHEST - #terracotta - - WHITE_TERRACOTTA - - ORANGE_TERRACOTTA - - MAGENTA_TERRACOTTA - - LIGHT_BLUE_TERRACOTTA - - YELLOW_TERRACOTTA - - LIME_TERRACOTTA - - PINK_TERRACOTTA - - GRAY_TERRACOTTA - - LIGHT_GRAY_TERRACOTTA - - CYAN_TERRACOTTA - - PURPLE_TERRACOTTA - - BLUE_TERRACOTTA - - BROWN_TERRACOTTA - - GREEN_TERRACOTTA - - RED_TERRACOTTA - - BLACK_TERRACOTTA - #trapdoors - - ACACIA_TRAPDOOR - - BIRCH_TRAPDOOR - - DARK_OAK_TRAPDOOR - - JUNGLE_TRAPDOOR - - OAK_TRAPDOOR - - SPRUCE_TRAPDOOR - #weapon blocks - - COAL_BLOCK - #wood - - ACACIA_WOOD - - BIRCH_WOOD - - DARK_OAK_WOOD - - OAK_WOOD - - SPRUCE_WOOD - - STRIPPED_ACACIA_WOOD - - STRIPPED_BIRCH_WOOD - - STRIPPED_DARK_OAK_WOOD - - STRIPPED_OAK_WOOD - - STRIPPED_SPRUCE_WOOD - #wool - - WHITE_WOOL - - ORANGE_WOOL - - MAGENTA_WOOL - - LIGHT_BLUE_WOOL - - YELLOW_WOOL - - LIME_WOOL - - PINK_WOOL - - GRAY_WOOL - - LIGHT_GRAY_WOOL - - CYAN_WOOL - - PURPLE_WOOL - - BLUE_WOOL - - BROWN_WOOL - - GREEN_WOOL - - RED_WOOL - - BLACK_WOOL - + - crafting_table + - ALL_WOOD + - LAVA + - ALL_LOG + - all_planks + - GLASS + - LAPIS_BLOCK + - DISPENSER + - NOTE_BLOCK + - ALL_BED + - sticky_piston + - piston + - all_wool + - GOLD_BLOCK + - IRON_BLOCK + - all_slab + - BOOKSHELF + - TORCH + - FIRE + - oak_stairs + - birch_stairs + - jungle_stairs + - spruce_stairs + - stone_brick_stairs + - quartz_stairs + - nether_brick_stairs + - chest + - redstone_wire + - diamond_block + - nether_brick_stairs + - furnace + - all_sign + - ladder + - all_door + - lever + - all_pressure_plate + - redstone_torch + - redstone_wall_torch + - all_button + - clay + - all_fence + - netherrack + - glowstone + - cake + - repeater + - all_stained_glass + - all_trapdoor + - all_stone_bricks + - iron_bars + - glass_pane + - all_fence_gate + - nether_brick + - enchantment_table + - brewing_stand + - cauldron + - end_stone + - dragon_egg + - redstone_lamp + - ender chest + - TRIPWIRE_HOOK + - EMERALD_BLOCK + - BEACON + - cobblestone_wall + - mossy_cobblestone_wall + - FLOWER_POT + - SKULL + - all_ANVIL + - TRAPPED_CHEST + - COMPARATOR + - daylight_detector + - REDSTONE_BLOCK + - HOPPER + - all_QUARTZ_BLOCK + - all_rail + - DROPPER + - ALL_TERRACOTTA + - ALL_STAINED_GLASS_PANE + - SLIME_BLOCK + - ALL_CARPET + - COAL_BLOCK + - END_STONE_BRICKS canCruise: true cruiseSkipBlocks: 4 canFly: false @@ -267,16 +94,19 @@ requireWaterContact: true allowVerticalMovement: false speed: 0.5 tryNudge: false +passthroughBlocks: + - kelp + - kelp_plant + - tall_seagrass + - seagrass + - bubble_column flyblocks: - 5: + all_planks: - 25.0 - 100.0 - 145: # anvils are OP armor, so limit it + all_anvils: # anvils are OP armor, so limit it - 0.0 - 1.0 - 49: # so is obsidian - - 0.0 - - 1.0 - 8: # so is water + obsidian: # so is obsidian - 0.0 - 1.0 diff --git a/modules/Movecraft/src/main/resources/types/1_14/SubAirship.craft b/modules/Movecraft/src/main/resources/types/1_14/SubAirship.craft index 702587eae..2035a1f07 100644 --- a/modules/Movecraft/src/main/resources/types/1_14/SubAirship.craft +++ b/modules/Movecraft/src/main/resources/types/1_14/SubAirship.craft @@ -4,7 +4,6 @@ minSize: 1000 allowedBlocks: - crafting_table - ALL_WOOD - - WATER - LAVA - ALL_LOG - all_planks @@ -102,8 +101,15 @@ tryNudge: false halfSpeedUnderwater: true sinkPercent: 99.0 overallSinkPercent: 60.0 + +passthroughBlocks: + - kelp + - kelp_plant + - tall_seagrass + - seagrass + - bubble_column moveblocks: - 152: # redstone represents engines + redstone_block: # redstone represents engines - 1.0 - 100.0 flyblocks: diff --git a/modules/Movecraft/src/main/resources/types/1_14/Submarine.craft b/modules/Movecraft/src/main/resources/types/1_14/Submarine.craft index ce3189fba..df77f0a13 100644 --- a/modules/Movecraft/src/main/resources/types/1_14/Submarine.craft +++ b/modules/Movecraft/src/main/resources/types/1_14/Submarine.craft @@ -2,260 +2,87 @@ name: Submarine maxSize: 100000 minSize: 10 allowedBlocks: - #beds - - WHITE_BED - - ORANGE_BED - - MAGENTA_BED - - LIGHT_BLUE_BED - - YELLOW_BED - - LIME_BED - - PINK_BED - - GRAY_BED - - LIGHT_BED - - CYAN_BED - - PURPLE_BED - - BLUE_BED - - BROWN_BED - - GREEN_BED - - RED_BED - - BLACK_BED - #buttons - - ACACIA_BUTTON - - BIRCH_BUTTON - - DARK_OAK_BUTTON - - JUNGLE_BUTTON - - OAK_BUTTON - - SPRUCE_BUTTON - - STONE_BUTTON - #carpets - - WHITE_CARPET - - ORANGE_CARPET - - MAGENTA_CARPET - - LIGHT_BLUE_CARPET - - YELLOW_CARPET - - LIME_CARPET - - PINK_CARPET - - GRAY_CARPET - - LIGHT_CARPET - - CYAN_CARPET - - PURPLE_CARPET - - BLUE_CARPET - - BROWN_CARPET - - GREEN_CARPET - - RED_CARPET - - BLACK_CARPET - #doors - - ACACIA_DOOR - - BIRCH_DOOR - - DARK_OAK_DOOR - - IRON_DOOR - - JUNGLE_DOOR - - OAK_DOOR - - SPRUCE_DOOR - #fences - - ACACIA_FENCE - - BIRCH_FENCE - - DARK_OAK_FENCE - - JUNGLE_FENCE - - OAK_FENCE - - NETHER_BRICK_FENCE - - SPRUCE_FENCE - #fence gates - - ACACIA_FENCE_GATE - - BIRCH_FENCE_GATE - - DARK_OAK_FENCE_GATE - - JUNGLE_FENCE_GATE - - OAK_FENCE_GATE - - SPRUCE_FENCE_GATE - #glass - - GLASS - - WHITE_STAINED_GLASS - - ORANGE_STAINED_GLASS - - MAGENTA_STAINED_GLASS - - LIGHT_BLUE_STAINED_GLASS - - YELLOW_STAINED_GLASS - - LIME_STAINED_GLASS - - PINK_STAINED_GLASS - - GRAY_STAINED_GLASS - - LIGHT_GRAY_STAINED_GLASS - - CYAN_STAINED_GLASS - - PURPLE_STAINED_GLASS - - BLUE_STAINED_GLASS - - BROWN_STAINED_GLASS - - GREEN_STAINED_GLASS - - RED_STAINED_GLASS - - BLACK_STAINED_GLASS - #glass pane - - GLASS_PANE - - WHITE_STAINED_GLASS_PANE - - ORANGE_STAINED_GLASS_PANE - - MAGENTA_STAINED_GLASS_PANE - - LIGHT_BLUE_STAINED_GLASS_PANE - - YELLOW_STAINED_GLASS_PANE - - LIME_STAINED_GLASS_PANE - - PINK_STAINED_GLASS_PANE - - GRAY_STAINED_GLASS_PANE - - LIGHT_GRAY_STAINED_GLASS_PANE - - CYAN_STAINED_GLASS_PANE - - PURPLE_STAINED_GLASS_PANE - - BLUE_STAINED_GLASS_PANE - - BROWN_STAINED_GLASS_PANE - - GREEN_STAINED_GLASS_PANE - - RED_STAINED_GLASS_PANE - - BLACK_STAINED_GLASS_PANE - #liquids - - LAVA - - WATER - #logs - - BIRCH_LOG - - JUNGLE_LOG - - OAK_LOG - - SPRUCE_LOG - - STRIPPED_BIRCH_LOG - - STRIPPED_JUNGLE_LOG - - STRIPPED_OAK_LOG - - STRIPPED_SPRUCE_LOG - #misc - - BOOKSHELF - - BREWING_STAND - - CRAFTING_TABLE - - CAULDRON - - FURNACE - - GLOWSTONE - - IRON_BARS - - LADDER - - NETHER_BRICKS - - TORCH - - WALL_TORCH - #planks - - ACACIA_PLANKS - - BIRCH_PLANKS - - DARK_OAK_PLANKS - - JUNGLE_PLANKS - - OAK_PLANKS - - SPRUCE_PLANKS - #pressure plates - - ACACIA_PRESSURE_PLATE - - BIRCH_PRESSURE_PLATE - - DARK_OAK_PRESSURE_PLATE - - HEAVY_WEIGHTED_PRESSURE_PLATE - - JUNGLE_PRESSURE_PLATE - - LIGHT_WEIGHTED_PRESSURE_PLATE - - OAK_PRESSURE_PLATE - - SPRUCE_PRESSURE_PLATE - - STONE_PRESSURE_PLATE - #redstone - - COMPARATOR - - LEVER - - NOTE_BLOCK - - PISTON - - PISTON_HEAD - - REDSTONE_BLOCK - - REDSTONE_WIRE - - REPEATER - - REDSTONE_TORCH - - REDSTONE_WALL_TORCH - - STICKY_PISTON - - TRIPWIRE_HOOK - #signs - - ACACIA_SIGN - - ACACIA_WALL_SIGN - - BIRCH_SIGN - - BIRCH_WALL_SIGN - - DARK_OAK_SIGN - - DARK_OAK_WALL_SIGN - - JUNGLE_SIGN - - JUNGLE_WALL_SIGN - - OAK_SIGN - - OAK_WALL_SIGN - - SPRUCE_SIGN - - SPRUCE_WALL_SIGN - #slabs - - ACACIA_SLAB - - BIRCH_SLAB - - BRICK_SLAB - - COBBLESTONE_SLAB - - DARK_OAK_SLAB - - DARK_PRISMARINE - - JUNGLE_SLAB - - NETHER_BRICK_SLAB - - OAK_SLAB - - PETRIFIED_OAK_SLAB - - PRISMARINE_SLAB - - PRISMARINE_BRICK_SLAB - - RED_SANDSTONE_SLAB - - QUARTZ_SLAB - - SPRUCE_SLAB - - STONE_SLAB - #stairs - - BIRCH_STAIRS - - JUNGLE_STAIRS - - OAK_STAIRS - - NETHER_BRICK_STAIRS - - SMOOTH_STAIRS - - SPRUCE_STAIRS - - STONE_BRICK_STAIRS - #storage - - CHEST - - DISPENSER - - DROPPER - - HOPPER - - TRAPPED_CHEST - #terracotta - - WHITE_TERRACOTTA - - ORANGE_TERRACOTTA - - MAGENTA_TERRACOTTA - - LIGHT_BLUE_TERRACOTTA - - YELLOW_TERRACOTTA - - LIME_TERRACOTTA - - PINK_TERRACOTTA - - GRAY_TERRACOTTA - - LIGHT_GRAY_TERRACOTTA - - CYAN_TERRACOTTA - - PURPLE_TERRACOTTA - - BLUE_TERRACOTTA - - BROWN_TERRACOTTA - - GREEN_TERRACOTTA - - RED_TERRACOTTA - - BLACK_TERRACOTTA - #trapdoors - - ACACIA_TRAPDOOR - - BIRCH_TRAPDOOR - - DARK_OAK_TRAPDOOR - - JUNGLE_TRAPDOOR - - OAK_TRAPDOOR - - SPRUCE_TRAPDOOR - #weapon blocks - - COAL_BLOCK - #wood - - ACACIA_WOOD - - BIRCH_WOOD - - DARK_OAK_WOOD - - OAK_WOOD - - SPRUCE_WOOD - - STRIPPED_ACACIA_WOOD - - STRIPPED_BIRCH_WOOD - - STRIPPED_DARK_OAK_WOOD - - STRIPPED_OAK_WOOD - - STRIPPED_SPRUCE_WOOD - #wool - - WHITE_WOOL - - ORANGE_WOOL - - MAGENTA_WOOL - - LIGHT_BLUE_WOOL - - YELLOW_WOOL - - LIME_WOOL - - PINK_WOOL - - GRAY_WOOL - - LIGHT_GRAY_WOOL - - CYAN_WOOL - - PURPLE_WOOL - - BLUE_WOOL - - BROWN_WOOL - - GREEN_WOOL - - RED_WOOL - - BLACK_WOOL - + - crafting_table + - ALL_WOOD + - LAVA + - ALL_LOG + - all_planks + - GLASS + - LAPIS_BLOCK + - DISPENSER + - NOTE_BLOCK + - ALL_BED + - sticky_piston + - piston + - all_wool + - GOLD_BLOCK + - IRON_BLOCK + - all_slab + - BOOKSHELF + - TORCH + - FIRE + - oak_stairs + - birch_stairs + - jungle_stairs + - spruce_stairs + - stone_brick_stairs + - quartz_stairs + - nether_brick_stairs + - chest + - redstone_wire + - diamond_block + - nether_brick_stairs + - furnace + - all_sign + - ladder + - all_door + - lever + - all_pressure_plate + - redstone_torch + - redstone_wall_torch + - all_button + - clay + - all_fence + - netherrack + - glowstone + - cake + - repeater + - all_stained_glass + - all_trapdoor + - all_stone_bricks + - iron_bars + - glass_pane + - all_fence_gate + - nether_brick + - enchantment_table + - brewing_stand + - cauldron + - end_stone + - dragon_egg + - redstone_lamp + - ender chest + - TRIPWIRE_HOOK + - EMERALD_BLOCK + - BEACON + - cobblestone_wall + - mossy_cobblestone_wall + - FLOWER_POT + - SKULL + - all_ANVIL + - TRAPPED_CHEST + - COMPARATOR + - daylight_detector + - REDSTONE_BLOCK + - HOPPER + - all_QUARTZ_BLOCK + - all_rail + - DROPPER + - ALL_TERRACOTTA + - ALL_STAINED_GLASS_PANE + - SLIME_BLOCK + - ALL_CARPET + - COAL_BLOCK + - END_STONE_BRICKS canCruise: true cruiseSkipBlocks: 4 canFly: false @@ -268,6 +95,13 @@ requireWaterContact: true allowVerticalMovement: true fuelBurnRate: 1.0 tryNudge: false + +passthroughBlocks: + - kelp + - kelp_plant + - tall_seagrass + - seagrass + - bubble_column flyblocks: [ACACIA_PLANKS, BIRCH_PLANKS, DARK_OAK_PLANKS, JUNGLE_PLANKS, OAK_PLANKS, SPRUCE_PLANKS]: - 25.0 diff --git a/modules/Movecraft/src/main/resources/types/1_14/Turret.craft b/modules/Movecraft/src/main/resources/types/1_14/Turret.craft index 15cc0d687..3fc3c1262 100644 --- a/modules/Movecraft/src/main/resources/types/1_14/Turret.craft +++ b/modules/Movecraft/src/main/resources/types/1_14/Turret.craft @@ -2,194 +2,75 @@ name: Turret maxSize: 1000 minSize: 1 allowedBlocks: - #beds - - WHITE_BED - - ORANGE_BED - - MAGENTA_BED - - LIGHT_BLUE_BED - - YELLOW_BED - - LIME_BED - - PINK_BED - - GRAY_BED - - LIGHT_BED - - CYAN_BED - - PURPLE_BED - - BLUE_BED - - BROWN_BED - - GREEN_BED - - RED_BED - - BLACK_BED - #buttons - - ACACIA_BUTTON - - BIRCH_BUTTON - - DARK_OAK_BUTTON - - JUNGLE_BUTTON - - OAK_BUTTON - - SPRUCE_BUTTON - - STONE_BUTTON - #doors - - ACACIA_DOOR - - BIRCH_DOOR - - DARK_OAK_DOOR - - IRON_DOOR - - JUNGLE_DOOR - - OAK_DOOR - - SPRUCE_DOOR - #fences - - ACACIA_FENCE - - BIRCH_FENCE - - DARK_OAK_FENCE - - JUNGLE_FENCE - - OAK_FENCE - - SPRUCE_FENCE - #fence gates - - ACACIA_FENCE_GATE - - BIRCH_FENCE_GATE - - DARK_OAK_FENCE_GATE - - JUNGLE_FENCE_GATE - - OAK_FENCE_GATE - - SPRUCE_FENCE_GATE - #glass - - GLASS - - WHITE_STAINED_GLASS - - ORANGE_STAINED_GLASS - - MAGENTA_STAINED_GLASS - - LIGHT_BLUE_STAINED_GLASS - - YELLOW_STAINED_GLASS - - LIME_STAINED_GLASS - - PINK_STAINED_GLASS - - GRAY_STAINED_GLASS - - LIGHT_GRAY_STAINED_GLASS - - CYAN_STAINED_GLASS - - PURPLE_STAINED_GLASS - - BLUE_STAINED_GLASS - - BROWN_STAINED_GLASS - - GREEN_STAINED_GLASS - - RED_STAINED_GLASS - - BLACK_STAINED_GLASS - #glass pane - - GLASS_PANE - - WHITE_STAINED_GLASS_PANE - - ORANGE_STAINED_GLASS_PANE - - MAGENTA_STAINED_GLASS_PANE - - LIGHT_BLUE_STAINED_GLASS_PANE - - YELLOW_STAINED_GLASS_PANE - - LIME_STAINED_GLASS_PANE - - PINK_STAINED_GLASS_PANE - - GRAY_STAINED_GLASS_PANE - - LIGHT_GRAY_STAINED_GLASS_PANE - - CYAN_STAINED_GLASS_PANE - - PURPLE_STAINED_GLASS_PANE - - BLUE_STAINED_GLASS_PANE - - BROWN_STAINED_GLASS_PANE - - GREEN_STAINED_GLASS_PANE - - RED_STAINED_GLASS_PANE - - BLACK_STAINED_GLASS_PANE - #interior - - BOOKSHELF - - BREWING_STAND - - CAULDRON - - IRON_BARS - - SIGN - - TORCH - - WALL_SIGN - - WALL_TORCH - #liquids - - LAVA - - WATER - #logs - - BIRCH_LOG - - JUNGLE_LOG - - OAK_LOG - - SPRUCE_LOG - - STRIPPED_BIRCH_LOG - - STRIPPED_JUNGLE_LOG - - STRIPPED_OAK_LOG - - STRIPPED_SPRUCE_LOG - #planks - - ACACIA_PLANKS - - BIRCH_PLANKS - - DARK_OAK_PLANKS - - JUNGLE_PLANKS - - OAK_PLANKS - - SPRUCE_PLANKS - #pressure plates - - ACACIA_PRESSURE_PLATE - - BIRCH_PRESSURE_PLATE - - DARK_OAK_PRESSURE_PLATE - - HEAVY_WEIGHTED_PRESSURE_PLATE - - JUNGLE_PRESSURE_PLATE - - LIGHT_WEIGHTED_PRESSURE_PLATE - - OAK_PRESSURE_PLATE - - SPRUCE_PRESSURE_PLATE - #redstone - - COMPARATOR - - NOTE_BLOCK - - PISTON - - PISTON_HEAD - - REDSTONE_BLOCK - - REDSTONE_WIRE - - REPEATER - - STICKY_PISTON - - TRIPWIRE_HOOK - #slabs - - ACACIA_SLAB - - BIRCH_SLAB - - BRICK_SLAB - - COBBLESTONE_SLAB - - DARK_OAK_SLAB - - DARK_PRISMARINE - - JUNGLE_SLAB - - NETHER_BRICK_SLAB - - OAK_SLAB - - PETRIFIED_OAK_SLAB - - PRISMARINE_SLAB - - PRISMARINE_BRICK_SLAB - - RED_SANDSTONE_SLAB - - QUARTZ_SLAB - - SPRUCE_SLAB - - STONE_SLAB - #stairs - - BIRCH_STAIRS - - JUNGLE_STAIRS - - OAK_STAIRS - - SMOOTH_STAIRS - - SPRUCE_STAIRS - #storage - - CHEST - - DISPENSER - - DROPPER - - HOPPER - - TRAPPED_CHEST - #terracotta - - GRAY_TERRACOTTA - - LIGHT_GRAY_TERRACOTTA - - BLACK_TERRACOTTA - #trapdoors - - ACACIA_TRAPDOOR - - BIRCH_TRAPDOOR - - DARK_OAK_TRAPDOOR - - JUNGLE_TRAPDOOR - - OAK_TRAPDOOR - - SPRUCE_TRAPDOOR - #weapon blocks - - COAL_BLOCK - #wood - - ACACIA_WOOD - - BIRCH_WOOD - - DARK_OAK_WOOD - - OAK_WOOD - - SPRUCE_WOOD - - STRIPPED_ACACIA_WOOD - - STRIPPED_BIRCH_WOOD - - STRIPPED_DARK_OAK_WOOD - - STRIPPED_OAK_WOOD - - STRIPPED_SPRUCE_WOOD - #wool - - LIGHT_GRAY_WOOL - -forbiddenBlocks: - - PISTON_HEAD + - ALL_WOOD + - WATER + - LAVA + - ALL_LOG + - all_planks + - GLASS + - DISPENSER + - NOTE_BLOCK + - ALL_BED + - sticky_piston + - piston_head + - light_gray_wool + - all_slab + - BOOKSHELF + - TORCH + - FIRE + - oak_stairs + - birch_stairs + - jungle_stairs + - spruce_stairs + - chest + - redstone_wire + - furnace + - all_sign + - ladder + - all_door + - lever + - all_pressure_plate + - redstone_torch + - redstone_wall_torch + - all_button + - all_fence + - netherrack + - glowstone + - cake + - redstone_repeater + - all_stained_glass + - all_trapdoor + - all_stone_bricks + - iron_bars + - glass_pane + - all_fence_gate + - enchantment_table + - brewing_stand + - cauldron + - dragon_egg + - redstone_lamp + - ender chest + - TRIPWIRE_HOOK + - EMERALD_BLOCK + - BEACON + - FLOWER_POT + - SKULL + - all_ANVIL + - TRAPPED_CHEST + - REDSTONE_COMPARATOR + - daylight_detector + - REDSTONE_BLOCK + - HOPPER + - all_rail + - DROPPER + - light_gray_terracotta + - gray_terracotta + - black_terracotta + - ALL_STAINED_GLASS_PANE + - SLIME_BLOCK + - ALL_CARPET + - COAL_BLOCK + - END_STONE_BRICKS canFly: true diff --git a/modules/Movecraft/src/main/resources/types/1_14/airship.craft b/modules/Movecraft/src/main/resources/types/1_14/airship.craft index 88f281e52..462501fec 100644 --- a/modules/Movecraft/src/main/resources/types/1_14/airship.craft +++ b/modules/Movecraft/src/main/resources/types/1_14/airship.craft @@ -2,88 +2,88 @@ name: Airship maxSize: 5000 minSize: 1000 allowedBlocks: - - crafting_table - - ALL_WOOD - - WATER - - LAVA - - ALL_LOG - - all_planks - - GLASS - - LAPIS_BLOCK - - DISPENSER - - NOTE_BLOCK - - ALL_BED - - sticky_piston - - piston - - all_wool - - GOLD_BLOCK - - IRON_BLOCK - - all_slab - - BOOKSHELF - - TORCH - - FIRE - - oak_stairs - - birch_stairs - - jungle_stairs - - spruce_stairs - - stone_brick_stairs - - quartz_stairs - - nether_brick_stairs - - chest - - redstone_wire - - diamond_block - - nether_brick_stairs - - furnace - - all_sign - - ladder - - all_door - - lever - - all_pressure_plate - - redstone_torch - - redstone_wall_torch - - all_button - - clay - - all_fence - - netherrack - - glowstone - - cake - - repeater - - all_stained_glass - - all_trapdoor - - all_stone_bricks - - iron_bars - - glass_pane - - all_fence_gate - - nether_brick - - enchantment_table - - brewing_stand - - cauldron - - end_stone - - dragon_egg - - redstone_lamp - - ender chest - - TRIPWIRE_HOOK - - EMERALD_BLOCK - - BEACON - - cobblestone_wall - - mossy_cobblestone_wall - - FLOWER_POT - - SKULL - - all_ANVIL - - TRAPPED_CHEST - - COMPARATOR - - daylight_detector - - REDSTONE_BLOCK - - HOPPER - - all_QUARTZ_BLOCK - - all_rail - - DROPPER - - ALL_TERRACOTTA - - ALL_STAINED_GLASS_PANE - - SLIME_BLOCK - - ALL_CARPET - - COAL_BLOCK - - END_STONE_BRICKS + - ALL_WOOD + - WATER + - LAVA + - ALL_LOG + - all_planks + - GLASS + - LAPIS_BLOCK + - DISPENSER + - NOTE_BLOCK + - ALL_BED + - sticky_piston + - piston_head + - all_wool + - GOLD_BLOCK + - IRON_BLOCK + - all_slab + - BOOKSHELF + - TORCH + - FIRE + - oak_stairs + - birch_stairs + - jungle_stairs + - spruce_stairs + - stone_brick_stairs + - quartz_stairs + - nether_brick_stairs + - chest + - redstone_wire + - diamond_block + - nether_brick_stairs + - furnace + - all_sign + - ladder + - all_door + - lever + - all_pressure_plate + - redstone_torch + - redstone_wall_torch + - all_button + - clay + - all_fence + - netherrack + - glowstone + - cake + - redstone_repeater + - all_stained_glass + - all_trapdoor + - all_stone_bricks + - iron_bars + - glass_pane + - all_fence_gate + - nether_brick + - enchantment_table + - brewing_stand + - cauldron + - end_stone + - dragon_egg + - redstone_lamp + - ender chest + - TRIPWIRE_HOOK + - EMERALD_BLOCK + - BEACON + - cobblestone_wall + - mossy_cobblestone_wall + - FLOWER_POT + - SKULL + - all_ANVIL + - TRAPPED_CHEST + - REDSTONE_COMPARATOR + - daylight_detector + - REDSTONE_BLOCK + - HOPPER + - all_QUARTZ_BLOCK + - all_rail + - DROPPER + - ALL_TERRACOTTA + - ALL_STAINED_GLASS_PANE + - SLIME_BLOCK + - ALL_CARPET + - COAL_BLOCK + - END_STONE_BRICKS + - barrel canCruise: true rotateAtMidpoint: true @@ -104,14 +104,14 @@ tryNudge: false canStaticMove: true maxStaticMove: 2 moveblocks: - redstone_block: # redstone represents engines + REDSTONE_BLOCK: # redstone represents engines - 1.0 - 100.0 flyblocks: - [WHITE_WOOL, ORANGE_WOOL, MAGENTA_WOOL,LIGHT_BLUE_WOOL,YELLOW_WOOL,LIME_WOOL,PINK_WOOL,GRAY_WOOL,LIGHT_GRAY_WOOL,CYAN_WOOL,PURPLE_WOOL,BLUE_WOOL,BROWN_WOOL, GREEN_WOOL, RED_WOOL, BLACK_WOOL]: #wool represents lift + all_wool: #wool represents lift - 50.0 - 100.0 - [CHEST,TRAPPED_CHEST]: # limit chests to make big airships important for merchant missions + [CHEST,TRAPPED_CHEST, barrel]: # limit chests to make big airships important for merchant missions - 0.0 - 1.0 [DISPENSER,DROPPER,HOPPER]: # dispensers and hoppers can be used for inventory too, so limit them as well diff --git a/modules/Movecraft/src/main/resources/types/1_14/airskiff.craft b/modules/Movecraft/src/main/resources/types/1_14/airskiff.craft index 2b60ac25d..fcb2c6ab9 100644 --- a/modules/Movecraft/src/main/resources/types/1_14/airskiff.craft +++ b/modules/Movecraft/src/main/resources/types/1_14/airskiff.craft @@ -2,216 +2,75 @@ name: Airskiff maxSize: 80 minSize: 10 allowedBlocks: - #beds - - WHITE_BED - - ORANGE_BED - - MAGENTA_BED - - LIGHT_BLUE_BED - - YELLOW_BED - - LIME_BED - - PINK_BED - - GRAY_BED - - LIGHT_BED - - CYAN_BED - - PURPLE_BED - - BLUE_BED - - BROWN_BED - - GREEN_BED - - RED_BED - - BLACK_BED - #buttons - - ACACIA_BUTTON - - BIRCH_BUTTON - - DARK_OAK_BUTTON - - JUNGLE_BUTTON - - OAK_BUTTON - - SPRUCE_BUTTON - - STONE_BUTTON - #doors - - ACACIA_DOOR - - BIRCH_DOOR - - DARK_OAK_DOOR - - IRON_DOOR - - JUNGLE_DOOR - - OAK_DOOR - - SPRUCE_DOOR - #fences - - ACACIA_FENCE - - BIRCH_FENCE - - DARK_OAK_FENCE - - JUNGLE_FENCE - - OAK_FENCE - - SPRUCE_FENCE - #fence gates - - ACACIA_FENCE_GATE - - BIRCH_FENCE_GATE - - DARK_OAK_FENCE_GATE - - JUNGLE_FENCE_GATE - - OAK_FENCE_GATE - - SPRUCE_FENCE_GATE - #glass - - GLASS - - WHITE_STAINED_GLASS - - ORANGE_STAINED_GLASS - - MAGENTA_STAINED_GLASS - - LIGHT_BLUE_STAINED_GLASS - - YELLOW_STAINED_GLASS - - LIME_STAINED_GLASS - - PINK_STAINED_GLASS - - GRAY_STAINED_GLASS - - LIGHT_GRAY_STAINED_GLASS - - CYAN_STAINED_GLASS - - PURPLE_STAINED_GLASS - - BLUE_STAINED_GLASS - - BROWN_STAINED_GLASS - - GREEN_STAINED_GLASS - - RED_STAINED_GLASS - - BLACK_STAINED_GLASS - #glass pane - - GLASS_PANE - - WHITE_STAINED_GLASS_PANE - - ORANGE_STAINED_GLASS_PANE - - MAGENTA_STAINED_GLASS_PANE - - LIGHT_BLUE_STAINED_GLASS_PANE - - YELLOW_STAINED_GLASS_PANE - - LIME_STAINED_GLASS_PANE - - PINK_STAINED_GLASS_PANE - - GRAY_STAINED_GLASS_PANE - - LIGHT_GRAY_STAINED_GLASS_PANE - - CYAN_STAINED_GLASS_PANE - - PURPLE_STAINED_GLASS_PANE - - BLUE_STAINED_GLASS_PANE - - BROWN_STAINED_GLASS_PANE - - GREEN_STAINED_GLASS_PANE - - RED_STAINED_GLASS_PANE - - BLACK_STAINED_GLASS_PANE - #interior - - BOOKSHELF - - BREWING_STAND - - CAULDRON - - IRON_BARS - - TORCH - - WALL_TORCH - #liquids - - LAVA - - WATER - #logs - - BIRCH_LOG - - JUNGLE_LOG - - OAK_LOG - - SPRUCE_LOG - - STRIPPED_BIRCH_LOG - - STRIPPED_JUNGLE_LOG - - STRIPPED_OAK_LOG - - STRIPPED_SPRUCE_LOG - #planks - - ACACIA_PLANKS - - BIRCH_PLANKS - - DARK_OAK_PLANKS - - JUNGLE_PLANKS - - OAK_PLANKS - - SPRUCE_PLANKS - #pressure plates - - ACACIA_PRESSURE_PLATE - - BIRCH_PRESSURE_PLATE - - DARK_OAK_PRESSURE_PLATE - - HEAVY_WEIGHTED_PRESSURE_PLATE - - JUNGLE_PRESSURE_PLATE - - LIGHT_WEIGHTED_PRESSURE_PLATE - - OAK_PRESSURE_PLATE - - SPRUCE_PRESSURE_PLATE - #redstone - - COMPARATOR - - NOTE_BLOCK - - PISTON - - PISTON_HEAD - - REDSTONE_BLOCK - - REDSTONE_WIRE - - REPEATER - - REDSTONE_TORCH - - REDSTONE_WALL_TORCH - - STICKY_PISTON - - TRIPWIRE_HOOK - #signs - - ACACIA_SIGN - - ACACIA_WALL_SIGN - - BIRCH_SIGN - - BIRCH_WALL_SIGN - - DARK_OAK_SIGN - - DARK_OAK_WALL_SIGN - - JUNGLE_SIGN - - JUNGLE_WALL_SIGN - - OAK_SIGN - - OAK_WALL_SIGN - - SPRUCE_SIGN - - SPRUCE_WALL_SIGN - #slabs - - ACACIA_SLAB - - BIRCH_SLAB - - BRICK_SLAB - - COBBLESTONE_SLAB - - DARK_OAK_SLAB - - DARK_PRISMARINE - - JUNGLE_SLAB - - NETHER_BRICK_SLAB - - OAK_SLAB - - PETRIFIED_OAK_SLAB - - PRISMARINE_SLAB - - PRISMARINE_BRICK_SLAB - - RED_SANDSTONE_SLAB - - QUARTZ_SLAB - - SPRUCE_SLAB - - STONE_SLAB - #stairs - - BIRCH_STAIRS - - JUNGLE_STAIRS - - OAK_STAIRS - - SMOOTH_STAIRS - - SPRUCE_STAIRS - #storage - - CHEST - - DISPENSER - - DROPPER - - HOPPER - - TRAPPED_CHEST - #trapdoors - - ACACIA_TRAPDOOR - - BIRCH_TRAPDOOR - - DARK_OAK_TRAPDOOR - - JUNGLE_TRAPDOOR - - OAK_TRAPDOOR - - SPRUCE_TRAPDOOR - #weapon blocks - - COAL_BLOCK - #wood - - ACACIA_WOOD - - BIRCH_WOOD - - DARK_OAK_WOOD - - OAK_WOOD - - SPRUCE_WOOD - - STRIPPED_ACACIA_WOOD - - STRIPPED_BIRCH_WOOD - - STRIPPED_DARK_OAK_WOOD - - STRIPPED_OAK_WOOD - - STRIPPED_SPRUCE_WOOD - #wool - - WHITE_WOOL - - ORANGE_WOOL - - MAGENTA_WOOL - - LIGHT_BLUE_WOOL - - YELLOW_WOOL - - LIME_WOOL - - PINK_WOOL - - GRAY_WOOL - - LIGHT_GRAY_WOOL - - CYAN_WOOL - - PURPLE_WOOL - - BLUE_WOOL - - BROWN_WOOL - - GREEN_WOOL - - RED_WOOL - - BLACK_WOOL - + - ALL_WOOD + - WATER + - LAVA + - ALL_LOG + - all_planks + - GLASS + - DISPENSER + - NOTE_BLOCK + - ALL_BED + - sticky_piston + - piston_head + - all_wool + - all_slab + - BOOKSHELF + - TORCH + - FIRE + - oak_stairs + - birch_stairs + - jungle_stairs + - spruce_stairs + - chest + - redstone_wire + - nether_brick_stairs + - furnace + - all_sign + - ladder + - all_door + - lever + - all_pressure_plate + - redstone_torch + - redstone_wall_torch + - all_button + - all_fence + - netherrack + - glowstone + - cake + - repeater + - all_stained_glass + - all_trapdoor + - all_stone_bricks + - iron_bars + - glass_pane + - all_fence_gate + - enchantment_table + - brewing_stand + - cauldron + - dragon_egg + - redstone_lamp + - ender chest + - TRIPWIRE_HOOK + - EMERALD_BLOCK + - BEACON + - FLOWER_POT + - SKULL + - all_ANVIL + - TRAPPED_CHEST + - COMPARATOR + - daylight_detector + - REDSTONE_BLOCK + - HOPPER + - all_QUARTZ_BLOCK: + - all_rail + - DROPPER + - ALL_STAINED_GLASS_PANE + - SLIME_BLOCK + - ALL_CARPET + - COAL_BLOCK + - END_STONE_BRICKS + - barrel forbiddenBlocks: - PISTON_HEAD @@ -237,10 +96,10 @@ speed: 3.0 tryNudge: false sinkPercent: 99.0 flyblocks: - [WHITE_WOOL, ORANGE_WOOL, MAGENTA_WOOL,LIGHT_BLUE_WOOL,YELLOW_WOOL,LIME_WOOL,PINK_WOOL,GRAY_WOOL,LIGHT_GRAY_WOOL,CYAN_WOOL,PURPLE_WOOL,BLUE_WOOL,BROWN_WOOL, GREEN_WOOL, RED_WOOL, BLACK_WOOL]: #wool represents lift + all_wool: #wool represents lift - 50.0 - 100.0 - [CHEST,TRAPPED_CHEST]: # limit chests to make big airships important for merchant missions + [CHEST,TRAPPED_CHEST, barrel]: # limit chests to make big airships important for merchant missions - 0.0 - N2 [DISPENSER,HOPPER]: # dispensers and hoppers can be used for inventory too, so limit them as well diff --git a/modules/Movecraft/src/main/resources/types/1_14/elevator.craft b/modules/Movecraft/src/main/resources/types/1_14/elevator.craft index 8ebe8d222..b1dcc0e7f 100644 --- a/modules/Movecraft/src/main/resources/types/1_14/elevator.craft +++ b/modules/Movecraft/src/main/resources/types/1_14/elevator.craft @@ -2,208 +2,74 @@ name: elevator maxSize: 1000 minSize: 10 allowedBlocks: - #beds - - WHITE_BED - - ORANGE_BED - - MAGENTA_BED - - LIGHT_BLUE_BED - - YELLOW_BED - - LIME_BED - - PINK_BED - - GRAY_BED - - LIGHT_BED - - CYAN_BED - - PURPLE_BED - - BLUE_BED - - BROWN_BED - - GREEN_BED - - RED_BED - - BLACK_BED - #buttons - - ACACIA_BUTTON - - BIRCH_BUTTON - - DARK_OAK_BUTTON - - JUNGLE_BUTTON - - OAK_BUTTON - - SPRUCE_BUTTON - - STONE_BUTTON - #doors - - ACACIA_DOOR - - BIRCH_DOOR - - DARK_OAK_DOOR - - IRON_DOOR - - JUNGLE_DOOR - - OAK_DOOR - - SPRUCE_DOOR - #fences - - ACACIA_FENCE - - BIRCH_FENCE - - DARK_OAK_FENCE - - JUNGLE_FENCE - - OAK_FENCE - - SPRUCE_FENCE - #fence gates - - ACACIA_FENCE_GATE - - BIRCH_FENCE_GATE - - DARK_OAK_FENCE_GATE - - JUNGLE_FENCE_GATE - - OAK_FENCE_GATE - - SPRUCE_FENCE_GATE - #glass - - GLASS - - WHITE_STAINED_GLASS - - ORANGE_STAINED_GLASS - - MAGENTA_STAINED_GLASS - - LIGHT_BLUE_STAINED_GLASS - - YELLOW_STAINED_GLASS - - LIME_STAINED_GLASS - - PINK_STAINED_GLASS - - GRAY_STAINED_GLASS - - LIGHT_GRAY_STAINED_GLASS - - CYAN_STAINED_GLASS - - PURPLE_STAINED_GLASS - - BLUE_STAINED_GLASS - - BROWN_STAINED_GLASS - - GREEN_STAINED_GLASS - - RED_STAINED_GLASS - - BLACK_STAINED_GLASS - #glass pane - - GLASS_PANE - - WHITE_STAINED_GLASS_PANE - - ORANGE_STAINED_GLASS_PANE - - MAGENTA_STAINED_GLASS_PANE - - LIGHT_BLUE_STAINED_GLASS_PANE - - YELLOW_STAINED_GLASS_PANE - - LIME_STAINED_GLASS_PANE - - PINK_STAINED_GLASS_PANE - - GRAY_STAINED_GLASS_PANE - - LIGHT_GRAY_STAINED_GLASS_PANE - - CYAN_STAINED_GLASS_PANE - - PURPLE_STAINED_GLASS_PANE - - BLUE_STAINED_GLASS_PANE - - BROWN_STAINED_GLASS_PANE - - GREEN_STAINED_GLASS_PANE - - RED_STAINED_GLASS_PANE - - BLACK_STAINED_GLASS_PANE - #interior - - BOOKSHELF - - BREWING_STAND - - CAULDRON - - IRON_BARS - - SIGN - - TORCH - - WALL_SIGN - - WALL_TORCH - #liquids - - LAVA - - WATER - #logs - - BIRCH_LOG - - JUNGLE_LOG - - OAK_LOG - - SPRUCE_LOG - - STRIPPED_BIRCH_LOG - - STRIPPED_JUNGLE_LOG - - STRIPPED_OAK_LOG - - STRIPPED_SPRUCE_LOG - #planks - - ACACIA_PLANKS - - BIRCH_PLANKS - - DARK_OAK_PLANKS - - JUNGLE_PLANKS - - OAK_PLANKS - - SPRUCE_PLANKS - #pressure plates - - ACACIA_PRESSURE_PLATE - - BIRCH_PRESSURE_PLATE - - DARK_OAK_PRESSURE_PLATE - - HEAVY_WEIGHTED_PRESSURE_PLATE - - JUNGLE_PRESSURE_PLATE - - LIGHT_WEIGHTED_PRESSURE_PLATE - - OAK_PRESSURE_PLATE - - SPRUCE_PRESSURE_PLATE - #redstone - - COMPARATOR - - NOTE_BLOCK - - PISTON - - PISTON_HEAD - - REDSTONE_BLOCK - - REDSTONE_WIRE - - REPEATER - - REDSTONE_TORCH - - REDSTONE_WALL_TORCH - - STICKY_PISTON - - TRIPWIRE_HOOK - #slabs - - ACACIA_SLAB - - BIRCH_SLAB - - BRICK_SLAB - - COBBLESTONE_SLAB - - DARK_OAK_SLAB - - DARK_PRISMARINE - - JUNGLE_SLAB - - NETHER_BRICK_SLAB - - OAK_SLAB - - PETRIFIED_OAK_SLAB - - PRISMARINE_SLAB - - PRISMARINE_BRICK_SLAB - - RED_SANDSTONE_SLAB - - QUARTZ_SLAB - - SPRUCE_SLAB - - STONE_SLAB - #stairs - - BIRCH_STAIRS - - JUNGLE_STAIRS - - OAK_STAIRS - - SMOOTH_STAIRS - - SPRUCE_STAIRS - #storage - - CHEST - - DISPENSER - - DROPPER - - HOPPER - - TRAPPED_CHEST - #trapdoors - - ACACIA_TRAPDOOR - - BIRCH_TRAPDOOR - - DARK_OAK_TRAPDOOR - - JUNGLE_TRAPDOOR - - OAK_TRAPDOOR - - SPRUCE_TRAPDOOR - #weapon blocks - - COAL_BLOCK - #wood - - ACACIA_WOOD - - BIRCH_WOOD - - DARK_OAK_WOOD - - OAK_WOOD - - SPRUCE_WOOD - - STRIPPED_ACACIA_WOOD - - STRIPPED_BIRCH_WOOD - - STRIPPED_DARK_OAK_WOOD - - STRIPPED_OAK_WOOD - - STRIPPED_SPRUCE_WOOD - #wool - - WHITE_WOOL - - ORANGE_WOOL - - MAGENTA_WOOL - - LIGHT_BLUE_WOOL - - YELLOW_WOOL - - LIME_WOOL - - PINK_WOOL - - GRAY_WOOL - - LIGHT_GRAY_WOOL - - CYAN_WOOL - - PURPLE_WOOL - - BLUE_WOOL - - BROWN_WOOL - - GREEN_WOOL - - RED_WOOL - - BLACK_WOOL - -forbiddenBlocks: - - PISTON_HEAD - + - ALL_WOOD + - WATER + - LAVA + - ALL_LOG + - all_planks + - GLASS + - DISPENSER + - NOTE_BLOCK + - ALL_BED + - sticky_piston + - piston_head + - all_wool + - all_slab + - BOOKSHELF + - TORCH + - FIRE + - oak_stairs + - birch_stairs + - jungle_stairs + - spruce_stairs + - chest + - redstone_wire + - nether_brick_stairs + - furnace + - all_sign + - ladder + - all_door + - lever + - all_pressure_plate + - redstone_torch + - redstone_wall_torch + - all_button + - all_fence + - netherrack + - glowstone + - cake + - repeater + - all_stained_glass + - all_trapdoor + - all_stone_bricks + - iron_bars + - glass_pane + - all_fence_gate + - enchantment_table + - brewing_stand + - cauldron + - dragon_egg + - redstone_lamp + - ender chest + - TRIPWIRE_HOOK + - EMERALD_BLOCK + - BEACON + - FLOWER_POT + - SKULL + - all_ANVIL + - TRAPPED_CHEST + - COMPARATOR + - daylight_detector + - REDSTONE_BLOCK + - HOPPER + - all_QUARTZ_BLOCK: + - all_rail + - DROPPER + - ALL_STAINED_GLASS_PANE + - SLIME_BLOCK + - ALL_CARPET + - COAL_BLOCK + - END_STONE_BRICKS canFly: true canCruise: false collisionExplosion: 0.0 @@ -218,6 +84,6 @@ speed: 1.0 tryNudge: false sinkPercent: 99.0 flyblocks: - [WHITE_WOOL, ORANGE_WOOL, MAGENTA_WOOL,LIGHT_BLUE_WOOL,YELLOW_WOOL,LIME_WOOL,PINK_WOOL,GRAY_WOOL,LIGHT_GRAY_WOOL,CYAN_WOOL,PURPLE_WOOL,BLUE_WOOL,BROWN_WOOL, GREEN_WOOL, RED_WOOL, BLACK_WOOL]: #wool represents lift + all_wool: #wool represents lift - 0.0 - 100.0 \ No newline at end of file From 015f3960ac4d3ade94e254c030a32024f10709b5 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Sun, 15 Sep 2019 02:44:32 +0200 Subject: [PATCH 044/304] Fixed 1.14 and legacy file saving as well as malformed example craft types --- .../movecraft/craft/CraftManager.java | 45 +++++++++++-------- .../main/resources/types/1_14/airskiff.craft | 2 +- .../main/resources/types/1_14/elevator.craft | 2 +- .../src/main/resources/types/airskiff.craft | 2 +- .../src/main/resources/types/elevator.craft | 2 +- 5 files changed, 30 insertions(+), 23 deletions(-) diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/CraftManager.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/CraftManager.java index 2b190759f..537932334 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/CraftManager.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/CraftManager.java @@ -21,8 +21,6 @@ import net.countercraft.movecraft.config.Settings; import net.countercraft.movecraft.events.CraftReleaseEvent; import net.countercraft.movecraft.localisation.I18nSupport; -import net.countercraft.movecraft.utils.ChatUtils; -import org.apache.commons.lang3.tuple.ImmutablePair; import org.bukkit.Bukkit; import org.bukkit.World; import org.bukkit.entity.Player; @@ -80,14 +78,7 @@ private Set loadCraftTypes(){ Movecraft.getInstance().saveResource("types/legacy/SubAirship.craft", false); Movecraft.getInstance().saveResource("types/legacy/Submarine.craft", false); Movecraft.getInstance().saveResource("types/legacy/Turret.craft", false); - final File legacydir = new File(craftsFile,"legacy"); - for (File craftFile : legacydir.listFiles()){ - final String fileName = craftFile.getName(); - if (!craftFile.renameTo(new File(craftFile, fileName))) continue; - craftFile.delete(); - } - if (legacydir.listFiles().length == 0) - legacydir.delete(); + } else if (Settings.is1_14){ //if 1.14, save 1.14 files Movecraft.getInstance().saveResource("types/1_14/airship.craft", false); Movecraft.getInstance().saveResource("types/1_14/airskiff.craft", false); @@ -99,14 +90,7 @@ private Set loadCraftTypes(){ Movecraft.getInstance().saveResource("types/1_14/SubAirship.craft", false); Movecraft.getInstance().saveResource("types/1_14/Submarine.craft", false); Movecraft.getInstance().saveResource("types/1_14/Turret.craft", false); - final File v1_14dir = new File(craftsFile,"/1_14"); - for (File craftFile : v1_14dir.listFiles()){ - final String fileName = craftFile.getName(); - if (!craftFile.renameTo(new File(craftFile, fileName))) continue; - craftFile.delete(); - } - if (v1_14dir.listFiles().length == 0) - v1_14dir.delete(); + } else { //if 1.13, save 1.13 files Movecraft.getInstance().saveResource("types/airship.craft", false); Movecraft.getInstance().saveResource("types/airskiff.craft", false); @@ -120,7 +104,29 @@ private Set loadCraftTypes(){ Movecraft.getInstance().saveResource("types/Turret.craft", false); } } - + final File legacydir = new File(craftsFile,"legacy"); + if (legacydir.exists()) { + for (File craftFile : legacydir.listFiles()) { + final String fileName = craftFile.getName(); + if (!craftFile.renameTo(new File(craftsFile, fileName))) continue; + craftFile.delete(); + } + if (legacydir.listFiles().length == 0) + legacydir.delete(); + } + final File v1_14dir = new File(craftsFile,"1_14"); + if (v1_14dir.exists()) { + File[] files = v1_14dir.listFiles(); + for (File craftFile : files) { + final String fileName = craftFile.getName(); + Bukkit.getLogger().info(fileName); + File destination = new File(craftsFile, fileName); + if (!craftFile.renameTo(destination)) continue; + craftFile.delete(); + } + if (v1_14dir.listFiles().length == 0) + v1_14dir.delete(); + } Set craftTypes = new HashSet<>(); File[] files = craftsFile.listFiles(); if (files == null){ @@ -131,6 +137,7 @@ private Set loadCraftTypes(){ if (file.isFile()) { if (file.getName().contains(".craft")) { + Bukkit.getLogger().info(file.getName()); CraftType type = new CraftType(file); craftTypes.add(type); } diff --git a/modules/Movecraft/src/main/resources/types/1_14/airskiff.craft b/modules/Movecraft/src/main/resources/types/1_14/airskiff.craft index fcb2c6ab9..b2dbd621f 100644 --- a/modules/Movecraft/src/main/resources/types/1_14/airskiff.craft +++ b/modules/Movecraft/src/main/resources/types/1_14/airskiff.craft @@ -62,7 +62,7 @@ allowedBlocks: - daylight_detector - REDSTONE_BLOCK - HOPPER - - all_QUARTZ_BLOCK: + - all_QUARTZ_BLOCK - all_rail - DROPPER - ALL_STAINED_GLASS_PANE diff --git a/modules/Movecraft/src/main/resources/types/1_14/elevator.craft b/modules/Movecraft/src/main/resources/types/1_14/elevator.craft index b1dcc0e7f..e4a3ab218 100644 --- a/modules/Movecraft/src/main/resources/types/1_14/elevator.craft +++ b/modules/Movecraft/src/main/resources/types/1_14/elevator.craft @@ -62,7 +62,7 @@ allowedBlocks: - daylight_detector - REDSTONE_BLOCK - HOPPER - - all_QUARTZ_BLOCK: + - all_QUARTZ_BLOCK - all_rail - DROPPER - ALL_STAINED_GLASS_PANE diff --git a/modules/Movecraft/src/main/resources/types/airskiff.craft b/modules/Movecraft/src/main/resources/types/airskiff.craft index 7cdea8794..57f424278 100644 --- a/modules/Movecraft/src/main/resources/types/airskiff.craft +++ b/modules/Movecraft/src/main/resources/types/airskiff.craft @@ -62,7 +62,7 @@ allowedBlocks: - daylight_detector - REDSTONE_BLOCK - HOPPER - - all_QUARTZ_BLOCK: + - all_QUARTZ_BLOCK - all_rail - DROPPER - ALL_STAINED_GLASS_PANE diff --git a/modules/Movecraft/src/main/resources/types/elevator.craft b/modules/Movecraft/src/main/resources/types/elevator.craft index b1dcc0e7f..e4a3ab218 100644 --- a/modules/Movecraft/src/main/resources/types/elevator.craft +++ b/modules/Movecraft/src/main/resources/types/elevator.craft @@ -62,7 +62,7 @@ allowedBlocks: - daylight_detector - REDSTONE_BLOCK - HOPPER - - all_QUARTZ_BLOCK: + - all_QUARTZ_BLOCK - all_rail - DROPPER - ALL_STAINED_GLASS_PANE From 9b72c64450b8e66b881a4a64a51c35a9680d61a9 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Sun, 15 Sep 2019 02:46:08 +0200 Subject: [PATCH 045/304] Removed debug messages --- .../java/net/countercraft/movecraft/craft/CraftManager.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/CraftManager.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/CraftManager.java index 537932334..ad74bd7ae 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/CraftManager.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/CraftManager.java @@ -119,7 +119,6 @@ private Set loadCraftTypes(){ File[] files = v1_14dir.listFiles(); for (File craftFile : files) { final String fileName = craftFile.getName(); - Bukkit.getLogger().info(fileName); File destination = new File(craftsFile, fileName); if (!craftFile.renameTo(destination)) continue; craftFile.delete(); @@ -137,7 +136,6 @@ private Set loadCraftTypes(){ if (file.isFile()) { if (file.getName().contains(".craft")) { - Bukkit.getLogger().info(file.getName()); CraftType type = new CraftType(file); craftTypes.add(type); } From ef8f0a1aad175aaebc89ad2943c53075ca53057c Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Fri, 20 Sep 2019 02:34:10 +0200 Subject: [PATCH 046/304] Bug fixes --- .../movecraft/async/AsyncManager.java | 4 +- .../async/detection/DetectionTask.java | 33 +++++------ .../async/rotation/RotationTask.java | 1 + .../async/translation/TranslationTask.java | 7 +++ .../movecraft/craft/CraftManager.java | 7 ++- .../countercraft/movecraft/craft/ICraft.java | 2 +- .../update/CraftTranslateCommand.java | 1 + .../movecraft/sign/SubcraftRotateSign.java | 11 ++-- .../movecraft/sync/EntityProcessor.java | 55 +++++++++---------- .../movecraft/craft/CraftType.java | 31 ++++++++--- .../compat/v1_13_R2/IWorldHandler.java | 2 +- 11 files changed, 89 insertions(+), 65 deletions(-) diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java index faed063eb..5067368c1 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java @@ -455,10 +455,10 @@ else if (climb){ if (pcraft.getCruiseDirection() == BlockFace.NORTH) { dz = 0 - 1 - pcraft.getType().getCruiseSkipBlocks(); if (bankRight) { - dx = (0 - 1 - pcraft.getType().getCruiseSkipBlocks()) >> 1; + dx = (1 + pcraft.getType().getCruiseSkipBlocks()) >> 1; } if (bankLeft) { - dx = (1 + pcraft.getType().getCruiseSkipBlocks()) >> 1; + dx = (0 - 1 - pcraft.getType().getCruiseSkipBlocks()) >> 1; } } // ship faces south diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/detection/DetectionTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/detection/DetectionTask.java index 4e780be2b..f1bb7e7b9 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/detection/DetectionTask.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/detection/DetectionTask.java @@ -399,32 +399,33 @@ private boolean confirmStructureRequirements(Map>, L float blockPercentage = (((float) numberOfBlocks / data.getBlockList().size()) * 100); Double minPercentage = flyBlocks.get(i).get(0); Double maxPercentage = flyBlocks.get(i).get(1); + ArrayList flyBlockTypes = new ArrayList<>(i.keySet()); if (minPercentage < 10000.0) { if (blockPercentage < minPercentage) { - if (i != null) { - if (i.get(0) != null) { - if (i.get(0).isEmpty() || i.get(0) == null) { + + if (i.get(flyBlockTypes.get(0)) == null) { + if (i.get(flyBlockTypes.get(0)).isEmpty()) { fail(String.format( I18nSupport.getInternationalisedString("Not enough flyblock") + ": %s %.2f%% < %.2f%%", - i.keySet().iterator().next().name().toLowerCase().replace("_", " "), blockPercentage, + flyBlockTypes.get(0).name().toLowerCase().replace("_", " "), blockPercentage, minPercentage)); return false; } else { fail(String.format( I18nSupport.getInternationalisedString("Not enough flyblock") + ": %s %.2f%% < %.2f%%", - i.keySet().iterator().next().name().toLowerCase().replace("_", " "), + flyBlockTypes.get(0).name().toLowerCase().replace("_", " "), blockPercentage, minPercentage)); return false; } } else { fail(String.format( I18nSupport.getInternationalisedString("Not enough flyblock") + ": %s %.2f%% < %.2f%%", - i.keySet().iterator().next().name().toLowerCase().replace("_", " "), blockPercentage, + flyBlockTypes.get(0).name().toLowerCase().replace("_", " "), blockPercentage, minPercentage)); return false; } } - } + } else { if (numberOfBlocks < flyBlocks.get(i).get(0) - 10000.0) { if (i != null) { @@ -432,19 +433,19 @@ private boolean confirmStructureRequirements(Map>, L if (i.get(0).isEmpty() || i.get(0) == null) { fail(String.format( I18nSupport.getInternationalisedString("Not enough flyblock") + ": %s %d < %d", - i.keySet().iterator().next().name().toLowerCase().replace("_", " "), numberOfBlocks, + flyBlockTypes.get(0).name().toLowerCase().replace("_", " "), numberOfBlocks, flyBlocks.get(i).get(0).intValue() - 10000)); return false; } else { fail(String.format( I18nSupport.getInternationalisedString("Not enough flyblock") + ": %s %d < %d", - i.keySet().iterator().next().name().toLowerCase().replace("_", " "), + flyBlockTypes.get(0).name().toLowerCase().replace("_", " "), numberOfBlocks, flyBlocks.get(i).get(0).intValue() - 10000)); return false; } } else { fail(String.format(I18nSupport.getInternationalisedString("Not enough flyblock") + ": %s %d > %d", - i.keySet().iterator().next().name().toLowerCase().replace("_", " "), numberOfBlocks, + flyBlockTypes.get(0).name().toLowerCase().replace("_", " "), numberOfBlocks, flyBlocks.get(i).get(1).intValue() - 10000)); return false; } @@ -458,20 +459,20 @@ private boolean confirmStructureRequirements(Map>, L if (i.get(0).isEmpty() || i.get(0) == null) { fail(String.format( I18nSupport.getInternationalisedString("Too much flyblock") + ": %s %.2f%% > %.2f%%", - i.keySet().iterator().next().name().toLowerCase().replace("_", " "), blockPercentage, + flyBlockTypes.get(0).name().toLowerCase().replace("_", " "), blockPercentage, maxPercentage)); return false; } else { fail(String.format( I18nSupport.getInternationalisedString("Too much flyblock") + ": %s %.2f%% > %.2f%%", - i.keySet().iterator().next().name().toLowerCase().replace("_", " "), + flyBlockTypes.get(0).name().toLowerCase().replace("_", " "), blockPercentage, maxPercentage)); return false; } } else { fail(String.format( I18nSupport.getInternationalisedString("Too much flyblock") + ": %s %.2f%% > %.2f%%", - i.keySet().iterator().next().name().toLowerCase().replace("_", " "), + flyBlockTypes.get(0).name().toLowerCase().replace("_", " "), blockPercentage, maxPercentage)); return false; } @@ -483,18 +484,18 @@ private boolean confirmStructureRequirements(Map>, L if (i.get(0) != null) { if (i.get(0).isEmpty()) { fail(String.format(I18nSupport.getInternationalisedString("Too much flyblock") + ": %s %d > %d", - i.keySet().iterator().next().name().toLowerCase().replace("_", " "), numberOfBlocks, + flyBlockTypes.get(0).name().toLowerCase().replace("_", " "), numberOfBlocks, flyBlocks.get(i).get(1).intValue() - 10000)); return false; } else { fail(String.format(I18nSupport.getInternationalisedString("Too much flyblock") + ": %s %d > %d", - i.keySet().iterator().next().name().toLowerCase().replace("_", " "), + flyBlockTypes.get(0).name().toLowerCase().replace("_", " "), numberOfBlocks, flyBlocks.get(i).get(1).intValue() - 10000)); return false; } } else { fail(String.format(I18nSupport.getInternationalisedString("Too much flyblock") + ": %s %d > %d", - i.keySet().iterator().next().name().toLowerCase().replace("_", " "), numberOfBlocks, + flyBlockTypes.get(0).name().toLowerCase().replace("_", " "), numberOfBlocks, flyBlocks.get(i).get(1).intValue() - 10000)); return false; } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/rotation/RotationTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/rotation/RotationTask.java index a76b936fb..3c5226d4a 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/rotation/RotationTask.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/rotation/RotationTask.java @@ -93,6 +93,7 @@ protected void execute() { return; Player craftPilot = CraftManager.getInstance().getPlayerFromCraft(getCraft()); + if (getCraft().getDisabled() && (!getCraft().getSinking())) { failed = true; failMessage = I18nSupport.getInternationalisedString("Translation - Failed Craft Is Disabled"); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java index 3620af376..58d327074 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java @@ -383,6 +383,13 @@ public void run() { }.runTask(Movecraft.getInstance()); } + if (oldHitBox.isEmpty()) + return; + if (!craft.getType().getMoveEntities() && !(craft.getSinking() && craft.getType().getOnlyMovePlayers())) { + //add releaseTask without playermove to manager + if (!craft.getType().getCruiseOnPilot() && !craft.getSinking()) // not necessary to release cruiseonpilot crafts, because they will already be released + CraftManager.getInstance().addReleaseTask(craft); + } updates.add(new CraftTranslateCommand(craft, new MovecraftLocation(dx, dy, dz))); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/CraftManager.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/CraftManager.java index ad74bd7ae..056cab199 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/CraftManager.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/CraftManager.java @@ -160,7 +160,12 @@ public void addCraft(@NotNull Craft c, @Nullable Player p) { public void removeCraft(@NotNull Craft c) { //TODO move this to callers - Bukkit.getServer().getPluginManager().callEvent(new CraftReleaseEvent(c, CraftReleaseEvent.Reason.PLAYER)); + new BukkitRunnable() { + @Override + public void run() { + Bukkit.getServer().getPluginManager().callEvent(new CraftReleaseEvent(c, CraftReleaseEvent.Reason.PLAYER)); + } + }.runTask(Movecraft.getInstance()); removeReleaseTask(c); Player player = getPlayerFromCraft(c); if (player!=null) diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/ICraft.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/ICraft.java index 7e8ac79de..25e4236cf 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/ICraft.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/ICraft.java @@ -87,7 +87,7 @@ public void translate(int dx, int dy, int dz) { setClimbing(false); } TranslationTask task = new TranslationTask(this, dx, dy, dz); - task.getUpdates().addAll(EntityProcessor.translateEntities(this, new MovecraftLocation(dx, dy, dz))); + task.getUpdates().addAll(EntityProcessor.translateEntities(this, dx, dy, dz)); Movecraft.getInstance().getAsyncManager().submitTask(task, this); } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftTranslateCommand.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftTranslateCommand.java index 433373dde..ac2844d53 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftTranslateCommand.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftTranslateCommand.java @@ -155,6 +155,7 @@ public void doUpdate() { craft.getPhaseBlocks().put(location, material); } //translate the craft + handler.translateCraft(craft, displacement); //trigger sign events for (MovecraftLocation location : craft.getHitBox()) { diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/SubcraftRotateSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/SubcraftRotateSign.java index aa05f20b5..4130a94c7 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/SubcraftRotateSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/SubcraftRotateSign.java @@ -7,11 +7,7 @@ import net.countercraft.movecraft.craft.CraftManager; import net.countercraft.movecraft.craft.CraftType; import net.countercraft.movecraft.craft.ICraft; -import net.countercraft.movecraft.localisation.I18nSupport; -import net.countercraft.movecraft.events.CraftDetectEvent; import net.countercraft.movecraft.events.CraftPilotEvent; -import net.countercraft.movecraft.events.CraftReleaseEvent; -import net.countercraft.movecraft.events.CraftRotateEvent; import net.countercraft.movecraft.localisation.I18nSupport; import net.countercraft.movecraft.utils.MathUtils; import org.bukkit.Bukkit; @@ -25,7 +21,8 @@ import org.bukkit.event.player.PlayerInteractEvent; import org.bukkit.scheduler.BukkitRunnable; -import java.util.*; +import java.util.HashSet; +import java.util.Set; public final class SubcraftRotateSign implements Listener { private static final String HEADER = "Subcraft Rotate"; @@ -49,7 +46,7 @@ public final void onSignClick(PlayerInteractEvent event) { return; } final Location loc = event.getClickedBlock().getLocation(); - final MovecraftLocation startPoint = new MovecraftLocation(loc.getBlockX(), loc.getBlockY(), loc.getBlockZ()); + final MovecraftLocation startPoint = MathUtils.bukkit2MovecraftLoc(loc); if(rotatingCrafts.contains(startPoint)){ event.getPlayer().sendMessage(I18nSupport.getInternationalisedString("Already Rotating")); event.setCancelled(true); @@ -103,7 +100,7 @@ public void run() { } }.runTaskLater(Movecraft.getInstance(), 3); } - }.runTaskLater(Movecraft.getInstance(), 3); + }.runTaskLater(Movecraft.getInstance(), 5); event.setCancelled(true); } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sync/EntityProcessor.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sync/EntityProcessor.java index d21012031..8991c8a42 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sync/EntityProcessor.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sync/EntityProcessor.java @@ -3,7 +3,6 @@ import net.countercraft.movecraft.MovecraftLocation; import net.countercraft.movecraft.Rotation; import net.countercraft.movecraft.craft.Craft; -import net.countercraft.movecraft.craft.CraftManager; import net.countercraft.movecraft.mapUpdater.update.EntityMoveUpdateCommand; import net.countercraft.movecraft.mapUpdater.update.UpdateCommand; import net.countercraft.movecraft.utils.HashHitBox; @@ -12,47 +11,45 @@ import org.bukkit.entity.Entity; import org.bukkit.entity.EntityType; -import java.util.LinkedList; +import java.util.HashSet; +import java.util.Set; public class EntityProcessor { private EntityProcessor(){ } - - public static LinkedList translateEntities(Craft craft, MovecraftLocation displacement) { - LinkedList updates = new LinkedList<>(); + public static Set translateEntities(Craft craft, int dx, int dy, int dz){ HashHitBox oldHitBox = craft.getHitBox(); - if (craft.getType().getMoveEntities() && !(craft.getSinking() && craft.getType().getOnlyMovePlayers())) { - Location midpoint = new Location( - craft.getW(), - (oldHitBox.getMaxX() + oldHitBox.getMinX())/2.0, - (oldHitBox.getMaxY() + oldHitBox.getMinY())/2.0, - (oldHitBox.getMaxZ() + oldHitBox.getMinZ())/2.0); - for (Entity entity : craft.getW().getNearbyEntities(midpoint, oldHitBox.getXLength() / 2.0 + 1, oldHitBox.getYLength() / 2.0 + 2, oldHitBox.getZLength() / 2.0 + 1)) { - if (entity.getType() == EntityType.PLAYER) { - if(craft.getSinking()){ - continue; - } - EntityMoveUpdateCommand eUp = new EntityMoveUpdateCommand(entity, displacement.getX(), displacement.getY(), displacement.getZ(), 0, 0); - updates.add(eUp); - } else if (!craft.getType().getOnlyMovePlayers() || entity.getType() == EntityType.PRIMED_TNT) { - EntityMoveUpdateCommand eUp = new EntityMoveUpdateCommand(entity, displacement.getX(), displacement.getY(), displacement.getZ(), 0, 0); - updates.add(eUp); + final HashSet updateCmds = new HashSet<>(); + if (oldHitBox.isEmpty()) + return updateCmds; + + Location midpoint = new Location( + craft.getW(), + (oldHitBox.getMaxX() + oldHitBox.getMinX())/2.0, + (oldHitBox.getMaxY() + oldHitBox.getMinY())/2.0, + (oldHitBox.getMaxZ() + oldHitBox.getMinZ())/2.0); + for (Entity entity : craft.getW().getNearbyEntities(midpoint, oldHitBox.getXLength() / 2.0 + 1, oldHitBox.getYLength() / 2.0 + 2, oldHitBox.getZLength() / 2.0 + 1)) { + if (entity.getType() == EntityType.PLAYER) { + if(craft.getSinking()){ + continue; } + EntityMoveUpdateCommand eUp = new EntityMoveUpdateCommand(entity, dx, dy, dz, 0, 0); + updateCmds.add(eUp); + } else if (!craft.getType().getOnlyMovePlayers() || entity.getType() == EntityType.PRIMED_TNT) { + EntityMoveUpdateCommand eUp = new EntityMoveUpdateCommand(entity, dx, dy, dz, 0, 0); + updateCmds.add(eUp); } - } else { - //add releaseTask without playermove to manager - if (!craft.getType().getCruiseOnPilot() && !craft.getSinking()) // not necessary to release cruiseonpilot crafts, because they will already be released - CraftManager.getInstance().addReleaseTask(craft); } - return updates; + return updateCmds; } - public static LinkedList rotateEntities(Craft craft, MovecraftLocation originPoint, Rotation rotation){ - //rotate entities in the craft - LinkedList updates = new LinkedList<>(); + public static Set rotateEntities(Craft craft, MovecraftLocation originPoint, Rotation rotation){ HashHitBox oldHitBox = craft.getHitBox(); + final HashSet updates = new HashSet<>(); + if (oldHitBox.isEmpty()) + return updates; Location tOP = new Location(craft.getW(), originPoint.getX(), originPoint.getY(), originPoint.getZ()); tOP.setX(tOP.getBlockX() + 0.5); tOP.setZ(tOP.getBlockZ() + 0.5); diff --git a/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java b/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java index 2ecb6c6f0..dddbd7ac9 100644 --- a/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java +++ b/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java @@ -717,8 +717,11 @@ private Map>, List> materialMapListFromObjec } } } else if (i instanceof Integer) { + if (!Settings.IsLegacy){ + throw new IllegalArgumentException("Numerical IDs are not supported by the current server version!"); + } Integer typeID = (Integer) i; - Material type = Settings.IsLegacy ? Material.getMaterial(typeID) : null; + Material type = Material.getMaterial(typeID); materialMap.put(type, new ArrayList<>()); } else if (i instanceof String) { String string = (String) i; @@ -745,19 +748,31 @@ private Map>, List> materialMapListFromObjec } } else { Material type; + boolean all = false; + if (string.toUpperCase().startsWith("ALL_")) { + string = string.replace("ALL_", ""); + for (Material m : Material.values()){ + if (m.name().endsWith(string)){ + materialMap.put(m, new ArrayList<>()); + } + all = true; + } + } if (string.contains("0") || string.contains("1") || string.contains("2") || string.contains("3") || string.contains("4") || string.contains("5") || string.contains("6") || string.contains("7") || string.contains("8") || string.contains("9")) { Integer typeID = Integer.valueOf(string); type = Material.getMaterial(typeID); - } else { + } else { type = Material.getMaterial(string); } - if (materialMap.containsKey(type)) { - List dataList = materialMap.get(type); - materialMap.put(type, dataList); - } else { - List dataList = new ArrayList<>(); - materialMap.put(type, dataList); + if (!all) { + if (materialMap.containsKey(type)) { + List dataList = materialMap.get(type); + materialMap.put(type, dataList); + } else { + List dataList = new ArrayList<>(); + materialMap.put(type, dataList); + } } } } else { diff --git a/modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/IWorldHandler.java b/modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/IWorldHandler.java index 3f584a586..b38063f66 100644 --- a/modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/IWorldHandler.java +++ b/modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/IWorldHandler.java @@ -305,7 +305,7 @@ public void setBlockFast(@NotNull Location location, @NotNull Rotation rotation, public void disableShadow(@NotNull Material type) { Method method; //try { - Block tempBlock = CraftMagicNumbers.getBlock(type); + Item item = CraftMagicNumbers.getItem(type); //method = Block.class.getDeclaredMethod("d", int.class); //method.setAccessible(true); //method.invoke(tempBlock, 0); From 0973ebf2bf419fbbdc0374edb5a407453b3f6069 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Sat, 21 Sep 2019 15:21:44 +0200 Subject: [PATCH 047/304] Fixed entity processing, event being fired async and added recommendation to use Paper --- .../net/countercraft/movecraft/Movecraft.java | 12 ++- .../async/rotation/RotationTask.java | 14 +-- .../async/translation/TranslationTask.java | 88 ++++++++++--------- .../countercraft/movecraft/craft/ICraft.java | 80 +++++++++++++++++ 4 files changed, 144 insertions(+), 50 deletions(-) diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java index 28af60401..c338a3342 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java @@ -112,7 +112,17 @@ public void onEnable() { }catch (Exception e){ Settings.IsPaper=false; } - + if (!Settings.IsPaper){ + logger.warning("======== Movecraft === Use Paper ======="); + logger.warning("Your server version: " + getServer().getVersion()); + logger.warning("You may experience performance issues"); + logger.warning("with this server platform."); + logger.warning(""); + logger.warning("It is recommended you use Paper"); + logger.warning("for better performance."); + logger.warning("Download at papermc.io/downloads"); + logger.warning("======== Movecraft === Use Paper ======="); + } Settings.LOCALE = getConfig().getString("Locale"); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/rotation/RotationTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/rotation/RotationTask.java index 3c5226d4a..c1adf748a 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/rotation/RotationTask.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/rotation/RotationTask.java @@ -98,13 +98,14 @@ protected void execute() { failed = true; failMessage = I18nSupport.getInternationalisedString("Translation - Failed Craft Is Disabled"); } - double fuelBurnRate = craft.getType().getFuelBurnRate(); - if (fuelBurnRate > 0.0) { + if (craft.getType().getFuelBurnRate() > 0.0) { + new BukkitRunnable() { @Override public void run() { // check for fuel, burn some from a furnace if needed. Blocks of coal are supported, in addition to coal and charcoal - + double fuelBurnRate = craft.getType().getFuelBurnRate(); + // going down doesn't require fuel if (fuelBurnRate == 0.0 || craft.getSinking()) { return; } @@ -113,7 +114,7 @@ public void run() { return; } Block fuelHolder = null; - for (MovecraftLocation bTest : craft.getHitBox()) { + for (MovecraftLocation bTest : oldHitBox) { Block b = craft.getW().getBlockAt(bTest.getX(), bTest.getY(), bTest.getZ()); //Get all fuel holders if (b.getType() == Material.FURNACE) { @@ -134,8 +135,8 @@ public void run() { return; } Furnace furnace = (Furnace) fuelHolder.getState(); - for (Material fuel : Settings.FuelTypes.keySet()) { - if (furnace.getInventory().contains(fuel)) { + for (Material fuel : Settings.FuelTypes.keySet()){ + if (furnace.getInventory().contains(fuel)){ ItemStack item = furnace.getInventory().getItem(furnace.getInventory().first(fuel)); int amount = item.getAmount(); if (amount == 1) { @@ -148,6 +149,7 @@ public void run() { } } }.runTask(Movecraft.getInstance()); + } // if a subcraft, find the parent craft. If not a subcraft, it is it's own parent Set craftsInWorld = CraftManager.getInstance().getCraftsInWorld(getCraft().getW()); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java index 58d327074..e197a81ec 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java @@ -132,6 +132,48 @@ protected void execute() { if(oldHitBox.isEmpty()){ return; } + + //Prevent disabled crafts from moving + if (getCraft().getDisabled() && (!getCraft().getSinking())) { + fail(I18nSupport.getInternationalisedString("Translation - Failed Craft Is Disabled")); + return; + } + + if (getCraft().isRepairing()){ + fail("You cannot move a repairing craft!"); + return; + } + final int minY = oldHitBox.getMinY(); + final int maxY = oldHitBox.getMaxY(); + + //Check if the craft is too high + if(craft.getType().getMaxHeightLimit() < craft.getHitBox().getMinY()){ + dy = Math.min(dy,-1); + }else if(craft.getType().getMaxHeightAboveGround() > 0){ + final MovecraftLocation middle = oldHitBox.getMidPoint(); + int testY = minY; + for (int y = minY;y > 0;y--) { + if (y == minY) + continue; + if (craft.getW().getBlockAt(middle.getX(), y, middle.getZ()).getType() == Material.AIR || !Settings.IsLegacy && (craft.getW().getBlockAt(middle.getX(), y, middle.getZ()).getType() == Material.CAVE_AIR || craft.getW().getBlockAt(middle.getX(), y, middle.getZ()).getType() == Material.VOID_AIR)){ + continue; + } + testY = y; + break; + } + if (minY - testY > craft.getType().getMaxHeightAboveGround()) { + dy = Math.min(dy,-1); + } + } + + //Fail the movement if the craft is too high + if (dy>0 && maxY + dy > craft.getType().getMaxHeightLimit()) { + fail(I18nSupport.getInternationalisedString("Translation - Failed Craft hit height limit")); + return; + } else if (minY + dy < craft.getType().getMinHeightLimit() && dy < 0 && !craft.getSinking()) { + fail(I18nSupport.getInternationalisedString("Translation - Failed Craft hit minimum height limit")); + return; + } if (craft.getType().getFuelBurnRate() > 0.0) { new BukkitRunnable() { @Override @@ -151,7 +193,7 @@ public void run() { return; } Block fuelHolder = null; - for (MovecraftLocation bTest : craft.getHitBox()) { + for (MovecraftLocation bTest : oldHitBox) { Block b = craft.getW().getBlockAt(bTest.getX(), bTest.getY(), bTest.getZ()); //Get all fuel holders if (b.getType() == Material.FURNACE) { @@ -171,8 +213,8 @@ public void run() { return; } Furnace furnace = (Furnace) fuelHolder.getState(); - for (Material fuel : Settings.FuelTypes.keySet()) { - if (furnace.getInventory().contains(fuel)) { + for (Material fuel : Settings.FuelTypes.keySet()){ + if (furnace.getInventory().contains(fuel)){ ItemStack item = furnace.getInventory().getItem(furnace.getInventory().first(fuel)); int amount = item.getAmount(); if (amount == 1) { @@ -185,49 +227,9 @@ public void run() { } } }.runTask(Movecraft.getInstance()); - } - //Prevent disabled crafts from moving - if (getCraft().getDisabled() && (!getCraft().getSinking())) { - fail(I18nSupport.getInternationalisedString("Translation - Failed Craft Is Disabled")); - return; - } - if (getCraft().isRepairing()){ - fail("You cannot move a repairing craft!"); - return; - } - final int minY = oldHitBox.getMinY(); - final int maxY = oldHitBox.getMaxY(); - //Check if the craft is too high - if(craft.getType().getMaxHeightLimit() < craft.getHitBox().getMinY()){ - dy = Math.min(dy,-1); - }else if(craft.getType().getMaxHeightAboveGround() > 0){ - final MovecraftLocation middle = oldHitBox.getMidPoint(); - int testY = minY; - for (int y = minY;y > 0;y--) { - if (y == minY) - continue; - if (craft.getW().getBlockAt(middle.getX(), y, middle.getZ()).getType() == Material.AIR || !Settings.IsLegacy && (craft.getW().getBlockAt(middle.getX(), y, middle.getZ()).getType() == Material.CAVE_AIR || craft.getW().getBlockAt(middle.getX(), y, middle.getZ()).getType() == Material.VOID_AIR)){ - continue; - } - testY = y; - break; - } - if (minY - testY > craft.getType().getMaxHeightAboveGround()) { - dy = Math.min(dy,-1); - } } - - //Fail the movement if the craft is too high - if (dy>0 && maxY + dy > craft.getType().getMaxHeightLimit()) { - fail(I18nSupport.getInternationalisedString("Translation - Failed Craft hit height limit")); - return; - } else if (minY + dy < craft.getType().getMinHeightLimit() && dy < 0 && !craft.getSinking()) { - fail(I18nSupport.getInternationalisedString("Translation - Failed Craft hit minimum height limit")); - return; - } - //TODO: Check fuel //if (!checkFuel()) { //fail(I18nSupport.getInternationalisedString("Translation - Failed Craft out of fuel")); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/ICraft.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/ICraft.java index 25e4236cf..8621b4799 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/ICraft.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/ICraft.java @@ -6,10 +6,18 @@ import net.countercraft.movecraft.async.detection.DetectionTask; import net.countercraft.movecraft.async.rotation.RotationTask; import net.countercraft.movecraft.async.translation.TranslationTask; +import net.countercraft.movecraft.config.Settings; import net.countercraft.movecraft.localisation.I18nSupport; +import net.countercraft.movecraft.mapUpdater.MapUpdateManager; +import net.countercraft.movecraft.mapUpdater.update.FuelBurnUpdateCommand; import net.countercraft.movecraft.sync.EntityProcessor; +import org.bukkit.Material; +import org.bukkit.Sound; import org.bukkit.World; +import org.bukkit.block.Block; +import org.bukkit.block.Furnace; import org.bukkit.entity.Player; +import org.bukkit.inventory.InventoryHolder; import org.jetbrains.annotations.NotNull; import java.util.UUID; @@ -87,6 +95,7 @@ public void translate(int dx, int dy, int dz) { setClimbing(false); } TranslationTask task = new TranslationTask(this, dx, dy, dz); + task.getUpdates().addAll(EntityProcessor.translateEntities(this, dx, dy, dz)); Movecraft.getInstance().getAsyncManager().submitTask(task, this); } @@ -135,6 +144,42 @@ public void rotate(Rotation rotation, MovecraftLocation originPoint) { } }*/ RotationTask task = new RotationTask(this, originPoint, rotation, this.getW()); + if (getType().getFuelBurnRate() > 0.0) { + + // check for fuel, burn some from a furnace if needed. Blocks of coal are supported, in addition to coal and charcoal + double fuelBurnRate = getType().getFuelBurnRate(); + // going down doesn't require fuel + if (fuelBurnRate == 0.0 || getSinking()) { + return; + } + if (getBurningFuel() >= fuelBurnRate) { + setBurningFuel(getBurningFuel() - fuelBurnRate); + return; + } + Block fuelHolder = null; + for (MovecraftLocation bTest : getHitBox()) { + Block b = getW().getBlockAt(bTest.getX(), bTest.getY(), bTest.getZ()); + //Get all fuel holders + if (b.getType() == Material.FURNACE) { + InventoryHolder holder = (InventoryHolder) b.getState(); + for (Material fuel : Settings.FuelTypes.keySet()) { + if (holder.getInventory().contains(fuel)) { + fuelHolder = b; + break; + } + } + } + if (fuelHolder != null) break; + + } + if (fuelHolder == null) { + getNotificationPlayer().sendMessage(I18nSupport.getInternationalisedString("Translation - Failed Craft out of fuel")); + return; + } + Furnace furnace = (Furnace) fuelHolder.getState(); + MapUpdateManager.getInstance().scheduleUpdate(new FuelBurnUpdateCommand(this, fuelHolder)); + + } task.getUpdates().addAll(EntityProcessor.rotateEntities(this, originPoint, rotation)); Movecraft.getInstance().getAsyncManager().submitTask(task, this); } @@ -142,6 +187,41 @@ public void rotate(Rotation rotation, MovecraftLocation originPoint) { @Override public void rotate(Rotation rotation, MovecraftLocation originPoint, boolean isSubCraft) { RotationTask task = new RotationTask(this, originPoint, rotation, this.getW(), isSubCraft); + if (getType().getFuelBurnRate() > 0.0) { + + // check for fuel, burn some from a furnace if needed. Blocks of coal are supported, in addition to coal and charcoal + double fuelBurnRate = getType().getFuelBurnRate(); + // going down doesn't require fuel + if (fuelBurnRate == 0.0 || getSinking()) { + return; + } + if (getBurningFuel() >= fuelBurnRate) { + setBurningFuel(getBurningFuel() - fuelBurnRate); + return; + } + Block fuelHolder = null; + for (MovecraftLocation bTest : getHitBox()) { + Block b = getW().getBlockAt(bTest.getX(), bTest.getY(), bTest.getZ()); + //Get all fuel holders + if (b.getType() == Material.FURNACE) { + InventoryHolder holder = (InventoryHolder) b.getState(); + for (Material fuel : Settings.FuelTypes.keySet()) { + if (holder.getInventory().contains(fuel)) { + fuelHolder = b; + break; + } + } + } + if (fuelHolder != null) break; + + } + if (fuelHolder == null) { + getNotificationPlayer().sendMessage(I18nSupport.getInternationalisedString("Translation - Failed Craft out of fuel")); + return; + } + MapUpdateManager.getInstance().scheduleUpdate(new FuelBurnUpdateCommand(this, fuelHolder)); + + } task.getUpdates().addAll(EntityProcessor.rotateEntities(this, originPoint, rotation)); Movecraft.getInstance().getAsyncManager().submitTask(task, this); } From 8ffca32d25a51c31b169cb12fe18eabade58e2ea Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Tue, 24 Sep 2019 21:52:24 +0200 Subject: [PATCH 048/304] Fixed several movement bugs. Includes, but are not limited to: - Crafts banking to the opposite side at certain cruise directions - Crafts unable to rotate more than once. Closing #4 --- .../movecraft/async/AsyncManager.java | 4 +- .../async/rotation/RotationTask.java | 8 +- .../async/translation/TranslationTask.java | 62 ++++++- .../countercraft/movecraft/craft/ICraft.java | 174 +++++++++++------- .../update/EntityMoveUpdateCommand.java | 6 +- .../movecraft/sign/CruiseSign.java | 4 - .../countercraft/movecraft/WorldHandler.java | 7 +- 7 files changed, 184 insertions(+), 81 deletions(-) diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java index 5067368c1..41365717b 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java @@ -465,10 +465,10 @@ else if (climb){ if (pcraft.getCruiseDirection() == BlockFace.SOUTH) { dz = 1 + pcraft.getType().getCruiseSkipBlocks(); if (bankLeft) { - dx = (0 - 1 - pcraft.getType().getCruiseSkipBlocks()) >> 1; + dx = (1 + pcraft.getType().getCruiseSkipBlocks()) >> 1; } if (bankRight) { - dx = (1 + pcraft.getType().getCruiseSkipBlocks()) >> 1; + dx = (0 - 1 - pcraft.getType().getCruiseSkipBlocks()) >> 1; } } if (pcraft.getType().getCruiseOnPilot()) { diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/rotation/RotationTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/rotation/RotationTask.java index c1adf748a..247b66d20 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/rotation/RotationTask.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/rotation/RotationTask.java @@ -237,19 +237,19 @@ public void run() { // ship faces west switch (getCraft().getCruiseDirection()) { case WEST: - getCraft().setCruiseDirection(BlockFace.SOUTH); + getCraft().setCruiseDirection(BlockFace.NORTH); break; // ship faces east case EAST: - getCraft().setCruiseDirection(BlockFace.NORTH); + getCraft().setCruiseDirection(BlockFace.SOUTH); break; // ship faces north case NORTH: - getCraft().setCruiseDirection(BlockFace.WEST); + getCraft().setCruiseDirection(BlockFace.EAST); break; // ship faces south case SOUTH: - getCraft().setCruiseDirection(BlockFace.EAST); + getCraft().setCruiseDirection(BlockFace.WEST); break; } } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java index e197a81ec..76533bc07 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java @@ -19,6 +19,7 @@ import org.bukkit.Material; import org.bukkit.Sound; import org.bukkit.block.Block; +import org.bukkit.block.BlockFace; import org.bukkit.block.Chest; import org.bukkit.block.Furnace; import org.bukkit.entity.EntityType; @@ -165,7 +166,27 @@ protected void execute() { dy = Math.min(dy,-1); } } - + if (craft.getType().getUseGravity() && !craft.getSinking()){ + boolean onGround = isOnGround(oldHitBox); + boolean inclined = dy >= 0 && inclineCraft(oldHitBox); + boolean hoverCraft = craft.getType().getCanHover(); + if (inclined){ + dy = 1; + } else if (!onGround && hoverCraft){ + MovecraftLocation midPoint = oldHitBox.getMidPoint(); + MovecraftLocation bottomPoint = new MovecraftLocation(midPoint.getX(), oldHitBox.getMinY(), midPoint.getZ()); + MovecraftLocation testSurface = bottomPoint.translate(0, -1, 0); + while (oldHitBox.contains(testSurface) || testSurface.toBukkit(craft.getW()).getBlock().getRelative(BlockFace.DOWN).getType().equals(Material.AIR) || craft.getType().getPassthroughBlocks().contains(testSurface.toBukkit(craft.getW()).getBlock().getRelative(BlockFace.DOWN).getType())){ + testSurface = testSurface.translate(0, -1, 0); + } + int distance = bottomPoint.getY() - testSurface.getY(); + if (distance > craft.getType().getHoverLimit()){ + dy = -1; + } + } else if (!onGround){ + dy = -1; + } + } //Fail the movement if the craft is too high if (dy>0 && maxY + dy > craft.getType().getMaxHeightLimit()) { fail(I18nSupport.getInternationalisedString("Translation - Failed Craft hit height limit")); @@ -294,6 +315,12 @@ public void run() { } } //END OF: if (blockObstructed) } + for (UpdateCommand update : getUpdates()){ + if (!(update instanceof EntityMoveUpdateCommand)) + continue; + EntityMoveUpdateCommand eUp = (EntityMoveUpdateCommand) update; + eUp.setY(dy); + } //call event CraftTranslateEvent event = new CraftTranslateEvent(craft, oldHitBox, newHitBox); @@ -521,7 +548,40 @@ private ItemStack putInToChests(ItemStack stack, ArrayList inventorie return stack; } + private boolean inclineCraft(HashHitBox hitBox){ + HashHitBox collisionBox = new HashHitBox(); + for (MovecraftLocation ml : hitBox){ + MovecraftLocation nl = ml.translate(dx, dy, dz); + if (hitBox.contains(nl)) + continue; + if (ml.getY() > hitBox.getMinY()) + continue; + collisionBox.add(nl); + } + for (MovecraftLocation ml : collisionBox){ + if (!ml.toBukkit(craft.getW()).getBlock().getType().equals(Material.AIR) && !craft.getType().getPassthroughBlocks().contains(ml.toBukkit(craft.getW()).getBlock().getType()) && !craft.getType().getHarvestBlocks().contains(ml.toBukkit(craft.getW()).getBlock().getType())){ + return true; + } + } + + return false; + } + private boolean isOnGround(HashHitBox hitBox){ + for (MovecraftLocation location : hitBox){ + MovecraftLocation newLoc = location.translate(dx, dy, dz); + int minY = hitBox.getMinY() + dy; + if (newLoc.getY() > minY){ + continue; + } + Location groundLoc = newLoc.translate(0,-1,0).toBukkit(craft.getW()); + if (groundLoc.getBlock().getType().equals(Material.AIR) || craft.getType().getPassthroughBlocks().contains(groundLoc.getBlock().getType())){ + continue; + } + return true; + } + return false; + } public boolean failed(){ diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/ICraft.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/ICraft.java index 8621b4799..8f800b007 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/ICraft.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/ICraft.java @@ -6,18 +6,16 @@ import net.countercraft.movecraft.async.detection.DetectionTask; import net.countercraft.movecraft.async.rotation.RotationTask; import net.countercraft.movecraft.async.translation.TranslationTask; -import net.countercraft.movecraft.config.Settings; import net.countercraft.movecraft.localisation.I18nSupport; -import net.countercraft.movecraft.mapUpdater.MapUpdateManager; -import net.countercraft.movecraft.mapUpdater.update.FuelBurnUpdateCommand; import net.countercraft.movecraft.sync.EntityProcessor; +import net.countercraft.movecraft.utils.HashHitBox; +import net.countercraft.movecraft.utils.MathUtils; +import org.bukkit.Location; import org.bukkit.Material; -import org.bukkit.Sound; import org.bukkit.World; -import org.bukkit.block.Block; -import org.bukkit.block.Furnace; +import org.bukkit.block.BlockFace; import org.bukkit.entity.Player; -import org.bukkit.inventory.InventoryHolder; +import org.bukkit.scheduler.BukkitRunnable; import org.jetbrains.annotations.NotNull; import java.util.UUID; @@ -143,89 +141,126 @@ public void rotate(Rotation rotation, MovecraftLocation originPoint) { } } }*/ - RotationTask task = new RotationTask(this, originPoint, rotation, this.getW()); - if (getType().getFuelBurnRate() > 0.0) { - - // check for fuel, burn some from a furnace if needed. Blocks of coal are supported, in addition to coal and charcoal - double fuelBurnRate = getType().getFuelBurnRate(); - // going down doesn't require fuel - if (fuelBurnRate == 0.0 || getSinking()) { - return; - } - if (getBurningFuel() >= fuelBurnRate) { - setBurningFuel(getBurningFuel() - fuelBurnRate); + if (getType().getUseGravity()) { + MoveOnRotate move = moveUp(rotation, originPoint); + final Craft craft = this; + if (move.equals(MoveOnRotate.UP)) { + translate(0, 1, 0); + new BukkitRunnable(){ + @Override + public void run() { + RotationTask task = new RotationTask(craft, originPoint, rotation, craft.getW()); + task.getUpdates().addAll(EntityProcessor.rotateEntities(craft, originPoint, rotation)); + Movecraft.getInstance().getAsyncManager().submitTask(task, craft); + } + }.runTaskLaterAsynchronously(Movecraft.getInstance(), 5); return; - } - Block fuelHolder = null; - for (MovecraftLocation bTest : getHitBox()) { - Block b = getW().getBlockAt(bTest.getX(), bTest.getY(), bTest.getZ()); - //Get all fuel holders - if (b.getType() == Material.FURNACE) { - InventoryHolder holder = (InventoryHolder) b.getState(); - for (Material fuel : Settings.FuelTypes.keySet()) { - if (holder.getInventory().contains(fuel)) { - fuelHolder = b; - break; - } + } else if (move.equals(MoveOnRotate.DOWN)) { + RotationTask task = new RotationTask(craft, originPoint, rotation, craft.getW()); + task.getUpdates().addAll(EntityProcessor.rotateEntities(craft, originPoint, rotation)); + Movecraft.getInstance().getAsyncManager().submitTask(task, craft); + new BukkitRunnable(){ + @Override + public void run() { + translate(0, -1, 0); } - } - if (fuelHolder != null) break; - - } - if (fuelHolder == null) { - getNotificationPlayer().sendMessage(I18nSupport.getInternationalisedString("Translation - Failed Craft out of fuel")); + }.runTaskLaterAsynchronously(Movecraft.getInstance(), 5); return; } - Furnace furnace = (Furnace) fuelHolder.getState(); - MapUpdateManager.getInstance().scheduleUpdate(new FuelBurnUpdateCommand(this, fuelHolder)); - } + RotationTask task = new RotationTask(this, originPoint, rotation, this.getW()); task.getUpdates().addAll(EntityProcessor.rotateEntities(this, originPoint, rotation)); Movecraft.getInstance().getAsyncManager().submitTask(task, this); + } @Override public void rotate(Rotation rotation, MovecraftLocation originPoint, boolean isSubCraft) { - RotationTask task = new RotationTask(this, originPoint, rotation, this.getW(), isSubCraft); - if (getType().getFuelBurnRate() > 0.0) { + if (getType().getUseGravity()) { + MoveOnRotate move = moveUp(rotation, originPoint); + boolean translated = false; + if (move.equals(MoveOnRotate.UP)) { + translate(0, 1, 0); + translated = true; + } else if (move.equals(MoveOnRotate.DOWN)) { + translate(0, -1, 0); + translated = true; + } + if (translated){ + final Craft craft = this; + new BukkitRunnable(){ - // check for fuel, burn some from a furnace if needed. Blocks of coal are supported, in addition to coal and charcoal - double fuelBurnRate = getType().getFuelBurnRate(); - // going down doesn't require fuel - if (fuelBurnRate == 0.0 || getSinking()) { + @Override + public void run() { + RotationTask task = new RotationTask(craft, originPoint, rotation, craft.getW(), isSubCraft); + task.getUpdates().addAll(EntityProcessor.rotateEntities(craft, originPoint, rotation)); + Movecraft.getInstance().getAsyncManager().submitTask(task, craft); + } + }.runTaskLaterAsynchronously(Movecraft.getInstance(), 8); return; } - if (getBurningFuel() >= fuelBurnRate) { - setBurningFuel(getBurningFuel() - fuelBurnRate); - return; + } + RotationTask task = new RotationTask(this, originPoint, rotation, this.getW(), isSubCraft); + task.getUpdates().addAll(EntityProcessor.rotateEntities(this, originPoint, rotation)); + Movecraft.getInstance().getAsyncManager().submitTask(task, this); + } + + private MoveOnRotate moveUp(Rotation rotation, MovecraftLocation originPoint){ + HashHitBox newHitBox = new HashHitBox(); + for (MovecraftLocation origLoc : getHitBox()) { + MovecraftLocation newLoc = MathUtils.rotateVec(rotation, origLoc.subtract(originPoint)).add(originPoint); + if (getHitBox().contains(newLoc)){ + continue; } - Block fuelHolder = null; - for (MovecraftLocation bTest : getHitBox()) { - Block b = getW().getBlockAt(bTest.getX(), bTest.getY(), bTest.getZ()); - //Get all fuel holders - if (b.getType() == Material.FURNACE) { - InventoryHolder holder = (InventoryHolder) b.getState(); - for (Material fuel : Settings.FuelTypes.keySet()) { - if (holder.getInventory().contains(fuel)) { - fuelHolder = b; - break; - } - } + newHitBox.add(newLoc); + } + for (MovecraftLocation newLoc : newHitBox){ + Location bukkitLoc = newLoc.toBukkit(getW()); + Material testObstackle = bukkitLoc.getBlock().getType(); + if (!testObstackle.equals(Material.AIR) && !getType().getPassthroughBlocks().contains(testObstackle) && !getType().getHarvestBlocks().contains(testObstackle)) { + return MoveOnRotate.UP; + } + } + for (MovecraftLocation newLoc : newHitBox){ + Rotation invertedRotation; + if (rotation.equals(Rotation.CLOCKWISE)){ + invertedRotation = Rotation.ANTICLOCKWISE; + } else if (rotation.equals(Rotation.ANTICLOCKWISE)){ + invertedRotation = Rotation.CLOCKWISE; + } else { + invertedRotation = rotation; + } + MovecraftLocation origLoc = MathUtils.rotateVec(invertedRotation , newLoc.subtract(originPoint)).add(originPoint); + Location bukkitLoc = newLoc.toBukkit(getW()); + Material testSurface = bukkitLoc.getBlock().getRelative(0, -1, 0).getType(); + if (!testSurface.equals(Material.AIR) && + !getType().getPassthroughBlocks().contains(testSurface) || newLoc.getY() <= getType().getMinHeightLimit()) { + if (getType().getHarvestBlocks().contains(testSurface) && getType().getHarvesterBladeBlocks().contains(origLoc.toBukkit(getW()).getBlock().getType())) { + continue; } - if (fuelHolder != null) break; + return MoveOnRotate.NONE; + } + } + + + + + if (getType().getCanHover()){ + MovecraftLocation bottomPoint = new MovecraftLocation(getHitBox().getMidPoint().getX(), getHitBox().getMinY(), getHitBox().getMidPoint().getZ()); + MovecraftLocation surface = bottomPoint; + while (surface.toBukkit(getW()).getBlock().getRelative(BlockFace.DOWN).getType() == Material.AIR || getType().getPassthroughBlocks().contains(surface.toBukkit(getW()).getBlock().getRelative(BlockFace.DOWN).getType())){ + surface = surface.translate(0, -1, 0); } - if (fuelHolder == null) { - getNotificationPlayer().sendMessage(I18nSupport.getInternationalisedString("Translation - Failed Craft out of fuel")); - return; + int distance = bottomPoint.getY() - surface.getY(); + if (distance <= getType().getHoverLimit()){ + return MoveOnRotate.NONE; } - MapUpdateManager.getInstance().scheduleUpdate(new FuelBurnUpdateCommand(this, fuelHolder)); - } - task.getUpdates().addAll(EntityProcessor.rotateEntities(this, originPoint, rotation)); - Movecraft.getInstance().getAsyncManager().submitTask(task, this); + return MoveOnRotate.DOWN; } + @Override public boolean equals(Object obj) { if(!(obj instanceof ICraft)){ @@ -239,4 +274,7 @@ public int hashCode() { return id.hashCode(); } + private enum MoveOnRotate{ + NONE, UP, DOWN + } } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/EntityMoveUpdateCommand.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/EntityMoveUpdateCommand.java index 6e4fca7aa..079f4e4fd 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/EntityMoveUpdateCommand.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/EntityMoveUpdateCommand.java @@ -30,7 +30,7 @@ public class EntityMoveUpdateCommand extends UpdateCommand { private final Entity entity; private final double x; - private final double y; + private double y; private final double z; private final float yaw; private final float pitch; @@ -57,6 +57,10 @@ public void doUpdate() { } Movecraft.getInstance().getWorldHandler().addPlayerLocation((Player) entity,x,y,z,yaw,pitch); + + } + public void setY(int y){ + this.y = y; } @Override diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CruiseSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CruiseSign.java index 7028b0294..de9fc64d2 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CruiseSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CruiseSign.java @@ -1,6 +1,5 @@ package net.countercraft.movecraft.sign; -import net.countercraft.movecraft.Movecraft; import net.countercraft.movecraft.MovecraftLocation; import net.countercraft.movecraft.config.Settings; import net.countercraft.movecraft.craft.Craft; @@ -99,9 +98,6 @@ public final void onSignClick(PlayerInteractEvent event) { sign.update(true); CraftManager.getInstance().getCraftByPlayer(event.getPlayer()).setCruising(false); } - if (c == null) - return; - Movecraft.getInstance().getLogger().info("Cruising: " + c.getCruising()); } @EventHandler(priority = EventPriority.NORMAL) diff --git a/modules/api/src/main/java/net/countercraft/movecraft/WorldHandler.java b/modules/api/src/main/java/net/countercraft/movecraft/WorldHandler.java index 4c81c798b..18c02ef8d 100644 --- a/modules/api/src/main/java/net/countercraft/movecraft/WorldHandler.java +++ b/modules/api/src/main/java/net/countercraft/movecraft/WorldHandler.java @@ -3,6 +3,8 @@ import net.countercraft.movecraft.craft.Craft; import org.bukkit.Location; import org.bukkit.Material; +import org.bukkit.block.Block; +import org.bukkit.block.BlockFace; import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; @@ -14,6 +16,9 @@ public abstract class WorldHandler { public abstract void disableShadow(@NotNull Material type); public void addPlayerLocation(Player player, double x, double y, double z, float yaw, float pitch){ Location playerLoc = player.getLocation(); - player.teleport(new Location(player.getWorld(), x + playerLoc.getX(),y + playerLoc.getY(),z + playerLoc.getZ(),yaw + playerLoc.getYaw(),pitch + playerLoc.getPitch())); + Block standingOn = playerLoc.getBlock().getRelative(BlockFace.DOWN); + Location tpLoc = new Location(player.getWorld(), x + playerLoc.getX(),y + playerLoc.getY(),z + playerLoc.getZ(),yaw + playerLoc.getYaw(),pitch + playerLoc.getPitch()); + player.teleport(tpLoc); + player.sendBlockChange(tpLoc.subtract(0,1,0), standingOn.getType(), standingOn.getData()); } } From 990a710651bc05d5c0f35f79c96e5ac1d6c60c56 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Thu, 26 Sep 2019 00:49:15 +0200 Subject: [PATCH 049/304] Fixed gravity on rotation --- .../countercraft/movecraft/craft/ICraft.java | 25 +++++++++++-------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/ICraft.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/ICraft.java index 8f800b007..3dd91487b 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/ICraft.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/ICraft.java @@ -178,25 +178,28 @@ public void run() { public void rotate(Rotation rotation, MovecraftLocation originPoint, boolean isSubCraft) { if (getType().getUseGravity()) { MoveOnRotate move = moveUp(rotation, originPoint); - boolean translated = false; + final Craft craft = this; if (move.equals(MoveOnRotate.UP)) { translate(0, 1, 0); - translated = true; - } else if (move.equals(MoveOnRotate.DOWN)) { - translate(0, -1, 0); - translated = true; - } - if (translated){ - final Craft craft = this; new BukkitRunnable(){ - @Override public void run() { - RotationTask task = new RotationTask(craft, originPoint, rotation, craft.getW(), isSubCraft); + RotationTask task = new RotationTask(craft, originPoint, rotation, craft.getW()); task.getUpdates().addAll(EntityProcessor.rotateEntities(craft, originPoint, rotation)); Movecraft.getInstance().getAsyncManager().submitTask(task, craft); } - }.runTaskLaterAsynchronously(Movecraft.getInstance(), 8); + }.runTaskLaterAsynchronously(Movecraft.getInstance(), 5); + return; + } else if (move.equals(MoveOnRotate.DOWN)) { + RotationTask task = new RotationTask(craft, originPoint, rotation, craft.getW()); + task.getUpdates().addAll(EntityProcessor.rotateEntities(craft, originPoint, rotation)); + Movecraft.getInstance().getAsyncManager().submitTask(task, craft); + new BukkitRunnable(){ + @Override + public void run() { + translate(0, -1, 0); + } + }.runTaskLaterAsynchronously(Movecraft.getInstance(), 5); return; } } From 59255699c2dc00cd6a74e7efbfac5039bb2b4b93 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Mon, 30 Sep 2019 22:07:57 +0200 Subject: [PATCH 050/304] Now using NMS for player teleport. Also found a way to get around players being tped to 0,0,0 in 1.13 and 1.14 --- .../movecraft/sync/EntityProcessor.java | 4 +-- .../compat/v1_13_R2/IWorldHandler.java | 28 ++++++++++++++++-- .../compat/v1_14_R1/IWorldHandler.java | 29 +++++++++++++++---- .../compat/we6/IMovecraftRepair.java | 2 -- 4 files changed, 51 insertions(+), 12 deletions(-) diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sync/EntityProcessor.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sync/EntityProcessor.java index 8991c8a42..f662f52a0 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sync/EntityProcessor.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sync/EntityProcessor.java @@ -35,10 +35,10 @@ public static Set translateEntities(Craft craft, int dx, int dy, if(craft.getSinking()){ continue; } - EntityMoveUpdateCommand eUp = new EntityMoveUpdateCommand(entity, dx, dy, dz, 0, 0); + EntityMoveUpdateCommand eUp = new EntityMoveUpdateCommand(entity, dx, dy, dz, entity.getLocation().getYaw(), entity.getLocation().getPitch()); updateCmds.add(eUp); } else if (!craft.getType().getOnlyMovePlayers() || entity.getType() == EntityType.PRIMED_TNT) { - EntityMoveUpdateCommand eUp = new EntityMoveUpdateCommand(entity, dx, dy, dz, 0, 0); + EntityMoveUpdateCommand eUp = new EntityMoveUpdateCommand(entity, dx, dy, dz, entity.getLocation().getYaw(), entity.getLocation().getPitch()); updateCmds.add(eUp); } } diff --git a/modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/IWorldHandler.java b/modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/IWorldHandler.java index b38063f66..e6023b543 100644 --- a/modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/IWorldHandler.java +++ b/modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/IWorldHandler.java @@ -1,18 +1,22 @@ package net.countercraft.movecraft.compat.v1_13_R2; -import net.countercraft.movecraft.config.Settings; -import net.countercraft.movecraft.utils.MathUtils; import net.countercraft.movecraft.MovecraftLocation; import net.countercraft.movecraft.Rotation; -import net.countercraft.movecraft.utils.CollectionUtils; import net.countercraft.movecraft.WorldHandler; +import net.countercraft.movecraft.config.Settings; import net.countercraft.movecraft.craft.Craft; +import net.countercraft.movecraft.utils.CollectionUtils; +import net.countercraft.movecraft.utils.MathUtils; import net.minecraft.server.v1_13_R2.*; +import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.Material; +import org.bukkit.craftbukkit.v1_13_R2.entity.CraftPlayer; import org.bukkit.craftbukkit.v1_13_R2.CraftWorld; import org.bukkit.craftbukkit.v1_13_R2.block.CraftBlockState; import org.bukkit.craftbukkit.v1_13_R2.util.CraftMagicNumbers; +import org.bukkit.entity.Player; +import org.bukkit.event.player.PlayerMoveEvent; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -245,6 +249,24 @@ public void translateCraft(@NotNull Craft craft, @NotNull MovecraftLocation disp //sendToPlayers(chunks.toArray(new Chunk[0])); } + @Override + public void addPlayerLocation(Player player, double x, double y, double z, float yaw, float pitch){ + EntityPlayer ePlayer = ((CraftPlayer) player).getHandle(); + if(internalTeleportMH == null) { + //something went wrong + super.addPlayerLocation(player, x, y, z, yaw, pitch); + return; + } + try { + final Location oldLoc = player.getLocation().clone(); + final Location newLoc = player.getLocation().add(x,y,z); + internalTeleportMH.invoke(ePlayer.playerConnection, x + player.getLocation().getX(), y + player.getLocation().getY(), z + player.getLocation().getZ(), yaw, pitch, EnumSet.allOf(PacketPlayOutPosition.EnumPlayerTeleportFlags.class)); + Bukkit.getServer().getPluginManager().callEvent(new PlayerMoveEvent(player,oldLoc,newLoc)); + } catch (Throwable throwable) { + throwable.printStackTrace(); + } + } + @Nullable private TileEntity removeTileEntity(@NotNull World world, @NotNull BlockPosition position){ TileEntity tile = world.getTileEntity(position); diff --git a/modules/v1_14_R1/src/main/java/net/countercraft/movecraft/compat/v1_14_R1/IWorldHandler.java b/modules/v1_14_R1/src/main/java/net/countercraft/movecraft/compat/v1_14_R1/IWorldHandler.java index 2ef8114be..8194cf7b7 100644 --- a/modules/v1_14_R1/src/main/java/net/countercraft/movecraft/compat/v1_14_R1/IWorldHandler.java +++ b/modules/v1_14_R1/src/main/java/net/countercraft/movecraft/compat/v1_14_R1/IWorldHandler.java @@ -7,15 +7,16 @@ import net.countercraft.movecraft.craft.Craft; import net.countercraft.movecraft.utils.CollectionUtils; import net.countercraft.movecraft.utils.MathUtils; - import net.minecraft.server.v1_14_R1.*; - +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.Material; import org.bukkit.craftbukkit.v1_14_R1.CraftWorld; import org.bukkit.craftbukkit.v1_14_R1.block.CraftBlockState; +import org.bukkit.craftbukkit.v1_14_R1.entity.CraftPlayer; import org.bukkit.craftbukkit.v1_14_R1.util.CraftMagicNumbers; - -import org.bukkit.Location; -import org.bukkit.Material; +import org.bukkit.entity.Player; +import org.bukkit.event.player.PlayerMoveEvent; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -248,6 +249,24 @@ public void translateCraft(@NotNull Craft craft, @NotNull MovecraftLocation disp //sendToPlayers(chunks.toArray(new Chunk[0])); } + @Override + public void addPlayerLocation(Player player, double x, double y, double z, float yaw, float pitch){ + EntityPlayer ePlayer = ((CraftPlayer) player).getHandle(); + if(internalTeleportMH == null) { + //something went wrong + super.addPlayerLocation(player, x, y, z, yaw, pitch); + return; + } + try { + final Location oldLoc = player.getLocation().clone(); + final Location newLoc = player.getLocation().add(x,y,z); + internalTeleportMH.invoke(ePlayer.playerConnection, x + player.getLocation().getX(), y + player.getLocation().getY(), z + player.getLocation().getZ(), yaw, pitch, EnumSet.allOf(PacketPlayOutPosition.EnumPlayerTeleportFlags.class)); + Bukkit.getServer().getPluginManager().callEvent(new PlayerMoveEvent(player,oldLoc,newLoc)); + } catch (Throwable throwable) { + throwable.printStackTrace(); + } + } + @Nullable private TileEntity removeTileEntity(@NotNull World world, @NotNull BlockPosition position){ TileEntity tile = world.getTileEntity(position); diff --git a/modules/worldedit/WE6Utils/src/main/java/net/countercraft/movecraft/compat/we6/IMovecraftRepair.java b/modules/worldedit/WE6Utils/src/main/java/net/countercraft/movecraft/compat/we6/IMovecraftRepair.java index b862238db..12175039a 100644 --- a/modules/worldedit/WE6Utils/src/main/java/net/countercraft/movecraft/compat/we6/IMovecraftRepair.java +++ b/modules/worldedit/WE6Utils/src/main/java/net/countercraft/movecraft/compat/we6/IMovecraftRepair.java @@ -49,12 +49,10 @@ import java.util.Set; public class IMovecraftRepair extends MovecraftRepair { - private static MovecraftRepair instance; private final Plugin plugin; private HashMap>> locMissingBlocksMap = new HashMap<>(); private HashMap numDiffBlocksMap = new HashMap<>(); private HashMap, Double>> missingBlocksMap = new HashMap<>(); - private final HashMap distanceMap = new HashMap<>(); public IMovecraftRepair(Plugin plugin) { this.plugin = plugin; From 8121632b512d8abe8e52cb4d6c892023c62a83aa Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Tue, 1 Oct 2019 23:32:02 +0200 Subject: [PATCH 051/304] Fixed harvesting being processed in the main thread --- .../async/translation/TranslationTask.java | 38 +++++++++++-------- 1 file changed, 22 insertions(+), 16 deletions(-) diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java index 76533bc07..fcce890d0 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java @@ -18,10 +18,7 @@ import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.Sound; -import org.bukkit.block.Block; -import org.bukkit.block.BlockFace; -import org.bukkit.block.Chest; -import org.bukkit.block.Furnace; +import org.bukkit.block.*; import org.bukkit.entity.EntityType; import org.bukkit.entity.Player; import org.bukkit.inventory.Inventory; @@ -504,19 +501,28 @@ private void captureYield(List harvestedBlocks) { } } //get contents of inventories before deposting - if (block.getState() instanceof InventoryHolder) { - if (block.getState() instanceof Chest) { - drops.addAll(Arrays.asList(((Chest) block.getState()).getBlockInventory().getContents())); - } else { - drops.addAll(Arrays.asList((((InventoryHolder) block.getState()).getInventory().getContents()))); + new BukkitRunnable() { + @Override + public void run() { + if (block.getState() instanceof InventoryHolder) { + if (block.getState() instanceof Chest) { + drops.addAll(Arrays.asList(((Chest) block.getState()).getBlockInventory().getContents())); + } else if (block.getState() instanceof Barrel){ + drops.addAll(Arrays.asList(((Barrel) block.getState()).getInventory().getContents())); + } + else { + drops.addAll(Arrays.asList((((InventoryHolder) block.getState()).getInventory().getContents()))); + } + } + for (ItemStack drop : drops) { + ItemStack retStack = putInToChests(drop, chests); + if (retStack != null) + //drop items on position + updates.add(new ItemDropUpdateCommand(new Location(craft.getW(), harvestedBlock.getX(), harvestedBlock.getY(), harvestedBlock.getZ()), retStack)); + } } - } - for (ItemStack drop : drops) { - ItemStack retStack = putInToChests(drop, chests); - if (retStack != null) - //drop items on position - updates.add(new ItemDropUpdateCommand(new Location(craft.getW(), harvestedBlock.getX(), harvestedBlock.getY(), harvestedBlock.getZ()), retStack)); - } + }.runTask(Movecraft.getInstance()); + } } From 9eee1e5d6073ee36e902aa30bfb630b6f17c59f9 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Mon, 7 Oct 2019 02:15:25 +0200 Subject: [PATCH 052/304] Fixed Movecraft breaking if WorldGuard is absent --- .../movecraft/async/AsyncManager.java | 7 +--- .../movecraft/listener/BlockListener.java | 32 ++++--------------- .../movecraft/utils/WorldguardUtils.java | 18 +++++++++++ 3 files changed, 26 insertions(+), 31 deletions(-) diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java index 41365717b..19b74ebf5 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java @@ -24,10 +24,6 @@ import com.sk89q.worldguard.WorldGuard; import com.sk89q.worldguard.bukkit.WorldGuardPlugin; import com.sk89q.worldguard.protection.ApplicableRegionSet; -import com.sk89q.worldguard.protection.flags.DefaultFlag; -import com.sk89q.worldguard.protection.flags.Flag; -import com.sk89q.worldguard.protection.flags.Flags; -import com.sk89q.worldguard.protection.flags.StateFlag; import com.sk89q.worldguard.protection.managers.RegionManager; import com.sk89q.worldguard.protection.regions.ProtectedRegion; import com.sk89q.worldguard.protection.regions.RegionContainer; @@ -615,8 +611,7 @@ private void detectSinking(){ break; } } - Flag pvpFlag = Settings.IsLegacy ? DefaultFlag.PVP : Flags.PVP; - if (region != null && Settings.WorldGuardBlockSinkOnPVPPerm && region.getFlag(pvpFlag).equals(StateFlag.State.DENY)){ + if (region != null && Settings.WorldGuardBlockSinkOnPVPPerm && WorldguardUtils.pvpAllowed(region)){ notifyP.sendMessage(I18nSupport.getInternationalisedString("Player- Craft should sink but PVP is not allowed in this WorldGuard region")); isSinking = false; } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/BlockListener.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/BlockListener.java index 04bc30676..8ef7a80e9 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/BlockListener.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/BlockListener.java @@ -21,24 +21,17 @@ import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldguard.WorldGuard; import com.sk89q.worldguard.protection.ApplicableRegionSet; -import com.sk89q.worldguard.protection.flags.DefaultFlag; -import com.sk89q.worldguard.protection.flags.Flags; -import com.sk89q.worldguard.protection.flags.StateFlag; -import com.sk89q.worldguard.protection.regions.ProtectedRegion; import net.countercraft.movecraft.Movecraft; -import net.countercraft.movecraft.utils.LegacyUtils; -import net.countercraft.movecraft.utils.MathUtils; import net.countercraft.movecraft.MovecraftLocation; -import net.countercraft.movecraft.craft.Craft; import net.countercraft.movecraft.config.Settings; +import net.countercraft.movecraft.craft.Craft; import net.countercraft.movecraft.craft.CraftManager; import net.countercraft.movecraft.localisation.I18nSupport; +import net.countercraft.movecraft.utils.LegacyUtils; +import net.countercraft.movecraft.utils.MathUtils; +import net.countercraft.movecraft.utils.WorldguardUtils; import net.countercraft.movecraft.warfare.assault.AssaultUtils; -import org.bukkit.Bukkit; -import org.bukkit.ChatColor; -import org.bukkit.Location; -import org.bukkit.Material; -import org.bukkit.World; +import org.bukkit.*; import org.bukkit.block.Block; import org.bukkit.block.BlockFace; import org.bukkit.block.Hopper; @@ -283,19 +276,8 @@ public void onBlockIgnite(BlockIgniteEvent event) { } // check to see if fire spread is allowed, don't check if compatmanager integration is not enabled if (Movecraft.getInstance().getWorldGuardPlugin() != null && (Settings.WorldGuardBlockMoveOnBuildPerm || Settings.WorldGuardBlockSinkOnPVPPerm)) { - ApplicableRegionSet set; - Location loc = testBlock.getLocation(); - if (Settings.IsLegacy){ - set = LegacyUtils.getApplicableRegions(LegacyUtils.getRegionManager(Movecraft.getInstance().getWorldGuardPlugin(), loc.getWorld()), loc);//.getApplicableRegions(); - if (!LegacyUtils.allows(set, DefaultFlag.FIRE_SPREAD)) - return; - } else { - set = WorldGuard.getInstance().getPlatform().getRegionContainer().get(BukkitAdapter.adapt(testBlock.getWorld())).getApplicableRegions(BlockVector3.at(loc.getBlockX(), loc.getBlockY(), loc.getBlockZ())); - for (ProtectedRegion region : set){ - if (region.getFlag(Flags.FIRE_SPREAD) == StateFlag.State.DENY){ - return; - } - } + if (!WorldguardUtils.allowFireSpread(testBlock.getLocation())){ + return; } } testBlock.setType(org.bukkit.Material.AIR); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/WorldguardUtils.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/WorldguardUtils.java index 8258bd1c2..1dc147e62 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/WorldguardUtils.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/WorldguardUtils.java @@ -1,6 +1,8 @@ package net.countercraft.movecraft.utils; +import com.sk89q.worldedit.bukkit.BukkitAdapter; import com.sk89q.worldedit.bukkit.BukkitWorld; +import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldguard.WorldGuard; import com.sk89q.worldguard.protection.ApplicableRegionSet; import com.sk89q.worldguard.protection.flags.DefaultFlag; @@ -79,6 +81,22 @@ public static boolean explosionsPermitted(Location loc){ } return true; } + public static boolean allowFireSpread(Location loc){ + ApplicableRegionSet set; + if (Settings.IsLegacy){ + set = LegacyUtils.getApplicableRegions(LegacyUtils.getRegionManager(Movecraft.getInstance().getWorldGuardPlugin(), loc.getWorld()), loc);//.getApplicableRegions(); + return LegacyUtils.allows(set, DefaultFlag.FIRE_SPREAD); + + } else { + set = WorldGuard.getInstance().getPlatform().getRegionContainer().get(BukkitAdapter.adapt(loc.getWorld())).getApplicableRegions(BlockVector3.at(loc.getBlockX(), loc.getBlockY(), loc.getBlockZ())); + for (ProtectedRegion region : set){ + if (region.getFlag(Flags.FIRE_SPREAD) == StateFlag.State.DENY){ + return false; + } + } + } + return true; + } public static ApplicableRegionSet getRegionsAt(Location loc){ World world = loc.getWorld(); ApplicableRegionSet regions; From a8d6e9f17bc665739c3851f8333dc25c07d13dec Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Mon, 7 Oct 2019 02:21:32 +0200 Subject: [PATCH 053/304] updated .travis.yml --- .travis.yml | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 32ef37608..f40eeda19 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,6 +14,14 @@ before_install: | wget -O BuildTools.jar https://hub.spigotmc.org/jenkins/job/BuildTools/lastSuccessfulBuild/artifact/target/BuildTools.jar java -jar BuildTools.jar --rev 1.12.1 | grep -vE "[^/ ]*/[^/ ]*\s*KB\s*$" | grep -v "^\s*$" fi + if [ ! -d "$HOME/.m2/repository/org/spigotmc/spigot/1.13.2-R0.1-SNAPSHOT" ]; then + wget -O BuildTools.jar https://hub.spigotmc.org/jenkins/job/BuildTools/lastSuccessfulBuild/artifact/target/BuildTools.jar + java -jar BuildTools.jar --rev 1.13.2 | grep -vE "[^/ ]*/[^/ ]*\s*KB\s*$" | grep -v "^\s*$" + fi + if [ ! -d "$HOME/.m2/repository/org/spigotmc/spigot/1.14.4-R0.1-SNAPSHOT" ]; then + wget -O BuildTools.jar https://hub.spigotmc.org/jenkins/job/BuildTools/lastSuccessfulBuild/artifact/target/BuildTools.jar + java -jar BuildTools.jar --rev 1.14.4 | grep -vE "[^/ ]*/[^/ ]*\s*KB\s*$" | grep -v "^\s*$" + fi language: java jdk: oraclejdk8 sudo: false @@ -26,5 +34,5 @@ deploy: file: "target/Movecraft.jar" skip_cleanup: true on: - repo: APDevTeam/Movecraft + repo: eirikh1996/Movecraft tags: true \ No newline at end of file From 6ebb746db2d858a461fcd637180e34723cfea3be Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Mon, 7 Oct 2019 14:05:16 +0200 Subject: [PATCH 054/304] Fine tuned telepotation when craft moves --- .../net/countercraft/movecraft/Movecraft.java | 17 +++++++++++++++++ .../update/EntityMoveUpdateCommand.java | 5 +++-- .../movecraft/sync/EntityProcessor.java | 4 ++-- 3 files changed, 22 insertions(+), 4 deletions(-) diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java index c338a3342..6d0219072 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java @@ -558,6 +558,23 @@ private void saveLocaleFiles(){ } } + public void reload(){ + onDisable(); + asyncManager.cancel(); + if (assaultManager != null) + assaultManager.cancel(); + assaultManager = null; + if (siegeManager != null) + siegeManager.cancel(); + siegeManager = null; + if (repairManager != null){ + repairManager.cancel(); + } + repairManager = null; + onEnable(); + + + } public WorldGuardPlugin getWorldGuardPlugin() { return worldGuardPlugin; diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/EntityMoveUpdateCommand.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/EntityMoveUpdateCommand.java index 7f87035d0..d1a479436 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/EntityMoveUpdateCommand.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/EntityMoveUpdateCommand.java @@ -21,6 +21,7 @@ import org.bukkit.Location; import org.bukkit.entity.Entity; import org.bukkit.entity.Player; +import org.bukkit.event.player.PlayerTeleportEvent; import java.util.Objects; @@ -51,8 +52,8 @@ public Entity getEntity() { @Override public void doUpdate() { Location playerLoc = entity.getLocation(); - if (!(entity instanceof Player) || yaw > .01 || pitch > .01) { - entity.teleport(new Location(entity.getWorld(), x + playerLoc.getX(), y + playerLoc.getY(), z + playerLoc.getZ(), yaw + playerLoc.getYaw(), pitch + playerLoc.getPitch())); + if (!(entity instanceof Player) || Math.abs(yaw) > .01 || pitch > .01) { + entity.teleport(new Location(entity.getWorld(), x + playerLoc.getX(), y + playerLoc.getY(), z + playerLoc.getZ(), yaw + playerLoc.getYaw(), pitch + playerLoc.getPitch()), PlayerTeleportEvent.TeleportCause.UNKNOWN); return; } //Movecraft.getInstance().getWorldHandler().addPlayerLocation((Player) entity,x,y,z,yaw,pitch); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sync/EntityProcessor.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sync/EntityProcessor.java index f662f52a0..81cc9429c 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sync/EntityProcessor.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sync/EntityProcessor.java @@ -35,10 +35,10 @@ public static Set translateEntities(Craft craft, int dx, int dy, if(craft.getSinking()){ continue; } - EntityMoveUpdateCommand eUp = new EntityMoveUpdateCommand(entity, dx, dy, dz, entity.getLocation().getYaw(), entity.getLocation().getPitch()); + EntityMoveUpdateCommand eUp = new EntityMoveUpdateCommand(entity, dx, dy, dz, 0, 0); updateCmds.add(eUp); } else if (!craft.getType().getOnlyMovePlayers() || entity.getType() == EntityType.PRIMED_TNT) { - EntityMoveUpdateCommand eUp = new EntityMoveUpdateCommand(entity, dx, dy, dz, entity.getLocation().getYaw(), entity.getLocation().getPitch()); + EntityMoveUpdateCommand eUp = new EntityMoveUpdateCommand(entity, dx, dy, dz, 0, 0); updateCmds.add(eUp); } } From 180510e9562cae52b8f2768b9dd94677d4107887 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Tue, 8 Oct 2019 00:28:21 +0200 Subject: [PATCH 055/304] Overhauled how allowedBlocks, forbiddenBlocks, flyBlocks and moveBlocks data are stored --- .../movecraft/async/AsyncManager.java | 47 +-- .../async/detection/DetectionTask.java | 142 ++++---- .../async/detection/DetectionTaskData.java | 15 +- .../movecraft/listener/PlayerListener.java | 12 +- .../movecraft/sign/StatusSign.java | 93 +++--- .../movecraft/MovecraftBlock.java | 46 +++ .../movecraft/craft/CraftType.java | 38 +-- .../movecraft/utils/BlockContainer.java | 154 +++++++++ .../movecraft/utils/BlockLimitManager.java | 306 ++++++++++++++++++ 9 files changed, 666 insertions(+), 187 deletions(-) create mode 100644 modules/api/src/main/java/net/countercraft/movecraft/MovecraftBlock.java create mode 100644 modules/api/src/main/java/net/countercraft/movecraft/utils/BlockContainer.java create mode 100644 modules/api/src/main/java/net/countercraft/movecraft/utils/BlockLimitManager.java diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java index 668951b94..440134d23 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java @@ -27,10 +27,8 @@ import com.sk89q.worldguard.protection.managers.RegionManager; import com.sk89q.worldguard.protection.regions.ProtectedRegion; import com.sk89q.worldguard.protection.regions.RegionContainer; -import net.countercraft.movecraft.Movecraft; -import net.countercraft.movecraft.MovecraftLocation; +import net.countercraft.movecraft.*; import net.countercraft.movecraft.Rotation; -import net.countercraft.movecraft.WorldHandler; import net.countercraft.movecraft.async.detection.DetectionTask; import net.countercraft.movecraft.async.detection.DetectionTaskData; import net.countercraft.movecraft.async.rotation.RotationTask; @@ -499,24 +497,28 @@ private void detectSinking(){ final World w = pcraft.getW(); int totalNonAirBlocks = 0; int totalNonAirWaterBlocks = 0; - HashMap>, Integer> foundFlyBlocks = new HashMap<>(); - HashMap>, Integer> foundMoveBlocks = new HashMap<>(); + HashMap, Integer> foundFlyBlocks = new HashMap<>(); + HashMap, Integer> foundMoveBlocks = new HashMap<>(); // go through each block in the blocklist, and // if its in the FlyBlocks, total up the number // of them + BlockLimitManager moveBlocks = pcraft.getType().getMoveBlocks(); + BlockLimitManager flyBlocks = pcraft.getType().getFlyBlocks(); for (MovecraftLocation l : pcraft.getHitBox()) { Material blockType = w.getBlockAt(l.getX(), l.getY(), l.getZ()).getType(); byte dataID = w.getBlockAt(l.getX(), l.getY(), l.getZ()).getData(); - for (Map> flyBlockDef : pcraft.getType().getFlyBlocks().keySet()) { - if ((flyBlockDef.containsKey(blockType) && flyBlockDef.get(blockType).isEmpty())|| (flyBlockDef.containsKey(blockType) && flyBlockDef.get(blockType).contains(dataID))) { - foundFlyBlocks.merge(flyBlockDef, 1, (a, b) -> a + b); - } + if (flyBlocks.contains(blockType)) { + foundFlyBlocks.merge(flyBlocks.get(blockType).getBlocks(), 1, (a, b) -> a + b); + } else if (flyBlocks.contains(blockType, dataID)){ + foundFlyBlocks.merge(flyBlocks.get(blockType, dataID).getBlocks(), 1, (a, b) -> a + b); } - for (Map> moveBlockDef : pcraft.getType().getMoveBlocks().keySet()) { - if ((moveBlockDef.containsKey(blockType) && moveBlockDef.get(blockType).isEmpty())|| (moveBlockDef.containsKey(blockType) && moveBlockDef.get(blockType).contains(dataID))) { - foundMoveBlocks.merge(moveBlockDef, 1, (a, b) -> a + b); + + if (moveBlocks.contains(blockType)) { + foundMoveBlocks.merge(moveBlocks.get(blockType).getBlocks(), 1, (a, b) -> a + b); + } else if (moveBlocks.contains(blockType, dataID)){ + foundMoveBlocks.merge(moveBlocks.get(blockType, dataID).getBlocks(), 1, (a, b) -> a + b); } - } + if (blockType != Material.AIR) { totalNonAirBlocks++; @@ -531,29 +533,28 @@ private void detectSinking(){ // SinkPercent boolean isSinking = false; - for (Map> i : pcraft.getType().getFlyBlocks().keySet()) { + for (BlockLimitManager.Entry i : pcraft.getType().getFlyBlocks().getEntries()) { int numfound = 0; - if (foundFlyBlocks.get(i) != null) { - numfound = foundFlyBlocks.get(i); + if (foundFlyBlocks.get(i.getBlocks()) != null) { + numfound = foundFlyBlocks.get(i.getBlocks()); } double percent = ((double) numfound / (double) totalNonAirBlocks) * 100.0; - double flyPercent = pcraft.getType().getFlyBlocks().get(i).get(0); + double flyPercent = i.getLowerLimit(); double sinkPercent = flyPercent * pcraft.getType().getSinkPercent() / 100.0; if (percent < sinkPercent) { isSinking = true; } } - for (Map> i : pcraft.getType().getMoveBlocks().keySet()) { + for (BlockLimitManager.Entry i : pcraft.getType().getMoveBlocks().getEntries()) { int numfound = 0; - if (foundMoveBlocks.get(i) != null) { - numfound = foundMoveBlocks.get(i); + if (foundMoveBlocks.get(i.getBlocks()) != null) { + numfound = foundMoveBlocks.get(i.getBlocks()); } double percent = ((double) numfound / (double) totalNonAirBlocks) * 100.0; - double movePercent = pcraft.getType().getMoveBlocks().get(i).get(0); + double movePercent = i.getLowerLimit(); double disablePercent = movePercent * pcraft.getType().getSinkPercent() / 100.0; if (percent < disablePercent && !pcraft.getDisabled() && pcraft.isNotProcessing()) { - Bukkit.broadcastMessage(String.valueOf(percent)); pcraft.setDisabled(true); if (pcraft.getNotificationPlayer() != null) { Location loc = pcraft.getNotificationPlayer().getLocation(); @@ -612,7 +613,7 @@ private void detectSinking(){ break; } } - if (region != null && Settings.WorldGuardBlockSinkOnPVPPerm && WorldguardUtils.pvpAllowed(region)){ + if (region != null && Settings.WorldGuardBlockSinkOnPVPPerm && WorldguardUtils.pvpAllowed(region) && notifyP != null){ notifyP.sendMessage(I18nSupport.getInternationalisedString("Player- Craft should sink but PVP is not allowed in this WorldGuard region")); isSinking = false; } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/detection/DetectionTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/detection/DetectionTask.java index 4fea14914..9d8aa51d0 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/detection/DetectionTask.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/detection/DetectionTask.java @@ -19,11 +19,13 @@ import net.countercraft.movecraft.Movecraft; +import net.countercraft.movecraft.MovecraftBlock; import net.countercraft.movecraft.MovecraftLocation; import net.countercraft.movecraft.async.AsyncTask; import net.countercraft.movecraft.config.Settings; import net.countercraft.movecraft.craft.Craft; import net.countercraft.movecraft.localisation.I18nSupport; +import net.countercraft.movecraft.utils.BlockLimitManager; import net.countercraft.movecraft.utils.HashHitBox; import net.countercraft.movecraft.utils.LegacyUtils; import org.bukkit.Bukkit; @@ -45,14 +47,14 @@ public class DetectionTask extends AsyncTask { private final Stack blockStack = new Stack<>(); private final HashHitBox blockList = new HashHitBox(); private final HashSet visited = new HashSet<>(); - private final HashMap>, Integer> blockTypeCount = new HashMap>, Integer>(); + private final HashMap, Integer> blockTypeCount = new HashMap<>(); private final DetectionTaskData data; private final World world; private int maxX; private int maxY; private int maxZ; private int minY; - private Map>, List> dFlyBlocks; + private BlockLimitManager dFlyBlocks; private int foundDynamicFlyBlock = 0; public DetectionTask(Craft c, MovecraftLocation startLocation, Player player) { @@ -68,7 +70,7 @@ public DetectionTask(Craft c, MovecraftLocation startLocation, Player player) { @Override public void execute() { long startTime = System.currentTimeMillis(); - Map>, List> flyBlocks = getCraft().getType().getFlyBlocks(); + BlockLimitManager flyBlocks = getCraft().getType().getFlyBlocks(); dFlyBlocks = flyBlocks; blockStack.push(startLocation); do { @@ -82,12 +84,13 @@ public void execute() { int totalBlocks = blockList.size(); double ratio = (double) foundDynamicFlyBlock / totalBlocks; double foundMinimum = 0.0; - for (Map> i : flyBlocks.keySet()) { - for (Material dFlyBlock : getCraft().getType().getDynamicFlyBlocks()){ - if (i.containsKey(dFlyBlock)) - foundMinimum = flyBlocks.get(i).get(0); + for (BlockLimitManager.Entry entry : flyBlocks.getEntries()){ + for (MovecraftBlock block : entry.getBlocks()){ + if (!getCraft().getType().getDynamicFlyBlocks().contains(block.getType())){ + continue; + } + foundMinimum = entry.getLowerLimit(); } - } ratio = ratio - (foundMinimum / 100.0); ratio = ratio * getCraft().getType().getDynamicFlyBlockSpeedFactor(); @@ -183,13 +186,11 @@ public void run() { addToBlockList(workingLocation); Material blockType = testType; - int dataID = testData; - for (Map> flyBlockDef : dFlyBlocks.keySet()) { - if ((flyBlockDef.containsKey(blockType) && flyBlockDef.get(blockType).isEmpty()) || (flyBlockDef.containsKey(blockType) && flyBlockDef.get(blockType).contains(dataID))) { - addToBlockCount(flyBlockDef); - } else { - addToBlockCount(null); - } + byte dataID = (byte) testData; + if (dFlyBlocks.hasMetaData(blockType) && dFlyBlocks.contains(blockType, dataID)){ + addToBlockCount(dFlyBlocks.get(blockType, dataID).getBlocks()); + } else if (dFlyBlocks.contains(blockType)) { + addToBlockCount(dFlyBlocks.get(blockType).getBlocks()); } if (getCraft().getType().getDynamicFlyBlockSpeedFactor() != 0.0) { if (getCraft().getType().getDynamicFlyBlocks().contains(blockType)) { @@ -210,42 +211,11 @@ public void run() { } private boolean isAllowedBlock(Material test, int testData) { - - if (data.getAllowedBlocks().containsKey(test)){ - if (!data.getAllowedBlocks().get(test).isEmpty()){ - if (data.getAllowedBlocks().get(test).contains(testData)){ - return true; - } else { - return false; - } - } else { - return true; - } - } - /* - for (Material type : data.getAllowedBlocks().keySet()) { - if ((type == test) || (type == test && data.getAllowedBlocks().get(test).contains(testData))) { - return true; - } - }*/ - - return false; + return data.getAllowedBlocks().contains(test) || data.getAllowedBlocks().contains(test, (byte) testData); } private boolean isForbiddenBlock(Material test, int testData) { - if (data.getForbiddenBlocks().containsKey(test)){ - if (!data.getForbiddenBlocks().get(test).isEmpty()){ - if (data.getForbiddenBlocks().get(test).contains(testData)){ - return true; - } else { - return false; - } - } else { - return true; - } - } - - return false; + return data.getForbiddenBlocks().contains(test) || data.getAllowedBlocks().contains(test, (byte) testData); } private synchronized boolean containsForbiddenSignString(Block testBlock) { @@ -285,7 +255,7 @@ private void addToDetectionStack(MovecraftLocation l) { blockStack.push(l); } - private void addToBlockCount(Map> id) { + private void addToBlockCount(Set id) { Integer count = blockTypeCount.get(id); if (count == null) { @@ -381,8 +351,8 @@ private MovecraftLocation[] finaliseBlockList(HashSet blockSe return finalList.toArray(new MovecraftLocation[1]); } - private boolean confirmStructureRequirements(Map>, List> flyBlocks, - HashMap>, Integer> countData) { + private boolean confirmStructureRequirements(BlockLimitManager flyBlocks, + HashMap, Integer> countData) { if (getCraft().getType().getRequireWaterContact()) { if (!data.getWaterContact()) { fail(I18nSupport @@ -390,56 +360,56 @@ private boolean confirmStructureRequirements(Map>, L return false; } } - for (Map> i : flyBlocks.keySet()) { - Integer numberOfBlocks = countData.get(i); + for (BlockLimitManager.Entry i : flyBlocks.getEntries()) { + Integer numberOfBlocks = countData.get(i.getBlocks()); if (numberOfBlocks == null) { numberOfBlocks = 0; } float blockPercentage = (((float) numberOfBlocks / data.getBlockList().size()) * 100); - Double minPercentage = flyBlocks.get(i).get(0); - Double maxPercentage = flyBlocks.get(i).get(1); - ArrayList flyBlockTypes = new ArrayList<>(i.keySet()); + Double minPercentage = i.getLowerLimit(); + Double maxPercentage = i.getUpperLimit(); + ArrayList flyBlockTypes = new ArrayList<>(i.getBlocks()); + String name = flyBlockTypes.get(0).getType().name(); if (minPercentage < 10000.0) { if (blockPercentage < minPercentage) { - fail(String.format( - I18nSupport.getInternationalisedString("Detection - Not enough flyblock") + ": %s %.2f%% < %.2f%%", - flyBlockTypes.get(0).name().toLowerCase().replace("_", " "), - blockPercentage, minPercentage)); - return false; - + fail(String.format( + I18nSupport.getInternationalisedString("Detection - Not enough flyblock") + ": %s %.2f%% < %.2f%%", + name.toLowerCase().replace("_", " "), + blockPercentage, minPercentage)); + return false; - } else { - if (numberOfBlocks < flyBlocks.get(i).get(0) - 10000.0) { + } + } else { + if (numberOfBlocks < i.getLowerLimit() - 10000.0) { - fail(String.format( - I18nSupport.getInternationalisedString("Detection - Not enough flyblock") + ": %s %d < %d", - flyBlockTypes.get(0).name().toLowerCase().replace("_", " "), - numberOfBlocks, flyBlocks.get(i).get(0).intValue() - 10000)); - return false; + fail(String.format( + I18nSupport.getInternationalisedString("Detection - Not enough flyblock") + ": %s %d < %d", + name.toLowerCase().replace("_", " "), + numberOfBlocks, (int) i.getLowerLimit() - 10000)); + return false; - } } - if (maxPercentage < 10000.0) { - if (blockPercentage > maxPercentage) { - fail(String.format( - I18nSupport.getInternationalisedString("Detection - Too much flyblock") + ": %s %.2f%% > %.2f%%", - flyBlockTypes.get(0).name().toLowerCase().replace("_", " "), blockPercentage, - maxPercentage)); - return false; - } - } - } else { - if (numberOfBlocks > flyBlocks.get(i).get(1) - 10000.0) { - fail(String.format(I18nSupport.getInternationalisedString("Detection - Too much flyblock") + ": %s %d > %d", - flyBlockTypes.get(0).name().toLowerCase().replace("_", " "), numberOfBlocks, - flyBlocks.get(i).get(1).intValue() - 10000)); - return false; + } + if (maxPercentage < 10000.0) { + if (blockPercentage > maxPercentage) { + fail(String.format( + I18nSupport.getInternationalisedString("Detection - Too much flyblock") + ": %s %.2f%% > %.2f%%", + name.toLowerCase().replace("_", " "), blockPercentage, + maxPercentage)); + return false; + } + } else { + if (numberOfBlocks > i.getUpperLimit() - 10000.0) { + fail(String.format(I18nSupport.getInternationalisedString("Detection - Too much flyblock") + ": %s %d > %d", + name.toLowerCase().replace("_", " "), numberOfBlocks, + i.getUpperLimit() - 10000)); + return false; - } } } + } return true; } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/detection/DetectionTaskData.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/detection/DetectionTaskData.java index 88613478d..429d208f7 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/detection/DetectionTaskData.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/detection/DetectionTaskData.java @@ -17,15 +17,12 @@ package net.countercraft.movecraft.async.detection; +import net.countercraft.movecraft.utils.BlockContainer; import net.countercraft.movecraft.utils.HashHitBox; import net.countercraft.movecraft.utils.HitBox; -import org.bukkit.Material; import org.bukkit.World; import org.bukkit.entity.Player; -import java.util.List; -import java.util.Map; - @Deprecated public class DetectionTaskData { public Double dynamicFlyBlockSpeedMultiplier; @@ -37,11 +34,11 @@ public class DetectionTaskData { private Player player; private Player notificationPlayer; private int minX, minZ; - private Map> allowedBlocks; - private Map> forbiddenBlocks; + private BlockContainer allowedBlocks; + private BlockContainer forbiddenBlocks; private String[] forbiddenSignStrings; - public DetectionTaskData(World w, Player player, Player notificationPlayer, Map> allowedBlocks, Map> forbiddenBlocks, String[] forbiddenSignStrings) { + public DetectionTaskData(World w, Player player, Player notificationPlayer, BlockContainer allowedBlocks, BlockContainer forbiddenBlocks, String[] forbiddenSignStrings) { this.w = w; this.player = player; this.notificationPlayer = notificationPlayer; @@ -54,11 +51,11 @@ public DetectionTaskData(World w, Player player, Player notificationPlayer, Map< public DetectionTaskData() { } - public Map> getAllowedBlocks() { + public BlockContainer getAllowedBlocks() { return allowedBlocks; } - public Map> getForbiddenBlocks() { + public BlockContainer getForbiddenBlocks() { return forbiddenBlocks; } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/PlayerListener.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/PlayerListener.java index ded5abf98..2dd299c35 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/PlayerListener.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/PlayerListener.java @@ -23,6 +23,7 @@ import net.countercraft.movecraft.craft.Craft; import net.countercraft.movecraft.craft.CraftManager; import net.countercraft.movecraft.localisation.I18nSupport; +import net.countercraft.movecraft.utils.BlockContainer; import net.countercraft.movecraft.utils.MathUtils; import org.bukkit.Material; import org.bukkit.block.Block; @@ -34,7 +35,6 @@ import org.bukkit.event.player.PlayerMoveEvent; import org.bukkit.event.player.PlayerQuitEvent; -import java.util.List; import java.util.Map; import java.util.WeakHashMap; @@ -43,8 +43,8 @@ public class PlayerListener implements Listener { private String checkCraftBorders(Craft craft) { String ret = ""; - final Map> ALLOWED_BLOCKS = craft.getType().getAllowedBlocks(); - final Map> FORBIDDEN_BLOCKS = craft.getType().getForbiddenBlocks(); + final BlockContainer ALLOWED_BLOCKS = craft.getType().getAllowedBlocks(); + final BlockContainer FORBIDDEN_BLOCKS = craft.getType().getForbiddenBlocks(); final MovecraftLocation[] SHIFTS = { //x new MovecraftLocation(-1, 0, 0), @@ -74,14 +74,14 @@ private String checkCraftBorders(Craft craft) { } Block testBlock = test.toBukkit(craft.getW()).getBlock(); Material type = testBlock.getType(); - int metaData = testBlock.getData(); + byte metaData = testBlock.getData(); //Break the loop if an allowed block is found adjacent to the craft's hitbox - if (ALLOWED_BLOCKS.get(type) == null || ALLOWED_BLOCKS.get(type).isEmpty() ? ALLOWED_BLOCKS.containsKey(type) : ALLOWED_BLOCKS.get(type).contains(metaData)){ + if (ALLOWED_BLOCKS.contains(type) || ALLOWED_BLOCKS.contains(type, metaData)){ ret = "@ " + test.toString() + " " + type.name(); break; } //Do the same if a forbidden block is found - else if (FORBIDDEN_BLOCKS.get(type) == null || FORBIDDEN_BLOCKS.get(type).isEmpty() ? FORBIDDEN_BLOCKS.containsKey(type) : FORBIDDEN_BLOCKS.get(type).contains(metaData)){ + else if (FORBIDDEN_BLOCKS.contains(type) || FORBIDDEN_BLOCKS.contains(type, metaData)){ ret = "@ " + test.toString() + " " + type.name(); break; } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/StatusSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/StatusSign.java index ae768e3ff..fb052118f 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/StatusSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/StatusSign.java @@ -5,17 +5,20 @@ import net.countercraft.movecraft.craft.Craft; import net.countercraft.movecraft.events.CraftDetectEvent; import net.countercraft.movecraft.events.SignTranslateEvent; +import net.countercraft.movecraft.utils.BlockLimitManager; import org.bukkit.ChatColor; +import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.World; import org.bukkit.block.Block; +import org.bukkit.block.Furnace; import org.bukkit.block.Sign; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; -import org.bukkit.inventory.InventoryHolder; import org.bukkit.inventory.ItemStack; -import java.util.*; +import java.util.HashMap; +import java.util.Map; public final class StatusSign implements Listener{ @@ -43,53 +46,53 @@ public final void onSignTranslate(SignTranslateEvent event) { return; } int fuel = 0; - int totalBlocks = 0; - Map foundBlocks = new HashMap<>(); - for (MovecraftLocation ml : craft.getHitBox()) { - Material blockType = craft.getW().getBlockAt(ml.getX(), ml.getY(), ml.getZ()).getType(); - Integer count = foundBlocks.get(blockType); - if (foundBlocks.containsKey(blockType)) { - foundBlocks.put(blockType, count + 1); - } else { - foundBlocks.put(blockType, 1); + int totalBlocks = craft.getHitBox().size(); + int signLine = 1; + int signColumn = 0; + final BlockLimitManager flyBlocks = craft.getType().getFlyBlocks(); + Map foundFlyBlocks = new HashMap<>(); + for (MovecraftLocation ml : craft.getHitBox()){ + Location loc = ml.toBukkit(craft.getW()); + Material testType = loc.getBlock().getType(); + byte data = 0; + if (Settings.IsLegacy){ + data = loc.getBlock().getData(); } - if (blockType == Material.FURNACE) { - InventoryHolder inventoryHolder = (InventoryHolder) craft.getW().getBlockAt(ml.getX(), ml.getY(), ml.getZ()).getState(); - for (Material fuelType : Settings.FuelTypes.keySet()) { - if (!inventoryHolder.getInventory().contains(fuelType)) { + if (flyBlocks.contains(testType)){ + if (foundFlyBlocks.containsKey(flyBlocks.get(testType))){ + int count = foundFlyBlocks.get(flyBlocks.get(testType)); + count++; + foundFlyBlocks.put(flyBlocks.get(testType), count); + } else { + foundFlyBlocks.put(flyBlocks.get(testType), 1); + } + } else if (flyBlocks.contains(testType, data)){ + if (foundFlyBlocks.containsKey(flyBlocks.get(testType, data))){ + int count = foundFlyBlocks.get(flyBlocks.get(testType, data)); + count++; + foundFlyBlocks.put(flyBlocks.get(testType, data), count); + } else { + foundFlyBlocks.put(flyBlocks.get(testType, data), 1); + } + } + + if (testType == Material.FURNACE) { + Furnace furnace = (Furnace) loc.getBlock().getState(); + for (ItemStack fuelStack : furnace.getInventory().getContents()) { + if (fuelStack == null || !Settings.FuelTypes.containsKey(fuelStack.getType())) { continue; } - ItemStack[] content = inventoryHolder.getInventory().getContents(); - for (ItemStack item : content) { - if (item == null) - continue; - fuel += item.getAmount() * Settings.FuelTypes.get(fuelType); - } + fuel += fuelStack.getAmount() * Settings.FuelTypes.get(fuelStack.getType()); } - - } - if (blockType != Material.AIR || blockType != Material.CAVE_AIR || blockType != Material.VOID_AIR) { - totalBlocks++; } } - int signLine = 1; - int signColumn = 0; - for (Map> alFlyBlock : craft.getType().getFlyBlocks().keySet()) { - ArrayList flyBlocks = new ArrayList<>(alFlyBlock.keySet()); - Collections.sort(flyBlocks); - Double minimum = craft.getType().getFlyBlocks().get(alFlyBlock).get(0); - int amount = 0; - boolean addToStatus = false; - for (Material flyBlock : flyBlocks) { - if (foundBlocks.containsKey(flyBlock) && minimum > 0) { // if it has a minimum, it should be considered for sinking consideration - amount += foundBlocks.get(flyBlock); - addToStatus = true; - } - } - Material flyBlock = flyBlocks.get(0); - if (addToStatus) { - Double percentPresent = (double) (amount * 100 / totalBlocks); + for (BlockLimitManager.Entry entry : foundFlyBlocks.keySet()) { + int amount = foundFlyBlocks.get(entry); + double minimum = entry.getLowerLimit(); + if (minimum == 0) + continue; + double percentPresent = ((double) amount * 100 / (double) totalBlocks); String signText = ""; if (percentPresent > minimum * 1.04) { signText += ChatColor.GREEN; @@ -100,9 +103,9 @@ public final void onSignTranslate(SignTranslateEvent event) { } signText += Settings.StatusSignMarkers.get(flyBlocks); signText += " "; - signText += percentPresent.intValue(); + signText += (int) percentPresent; signText += "/"; - signText += minimum.intValue(); + signText += (int) minimum; signText += " "; if (signColumn == 0) { event.setLine(signLine, signText); @@ -115,7 +118,7 @@ public final void onSignTranslate(SignTranslateEvent event) { signColumn = 0; } } - } + if (signLine < 3 && signColumn == 1){ signLine++; } diff --git a/modules/api/src/main/java/net/countercraft/movecraft/MovecraftBlock.java b/modules/api/src/main/java/net/countercraft/movecraft/MovecraftBlock.java new file mode 100644 index 000000000..3e53ecf37 --- /dev/null +++ b/modules/api/src/main/java/net/countercraft/movecraft/MovecraftBlock.java @@ -0,0 +1,46 @@ +package net.countercraft.movecraft; + +import org.bukkit.Material; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Objects; + +public final class MovecraftBlock { + private final Material type; + private final Byte data; + public MovecraftBlock(Material type, Byte data){ + this.type = type; + this.data = data; + } + + public MovecraftBlock(Material type){ + this.type = type; + this.data = null; + } + + @NotNull + public Material getType() { + return type; + } + + @Nullable + public Byte getData() { + return data; + } + + @Override + public boolean equals(Object obj) { + if (!(obj instanceof MovecraftBlock)){ + return false; + } + MovecraftBlock mb = (MovecraftBlock) obj; + return getType() == mb.getType() && getData() == mb.getData(); + } + + @Override + public int hashCode() { + return Objects.hash(type, data); + } +} + diff --git a/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java b/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java index a1a6f03b5..57af97f41 100644 --- a/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java +++ b/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java @@ -18,6 +18,9 @@ package net.countercraft.movecraft.craft; import net.countercraft.movecraft.config.Settings; +import net.countercraft.movecraft.utils.BlockContainer; +import net.countercraft.movecraft.utils.BlockLimitManager; +import org.bukkit.Bukkit; import org.bukkit.Material; import org.bukkit.entity.EntityType; import org.bukkit.potion.PotionEffect; @@ -84,15 +87,11 @@ final public class CraftType { private final float explodeOnCrash; private final float collisionExplosion; @NotNull private final String craftName; - //@NotNull private final int[] allowedBlocks; - @NotNull private final Map> allowedBlocks; - //@NotNull private final Map> allowedBlocks; - //@NotNull private final int[] forbiddenBlocks; - @NotNull private final Map> forbiddenBlocks; - //@NotNull private final Map> forbiddenBlocks; + @NotNull private final BlockContainer allowedBlocks; + @NotNull private final BlockContainer forbiddenBlocks; @NotNull private final String[] forbiddenSignStrings; - @NotNull private final Map>, List> flyBlocks; - @NotNull private final Map>, List> moveBlocks; + @NotNull private final BlockLimitManager flyBlocks; + @NotNull private final BlockLimitManager moveBlocks; @NotNull private final List harvestBlocks; @NotNull private final List harvesterBladeBlocks; @NotNull private final Set passthroughBlocks; @@ -114,13 +113,14 @@ public CraftType(File f) { } craftName = (String) data.get("name"); + Bukkit.getLogger().info(craftName); maxSize = integerFromObject(data.get("maxSize")); minSize = integerFromObject(data.get("minSize")); - allowedBlocks = materialMapFromObject(data.get("allowedBlocks")); + allowedBlocks = new BlockContainer(data.get("allowedBlocks")); if (data.containsKey("forbiddenBlocks")){ - forbiddenBlocks = materialMapFromObject(data.get("forbiddenBlocks")); + forbiddenBlocks = new BlockContainer(data.get("forbiddenBlocks")); } else { - forbiddenBlocks = Collections.emptyMap(); + forbiddenBlocks = new BlockContainer(); } forbiddenSignStrings = stringListFromObject(data.get("forbiddenSignStrings")); if (data.containsKey("canFly")) { @@ -147,11 +147,11 @@ public CraftType(File f) { cruiseTickCooldown = tickCooldown; } - flyBlocks = materialMapListFromObject(data.get("flyblocks")); + flyBlocks = new BlockLimitManager(data.get("flyblocks")); if (data.containsKey("moveblocks")) { - moveBlocks = materialMapListFromObject(data.get("moveblocks")); + moveBlocks = new BlockLimitManager(data.get("moveblocks")); } else { - moveBlocks = new HashMap<>(); + moveBlocks = new BlockLimitManager(); } if (data.containsKey("canCruise")) { @@ -882,11 +882,13 @@ public int getMinSize() { return minSize; } - public Map> getAllowedBlocks() { + @NotNull + public BlockContainer getAllowedBlocks() { return allowedBlocks; } - public Map> getForbiddenBlocks() { + @NotNull + public BlockContainer getForbiddenBlocks() { return forbiddenBlocks; } @@ -1031,12 +1033,12 @@ public boolean isTryNudge() { } @NotNull - public Map>, List> getFlyBlocks() { + public BlockLimitManager getFlyBlocks() { return flyBlocks; } @NotNull - public Map>, List> getMoveBlocks() { + public BlockLimitManager getMoveBlocks() { return moveBlocks; } diff --git a/modules/api/src/main/java/net/countercraft/movecraft/utils/BlockContainer.java b/modules/api/src/main/java/net/countercraft/movecraft/utils/BlockContainer.java new file mode 100644 index 000000000..b487c3720 --- /dev/null +++ b/modules/api/src/main/java/net/countercraft/movecraft/utils/BlockContainer.java @@ -0,0 +1,154 @@ +package net.countercraft.movecraft.utils; + +import net.countercraft.movecraft.MovecraftBlock; +import org.bukkit.Bukkit; +import org.bukkit.Material; +import org.jetbrains.annotations.NotNull; + +import java.util.*; + +public class BlockContainer implements Iterable{ + private final Set blocks = new HashSet<>(); + private final Map byMaterial = new HashMap<>(); + + /** + * Constructs an instance of an empty Block container + */ + public BlockContainer(){ + + } + + public BlockContainer(Object obj){ + if (obj instanceof ArrayList){ + ArrayList objList = (ArrayList) obj; + for (Object o : objList){ + Material type; + + if (o instanceof String){ + String str = (String) o; + str = str.toUpperCase(); + if (str.contains(":")){ + String[] parts = str.split(":"); + try{ + int id = Integer.parseInt(parts[0]); + type = Material.getMaterial(id); + } catch (NumberFormatException e){ + type = Material.getMaterial(parts[0]); + } catch (Exception e){ + throw new IllegalArgumentException("Numerical IDs are not supported by this version: " + Bukkit.getVersion(), e); + } + Byte data = Byte.parseByte(parts[1]); + blocks.add(new MovecraftBlock(type, data)); + continue; + } else if (str.startsWith("ALL_")){ + str = str.replace("ALL_", ""); + for (Material m : Material.values()){ + if (!m.name().endsWith(str)){ + continue; + } + blocks.add(new MovecraftBlock(m)); + } + continue; + } + type = Material.getMaterial(str); + if (type == null){ + throw new IllegalArgumentException(str + "is not a valid Material ID"); + } + blocks.add(new MovecraftBlock(type)); + } else if (o instanceof Integer){ + int id = (int) o; + try { + type = Material.getMaterial(id); + blocks.add(new MovecraftBlock(type)); + } catch (Throwable t){ + throw new IllegalArgumentException("Numerical material IDs are not supportedby this version: " + Bukkit.getVersion()); + } + } else { + type = (Material) o; + blocks.add(new MovecraftBlock(type)); + } + } + } else if (obj instanceof Integer){ + int id = (int) obj; + try { + Material type = Material.getMaterial(id); + blocks.add(new MovecraftBlock(type)); + } catch (Throwable t){ + throw new IllegalArgumentException("Numerical material IDs are not supportedby this version: " + Bukkit.getVersion()); + } + } else if (obj instanceof String) { + Material type; + String str = (String) obj; + if (str.contains(":")){ + String[] parts = str.split(":"); + try{ + int id = Integer.parseInt(parts[0]); + type = Material.getMaterial(id); + } catch (NumberFormatException e){ + type = Material.getMaterial(parts[0]); + } catch (Exception e){ + throw new IllegalArgumentException("Numerical IDs are not supported by this version: " + Bukkit.getVersion(), e); + } + Byte data = Byte.parseByte(parts[1]); + blocks.add(new MovecraftBlock(type, data)); + return; + } + type = Material.getMaterial(str); + if (type == null){ + throw new IllegalArgumentException(str + "is not a valid Material ID"); + } + blocks.add(new MovecraftBlock(type)); + } else { + blocks.add(new MovecraftBlock((Material) obj)); + } + for (MovecraftBlock mb : blocks){ + byMaterial.put(mb.getType(), mb); + } + } + + public boolean contains(MovecraftBlock movecraftBlock){ + return blocks.contains(movecraftBlock); + } + + /** + * Check if this block container contains given material + * @param type the Material this container should contain + * @return true if it contains a block with the same type and no meta data. False otherwise + */ + public boolean contains(Material type){ + return contains(new MovecraftBlock(type)); + } + + /** + * Check if this block container contains given material and metadata value + * @param type the Material this container should contain + * @param data the corresponding metadata value this container should contain + * @return true if the block container contains both the type and data values. False otherwhise + */ + public boolean contains(Material type, Byte data){ + return contains(new MovecraftBlock(type, data)); + } + + public boolean isEmpty(){ + return blocks.isEmpty(); + } + + public int size(){ + return blocks.size(); + } + + public MovecraftBlock get(Material type){ + return byMaterial.get(type); + } + + @NotNull + @Override + public Iterator iterator() { + return Collections.unmodifiableSet(blocks).iterator(); + } + + @Override + public int hashCode() { + return Objects.hash(blocks); + } +} diff --git a/modules/api/src/main/java/net/countercraft/movecraft/utils/BlockLimitManager.java b/modules/api/src/main/java/net/countercraft/movecraft/utils/BlockLimitManager.java new file mode 100644 index 000000000..cd5b5fae0 --- /dev/null +++ b/modules/api/src/main/java/net/countercraft/movecraft/utils/BlockLimitManager.java @@ -0,0 +1,306 @@ +package net.countercraft.movecraft.utils; + +import net.countercraft.movecraft.MovecraftBlock; +import org.bukkit.Bukkit; +import org.bukkit.Material; + +import java.util.*; + +public class BlockLimitManager { + private final Set entries = new HashSet<>(); + public BlockLimitManager(){} + + public BlockLimitManager(Object obj){ + HashMap objMap = (HashMap) obj; + for (Object i : objMap.keySet()) { + Set blocks = new HashSet<>(); + if (i instanceof ArrayList) { + for (Object o : (ArrayList) i) { + Material type; + if (o instanceof Integer) { + try { + Integer typeID = (Integer) o; + type = Material.getMaterial(typeID); + blocks.add(new MovecraftBlock(type)); + } catch (Throwable t){ + throw new IllegalArgumentException("Numerical block IDs are not supported by this version: " + Bukkit.getVersion(), t); + } + + } else if (o instanceof String) { + String string = (String) o; + string = string.toUpperCase(); + if (string.contains(":")) { + String[] parts = string.split(":"); + Byte data = Byte.valueOf(parts[1]); + try { + int id = Integer.parseInt(parts[0]); + type = Material.getMaterial(id); + } catch (Throwable t){ + if (!(t instanceof NumberFormatException)) + throw new IllegalArgumentException("Numerical block IDs are not supported by this version: " + Bukkit.getVersion(), t); + type = Material.getMaterial(parts[0]); + } + blocks.add(new MovecraftBlock(type, data)); + } else if (string.toUpperCase().startsWith("ALL_")){ + string = string.replace("ALL_", ""); + for (Material m : Material.values()){ + if (!m.name().endsWith(string)){ + continue; + } + blocks.add(new MovecraftBlock(m)); + } + } else { + try { + int id = Integer.parseInt(string); + type = Material.getMaterial(id); + } catch (Throwable t){ + if (!(t instanceof NumberFormatException)){ + throw new IllegalArgumentException("Numerical block IDs are not supported by this version: " + Bukkit.getVersion(), t); + } + type = Material.getMaterial(string); + } + blocks.add(new MovecraftBlock(type)); + } + } else { + type = (Material) o; + blocks.add(new MovecraftBlock(type)); + } + } + } else if (i instanceof Map) { + Material type; + HashMap objMapKey = (HashMap) i; + for (Object o : objMapKey.keySet()) { + List dataList = (List) objMapKey.get(o); + if (o instanceof Integer) { + + try { + Integer typeID = (Integer) o; + type = Material.getMaterial(typeID); + } catch (Throwable t){ + throw new IllegalArgumentException("Numerical block IDs are not supported by this version: " + Bukkit.getVersion(), t); + } + } else if (o instanceof String) { + String string = (String) o; + string = string.toUpperCase(); + if (string.contains(":")) { + String[] parts = string.split(":"); + Byte data = Byte.valueOf(parts[1]); + try { + int id = Integer.parseInt(parts[0]); + type = Material.getMaterial(id); + } catch (Throwable t){ + if (!(t instanceof NumberFormatException)) + throw new IllegalArgumentException("Numerical block IDs are not supported by this version: " + Bukkit.getVersion(), t); + type = Material.getMaterial(parts[0]); + } + if (dataList == null) + dataList = new ArrayList<>(); + dataList.add(data); + } else if (string.toUpperCase().startsWith("ALL_")){ + string = string.replace("ALL_", ""); + for (Material m : Material.values()){ + if (!m.name().endsWith(string)){ + continue; + } + blocks.add(new MovecraftBlock(m)); + } + continue; + } else { + try { + int id = Integer.parseInt(string); + type = Material.getMaterial(id); + } catch (Throwable t){ + if (!(t instanceof NumberFormatException)){ + throw new IllegalArgumentException("Numerical block IDs are not supported by this version: " + Bukkit.getVersion(), t); + } + type = Material.getMaterial(string); + } + } + + } else { + type = (Material) o; + } + if (dataList == null || dataList.isEmpty()){ + blocks.add(new MovecraftBlock(type)); + } else { + for (int data : dataList){ + blocks.add(new MovecraftBlock(type, (byte) data)); + } + } + } + } else if (i instanceof Integer) { + try { + Integer typeID = (Integer) i; + Material type = Material.getMaterial(typeID); + blocks.add(new MovecraftBlock(type)); + } catch (Throwable t){ + throw new IllegalArgumentException("Numerical block IDs are not supported by this version: " + Bukkit.getVersion(), t); + } + } else if (i instanceof String) { + String string = (String) i; + Material type; + string = string.toUpperCase(); + if (string.contains(":")) { + String[] parts = string.split(":"); + Byte data = Byte.valueOf(parts[1]); + try { + int id = Integer.parseInt(parts[0]); + type = Material.getMaterial(id); + } catch (Throwable t){ + if (!(t instanceof NumberFormatException)) + throw new IllegalArgumentException("Numerical block IDs are not supported by this version: " + Bukkit.getVersion(), t); + type = Material.getMaterial(parts[0]); + } + blocks.add(new MovecraftBlock(type, data)); + } else if (string.toUpperCase().startsWith("ALL_")){ + string = string.replace("ALL_", ""); + for (Material m : Material.values()){ + if (!m.name().endsWith(string)){ + continue; + } + blocks.add(new MovecraftBlock(m)); + } + } else { + try { + int id = Integer.parseInt(string); + type = Material.getMaterial(id); + } catch (Throwable t){ + if (!(t instanceof NumberFormatException)){ + throw new IllegalArgumentException("Numerical block IDs are not supported by this version: " + Bukkit.getVersion(), t); + } + type = Material.getMaterial(string); + } + blocks.add(new MovecraftBlock(type)); + } + } else { + Material type = (Material) i; + blocks.add(new MovecraftBlock(type)); + } + + // then read in the limitation values, low and high + ArrayList objList = (ArrayList) objMap.get(i); + ArrayList limitList = new ArrayList<>(); + for (Object limitObj : objList) { + if (limitObj instanceof String) { + String str = (String) limitObj; + if (str.contains("N")) { // a # indicates a specific quantity, IE: #2 for exactly 2 of the block + String[] parts = str.split("N"); + Double val = Double.valueOf(parts[1]); + limitList.add(10000d + val); // limit greater than 10000 indicates an specific quantity (not a ratio) + } else { + Double val = Double.valueOf(str); + limitList.add(val); + } + } else if (limitObj instanceof Integer) { + Double ret = ((Integer) limitObj).doubleValue(); + limitList.add(ret); + } else { + limitList.add((Double) limitObj); + } + } + entries.add(new Entry(blocks, limitList.get(0), limitList.get(1))); + } + } + + public Set getEntries() { + return entries; + } + + public boolean contains(Material type){ + MovecraftBlock block = new MovecraftBlock(type); + for (Entry e : getEntries()){ + if (!e.getBlocks().contains(block)){ + continue; + } + return true; + } + return false; + } + + public boolean contains(Material type, byte data){ + MovecraftBlock block = new MovecraftBlock(type, data); + for (Entry e : getEntries()){ + if (!e.getBlocks().contains(block)){ + continue; + } + return true; + } + return false; + } + + public boolean hasMetaData(Material type){ + for (Entry e : getEntries()){ + for (MovecraftBlock block : e.getBlocks()){ + if (block.getType() != type){ + continue; + } + return block.getData() != null; + } + } + return false; + } + + public double getLowerLimit(Material type){ + Entry entry = get(type); + return entry != null && entry.getBlocks().contains(new MovecraftBlock(type)) ? entry.getLowerLimit() : 0.0; + } + + public double getLowerLimit(Material type, byte data) { + Entry entry = get(type); + return entry != null && entry.getBlocks().contains(new MovecraftBlock(type, data)) ? entry.getLowerLimit() : 0.0; + } + + public double getUpperLimit(Material type){ + Entry entry = get(type); + return entry != null && entry.getBlocks().contains(new MovecraftBlock(type)) ? entry.getUpperLimit() : 0.0; + } + + public double getUpperLimit(Material type, byte data){ + Entry entry = get(type); + return entry != null && entry.getBlocks().contains(new MovecraftBlock(type, data)) ? entry.getUpperLimit() : 0.0; + } + public Entry get(Material type, byte data){ + Entry entry = get(type); + for (MovecraftBlock b : entry.getBlocks()){ + if (b.getData() != data) + continue; + return entry; + } + return null; + } + + public Entry get(Material type){ + for (Entry e : entries){ + for (MovecraftBlock block : e.getBlocks()){ + if (block.getType() != type){ + continue; + } + return e; + } + } + return null; + } + public static class Entry { + private final Set blocks; + private final double lowerLimit; + private final double upperLimit; + + Entry(Set blocks, double lowerLimit, double upperLimit) { + this.lowerLimit = lowerLimit; + this.upperLimit = upperLimit; + this.blocks = blocks; + } + + public double getLowerLimit() { + return lowerLimit; + } + + public double getUpperLimit() { + return upperLimit; + } + + public Set getBlocks() { + return blocks; + } + } +} From c0e89d1ebb254d8044083e84c5e84790fed6d5e8 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Tue, 8 Oct 2019 01:20:29 +0200 Subject: [PATCH 056/304] Added permission to repair --- .../java/net/countercraft/movecraft/sign/RepairSign.java | 8 ++++++++ .../java/net/countercraft/movecraft/MovecraftBlock.java | 9 +++++++++ .../movecraft/compat/we6/IMovecraftRepair.java | 3 +-- 3 files changed, 18 insertions(+), 2 deletions(-) diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RepairSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RepairSign.java index 04d736d45..bd6ff9a21 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RepairSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RepairSign.java @@ -92,6 +92,10 @@ private void signLeftClick(PlayerInteractEvent event){ event.getPlayer().sendMessage(I18nSupport.getInternationalisedString("You must be piloting a craft")); return; } + if (!event.getPlayer().hasPermission("movecraft." + pCraft.getType().getCraftName() + ".repair")){ + event.getPlayer().sendMessage(I18nSupport.getInternationalisedString("Insufficient Permissions")); + return; + } MovecraftRepair movecraftRepair = Movecraft.getInstance().getMovecraftRepair(); @@ -117,6 +121,10 @@ private void signRightClick(PlayerInteractEvent event){ event.getPlayer().sendMessage(I18nSupport.getInternationalisedString("Repair functionality is disabled or WorldEdit was not detected")); return; } + if (!event.getPlayer().hasPermission("movecraft." + pCraft.getType().getCraftName() + ".repair")){ + event.getPlayer().sendMessage(I18nSupport.getInternationalisedString("Insufficient Permissions")); + return; + } String repairName = event.getPlayer().getName(); repairName += sign.getLine(1); MovecraftRepair movecraftRepair = Movecraft.getInstance().getMovecraftRepair(); diff --git a/modules/api/src/main/java/net/countercraft/movecraft/MovecraftBlock.java b/modules/api/src/main/java/net/countercraft/movecraft/MovecraftBlock.java index 3e53ecf37..146949a1a 100644 --- a/modules/api/src/main/java/net/countercraft/movecraft/MovecraftBlock.java +++ b/modules/api/src/main/java/net/countercraft/movecraft/MovecraftBlock.java @@ -6,9 +6,13 @@ import java.util.Objects; +/** + * Represents a block with the respective + */ public final class MovecraftBlock { private final Material type; private final Byte data; + public MovecraftBlock(Material type, Byte data){ this.type = type; this.data = data; @@ -42,5 +46,10 @@ public boolean equals(Object obj) { public int hashCode() { return Objects.hash(type, data); } + + @Override + public String toString() { + return "{Type: " + type.name() + (data != null ? ", Data: " + data : "") + "}"; + } } diff --git a/modules/worldedit/WE6Utils/src/main/java/net/countercraft/movecraft/compat/we6/IMovecraftRepair.java b/modules/worldedit/WE6Utils/src/main/java/net/countercraft/movecraft/compat/we6/IMovecraftRepair.java index 12175039a..1bcc952fb 100644 --- a/modules/worldedit/WE6Utils/src/main/java/net/countercraft/movecraft/compat/we6/IMovecraftRepair.java +++ b/modules/worldedit/WE6Utils/src/main/java/net/countercraft/movecraft/compat/we6/IMovecraftRepair.java @@ -85,8 +85,7 @@ public boolean saveCraftRepairState(Craft craft, Sign sign) { BlockArrayClipboard clipboard = new BlockArrayClipboard(cRegion); clipboard.setOrigin(origin); Extent source = WorldEdit.getInstance().getEditSessionFactory().getEditSession(weWorld, -1); - Extent destination = clipboard; - ForwardExtentCopy copy = new ForwardExtentCopy(source, cRegion, clipboard.getOrigin(), destination, clipboard.getOrigin()); + ForwardExtentCopy copy = new ForwardExtentCopy(source, cRegion, clipboard.getOrigin(), clipboard, clipboard.getOrigin()); BlockMask mask = new BlockMask(source, blockSet); copy.setSourceMask(mask); Operations.completeLegacy(copy); From 250b99c2f0dae3ec7d173d248b3574771e1871ff Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Tue, 8 Oct 2019 11:51:09 +0200 Subject: [PATCH 057/304] Updated travis.yml and fixed ArrayIndexOutOfBoundsException in DetectionTask --- .travis.yml | 1 + .../countercraft/movecraft/async/detection/DetectionTask.java | 2 ++ .../net/countercraft/movecraft/utils/BlockLimitManager.java | 4 ++++ 3 files changed, 7 insertions(+) diff --git a/.travis.yml b/.travis.yml index f40eeda19..36db5f0aa 100644 --- a/.travis.yml +++ b/.travis.yml @@ -35,4 +35,5 @@ deploy: skip_cleanup: true on: repo: eirikh1996/Movecraft + dist: trusty tags: true \ No newline at end of file diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/detection/DetectionTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/detection/DetectionTask.java index 9d8aa51d0..5a675d5d4 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/detection/DetectionTask.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/detection/DetectionTask.java @@ -370,6 +370,8 @@ private boolean confirmStructureRequirements(BlockLimitManager flyBlocks, Double minPercentage = i.getLowerLimit(); Double maxPercentage = i.getUpperLimit(); ArrayList flyBlockTypes = new ArrayList<>(i.getBlocks()); + if (flyBlockTypes.isEmpty()) + continue; String name = flyBlockTypes.get(0).getType().name(); if (minPercentage < 10000.0) { if (blockPercentage < minPercentage) { diff --git a/modules/api/src/main/java/net/countercraft/movecraft/utils/BlockLimitManager.java b/modules/api/src/main/java/net/countercraft/movecraft/utils/BlockLimitManager.java index cd5b5fae0..d2aa0e3c3 100644 --- a/modules/api/src/main/java/net/countercraft/movecraft/utils/BlockLimitManager.java +++ b/modules/api/src/main/java/net/countercraft/movecraft/utils/BlockLimitManager.java @@ -13,6 +13,10 @@ public BlockLimitManager(){} public BlockLimitManager(Object obj){ HashMap objMap = (HashMap) obj; for (Object i : objMap.keySet()) { + //Ignore keys that are null + if (i == null){ + continue; + } Set blocks = new HashSet<>(); if (i instanceof ArrayList) { for (Object o : (ArrayList) i) { From 840cf8a986a44cccc85de1cf910b8ad33dea1a0a Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Tue, 15 Oct 2019 23:15:29 +0200 Subject: [PATCH 058/304] Made repairs only store blocks contained in a craft's hitbox --- .../compat/we6/IMovecraftRepair.java | 26 ++++++++++++++++--- .../compat/we7/IMovecraftRepair.java | 22 ++++++++++++++++ 2 files changed, 44 insertions(+), 4 deletions(-) diff --git a/modules/worldedit/WE6Utils/src/main/java/net/countercraft/movecraft/compat/we6/IMovecraftRepair.java b/modules/worldedit/WE6Utils/src/main/java/net/countercraft/movecraft/compat/we6/IMovecraftRepair.java index 1bcc952fb..7bc5f2269 100644 --- a/modules/worldedit/WE6Utils/src/main/java/net/countercraft/movecraft/compat/we6/IMovecraftRepair.java +++ b/modules/worldedit/WE6Utils/src/main/java/net/countercraft/movecraft/compat/we6/IMovecraftRepair.java @@ -5,6 +5,7 @@ import com.sk89q.jnbt.Tag; import com.sk89q.worldedit.MaxChangedBlocksException; import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.WorldEditException; import com.sk89q.worldedit.blocks.BaseBlock; import com.sk89q.worldedit.bukkit.BukkitWorld; import com.sk89q.worldedit.extent.Extent; @@ -26,9 +27,7 @@ import net.countercraft.movecraft.MovecraftRepair; import net.countercraft.movecraft.config.Settings; import net.countercraft.movecraft.craft.Craft; -import net.countercraft.movecraft.utils.HashHitBox; -import net.countercraft.movecraft.utils.MathUtils; -import net.countercraft.movecraft.utils.Pair; +import net.countercraft.movecraft.utils.*; import org.bukkit.*; import org.bukkit.block.Block; import org.bukkit.block.Dispenser; @@ -80,6 +79,7 @@ public boolean saveCraftRepairState(Craft craft, Sign sign) { repairName += ".schematic"; File repairStateFile = new File(playerDirectory, repairName); Set blockSet = baseBlocksFromCraft(craft); + final HitBox outsideLocs = CollectionUtils.filter(solidBlockLocs(craft.getW(), cRegion), hitBox); try { BlockArrayClipboard clipboard = new BlockArrayClipboard(cRegion); @@ -90,11 +90,14 @@ public boolean saveCraftRepairState(Craft craft, Sign sign) { copy.setSourceMask(mask); Operations.completeLegacy(copy); ClipboardWriter writer = ClipboardFormat.SCHEMATIC.getWriter(new FileOutputStream(repairStateFile, false)); + for (MovecraftLocation ml : outsideLocs){ + clipboard.setBlock(new com.sk89q.worldedit.Vector(ml.getX(), ml.getY(), ml.getZ()), new BaseBlock(0)); + } writer.write(clipboard, worldData); writer.close(); return true; - } catch (MaxChangedBlocksException | IOException e) { + } catch (IOException | WorldEditException e) { e.printStackTrace(); return false; } @@ -598,4 +601,19 @@ private Set baseBlocksFromCraft(Craft craft) { } return returnSet; } + + private HashHitBox solidBlockLocs(World w, CuboidRegion cr){ + HashHitBox returnSet = new HashHitBox(); + for (int x = cr.getMinimumPoint().getBlockX(); x <= cr.getMaximumPoint().getBlockX(); x++){ + for (int y = cr.getMinimumPoint().getBlockY(); y <= cr.getMaximumPoint().getBlockY(); y++){ + for (int z = cr.getMinimumPoint().getBlockZ(); z <= cr.getMaximumPoint().getBlockZ(); z++){ + MovecraftLocation ml = new MovecraftLocation(x, y, z); + if (ml.toBukkit(w).getBlock().getType() != Material.AIR){ + returnSet.add(ml); + } + } + } + } + return returnSet; + } } diff --git a/modules/worldedit/WE7Utils/src/main/java/net/countercraft/movecraft/compat/we7/IMovecraftRepair.java b/modules/worldedit/WE7Utils/src/main/java/net/countercraft/movecraft/compat/we7/IMovecraftRepair.java index 57f23fb5c..89da63b87 100644 --- a/modules/worldedit/WE7Utils/src/main/java/net/countercraft/movecraft/compat/we7/IMovecraftRepair.java +++ b/modules/worldedit/WE7Utils/src/main/java/net/countercraft/movecraft/compat/we7/IMovecraftRepair.java @@ -27,10 +27,13 @@ import com.sk89q.worldguard.protection.regions.ProtectedCuboidRegion; import com.sk89q.worldguard.protection.regions.ProtectedPolygonalRegion; import com.sk89q.worldguard.protection.regions.ProtectedRegion; +import net.countercraft.movecraft.MovecraftLocation; import net.countercraft.movecraft.MovecraftRepair; import net.countercraft.movecraft.config.Settings; import net.countercraft.movecraft.craft.Craft; +import net.countercraft.movecraft.utils.CollectionUtils; import net.countercraft.movecraft.utils.HashHitBox; +import net.countercraft.movecraft.utils.HitBox; import net.countercraft.movecraft.utils.Pair; import org.bukkit.Location; import org.bukkit.Material; @@ -85,8 +88,12 @@ public boolean saveCraftRepairState(Craft craft, Sign sign) { ForwardExtentCopy copy = new ForwardExtentCopy(source, region, clipboard.getOrigin(), destination, clipboard.getOrigin()); ExistingBlockMask mask = new ExistingBlockMask(source); copy.setSourceMask(mask); + final HitBox outsideLocs = CollectionUtils.filter(solidBlockLocs(world, region), hitBox); try { Operations.complete(copy); + for (MovecraftLocation ml : outsideLocs){ + clipboard.setBlock(BlockVector3.at(ml.getX(), ml.getY(), ml.getZ()), BukkitAdapter.asBlockType(Material.AIR).getDefaultState()); + } } catch (WorldEditException e) { e.printStackTrace(); return false; @@ -445,4 +452,19 @@ public ArrayDeque> getMissingBlockLocations(String s) { public long getNumDiffBlocks(String s) { return numDiffBlocksMap.get(s); } + + private HashHitBox solidBlockLocs(World w, CuboidRegion cr){ + HashHitBox returnSet = new HashHitBox(); + for (int x = cr.getMinimumPoint().getBlockX(); x <= cr.getMaximumPoint().getBlockX(); x++){ + for (int y = cr.getMinimumPoint().getBlockY(); y <= cr.getMaximumPoint().getBlockY(); y++){ + for (int z = cr.getMinimumPoint().getBlockZ(); z <= cr.getMaximumPoint().getBlockZ(); z++){ + MovecraftLocation ml = new MovecraftLocation(x, y, z); + if (ml.toBukkit(w).getBlock().getType() != Material.AIR){ + returnSet.add(ml); + } + } + } + } + return returnSet; + } } From 6c672ebeae858e90fe9de830518cd11b8e4f9b13 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Wed, 16 Oct 2019 22:30:09 +0200 Subject: [PATCH 059/304] Various fixes, including, but not limited to: Repair system --- .../net/countercraft/movecraft/Movecraft.java | 10 +- .../movecraft/sign/RepairSign.java | 35 +- .../movecraft/MovecraftRepair.java | 4 +- .../movecraft/craft/CraftType.java | 650 +++++++++--------- .../compat/v1_14_R1/NextTickProvider.java | 7 +- .../compat/we6/IMovecraftRepair.java | 10 +- .../compat/we7/IMovecraftRepair.java | 9 +- 7 files changed, 364 insertions(+), 361 deletions(-) diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java index 6d0219072..93a53e359 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java @@ -255,7 +255,13 @@ public void onEnable() { } List disableShadowBlocks = getConfig().getStringList("DisableShadowBlocks"); for (String typ : disableShadowBlocks){ - Settings.DisableShadowBlocks.add(Material.getMaterial(typ.toUpperCase())); + Material type; + try { + type = LegacyUtils.getMaterial(Integer.parseInt(typ)); + } catch (NumberFormatException e){ + type = Material.getMaterial(typ); + } + Settings.DisableShadowBlocks.add(type); } Settings.RepairMaxPercent = getConfig().getDouble("RepairMaxPercent", 50.0); Settings.ForbiddenRemoteSigns = new HashSet<>(getConfig().getStringList("ForbiddenRemoteSigns")); @@ -270,7 +276,7 @@ public void onEnable() { } //load up WorldGuard if it's present Plugin wGPlugin = getServer().getPluginManager().getPlugin("WorldGuard"); - if (wGPlugin == null || !(wGPlugin instanceof WorldGuardPlugin)) { + if (!(wGPlugin instanceof WorldGuardPlugin)) { logger.log(Level.INFO, I18nSupport.getInternationalisedString("Startup - WG Not Found")); Settings.SiegeEnable = false; Settings.AssaultEnable = false; diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RepairSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RepairSign.java index 93b63fd4d..298884ead 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RepairSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RepairSign.java @@ -3,6 +3,7 @@ import com.sk89q.worldedit.blocks.BaseBlock; import com.sk89q.worldedit.bukkit.BukkitAdapter; import com.sk89q.worldedit.extent.clipboard.Clipboard; +import javafx.util.Pair; import net.countercraft.movecraft.Movecraft; import net.countercraft.movecraft.MovecraftLocation; import net.countercraft.movecraft.MovecraftRepair; @@ -17,7 +18,6 @@ import net.countercraft.movecraft.repair.RepairManager; import net.countercraft.movecraft.repair.RepairUtils; import net.countercraft.movecraft.utils.LegacyUtils; -import net.countercraft.movecraft.utils.Pair; import net.countercraft.movecraft.utils.WorldEditUtils; import org.bukkit.ChatColor; import org.bukkit.Material; @@ -126,7 +126,6 @@ private void signRightClick(PlayerInteractEvent event){ return; } String repairName = event.getPlayer().getUniqueId().toString(); - repairName += "_"; repairName += ChatColor.stripColor(sign.getLine(1)); MovecraftRepair movecraftRepair = Movecraft.getInstance().getMovecraftRepair(); Clipboard clipboard = movecraftRepair.loadCraftRepairStateClipboard(pCraft, sign); @@ -156,13 +155,13 @@ private void signRightClick(PlayerInteractEvent event){ Block b = pCraft.getW().getBlockAt(loc.getX(), loc.getY(), loc.getZ()); if ((b.getType() == Material.CHEST) || (b.getType() == Material.TRAPPED_CHEST)) { InventoryHolder inventoryHolder = (InventoryHolder) b.getState(); - if (inventoryHolder.getInventory().contains(type.getLeft()) && remainingQty > 0) { - HashMap foundItems = inventoryHolder.getInventory().all(type.getLeft()); + if (inventoryHolder.getInventory().contains(type.getKey()) && remainingQty > 0) { + HashMap foundItems = inventoryHolder.getInventory().all(type.getKey()); // count how many were in the chest int numfound = 0; for (ItemStack istack : foundItems.values()) { //Check data value if it is coal - if (istack.getType().equals(Material.COAL) && istack.getData().getData() != type.getRight()){ + if (istack.getType().equals(Material.COAL) && istack.getData().getData() != type.getValue()){ continue; } numfound += istack.getAmount(); @@ -173,15 +172,15 @@ private void signRightClick(PlayerInteractEvent event){ } } if (remainingQty > 0) { - if (type.getLeft().equals(Material.COAL)) { - event.getPlayer().sendMessage(String.format(I18nSupport.getInternationalisedString("Repair - Need more of material") + ": %s - %d", type.getRight() == 1 ? "charcoal" : "coal", remainingQty)); + if (type.getKey().equals(Material.COAL)) { + event.getPlayer().sendMessage(String.format(I18nSupport.getInternationalisedString("Repair - Need more of material") + ": %s - %d", type.getValue() == 1 ? "charcoal" : "coal", remainingQty)); } else { - event.getPlayer().sendMessage(String.format(I18nSupport.getInternationalisedString("Repair - Need more of material") + ": %s - %d", type.getLeft().name().toLowerCase().replace("_", " "), remainingQty)); + event.getPlayer().sendMessage(String.format(I18nSupport.getInternationalisedString("Repair - Need more of material") + ": %s - %d", type.getKey().name().toLowerCase().replace("_", " "), remainingQty)); } enoughMaterial = false; } else { - chestsToTakeFrom.put(type.getLeft(), chests); + chestsToTakeFrom.put(type.getKey(), chests); } } if (Movecraft.getInstance().getEconomy() != null && enoughMaterial) { @@ -197,10 +196,10 @@ private void signRightClick(PlayerInteractEvent event){ // we know we have enough materials to make the repairs, so remove the materials from the chests for (Pair type : numMissingItems.keySet()) { int remainingQty = (int) Math.round(numMissingItems.get(type)); - for (InventoryHolder inventoryHolder : chestsToTakeFrom.get(type.getLeft())) { - HashMap foundItems = inventoryHolder.getInventory().all(type.getLeft()); + for (InventoryHolder inventoryHolder : chestsToTakeFrom.get(type.getKey())) { + HashMap foundItems = inventoryHolder.getInventory().all(type.getKey()); for (ItemStack istack : foundItems.values()) { - if (istack.getType().equals(Material.COAL) && istack.getData().getData() != type.getRight()){ + if (istack.getType().equals(Material.COAL) && istack.getData().getData() != type.getValue()){ continue; } if (istack.getAmount() <= remainingQty) { @@ -222,8 +221,8 @@ private void signRightClick(PlayerInteractEvent event){ while (!locMissingBlocks.isEmpty()){ Pair locs = locMissingBlocks.pollFirst(); assert locs != null; - Vector cLoc = locs.getRight(); - MovecraftLocation moveLoc = new MovecraftLocation(locs.getLeft().getBlockX(), locs.getLeft().getBlockY(), locs.getLeft().getBlockZ()); + Vector cLoc = locs.getValue(); + MovecraftLocation moveLoc = new MovecraftLocation(locs.getKey().getBlockX(), locs.getKey().getBlockY(), locs.getKey().getBlockZ()); //To avoid any issues during the repair, keep certain blocks in different linked lists Material type; if (Settings.IsLegacy) { @@ -264,12 +263,12 @@ private void signRightClick(PlayerInteractEvent event){ return; } if (numDifferentBlocks != 0) { - for (Pair blockType : numMissingItems.keySet()) { event.getPlayer().sendMessage(I18nSupport.getInternationalisedString("Repair - Supplies needed")); - if (blockType.getLeft().equals(Material.COAL)) { - event.getPlayer().sendMessage(String.format("%s : %d", blockType.getRight() == 1 ? "charcoal" : "coal" , Math.round(numMissingItems.get(blockType)))); + for (Pair blockType : numMissingItems.keySet()) { + if (blockType.getKey().equals(Material.COAL)) { + event.getPlayer().sendMessage(String.format("%s : %d", blockType.getValue() == 1 ? "charcoal" : "coal" , Math.round(numMissingItems.get(blockType)))); } else { - event.getPlayer().sendMessage(String.format("%s : %d", blockType.getLeft().name().toLowerCase().replace("_", " "), Math.round(numMissingItems.get(blockType)))); + event.getPlayer().sendMessage(String.format("%s : %d", blockType.getKey().name().toLowerCase().replace("_", " "), Math.round(numMissingItems.get(blockType)))); } } long durationInSeconds = numDifferentBlocks * Settings.RepairTicksPerBlock / 20; diff --git a/modules/api/src/main/java/net/countercraft/movecraft/MovecraftRepair.java b/modules/api/src/main/java/net/countercraft/movecraft/MovecraftRepair.java index 150a7a3ae..7d50c5262 100644 --- a/modules/api/src/main/java/net/countercraft/movecraft/MovecraftRepair.java +++ b/modules/api/src/main/java/net/countercraft/movecraft/MovecraftRepair.java @@ -2,8 +2,8 @@ import com.sk89q.worldedit.extent.clipboard.Clipboard; import com.sk89q.worldguard.protection.regions.ProtectedRegion; +import javafx.util.Pair; import net.countercraft.movecraft.craft.Craft; -import net.countercraft.movecraft.utils.Pair; import org.bukkit.Material; import org.bukkit.World; import org.bukkit.block.Sign; @@ -20,7 +20,7 @@ public abstract class MovecraftRepair { public abstract Clipboard loadRegionRepairStateClipboard(String repairStateName, World bukkitWorld); - public abstract HashMap, Double> getMissingBlocks(String repairName); + public abstract HashMap, Double> getMissingBlocks(String repairName); public abstract ArrayDeque> getMissingBlockLocations(String repairName); diff --git a/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java b/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java index 57af97f41..d2b3c2575 100644 --- a/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java +++ b/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java @@ -112,353 +112,351 @@ public CraftType(File f) { throw new TypeNotFoundException("No file found at path " + f.getAbsolutePath()); } - craftName = (String) data.get("name"); - Bukkit.getLogger().info(craftName); - maxSize = integerFromObject(data.get("maxSize")); - minSize = integerFromObject(data.get("minSize")); - allowedBlocks = new BlockContainer(data.get("allowedBlocks")); - if (data.containsKey("forbiddenBlocks")){ - forbiddenBlocks = new BlockContainer(data.get("forbiddenBlocks")); - } else { - forbiddenBlocks = new BlockContainer(); - } - forbiddenSignStrings = stringListFromObject(data.get("forbiddenSignStrings")); - if (data.containsKey("canFly")) { - blockedByWater = (Boolean) data.get("canFly"); - } else if (data.containsKey("blockedByWater")) { - blockedByWater = (Boolean) data.get("blockedByWater"); - } else { - blockedByWater = true; - } - if (data.containsKey("requireWaterContact")) { - requireWaterContact = (Boolean) data.get("requireWaterContact"); - } else { - requireWaterContact = false; - } - if (data.containsKey("tryNudge")) { - tryNudge = (Boolean) data.get("tryNudge"); - } else { - tryNudge = false; - } - tickCooldown = (int) Math.ceil(20 / (doubleFromObject(data.get("speed")))); - if (data.containsKey("cruiseSpeed")) { - cruiseTickCooldown = (int) Math.ceil(20 / (doubleFromObject(data.get("cruiseSpeed")))); - } else { - cruiseTickCooldown = tickCooldown; - } + try { + craftName = (String) data.get("name"); + Bukkit.getLogger().info(craftName); + maxSize = integerFromObject(data.get("maxSize")); + minSize = integerFromObject(data.get("minSize")); + allowedBlocks = new BlockContainer(data.get("allowedBlocks")); + if (data.containsKey("forbiddenBlocks")) { + forbiddenBlocks = new BlockContainer(data.get("forbiddenBlocks")); + } else { + forbiddenBlocks = new BlockContainer(); + } + forbiddenSignStrings = stringListFromObject(data.get("forbiddenSignStrings")); + if (data.containsKey("canFly")) { + blockedByWater = (Boolean) data.get("canFly"); + } else if (data.containsKey("blockedByWater")) { + blockedByWater = (Boolean) data.get("blockedByWater"); + } else { + blockedByWater = true; + } + if (data.containsKey("requireWaterContact")) { + requireWaterContact = (Boolean) data.get("requireWaterContact"); + } else { + requireWaterContact = false; + } + if (data.containsKey("tryNudge")) { + tryNudge = (Boolean) data.get("tryNudge"); + } else { + tryNudge = false; + } + tickCooldown = (int) Math.ceil(20 / (doubleFromObject(data.get("speed")))); + if (data.containsKey("cruiseSpeed")) { + cruiseTickCooldown = (int) Math.ceil(20 / (doubleFromObject(data.get("cruiseSpeed")))); + } else { + cruiseTickCooldown = tickCooldown; + } - flyBlocks = new BlockLimitManager(data.get("flyblocks")); - if (data.containsKey("moveblocks")) { - moveBlocks = new BlockLimitManager(data.get("moveblocks")); - } else { - moveBlocks = new BlockLimitManager(); - } + flyBlocks = new BlockLimitManager(data.get("flyblocks")); + if (data.containsKey("moveblocks")) { + moveBlocks = new BlockLimitManager(data.get("moveblocks")); + } else { + moveBlocks = new BlockLimitManager(); + } - if (data.containsKey("canCruise")) { - canCruise = (Boolean) data.get("canCruise"); - } else { - canCruise = false; - } - if (data.containsKey("canTeleport")) { - canTeleport = (Boolean) data.get("canTeleport"); - } else { - canTeleport = false; - } - if (data.containsKey("canBeNamed")){ - canBeNamed = (Boolean) data.get("canBeNamed"); - } else { - canBeNamed = true; - } - if (data.containsKey("cruiseOnPilot")) { - cruiseOnPilot = (Boolean) data.get("cruiseOnPilot"); - } else { - cruiseOnPilot = false; - } - if (data.containsKey("cruiseOnPilotVertMove")) { - cruiseOnPilotVertMove = integerFromObject(data.get("cruiseOnPilotVertMove")); - } else { - cruiseOnPilotVertMove = 0; - } - if (data.containsKey("allowVerticalMovement")) { - allowVerticalMovement = (Boolean) data.get("allowVerticalMovement"); - } else { - allowVerticalMovement = true; - } - if (data.containsKey("rotateAtMidpoint")) { - rotateAtMidpoint = (Boolean) data.get("rotateAtMidpoint"); - } else { - rotateAtMidpoint = false; - } - if (data.containsKey("allowHorizontalMovement")) { - allowHorizontalMovement = (Boolean) data.get("allowHorizontalMovement"); - } else { - allowHorizontalMovement = true; - } - if (data.containsKey("allowRemoteSign")) { - allowRemoteSign = (Boolean) data.get("allowRemoteSign"); - } else { - allowRemoteSign = true; - } - if (data.containsKey("allowCannonDirectorSign")) { - allowCannonDirectorSign = (Boolean) data.get("allowCannonDirectorSign"); - } else { - allowCannonDirectorSign = true; - } - if (data.containsKey("allowAADirectorSign")) { - allowAADirectorSign = (Boolean) data.get("allowAADirectorSign"); - } else { - allowAADirectorSign = true; - } - if (data.containsKey("canStaticMove")) { - canStaticMove = (Boolean) data.get("canStaticMove"); - } else { - canStaticMove = false; - } - if (data.containsKey("maxStaticMove")) { - maxStaticMove = integerFromObject(data.get("maxStaticMove")); - } else { - maxStaticMove = 10000; - } - if (data.containsKey("cruiseSkipBlocks")) { - cruiseSkipBlocks = integerFromObject(data.get("cruiseSkipBlocks")); - } else { - cruiseSkipBlocks = 0; - } - if (data.containsKey("vertCruiseSkipBlocks")) { - vertCruiseSkipBlocks = integerFromObject(data.get("vertCruiseSkipBlocks")); - } else { - vertCruiseSkipBlocks = cruiseSkipBlocks; - } - if (data.containsKey("halfSpeedUnderwater")) { - halfSpeedUnderwater = (Boolean) data.get("halfSpeedUnderwater"); - } else { - halfSpeedUnderwater = false; - } - if (data.containsKey("focusedExplosion")) { - focusedExplosion = (Boolean) data.get("focusedExplosion"); - } else { - focusedExplosion = false; - } - if (data.containsKey("mustBeSubcraft")) { - mustBeSubcraft = (Boolean) data.get("mustBeSubcraft"); - } else { - mustBeSubcraft = false; - } - if (data.containsKey("staticWaterLevel")) { - staticWaterLevel = integerFromObject(data.get("staticWaterLevel")); - } else { - staticWaterLevel = 0; - } - if (data.containsKey("fuelBurnRate")) { - fuelBurnRate = doubleFromObject(data.get("fuelBurnRate")); - } else { - fuelBurnRate = 0d; - } - if (data.containsKey("sinkPercent")) { - sinkPercent = doubleFromObject(data.get("sinkPercent")); - } else { - sinkPercent = 0d; - } - if (data.containsKey("overallSinkPercent")) { - overallSinkPercent = doubleFromObject(data.get("overallSinkPercent")); - } else { - overallSinkPercent = 0d; - } - if (data.containsKey("detectionMultiplier")) { - detectionMultiplier = doubleFromObject(data.get("detectionMultiplier")); - } else { - detectionMultiplier = 0d; - } - if (data.containsKey("underwaterDetectionMultiplier")) { - underwaterDetectionMultiplier = doubleFromObject(data.get("underwaterDetectionMultiplier")); - } else { - underwaterDetectionMultiplier = detectionMultiplier; - } - if(data.containsKey("sinkTickRate")){ - sinkRateTicks = integerFromObject(data.get("sinkTickRate")); - }else if (data.containsKey("sinkSpeed")) { - sinkRateTicks = (int) Math.ceil(20 / (doubleFromObject(data.get("sinkSpeed")))); - } else { - //sinkRateTicks = (int) Settings.SinkRateTicks; - sinkRateTicks = 0; - } - if (data.containsKey("keepMovingOnSink")) { - keepMovingOnSink = (Boolean) data.get("keepMovingOnSink"); - } else { - keepMovingOnSink = false; - } - if (data.containsKey("smokeOnSink")) { - smokeOnSink = integerFromObject(data.get("smokeOnSink")); - } else { - smokeOnSink = 0; - } - if (data.containsKey("explodeOnCrash")) { - double temp = doubleFromObject(data.get("explodeOnCrash")); - explodeOnCrash = (float) temp; - } else { - explodeOnCrash = 0F; - } - if (data.containsKey("collisionExplosion")) { - double temp = doubleFromObject(data.get("collisionExplosion")); - collisionExplosion = (float) temp; - } else { - collisionExplosion = 0F; - } - if (data.containsKey("minHeightLimit")) { - minHeightLimit = Math.max(0, integerFromObject(data.get("minHeightLimit"))); - } else { - minHeightLimit = 0; - } - if (data.containsKey("maxHeightLimit")) { - int value = integerFromObject(data.get("maxHeightLimit")); - if (value <= minHeightLimit) { - value = 255; + if (data.containsKey("canCruise")) { + canCruise = (Boolean) data.get("canCruise"); + } else { + canCruise = false; + } + if (data.containsKey("canTeleport")) { + canTeleport = (Boolean) data.get("canTeleport"); + } else { + canTeleport = false; + } + if (data.containsKey("canBeNamed")) { + canBeNamed = (Boolean) data.get("canBeNamed"); + } else { + canBeNamed = true; + } + if (data.containsKey("cruiseOnPilot")) { + cruiseOnPilot = (Boolean) data.get("cruiseOnPilot"); + } else { + cruiseOnPilot = false; + } + if (data.containsKey("cruiseOnPilotVertMove")) { + cruiseOnPilotVertMove = integerFromObject(data.get("cruiseOnPilotVertMove")); + } else { + cruiseOnPilotVertMove = 0; + } + if (data.containsKey("allowVerticalMovement")) { + allowVerticalMovement = (Boolean) data.get("allowVerticalMovement"); + } else { + allowVerticalMovement = true; + } + if (data.containsKey("rotateAtMidpoint")) { + rotateAtMidpoint = (Boolean) data.get("rotateAtMidpoint"); + } else { + rotateAtMidpoint = false; + } + if (data.containsKey("allowHorizontalMovement")) { + allowHorizontalMovement = (Boolean) data.get("allowHorizontalMovement"); + } else { + allowHorizontalMovement = true; + } + if (data.containsKey("allowRemoteSign")) { + allowRemoteSign = (Boolean) data.get("allowRemoteSign"); + } else { + allowRemoteSign = true; + } + if (data.containsKey("allowCannonDirectorSign")) { + allowCannonDirectorSign = (Boolean) data.get("allowCannonDirectorSign"); + } else { + allowCannonDirectorSign = true; + } + if (data.containsKey("allowAADirectorSign")) { + allowAADirectorSign = (Boolean) data.get("allowAADirectorSign"); + } else { + allowAADirectorSign = true; + } + if (data.containsKey("canStaticMove")) { + canStaticMove = (Boolean) data.get("canStaticMove"); + } else { + canStaticMove = false; + } + if (data.containsKey("maxStaticMove")) { + maxStaticMove = integerFromObject(data.get("maxStaticMove")); + } else { + maxStaticMove = 10000; + } + if (data.containsKey("cruiseSkipBlocks")) { + cruiseSkipBlocks = integerFromObject(data.get("cruiseSkipBlocks")); + } else { + cruiseSkipBlocks = 0; + } + if (data.containsKey("vertCruiseSkipBlocks")) { + vertCruiseSkipBlocks = integerFromObject(data.get("vertCruiseSkipBlocks")); + } else { + vertCruiseSkipBlocks = cruiseSkipBlocks; + } + if (data.containsKey("halfSpeedUnderwater")) { + halfSpeedUnderwater = (Boolean) data.get("halfSpeedUnderwater"); + } else { + halfSpeedUnderwater = false; + } + if (data.containsKey("focusedExplosion")) { + focusedExplosion = (Boolean) data.get("focusedExplosion"); + } else { + focusedExplosion = false; + } + if (data.containsKey("mustBeSubcraft")) { + mustBeSubcraft = (Boolean) data.get("mustBeSubcraft"); + } else { + mustBeSubcraft = false; + } + if (data.containsKey("staticWaterLevel")) { + staticWaterLevel = integerFromObject(data.get("staticWaterLevel")); + } else { + staticWaterLevel = 0; + } + if (data.containsKey("fuelBurnRate")) { + fuelBurnRate = doubleFromObject(data.get("fuelBurnRate")); + } else { + fuelBurnRate = 0d; + } + if (data.containsKey("sinkPercent")) { + sinkPercent = doubleFromObject(data.get("sinkPercent")); + } else { + sinkPercent = 0d; + } + if (data.containsKey("overallSinkPercent")) { + overallSinkPercent = doubleFromObject(data.get("overallSinkPercent")); + } else { + overallSinkPercent = 0d; + } + if (data.containsKey("detectionMultiplier")) { + detectionMultiplier = doubleFromObject(data.get("detectionMultiplier")); + } else { + detectionMultiplier = 0d; + } + if (data.containsKey("underwaterDetectionMultiplier")) { + underwaterDetectionMultiplier = doubleFromObject(data.get("underwaterDetectionMultiplier")); + } else { + underwaterDetectionMultiplier = detectionMultiplier; + } + if (data.containsKey("sinkTickRate")) { + sinkRateTicks = integerFromObject(data.get("sinkTickRate")); + } else if (data.containsKey("sinkSpeed")) { + sinkRateTicks = (int) Math.ceil(20 / (doubleFromObject(data.get("sinkSpeed")))); + } else { + //sinkRateTicks = (int) Settings.SinkRateTicks; + sinkRateTicks = 0; + } + if (data.containsKey("keepMovingOnSink")) { + keepMovingOnSink = (Boolean) data.get("keepMovingOnSink"); + } else { + keepMovingOnSink = false; + } + if (data.containsKey("smokeOnSink")) { + smokeOnSink = integerFromObject(data.get("smokeOnSink")); + } else { + smokeOnSink = 0; + } + if (data.containsKey("explodeOnCrash")) { + double temp = doubleFromObject(data.get("explodeOnCrash")); + explodeOnCrash = (float) temp; + } else { + explodeOnCrash = 0F; + } + if (data.containsKey("collisionExplosion")) { + double temp = doubleFromObject(data.get("collisionExplosion")); + collisionExplosion = (float) temp; + } else { + collisionExplosion = 0F; + } + if (data.containsKey("minHeightLimit")) { + minHeightLimit = Math.max(0, integerFromObject(data.get("minHeightLimit"))); + } else { + minHeightLimit = 0; + } + if (data.containsKey("maxHeightLimit")) { + int value = integerFromObject(data.get("maxHeightLimit")); + if (value <= minHeightLimit) { + value = 255; + } + maxHeightLimit = value; + } else { + maxHeightLimit = 254; + } + if (data.containsKey("maxHeightAboveGround")) { + maxHeightAboveGround = integerFromObject(data.get("maxHeightAboveGround")); + } else { + maxHeightAboveGround = -1; + } + if (data.containsKey("canDirectControl")) { + canDirectControl = (Boolean) data.get("canDirectControl"); + } else { + canDirectControl = true; + } + if (data.containsKey("canHover")) { + canHover = (Boolean) data.get("canHover"); + } else { + canHover = false; + } + if (data.containsKey("canHoverOverWater")) { + canHoverOverWater = (Boolean) data.get("canHoverOverWater"); + } else { + canHoverOverWater = true; + } + if (data.containsKey("moveEntities")) { + moveEntities = (Boolean) data.get("moveEntities"); + } else { + moveEntities = true; } - maxHeightLimit = value; - } else { - maxHeightLimit = 254; - } - if (data.containsKey("maxHeightAboveGround")) { - maxHeightAboveGround = integerFromObject(data.get("maxHeightAboveGround")); - } else { - maxHeightAboveGround = -1; - } - if (data.containsKey("canDirectControl")) { - canDirectControl = (Boolean) data.get("canDirectControl"); - } else { - canDirectControl = true; - } - if (data.containsKey("canHover")) { - canHover = (Boolean) data.get("canHover"); - } else { - canHover = false; - } - if (data.containsKey("canHoverOverWater")) { - canHoverOverWater = (Boolean) data.get("canHoverOverWater"); - } else { - canHoverOverWater = true; - } - if (data.containsKey("moveEntities")) { - moveEntities = (Boolean) data.get("moveEntities"); - } else { - moveEntities = true; - } - if(data.containsKey("onlyMovePlayers")){ - onlyMovePlayers = (Boolean) data.get("onlyMovePlayers"); - } else { - onlyMovePlayers = true; - } + if (data.containsKey("onlyMovePlayers")) { + onlyMovePlayers = (Boolean) data.get("onlyMovePlayers"); + } else { + onlyMovePlayers = true; + } - if (data.containsKey("useGravity")) { - useGravity = (Boolean) data.get("useGravity"); - } else { - useGravity = false; - } + if (data.containsKey("useGravity")) { + useGravity = (Boolean) data.get("useGravity"); + } else { + useGravity = false; + } - if (data.containsKey("hoverLimit")) { - hoverLimit = Math.max(0, integerFromObject(data.get("hoverLimit"))); - } else { - hoverLimit = 0; - } - harvestBlocks = new ArrayList<>(); - harvesterBladeBlocks = new ArrayList<>(); - if (data.containsKey("harvestBlocks")) { - /* String[] temp = ((ArrayList ) data.get( "harvestBlocks" )).toArray( new String[1] ); - for (int i = 0; i < temp.length; i++){ - Material mat = Material.getMaterial(temp[i]); - if (mat != null ){ - harvestBlocks.add(mat); - }*/ - ArrayList objList = (ArrayList) data.get("harvestBlocks"); - for (Object i : objList) { - if (i instanceof String) { - Material mat = Material.getMaterial(((String) i).toUpperCase()); - harvestBlocks.add(mat); - } else { - Material mat = Material.getMaterial((Integer) i); - harvestBlocks.add(mat); - } + if (data.containsKey("hoverLimit")) { + hoverLimit = Math.max(0, integerFromObject(data.get("hoverLimit"))); + } else { + hoverLimit = 0; } + harvestBlocks = new ArrayList<>(); + harvesterBladeBlocks = new ArrayList<>(); + if (data.containsKey("harvestBlocks")) { + ArrayList objList = (ArrayList) data.get("harvestBlocks"); + for (Object i : objList) { + if (i instanceof String) { + Material mat = Material.getMaterial(((String) i).toUpperCase()); + harvestBlocks.add(mat); + } else { + Material mat = Material.getMaterial((Integer) i); + harvestBlocks.add(mat); + } + } - } - if (data.containsKey("harvesterBladeBlocks")) { - ArrayList objList = (ArrayList) data.get("harvesterBladeBlocks"); - for (Object i : objList) { - if (i instanceof String) { - Material mat = Material.getMaterial(((String) i).toUpperCase()); - harvesterBladeBlocks.add(mat); - } else { - Integer typeID = (Integer) i; - Material mat = Material.getMaterial((Integer) i); - harvesterBladeBlocks.add(mat); + } + if (data.containsKey("harvesterBladeBlocks")) { + ArrayList objList = (ArrayList) data.get("harvesterBladeBlocks"); + for (Object i : objList) { + if (i instanceof String) { + Material mat = Material.getMaterial(((String) i).toUpperCase()); + harvesterBladeBlocks.add(mat); + } else { + Integer typeID = (Integer) i; + Material mat = Material.getMaterial((Integer) i); + harvesterBladeBlocks.add(mat); + } } } - } - passthroughBlocks = new HashSet<>(); - if (data.containsKey("passthroughBlocks")) { - ArrayList objList = (ArrayList) data.get("passthroughBlocks"); - for (Object i : objList) { - if (i instanceof String) { - Material mat = Material.getMaterial(((String) i).toUpperCase()); - passthroughBlocks.add(mat); + passthroughBlocks = new HashSet<>(); + if (data.containsKey("passthroughBlocks")) { + ArrayList objList = (ArrayList) data.get("passthroughBlocks"); + for (Object i : objList) { + if (i instanceof String) { + Material mat = Material.getMaterial(((String) i).toUpperCase()); + passthroughBlocks.add(mat); + } else { + Material mat = Material.getMaterial((Integer) i); + passthroughBlocks.add(mat); + } + } + } + if (!blockedByWater) { + passthroughBlocks.add(Material.WATER); + if (Settings.IsLegacy) { + passthroughBlocks.add(Material.STATIONARY_WATER); } else { - Material mat = Material.getMaterial((Integer) i); - passthroughBlocks.add(mat); + passthroughBlocks.add(Material.getMaterial("BUBBLE_COLUMN")); } + } - } - if(!blockedByWater){ - passthroughBlocks.add(Material.WATER); - if (Settings.IsLegacy){ - passthroughBlocks.add(Material.STATIONARY_WATER); + if (data.containsKey("allowVerticalTakeoffAndLanding")) { + allowVerticalTakeoffAndLanding = (Boolean) data.get("allowVerticalTakeoffAndLanding"); } else { - passthroughBlocks.add(Material.getMaterial("BUBBLE_COLUMN")); + allowVerticalTakeoffAndLanding = true; } - } - if (data.containsKey("allowVerticalTakeoffAndLanding")) { - allowVerticalTakeoffAndLanding = (Boolean) data.get("allowVerticalTakeoffAndLanding"); - } else { - allowVerticalTakeoffAndLanding = true; - } - - if (data.containsKey("dynamicLagSpeedFactor")) { - dynamicLagSpeedFactor = doubleFromObject(data.get("dynamicLagSpeedFactor")); - } else { - dynamicLagSpeedFactor = 0d; - } - if (data.containsKey("dynamicFlyBlockSpeedFactor")) { - dynamicFlyBlockSpeedFactor = doubleFromObject(data.get("dynamicFlyBlockSpeedFactor")); - } else { - dynamicFlyBlockSpeedFactor = 0d; - } - dynamicFlyBlocks = new HashSet<>(); - if (data.containsKey("dynamicFlyBlocks")) { - ArrayList entries = (ArrayList) data.get("dynamicFlyBlocks"); - for (Object o : entries){ - if (o instanceof String){ - dynamicFlyBlocks.add(Material.getMaterial((String) o)); - } else { - dynamicFlyBlocks.add(Material.getMaterial((Integer) o)); + if (data.containsKey("dynamicLagSpeedFactor")) { + dynamicLagSpeedFactor = doubleFromObject(data.get("dynamicLagSpeedFactor")); + } else { + dynamicLagSpeedFactor = 0d; + } + if (data.containsKey("dynamicFlyBlockSpeedFactor")) { + dynamicFlyBlockSpeedFactor = doubleFromObject(data.get("dynamicFlyBlockSpeedFactor")); + } else { + dynamicFlyBlockSpeedFactor = 0d; + } + dynamicFlyBlocks = new HashSet<>(); + if (data.containsKey("dynamicFlyBlocks")) { + ArrayList entries = (ArrayList) data.get("dynamicFlyBlocks"); + for (Object o : entries) { + if (o instanceof String) { + dynamicFlyBlocks.add(Material.getMaterial((String) o)); + } else { + dynamicFlyBlocks.add(Material.getMaterial((Integer) o)); + } } } - } - chestPenalty = data.containsKey("chestPenalty") ? doubleFromObject(data.get("chestPenalty")) : 0d; - effectRange = data.containsKey("effectRange") ? integerFromObject(data.get("effectRange")) : 0; - potionEffectsToApply = data.containsKey("potionEffectsToApply") ? effectListFromObject(data.get("potionEffectsToApply")) : Collections.emptyMap(); - if (data.containsKey("entitiesToSpawn")){ - entitiesToSpawn = new HashSet<>(); - ArrayList entries = (ArrayList) data.get("entitiesToSpawn"); - for (Object o : entries){ - if (o instanceof String){ - entitiesToSpawn.add(EntityType.valueOf(((String) o).toUpperCase())); + chestPenalty = data.containsKey("chestPenalty") ? doubleFromObject(data.get("chestPenalty")) : 0d; + effectRange = data.containsKey("effectRange") ? integerFromObject(data.get("effectRange")) : 0; + potionEffectsToApply = data.containsKey("potionEffectsToApply") ? effectListFromObject(data.get("potionEffectsToApply")) : Collections.emptyMap(); + if (data.containsKey("entitiesToSpawn")) { + entitiesToSpawn = new HashSet<>(); + ArrayList entries = (ArrayList) data.get("entitiesToSpawn"); + for (Object o : entries) { + if (o instanceof String) { + entitiesToSpawn.add(EntityType.valueOf(((String) o).toUpperCase())); + } } + } else { + entitiesToSpawn = Collections.emptySet(); } - } else { - entitiesToSpawn = Collections.emptySet(); + maxEntitiesToBeSpawned = data.containsKey("maxEntitiesToBeSpawned") ? (int) data.get("maxEntitiesToBeSpawned") : 0; + } catch (Exception e){ + throw new CraftTypeException("Craft file " + f.getName() + " is malformed", e); } - maxEntitiesToBeSpawned = data.containsKey("maxEntitiesToBeSpawned") ? (int) data.get("maxEntitiesToBeSpawned") : 0; } private Integer integerFromObject(Object obj) { diff --git a/modules/v1_14_R1/src/main/java/net/countercraft/movecraft/compat/v1_14_R1/NextTickProvider.java b/modules/v1_14_R1/src/main/java/net/countercraft/movecraft/compat/v1_14_R1/NextTickProvider.java index a74ff7623..614c5fd4d 100644 --- a/modules/v1_14_R1/src/main/java/net/countercraft/movecraft/compat/v1_14_R1/NextTickProvider.java +++ b/modules/v1_14_R1/src/main/java/net/countercraft/movecraft/compat/v1_14_R1/NextTickProvider.java @@ -1,7 +1,6 @@ package net.countercraft.movecraft.compat.v1_14_R1; -import net.countercraft.movecraft.utils.Pair; - +import javafx.util.Pair; import net.minecraft.server.v1_14_R1.*; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -39,14 +38,14 @@ public NextTickListEntry getNextTick(@NotNull WorldServer world,@NotNull BlockPo if(!isRegistered(world)) registerWorld(world); Pair, Collection> listPair = tickMap.get(world); - for(Iterator iterator = listPair.getLeft().iterator(); iterator.hasNext();) { + for(Iterator iterator = listPair.getKey().iterator(); iterator.hasNext();) { NextTickListEntry listEntry = iterator.next(); if (position.equals(listEntry.a)) { iterator.remove(); return listEntry; } } - for(Iterator iterator = listPair.getRight().iterator(); iterator.hasNext();) { + for(Iterator iterator = listPair.getValue().iterator(); iterator.hasNext();) { NextTickListEntry listEntry = iterator.next(); if (position.equals(listEntry.a)) { iterator.remove(); diff --git a/modules/worldedit/WE6Utils/src/main/java/net/countercraft/movecraft/compat/we6/IMovecraftRepair.java b/modules/worldedit/WE6Utils/src/main/java/net/countercraft/movecraft/compat/we6/IMovecraftRepair.java index 7bc5f2269..7f9d75a6b 100644 --- a/modules/worldedit/WE6Utils/src/main/java/net/countercraft/movecraft/compat/we6/IMovecraftRepair.java +++ b/modules/worldedit/WE6Utils/src/main/java/net/countercraft/movecraft/compat/we6/IMovecraftRepair.java @@ -23,11 +23,15 @@ import com.sk89q.worldguard.protection.regions.ProtectedCuboidRegion; import com.sk89q.worldguard.protection.regions.ProtectedPolygonalRegion; import com.sk89q.worldguard.protection.regions.ProtectedRegion; +import javafx.util.Pair; import net.countercraft.movecraft.MovecraftLocation; import net.countercraft.movecraft.MovecraftRepair; import net.countercraft.movecraft.config.Settings; import net.countercraft.movecraft.craft.Craft; -import net.countercraft.movecraft.utils.*; +import net.countercraft.movecraft.utils.CollectionUtils; +import net.countercraft.movecraft.utils.HashHitBox; +import net.countercraft.movecraft.utils.HitBox; +import net.countercraft.movecraft.utils.MathUtils; import org.bukkit.*; import org.bukkit.block.Block; import org.bukkit.block.Dispenser; @@ -574,11 +578,11 @@ public Clipboard loadRegionRepairStateClipboard(String s, World world) { } @Override - public HashMap, Double> getMissingBlocks(String repairName) { + public HashMap, Double> getMissingBlocks(String repairName) { return missingBlocksMap.get(repairName); } - public ArrayDeque> getMissingBlockLocations(String repairName) { + public ArrayDeque> getMissingBlockLocations(String repairName) { return locMissingBlocksMap.get(repairName); } diff --git a/modules/worldedit/WE7Utils/src/main/java/net/countercraft/movecraft/compat/we7/IMovecraftRepair.java b/modules/worldedit/WE7Utils/src/main/java/net/countercraft/movecraft/compat/we7/IMovecraftRepair.java index 89da63b87..698aa0bd1 100644 --- a/modules/worldedit/WE7Utils/src/main/java/net/countercraft/movecraft/compat/we7/IMovecraftRepair.java +++ b/modules/worldedit/WE7Utils/src/main/java/net/countercraft/movecraft/compat/we7/IMovecraftRepair.java @@ -27,6 +27,7 @@ import com.sk89q.worldguard.protection.regions.ProtectedCuboidRegion; import com.sk89q.worldguard.protection.regions.ProtectedPolygonalRegion; import com.sk89q.worldguard.protection.regions.ProtectedRegion; +import javafx.util.Pair; import net.countercraft.movecraft.MovecraftLocation; import net.countercraft.movecraft.MovecraftRepair; import net.countercraft.movecraft.config.Settings; @@ -34,7 +35,6 @@ import net.countercraft.movecraft.utils.CollectionUtils; import net.countercraft.movecraft.utils.HashHitBox; import net.countercraft.movecraft.utils.HitBox; -import net.countercraft.movecraft.utils.Pair; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.World; @@ -54,7 +54,6 @@ public class IMovecraftRepair extends MovecraftRepair { private final HashMap>> locMissingBlocksMap = new HashMap<>(); - private final HashMap offsetMap = new HashMap<>(); private final HashMap numDiffBlocksMap = new HashMap<>(); private final HashMap, Double>> missingBlocksMap = new HashMap<>(); private final HashMap distanceMap = new HashMap<>(); @@ -84,8 +83,7 @@ public boolean saveCraftRepairState(Craft craft, Sign sign) { BlockArrayClipboard clipboard = new BlockArrayClipboard(region); clipboard.setOrigin(origin); Extent source = WorldEdit.getInstance().getEditSessionFactory().getEditSession(weWorld, -1); - Extent destination = clipboard; - ForwardExtentCopy copy = new ForwardExtentCopy(source, region, clipboard.getOrigin(), destination, clipboard.getOrigin()); + ForwardExtentCopy copy = new ForwardExtentCopy(source, region, clipboard.getOrigin(), clipboard, clipboard.getOrigin()); ExistingBlockMask mask = new ExistingBlockMask(source); copy.setSourceMask(mask); final HitBox outsideLocs = CollectionUtils.filter(solidBlockLocs(world, region), hitBox); @@ -168,7 +166,7 @@ public boolean saveRegionRepairState(World world, ProtectedRegion region) { @Override public Clipboard loadCraftRepairStateClipboard(Craft craft, Sign sign) { - String s = craft.getNotificationPlayer().getName() + sign.getLine(1); + String s = craft.getNotificationPlayer().getUniqueId().toString() + sign.getLine(1); File dataDirectory = new File(plugin.getDataFolder(), "RepairStates"); File playerDirectory = new File(dataDirectory, craft.getNotificationPlayer().getUniqueId().toString()); File file = new File(playerDirectory, sign.getLine(1) + ".schematic"); // The schematic file @@ -444,7 +442,6 @@ public HashMap, Double> getMissingBlocks(String s) { @Override public ArrayDeque> getMissingBlockLocations(String s) { - return locMissingBlocksMap.get(s); } From 14d9efbf2e120ab24e19d84b3d8c0c98748369dd Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Wed, 16 Oct 2019 23:10:06 +0200 Subject: [PATCH 060/304] Fixed a NullPointerException occuring when FAWE is used on 1.13 --- .../net/countercraft/movecraft/compat/we7/IMovecraftRepair.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/worldedit/WE7Utils/src/main/java/net/countercraft/movecraft/compat/we7/IMovecraftRepair.java b/modules/worldedit/WE7Utils/src/main/java/net/countercraft/movecraft/compat/we7/IMovecraftRepair.java index 698aa0bd1..3f3ba3ccd 100644 --- a/modules/worldedit/WE7Utils/src/main/java/net/countercraft/movecraft/compat/we7/IMovecraftRepair.java +++ b/modules/worldedit/WE7Utils/src/main/java/net/countercraft/movecraft/compat/we7/IMovecraftRepair.java @@ -206,7 +206,7 @@ public Clipboard loadCraftRepairStateClipboard(Craft craft, Sign sign) { Block bukkitBlock = sign.getWorld().getBlockAt(loc); boolean isImportant = true; - if (type.equals(Material.AIR) || type.equals(Material.CAVE_AIR) || type.equals(Material.VOID_AIR)){ + if (type == null || type.equals(Material.AIR) || type.equals(Material.CAVE_AIR) || type.equals(Material.VOID_AIR)){ isImportant = false; } boolean blockMissing = isImportant && type != bukkitBlock.getType(); From df5cdad053fa27ba4859baa8a2ca2b93d4efc793 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Thu, 17 Oct 2019 14:01:27 +0200 Subject: [PATCH 061/304] Added warning message on FAWE detection due to a critical bug in FAWE api in 1.13+ --- .../java/net/countercraft/movecraft/Movecraft.java | 14 ++++++++++++++ .../movecraft/compat/we7/IMovecraftRepair.java | 3 ++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java index 93a53e359..a99898576 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java @@ -123,6 +123,20 @@ public void onEnable() { logger.warning("Download at papermc.io/downloads"); logger.warning("======== Movecraft === Use Paper ======="); } + try { + Class.forName("com.boydti.fawe.Fawe"); + if (!Settings.IsLegacy){ + logger.warning("======= Movecraft === FAWE detected ========"); + logger.warning("FAWE has been detected on the server"); + logger.warning("the 1.13+ version of FAWE has critical"); + logger.warning("bugs that will break the repair system"); + logger.warning("Therefore, use WorldEdit instead or disable"); + logger.warning("repair functionality and assault"); + logger.warning("======= Movecraft === FAWE detected ========"); + } + } catch (ClassNotFoundException e) { + + } Settings.LOCALE = getConfig().getString("Locale"); diff --git a/modules/worldedit/WE7Utils/src/main/java/net/countercraft/movecraft/compat/we7/IMovecraftRepair.java b/modules/worldedit/WE7Utils/src/main/java/net/countercraft/movecraft/compat/we7/IMovecraftRepair.java index 3f3ba3ccd..b642f58ff 100644 --- a/modules/worldedit/WE7Utils/src/main/java/net/countercraft/movecraft/compat/we7/IMovecraftRepair.java +++ b/modules/worldedit/WE7Utils/src/main/java/net/countercraft/movecraft/compat/we7/IMovecraftRepair.java @@ -206,7 +206,7 @@ public Clipboard loadCraftRepairStateClipboard(Craft craft, Sign sign) { Block bukkitBlock = sign.getWorld().getBlockAt(loc); boolean isImportant = true; - if (type == null || type.equals(Material.AIR) || type.equals(Material.CAVE_AIR) || type.equals(Material.VOID_AIR)){ + if (type.equals(Material.AIR) || type.equals(Material.CAVE_AIR) || type.equals(Material.VOID_AIR)){ isImportant = false; } boolean blockMissing = isImportant && type != bukkitBlock.getType(); @@ -226,6 +226,7 @@ public Clipboard loadCraftRepairStateClipboard(Craft craft, Sign sign) { } if (blockMissing){ + Material typeToConsume = type; double qtyToConsume = 1.0; if (type.equals(Material.WATER)||type.equals(Material.LAVA)){ From 797365465c03a81fda9987931bd2527a139682b4 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Sat, 19 Oct 2019 20:51:27 +0200 Subject: [PATCH 062/304] Create FUNDING.yml --- .github/FUNDING.yml | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 .github/FUNDING.yml diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 000000000..1e8e7cee5 --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,12 @@ +# These are supported funding model platforms + +github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] +patreon: eirikh1996plugins +open_collective: # Replace with a single Open Collective username +ko_fi: # Replace with a single Ko-fi username +tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel +community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry +liberapay: # Replace with a single Liberapay username +issuehunt: # Replace with a single IssueHunt username +otechie: # Replace with a single Otechie username +custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] From cb09b08c24a76c7a76160341333a02b5c28522c5 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Fri, 25 Oct 2019 12:34:23 +0200 Subject: [PATCH 063/304] Fixed NullPointerException in repair sign as well as malformed example craft files for 1.13 and 1.14 --- .../net/countercraft/movecraft/Movecraft.java | 29 +++- .../async/translation/TranslationTask.java | 4 +- .../update/EntitySpawnUpdateCommand.java | 55 ------ ...eCommand.java => EntityUpdateCommand.java} | 8 +- .../movecraft/sign/RepairSign.java | 2 +- .../movecraft/sync/EntityProcessor.java | 8 +- .../localisation/movecraftlang_ar.properties | 85 --------- .../localisation/movecraftlang_en.properties | 2 +- .../resources/types/1_14/BigAirship.craft | 162 ++++++++--------- .../resources/types/1_14/BigSubAirship.craft | 164 +++++++++--------- .../src/main/resources/types/1_14/Ship.craft | 163 ++++++++--------- .../resources/types/1_14/SubAirship.craft | 163 ++++++++--------- .../main/resources/types/1_14/Submarine.craft | 163 ++++++++--------- .../main/resources/types/1_14/Turret.craft | 8 +- .../main/resources/types/1_14/airship.craft | 8 +- .../main/resources/types/1_14/airskiff.craft | 4 +- .../main/resources/types/1_14/elevator.craft | 135 +++++++------- .../src/main/resources/types/BigAirship.craft | 163 +++++++++-------- .../main/resources/types/BigSubAirship.craft | 163 +++++++++-------- .../src/main/resources/types/Ship.craft | 163 +++++++++-------- .../src/main/resources/types/SubAirship.craft | 163 +++++++++-------- .../src/main/resources/types/Submarine.craft | 163 +++++++++-------- .../src/main/resources/types/Turret.craft | 9 +- .../src/main/resources/types/airship.craft | 10 +- .../src/main/resources/types/airskiff.craft | 6 +- .../src/main/resources/types/elevator.craft | 6 +- .../movecraft/events/CraftExplodeEvent.java | 14 +- 27 files changed, 955 insertions(+), 1068 deletions(-) delete mode 100644 modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/EntitySpawnUpdateCommand.java rename modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/{EntityMoveUpdateCommand.java => EntityUpdateCommand.java} (90%) delete mode 100644 modules/Movecraft/src/main/resources/localisation/movecraftlang_ar.properties diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java index a99898576..5ed995827 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java @@ -145,13 +145,25 @@ public void onEnable() { Settings.Debug = getConfig().getBoolean("Debug", false); Settings.DisableSpillProtection = getConfig().getBoolean("DisableSpillProtection", false); // if the PilotTool is specified in the config_legacy.yml file, use it - if (getConfig().getString("PilotTool") != null || getConfig().getString("PilotTool") != "") { - logger.log(Level.INFO, I18nSupport.getInternationalisedString("Startup - Recognized Pilot Tool") - + getConfig().getString("PilotTool")); - Settings.PilotTool = Material.getMaterial(getConfig().getString("PilotTool")); + Object pt = getConfig().get("PilotTool"); + final Material pilotTool; + if (pt instanceof Integer){ + int toolID = (int) pt; + if (!Settings.IsLegacy) { + throw new IllegalArgumentException("Numerical block IDs are not supported by this version"); + } + pilotTool = LegacyUtils.getMaterial(toolID); + } else if (pt instanceof String){ + String str = (String) pt; + str = str.toUpperCase(); + pilotTool = Material.getMaterial(str); } else { - logger.log(Level.INFO, I18nSupport.getInternationalisedString("Startup - No Pilot Tool")); + pilotTool = null; } + Settings.PilotTool = pilotTool != null ? pilotTool : Material.STICK; + logger.info(pilotTool != null ?I18nSupport.getInternationalisedString("Startup - Recognized Pilot Tool") + + pilotTool.name().toLowerCase() : + I18nSupport.getInternationalisedString("Startup - No Pilot Tool")); //Switch to interfaces try { @@ -274,8 +286,13 @@ public void onEnable() { type = LegacyUtils.getMaterial(Integer.parseInt(typ)); } catch (NumberFormatException e){ type = Material.getMaterial(typ); + } catch (NoSuchMethodError e){ + logger.warning(I18nSupport.getInternationalisedString("Startup - Numerical ID found") + " DisableShadowBlocks: " + typ); + type = null; + } + if (type != null) { + Settings.DisableShadowBlocks.add(type); } - Settings.DisableShadowBlocks.add(type); } Settings.RepairMaxPercent = getConfig().getDouble("RepairMaxPercent", 50.0); Settings.ForbiddenRemoteSigns = new HashSet<>(getConfig().getStringList("ForbiddenRemoteSigns")); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java index 4401c4509..d273429be 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java @@ -320,9 +320,9 @@ public void run() { } //END OF: if (blockObstructed) } for (UpdateCommand update : getUpdates()){ - if (!(update instanceof EntityMoveUpdateCommand)) + if (!(update instanceof EntityUpdateCommand)) continue; - EntityMoveUpdateCommand eUp = (EntityMoveUpdateCommand) update; + EntityUpdateCommand eUp = (EntityUpdateCommand) update; eUp.setY(dy); } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/EntitySpawnUpdateCommand.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/EntitySpawnUpdateCommand.java deleted file mode 100644 index de2d7a88a..000000000 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/EntitySpawnUpdateCommand.java +++ /dev/null @@ -1,55 +0,0 @@ -package net.countercraft.movecraft.mapUpdater.update; - -import net.countercraft.movecraft.utils.MathUtils; -import org.bukkit.Location; -import org.bukkit.entity.EntityType; -import org.jetbrains.annotations.NotNull; - -import java.util.ArrayDeque; -import java.util.Set; - -public class EntitySpawnUpdateCommand extends UpdateCommand { - @NotNull private final int spawnRange; - @NotNull private final int maxEntities; - @NotNull private final Location loc; - @NotNull private final Set entitiesToSpawn; - - public EntitySpawnUpdateCommand(@NotNull int spawnRange, @NotNull int maxEntities, @NotNull Location loc, @NotNull Set entitiesToSpawn){ - this.spawnRange = spawnRange; - this.maxEntities = maxEntities; - this.loc = loc; - this.entitiesToSpawn = entitiesToSpawn; - } - @Override - public void doUpdate() { - //Get locations where entities can be spawned - @NotNull ArrayDeque spawnLocs = new ArrayDeque<>(); - int minX = loc.getBlockX() - spawnRange; - int minZ = loc.getBlockZ() - spawnRange; - int maxX = loc.getBlockX() + spawnRange; - int maxZ = loc.getBlockZ() + spawnRange; - for (int i = 1 ; i <= maxEntities; i++){ - final int randX = MathUtils.randomInteger(minX,maxX); - final int randZ = MathUtils.randomInteger(minZ,maxZ); - final int y =loc.getBlockY(); - @NotNull final Location spawnLoc = new Location(loc.getWorld(),randX,y,randZ); - for (int dy = 0 ; dy <= 255 - y; dy++){ - if (loc.getWorld().getBlockAt(randX,y + dy, randZ).getType().name().endsWith("AIR")){ - spawnLoc.add(0,dy,0); - break; - } - - } - spawnLocs.addLast(spawnLoc); - } - //Spawn entities at the determined locations - while (!spawnLocs.isEmpty()){ - for (EntityType entity : entitiesToSpawn){ - @NotNull Location poll = spawnLocs.pollFirst(); - if (poll == null) - continue; - loc.getWorld().spawnEntity(poll,entity); - } - } - } -} diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/EntityMoveUpdateCommand.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/EntityUpdateCommand.java similarity index 90% rename from modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/EntityMoveUpdateCommand.java rename to modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/EntityUpdateCommand.java index d1a479436..a05ea8ba9 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/EntityMoveUpdateCommand.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/EntityUpdateCommand.java @@ -28,7 +28,7 @@ /** * Class that stores the data about a single blocks changes to the map in an unspecified world. The world is retrieved contextually from the submitting craft. */ -public class EntityMoveUpdateCommand extends UpdateCommand { +public class EntityUpdateCommand extends UpdateCommand { private final Entity entity; private final double x; private double y; @@ -36,7 +36,7 @@ public class EntityMoveUpdateCommand extends UpdateCommand { private final float yaw; private final float pitch; - public EntityMoveUpdateCommand(Entity entity, double x, double y, double z, float yaw, float pitch) { + public EntityUpdateCommand(Entity entity, double x, double y, double z, float yaw, float pitch) { this.entity = entity; this.x = x; this.y = y; @@ -71,10 +71,10 @@ public int hashCode() { @Override public boolean equals(Object obj) { - if(!(obj instanceof EntityMoveUpdateCommand)){ + if(!(obj instanceof EntityUpdateCommand)){ return false; } - EntityMoveUpdateCommand other = (EntityMoveUpdateCommand) obj; + EntityUpdateCommand other = (EntityUpdateCommand) obj; return this.x == other.x && this.y == other.y && this.z == other.z && diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RepairSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RepairSign.java index 298884ead..5e0bfd510 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RepairSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RepairSign.java @@ -136,7 +136,7 @@ private void signRightClick(PlayerInteractEvent event){ long numDifferentBlocks = movecraftRepair.getNumDiffBlocks(repairName); boolean secondClick = false; if (!playerInteractTimeMap.isEmpty()) { - if (System.currentTimeMillis() - playerInteractTimeMap.get(p.getUniqueId()) < 5000) { + if (playerInteractTimeMap.get(p.getUniqueId()) != null && System.currentTimeMillis() - playerInteractTimeMap.get(p.getUniqueId()) < 5000) { secondClick = true; } } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sync/EntityProcessor.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sync/EntityProcessor.java index 81cc9429c..92a37421e 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sync/EntityProcessor.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sync/EntityProcessor.java @@ -3,7 +3,7 @@ import net.countercraft.movecraft.MovecraftLocation; import net.countercraft.movecraft.Rotation; import net.countercraft.movecraft.craft.Craft; -import net.countercraft.movecraft.mapUpdater.update.EntityMoveUpdateCommand; +import net.countercraft.movecraft.mapUpdater.update.EntityUpdateCommand; import net.countercraft.movecraft.mapUpdater.update.UpdateCommand; import net.countercraft.movecraft.utils.HashHitBox; import net.countercraft.movecraft.utils.MathUtils; @@ -35,10 +35,10 @@ public static Set translateEntities(Craft craft, int dx, int dy, if(craft.getSinking()){ continue; } - EntityMoveUpdateCommand eUp = new EntityMoveUpdateCommand(entity, dx, dy, dz, 0, 0); + EntityUpdateCommand eUp = new EntityUpdateCommand(entity, dx, dy, dz, 0, 0); updateCmds.add(eUp); } else if (!craft.getType().getOnlyMovePlayers() || entity.getType() == EntityType.PRIMED_TNT) { - EntityMoveUpdateCommand eUp = new EntityMoveUpdateCommand(entity, dx, dy, dz, 0, 0); + EntityUpdateCommand eUp = new EntityUpdateCommand(entity, dx, dy, dz, 0, 0); updateCmds.add(eUp); } } @@ -68,7 +68,7 @@ public static Set rotateEntities(Craft craft, MovecraftLocation o double[] rotatedCoords = MathUtils.rotateVecNoRound(rotation, adjustedPLoc.getX(), adjustedPLoc.getZ()); float newYaw = rotation == Rotation.CLOCKWISE ? 90F : -90F; - EntityMoveUpdateCommand eUp = new EntityMoveUpdateCommand(entity, rotatedCoords[0] + tOP.getX() - entity.getLocation().getX(), 0, rotatedCoords[1] + tOP.getZ() - entity.getLocation().getZ(), newYaw, 0); + EntityUpdateCommand eUp = new EntityUpdateCommand(entity, rotatedCoords[0] + tOP.getX() - entity.getLocation().getX(), 0, rotatedCoords[1] + tOP.getZ() - entity.getLocation().getZ(), newYaw, 0); updates.add(eUp); } } diff --git a/modules/Movecraft/src/main/resources/localisation/movecraftlang_ar.properties b/modules/Movecraft/src/main/resources/localisation/movecraftlang_ar.properties deleted file mode 100644 index ff50c49eb..000000000 --- a/modules/Movecraft/src/main/resources/localisation/movecraftlang_ar.properties +++ /dev/null @@ -1,85 +0,0 @@ -# -# This file is part of Movecraft. -# -# Movecraft is free software: you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published by -# the Free Software Foundation, either version 3 of the License, or -# (at your option) any later version. -# -# Movecraft is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with Movecraft. If not, see . -# - -# Message returned when a craft is too small. One Integer which is the minimum size of that Craft Type -Detection\ -\ Craft\ too\ small=%d ??? ????????\! ???? ??????? ????? ??????. ???? ?????? ???? ?????? ?? -Detection\ -\ Craft\ too\ large=%d ??? ???\! ???? ??????? ????? ????. ???? ?????? ???? ????? ?? -Detection\ -\ Forbidden\ block\ found=??? ???\! ?? ?????? ??? ???? ?????? ??? ???????. -Detection\ -\ Failed\ -\ Already\ commanding\ a\ craft=You are already commanding a craft\! -Detection\ -\ Failed\ Craft\ is\ already\ being\ controlled=The craft is already being controlled\! -Detection\ -\ Successfully\ piloted\ craft=Succesfully piloted craft\! -Rotation\ -\ Craft\ is\ obstructed=Craft is obstructed -Rotation\ -\ Craft\ Collision=Craft Collision -Translation\ -\ Failed\ Craft\ hit\ height\ limit=Craft has hit the height limit -Translation\ -\ Failed\ Craft\ is\ obstructed=The craft cannot move because its path is obstructed\! -Translation\ -\ Failed\ Craft\ out\ of\ fuel=The craft is out of fuel\! -Translation\ -\ Failed\ Craft\ hit\ minimum\ height\ limit=Craft has hit the minimum height limit -Translation\\=-\\ Failed\\ Craft\\ over\\ water=This craft cannot move over water\\! -Translation\ -\ Craft\ collision=Craft Collision -Internal\ -\ Error\ -\ Proccessor\ thread\ encountered\ an\ error=Async Task generated an exception. -Startup\ -\ Number\ of\ craft\ files\ loaded=Loaded %d Craft files -Startup\ -\ Error\ parsing\ CraftType\ file=***ERROR PARSING CRAFT FILE FROM DIRECTORY \: %s*** -Startup\ -\ Error\ -\ Reload\ error=Movecraft is incompatible with the reload command. Movecraft has shut down and will restart when the server is restarted. -Startup\ -\ Error\ -\ Disable\ warning\ for\ reload=If you wish to use the reload command and Movecraft, you may disable this check inside the config.yml by setting 'safeReload \: false' -Startup\ -\ Enabled\ message=[V %S] has been enabled. -Item\ -\ Storage\ Crate\ name=Storage Crate -Player-\ Craft\ has\ been\ released=Your craft has been released\! -Player-\ Craft\ should\ sink\ but\ PVP\ is\ not\ allowed\ in\ this\ WorldGuard\ region=Player- Craft should sink but PVP is not allowed in this WorldGuard region -Player-\ Craft\ is\ sinking=Your craft has taken too much damage and is sinking\! ABANDON SHIP\! -Player-\ Error\ -\ You\ do\ not\ have\ a\ craft\ to\ release!=You do not have a craft to release\! -Player\ -\ Error\ -\ Already\ piloting\ craft=You are already commanding a craft\! -MCStats\ -\ \:(\ -\ Admin\ has\ opted\ out=You have selected to opt out of mcstats.org data submission. The developer of Movecraft would greatly appreciate you submitting your data. -MCStats\ -\ Thank\ you\ message=Submitted statistics to mcstats.org succesfully. Thank you for your support. -MCStats\ -\ Error\ -\ Unable\ to\ upload\ stats=Unable to upload statistics to mcstats.org. Please check your network connection. -Release\ -\ Player\ has\ left\ craft=You have left your craft\! You have 15 seconds to return to it or it will be automatically released. -Release\ -\ Craft\ has\ been\ released\ message=You have released your craft. -Release\ -\ Player\ has\ released\ a\ craft\ console=Player %s has released a craft of type %s with size %d at coordinates \: %d x , %d z -Detection\ -\ Success\ -\ Log\ Output=Player %s piloted a craft of type %s with size %d at location\: %d x, %d z -Not\ enough\ flyblock=Not enough flyblock -Too\ much\ flyblock=Too much flyblock -Detection\ -\ ERROR\:\ Double\ chest\ found=Detection failed\! ERROR \: Double chest found -Detection\ -\ Failed\ -\ Water\ contact\ required\ but\ not\ found=Detection failed\: Water contact required but not found -Rotation\ -\ Player\ is\ not\ permitted\ to\ build\ in\ this\ WorldGuard\ region=Rotation - Player is not permitted to build in this WorldGuard region -Translation\ -\ Failed\ Player\ is\ not\ permitted\ to\ build\ in\ this\ WorldGuard\ region=Translation Failed - Player is not permitted to build in this WorldGuard region -Parent\ Craft\ is\ busy=Parent Craft is busy -Insufficient\ Permissions=Insufficient Permissions -ERROR\:\ Remote\ Sign\ must\ be\ a\ part\ of\ a\ piloted\ craft\!=ERROR\: Remote Sign must be a part of a piloted craft\! -ERROR\:\ Remote\ Signs\ not\ allowed\ on\ this\ craft\!=ERROR\: Remote Signs not allowed on this craft\! -ERROR\:\ Could\ not\ find\ target\ sign\!=ERROR\: Could not find target sign\! -Entering\ Direct\ Control\ Mode=Entering Direct Control Mode -Leaving\ Direct\ Control\ Mode=Leaving Direct Control Mode -Craft\ is\ too\ big\ to\ check\ its\ borders\.\ Make\ sure\ this\ area\ is\ safe\ to\ release\ your\ craft\ in\.=Craft is too big to check its borders. Make sure this area is safe to release your craft in. -You\ have\ left\ your\ craft\.\ You\ may\ return\ to\ your\ craft\ by\ typing\ \/manoverboard\ any\ time\ before\ the\ timeout\ expires=You have left your craft. If you have fallen out of your craft, you man type /manoverboard before the timout expires and be returned to it. -WARNING\!\ There\ are\ blocks\ near\ your\ craft\ that\ may\ merge\ with\ the\ \craft\ "=WARNING\! There are blocks near your craft that may merge with the craft -You\ can\ only\ create\ a\ Crew\:\ sign\ for\ yourself=You can only create a Crew\: sign for yourself -Repair\ functionality\ is\ disabled\ or\ WorldEdit\ was\ not\ detected=Repair functionality is disabled or WorldEdit was not detected -You\ must\ be\ piloting\ a\ craft=You must be piloting a craft -Could\ not\ save\ file=Could not save file -State\ saved=State saved -REPAIR\ STATE\ NOT\ FOUND=REPAIR STATE NOT FOUND -Repairs\ underway=Repairs underway -Repairs\ complete\.\ You\ may\ now\ pilot\ the\ craft=Repairs complete. You may now pilot the craft -You\ do\ not\ have\ enough\ money=You do not have enough money -Need\ more\ of\ material=Need more of material -Towny\ -\ Detection\ Failed=Detection Failed - You are not permitted to pilot a craft on this plot in the town -Towny\ -\ Translation\ Failed=Translation Failed - You are not permitted to move a craft on this plot in the town -Towny\ -\ Rotation\ Failed=Rotation Failed - You are not permitted to rotate a craft on this plot in the town -Towny\ -\ Sinking\ a\ craft\ is\ not\ allowed\ in\ this\ town\ plot=Sinking a craft is not allowed in this town plot\! -WGCustomFlags\ -\ Translation\ Failed=Translation Failed - You are not permitted to move a craft in this WorldGuard region -WGCustomFlags\ -\ Rotation\ Failed=Rotation Failed - You are not permitterd to rotate a craft in this WorldGuard region -WGCustomFlags\ -\ Detection\ Failed=Detection Failed - You are not permitted to pilot a craft in this WorldGuard region -WGCustomFlags\ -\ Sinking\ a\ craft\ is\ not\ allowed\ in\ this\ WorldGuard\ region=Sinking is not allowed in this WorldGuard region\! diff --git a/modules/Movecraft/src/main/resources/localisation/movecraftlang_en.properties b/modules/Movecraft/src/main/resources/localisation/movecraftlang_en.properties index 53be715d8..29a0876b3 100644 --- a/modules/Movecraft/src/main/resources/localisation/movecraftlang_en.properties +++ b/modules/Movecraft/src/main/resources/localisation/movecraftlang_en.properties @@ -176,7 +176,7 @@ Siege\ -\ Saturday=Saturday Siege\ -\ Sunday=Sunday Startup\ -\ Number\ of\ craft\ files\ loaded=Loaded %d Craft files Startup\ -\ No\ Crafts\ Found=NO CRAFT FILES FOUND\! -Startup\ -\ Error\ parsing\ CraftType\ file=***ERROR PARSING CRAFT FILE FROM DIRECTORY \: %s*** +Startup\ -\ Numerical\ ID\ found=Numerical IDs are not supported by the current server version, but was found under Startup\ -\ Error\ -\ Reload\ error=Movecraft is incompatible with the reload command. Movecraft has shut down and will restart when the server is restarted. Startup\ -\ Error\ -\ Disable\ warning\ for\ reload=If you wish to use the reload command and Movecraft, you may disable this check inside the config.yml by setting 'safeReload \: false' Startup\ -\ Enabled\ message=[V %S] has been enabled. diff --git a/modules/Movecraft/src/main/resources/types/1_14/BigAirship.craft b/modules/Movecraft/src/main/resources/types/1_14/BigAirship.craft index d5dcef13f..d84e2655c 100644 --- a/modules/Movecraft/src/main/resources/types/1_14/BigAirship.craft +++ b/modules/Movecraft/src/main/resources/types/1_14/BigAirship.craft @@ -2,88 +2,88 @@ name: BigAirship maxSize: 20000 minSize: 10000 allowedBlocks: - - crafting_table - ALL_WOOD - - WATER - - LAVA - - ALL_LOG - - all_planks - - GLASS - - LAPIS_BLOCK - - DISPENSER - - NOTE_BLOCK - - ALL_BED - - sticky_piston - - piston - - all_wool - - GOLD_BLOCK - - IRON_BLOCK - - all_slab - - BOOKSHELF - - TORCH - - FIRE - - oak_stairs - - birch_stairs - - jungle_stairs - - spruce_stairs - - stone_brick_stairs - - quartz_stairs - - nether_brick_stairs - - chest - - redstone_wire - - diamond_block - - nether_brick_stairs - - furnace - - all_sign - - ladder - - all_door - - lever - - all_pressure_plate - - redstone_torch - - redstone_wall_torch - - all_button - - clay - - all_fence - - netherrack - - glowstone - - cake - - repeater - - all_stained_glass - - all_trapdoor - - all_stone_bricks - - iron_bars - - glass_pane - - all_fence_gate - - nether_brick - - enchantment_table - - brewing_stand - - cauldron - - end_stone - - dragon_egg - - redstone_lamp - - ender chest - - TRIPWIRE_HOOK - - EMERALD_BLOCK - - BEACON - - cobblestone_wall - - mossy_cobblestone_wall - - FLOWER_POT - - SKULL - - all_ANVIL - - TRAPPED_CHEST - - COMPARATOR - - daylight_detector - - REDSTONE_BLOCK - - HOPPER - - all_QUARTZ_BLOCK - - all_rail - - DROPPER - - ALL_TERRACOTTA - - ALL_STAINED_GLASS_PANE - - SLIME_BLOCK - - ALL_CARPET - - COAL_BLOCK - - END_STONE_BRICKS + - WATER + - LAVA + - ALL_LOG + - all_planks + - GLASS + - LAPIS_BLOCK + - DISPENSER + - NOTE_BLOCK + - ALL_BED + - sticky_piston + - piston_head + - all_wool + - GOLD_BLOCK + - IRON_BLOCK + - all_slab + - BOOKSHELF + - TORCH + - FIRE + - oak_stairs + - birch_stairs + - jungle_stairs + - spruce_stairs + - stone_brick_stairs + - quartz_stairs + - nether_brick_stairs + - chest + - redstone_wire + - diamond_block + - nether_brick_stairs + - furnace + - all_sign + - ladder + - all_door + - lever + - all_pressure_plate + - redstone_torch + - redstone_wall_torch + - all_button + - clay + - all_fence + - netherrack + - glowstone + - cake + - repeater + - all_stained_glass + - all_trapdoor + - all_stone_bricks + - iron_bars + - glass_pane + - all_fence_gate + - nether_brick + - enchanting_table + - brewing_stand + - cauldron + - end_stone + - dragon_egg + - redstone_lamp + - ender_chest + - TRIPWIRE_HOOK + - EMERALD_BLOCK + - BEACON + - cobblestone_wall + - mossy_cobblestone_wall + - FLOWER_POT + - SKULL + - all_ANVIL + - TRAPPED_CHEST + - COMPARATOR + - daylight_detector + - REDSTONE_BLOCK + - HOPPER + - all_QUARTZ_BLOCK + - all_rail + - DROPPER + - ALL_TERRACOTTA + - ALL_STAINED_GLASS_PANE + - SLIME_BLOCK + - ALL_CARPET + - COAL_BLOCK + - END_STONE_BRICKS + - barrel canCruise: true rotateAtMidpoint: true blockRemoteRotate: true diff --git a/modules/Movecraft/src/main/resources/types/1_14/BigSubAirship.craft b/modules/Movecraft/src/main/resources/types/1_14/BigSubAirship.craft index e0a43c22b..9843f02af 100644 --- a/modules/Movecraft/src/main/resources/types/1_14/BigSubAirship.craft +++ b/modules/Movecraft/src/main/resources/types/1_14/BigSubAirship.craft @@ -2,88 +2,88 @@ name: BigSubAirship maxSize: 20000 minSize: 10000 allowedBlocks: - - crafting_table - - ALL_WOOD - - WATER - - LAVA - - ALL_LOG - - all_planks - - GLASS - - LAPIS_BLOCK - - DISPENSER - - NOTE_BLOCK - - ALL_BED - - sticky_piston - - piston - - all_wool - - GOLD_BLOCK - - IRON_BLOCK - - all_slab - - BOOKSHELF - - TORCH - - FIRE - - oak_stairs - - birch_stairs - - jungle_stairs - - spruce_stairs - - stone_brick_stairs - - quartz_stairs - - nether_brick_stairs - - chest - - redstone_wire - - diamond_block - - nether_brick_stairs - - furnace - - all_sign - - ladder - - all_door - - lever - - all_pressure_plate - - redstone_torch - - redstone_wall_torch - - all_button - - clay - - all_fence - - netherrack - - glowstone - - cake - - repeater - - all_stained_glass - - all_trapdoor - - all_stone_bricks - - iron_bars - - glass_pane - - all_fence_gate - - nether_brick - - enchantment_table - - brewing_stand - - cauldron - - end_stone - - dragon_egg - - redstone_lamp - - ender chest - - TRIPWIRE_HOOK - - EMERALD_BLOCK - - BEACON - - cobblestone_wall - - mossy_cobblestone_wall - - FLOWER_POT - - SKULL - - all_ANVIL - - TRAPPED_CHEST - - COMPARATOR - - daylight_detector - - REDSTONE_BLOCK - - HOPPER - - all_QUARTZ_BLOCK - - all_rail - - DROPPER - - ALL_TERRACOTTA - - ALL_STAINED_GLASS_PANE - - SLIME_BLOCK - - ALL_CARPET - - COAL_BLOCK - - END_STONE_BRICKS +- ALL_WOOD + - WATER + - LAVA + - ALL_LOG + - all_planks + - GLASS + - LAPIS_BLOCK + - DISPENSER + - NOTE_BLOCK + - ALL_BED + - sticky_piston + - piston_head + - all_wool + - GOLD_BLOCK + - IRON_BLOCK + - all_slab + - BOOKSHELF + - TORCH + - FIRE + - oak_stairs + - birch_stairs + - jungle_stairs + - spruce_stairs + - stone_brick_stairs + - quartz_stairs + - nether_brick_stairs + - chest + - redstone_wire + - diamond_block + - nether_brick_stairs + - furnace + - all_sign + - ladder + - all_door + - lever + - all_pressure_plate + - redstone_torch + - redstone_wall_torch + - all_button + - clay + - all_fence + - netherrack + - glowstone + - cake + - repeater + - all_stained_glass + - all_trapdoor + - all_stone_bricks + - iron_bars + - glass_pane + - all_fence_gate + - nether_brick + - enchanting_table + - brewing_stand + - cauldron + - end_stone + - dragon_egg + - redstone_lamp + - ender_chest + - TRIPWIRE_HOOK + - EMERALD_BLOCK + - BEACON + - cobblestone_wall + - mossy_cobblestone_wall + - FLOWER_POT + - SKULL + - all_ANVIL + - TRAPPED_CHEST + - COMPARATOR + - daylight_detector + - REDSTONE_BLOCK + - HOPPER + - all_QUARTZ_BLOCK + - all_rail + - DROPPER + - ALL_TERRACOTTA + - ALL_STAINED_GLASS_PANE + - SLIME_BLOCK + - ALL_CARPET + - COAL_BLOCK + - END_STONE_BRICKS + - barrel canCruise: true rotateAtMidpoint: true blockRemoteRotate: true diff --git a/modules/Movecraft/src/main/resources/types/1_14/Ship.craft b/modules/Movecraft/src/main/resources/types/1_14/Ship.craft index b4411d0d9..48daef3b0 100644 --- a/modules/Movecraft/src/main/resources/types/1_14/Ship.craft +++ b/modules/Movecraft/src/main/resources/types/1_14/Ship.craft @@ -2,87 +2,88 @@ name: Ship maxSize: 100000 minSize: 10 allowedBlocks: - - crafting_table - - ALL_WOOD - - LAVA - - ALL_LOG - - all_planks - - GLASS - - LAPIS_BLOCK - - DISPENSER - - NOTE_BLOCK - - ALL_BED - - sticky_piston - - piston - - all_wool - - GOLD_BLOCK - - IRON_BLOCK - - all_slab - - BOOKSHELF - - TORCH - - FIRE - - oak_stairs - - birch_stairs - - jungle_stairs - - spruce_stairs - - stone_brick_stairs - - quartz_stairs - - nether_brick_stairs - - chest - - redstone_wire - - diamond_block - - nether_brick_stairs - - furnace - - all_sign - - ladder - - all_door - - lever - - all_pressure_plate - - redstone_torch - - redstone_wall_torch - - all_button - - clay - - all_fence - - netherrack - - glowstone - - cake - - repeater - - all_stained_glass - - all_trapdoor - - all_stone_bricks - - iron_bars - - glass_pane - - all_fence_gate - - nether_brick - - enchantment_table - - brewing_stand - - cauldron - - end_stone - - dragon_egg - - redstone_lamp - - ender chest - - TRIPWIRE_HOOK - - EMERALD_BLOCK - - BEACON - - cobblestone_wall - - mossy_cobblestone_wall - - FLOWER_POT - - SKULL - - all_ANVIL - - TRAPPED_CHEST - - COMPARATOR - - daylight_detector - - REDSTONE_BLOCK - - HOPPER - - all_QUARTZ_BLOCK - - all_rail - - DROPPER - - ALL_TERRACOTTA - - ALL_STAINED_GLASS_PANE - - SLIME_BLOCK - - ALL_CARPET - - COAL_BLOCK - - END_STONE_BRICKS +- ALL_WOOD + - WATER + - LAVA + - ALL_LOG + - all_planks + - GLASS + - LAPIS_BLOCK + - DISPENSER + - NOTE_BLOCK + - ALL_BED + - sticky_piston + - piston_head + - all_wool + - GOLD_BLOCK + - IRON_BLOCK + - all_slab + - BOOKSHELF + - TORCH + - FIRE + - oak_stairs + - birch_stairs + - jungle_stairs + - spruce_stairs + - stone_brick_stairs + - quartz_stairs + - nether_brick_stairs + - chest + - redstone_wire + - diamond_block + - nether_brick_stairs + - furnace + - all_sign + - ladder + - all_door + - lever + - all_pressure_plate + - redstone_torch + - redstone_wall_torch + - all_button + - clay + - all_fence + - netherrack + - glowstone + - cake + - repeater + - all_stained_glass + - all_trapdoor + - all_stone_bricks + - iron_bars + - glass_pane + - all_fence_gate + - nether_brick + - enchanting_table + - brewing_stand + - cauldron + - end_stone + - dragon_egg + - redstone_lamp + - ender_chest + - TRIPWIRE_HOOK + - EMERALD_BLOCK + - BEACON + - cobblestone_wall + - mossy_cobblestone_wall + - FLOWER_POT + - SKULL + - all_ANVIL + - TRAPPED_CHEST + - COMPARATOR + - daylight_detector + - REDSTONE_BLOCK + - HOPPER + - all_QUARTZ_BLOCK + - all_rail + - DROPPER + - ALL_TERRACOTTA + - ALL_STAINED_GLASS_PANE + - SLIME_BLOCK + - ALL_CARPET + - COAL_BLOCK + - END_STONE_BRICKS + - barrel canCruise: true cruiseSkipBlocks: 4 canFly: false diff --git a/modules/Movecraft/src/main/resources/types/1_14/SubAirship.craft b/modules/Movecraft/src/main/resources/types/1_14/SubAirship.craft index 2035a1f07..d9fc519d3 100644 --- a/modules/Movecraft/src/main/resources/types/1_14/SubAirship.craft +++ b/modules/Movecraft/src/main/resources/types/1_14/SubAirship.craft @@ -2,87 +2,88 @@ name: SubAirship maxSize: 5000 minSize: 1000 allowedBlocks: - - crafting_table - - ALL_WOOD - - LAVA - - ALL_LOG - - all_planks - - GLASS - - LAPIS_BLOCK - - DISPENSER - - NOTE_BLOCK - - ALL_BED - - sticky_piston - - piston - - all_wool - - GOLD_BLOCK - - IRON_BLOCK - - all_slab - - BOOKSHELF - - TORCH - - FIRE - - oak_stairs - - birch_stairs - - jungle_stairs - - spruce_stairs - - stone_brick_stairs - - quartz_stairs - - nether_brick_stairs - - chest - - redstone_wire - - diamond_block - - nether_brick_stairs - - furnace - - all_sign - - ladder - - all_door - - lever - - all_pressure_plate - - redstone_torch - - redstone_wall_torch - - all_button - - clay - - all_fence - - netherrack - - glowstone - - cake - - repeater - - all_stained_glass - - all_trapdoor - - all_stone_bricks - - iron_bars - - glass_pane - - all_fence_gate - - nether_brick - - enchantment_table - - brewing_stand - - cauldron - - end_stone - - dragon_egg - - redstone_lamp - - ender chest - - TRIPWIRE_HOOK - - EMERALD_BLOCK - - BEACON - - cobblestone_wall - - mossy_cobblestone_wall - - FLOWER_POT - - SKULL - - all_ANVIL - - TRAPPED_CHEST - - COMPARATOR - - daylight_detector - - REDSTONE_BLOCK - - HOPPER - - all_QUARTZ_BLOCK - - all_rail - - DROPPER - - ALL_TERRACOTTA - - ALL_STAINED_GLASS_PANE - - SLIME_BLOCK - - ALL_CARPET - - COAL_BLOCK - - END_STONE_BRICKS +- ALL_WOOD + - WATER + - LAVA + - ALL_LOG + - all_planks + - GLASS + - LAPIS_BLOCK + - DISPENSER + - NOTE_BLOCK + - ALL_BED + - sticky_piston + - piston_head + - all_wool + - GOLD_BLOCK + - IRON_BLOCK + - all_slab + - BOOKSHELF + - TORCH + - FIRE + - oak_stairs + - birch_stairs + - jungle_stairs + - spruce_stairs + - stone_brick_stairs + - quartz_stairs + - nether_brick_stairs + - chest + - redstone_wire + - diamond_block + - nether_brick_stairs + - furnace + - all_sign + - ladder + - all_door + - lever + - all_pressure_plate + - redstone_torch + - redstone_wall_torch + - all_button + - clay + - all_fence + - netherrack + - glowstone + - cake + - repeater + - all_stained_glass + - all_trapdoor + - all_stone_bricks + - iron_bars + - glass_pane + - all_fence_gate + - nether_brick + - enchanting_table + - brewing_stand + - cauldron + - end_stone + - dragon_egg + - redstone_lamp + - ender_chest + - TRIPWIRE_HOOK + - EMERALD_BLOCK + - BEACON + - cobblestone_wall + - mossy_cobblestone_wall + - FLOWER_POT + - SKULL + - all_ANVIL + - TRAPPED_CHEST + - COMPARATOR + - daylight_detector + - REDSTONE_BLOCK + - HOPPER + - all_QUARTZ_BLOCK + - all_rail + - DROPPER + - ALL_TERRACOTTA + - ALL_STAINED_GLASS_PANE + - SLIME_BLOCK + - ALL_CARPET + - COAL_BLOCK + - END_STONE_BRICKS + - barrel canCruise: true rotateAtMidpoint: true cruiseSkipBlocks: 4 diff --git a/modules/Movecraft/src/main/resources/types/1_14/Submarine.craft b/modules/Movecraft/src/main/resources/types/1_14/Submarine.craft index df77f0a13..4b788847a 100644 --- a/modules/Movecraft/src/main/resources/types/1_14/Submarine.craft +++ b/modules/Movecraft/src/main/resources/types/1_14/Submarine.craft @@ -2,87 +2,88 @@ name: Submarine maxSize: 100000 minSize: 10 allowedBlocks: - - crafting_table - - ALL_WOOD - - LAVA - - ALL_LOG - - all_planks - - GLASS - - LAPIS_BLOCK - - DISPENSER - - NOTE_BLOCK - - ALL_BED - - sticky_piston - - piston - - all_wool - - GOLD_BLOCK - - IRON_BLOCK - - all_slab - - BOOKSHELF - - TORCH - - FIRE - - oak_stairs - - birch_stairs - - jungle_stairs - - spruce_stairs - - stone_brick_stairs - - quartz_stairs - - nether_brick_stairs - - chest - - redstone_wire - - diamond_block - - nether_brick_stairs - - furnace - - all_sign - - ladder - - all_door - - lever - - all_pressure_plate - - redstone_torch - - redstone_wall_torch - - all_button - - clay - - all_fence - - netherrack - - glowstone - - cake - - repeater - - all_stained_glass - - all_trapdoor - - all_stone_bricks - - iron_bars - - glass_pane - - all_fence_gate - - nether_brick - - enchantment_table - - brewing_stand - - cauldron - - end_stone - - dragon_egg - - redstone_lamp - - ender chest - - TRIPWIRE_HOOK - - EMERALD_BLOCK - - BEACON - - cobblestone_wall - - mossy_cobblestone_wall - - FLOWER_POT - - SKULL - - all_ANVIL - - TRAPPED_CHEST - - COMPARATOR - - daylight_detector - - REDSTONE_BLOCK - - HOPPER - - all_QUARTZ_BLOCK - - all_rail - - DROPPER - - ALL_TERRACOTTA - - ALL_STAINED_GLASS_PANE - - SLIME_BLOCK - - ALL_CARPET - - COAL_BLOCK - - END_STONE_BRICKS +- ALL_WOOD + - WATER + - LAVA + - ALL_LOG + - all_planks + - GLASS + - LAPIS_BLOCK + - DISPENSER + - NOTE_BLOCK + - ALL_BED + - sticky_piston + - piston_head + - all_wool + - GOLD_BLOCK + - IRON_BLOCK + - all_slab + - BOOKSHELF + - TORCH + - FIRE + - oak_stairs + - birch_stairs + - jungle_stairs + - spruce_stairs + - stone_brick_stairs + - quartz_stairs + - nether_brick_stairs + - chest + - redstone_wire + - diamond_block + - nether_brick_stairs + - furnace + - all_sign + - ladder + - all_door + - lever + - all_pressure_plate + - redstone_torch + - redstone_wall_torch + - all_button + - clay + - all_fence + - netherrack + - glowstone + - cake + - repeater + - all_stained_glass + - all_trapdoor + - all_stone_bricks + - iron_bars + - glass_pane + - all_fence_gate + - nether_brick + - enchanting_table + - brewing_stand + - cauldron + - end_stone + - dragon_egg + - redstone_lamp + - ender_chest + - TRIPWIRE_HOOK + - EMERALD_BLOCK + - BEACON + - cobblestone_wall + - mossy_cobblestone_wall + - FLOWER_POT + - SKULL + - all_ANVIL + - TRAPPED_CHEST + - COMPARATOR + - daylight_detector + - REDSTONE_BLOCK + - HOPPER + - all_QUARTZ_BLOCK + - all_rail + - DROPPER + - ALL_TERRACOTTA + - ALL_STAINED_GLASS_PANE + - SLIME_BLOCK + - ALL_CARPET + - COAL_BLOCK + - END_STONE_BRICKS + - barrel canCruise: true cruiseSkipBlocks: 4 canFly: false diff --git a/modules/Movecraft/src/main/resources/types/1_14/Turret.craft b/modules/Movecraft/src/main/resources/types/1_14/Turret.craft index 3fc3c1262..df8ecccb4 100644 --- a/modules/Movecraft/src/main/resources/types/1_14/Turret.craft +++ b/modules/Movecraft/src/main/resources/types/1_14/Turret.craft @@ -37,19 +37,19 @@ allowedBlocks: - netherrack - glowstone - cake - - redstone_repeater + - repeater - all_stained_glass - all_trapdoor - all_stone_bricks - iron_bars - glass_pane - all_fence_gate - - enchantment_table + - enchanting_table - brewing_stand - cauldron - dragon_egg - redstone_lamp - - ender chest + - ender_chest - TRIPWIRE_HOOK - EMERALD_BLOCK - BEACON @@ -57,7 +57,7 @@ allowedBlocks: - SKULL - all_ANVIL - TRAPPED_CHEST - - REDSTONE_COMPARATOR + - COMPARATOR - daylight_detector - REDSTONE_BLOCK - HOPPER diff --git a/modules/Movecraft/src/main/resources/types/1_14/airship.craft b/modules/Movecraft/src/main/resources/types/1_14/airship.craft index 462501fec..9239c82f9 100644 --- a/modules/Movecraft/src/main/resources/types/1_14/airship.craft +++ b/modules/Movecraft/src/main/resources/types/1_14/airship.craft @@ -46,7 +46,7 @@ allowedBlocks: - netherrack - glowstone - cake - - redstone_repeater + - repeater - all_stained_glass - all_trapdoor - all_stone_bricks @@ -54,13 +54,13 @@ allowedBlocks: - glass_pane - all_fence_gate - nether_brick - - enchantment_table + - enchanting_table - brewing_stand - cauldron - end_stone - dragon_egg - redstone_lamp - - ender chest + - ender_chest - TRIPWIRE_HOOK - EMERALD_BLOCK - BEACON @@ -70,7 +70,7 @@ allowedBlocks: - SKULL - all_ANVIL - TRAPPED_CHEST - - REDSTONE_COMPARATOR + - COMPARATOR - daylight_detector - REDSTONE_BLOCK - HOPPER diff --git a/modules/Movecraft/src/main/resources/types/1_14/airskiff.craft b/modules/Movecraft/src/main/resources/types/1_14/airskiff.craft index b2dbd621f..d530a91b8 100644 --- a/modules/Movecraft/src/main/resources/types/1_14/airskiff.craft +++ b/modules/Movecraft/src/main/resources/types/1_14/airskiff.craft @@ -45,12 +45,12 @@ allowedBlocks: - iron_bars - glass_pane - all_fence_gate - - enchantment_table + - enchanting_table - brewing_stand - cauldron - dragon_egg - redstone_lamp - - ender chest + - ender_chest - TRIPWIRE_HOOK - EMERALD_BLOCK - BEACON diff --git a/modules/Movecraft/src/main/resources/types/1_14/elevator.craft b/modules/Movecraft/src/main/resources/types/1_14/elevator.craft index e4a3ab218..9cd7b8fe3 100644 --- a/modules/Movecraft/src/main/resources/types/1_14/elevator.craft +++ b/modules/Movecraft/src/main/resources/types/1_14/elevator.craft @@ -3,73 +3,74 @@ maxSize: 1000 minSize: 10 allowedBlocks: - ALL_WOOD - - WATER - - LAVA - - ALL_LOG - - all_planks - - GLASS - - DISPENSER - - NOTE_BLOCK - - ALL_BED - - sticky_piston - - piston_head - - all_wool - - all_slab - - BOOKSHELF - - TORCH - - FIRE - - oak_stairs - - birch_stairs - - jungle_stairs - - spruce_stairs - - chest - - redstone_wire - - nether_brick_stairs - - furnace - - all_sign - - ladder - - all_door - - lever - - all_pressure_plate - - redstone_torch - - redstone_wall_torch - - all_button - - all_fence - - netherrack - - glowstone - - cake - - repeater - - all_stained_glass - - all_trapdoor - - all_stone_bricks - - iron_bars - - glass_pane - - all_fence_gate - - enchantment_table - - brewing_stand - - cauldron - - dragon_egg - - redstone_lamp - - ender chest - - TRIPWIRE_HOOK - - EMERALD_BLOCK - - BEACON - - FLOWER_POT - - SKULL - - all_ANVIL - - TRAPPED_CHEST - - COMPARATOR - - daylight_detector - - REDSTONE_BLOCK - - HOPPER - - all_QUARTZ_BLOCK - - all_rail - - DROPPER - - ALL_STAINED_GLASS_PANE - - SLIME_BLOCK - - ALL_CARPET - - COAL_BLOCK - - END_STONE_BRICKS + - WATER + - LAVA + - ALL_LOG + - all_planks + - GLASS + - DISPENSER + - NOTE_BLOCK + - ALL_BED + - sticky_piston + - piston_head + - all_wool + - all_slab + - BOOKSHELF + - TORCH + - FIRE + - oak_stairs + - birch_stairs + - jungle_stairs + - spruce_stairs + - chest + - redstone_wire + - nether_brick_stairs + - furnace + - all_sign + - ladder + - all_door + - lever + - all_pressure_plate + - redstone_torch + - redstone_wall_torch + - all_button + - all_fence + - netherrack + - glowstone + - cake + - repeater + - all_stained_glass + - all_trapdoor + - all_stone_bricks + - iron_bars + - glass_pane + - all_fence_gate + - enchanting_table + - brewing_stand + - cauldron + - dragon_egg + - redstone_lamp + - ender_chest + - TRIPWIRE_HOOK + - EMERALD_BLOCK + - BEACON + - FLOWER_POT + - SKULL + - all_ANVIL + - TRAPPED_CHEST + - COMPARATOR + - daylight_detector + - REDSTONE_BLOCK + - HOPPER + - all_QUARTZ_BLOCK + - all_rail + - DROPPER + - ALL_STAINED_GLASS_PANE + - SLIME_BLOCK + - ALL_CARPET + - COAL_BLOCK + - END_STONE_BRICKS + - barrel canFly: true canCruise: false collisionExplosion: 0.0 diff --git a/modules/Movecraft/src/main/resources/types/BigAirship.craft b/modules/Movecraft/src/main/resources/types/BigAirship.craft index d5dcef13f..8f5efe037 100644 --- a/modules/Movecraft/src/main/resources/types/BigAirship.craft +++ b/modules/Movecraft/src/main/resources/types/BigAirship.craft @@ -2,88 +2,87 @@ name: BigAirship maxSize: 20000 minSize: 10000 allowedBlocks: - - crafting_table - - ALL_WOOD - - WATER - - LAVA - - ALL_LOG - - all_planks - - GLASS - - LAPIS_BLOCK - - DISPENSER - - NOTE_BLOCK - - ALL_BED - - sticky_piston - - piston - - all_wool - - GOLD_BLOCK - - IRON_BLOCK - - all_slab - - BOOKSHELF - - TORCH - - FIRE - - oak_stairs - - birch_stairs - - jungle_stairs - - spruce_stairs - - stone_brick_stairs - - quartz_stairs - - nether_brick_stairs - - chest - - redstone_wire - - diamond_block - - nether_brick_stairs - - furnace - - all_sign - - ladder - - all_door - - lever - - all_pressure_plate - - redstone_torch - - redstone_wall_torch - - all_button - - clay - - all_fence - - netherrack - - glowstone - - cake - - repeater - - all_stained_glass - - all_trapdoor - - all_stone_bricks - - iron_bars - - glass_pane - - all_fence_gate - - nether_brick - - enchantment_table - - brewing_stand - - cauldron - - end_stone - - dragon_egg - - redstone_lamp - - ender chest - - TRIPWIRE_HOOK - - EMERALD_BLOCK - - BEACON - - cobblestone_wall - - mossy_cobblestone_wall - - FLOWER_POT - - SKULL - - all_ANVIL - - TRAPPED_CHEST - - COMPARATOR - - daylight_detector - - REDSTONE_BLOCK - - HOPPER - - all_QUARTZ_BLOCK - - all_rail - - DROPPER - - ALL_TERRACOTTA - - ALL_STAINED_GLASS_PANE - - SLIME_BLOCK - - ALL_CARPET - - COAL_BLOCK - - END_STONE_BRICKS +- ALL_WOOD + - WATER + - LAVA + - ALL_LOG + - all_planks + - GLASS + - LAPIS_BLOCK + - DISPENSER + - NOTE_BLOCK + - ALL_BED + - sticky_piston + - piston_head + - all_wool + - GOLD_BLOCK + - IRON_BLOCK + - all_slab + - BOOKSHELF + - TORCH + - FIRE + - oak_stairs + - birch_stairs + - jungle_stairs + - spruce_stairs + - stone_brick_stairs + - quartz_stairs + - nether_brick_stairs + - chest + - redstone_wire + - diamond_block + - nether_brick_stairs + - furnace + - all_sign + - ladder + - all_door + - lever + - all_pressure_plate + - redstone_torch + - redstone_wall_torch + - all_button + - clay + - all_fence + - netherrack + - glowstone + - cake + - repeater + - all_stained_glass + - all_trapdoor + - all_stone_bricks + - iron_bars + - glass_pane + - all_fence_gate + - nether_brick + - enchanting_table + - brewing_stand + - cauldron + - end_stone + - dragon_egg + - redstone_lamp + - ender_chest + - TRIPWIRE_HOOK + - EMERALD_BLOCK + - BEACON + - cobblestone_wall + - mossy_cobblestone_wall + - FLOWER_POT + - SKULL + - all_ANVIL + - TRAPPED_CHEST + - COMPARATOR + - daylight_detector + - REDSTONE_BLOCK + - HOPPER + - all_QUARTZ_BLOCK + - all_rail + - DROPPER + - ALL_TERRACOTTA + - ALL_STAINED_GLASS_PANE + - SLIME_BLOCK + - ALL_CARPET + - COAL_BLOCK + - END_STONE_BRICKS canCruise: true rotateAtMidpoint: true blockRemoteRotate: true diff --git a/modules/Movecraft/src/main/resources/types/BigSubAirship.craft b/modules/Movecraft/src/main/resources/types/BigSubAirship.craft index e0a43c22b..7b35acac0 100644 --- a/modules/Movecraft/src/main/resources/types/BigSubAirship.craft +++ b/modules/Movecraft/src/main/resources/types/BigSubAirship.craft @@ -2,88 +2,87 @@ name: BigSubAirship maxSize: 20000 minSize: 10000 allowedBlocks: - - crafting_table - - ALL_WOOD - - WATER - - LAVA - - ALL_LOG - - all_planks - - GLASS - - LAPIS_BLOCK - - DISPENSER - - NOTE_BLOCK - - ALL_BED - - sticky_piston - - piston - - all_wool - - GOLD_BLOCK - - IRON_BLOCK - - all_slab - - BOOKSHELF - - TORCH - - FIRE - - oak_stairs - - birch_stairs - - jungle_stairs - - spruce_stairs - - stone_brick_stairs - - quartz_stairs - - nether_brick_stairs - - chest - - redstone_wire - - diamond_block - - nether_brick_stairs - - furnace - - all_sign - - ladder - - all_door - - lever - - all_pressure_plate - - redstone_torch - - redstone_wall_torch - - all_button - - clay - - all_fence - - netherrack - - glowstone - - cake - - repeater - - all_stained_glass - - all_trapdoor - - all_stone_bricks - - iron_bars - - glass_pane - - all_fence_gate - - nether_brick - - enchantment_table - - brewing_stand - - cauldron - - end_stone - - dragon_egg - - redstone_lamp - - ender chest - - TRIPWIRE_HOOK - - EMERALD_BLOCK - - BEACON - - cobblestone_wall - - mossy_cobblestone_wall - - FLOWER_POT - - SKULL - - all_ANVIL - - TRAPPED_CHEST - - COMPARATOR - - daylight_detector - - REDSTONE_BLOCK - - HOPPER - - all_QUARTZ_BLOCK - - all_rail - - DROPPER - - ALL_TERRACOTTA - - ALL_STAINED_GLASS_PANE - - SLIME_BLOCK - - ALL_CARPET - - COAL_BLOCK - - END_STONE_BRICKS +- ALL_WOOD + - WATER + - LAVA + - ALL_LOG + - all_planks + - GLASS + - LAPIS_BLOCK + - DISPENSER + - NOTE_BLOCK + - ALL_BED + - sticky_piston + - piston_head + - all_wool + - GOLD_BLOCK + - IRON_BLOCK + - all_slab + - BOOKSHELF + - TORCH + - FIRE + - oak_stairs + - birch_stairs + - jungle_stairs + - spruce_stairs + - stone_brick_stairs + - quartz_stairs + - nether_brick_stairs + - chest + - redstone_wire + - diamond_block + - nether_brick_stairs + - furnace + - all_sign + - ladder + - all_door + - lever + - all_pressure_plate + - redstone_torch + - redstone_wall_torch + - all_button + - clay + - all_fence + - netherrack + - glowstone + - cake + - repeater + - all_stained_glass + - all_trapdoor + - all_stone_bricks + - iron_bars + - glass_pane + - all_fence_gate + - nether_brick + - enchanting_table + - brewing_stand + - cauldron + - end_stone + - dragon_egg + - redstone_lamp + - ender_chest + - TRIPWIRE_HOOK + - EMERALD_BLOCK + - BEACON + - cobblestone_wall + - mossy_cobblestone_wall + - FLOWER_POT + - SKULL + - all_ANVIL + - TRAPPED_CHEST + - COMPARATOR + - daylight_detector + - REDSTONE_BLOCK + - HOPPER + - all_QUARTZ_BLOCK + - all_rail + - DROPPER + - ALL_TERRACOTTA + - ALL_STAINED_GLASS_PANE + - SLIME_BLOCK + - ALL_CARPET + - COAL_BLOCK + - END_STONE_BRICKS canCruise: true rotateAtMidpoint: true blockRemoteRotate: true diff --git a/modules/Movecraft/src/main/resources/types/Ship.craft b/modules/Movecraft/src/main/resources/types/Ship.craft index 4b7d96703..d8b05d6f4 100644 --- a/modules/Movecraft/src/main/resources/types/Ship.craft +++ b/modules/Movecraft/src/main/resources/types/Ship.craft @@ -2,88 +2,87 @@ name: Ship maxSize: 100000 minSize: 10 allowedBlocks: - - crafting_table - - ALL_WOOD - - WATER - - LAVA - - ALL_LOG - - all_planks - - GLASS - - LAPIS_BLOCK - - DISPENSER - - NOTE_BLOCK - - ALL_BED - - sticky_piston - - piston - - all_wool - - GOLD_BLOCK - - IRON_BLOCK - - all_slab - - BOOKSHELF - - TORCH - - FIRE - - oak_stairs - - birch_stairs - - jungle_stairs - - spruce_stairs - - stone_brick_stairs - - quartz_stairs - - nether_brick_stairs - - chest - - redstone_wire - - diamond_block - - nether_brick_stairs - - furnace - - all_sign - - ladder - - all_door - - lever - - all_pressure_plate - - redstone_torch - - redstone_wall_torch - - all_button - - clay - - all_fence - - netherrack - - glowstone - - cake - - repeater - - all_stained_glass - - all_trapdoor - - all_stone_bricks - - iron_bars - - glass_pane - - all_fence_gate - - nether_brick - - enchantment_table - - brewing_stand - - cauldron - - end_stone - - dragon_egg - - redstone_lamp - - ender chest - - TRIPWIRE_HOOK - - EMERALD_BLOCK - - BEACON - - cobblestone_wall - - mossy_cobblestone_wall - - FLOWER_POT - - SKULL - - all_ANVIL - - TRAPPED_CHEST - - COMPARATOR - - daylight_detector - - REDSTONE_BLOCK - - HOPPER - - all_QUARTZ_BLOCK - - all_rail - - DROPPER - - ALL_TERRACOTTA - - ALL_STAINED_GLASS_PANE - - SLIME_BLOCK - - ALL_CARPET - - COAL_BLOCK - - END_STONE_BRICKS +- ALL_WOOD + - WATER + - LAVA + - ALL_LOG + - all_planks + - GLASS + - LAPIS_BLOCK + - DISPENSER + - NOTE_BLOCK + - ALL_BED + - sticky_piston + - piston_head + - all_wool + - GOLD_BLOCK + - IRON_BLOCK + - all_slab + - BOOKSHELF + - TORCH + - FIRE + - oak_stairs + - birch_stairs + - jungle_stairs + - spruce_stairs + - stone_brick_stairs + - quartz_stairs + - nether_brick_stairs + - chest + - redstone_wire + - diamond_block + - nether_brick_stairs + - furnace + - all_sign + - ladder + - all_door + - lever + - all_pressure_plate + - redstone_torch + - redstone_wall_torch + - all_button + - clay + - all_fence + - netherrack + - glowstone + - cake + - repeater + - all_stained_glass + - all_trapdoor + - all_stone_bricks + - iron_bars + - glass_pane + - all_fence_gate + - nether_brick + - enchanting_table + - brewing_stand + - cauldron + - end_stone + - dragon_egg + - redstone_lamp + - ender_chest + - TRIPWIRE_HOOK + - EMERALD_BLOCK + - BEACON + - cobblestone_wall + - mossy_cobblestone_wall + - FLOWER_POT + - SKULL + - all_ANVIL + - TRAPPED_CHEST + - COMPARATOR + - daylight_detector + - REDSTONE_BLOCK + - HOPPER + - all_QUARTZ_BLOCK + - all_rail + - DROPPER + - ALL_TERRACOTTA + - ALL_STAINED_GLASS_PANE + - SLIME_BLOCK + - ALL_CARPET + - COAL_BLOCK + - END_STONE_BRICKS canCruise: true cruiseSkipBlocks: 4 canFly: false diff --git a/modules/Movecraft/src/main/resources/types/SubAirship.craft b/modules/Movecraft/src/main/resources/types/SubAirship.craft index 6e04449ed..0e63057a1 100644 --- a/modules/Movecraft/src/main/resources/types/SubAirship.craft +++ b/modules/Movecraft/src/main/resources/types/SubAirship.craft @@ -2,88 +2,87 @@ name: SubAirship maxSize: 5000 minSize: 1000 allowedBlocks: - - crafting_table - - ALL_WOOD - - WATER - - LAVA - - ALL_LOG - - all_planks - - GLASS - - LAPIS_BLOCK - - DISPENSER - - NOTE_BLOCK - - ALL_BED - - sticky_piston - - piston - - all_wool - - GOLD_BLOCK - - IRON_BLOCK - - all_slab - - BOOKSHELF - - TORCH - - FIRE - - oak_stairs - - birch_stairs - - jungle_stairs - - spruce_stairs - - stone_brick_stairs - - quartz_stairs - - nether_brick_stairs - - chest - - redstone_wire - - diamond_block - - nether_brick_stairs - - furnace - - all_sign - - ladder - - all_door - - lever - - all_pressure_plate - - redstone_torch - - redstone_wall_torch - - all_button - - clay - - all_fence - - netherrack - - glowstone - - cake - - repeater - - all_stained_glass - - all_trapdoor - - all_stone_bricks - - iron_bars - - glass_pane - - all_fence_gate - - nether_brick - - enchantment_table - - brewing_stand - - cauldron - - end_stone - - dragon_egg - - redstone_lamp - - ender chest - - TRIPWIRE_HOOK - - EMERALD_BLOCK - - BEACON - - cobblestone_wall - - mossy_cobblestone_wall - - FLOWER_POT - - SKULL - - all_ANVIL - - TRAPPED_CHEST - - COMPARATOR - - daylight_detector - - REDSTONE_BLOCK - - HOPPER - - all_QUARTZ_BLOCK - - all_rail - - DROPPER - - ALL_TERRACOTTA - - ALL_STAINED_GLASS_PANE - - SLIME_BLOCK - - ALL_CARPET - - COAL_BLOCK - - END_STONE_BRICKS +- ALL_WOOD + - WATER + - LAVA + - ALL_LOG + - all_planks + - GLASS + - LAPIS_BLOCK + - DISPENSER + - NOTE_BLOCK + - ALL_BED + - sticky_piston + - piston_head + - all_wool + - GOLD_BLOCK + - IRON_BLOCK + - all_slab + - BOOKSHELF + - TORCH + - FIRE + - oak_stairs + - birch_stairs + - jungle_stairs + - spruce_stairs + - stone_brick_stairs + - quartz_stairs + - nether_brick_stairs + - chest + - redstone_wire + - diamond_block + - nether_brick_stairs + - furnace + - all_sign + - ladder + - all_door + - lever + - all_pressure_plate + - redstone_torch + - redstone_wall_torch + - all_button + - clay + - all_fence + - netherrack + - glowstone + - cake + - repeater + - all_stained_glass + - all_trapdoor + - all_stone_bricks + - iron_bars + - glass_pane + - all_fence_gate + - nether_brick + - enchanting_table + - brewing_stand + - cauldron + - end_stone + - dragon_egg + - redstone_lamp + - ender_chest + - TRIPWIRE_HOOK + - EMERALD_BLOCK + - BEACON + - cobblestone_wall + - mossy_cobblestone_wall + - FLOWER_POT + - SKULL + - all_ANVIL + - TRAPPED_CHEST + - COMPARATOR + - daylight_detector + - REDSTONE_BLOCK + - HOPPER + - all_QUARTZ_BLOCK + - all_rail + - DROPPER + - ALL_TERRACOTTA + - ALL_STAINED_GLASS_PANE + - SLIME_BLOCK + - ALL_CARPET + - COAL_BLOCK + - END_STONE_BRICKS canCruise: true rotateAtMidpoint: true cruiseSkipBlocks: 4 diff --git a/modules/Movecraft/src/main/resources/types/Submarine.craft b/modules/Movecraft/src/main/resources/types/Submarine.craft index c5f9d073a..6d838eff4 100644 --- a/modules/Movecraft/src/main/resources/types/Submarine.craft +++ b/modules/Movecraft/src/main/resources/types/Submarine.craft @@ -2,88 +2,87 @@ name: Submarine maxSize: 100000 minSize: 10 allowedBlocks: - - crafting_table - - ALL_WOOD - - WATER - - LAVA - - ALL_LOG - - all_planks - - GLASS - - LAPIS_BLOCK - - DISPENSER - - NOTE_BLOCK - - ALL_BED - - sticky_piston - - piston - - all_wool - - GOLD_BLOCK - - IRON_BLOCK - - all_slab - - BOOKSHELF - - TORCH - - FIRE - - oak_stairs - - birch_stairs - - jungle_stairs - - spruce_stairs - - stone_brick_stairs - - quartz_stairs - - nether_brick_stairs - - chest - - redstone_wire - - diamond_block - - nether_brick_stairs - - furnace - - all_sign - - ladder - - all_door - - lever - - all_pressure_plate - - redstone_torch - - redstone_wall_torch - - all_button - - clay - - all_fence - - netherrack - - glowstone - - cake - - repeater - - all_stained_glass - - all_trapdoor - - all_stone_bricks - - iron_bars - - glass_pane - - all_fence_gate - - nether_brick - - enchantment_table - - brewing_stand - - cauldron - - end_stone - - dragon_egg - - redstone_lamp - - ender chest - - TRIPWIRE_HOOK - - EMERALD_BLOCK - - BEACON - - cobblestone_wall - - mossy_cobblestone_wall - - FLOWER_POT - - SKULL - - all_ANVIL - - TRAPPED_CHEST - - COMPARATOR - - daylight_detector - - REDSTONE_BLOCK - - HOPPER - - all_QUARTZ_BLOCK - - all_rail - - DROPPER - - ALL_TERRACOTTA - - ALL_STAINED_GLASS_PANE - - SLIME_BLOCK - - ALL_CARPET - - COAL_BLOCK - - END_STONE_BRICKS +- ALL_WOOD + - WATER + - LAVA + - ALL_LOG + - all_planks + - GLASS + - LAPIS_BLOCK + - DISPENSER + - NOTE_BLOCK + - ALL_BED + - sticky_piston + - piston_head + - all_wool + - GOLD_BLOCK + - IRON_BLOCK + - all_slab + - BOOKSHELF + - TORCH + - FIRE + - oak_stairs + - birch_stairs + - jungle_stairs + - spruce_stairs + - stone_brick_stairs + - quartz_stairs + - nether_brick_stairs + - chest + - redstone_wire + - diamond_block + - nether_brick_stairs + - furnace + - all_sign + - ladder + - all_door + - lever + - all_pressure_plate + - redstone_torch + - redstone_wall_torch + - all_button + - clay + - all_fence + - netherrack + - glowstone + - cake + - repeater + - all_stained_glass + - all_trapdoor + - all_stone_bricks + - iron_bars + - glass_pane + - all_fence_gate + - nether_brick + - enchanting_table + - brewing_stand + - cauldron + - end_stone + - dragon_egg + - redstone_lamp + - ender_chest + - TRIPWIRE_HOOK + - EMERALD_BLOCK + - BEACON + - cobblestone_wall + - mossy_cobblestone_wall + - FLOWER_POT + - SKULL + - all_ANVIL + - TRAPPED_CHEST + - COMPARATOR + - daylight_detector + - REDSTONE_BLOCK + - HOPPER + - all_QUARTZ_BLOCK + - all_rail + - DROPPER + - ALL_TERRACOTTA + - ALL_STAINED_GLASS_PANE + - SLIME_BLOCK + - ALL_CARPET + - COAL_BLOCK + - END_STONE_BRICKS canCruise: true cruiseSkipBlocks: 4 canFly: false diff --git a/modules/Movecraft/src/main/resources/types/Turret.craft b/modules/Movecraft/src/main/resources/types/Turret.craft index 2fc12a8f2..77a64930a 100644 --- a/modules/Movecraft/src/main/resources/types/Turret.craft +++ b/modules/Movecraft/src/main/resources/types/Turret.craft @@ -37,19 +37,19 @@ allowedBlocks: - netherrack - glowstone - cake - - redstone_repeater + - repeater - all_stained_glass - all_trapdoor - all_stone_bricks - iron_bars - glass_pane - all_fence_gate - - enchantment_table + - enchanting_table - brewing_stand - cauldron - dragon_egg - redstone_lamp - - ender chest + - ender_chest - TRIPWIRE_HOOK - EMERALD_BLOCK - BEACON @@ -57,7 +57,7 @@ allowedBlocks: - SKULL - all_ANVIL - TRAPPED_CHEST - - REDSTONE_COMPARATOR + - COMPARATOR - daylight_detector - REDSTONE_BLOCK - HOPPER @@ -71,7 +71,6 @@ allowedBlocks: - ALL_CARPET - COAL_BLOCK - END_STONE_BRICKS - forbiddenBlocks: - PISTON_HEAD diff --git a/modules/Movecraft/src/main/resources/types/airship.craft b/modules/Movecraft/src/main/resources/types/airship.craft index 57c7c9e7d..9f34ec484 100644 --- a/modules/Movecraft/src/main/resources/types/airship.craft +++ b/modules/Movecraft/src/main/resources/types/airship.craft @@ -2,7 +2,7 @@ name: Airship maxSize: 5000 minSize: 1000 allowedBlocks: - - ALL_WOOD +- ALL_WOOD - WATER - LAVA - ALL_LOG @@ -46,7 +46,7 @@ allowedBlocks: - netherrack - glowstone - cake - - redstone_repeater + - repeater - all_stained_glass - all_trapdoor - all_stone_bricks @@ -54,13 +54,13 @@ allowedBlocks: - glass_pane - all_fence_gate - nether_brick - - enchantment_table + - enchanting_table - brewing_stand - cauldron - end_stone - dragon_egg - redstone_lamp - - ender chest + - ender_chest - TRIPWIRE_HOOK - EMERALD_BLOCK - BEACON @@ -70,7 +70,7 @@ allowedBlocks: - SKULL - all_ANVIL - TRAPPED_CHEST - - REDSTONE_COMPARATOR + - COMPARATOR - daylight_detector - REDSTONE_BLOCK - HOPPER diff --git a/modules/Movecraft/src/main/resources/types/airskiff.craft b/modules/Movecraft/src/main/resources/types/airskiff.craft index 57f424278..955fcc468 100644 --- a/modules/Movecraft/src/main/resources/types/airskiff.craft +++ b/modules/Movecraft/src/main/resources/types/airskiff.craft @@ -2,7 +2,7 @@ name: Airskiff maxSize: 80 minSize: 10 allowedBlocks: - - ALL_WOOD +- ALL_WOOD - WATER - LAVA - ALL_LOG @@ -45,12 +45,12 @@ allowedBlocks: - iron_bars - glass_pane - all_fence_gate - - enchantment_table + - enchanting_table - brewing_stand - cauldron - dragon_egg - redstone_lamp - - ender chest + - ender_chest - TRIPWIRE_HOOK - EMERALD_BLOCK - BEACON diff --git a/modules/Movecraft/src/main/resources/types/elevator.craft b/modules/Movecraft/src/main/resources/types/elevator.craft index e4a3ab218..97934e00a 100644 --- a/modules/Movecraft/src/main/resources/types/elevator.craft +++ b/modules/Movecraft/src/main/resources/types/elevator.craft @@ -2,7 +2,7 @@ name: elevator maxSize: 1000 minSize: 10 allowedBlocks: - - ALL_WOOD +- ALL_WOOD - WATER - LAVA - ALL_LOG @@ -45,12 +45,12 @@ allowedBlocks: - iron_bars - glass_pane - all_fence_gate - - enchantment_table + - enchanting_table - brewing_stand - cauldron - dragon_egg - redstone_lamp - - ender chest + - ender_chest - TRIPWIRE_HOOK - EMERALD_BLOCK - BEACON diff --git a/modules/api/src/main/java/net/countercraft/movecraft/events/CraftExplodeEvent.java b/modules/api/src/main/java/net/countercraft/movecraft/events/CraftExplodeEvent.java index 7cb5accd3..bece993d4 100644 --- a/modules/api/src/main/java/net/countercraft/movecraft/events/CraftExplodeEvent.java +++ b/modules/api/src/main/java/net/countercraft/movecraft/events/CraftExplodeEvent.java @@ -2,13 +2,15 @@ import net.countercraft.movecraft.craft.Craft; import org.bukkit.block.Block; +import org.bukkit.event.Cancellable; import org.bukkit.event.HandlerList; import org.jetbrains.annotations.NotNull; import java.util.Set; -public class CraftExplodeEvent extends CraftEvent { +public class CraftExplodeEvent extends CraftEvent implements Cancellable { private static HandlerList handlerList = new HandlerList(); + private boolean cancelled = false; private double explosionForce; private Set destroyedBlocks; public CraftExplodeEvent(@NotNull Craft craft) { @@ -24,4 +26,14 @@ public HandlerList getHandlers() { public static HandlerList getHandlerList(){ return handlerList; } + + @Override + public boolean isCancelled() { + return cancelled; + } + + @Override + public void setCancelled(boolean cancelled) { + this.cancelled = cancelled; + } } From 6b3384e620dbbd66605292d40585c7e95b330db0 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Fri, 1 Nov 2019 15:37:47 +0100 Subject: [PATCH 064/304] Fixes in crew sign, DetectionTask and 1.13 WorldHandler --- .../async/detection/DetectionTask.java | 2 +- .../countercraft/movecraft/sign/CrewSign.java | 6 +++- .../movecraft/sign/RepairSign.java | 2 +- .../compat/v1_13_R2/IWorldHandler.java | 13 +++++--- .../compat/v1_13_R2/NextTickProvider.java | 32 ++++++++----------- modules/v1_14_R1/pom.xml | 2 +- 6 files changed, 30 insertions(+), 27 deletions(-) diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/detection/DetectionTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/detection/DetectionTask.java index 5a675d5d4..47c633ee2 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/detection/DetectionTask.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/detection/DetectionTask.java @@ -406,7 +406,7 @@ private boolean confirmStructureRequirements(BlockLimitManager flyBlocks, if (numberOfBlocks > i.getUpperLimit() - 10000.0) { fail(String.format(I18nSupport.getInternationalisedString("Detection - Too much flyblock") + ": %s %d > %d", name.toLowerCase().replace("_", " "), numberOfBlocks, - i.getUpperLimit() - 10000)); + (int) (i.getUpperLimit() - 10000))); return false; } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CrewSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CrewSign.java index 62781fda9..6df32b1f0 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CrewSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CrewSign.java @@ -120,7 +120,11 @@ public void onCraftDetect(CraftDetectEvent event){ } Sign sign = (Sign) block.getState(); if (ChatColor.stripColor(sign.getLine(0)).equalsIgnoreCase("Crew:") && Arrays.binarySearch(beds, sign.getLocation().subtract(0,1,0).getBlock().getType()) >= 0) { - event.getCraft().getCrewSigns().put(Bukkit.getPlayer(sign.getLine(1)).getUniqueId(),block.getLocation().subtract(0,1,0)); + final Player crew = Bukkit.getPlayer(sign.getLine(1)); + if (crew == null){ + return; + } + event.getCraft().getCrewSigns().put(crew.getUniqueId(),block.getLocation().subtract(0,1,0)); } } } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RepairSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RepairSign.java index 5e0bfd510..333b476d3 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RepairSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RepairSign.java @@ -135,7 +135,7 @@ private void signRightClick(PlayerInteractEvent event){ } //if clipboard is not null long numDifferentBlocks = movecraftRepair.getNumDiffBlocks(repairName); boolean secondClick = false; - if (!playerInteractTimeMap.isEmpty()) { + if (playerInteractTimeMap.containsKey(p.getUniqueId())) { if (playerInteractTimeMap.get(p.getUniqueId()) != null && System.currentTimeMillis() - playerInteractTimeMap.get(p.getUniqueId()) < 5000) { secondClick = true; } diff --git a/modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/IWorldHandler.java b/modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/IWorldHandler.java index e6023b543..b5d3b6d09 100644 --- a/modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/IWorldHandler.java +++ b/modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/IWorldHandler.java @@ -70,12 +70,14 @@ public void rotateCraft(@NotNull Craft craft, @NotNull MovecraftLocation originP for(BlockPosition position : rotatedPositions.keySet()){ //TileEntity tile = nativeWorld.removeTileEntity(position); TileEntity tile = removeTileEntity(nativeWorld,position); + if(tile == null) continue; tile.a(ROTATION[rotation.ordinal()]); //get the nextTick to move with the tile tiles.add(new TileHolder(tile, tickProvider.getNextTick((WorldServer)nativeWorld,position), position)); } + ((WorldServer)nativeWorld).getBlockTickList().a(); //******************************************* //* Step three: Translate all the blocks * @@ -104,7 +106,7 @@ public void rotateCraft(@NotNull Craft craft, @NotNull MovecraftLocation originP if(tileHolder.getNextTick()==null) continue; final long currentTime = nativeWorld.worldData.getTime(); - //nativeWorld.b(rotatedPositions.get(tileHolder.getNextTick().a), tileHolder.getNextTick().a(), (int) (tileHolder.getNextTick().b - currentTime), tileHolder.getNextTick().c); + nativeWorld.getBlockTickList().a(rotatedPositions.get(tileHolder.getNextTick().a), tileHolder.getNextTick().a(), (int) (tileHolder.getNextTick().b - currentTime), tileHolder.getNextTick().c); //BlockPosition, Object, int, TickListPriority nativeWorld.b(rotatedPositions.get(tileHolder.getNextTick().a), tileHolder.getTile()); } @@ -210,7 +212,7 @@ public void translateCraft(@NotNull Craft craft, @NotNull MovecraftLocation disp if(tileHolder.getNextTick()==null) continue; final long currentTime = nativeWorld.worldData.getTime(); - //nativeWorld.b(tileHolder.getNextTick().a.a(translateVector), tileHolder.getNextTick().a(), (int) (tileHolder.getNextTick().b - currentTime), tileHolder.getNextTick().c); + nativeWorld.getBlockTickList().a(tileHolder.getNextTick().a.a(translateVector), tileHolder.getNextTick().a(), (int) (tileHolder.getNextTick().b - currentTime), tileHolder.getNextTick().c); nativeWorld.b(tileHolder.getNextTick().a.a(translateVector), tileHolder.getTile()); } //******************************************* @@ -278,6 +280,7 @@ private TileEntity removeTileEntity(@NotNull World world, @NotNull BlockPosition if(!Settings.IsPaper) world.tileEntityList.remove(tile); world.tileEntityListTick.remove(tile); + world.getBlockTickList().a(position, tile.getBlock().getBlock(), (int) world.worldData.getTime()); if(!bMap.containsKey(world)){ try { Field bField = World.class.getDeclaredField("c"); @@ -357,10 +360,10 @@ private void moveTileEntity(@NotNull World nativeWorld, @NotNull BlockPosition n private class TileHolder{ @NotNull private final TileEntity tile; @Nullable - private final NextTickListEntry nextTick; + private final NextTickListEntry nextTick; @NotNull private final BlockPosition tilePosition; - public TileHolder(@NotNull TileEntity tile, @Nullable NextTickListEntry nextTick, @NotNull BlockPosition tilePosition){ + public TileHolder(@NotNull TileEntity tile, @Nullable NextTickListEntry nextTick, @NotNull BlockPosition tilePosition){ this.tile = tile; this.nextTick = nextTick; this.tilePosition = tilePosition; @@ -373,7 +376,7 @@ public TileEntity getTile() { } @Nullable - public NextTickListEntry getNextTick() { + public NextTickListEntry getNextTick() { return nextTick; } diff --git a/modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/NextTickProvider.java b/modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/NextTickProvider.java index f23508bce..e1f1e29f2 100644 --- a/modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/NextTickProvider.java +++ b/modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/NextTickProvider.java @@ -2,20 +2,15 @@ import net.minecraft.server.v1_13_R2.*; import org.apache.commons.lang3.tuple.ImmutablePair; +import org.bukkit.craftbukkit.v1_13_R2.util.HashTreeSet; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.bukkit.craftbukkit.v1_13_R2.util.HashTreeSet; - import java.lang.reflect.Field; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; +import java.util.*; public class NextTickProvider { - private Map,List>> tickMap = new HashMap<>(); + private Map>,List>>> tickMap = new HashMap<>(); private boolean isRegistered(@NotNull WorldServer world){ return tickMap.containsKey(world); @@ -23,35 +18,36 @@ private boolean isRegistered(@NotNull WorldServer world){ @SuppressWarnings("unchecked") private void registerWorld(@NotNull WorldServer world){ - List W = new ArrayList<>(); - HashTreeSet nextTickList = new HashTreeSet<>(); + List> g = new ArrayList<>(); + HashTreeSet> nextTickList = new HashTreeSet<>(); TickListServer blockTickListServer = world.getBlockTickList(); try { Field gField = TickListServer.class.getDeclaredField("g"); gField.setAccessible(true); - W = (List) gField.get(blockTickListServer); + g = (List>) gField.get(blockTickListServer); Field ntlField = TickListServer.class.getDeclaredField("nextTickList"); ntlField.setAccessible(true); - nextTickList = (HashTreeSet) ntlField.get(blockTickListServer); + nextTickList = (HashTreeSet>) ntlField.get(blockTickListServer); } catch (IllegalAccessException | IllegalArgumentException | NoSuchFieldException | SecurityException e1) { e1.printStackTrace(); } - tickMap.put(world, new ImmutablePair<>(nextTickList,W)); + tickMap.put(world, new ImmutablePair<>(nextTickList, g)); } @Nullable - public NextTickListEntry getNextTick(@NotNull WorldServer world,@NotNull BlockPosition position){ + public NextTickListEntry getNextTick(@NotNull WorldServer world,@NotNull BlockPosition position){ if(!isRegistered(world)) registerWorld(world); - ImmutablePair, List> listPair = tickMap.get(world); - for(Iterator iterator = listPair.left.iterator(); iterator.hasNext();) { - NextTickListEntry listEntry = iterator.next(); + ImmutablePair>, List>> listPair = tickMap.get(world); + + for(Iterator> iterator = listPair.left.iterator(); iterator.hasNext();) { + NextTickListEntry listEntry = iterator.next(); if (position.equals(listEntry.a)) { iterator.remove(); return listEntry; } } - for(Iterator iterator = listPair.right.iterator(); iterator.hasNext();) { + for(Iterator> iterator = listPair.right.iterator(); iterator.hasNext();) { NextTickListEntry listEntry = iterator.next(); if (position.equals(listEntry.a)) { iterator.remove(); diff --git a/modules/v1_14_R1/pom.xml b/modules/v1_14_R1/pom.xml index 1e95a4d85..9582428b7 100644 --- a/modules/v1_14_R1/pom.xml +++ b/modules/v1_14_R1/pom.xml @@ -35,7 +35,7 @@ org.bukkit craftbukkit - 1.14.2-R0.1-SNAPSHOT + 1.14.4-R0.1-SNAPSHOT From 7206eb29ba5835a778256f70b78448c010f4ed56 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Fri, 1 Nov 2019 23:40:20 +0100 Subject: [PATCH 065/304] Crew sign fix as well as switching from Pair to AbstractMap.SimpleImmutableEntry in repair --- .../countercraft/movecraft/sign/CrewSign.java | 3 +- .../movecraft/sign/RepairSign.java | 13 +++-- .../movecraft/MovecraftRepair.java | 6 +-- .../compat/v1_13_R2/IWorldHandler.java | 2 + .../compat/we6/IMovecraftRepair.java | 54 +++++++++---------- .../compat/we7/IMovecraftRepair.java | 40 +++++++------- 6 files changed, 56 insertions(+), 62 deletions(-) diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CrewSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CrewSign.java index 6df32b1f0..7c3f7761c 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CrewSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CrewSign.java @@ -104,7 +104,8 @@ public final void onPlayerRespawn(PlayerRespawnEvent event) { } player.sendMessage(I18nSupport.getInternationalisedString("CrewSign - Respawn")); Location respawnLoc = craft.getCrewSigns().get(player.getUniqueId()); - if (Arrays.binarySearch(beds, respawnLoc.getBlock().getType()) < 0){ + Material test = respawnLoc.getBlock().getType(); + if (Settings.IsLegacy ? test == LegacyUtils.BED_BLOCK : test.name().endsWith("BED")){ return; } event.setRespawnLocation(respawnLoc); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RepairSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RepairSign.java index 333b476d3..e93bcfd81 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RepairSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RepairSign.java @@ -3,7 +3,6 @@ import com.sk89q.worldedit.blocks.BaseBlock; import com.sk89q.worldedit.bukkit.BukkitAdapter; import com.sk89q.worldedit.extent.clipboard.Clipboard; -import javafx.util.Pair; import net.countercraft.movecraft.Movecraft; import net.countercraft.movecraft.MovecraftLocation; import net.countercraft.movecraft.MovecraftRepair; @@ -140,14 +139,14 @@ private void signRightClick(PlayerInteractEvent event){ secondClick = true; } } - HashMap, Double> numMissingItems = movecraftRepair.getMissingBlocks(repairName); - ArrayDeque> locMissingBlocks = movecraftRepair.getMissingBlockLocations(repairName); + HashMap, Double> numMissingItems = movecraftRepair.getMissingBlocks(repairName); + ArrayDeque> locMissingBlocks = movecraftRepair.getMissingBlockLocations(repairName); int totalSize = locMissingBlocks.size() + pCraft.getHitBox().size(); if (secondClick){ // check all the chests for materials for the repair HashMap> chestsToTakeFrom = new HashMap<>(); // typeid, list of chest inventories boolean enoughMaterial = true; - for (Pair type : numMissingItems.keySet()) { + for (AbstractMap.SimpleImmutableEntry type : numMissingItems.keySet()) { long longRemQty = Math.round(numMissingItems.get(type)); int remainingQty = (int) longRemQty; ArrayList chests = new ArrayList<>(); @@ -194,7 +193,7 @@ private void signRightClick(PlayerInteractEvent event){ } if (enoughMaterial) { // we know we have enough materials to make the repairs, so remove the materials from the chests - for (Pair type : numMissingItems.keySet()) { + for (AbstractMap.SimpleImmutableEntry type : numMissingItems.keySet()) { int remainingQty = (int) Math.round(numMissingItems.get(type)); for (InventoryHolder inventoryHolder : chestsToTakeFrom.get(type.getKey())) { HashMap foundItems = inventoryHolder.getInventory().all(type.getKey()); @@ -219,7 +218,7 @@ private void signRightClick(PlayerInteractEvent event){ final LinkedList updateCommandsFragileBlocks = new LinkedList<>(); while (!locMissingBlocks.isEmpty()){ - Pair locs = locMissingBlocks.pollFirst(); + AbstractMap.SimpleImmutableEntry locs = locMissingBlocks.pollFirst(); assert locs != null; Vector cLoc = locs.getValue(); MovecraftLocation moveLoc = new MovecraftLocation(locs.getKey().getBlockX(), locs.getKey().getBlockY(), locs.getKey().getBlockZ()); @@ -264,7 +263,7 @@ private void signRightClick(PlayerInteractEvent event){ } if (numDifferentBlocks != 0) { event.getPlayer().sendMessage(I18nSupport.getInternationalisedString("Repair - Supplies needed")); - for (Pair blockType : numMissingItems.keySet()) { + for (AbstractMap.SimpleImmutableEntry blockType : numMissingItems.keySet()) { if (blockType.getKey().equals(Material.COAL)) { event.getPlayer().sendMessage(String.format("%s : %d", blockType.getValue() == 1 ? "charcoal" : "coal" , Math.round(numMissingItems.get(blockType)))); } else { diff --git a/modules/api/src/main/java/net/countercraft/movecraft/MovecraftRepair.java b/modules/api/src/main/java/net/countercraft/movecraft/MovecraftRepair.java index 7d50c5262..8e15cb110 100644 --- a/modules/api/src/main/java/net/countercraft/movecraft/MovecraftRepair.java +++ b/modules/api/src/main/java/net/countercraft/movecraft/MovecraftRepair.java @@ -2,13 +2,13 @@ import com.sk89q.worldedit.extent.clipboard.Clipboard; import com.sk89q.worldguard.protection.regions.ProtectedRegion; -import javafx.util.Pair; import net.countercraft.movecraft.craft.Craft; import org.bukkit.Material; import org.bukkit.World; import org.bukkit.block.Sign; import org.bukkit.util.Vector; +import java.util.AbstractMap; import java.util.ArrayDeque; import java.util.HashMap; @@ -20,9 +20,9 @@ public abstract class MovecraftRepair { public abstract Clipboard loadRegionRepairStateClipboard(String repairStateName, World bukkitWorld); - public abstract HashMap, Double> getMissingBlocks(String repairName); + public abstract HashMap, Double> getMissingBlocks(String repairName); - public abstract ArrayDeque> getMissingBlockLocations(String repairName); + public abstract ArrayDeque> getMissingBlockLocations(String repairName); public abstract long getNumDiffBlocks(String repairName); } diff --git a/modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/IWorldHandler.java b/modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/IWorldHandler.java index b5d3b6d09..cd9c22fd4 100644 --- a/modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/IWorldHandler.java +++ b/modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/IWorldHandler.java @@ -36,6 +36,7 @@ public class IWorldHandler extends WorldHandler{ } private final NextTickProvider tickProvider = new NextTickProvider(); private final HashMap> bMap = new HashMap<>(); + private final HashMap tileMap = new HashMap<>(); private MethodHandle internalTeleportMH; public IWorldHandler() { @@ -353,6 +354,7 @@ private void moveTileEntity(@NotNull World nativeWorld, @NotNull BlockPosition n nativeWorld.capturedTileEntities.put(newPosition, tile); return; } + tileMap.put(newPosition, tile); tile.setPosition(newPosition); chunk.tileEntities.put(newPosition, tile); } diff --git a/modules/worldedit/WE6Utils/src/main/java/net/countercraft/movecraft/compat/we6/IMovecraftRepair.java b/modules/worldedit/WE6Utils/src/main/java/net/countercraft/movecraft/compat/we6/IMovecraftRepair.java index 7f9d75a6b..8d451adb3 100644 --- a/modules/worldedit/WE6Utils/src/main/java/net/countercraft/movecraft/compat/we6/IMovecraftRepair.java +++ b/modules/worldedit/WE6Utils/src/main/java/net/countercraft/movecraft/compat/we6/IMovecraftRepair.java @@ -23,7 +23,6 @@ import com.sk89q.worldguard.protection.regions.ProtectedCuboidRegion; import com.sk89q.worldguard.protection.regions.ProtectedPolygonalRegion; import com.sk89q.worldguard.protection.regions.ProtectedRegion; -import javafx.util.Pair; import net.countercraft.movecraft.MovecraftLocation; import net.countercraft.movecraft.MovecraftRepair; import net.countercraft.movecraft.config.Settings; @@ -46,16 +45,13 @@ import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; -import java.util.ArrayDeque; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Set; +import java.util.*; public class IMovecraftRepair extends MovecraftRepair { private final Plugin plugin; - private HashMap>> locMissingBlocksMap = new HashMap<>(); + private HashMap>> locMissingBlocksMap = new HashMap<>(); private HashMap numDiffBlocksMap = new HashMap<>(); - private HashMap, Double>> missingBlocksMap = new HashMap<>(); + private HashMap, Double>> missingBlocksMap = new HashMap<>(); public IMovecraftRepair(Plugin plugin) { this.plugin = plugin; @@ -188,8 +184,8 @@ public Clipboard loadCraftRepairStateClipboard(Craft craft, Sign sign) { return null; } long numDiffBlocks = 0; - HashMap, Double> missingBlocks = new HashMap<>(); - ArrayDeque> locMissingBlocks = new ArrayDeque<>(); + HashMap, Double> missingBlocks = new HashMap<>(); + ArrayDeque> locMissingBlocks = new ArrayDeque<>(); Vector minPos = MathUtils.we6vectorToBukkitVector(clipboard.getMinimumPoint()); Vector distance = MathUtils.we6vectorToBukkitVector(clipboard.getOrigin().subtract(clipboard.getMinimumPoint())); Vector size = MathUtils.we6vectorToBukkitVector(clipboard.getDimensions()); @@ -221,10 +217,10 @@ public Clipboard loadCraftRepairStateClipboard(Craft craft, Sign sign) { continue; } String id = ct.getString("id"); - Pair content; + AbstractMap.SimpleImmutableEntry content; if (id.equals("minecraft:coal")){ byte data = (byte) ct.getShort("Damage"); - content = new Pair<>(Material.COAL, data); + content = new AbstractMap.SimpleImmutableEntry<>(Material.COAL, data); if (!missingBlocks.containsKey(content)){ missingBlocks.put(content, (double) ct.getByte("Count")); } else { @@ -234,7 +230,7 @@ public Clipboard loadCraftRepairStateClipboard(Craft craft, Sign sign) { } } if (id.equals("minecraft:coal_block")){ - content = new Pair<>(Material.COAL_BLOCK, (byte) 0); + content = new AbstractMap.SimpleImmutableEntry<>(Material.COAL_BLOCK, (byte) 0); if (!missingBlocks.containsKey(content)){ missingBlocks.put(content, (double) ct.getByte("Count")); } else { @@ -340,9 +336,9 @@ public Clipboard loadCraftRepairStateClipboard(Craft craft, Sign sign) { } } } - Pair content; + AbstractMap.SimpleImmutableEntry content; if (numTNT > 0) { - content = new Pair<>(Material.TNT, (byte) 0); + content = new AbstractMap.SimpleImmutableEntry<>(Material.TNT, (byte) 0); if (!missingBlocks.containsKey(content)) { missingBlocks.put(content, (double) numTNT); } else { @@ -352,7 +348,7 @@ public Clipboard loadCraftRepairStateClipboard(Craft craft, Sign sign) { } } if (numFireCharges > 0) { - content = new Pair<>(Material.FIREBALL, (byte) 0); + content = new AbstractMap.SimpleImmutableEntry<>(Material.FIREBALL, (byte) 0); if (!missingBlocks.containsKey(content)) { missingBlocks.put(content, (double) numFireCharges); } else { @@ -362,7 +358,7 @@ public Clipboard loadCraftRepairStateClipboard(Craft craft, Sign sign) { } } if (numWaterBuckets > 0) { - content = new Pair<>(Material.WATER_BUCKET, (byte) 0); + content = new AbstractMap.SimpleImmutableEntry<>(Material.WATER_BUCKET, (byte) 0); if (!missingBlocks.containsKey(content)) { missingBlocks.put(content, (double) numWaterBuckets); } else { @@ -389,7 +385,7 @@ public Clipboard loadCraftRepairStateClipboard(Craft craft, Sign sign) { } } if (itemToConsume != 0) { - Pair missingBlock = new Pair<>(Material.getMaterial(itemToConsume), (byte) 0); + AbstractMap.SimpleImmutableEntry missingBlock = new AbstractMap.SimpleImmutableEntry<>(Material.getMaterial(itemToConsume), (byte) 0); if (!missingBlocks.containsKey(missingBlock)) { missingBlocks.put(missingBlock, qtyToConsume); } else { @@ -397,7 +393,7 @@ public Clipboard loadCraftRepairStateClipboard(Craft craft, Sign sign) { num += qtyToConsume; missingBlocks.put(missingBlock, num); } - locMissingBlocks.addLast(new Pair<>(new Vector(offset.getBlockX() + x, offset.getBlockY() + y, offset.getBlockZ() + z),new Vector(position.getBlockX(),position.getBlockY(),position.getBlockZ()))); + locMissingBlocks.addLast(new AbstractMap.SimpleImmutableEntry<>(new Vector(offset.getBlockX() + x, offset.getBlockY() + y, offset.getBlockZ() + z),new Vector(position.getBlockX(),position.getBlockY(),position.getBlockZ()))); } } if (bukkitBlock.getType() == Material.DISPENSER && block.getType() == 23) { @@ -442,9 +438,9 @@ public Clipboard loadCraftRepairStateClipboard(Craft craft, Sign sign) { } } //Bukkit.getLogger().info(String.format("TNT: %d, Fireballs: %d, Water buckets: %d", numTNT, numFireCharges, numWaterBuckets)); - Pair content; + AbstractMap.SimpleImmutableEntry content; if (numTNT > 0) { - content = new Pair<>(Material.TNT, (byte) 0); + content = new AbstractMap.SimpleImmutableEntry<>(Material.TNT, (byte) 0); if (!missingBlocks.containsKey(content)) { missingBlocks.put(content, (double) numTNT); } else { @@ -455,7 +451,7 @@ public Clipboard loadCraftRepairStateClipboard(Craft craft, Sign sign) { needReplace = true; } if (numFireCharges > 0) { - content = new Pair<>(Material.FIREBALL, (byte) 0); + content = new AbstractMap.SimpleImmutableEntry<>(Material.FIREBALL, (byte) 0); if (!missingBlocks.containsKey(content)) { missingBlocks.put(content, (double) numFireCharges); } else { @@ -466,7 +462,7 @@ public Clipboard loadCraftRepairStateClipboard(Craft craft, Sign sign) { needReplace = true; } if (numWaterBuckets > 0) { - content = new Pair<>(Material.WATER_BUCKET, (byte) 0); + content = new AbstractMap.SimpleImmutableEntry<>(Material.WATER_BUCKET, (byte) 0); if (!missingBlocks.containsKey(content)) { missingBlocks.put(content, (double) numWaterBuckets); } else { @@ -478,7 +474,7 @@ public Clipboard loadCraftRepairStateClipboard(Craft craft, Sign sign) { } if (needReplace) { numDiffBlocks++; - locMissingBlocks.addLast(new Pair<>(new Vector(offset.getBlockX() + x, offset.getBlockY() + y, offset.getBlockZ() + z),new Vector(position.getBlockX(),position.getBlockY(),position.getBlockZ()))); + locMissingBlocks.addLast(new AbstractMap.SimpleImmutableEntry<>(new Vector(offset.getBlockX() + x, offset.getBlockY() + y, offset.getBlockZ() + z),new Vector(position.getBlockX(),position.getBlockY(),position.getBlockZ()))); } } if (bukkitBlock.getType() == Material.FURNACE && block.getType() == 61){ @@ -497,7 +493,7 @@ public Clipboard loadCraftRepairStateClipboard(Craft craft, Sign sign) { continue; } String id = ct.getString("id"); - Pair content; + AbstractMap.SimpleImmutableEntry content; if (id.equals("minecraft:coal")){ byte data = (byte)ct.getShort("Damage"); byte count = ct.getByte("Count"); @@ -511,7 +507,7 @@ public Clipboard loadCraftRepairStateClipboard(Craft craft, Sign sign) { } } if (count > 0) { - content = new Pair<>(Material.COAL, data); + content = new AbstractMap.SimpleImmutableEntry<>(Material.COAL, data); if (!missingBlocks.containsKey(content)) { missingBlocks.put(content, (double) count); } else { @@ -532,7 +528,7 @@ public Clipboard loadCraftRepairStateClipboard(Craft craft, Sign sign) { count -= fInv.getFuel() != null ? (byte) fInv.getFuel().getAmount() : 0; } if (count > 0) { - content = new Pair<>(Material.COAL_BLOCK, (byte) 0); + content = new AbstractMap.SimpleImmutableEntry<>(Material.COAL_BLOCK, (byte) 0); if (!missingBlocks.containsKey(content)) { missingBlocks.put(content, (double) count); } else { @@ -547,7 +543,7 @@ public Clipboard loadCraftRepairStateClipboard(Craft craft, Sign sign) { } if (needsRefill > 0){ numDiffBlocks++; - locMissingBlocks.addLast(new Pair<>(new Vector(offset.getBlockX() + x, offset.getBlockY() + y, offset.getBlockZ() + z),new Vector(position.getBlockX(),position.getBlockY(),position.getBlockZ()))); + locMissingBlocks.addLast(new AbstractMap.SimpleImmutableEntry<>(new Vector(offset.getBlockX() + x, offset.getBlockY() + y, offset.getBlockZ() + z),new Vector(position.getBlockX(),position.getBlockY(),position.getBlockZ()))); } } } @@ -578,11 +574,11 @@ public Clipboard loadRegionRepairStateClipboard(String s, World world) { } @Override - public HashMap, Double> getMissingBlocks(String repairName) { + public HashMap, Double> getMissingBlocks(String repairName) { return missingBlocksMap.get(repairName); } - public ArrayDeque> getMissingBlockLocations(String repairName) { + public ArrayDeque> getMissingBlockLocations(String repairName) { return locMissingBlocksMap.get(repairName); } diff --git a/modules/worldedit/WE7Utils/src/main/java/net/countercraft/movecraft/compat/we7/IMovecraftRepair.java b/modules/worldedit/WE7Utils/src/main/java/net/countercraft/movecraft/compat/we7/IMovecraftRepair.java index b642f58ff..ca04181a7 100644 --- a/modules/worldedit/WE7Utils/src/main/java/net/countercraft/movecraft/compat/we7/IMovecraftRepair.java +++ b/modules/worldedit/WE7Utils/src/main/java/net/countercraft/movecraft/compat/we7/IMovecraftRepair.java @@ -27,7 +27,6 @@ import com.sk89q.worldguard.protection.regions.ProtectedCuboidRegion; import com.sk89q.worldguard.protection.regions.ProtectedPolygonalRegion; import com.sk89q.worldguard.protection.regions.ProtectedRegion; -import javafx.util.Pair; import net.countercraft.movecraft.MovecraftLocation; import net.countercraft.movecraft.MovecraftRepair; import net.countercraft.movecraft.config.Settings; @@ -47,15 +46,12 @@ import org.bukkit.util.Vector; import java.io.*; -import java.util.ArrayDeque; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Set; +import java.util.*; public class IMovecraftRepair extends MovecraftRepair { - private final HashMap>> locMissingBlocksMap = new HashMap<>(); + private final HashMap>> locMissingBlocksMap = new HashMap<>(); private final HashMap numDiffBlocksMap = new HashMap<>(); - private final HashMap, Double>> missingBlocksMap = new HashMap<>(); + private final HashMap, Double>> missingBlocksMap = new HashMap<>(); private final HashMap distanceMap = new HashMap<>(); private final Plugin plugin; @@ -184,8 +180,8 @@ public Clipboard loadCraftRepairStateClipboard(Craft craft, Sign sign) { } if (clipboard != null){ long numDiffBlocks = 0; - HashMap, Double> missingBlocks = new HashMap<>(); - ArrayDeque> locMissingBlocks = new ArrayDeque<>(); + HashMap, Double> missingBlocks = new HashMap<>(); + ArrayDeque> locMissingBlocks = new ArrayDeque<>(); HashMap materials = new HashMap<>(); BlockVector3 minPoint = clipboard.getMinimumPoint(); BlockVector3 length = clipboard.getDimensions(); @@ -280,9 +276,9 @@ public Clipboard loadCraftRepairStateClipboard(Craft craft, Sign sign) { } } } - Pair content; + AbstractMap.SimpleImmutableEntry content; if (numTNT > 0){ - content = new Pair<>(Material.TNT, (byte) 0); + content = new AbstractMap.SimpleImmutableEntry<>(Material.TNT, (byte) 0); if (missingBlocks.containsKey(content)){ double count = missingBlocks.get(content); count += numTNT; @@ -292,7 +288,7 @@ public Clipboard loadCraftRepairStateClipboard(Craft craft, Sign sign) { } } if (numFirecharge > 0){ - content = new Pair<>(Material.FIRE_CHARGE, (byte) 0); + content = new AbstractMap.SimpleImmutableEntry<>(Material.FIRE_CHARGE, (byte) 0); if (missingBlocks.containsKey(content)){ double count = missingBlocks.get(content); count += numFirecharge; @@ -302,7 +298,7 @@ public Clipboard loadCraftRepairStateClipboard(Craft craft, Sign sign) { } } if (numWaterBucket > 0){ - content = new Pair<>(Material.WATER_BUCKET, (byte) 0); + content = new AbstractMap.SimpleImmutableEntry<>(Material.WATER_BUCKET, (byte) 0); if (missingBlocks.containsKey(content)){ double count = missingBlocks.get(content); count += numWaterBucket; @@ -312,9 +308,9 @@ public Clipboard loadCraftRepairStateClipboard(Craft craft, Sign sign) { } } } - locMissingBlocks.addLast(new Pair<>(new Vector(cx,cy,cz),new Vector(position.getBlockX(),position.getBlockY(),position.getBlockZ()))); + locMissingBlocks.addLast(new AbstractMap.SimpleImmutableEntry<>(new Vector(cx,cy,cz),new Vector(position.getBlockX(),position.getBlockY(),position.getBlockZ()))); numDiffBlocks++; - Pair missingBlock = new Pair<>(typeToConsume, (byte) 0); + AbstractMap.SimpleImmutableEntry missingBlock = new AbstractMap.SimpleImmutableEntry<>(typeToConsume, (byte) 0); if (missingBlocks.containsKey(missingBlock)){ double count = missingBlocks.get(missingBlock); count += qtyToConsume; @@ -365,9 +361,9 @@ public Clipboard loadCraftRepairStateClipboard(Craft craft, Sign sign) { } } boolean needsReplace = false; - Pair content; + AbstractMap.SimpleImmutableEntry content; if (numTNT > 0){ - content = new Pair<>(Material.TNT, (byte) 0); + content = new AbstractMap.SimpleImmutableEntry<>(Material.TNT, (byte) 0); if (missingBlocks.containsKey(content)){ double count = missingBlocks.get(content); count += numTNT; @@ -378,7 +374,7 @@ public Clipboard loadCraftRepairStateClipboard(Craft craft, Sign sign) { needsReplace = true; } if (numFireCharge > 0){ - content = new Pair<>(Material.FIRE_CHARGE, (byte) 0); + content = new AbstractMap.SimpleImmutableEntry<>(Material.FIRE_CHARGE, (byte) 0); if (missingBlocks.containsKey(content)){ double count = missingBlocks.get(content); count += numFireCharge; @@ -389,7 +385,7 @@ public Clipboard loadCraftRepairStateClipboard(Craft craft, Sign sign) { needsReplace = true; } if (numWaterBucket > 0){ - content = new Pair<>(Material.WATER_BUCKET, (byte) 0); + content = new AbstractMap.SimpleImmutableEntry<>(Material.WATER_BUCKET, (byte) 0); if (missingBlocks.containsKey(content)){ double count = missingBlocks.get(content); count += numWaterBucket; @@ -400,7 +396,7 @@ public Clipboard loadCraftRepairStateClipboard(Craft craft, Sign sign) { needsReplace = true; } if (needsReplace){ - locMissingBlocks.addLast(new Pair<>(new Vector(cx,cy,cz),new Vector(position.getBlockX(),position.getBlockY(),position.getBlockZ()))); + locMissingBlocks.addLast(new AbstractMap.SimpleImmutableEntry<>(new Vector(cx,cy,cz),new Vector(position.getBlockX(),position.getBlockY(),position.getBlockZ()))); numDiffBlocks++; } @@ -437,12 +433,12 @@ public Clipboard loadRegionRepairStateClipboard(String s, World world) { } @Override - public HashMap, Double> getMissingBlocks(String s) { + public HashMap, Double> getMissingBlocks(String s) { return missingBlocksMap.get(s); } @Override - public ArrayDeque> getMissingBlockLocations(String s) { + public ArrayDeque> getMissingBlockLocations(String s) { return locMissingBlocksMap.get(s); } From bbfaafe8d708401ceb76ded3f61b6d096bcd4b0a Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Sat, 2 Nov 2019 22:29:21 +0100 Subject: [PATCH 066/304] Fix #16 --- .../net/countercraft/movecraft/Movecraft.java | 2 +- .../movecraft/async/AsyncManager.java | 49 ++----------------- .../async/translation/TranslationTask.java | 26 +++------- .../countercraft/movecraft/craft/ICraft.java | 4 +- .../movecraft/listener/InteractListener.java | 4 -- .../movecraft/sync/EntityProcessor.java | 3 ++ .../WorldGuardCompatManager.java | 49 ++++++++++++++++++- .../countercraft/movecraft/craft/Craft.java | 15 +----- .../movecraft/craft/CraftType.java | 17 ++----- 9 files changed, 68 insertions(+), 101 deletions(-) rename modules/Movecraft/src/main/java/net/countercraft/movecraft/{compatmanager => worldguard}/WorldGuardCompatManager.java (55%) diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java index 5ed995827..8b74acc71 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java @@ -26,7 +26,7 @@ import com.sk89q.worldguard.protection.flags.StateFlag; import net.countercraft.movecraft.async.AsyncManager; import net.countercraft.movecraft.commands.*; -import net.countercraft.movecraft.compatmanager.WorldGuardCompatManager; +import net.countercraft.movecraft.worldguard.WorldGuardCompatManager; import net.countercraft.movecraft.config.Settings; import net.countercraft.movecraft.craft.CraftManager; import net.countercraft.movecraft.listener.BlockListener; diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java index 440134d23..46ce4bb21 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java @@ -19,16 +19,8 @@ import at.pavlov.cannons.cannon.Cannon; import com.google.common.collect.Lists; -import com.sk89q.worldedit.bukkit.BukkitAdapter; -import com.sk89q.worldedit.math.BlockVector3; -import com.sk89q.worldguard.WorldGuard; -import com.sk89q.worldguard.bukkit.WorldGuardPlugin; -import com.sk89q.worldguard.protection.ApplicableRegionSet; -import com.sk89q.worldguard.protection.managers.RegionManager; -import com.sk89q.worldguard.protection.regions.ProtectedRegion; -import com.sk89q.worldguard.protection.regions.RegionContainer; -import net.countercraft.movecraft.*; import net.countercraft.movecraft.Rotation; +import net.countercraft.movecraft.*; import net.countercraft.movecraft.async.detection.DetectionTask; import net.countercraft.movecraft.async.detection.DetectionTaskData; import net.countercraft.movecraft.async.rotation.RotationTask; @@ -39,9 +31,9 @@ import net.countercraft.movecraft.events.CraftDetectEvent; import net.countercraft.movecraft.localisation.I18nSupport; import net.countercraft.movecraft.mapUpdater.MapUpdateManager; -import net.countercraft.movecraft.utils.*; import net.countercraft.movecraft.mapUpdater.update.BlockCreateCommand; import net.countercraft.movecraft.mapUpdater.update.UpdateCommand; +import net.countercraft.movecraft.utils.*; import org.bukkit.*; import org.bukkit.block.Block; import org.bukkit.block.BlockFace; @@ -388,7 +380,6 @@ private void processCruise() { boolean bankLeft = false; boolean bankRight = false; boolean dive = false; - boolean climb = pcraft.isClimbing(); if (pcraft.getPilotLocked()) { if (pcraft.getNotificationPlayer().isSneaking()) dive = true; @@ -410,9 +401,6 @@ private void processCruise() { if (pcraft.getCruiseDirection() == BlockFace.UP) { dy = 1 + pcraft.getType().getVertCruiseSkipBlocks(); } - else if (climb){ - dy = (1 + pcraft.getType().getCruiseSkipBlocks()) >> 1; - } // descend if (pcraft.getCruiseDirection() == BlockFace.DOWN) { dy = 0 - 1 - pcraft.getType().getVertCruiseSkipBlocks(); @@ -586,38 +574,7 @@ private void detectSinking(){ // know and release the craft. Otherwise // update the time for the next check Player notifyP = pcraft.getNotificationPlayer(); - if (Movecraft.getInstance().getWorldGuardPlugin() != null){ - WorldGuardPlugin wgPlugin = Movecraft.getInstance().getWorldGuardPlugin(); - ProtectedRegion region = null; - RegionManager regionManager; - if (Settings.IsLegacy){ - regionManager = LegacyUtils.getRegionManager(wgPlugin, pcraft.getW()); - } else { - RegionContainer container = WorldGuard.getInstance().getPlatform().getRegionContainer(); - regionManager = container.get(BukkitAdapter.adapt(pcraft.getW())); - } - for (MovecraftLocation location : pcraft.getHitBox()){ - ApplicableRegionSet regions; - if (Settings.IsLegacy) - regions = LegacyUtils.getApplicableRegions(regionManager, location.toBukkit(pcraft.getW())); - else { - regions = regionManager.getApplicableRegions(BlockVector3.at(location.getX(), location.getY(), location.getZ())); - } - for (ProtectedRegion pr : regions.getRegions()){ - if (WorldguardUtils.pvpAllowed(pr)){ - region = pr; - break; - } - } - if (region != null){ - break; - } - } - if (region != null && Settings.WorldGuardBlockSinkOnPVPPerm && WorldguardUtils.pvpAllowed(region) && notifyP != null){ - notifyP.sendMessage(I18nSupport.getInternationalisedString("Player- Craft should sink but PVP is not allowed in this WorldGuard region")); - isSinking = false; - } - } + if (isSinking && pcraft.isNotProcessing()) { if (notifyP != null) { diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java index d273429be..ae9c8bc5c 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java @@ -28,23 +28,6 @@ public class TranslationTask extends AsyncTask { private static final Set FALL_THROUGH_BLOCKS = new HashSet<>();//Settings.IsLegacy ? new Material[]{}:new Material[]{Material.AIR, - /*Material.WATER, - Material.LAVA, - Material.BROWN_MUSHROOM, - Material.RED_MUSHROOM, - Material.TORCH, - Material.FIRE, - Material.REDSTONE_WIRE, - Material.LADDER, - Material.WALL_SIGN, - Material.LEVER, - Material.STONE_BUTTON, - Material.SNOW, - Material.CARROT, - Material.POTATO, - };*/ - //private static final int[] FALL_THROUGH_BLOCKS = {0, 8, 9, 10, 11, 31, 37, 38, 39, 40, 50, 51, 55, 59, 63, 65, 68, 69, 70, 72, 75, 76, 77, 78, 83, 85, 93, 94, 111, 141, 142, 143, 171}; - private int dx, dy, dz; private HashHitBox newHitBox, oldHitBox; private boolean failed; @@ -272,7 +255,8 @@ public void run() { newHitBox.add(newLocation); continue; } - final Material testMaterial = newLocation.toBukkit(craft.getW()).getBlock().getType(); + final Block b = newLocation.toBukkit(craft.getW()).getBlock(); + final Material testMaterial = b.getType(); if ((testMaterial.equals(Material.CHEST) || testMaterial.equals(Material.TRAPPED_CHEST)) && checkChests(testMaterial, newLocation)) { //prevent chests collision @@ -374,8 +358,10 @@ public void run() { newHitBox.removeAll(toRemove); } - Bukkit.getLogger().info("Collapsed hitbox: "+craft.getCollapsedHitBox().size() + ", New hitbox: " + newHitBox.size()); - }else{ + if (Settings.Debug){ + Bukkit.getLogger().info("Collapsed hitbox: "+craft.getCollapsedHitBox().size() + ", New hitbox: " + newHitBox.size()); + } + }else{ for(MovecraftLocation location : collisionBox){ if (!(craft.getType().getCollisionExplosion() != 0.0F) || System.currentTimeMillis() - craft.getOrigPilotTime() <= 1000) { continue; diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/ICraft.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/ICraft.java index 345150af0..8cb80e62d 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/ICraft.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/ICraft.java @@ -83,9 +83,7 @@ public void translate(int dx, int dy, int dz) { }*/ - if (isClimbing()){ - setClimbing(false); - } + TranslationTask task = new TranslationTask(this, dx, dy, dz); task.getUpdates().addAll(EntityProcessor.translateEntities(this, dx, dy, dz)); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/InteractListener.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/InteractListener.java index 6670b907c..d07b0c098 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/InteractListener.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/InteractListener.java @@ -107,10 +107,6 @@ public void onPlayerInteractStick(PlayerInteractEvent event) { if (craft.getPilotLocked()) { // right click moves up or down if using direct // control - if (craft.getCruising()){ - craft.setClimbing(true); - return; - } int DY = 1; if (event.getPlayer().isSneaking()) DY = -1; diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sync/EntityProcessor.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sync/EntityProcessor.java index 92a37421e..64a0335b8 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sync/EntityProcessor.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sync/EntityProcessor.java @@ -11,6 +11,7 @@ import org.bukkit.entity.Entity; import org.bukkit.entity.EntityType; +import java.util.Collections; import java.util.HashSet; import java.util.Set; @@ -20,6 +21,8 @@ private EntityProcessor(){ } public static Set translateEntities(Craft craft, int dx, int dy, int dz){ + if (!craft.getType().getMoveEntities()) + return Collections.emptySet(); HashHitBox oldHitBox = craft.getHitBox(); final HashSet updateCmds = new HashSet<>(); if (oldHitBox.isEmpty()) diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/compatmanager/WorldGuardCompatManager.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/worldguard/WorldGuardCompatManager.java similarity index 55% rename from modules/Movecraft/src/main/java/net/countercraft/movecraft/compatmanager/WorldGuardCompatManager.java rename to modules/Movecraft/src/main/java/net/countercraft/movecraft/worldguard/WorldGuardCompatManager.java index dcc74a87a..cc5c5cfa3 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/compatmanager/WorldGuardCompatManager.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/worldguard/WorldGuardCompatManager.java @@ -1,17 +1,27 @@ -package net.countercraft.movecraft.compatmanager; +package net.countercraft.movecraft.worldguard; +import com.sk89q.worldedit.bukkit.BukkitAdapter; import com.sk89q.worldedit.bukkit.BukkitWorld; +import com.sk89q.worldedit.math.BlockVector3; import com.sk89q.worldedit.util.Location; import com.sk89q.worldguard.LocalPlayer; import com.sk89q.worldguard.WorldGuard; +import com.sk89q.worldguard.bukkit.WorldGuardPlugin; +import com.sk89q.worldguard.protection.ApplicableRegionSet; +import com.sk89q.worldguard.protection.managers.RegionManager; +import com.sk89q.worldguard.protection.regions.ProtectedRegion; +import com.sk89q.worldguard.protection.regions.RegionContainer; import com.sk89q.worldguard.protection.regions.RegionQuery; import net.countercraft.movecraft.Movecraft; import net.countercraft.movecraft.MovecraftLocation; import net.countercraft.movecraft.config.Settings; +import net.countercraft.movecraft.craft.Craft; import net.countercraft.movecraft.events.CraftRotateEvent; +import net.countercraft.movecraft.events.CraftSinkEvent; import net.countercraft.movecraft.events.CraftTranslateEvent; import net.countercraft.movecraft.localisation.I18nSupport; import net.countercraft.movecraft.utils.LegacyUtils; +import net.countercraft.movecraft.utils.WorldguardUtils; import org.bukkit.World; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; @@ -61,4 +71,41 @@ private boolean pilotHasAccessToRegion(Player player, MovecraftLocation location } } + public void onCraftSink(CraftSinkEvent event){ + Craft pcraft = event.getCraft(); + Player notifyP = event.getCraft().getNotificationPlayer(); + if (Movecraft.getInstance().getWorldGuardPlugin() != null){ + WorldGuardPlugin wgPlugin = Movecraft.getInstance().getWorldGuardPlugin(); + ProtectedRegion region = null; + RegionManager regionManager; + if (Settings.IsLegacy){ + regionManager = LegacyUtils.getRegionManager(wgPlugin, pcraft.getW()); + } else { + RegionContainer container = WorldGuard.getInstance().getPlatform().getRegionContainer(); + regionManager = container.get(BukkitAdapter.adapt(pcraft.getW())); + } + for (MovecraftLocation location : pcraft.getHitBox()){ + ApplicableRegionSet regions; + if (Settings.IsLegacy) + regions = LegacyUtils.getApplicableRegions(regionManager, location.toBukkit(pcraft.getW())); + else { + regions = regionManager.getApplicableRegions(BlockVector3.at(location.getX(), location.getY(), location.getZ())); + } + for (ProtectedRegion pr : regions.getRegions()){ + if (WorldguardUtils.pvpAllowed(pr)){ + region = pr; + break; + } + } + if (region != null){ + break; + } + } + if (region != null && Settings.WorldGuardBlockSinkOnPVPPerm && WorldguardUtils.pvpAllowed(region) && notifyP != null){ + notifyP.sendMessage(I18nSupport.getInternationalisedString("Player- Craft should sink but PVP is not allowed in this WorldGuard region")); + event.setCancelled(true); + } + } + } + } diff --git a/modules/api/src/main/java/net/countercraft/movecraft/craft/Craft.java b/modules/api/src/main/java/net/countercraft/movecraft/craft/Craft.java index edf69cfa6..a6349c7e2 100644 --- a/modules/api/src/main/java/net/countercraft/movecraft/craft/Craft.java +++ b/modules/api/src/main/java/net/countercraft/movecraft/craft/Craft.java @@ -49,7 +49,6 @@ public abstract class Craft { @NotNull protected World w; @NotNull private final AtomicBoolean processing = new AtomicBoolean(); private int maxHeightLimit; - private boolean climbing; private boolean cruising; private boolean sinking; private boolean disabled; @@ -92,7 +91,6 @@ public Craft(@NotNull CraftType type, @NotNull World world) { this.cannonDirector = null; this.AADirector = null; this.lastCruiseUpdate = System.currentTimeMillis() - 10000; - this.climbing = false; this.cruising = false; this.sinking = false; this.repairing = false; @@ -152,6 +150,7 @@ public boolean getSinking() { return sinking; } + /*public void setSinking(boolean sinking) { this.sinking = sinking; }*/ @@ -164,7 +163,6 @@ public void sink(){ return; } - sinking = true; } @@ -442,15 +440,4 @@ public void setRepairing(boolean repairing) { this.repairing = repairing; } - public boolean isClimbing() { - return climbing; - } - - public void setClimbing(boolean climbing) { - this.climbing = climbing; - } - - public enum SinkReason{ - NONE, DAMAGE, RANGE - } } diff --git a/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java b/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java index d2b3c2575..df33cadc0 100644 --- a/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java +++ b/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java @@ -75,6 +75,7 @@ final public class CraftType { private final int smokeOnSink; private final int tickCooldown; private final int hoverLimit; + private final int maxTravelDistance; private final Set dynamicFlyBlocks; private final double fuelBurnRate; private final double sinkPercent; @@ -439,6 +440,7 @@ public CraftType(File f) { } } } + maxTravelDistance = data.containsKey("maxTravelDistance") ? (int) data.get("maxTravelDistance") : 500; chestPenalty = data.containsKey("chestPenalty") ? doubleFromObject(data.get("chestPenalty")) : 0d; effectRange = data.containsKey("effectRange") ? integerFromObject(data.get("effectRange")) : 0; potionEffectsToApply = data.containsKey("potionEffectsToApply") ? effectListFromObject(data.get("potionEffectsToApply")) : Collections.emptyMap(); @@ -1124,18 +1126,8 @@ public int getEffectRange() { return effectRange; } - @NotNull - public Map getPotionEffectDelays() { - return potionEffectDelays; - } - - @NotNull - public Set getEntitiesToSpawn() { - return entitiesToSpawn; - } - - public int getMaxEntitiesToBeSpawned() { - return maxEntitiesToBeSpawned; + public int getMaxTravelDistance() { + return maxTravelDistance; } private class TypeNotFoundException extends RuntimeException { @@ -1149,4 +1141,5 @@ public CraftTypeException(String message, Throwable cause){ super(message,cause); } } + } From 49a134b94acf3f34763809e04f411dd336e07b4e Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Sat, 2 Nov 2019 22:41:55 +0100 Subject: [PATCH 067/304] Fix #15 --- .../Movecraft/src/main/resources/types/1_14/BigAirship.craft | 2 +- .../src/main/resources/types/1_14/BigSubAirship.craft | 3 +-- modules/Movecraft/src/main/resources/types/1_14/Ship.craft | 3 +-- .../Movecraft/src/main/resources/types/1_14/SubAirship.craft | 3 +-- .../Movecraft/src/main/resources/types/1_14/Submarine.craft | 3 +-- modules/Movecraft/src/main/resources/types/1_14/airship.craft | 2 +- modules/Movecraft/src/main/resources/types/BigAirship.craft | 2 +- modules/Movecraft/src/main/resources/types/BigSubAirship.craft | 3 +-- modules/Movecraft/src/main/resources/types/Ship.craft | 3 +-- modules/Movecraft/src/main/resources/types/SubAirship.craft | 3 +-- modules/Movecraft/src/main/resources/types/Submarine.craft | 2 +- modules/Movecraft/src/main/resources/types/airship.craft | 2 +- 12 files changed, 12 insertions(+), 19 deletions(-) diff --git a/modules/Movecraft/src/main/resources/types/1_14/BigAirship.craft b/modules/Movecraft/src/main/resources/types/1_14/BigAirship.craft index d84e2655c..41e655726 100644 --- a/modules/Movecraft/src/main/resources/types/1_14/BigAirship.craft +++ b/modules/Movecraft/src/main/resources/types/1_14/BigAirship.craft @@ -53,7 +53,7 @@ allowedBlocks: - iron_bars - glass_pane - all_fence_gate - - nether_brick + - nether_bricks - enchanting_table - brewing_stand - cauldron diff --git a/modules/Movecraft/src/main/resources/types/1_14/BigSubAirship.craft b/modules/Movecraft/src/main/resources/types/1_14/BigSubAirship.craft index 9843f02af..e17c15c51 100644 --- a/modules/Movecraft/src/main/resources/types/1_14/BigSubAirship.craft +++ b/modules/Movecraft/src/main/resources/types/1_14/BigSubAirship.craft @@ -3,7 +3,6 @@ maxSize: 20000 minSize: 10000 allowedBlocks: - ALL_WOOD - - WATER - LAVA - ALL_LOG - all_planks @@ -53,7 +52,7 @@ allowedBlocks: - iron_bars - glass_pane - all_fence_gate - - nether_brick + - nether_bricks - enchanting_table - brewing_stand - cauldron diff --git a/modules/Movecraft/src/main/resources/types/1_14/Ship.craft b/modules/Movecraft/src/main/resources/types/1_14/Ship.craft index 48daef3b0..8009b9e14 100644 --- a/modules/Movecraft/src/main/resources/types/1_14/Ship.craft +++ b/modules/Movecraft/src/main/resources/types/1_14/Ship.craft @@ -3,7 +3,6 @@ maxSize: 100000 minSize: 10 allowedBlocks: - ALL_WOOD - - WATER - LAVA - ALL_LOG - all_planks @@ -53,7 +52,7 @@ allowedBlocks: - iron_bars - glass_pane - all_fence_gate - - nether_brick + - nether_bricks - enchanting_table - brewing_stand - cauldron diff --git a/modules/Movecraft/src/main/resources/types/1_14/SubAirship.craft b/modules/Movecraft/src/main/resources/types/1_14/SubAirship.craft index d9fc519d3..eef089525 100644 --- a/modules/Movecraft/src/main/resources/types/1_14/SubAirship.craft +++ b/modules/Movecraft/src/main/resources/types/1_14/SubAirship.craft @@ -3,7 +3,6 @@ maxSize: 5000 minSize: 1000 allowedBlocks: - ALL_WOOD - - WATER - LAVA - ALL_LOG - all_planks @@ -53,7 +52,7 @@ allowedBlocks: - iron_bars - glass_pane - all_fence_gate - - nether_brick + - nether_bricks - enchanting_table - brewing_stand - cauldron diff --git a/modules/Movecraft/src/main/resources/types/1_14/Submarine.craft b/modules/Movecraft/src/main/resources/types/1_14/Submarine.craft index 4b788847a..2d4ce83f5 100644 --- a/modules/Movecraft/src/main/resources/types/1_14/Submarine.craft +++ b/modules/Movecraft/src/main/resources/types/1_14/Submarine.craft @@ -3,7 +3,6 @@ maxSize: 100000 minSize: 10 allowedBlocks: - ALL_WOOD - - WATER - LAVA - ALL_LOG - all_planks @@ -53,7 +52,7 @@ allowedBlocks: - iron_bars - glass_pane - all_fence_gate - - nether_brick + - nether_bricks - enchanting_table - brewing_stand - cauldron diff --git a/modules/Movecraft/src/main/resources/types/1_14/airship.craft b/modules/Movecraft/src/main/resources/types/1_14/airship.craft index 9239c82f9..9cfd8d352 100644 --- a/modules/Movecraft/src/main/resources/types/1_14/airship.craft +++ b/modules/Movecraft/src/main/resources/types/1_14/airship.craft @@ -53,7 +53,7 @@ allowedBlocks: - iron_bars - glass_pane - all_fence_gate - - nether_brick + - nether_bricks - enchanting_table - brewing_stand - cauldron diff --git a/modules/Movecraft/src/main/resources/types/BigAirship.craft b/modules/Movecraft/src/main/resources/types/BigAirship.craft index 8f5efe037..618222a0f 100644 --- a/modules/Movecraft/src/main/resources/types/BigAirship.craft +++ b/modules/Movecraft/src/main/resources/types/BigAirship.craft @@ -53,7 +53,7 @@ allowedBlocks: - iron_bars - glass_pane - all_fence_gate - - nether_brick + - nether_bricks - enchanting_table - brewing_stand - cauldron diff --git a/modules/Movecraft/src/main/resources/types/BigSubAirship.craft b/modules/Movecraft/src/main/resources/types/BigSubAirship.craft index 7b35acac0..9e0db2d88 100644 --- a/modules/Movecraft/src/main/resources/types/BigSubAirship.craft +++ b/modules/Movecraft/src/main/resources/types/BigSubAirship.craft @@ -3,7 +3,6 @@ maxSize: 20000 minSize: 10000 allowedBlocks: - ALL_WOOD - - WATER - LAVA - ALL_LOG - all_planks @@ -53,7 +52,7 @@ allowedBlocks: - iron_bars - glass_pane - all_fence_gate - - nether_brick + - nether_bricks - enchanting_table - brewing_stand - cauldron diff --git a/modules/Movecraft/src/main/resources/types/Ship.craft b/modules/Movecraft/src/main/resources/types/Ship.craft index d8b05d6f4..746db3b99 100644 --- a/modules/Movecraft/src/main/resources/types/Ship.craft +++ b/modules/Movecraft/src/main/resources/types/Ship.craft @@ -3,7 +3,6 @@ maxSize: 100000 minSize: 10 allowedBlocks: - ALL_WOOD - - WATER - LAVA - ALL_LOG - all_planks @@ -53,7 +52,7 @@ allowedBlocks: - iron_bars - glass_pane - all_fence_gate - - nether_brick + - nether_bricks - enchanting_table - brewing_stand - cauldron diff --git a/modules/Movecraft/src/main/resources/types/SubAirship.craft b/modules/Movecraft/src/main/resources/types/SubAirship.craft index 0e63057a1..5e48b2b40 100644 --- a/modules/Movecraft/src/main/resources/types/SubAirship.craft +++ b/modules/Movecraft/src/main/resources/types/SubAirship.craft @@ -3,7 +3,6 @@ maxSize: 5000 minSize: 1000 allowedBlocks: - ALL_WOOD - - WATER - LAVA - ALL_LOG - all_planks @@ -53,7 +52,7 @@ allowedBlocks: - iron_bars - glass_pane - all_fence_gate - - nether_brick + - nether_bricks - enchanting_table - brewing_stand - cauldron diff --git a/modules/Movecraft/src/main/resources/types/Submarine.craft b/modules/Movecraft/src/main/resources/types/Submarine.craft index 6d838eff4..6dd85af32 100644 --- a/modules/Movecraft/src/main/resources/types/Submarine.craft +++ b/modules/Movecraft/src/main/resources/types/Submarine.craft @@ -53,7 +53,7 @@ allowedBlocks: - iron_bars - glass_pane - all_fence_gate - - nether_brick + - nether_bricks - enchanting_table - brewing_stand - cauldron diff --git a/modules/Movecraft/src/main/resources/types/airship.craft b/modules/Movecraft/src/main/resources/types/airship.craft index 9f34ec484..cb1801141 100644 --- a/modules/Movecraft/src/main/resources/types/airship.craft +++ b/modules/Movecraft/src/main/resources/types/airship.craft @@ -53,7 +53,7 @@ allowedBlocks: - iron_bars - glass_pane - all_fence_gate - - nether_brick + - nether_bricks - enchanting_table - brewing_stand - cauldron From 8a67c23d3d0564920a65db890901800d9d6b3850 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Sat, 2 Nov 2019 23:25:09 +0100 Subject: [PATCH 068/304] Fixed crew sign and improved manoverboard --- .../movecraft/commands/ManOverboardCommand.java | 15 ++++++++++++++- .../net/countercraft/movecraft/sign/CrewSign.java | 7 ++++++- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/ManOverboardCommand.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/ManOverboardCommand.java index a6dddfe4e..faee9bbed 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/ManOverboardCommand.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/ManOverboardCommand.java @@ -33,7 +33,20 @@ public boolean onCommand(CommandSender commandSender, Command command, String s, return true; } - Location telPoint = craft.getCrewSigns().containsKey(player.getUniqueId()) ? craft.getCrewSigns().get(player.getUniqueId()) : getCraftTeleportPoint(craft); + Location telPoint; + if (craft.getCrewSigns().containsKey(player.getUniqueId())){ + telPoint = craft.getCrewSigns().get(player.getUniqueId()); + final Vector[] SHIFTS = {new Vector(1,0,0), new Vector(-1,0,0),new Vector(0,0,1),new Vector(0,0,-1)}; + for (Vector shift : SHIFTS){ + if (!telPoint.add(shift).getBlock().getType().name().endsWith("AIR")){ + continue; + } + telPoint = telPoint.add(shift); + break; + } + } else { + telPoint = getCraftTeleportPoint(craft); + } if (craft.getW() != player.getWorld()) { player.sendMessage(MOVECRAFT_COMMAND_PREFIX + I18nSupport.getInternationalisedString("ManOverboard - Other World")); return true; diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CrewSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CrewSign.java index 7c3f7761c..97a9fd624 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CrewSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CrewSign.java @@ -105,7 +105,12 @@ public final void onPlayerRespawn(PlayerRespawnEvent event) { player.sendMessage(I18nSupport.getInternationalisedString("CrewSign - Respawn")); Location respawnLoc = craft.getCrewSigns().get(player.getUniqueId()); Material test = respawnLoc.getBlock().getType(); - if (Settings.IsLegacy ? test == LegacyUtils.BED_BLOCK : test.name().endsWith("BED")){ + final boolean hasBed = Settings.IsLegacy ? test == LegacyUtils.BED_BLOCK : test.name().endsWith("BED"); + if (Settings.Debug){ + Bukkit.broadcastMessage("Has bed: " + hasBed + ". Found type at " + respawnLoc.toVector() + ": " + test.name()); + } + + if (!hasBed){ return; } event.setRespawnLocation(respawnLoc); From a7b5c7093b6209f6d8e6259f7699b4a66e5fecf0 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Mon, 4 Nov 2019 15:46:34 +0100 Subject: [PATCH 069/304] Fixed invalid skull value in craft files for 1.13 and 1.14 --- modules/Movecraft/src/main/resources/config.yml | 2 +- .../Movecraft/src/main/resources/types/1_14/BigAirship.craft | 2 +- .../Movecraft/src/main/resources/types/1_14/BigSubAirship.craft | 2 +- modules/Movecraft/src/main/resources/types/1_14/Ship.craft | 2 +- .../Movecraft/src/main/resources/types/1_14/SubAirship.craft | 2 +- modules/Movecraft/src/main/resources/types/1_14/Submarine.craft | 2 +- modules/Movecraft/src/main/resources/types/1_14/Turret.craft | 2 +- modules/Movecraft/src/main/resources/types/1_14/airship.craft | 2 +- modules/Movecraft/src/main/resources/types/1_14/airskiff.craft | 2 +- modules/Movecraft/src/main/resources/types/1_14/elevator.craft | 2 +- modules/Movecraft/src/main/resources/types/BigAirship.craft | 2 +- modules/Movecraft/src/main/resources/types/BigSubAirship.craft | 2 +- modules/Movecraft/src/main/resources/types/Ship.craft | 2 +- modules/Movecraft/src/main/resources/types/SubAirship.craft | 2 +- modules/Movecraft/src/main/resources/types/Submarine.craft | 2 +- modules/Movecraft/src/main/resources/types/Turret.craft | 2 +- modules/Movecraft/src/main/resources/types/airship.craft | 2 +- modules/Movecraft/src/main/resources/types/airskiff.craft | 2 +- 18 files changed, 18 insertions(+), 18 deletions(-) diff --git a/modules/Movecraft/src/main/resources/config.yml b/modules/Movecraft/src/main/resources/config.yml index 5c942c95f..8b92a337a 100644 --- a/modules/Movecraft/src/main/resources/config.yml +++ b/modules/Movecraft/src/main/resources/config.yml @@ -4,7 +4,7 @@ SinkRateTicks: 20 SinkCheckTicks: 100 TracerRateTicks: 5 TracerMinDistance: 60 # Minimum distance for tracers to appear -PilotTool: 280 +PilotTool: STICK WorldGuardBlockMoveOnBuildPerm: true WorldGuardBlockSinkOnPVPPerm: true ManOverboardTimeout: 30 diff --git a/modules/Movecraft/src/main/resources/types/1_14/BigAirship.craft b/modules/Movecraft/src/main/resources/types/1_14/BigAirship.craft index 41e655726..35e083103 100644 --- a/modules/Movecraft/src/main/resources/types/1_14/BigAirship.craft +++ b/modules/Movecraft/src/main/resources/types/1_14/BigAirship.craft @@ -67,7 +67,7 @@ allowedBlocks: - cobblestone_wall - mossy_cobblestone_wall - FLOWER_POT - - SKULL + - all_SKULL - all_ANVIL - TRAPPED_CHEST - COMPARATOR diff --git a/modules/Movecraft/src/main/resources/types/1_14/BigSubAirship.craft b/modules/Movecraft/src/main/resources/types/1_14/BigSubAirship.craft index e17c15c51..d53767d19 100644 --- a/modules/Movecraft/src/main/resources/types/1_14/BigSubAirship.craft +++ b/modules/Movecraft/src/main/resources/types/1_14/BigSubAirship.craft @@ -66,7 +66,7 @@ allowedBlocks: - cobblestone_wall - mossy_cobblestone_wall - FLOWER_POT - - SKULL + - all_SKULL - all_ANVIL - TRAPPED_CHEST - COMPARATOR diff --git a/modules/Movecraft/src/main/resources/types/1_14/Ship.craft b/modules/Movecraft/src/main/resources/types/1_14/Ship.craft index 8009b9e14..d59c2f182 100644 --- a/modules/Movecraft/src/main/resources/types/1_14/Ship.craft +++ b/modules/Movecraft/src/main/resources/types/1_14/Ship.craft @@ -66,7 +66,7 @@ allowedBlocks: - cobblestone_wall - mossy_cobblestone_wall - FLOWER_POT - - SKULL + - all_SKULL - all_ANVIL - TRAPPED_CHEST - COMPARATOR diff --git a/modules/Movecraft/src/main/resources/types/1_14/SubAirship.craft b/modules/Movecraft/src/main/resources/types/1_14/SubAirship.craft index eef089525..362e8f353 100644 --- a/modules/Movecraft/src/main/resources/types/1_14/SubAirship.craft +++ b/modules/Movecraft/src/main/resources/types/1_14/SubAirship.craft @@ -66,7 +66,7 @@ allowedBlocks: - cobblestone_wall - mossy_cobblestone_wall - FLOWER_POT - - SKULL + - all_SKULL - all_ANVIL - TRAPPED_CHEST - COMPARATOR diff --git a/modules/Movecraft/src/main/resources/types/1_14/Submarine.craft b/modules/Movecraft/src/main/resources/types/1_14/Submarine.craft index 2d4ce83f5..a16c67ff7 100644 --- a/modules/Movecraft/src/main/resources/types/1_14/Submarine.craft +++ b/modules/Movecraft/src/main/resources/types/1_14/Submarine.craft @@ -66,7 +66,7 @@ allowedBlocks: - cobblestone_wall - mossy_cobblestone_wall - FLOWER_POT - - SKULL + - all_SKULL - all_ANVIL - TRAPPED_CHEST - COMPARATOR diff --git a/modules/Movecraft/src/main/resources/types/1_14/Turret.craft b/modules/Movecraft/src/main/resources/types/1_14/Turret.craft index df8ecccb4..83ed863df 100644 --- a/modules/Movecraft/src/main/resources/types/1_14/Turret.craft +++ b/modules/Movecraft/src/main/resources/types/1_14/Turret.craft @@ -54,7 +54,7 @@ allowedBlocks: - EMERALD_BLOCK - BEACON - FLOWER_POT - - SKULL + - all_SKULL - all_ANVIL - TRAPPED_CHEST - COMPARATOR diff --git a/modules/Movecraft/src/main/resources/types/1_14/airship.craft b/modules/Movecraft/src/main/resources/types/1_14/airship.craft index 9cfd8d352..91d538986 100644 --- a/modules/Movecraft/src/main/resources/types/1_14/airship.craft +++ b/modules/Movecraft/src/main/resources/types/1_14/airship.craft @@ -67,7 +67,7 @@ allowedBlocks: - cobblestone_wall - mossy_cobblestone_wall - FLOWER_POT - - SKULL + - all_SKULL - all_ANVIL - TRAPPED_CHEST - COMPARATOR diff --git a/modules/Movecraft/src/main/resources/types/1_14/airskiff.craft b/modules/Movecraft/src/main/resources/types/1_14/airskiff.craft index d530a91b8..9c866fdee 100644 --- a/modules/Movecraft/src/main/resources/types/1_14/airskiff.craft +++ b/modules/Movecraft/src/main/resources/types/1_14/airskiff.craft @@ -55,7 +55,7 @@ allowedBlocks: - EMERALD_BLOCK - BEACON - FLOWER_POT - - SKULL + - all_SKULL - all_ANVIL - TRAPPED_CHEST - COMPARATOR diff --git a/modules/Movecraft/src/main/resources/types/1_14/elevator.craft b/modules/Movecraft/src/main/resources/types/1_14/elevator.craft index 9cd7b8fe3..9377f8684 100644 --- a/modules/Movecraft/src/main/resources/types/1_14/elevator.craft +++ b/modules/Movecraft/src/main/resources/types/1_14/elevator.craft @@ -55,7 +55,7 @@ allowedBlocks: - EMERALD_BLOCK - BEACON - FLOWER_POT - - SKULL + - all_SKULL - all_ANVIL - TRAPPED_CHEST - COMPARATOR diff --git a/modules/Movecraft/src/main/resources/types/BigAirship.craft b/modules/Movecraft/src/main/resources/types/BigAirship.craft index 618222a0f..4283f3bdd 100644 --- a/modules/Movecraft/src/main/resources/types/BigAirship.craft +++ b/modules/Movecraft/src/main/resources/types/BigAirship.craft @@ -67,7 +67,7 @@ allowedBlocks: - cobblestone_wall - mossy_cobblestone_wall - FLOWER_POT - - SKULL + - all_SKULL - all_ANVIL - TRAPPED_CHEST - COMPARATOR diff --git a/modules/Movecraft/src/main/resources/types/BigSubAirship.craft b/modules/Movecraft/src/main/resources/types/BigSubAirship.craft index 9e0db2d88..66f2d2ea4 100644 --- a/modules/Movecraft/src/main/resources/types/BigSubAirship.craft +++ b/modules/Movecraft/src/main/resources/types/BigSubAirship.craft @@ -66,7 +66,7 @@ allowedBlocks: - cobblestone_wall - mossy_cobblestone_wall - FLOWER_POT - - SKULL + - all_SKULL - all_ANVIL - TRAPPED_CHEST - COMPARATOR diff --git a/modules/Movecraft/src/main/resources/types/Ship.craft b/modules/Movecraft/src/main/resources/types/Ship.craft index 746db3b99..4e26be709 100644 --- a/modules/Movecraft/src/main/resources/types/Ship.craft +++ b/modules/Movecraft/src/main/resources/types/Ship.craft @@ -66,7 +66,7 @@ allowedBlocks: - cobblestone_wall - mossy_cobblestone_wall - FLOWER_POT - - SKULL + - all_SKULL - all_ANVIL - TRAPPED_CHEST - COMPARATOR diff --git a/modules/Movecraft/src/main/resources/types/SubAirship.craft b/modules/Movecraft/src/main/resources/types/SubAirship.craft index 5e48b2b40..3d4904282 100644 --- a/modules/Movecraft/src/main/resources/types/SubAirship.craft +++ b/modules/Movecraft/src/main/resources/types/SubAirship.craft @@ -66,7 +66,7 @@ allowedBlocks: - cobblestone_wall - mossy_cobblestone_wall - FLOWER_POT - - SKULL + - all_SKULL - all_ANVIL - TRAPPED_CHEST - COMPARATOR diff --git a/modules/Movecraft/src/main/resources/types/Submarine.craft b/modules/Movecraft/src/main/resources/types/Submarine.craft index 6dd85af32..4da6dc66d 100644 --- a/modules/Movecraft/src/main/resources/types/Submarine.craft +++ b/modules/Movecraft/src/main/resources/types/Submarine.craft @@ -67,7 +67,7 @@ allowedBlocks: - cobblestone_wall - mossy_cobblestone_wall - FLOWER_POT - - SKULL + - all_SKULL - all_ANVIL - TRAPPED_CHEST - COMPARATOR diff --git a/modules/Movecraft/src/main/resources/types/Turret.craft b/modules/Movecraft/src/main/resources/types/Turret.craft index 77a64930a..f0e1b47ac 100644 --- a/modules/Movecraft/src/main/resources/types/Turret.craft +++ b/modules/Movecraft/src/main/resources/types/Turret.craft @@ -54,7 +54,7 @@ allowedBlocks: - EMERALD_BLOCK - BEACON - FLOWER_POT - - SKULL + - all_SKULL - all_ANVIL - TRAPPED_CHEST - COMPARATOR diff --git a/modules/Movecraft/src/main/resources/types/airship.craft b/modules/Movecraft/src/main/resources/types/airship.craft index cb1801141..b596ddbd9 100644 --- a/modules/Movecraft/src/main/resources/types/airship.craft +++ b/modules/Movecraft/src/main/resources/types/airship.craft @@ -67,7 +67,7 @@ allowedBlocks: - cobblestone_wall - mossy_cobblestone_wall - FLOWER_POT - - SKULL + - all_SKULL - all_ANVIL - TRAPPED_CHEST - COMPARATOR diff --git a/modules/Movecraft/src/main/resources/types/airskiff.craft b/modules/Movecraft/src/main/resources/types/airskiff.craft index 955fcc468..d9771c0b7 100644 --- a/modules/Movecraft/src/main/resources/types/airskiff.craft +++ b/modules/Movecraft/src/main/resources/types/airskiff.craft @@ -55,7 +55,7 @@ allowedBlocks: - EMERALD_BLOCK - BEACON - FLOWER_POT - - SKULL + - all_SKULL - all_ANVIL - TRAPPED_CHEST - COMPARATOR From 2f48d104d2c020eecc4f0fdfa029adbb88737170 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Tue, 5 Nov 2019 17:38:45 +0100 Subject: [PATCH 070/304] Replaced javafx.util.Pair with AbstractMap.SimpleImmutableEntry in 1.14 World Handler --- .../movecraft/compat/v1_14_R1/NextTickProvider.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/modules/v1_14_R1/src/main/java/net/countercraft/movecraft/compat/v1_14_R1/NextTickProvider.java b/modules/v1_14_R1/src/main/java/net/countercraft/movecraft/compat/v1_14_R1/NextTickProvider.java index 614c5fd4d..cc9909c03 100644 --- a/modules/v1_14_R1/src/main/java/net/countercraft/movecraft/compat/v1_14_R1/NextTickProvider.java +++ b/modules/v1_14_R1/src/main/java/net/countercraft/movecraft/compat/v1_14_R1/NextTickProvider.java @@ -1,6 +1,5 @@ package net.countercraft.movecraft.compat.v1_14_R1; -import javafx.util.Pair; import net.minecraft.server.v1_14_R1.*; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -9,7 +8,7 @@ import java.util.*; public class NextTickProvider { - private Map,Collection>> tickMap = new HashMap<>(); + private Map,Collection>> tickMap = new HashMap<>(); private boolean isRegistered(@NotNull WorldServer world){ return tickMap.containsKey(world); @@ -30,14 +29,14 @@ private void registerWorld(@NotNull WorldServer world){ } catch (IllegalAccessException | IllegalArgumentException | NoSuchFieldException | SecurityException e1) { e1.printStackTrace(); } - tickMap.put(world, new Pair<>(nextTickList,W)); + tickMap.put(world, new AbstractMap.SimpleImmutableEntry<>(nextTickList,W)); } @Nullable public NextTickListEntry getNextTick(@NotNull WorldServer world,@NotNull BlockPosition position){ if(!isRegistered(world)) registerWorld(world); - Pair, Collection> listPair = tickMap.get(world); + AbstractMap.SimpleImmutableEntry, Collection> listPair = tickMap.get(world); for(Iterator iterator = listPair.getKey().iterator(); iterator.hasNext();) { NextTickListEntry listEntry = iterator.next(); if (position.equals(listEntry.a)) { From 7dc74d99250be912ebabe0bfd1505cce3c382720 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Thu, 7 Nov 2019 17:42:33 +0100 Subject: [PATCH 071/304] Replaced numerical IDs in config for 1.13+, fixes #18 --- .../Movecraft/src/main/resources/config.yml | 138 ++++++++++++------ 1 file changed, 94 insertions(+), 44 deletions(-) diff --git a/modules/Movecraft/src/main/resources/config.yml b/modules/Movecraft/src/main/resources/config.yml index 8b92a337a..776576016 100644 --- a/modules/Movecraft/src/main/resources/config.yml +++ b/modules/Movecraft/src/main/resources/config.yml @@ -38,48 +38,98 @@ AssaultRequiredOwnersOnline: 1 # At least this many owners must be online for th AssaultOwnerWeightPercent: 1.0 # Percentage of each Owner's balance (under the maximum) to include in the total cost & damages (Can be greater than 100) AssaultMemberWeightPercent: 1.0 # Percentage of each Member's balance (under the maximum) to include in the total cost & damages (Can be greater than 100) AssaultDestroyableBlocks: # these blocks will be removed if destroyed in assault. Other blocks will not be removed, but still count for damages. Don't include craft flyblocks, or blocks with metadata, or you can have issues. - - 1 - - 2 - - 3 - - 4 - - 12 - - 13 - - 15 - - 16 - - 18 - - 19 - - 24 - - 31 - - 37 - - 38 - - 39 - - 40 - - 46 - - 48 - - 60 - - 67 - - 73 - - 74 - - 78 - - 79 - - 80 - - 81 - - 98 - - 108 - - 128 - - 129 - - 161 - - 162 - - 163 - - 168 - - 169 - - 174 - - 175 - - 179 - - 180 - - 181 - - 182 - - 212 + - stone + - diorite + - polished_diorite + - granite + - polished_granite + - andesite + - polished_andesite + - grass_block + - dirt + - coarse_dirt + - podzol + - cobblestone + - sand + - red_sand + - gravel + - gold_ore + - iron_ore + - oak_leaves + - jungle_leaves + - birch_leaves + - spruce_leaves + - sponge + - wet_sponge + - sandstone + - smooth_sandstone + - cut_sandstone + - chiseled_sandstone + - grass + - fern + - tall_grass + - large_fern + - dandelion + - poppy + - blue_orchid + - allium + - azure_bluet + - red_tulip + - orange_tulip + - white_tulip + - pink_tulip + - oxeye_daisy + - cornflower + - lily_of_the_valley + - wither_rose + - sunflower + - lilac + - rose_bush + - peony + - brown_mushroom + - red_mushroom + - tnt + - mossy_cobblestone + - farmland + - cobblestone_stairs + - redstone_ore + - snow + - ice + - snow_block + - cactus + - stone_bricks + - cracked_stone_bricks + - mossy_stone_bricks + - chiseled_stone_bricks + - brick_stairs + - stone_stairs + - diorite_stairs + - polished_diorite_stairs + - andesite_stairs + - polished_andesite_stairs + - granite_stairs + - polished_granite_stairs + - sandstone_stairs + - smooth_sandstone_stairs + - emerald_ore + - dark_oak_leaves + - acacia_leaves + - acacia_log + - dark_oak_log + - acacia_stairs + - dark_oak_stairs + - prismarine + - prismarine_stairs + - dark_prismarine + - dark_prismarine_stairs + - sea_lantern + - packed_ice + - red_sandstone + - red_smooth_sandstone + - red_sandstone_stairs + - red_smooth_sandstone_stairs + - sandstone_slab + - ice SiegeEnable: true DisableShadowBlocks: # These blocks will not cast shadows. This improves the speed of moving ships of these blocks immensely. - 26 @@ -105,8 +155,8 @@ WGCustomFlagsUseMoveFlag: false WGCustomFlagsUseRotateFlag: false WGCustomFlagsUseSinkFlag: false DurabilityOverride: - 121: 80 - 206: 80 + end_stone: 80 + end_stone_bricks: 80 TownyBlockMoveOnSwitchPerm: false TownyBlockSinkOnNoPVP: false TownyWorldHeightLimits: From 1aa2465281cdbce2e1e5d682a9cecc79f5e4b0ae Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Mon, 11 Nov 2019 15:21:19 +0100 Subject: [PATCH 072/304] Rewrote entity movement and fixed a bug causing aircraft to be stuck on ground --- .../async/rotation/RotationTask.java | 3 +- .../async/translation/TranslationTask.java | 11 +- .../countercraft/movecraft/craft/ICraft.java | 5 - .../update/EntityRotateUpdateCommand.java | 72 +++++++++++ .../update/EntityTranslateUpdateCommand.java | 117 ++++++++++++++++++ .../update/EntityUpdateCommand.java | 85 ------------- .../movecraft/sync/EntityProcessor.java | 81 ------------ 7 files changed, 194 insertions(+), 180 deletions(-) create mode 100644 modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/EntityRotateUpdateCommand.java create mode 100644 modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/EntityTranslateUpdateCommand.java delete mode 100644 modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/EntityUpdateCommand.java delete mode 100644 modules/Movecraft/src/main/java/net/countercraft/movecraft/sync/EntityProcessor.java diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/rotation/RotationTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/rotation/RotationTask.java index c62db3577..74d1a4c98 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/rotation/RotationTask.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/rotation/RotationTask.java @@ -35,6 +35,7 @@ import net.countercraft.movecraft.events.CraftRotateEvent; import net.countercraft.movecraft.localisation.I18nSupport; import net.countercraft.movecraft.mapUpdater.update.CraftRotateCommand; +import net.countercraft.movecraft.mapUpdater.update.EntityRotateUpdateCommand; import net.countercraft.movecraft.mapUpdater.update.UpdateCommand; import net.countercraft.movecraft.utils.*; import org.bukkit.Bukkit; @@ -211,7 +212,7 @@ public void run() { updates.add(new CraftRotateCommand(getCraft(),originPoint, rotation)); - + updates.add(new EntityRotateUpdateCommand(craft, oldHitBox, rotation, originPoint)); if (getCraft().getCruising()) { if (rotation == Rotation.ANTICLOCKWISE) { diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java index ae9c8bc5c..5daeee9cd 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java @@ -131,7 +131,7 @@ protected void execute() { int testY = minY; while (testY > 0){ testY--; - if (craft.getW().getBlockAt(middle.getX(),testY,middle.getZ()).getType().name().endsWith("AIR")) + if (!craft.getW().getBlockAt(middle.getX(),testY,middle.getZ()).getType().name().endsWith("AIR")) break; } if (minY - testY > craft.getType().getMaxHeightAboveGround()) { @@ -156,6 +156,7 @@ protected void execute() { dy = -1; } } else if (!onGround){ + dy = -1; } } @@ -303,12 +304,6 @@ public void run() { } } //END OF: if (blockObstructed) } - for (UpdateCommand update : getUpdates()){ - if (!(update instanceof EntityUpdateCommand)) - continue; - EntityUpdateCommand eUp = (EntityUpdateCommand) update; - eUp.setY(dy); - } if (!craft.getType().getCanHoverOverWater()){ MovecraftLocation test = new MovecraftLocation(newHitBox.getMidPoint().getX(), newHitBox.getMinY(), newHitBox.getMidPoint().getZ()); @@ -417,7 +412,7 @@ public void run() { } updates.add(new CraftTranslateCommand(craft, new MovecraftLocation(dx, dy, dz))); - + updates.add(new EntityTranslateUpdateCommand(craft, dx, dy, dz)); captureYield(harvestedBlocks); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/ICraft.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/ICraft.java index 8cb80e62d..077e14d01 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/ICraft.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/ICraft.java @@ -7,7 +7,6 @@ import net.countercraft.movecraft.async.rotation.RotationTask; import net.countercraft.movecraft.async.translation.TranslationTask; import net.countercraft.movecraft.localisation.I18nSupport; -import net.countercraft.movecraft.sync.EntityProcessor; import org.bukkit.World; import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; @@ -85,8 +84,6 @@ public void translate(int dx, int dy, int dz) { TranslationTask task = new TranslationTask(this, dx, dy, dz); - - task.getUpdates().addAll(EntityProcessor.translateEntities(this, dx, dy, dz)); Movecraft.getInstance().getAsyncManager().submitTask(task, this); } @@ -99,14 +96,12 @@ public void rotate(Rotation rotation, MovecraftLocation originPoint) { } setLastRotateTime(System.nanoTime()); RotationTask task = new RotationTask(this, originPoint, rotation, this.getW()); - task.getUpdates().addAll(EntityProcessor.rotateEntities(this, originPoint, rotation)); Movecraft.getInstance().getAsyncManager().submitTask(task, this); } @Override public void rotate(Rotation rotation, MovecraftLocation originPoint, boolean isSubCraft) { RotationTask task = new RotationTask(this, originPoint, rotation, this.getW(), isSubCraft); - task.getUpdates().addAll(EntityProcessor.rotateEntities(this, originPoint, rotation)); Movecraft.getInstance().getAsyncManager().submitTask(task, this); } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/EntityRotateUpdateCommand.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/EntityRotateUpdateCommand.java new file mode 100644 index 000000000..57fbbb5c5 --- /dev/null +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/EntityRotateUpdateCommand.java @@ -0,0 +1,72 @@ +package net.countercraft.movecraft.mapUpdater.update; + +import net.countercraft.movecraft.MovecraftLocation; +import net.countercraft.movecraft.Rotation; +import net.countercraft.movecraft.craft.Craft; +import net.countercraft.movecraft.utils.HitBox; +import net.countercraft.movecraft.utils.MathUtils; +import org.bukkit.Location; +import org.bukkit.entity.Entity; +import org.bukkit.entity.EntityType; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; + +public class EntityRotateUpdateCommand extends UpdateCommand { + + private final Craft craft; + private final HitBox oldHitBox; + private final Rotation rotation; + private final MovecraftLocation originPoint; + + public EntityRotateUpdateCommand(Craft craft, HitBox oldHitBox, Rotation rotation, MovecraftLocation originPoint) { + this.craft = craft; + this.oldHitBox = oldHitBox; + this.rotation = rotation; + this.originPoint = originPoint; + } + + + @Override + public void doUpdate() { + final Map entities = getEntitiesOnCraft(); + for (Entity entity : entities.keySet()){ + final Location tp = entities.get(entity); + assert tp != null; + entity.teleport(tp); + } + + + } + private Map getEntitiesOnCraft() { + HashMap ret = new HashMap<>(); + if (oldHitBox.isEmpty()) + return Collections.emptyMap(); + Location tOP = new Location(craft.getW(), originPoint.getX(), originPoint.getY(), originPoint.getZ()); + tOP.setX(tOP.getBlockX() + 0.5); + tOP.setZ(tOP.getBlockZ() + 0.5); + + if (craft.getType().getMoveEntities() && !(craft.getSinking() && craft.getType().getOnlyMovePlayers())) { + Location midpoint = new Location( + craft.getW(), + (oldHitBox.getMaxX() + oldHitBox.getMinX())/2.0, + (oldHitBox.getMaxY() + oldHitBox.getMinY())/2.0, + (oldHitBox.getMaxZ() + oldHitBox.getMinZ())/2.0); + for(Entity entity : craft.getW().getNearbyEntities(midpoint, oldHitBox.getXLength()/2.0 + 1, oldHitBox.getYLength()/2.0 + 2, oldHitBox.getZLength()/2.0 + 1)){ + if ((entity.getType() == EntityType.PLAYER && !craft.getSinking()) || !craft.getType().getOnlyMovePlayers()) { + // Player is onboard this craft + + Location adjustedPLoc = entity.getLocation().subtract(tOP); + + double[] rotatedCoords = MathUtils.rotateVecNoRound(rotation, adjustedPLoc.getX(), adjustedPLoc.getZ()); + float newYaw = rotation == Rotation.CLOCKWISE ? 90F : -90F; + Location tpLoc = new Location(craft.getW(), rotatedCoords[0] + tOP.getX(), entity.getLocation().getY(), rotatedCoords[1] + tOP.getZ(), newYaw + entity.getLocation().getYaw() , entity.getLocation().getPitch()); + ret.put(entity, tpLoc); + + } + } + } + return ret; + } +} diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/EntityTranslateUpdateCommand.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/EntityTranslateUpdateCommand.java new file mode 100644 index 000000000..32c214efd --- /dev/null +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/EntityTranslateUpdateCommand.java @@ -0,0 +1,117 @@ +/* + * This file is part of Movecraft. + * + * Movecraft is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Movecraft is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Movecraft. If not, see . + */ + +package net.countercraft.movecraft.mapUpdater.update; + +import net.countercraft.movecraft.craft.Craft; +import net.countercraft.movecraft.utils.HitBox; +import net.countercraft.movecraft.utils.TeleportUtils; +import org.bukkit.Location; +import org.bukkit.entity.Entity; +import org.bukkit.entity.EntityType; +import org.bukkit.entity.Player; + +import java.util.Collection; +import java.util.HashSet; +import java.util.Objects; +import java.util.Set; + +/** + * Class that stores the data about a single blocks changes to the map in an unspecified world. The world is retrieved contextually from the submitting craft. + */ +public class EntityTranslateUpdateCommand extends UpdateCommand { + private final Craft craft; + private final double x; + private double y; + private final double z; + private final float yaw; + private final float pitch; + + public EntityTranslateUpdateCommand(Craft craft, double x, double y, double z) { + this.craft = craft; + this.x = x; + this.y = y; + this.z = z; + this.yaw = 0; + this.pitch = 0; + } + + + public Craft getCraft() { + return craft; + } + + @Override + public void doUpdate() { + if (craft.getHitBox().isEmpty()){ + return; + } + for (Entity entity : getEntitiesOnCraft()){ + Location playerLoc = entity.getLocation(); + if (!(entity instanceof Player) || yaw > .01 || pitch > .01 || yaw < -.01 || pitch < -.01) { + entity.teleport(new Location(entity.getWorld(), x + playerLoc.getX(),y + playerLoc.getY(),z + playerLoc.getZ(),yaw + playerLoc.getYaw(),pitch + playerLoc.getPitch())); + return; + } + //Movecraft.getInstance().getWorldHandler().addPlayerLocation((Player) entity,x,y,z,yaw,pitch); + TeleportUtils.teleport((Player) entity, new Location(entity.getWorld(), playerLoc.getX() + x, playerLoc.getY() + y, playerLoc.getZ() + z)); + } + + + } + + public void setY(int y){ + this.y = y; + } + + @Override + public int hashCode() { + return Objects.hash(craft, x, y, z, pitch, yaw); + } + + @Override + public boolean equals(Object obj) { + if(!(obj instanceof EntityTranslateUpdateCommand)){ + return false; + } + EntityTranslateUpdateCommand other = (EntityTranslateUpdateCommand) obj; + return this.x == other.x && + this.y == other.y && + this.z == other.z && + this.pitch == other.pitch && + this.yaw == other.yaw && + this.craft.equals(other.craft); + } + + private Collection getEntitiesOnCraft(){ + final HitBox oldHitBox = craft.getHitBox(); + final Location midpoint = oldHitBox.getMidPoint().toBukkit(craft.getW()); + final Collection entities = craft.getW().getNearbyEntities(midpoint, oldHitBox.getXLength() / 2.0 + 1, oldHitBox.getYLength() / 2.0 + 2, oldHitBox.getZLength() / 2.0 + 1); + final Set toMove = new HashSet<>(); + for (Entity entity : entities){ + if (entity.getType() == EntityType.PLAYER) { + if(craft.getSinking()){ + continue; + } + toMove.add(entity); + } else if (!craft.getType().getOnlyMovePlayers() || entity.getType() == EntityType.PRIMED_TNT) { + toMove.add(entity); + } + } + return toMove; + } +} + diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/EntityUpdateCommand.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/EntityUpdateCommand.java deleted file mode 100644 index 7d5433a10..000000000 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/EntityUpdateCommand.java +++ /dev/null @@ -1,85 +0,0 @@ -/* - * This file is part of Movecraft. - * - * Movecraft is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Movecraft is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Movecraft. If not, see . - */ - -package net.countercraft.movecraft.mapUpdater.update; - -import net.countercraft.movecraft.utils.TeleportUtils; -import org.bukkit.Location; -import org.bukkit.entity.Entity; -import org.bukkit.entity.Player; - -import java.util.Objects; - -/** - * Class that stores the data about a single blocks changes to the map in an unspecified world. The world is retrieved contextually from the submitting craft. - */ -public class EntityUpdateCommand extends UpdateCommand { - private final Entity entity; - private final double x; - private double y; - private final double z; - private final float yaw; - private final float pitch; - - public EntityUpdateCommand(Entity entity, double x, double y, double z, float yaw, float pitch) { - this.entity = entity; - this.x = x; - this.y = y; - this.z = z; - this.yaw = yaw; - this.pitch = pitch; - } - - public Entity getEntity() { - return entity; - } - - @Override - public void doUpdate() { - Location playerLoc = entity.getLocation(); - if (!(entity instanceof Player) || yaw > .01 || pitch > .01 || yaw < -.01 || pitch < -.01) { - entity.teleport(new Location(entity.getWorld(), x + playerLoc.getX(),y + playerLoc.getY(),z + playerLoc.getZ(),yaw + playerLoc.getYaw(),pitch + playerLoc.getPitch())); - return; - } - //Movecraft.getInstance().getWorldHandler().addPlayerLocation((Player) entity,x,y,z,yaw,pitch); - TeleportUtils.teleport((Player) entity, new Location(entity.getWorld(), playerLoc.getX() + x, playerLoc.getY() + y, playerLoc.getZ() + z)); - } - - public void setY(int y){ - this.y = y; - } - - @Override - public int hashCode() { - return Objects.hash(entity.getUniqueId(), x, y, z, pitch, yaw); - } - - @Override - public boolean equals(Object obj) { - if(!(obj instanceof EntityUpdateCommand)){ - return false; - } - EntityUpdateCommand other = (EntityUpdateCommand) obj; - return this.x == other.x && - this.y == other.y && - this.z == other.z && - this.pitch == other.pitch && - this.yaw == other.yaw && - this.entity.equals(other.entity); - } -} - diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sync/EntityProcessor.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sync/EntityProcessor.java deleted file mode 100644 index 64a0335b8..000000000 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sync/EntityProcessor.java +++ /dev/null @@ -1,81 +0,0 @@ -package net.countercraft.movecraft.sync; - -import net.countercraft.movecraft.MovecraftLocation; -import net.countercraft.movecraft.Rotation; -import net.countercraft.movecraft.craft.Craft; -import net.countercraft.movecraft.mapUpdater.update.EntityUpdateCommand; -import net.countercraft.movecraft.mapUpdater.update.UpdateCommand; -import net.countercraft.movecraft.utils.HashHitBox; -import net.countercraft.movecraft.utils.MathUtils; -import org.bukkit.Location; -import org.bukkit.entity.Entity; -import org.bukkit.entity.EntityType; - -import java.util.Collections; -import java.util.HashSet; -import java.util.Set; - -public class EntityProcessor { - - private EntityProcessor(){ - - } - public static Set translateEntities(Craft craft, int dx, int dy, int dz){ - if (!craft.getType().getMoveEntities()) - return Collections.emptySet(); - HashHitBox oldHitBox = craft.getHitBox(); - final HashSet updateCmds = new HashSet<>(); - if (oldHitBox.isEmpty()) - return updateCmds; - - Location midpoint = new Location( - craft.getW(), - (oldHitBox.getMaxX() + oldHitBox.getMinX())/2.0, - (oldHitBox.getMaxY() + oldHitBox.getMinY())/2.0, - (oldHitBox.getMaxZ() + oldHitBox.getMinZ())/2.0); - for (Entity entity : craft.getW().getNearbyEntities(midpoint, oldHitBox.getXLength() / 2.0 + 1, oldHitBox.getYLength() / 2.0 + 2, oldHitBox.getZLength() / 2.0 + 1)) { - if (entity.getType() == EntityType.PLAYER) { - if(craft.getSinking()){ - continue; - } - EntityUpdateCommand eUp = new EntityUpdateCommand(entity, dx, dy, dz, 0, 0); - updateCmds.add(eUp); - } else if (!craft.getType().getOnlyMovePlayers() || entity.getType() == EntityType.PRIMED_TNT) { - EntityUpdateCommand eUp = new EntityUpdateCommand(entity, dx, dy, dz, 0, 0); - updateCmds.add(eUp); - } - } - return updateCmds; - } - - public static Set rotateEntities(Craft craft, MovecraftLocation originPoint, Rotation rotation){ - HashHitBox oldHitBox = craft.getHitBox(); - final HashSet updates = new HashSet<>(); - if (oldHitBox.isEmpty()) - return updates; - Location tOP = new Location(craft.getW(), originPoint.getX(), originPoint.getY(), originPoint.getZ()); - tOP.setX(tOP.getBlockX() + 0.5); - tOP.setZ(tOP.getBlockZ() + 0.5); - - if (craft.getType().getMoveEntities() && !(craft.getSinking() && craft.getType().getOnlyMovePlayers())) { - Location midpoint = new Location( - craft.getW(), - (oldHitBox.getMaxX() + oldHitBox.getMinX())/2.0, - (oldHitBox.getMaxY() + oldHitBox.getMinY())/2.0, - (oldHitBox.getMaxZ() + oldHitBox.getMinZ())/2.0); - for(Entity entity : craft.getW().getNearbyEntities(midpoint, oldHitBox.getXLength()/2.0 + 1, oldHitBox.getYLength()/2.0 + 2, oldHitBox.getZLength()/2.0 + 1)){ - if ((entity.getType() == EntityType.PLAYER && !craft.getSinking()) || !craft.getType().getOnlyMovePlayers()) { - // Player is onboard this craft - - Location adjustedPLoc = entity.getLocation().subtract(tOP); - - double[] rotatedCoords = MathUtils.rotateVecNoRound(rotation, adjustedPLoc.getX(), adjustedPLoc.getZ()); - float newYaw = rotation == Rotation.CLOCKWISE ? 90F : -90F; - EntityUpdateCommand eUp = new EntityUpdateCommand(entity, rotatedCoords[0] + tOP.getX() - entity.getLocation().getX(), 0, rotatedCoords[1] + tOP.getZ() - entity.getLocation().getZ(), newYaw, 0); - updates.add(eUp); - } - } - } - return updates; - } -} From 626ea9afefc0e5e69e13d07cd54dc78a24791917 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Tue, 12 Nov 2019 15:51:04 +0100 Subject: [PATCH 073/304] Remove redundant/duplicate code --- .../movecraft/craft/CraftType.java | 32 ++++++++----------- 1 file changed, 13 insertions(+), 19 deletions(-) diff --git a/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java b/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java index a591e56b3..3466f3f9d 100644 --- a/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java +++ b/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java @@ -22,7 +22,6 @@ import net.countercraft.movecraft.utils.BlockLimitManager; import org.bukkit.Bukkit; import org.bukkit.Material; -import org.bukkit.entity.EntityType; import org.bukkit.potion.PotionEffect; import org.bukkit.potion.PotionEffectType; import org.jetbrains.annotations.NotNull; @@ -384,7 +383,6 @@ public CraftType(File f) { Material mat = Material.getMaterial(((String) i).toUpperCase()); harvesterBladeBlocks.add(mat); } else { - Integer typeID = (Integer) i; Material mat = Material.getMaterial((Integer) i); harvesterBladeBlocks.add(mat); } @@ -418,25 +416,21 @@ public CraftType(File f) { allowVerticalTakeoffAndLanding = true; } - if(!blockedByWater){ - passthroughBlocks.add(Material.WATER); - passthroughBlocks.add(Material.STATIONARY_WATER); - } - forbiddenHoverOverBlocks = new HashSet<>(); - if (data.containsKey("forbiddenHoverOverBlocks")){ - final ArrayList objList = (ArrayList) data.get("forbiddenHoverOverBlocks"); - for (Object i : objList){ - if (i instanceof Integer){ - forbiddenHoverOverBlocks.add(Material.getMaterial((int) i)); - } else if (i instanceof String){ - forbiddenHoverOverBlocks.add(Material.getMaterial(((String) i).toUpperCase())); + forbiddenHoverOverBlocks = new HashSet<>(); + if (data.containsKey("forbiddenHoverOverBlocks")){ + final ArrayList objList = (ArrayList) data.get("forbiddenHoverOverBlocks"); + for (Object i : objList){ + if (i instanceof Integer){ + forbiddenHoverOverBlocks.add(Material.getMaterial((int) i)); + } else if (i instanceof String){ + forbiddenHoverOverBlocks.add(Material.getMaterial(((String) i).toUpperCase())); + } } } - } - if (!canHoverOverWater){ - forbiddenHoverOverBlocks.add(Material.WATER); - forbiddenHoverOverBlocks.add(Material.STATIONARY_WATER); - } + if (!canHoverOverWater){ + forbiddenHoverOverBlocks.add(Material.WATER); + forbiddenHoverOverBlocks.add(Material.STATIONARY_WATER); + } if (data.containsKey("dynamicLagSpeedFactor")) { From 53b29fcc1b64f459771de6ec176a3ff9a526175b Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Wed, 13 Nov 2019 11:41:24 +0100 Subject: [PATCH 074/304] Waterlogging is now processed in translation/rotation tasks --- .../movecraft/async/AsyncManager.java | 9 --- .../async/rotation/RotationTask.java | 4 + .../async/translation/TranslationTask.java | 3 + .../update/WaterlogUpdateCommand.java | 73 +++++++++---------- .../movecraft/craft/CraftType.java | 7 +- 5 files changed, 48 insertions(+), 48 deletions(-) diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java index 46ce4bb21..970d67528 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java @@ -770,12 +770,6 @@ private void processFireballs() { } } - private void processWaterlogging(){ - for (Craft c : CraftManager.getInstance()){ - - } - } - private Craft fastNearestCraftToLoc(Location loc) { Craft ret = null; long closestDistSquared = 1000000000L; @@ -1092,9 +1086,6 @@ public void run() { processTracers(); processFireballs(); processTNTContactExplosives(); - if (!Settings.IsLegacy) { - processWaterlogging(); - } processFadingBlocks(); processDetection(); processAlgorithmQueue(); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/rotation/RotationTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/rotation/RotationTask.java index 74d1a4c98..8378bd9ca 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/rotation/RotationTask.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/rotation/RotationTask.java @@ -37,6 +37,7 @@ import net.countercraft.movecraft.mapUpdater.update.CraftRotateCommand; import net.countercraft.movecraft.mapUpdater.update.EntityRotateUpdateCommand; import net.countercraft.movecraft.mapUpdater.update.UpdateCommand; +import net.countercraft.movecraft.mapUpdater.update.WaterlogUpdateCommand; import net.countercraft.movecraft.utils.*; import org.bukkit.Bukkit; import org.bukkit.Location; @@ -213,6 +214,9 @@ public void run() { updates.add(new CraftRotateCommand(getCraft(),originPoint, rotation)); updates.add(new EntityRotateUpdateCommand(craft, oldHitBox, rotation, originPoint)); + if (!Settings.IsLegacy){ + updates.add(new WaterlogUpdateCommand(craft)); + } if (getCraft().getCruising()) { if (rotation == Rotation.ANTICLOCKWISE) { diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java index ba2cf67bc..7b18df742 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java @@ -413,6 +413,9 @@ public void run() { updates.add(new CraftTranslateCommand(craft, new MovecraftLocation(dx, dy, dz))); updates.add(new EntityTranslateUpdateCommand(craft, dx, dy, dz)); + if (!Settings.IsLegacy){ + updates.add(new WaterlogUpdateCommand(craft)); + } captureYield(harvestedBlocks); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/WaterlogUpdateCommand.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/WaterlogUpdateCommand.java index e29c80ae8..cd2a2f494 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/WaterlogUpdateCommand.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/WaterlogUpdateCommand.java @@ -1,21 +1,29 @@ package net.countercraft.movecraft.mapUpdater.update; -import net.countercraft.movecraft.Movecraft; import net.countercraft.movecraft.MovecraftLocation; import net.countercraft.movecraft.craft.Craft; import net.countercraft.movecraft.utils.HashHitBox; +import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.block.Block; import org.bukkit.block.data.Bisected; import org.bukkit.block.data.Waterlogged; +import org.bukkit.block.data.type.Slab; import org.bukkit.block.data.type.TrapDoor; -import org.bukkit.scheduler.BukkitRunnable; +import org.bukkit.util.Vector; public class WaterlogUpdateCommand extends UpdateCommand{ private final Craft craft; + private final Vector[] SHIFTS = {new Vector(0,1,0), + new Vector(0, -1, 0), + new Vector(1, 0, 0), + new Vector(-1, 0, 0), + new Vector(0, 0, 1), + new Vector(0, 0, -1)}; public WaterlogUpdateCommand(Craft craft){ this.craft = craft; } + @Override public void doUpdate() { HashHitBox hitBox = craft.getHitBox(); @@ -24,64 +32,53 @@ public void doUpdate() { if (!(b.getBlockData() instanceof Waterlogged)){ continue; } - BukkitRunnable runnable = null; Waterlogged wLog = (Waterlogged) b.getBlockData(); if (b.getY() > craft.getWaterLine()){ - runnable = new BukkitRunnable() { - @Override - public void run() { - wLog.setWaterlogged(false); - } - }; - runnable.runTask(Movecraft.getInstance()); + wLog.setWaterlogged(false); + b.setBlockData(wLog); continue; } if (wLog instanceof TrapDoor){ TrapDoor tDoor = (TrapDoor) wLog; if (tDoor.getHalf() == Bisected.Half.BOTTOM && b.getRelative(0,1,0).getType() == Material.WATER){ - runnable = new BukkitRunnable() { - @Override - public void run() { - tDoor.setWaterlogged(true); - } - }; + tDoor.setWaterlogged(true); } if (tDoor.getHalf() == Bisected.Half.TOP && b.getRelative(0,-1,0).getType() == Material.WATER){ - runnable = new BukkitRunnable() { - @Override - public void run() { - tDoor.setWaterlogged(true); - } - }; + tDoor.setWaterlogged(true); } if (b.getRelative(tDoor.getFacing().getOppositeFace()).getType() == Material.WATER){ - runnable = new BukkitRunnable() { - @Override - public void run() { - tDoor.setWaterlogged(true); + tDoor.setWaterlogged(true); + } + b.setBlockData(tDoor); + } else if (wLog instanceof Slab){ + Slab slab = (Slab) wLog; + if (slab.getType() == Slab.Type.TOP){ + for (Vector shift : SHIFTS){ + final Location testLoc = b.getLocation().add(shift); + if (shift.getY() == 1){ + continue; } - }; + if (!(testLoc.getBlock().getBlockData() instanceof Waterlogged)) { + continue; + } + slab.setWaterlogged(true); + b.setBlockData(slab); + break; + } } - } else { + } + else { if (b.getRelative(0,1,0).getType() == Material.WATER || b.getRelative(0,-1,0).getType() == Material.WATER || b.getRelative(0,0,1).getType() == Material.WATER || b.getRelative(0,0,-1).getType() == Material.WATER || b.getRelative(1,0,0).getType() == Material.WATER || b.getRelative(-1,0,0).getType() == Material.WATER ){ - runnable = new BukkitRunnable() { - @Override - public void run() { - wLog.setWaterlogged(true); - } - }; - + wLog.setWaterlogged(true); + b.setBlockData(wLog); } } - if (runnable == null) - return; - runnable.runTask(Movecraft.getInstance()); } } } diff --git a/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java b/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java index 3466f3f9d..1e07ded12 100644 --- a/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java +++ b/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java @@ -429,7 +429,12 @@ public CraftType(File f) { } if (!canHoverOverWater){ forbiddenHoverOverBlocks.add(Material.WATER); - forbiddenHoverOverBlocks.add(Material.STATIONARY_WATER); + if (Settings.IsLegacy){ + forbiddenHoverOverBlocks.add(Material.STATIONARY_WATER); + } else { + forbiddenHoverOverBlocks.add(Material.getMaterial("BUBBLE_COLUMN")); + } + } From bb455764a424b803b160a39bfc1efcf9811aa7ad Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Sat, 16 Nov 2019 02:14:54 +0100 Subject: [PATCH 075/304] Waterlogging is moved back to AsyncManager and has been recoded to not compromise on performance. Additionally, some fixes have been done to example craft type files --- .../movecraft/async/AsyncManager.java | 62 +++++++++++++ .../async/rotation/RotationTask.java | 5 +- .../async/translation/TranslationTask.java | 83 +++++++++-------- .../movecraft/craft/CraftManager.java | 8 +- .../update/HarvestBlockUpdateCommand.java | 4 + .../update/WaterlogUpdateCommand.java | 89 ++++--------------- .../movecraft/utils/WaterlogUtils.java | 63 +++++++++++++ .../localisation/movecraftlang_en.properties | 1 + .../resources/types/1_14/LaunchTorpedo.craft | 6 ++ .../main/resources/types/1_14/Turret.craft | 2 - .../main/resources/types/LaunchTorpedo.craft | 6 ++ .../src/main/resources/types/Turret.craft | 2 - .../movecraft/craft/CraftType.java | 33 +++++-- 13 files changed, 236 insertions(+), 128 deletions(-) create mode 100644 modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/HarvestBlockUpdateCommand.java create mode 100644 modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/WaterlogUtils.java diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java index 970d67528..ffbed8a9b 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java @@ -33,10 +33,17 @@ import net.countercraft.movecraft.mapUpdater.MapUpdateManager; import net.countercraft.movecraft.mapUpdater.update.BlockCreateCommand; import net.countercraft.movecraft.mapUpdater.update.UpdateCommand; +import net.countercraft.movecraft.mapUpdater.update.WaterlogUpdateCommand; import net.countercraft.movecraft.utils.*; import org.bukkit.*; import org.bukkit.block.Block; import org.bukkit.block.BlockFace; +import org.bukkit.block.data.Bisected; +import org.bukkit.block.data.BlockData; +import org.bukkit.block.data.Waterlogged; +import org.bukkit.block.data.type.Slab; +import org.bukkit.block.data.type.Stairs; +import org.bukkit.block.data.type.TrapDoor; import org.bukkit.entity.Player; import org.bukkit.entity.SmallFireball; import org.bukkit.entity.TNTPrimed; @@ -48,6 +55,8 @@ import java.util.concurrent.LinkedBlockingQueue; import java.util.logging.Level; +import static net.countercraft.movecraft.utils.WaterlogUtils.*; + @SuppressWarnings("deprecation") public class AsyncManager extends BukkitRunnable { //private static AsyncManager instance = new AsyncManager(); @@ -1089,6 +1098,9 @@ public void run() { processFadingBlocks(); processDetection(); processAlgorithmQueue(); + if (!Settings.IsLegacy){ + processWaterlogging(); + } //processScheduledBlockChanges(); // if(Settings.CompatibilityMode==false) // FastBlockChanger.getInstance().run(); @@ -1111,6 +1123,56 @@ public void run() { } + private void processWaterlogging() { + final Set updates = new HashSet<>(); + for (final Craft craft : CraftManager.getInstance()){ + for (MovecraftLocation location : craft.getHitBox()){ + final BlockData bData = location.toBukkit(craft.getW()).getBlock().getBlockData(); + if (!(bData instanceof Waterlogged)){ + continue; + } + final Waterlogged wLog = (Waterlogged) bData; + boolean waterlog = false; + if (wLog.isWaterlogged() && location.getY() > craft.getWaterLine()){ + updates.add(new WaterlogUpdateCommand(location.toBukkit(craft.getW()), false)); + } else if (!wLog.isWaterlogged() && location.getY() <= craft.getWaterLine() ){ + if (wLog instanceof TrapDoor){ + final TrapDoor trapDoor = (TrapDoor) wLog; + final Location testLoc = location.translate(0, (trapDoor.getHalf() == Bisected.Half.TOP ? -1 : 1), 0).toBukkit(craft.getW()); + if (testLoc.getBlock().getType() == Material.WATER || isWaterlogged(testLoc)){ + waterlog = true; + } + } else if (wLog instanceof Slab){ + final Slab slab = (Slab) wLog; + if (slab.getType() == Slab.Type.DOUBLE){ + continue; + } + final Location testLoc = location.translate(0, (slab.getType() == Slab.Type.TOP ? -1 : 1), 0).toBukkit(craft.getW()); + if (testLoc.getBlock().getType() == Material.WATER || isWaterlogged(testLoc) || waterToSides(location.toBukkit(craft.getW()))){ + waterlog = true; + } + + } else if (wLog instanceof Stairs){ + final Stairs stairs = (Stairs) wLog; + Block testBlock = location.toBukkit(craft.getW()).getBlock().getRelative(stairs.getFacing().getOppositeFace()); + Block yTest = location.translate(0, (stairs.getHalf() == Bisected.Half.TOP ? -1 : 1), 0).toBukkit(craft.getW()).getBlock(); + waterlog = testBlock.getType() == Material.WATER || isWaterlogged(testBlock.getLocation()) || yTest.getType() == Material.WATER || isWaterlogged(yTest.getLocation()); + } + + else if (waterToSides( location.toBukkit(craft.getW()))){ + waterlog = true; + } + + } + if (waterlog){ + updates.add(new WaterlogUpdateCommand(location.toBukkit(craft.getW()), true)); + } + } + } + MapUpdateManager.getInstance().scheduleUpdates(updates); + } + + private void clear(Craft c) { clearanceSet.add(c); } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/rotation/RotationTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/rotation/RotationTask.java index 8378bd9ca..6d3611e31 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/rotation/RotationTask.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/rotation/RotationTask.java @@ -37,7 +37,6 @@ import net.countercraft.movecraft.mapUpdater.update.CraftRotateCommand; import net.countercraft.movecraft.mapUpdater.update.EntityRotateUpdateCommand; import net.countercraft.movecraft.mapUpdater.update.UpdateCommand; -import net.countercraft.movecraft.mapUpdater.update.WaterlogUpdateCommand; import net.countercraft.movecraft.utils.*; import org.bukkit.Bukkit; import org.bukkit.Location; @@ -214,9 +213,7 @@ public void run() { updates.add(new CraftRotateCommand(getCraft(),originPoint, rotation)); updates.add(new EntityRotateUpdateCommand(craft, oldHitBox, rotation, originPoint)); - if (!Settings.IsLegacy){ - updates.add(new WaterlogUpdateCommand(craft)); - } + if (getCraft().getCruising()) { if (rotation == Rotation.ANTICLOCKWISE) { diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java index 7b18df742..bf2684309 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java @@ -410,12 +410,9 @@ public void run() { if (!craft.getType().getCruiseOnPilot() && !craft.getSinking()) // not necessary to release cruiseonpilot crafts, because they will already be released CraftManager.getInstance().addReleaseTask(craft); } - updates.add(new CraftTranslateCommand(craft, new MovecraftLocation(dx, dy, dz))); updates.add(new EntityTranslateUpdateCommand(craft, dx, dy, dz)); - if (!Settings.IsLegacy){ - updates.add(new WaterlogUpdateCommand(craft)); - } + captureYield(harvestedBlocks); @@ -466,48 +463,50 @@ private void captureYield(List harvestedBlocks) { if (harvestedBlocks.isEmpty()) { return; } - ArrayList chests = new ArrayList<>(); - //find chests - for (MovecraftLocation loc : oldHitBox) { - Block block = craft.getW().getBlockAt(loc.getX(), loc.getY(), loc.getZ()); - if (block.getType() == Material.CHEST || block.getType() == Material.TRAPPED_CHEST) - chests.add(((InventoryHolder) (block.getState())).getInventory()); - } - - for (MovecraftLocation harvestedBlock : harvestedBlocks) { - Block block = craft.getW().getBlockAt(harvestedBlock.getX(), harvestedBlock.getY(), harvestedBlock.getZ()); - List drops = new ArrayList<>(block.getDrops()); - if (Settings.IsLegacy) { - //generate seed drops - if (block.getType() == LegacyUtils.CROPS) { - Random rand = new Random(); - int amount = rand.nextInt(4); - if (amount > 0) { - ItemStack seeds = new ItemStack(LegacyUtils.SEEDS, amount); - drops.add(seeds); - } + new BukkitRunnable() { + @Override + public void run() { + ArrayList chests = new ArrayList<>(); + //find chests + for (MovecraftLocation loc : oldHitBox) { + Block block = craft.getW().getBlockAt(loc.getX(), loc.getY(), loc.getZ()); + if (block.getType() == Material.CHEST || block.getType() == Material.TRAPPED_CHEST) + chests.add(((InventoryHolder) (block.getState())).getInventory()); } - } else { - if (block.getType() == Material.WHEAT){ - Random rand = new Random(); - int amount = rand.nextInt(4); - if (amount > 0){ - ItemStack seeds = new ItemStack(Material.WHEAT_SEEDS, amount); - drops.add(seeds); + + for (MovecraftLocation harvestedBlock : harvestedBlocks) { + + Block block = craft.getW().getBlockAt(harvestedBlock.getX(), harvestedBlock.getY(), harvestedBlock.getZ()); + List drops = new ArrayList<>(block.getDrops()); + + if (Settings.IsLegacy) { + //generate seed drops + if (block.getType() == LegacyUtils.CROPS) { + Random rand = new Random(); + int amount = rand.nextInt(4); + if (amount > 0) { + ItemStack seeds = new ItemStack(LegacyUtils.SEEDS, amount); + drops.add(seeds); + } + } + } else { + if (block.getType() == Material.WHEAT) { + Random rand = new Random(); + int amount = rand.nextInt(4); + if (amount > 0) { + ItemStack seeds = new ItemStack(Material.WHEAT_SEEDS, amount); + drops.add(seeds); + } + } } - } - } - //get contents of inventories before deposting - new BukkitRunnable() { - @Override - public void run() { + //get contents of inventories before deposting + if (block.getState() instanceof InventoryHolder) { if (block.getState() instanceof Chest) { drops.addAll(Arrays.asList(((Chest) block.getState()).getBlockInventory().getContents())); - } else if (block.getState() instanceof Barrel){ + } else if (block.getState() instanceof Barrel) { drops.addAll(Arrays.asList(((Barrel) block.getState()).getInventory().getContents())); - } - else { + } else { drops.addAll(Arrays.asList((((InventoryHolder) block.getState()).getInventory().getContents()))); } } @@ -518,9 +517,9 @@ public void run() { updates.add(new ItemDropUpdateCommand(new Location(craft.getW(), harvestedBlock.getX(), harvestedBlock.getY(), harvestedBlock.getZ()), retStack)); } } - }.runTask(Movecraft.getInstance()); + } - } + }.runTask(Movecraft.getInstance()); } private ItemStack putInToChests(ItemStack stack, ArrayList inventories) { diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/CraftManager.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/CraftManager.java index c01871fd7..198a4494f 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/CraftManager.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/CraftManager.java @@ -136,8 +136,12 @@ private Set loadCraftTypes(){ if (file.isFile()) { if (file.getName().contains(".craft")) { - CraftType type = new CraftType(file); - craftTypes.add(type); + try { + CraftType type = new CraftType(file); + craftTypes.add(type); + } catch (Exception e){ + e.printStackTrace(); + } } } } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/HarvestBlockUpdateCommand.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/HarvestBlockUpdateCommand.java new file mode 100644 index 000000000..6565e5d92 --- /dev/null +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/HarvestBlockUpdateCommand.java @@ -0,0 +1,4 @@ +package net.countercraft.movecraft.mapUpdater.update; + +public class HarvestBlockUpdateCommand { +} diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/WaterlogUpdateCommand.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/WaterlogUpdateCommand.java index cd2a2f494..ebacb0bcb 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/WaterlogUpdateCommand.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/WaterlogUpdateCommand.java @@ -1,84 +1,31 @@ package net.countercraft.movecraft.mapUpdater.update; -import net.countercraft.movecraft.MovecraftLocation; -import net.countercraft.movecraft.craft.Craft; -import net.countercraft.movecraft.utils.HashHitBox; import org.bukkit.Location; -import org.bukkit.Material; -import org.bukkit.block.Block; -import org.bukkit.block.data.Bisected; import org.bukkit.block.data.Waterlogged; -import org.bukkit.block.data.type.Slab; -import org.bukkit.block.data.type.TrapDoor; import org.bukkit.util.Vector; public class WaterlogUpdateCommand extends UpdateCommand{ - private final Craft craft; - private final Vector[] SHIFTS = {new Vector(0,1,0), - new Vector(0, -1, 0), - new Vector(1, 0, 0), - new Vector(-1, 0, 0), - new Vector(0, 0, 1), - new Vector(0, 0, -1)}; - public WaterlogUpdateCommand(Craft craft){ - this.craft = craft; + private final Location location; + private final boolean waterlogged; + + public WaterlogUpdateCommand(Location location, boolean waterlogged){ + this.location = location; + + this.waterlogged = waterlogged; } @Override public void doUpdate() { - HashHitBox hitBox = craft.getHitBox(); - for (MovecraftLocation moveLoc : hitBox){ - Block b = moveLoc.toBukkit(craft.getW()).getBlock(); - if (!(b.getBlockData() instanceof Waterlogged)){ - continue; - } - Waterlogged wLog = (Waterlogged) b.getBlockData(); - if (b.getY() > craft.getWaterLine()){ - wLog.setWaterlogged(false); - b.setBlockData(wLog); - continue; - } - if (wLog instanceof TrapDoor){ - TrapDoor tDoor = (TrapDoor) wLog; - if (tDoor.getHalf() == Bisected.Half.BOTTOM && b.getRelative(0,1,0).getType() == Material.WATER){ - tDoor.setWaterlogged(true); - - } - if (tDoor.getHalf() == Bisected.Half.TOP && b.getRelative(0,-1,0).getType() == Material.WATER){ - tDoor.setWaterlogged(true); - } - if (b.getRelative(tDoor.getFacing().getOppositeFace()).getType() == Material.WATER){ - tDoor.setWaterlogged(true); - } - b.setBlockData(tDoor); - } else if (wLog instanceof Slab){ - Slab slab = (Slab) wLog; - if (slab.getType() == Slab.Type.TOP){ - for (Vector shift : SHIFTS){ - final Location testLoc = b.getLocation().add(shift); - if (shift.getY() == 1){ - continue; - } - if (!(testLoc.getBlock().getBlockData() instanceof Waterlogged)) { - continue; - } - slab.setWaterlogged(true); - b.setBlockData(slab); - break; - } - } - } - else { - if (b.getRelative(0,1,0).getType() == Material.WATER || - b.getRelative(0,-1,0).getType() == Material.WATER || - b.getRelative(0,0,1).getType() == Material.WATER || - b.getRelative(0,0,-1).getType() == Material.WATER || - b.getRelative(1,0,0).getType() == Material.WATER || - b.getRelative(-1,0,0).getType() == Material.WATER ){ - wLog.setWaterlogged(true); - b.setBlockData(wLog); - } - } - } + final Waterlogged wLog = (Waterlogged) location.getBlock().getBlockData(); + wLog.setWaterlogged(waterlogged); + location.getBlock().setBlockData(wLog); } + + + private final Vector[] SHIFTS = {new Vector(0,1,0), + new Vector(0, -1, 0), + new Vector(1, 0, 0), + new Vector(-1, 0, 0), + new Vector(0, 0, 1), + new Vector(0, 0, -1)}; } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/WaterlogUtils.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/WaterlogUtils.java new file mode 100644 index 000000000..c97f1635e --- /dev/null +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/WaterlogUtils.java @@ -0,0 +1,63 @@ +package net.countercraft.movecraft.utils; + +import net.countercraft.movecraft.MovecraftLocation; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.World; +import org.bukkit.block.Block; +import org.bukkit.block.data.Waterlogged; + +public class WaterlogUtils { + private WaterlogUtils(){ + + } + public static boolean adjacentToWater(World world, MovecraftLocation ml){ + for (MovecraftLocation shift : SHIFTS){ + final MovecraftLocation test = ml.add(shift); + final Block testBlock = test.toBukkit(world).getBlock(); + + if (testBlock.getType() == Material.WATER){ + return true; + } + else if (testBlock.getBlockData() instanceof Waterlogged){ + Waterlogged wlog = (Waterlogged) testBlock.getBlockData(); + if (!wlog.isWaterlogged()){ + return false; + } + return true; + } + } + return false; + } + + public static boolean isWaterlogged(Location location){ + if (!(location.getBlock().getBlockData() instanceof Waterlogged)){ + return false; + } + Waterlogged wlog = (Waterlogged) location.getBlock().getBlockData(); + return wlog.isWaterlogged(); + } + + public static boolean waterToSides(Location location){ + for (MovecraftLocation shift : SHIFTS){ + if (shift.getY() != 0){ + continue; + } + final Block test = location.add(shift.toBukkit(location.getWorld())).getBlock(); + if (test.getType() == Material.WATER){ + return true; + } else if (test.getBlockData() instanceof Waterlogged){ + final Waterlogged wlog = (Waterlogged) test.getBlockData(); + return wlog.isWaterlogged(); + } + } + return false; + } + + private static final MovecraftLocation[] SHIFTS = {new MovecraftLocation(0,1,0), + new MovecraftLocation(0, -1, 0), + new MovecraftLocation(1, 0, 0), + new MovecraftLocation(-1, 0, 0), + new MovecraftLocation(0, 0, 1), + new MovecraftLocation(0, 0, -1)}; +} diff --git a/modules/Movecraft/src/main/resources/localisation/movecraftlang_en.properties b/modules/Movecraft/src/main/resources/localisation/movecraftlang_en.properties index 05f4965b5..4c7b72bb1 100644 --- a/modules/Movecraft/src/main/resources/localisation/movecraftlang_en.properties +++ b/modules/Movecraft/src/main/resources/localisation/movecraftlang_en.properties @@ -88,6 +88,7 @@ Detection\ -\ Not\ Registered\ Pilot=Not one of the registered pilots on this cr Detection\ -\ Craft\ Type\ Cannot\ Be\ Named=Crafts of this type cannot be named Detection\ -\ Failed\ -\ Water\ contact\ required\ but\ not\ found=Detection failed\: Water contact required but not found Economy\ -\ Not\ Enough\ Money=You do not have enough money +Internal\ -\ Error\ -\ Processor\ thread\ encountered\ an\ error=Async task generated an exception ManOverboard\ -\ No\ Craft\ Found=No valid craft to ManOverboard to. ManOverboard\ -\ Must\ Be\ Player=Only Players may use ManOverboard. ManOverboard\ -\ Distance\ Too\ Far=Distance to craft is too far. diff --git a/modules/Movecraft/src/main/resources/types/1_14/LaunchTorpedo.craft b/modules/Movecraft/src/main/resources/types/1_14/LaunchTorpedo.craft index ace8eb4b7..d1f014b5e 100644 --- a/modules/Movecraft/src/main/resources/types/1_14/LaunchTorpedo.craft +++ b/modules/Movecraft/src/main/resources/types/1_14/LaunchTorpedo.craft @@ -24,6 +24,12 @@ speed: 9.0 tryNudge: false sinkPercent: 99.0 overallSinkPercent: 99.0 +passthroughBlocks: + - kelp + - kelp_plant + - tall_seagrass + - seagrass + - bubble_column flyblocks: COAL_BLOCK: - 10.0 diff --git a/modules/Movecraft/src/main/resources/types/1_14/Turret.craft b/modules/Movecraft/src/main/resources/types/1_14/Turret.craft index 83ed863df..e1487bdf9 100644 --- a/modules/Movecraft/src/main/resources/types/1_14/Turret.craft +++ b/modules/Movecraft/src/main/resources/types/1_14/Turret.craft @@ -30,8 +30,6 @@ allowedBlocks: - all_door - lever - all_pressure_plate - - redstone_torch - - redstone_wall_torch - all_button - all_fence - netherrack diff --git a/modules/Movecraft/src/main/resources/types/LaunchTorpedo.craft b/modules/Movecraft/src/main/resources/types/LaunchTorpedo.craft index ace8eb4b7..d1f014b5e 100644 --- a/modules/Movecraft/src/main/resources/types/LaunchTorpedo.craft +++ b/modules/Movecraft/src/main/resources/types/LaunchTorpedo.craft @@ -24,6 +24,12 @@ speed: 9.0 tryNudge: false sinkPercent: 99.0 overallSinkPercent: 99.0 +passthroughBlocks: + - kelp + - kelp_plant + - tall_seagrass + - seagrass + - bubble_column flyblocks: COAL_BLOCK: - 10.0 diff --git a/modules/Movecraft/src/main/resources/types/Turret.craft b/modules/Movecraft/src/main/resources/types/Turret.craft index f0e1b47ac..625064c53 100644 --- a/modules/Movecraft/src/main/resources/types/Turret.craft +++ b/modules/Movecraft/src/main/resources/types/Turret.craft @@ -30,8 +30,6 @@ allowedBlocks: - all_door - lever - all_pressure_plate - - redstone_torch - - redstone_wall_torch - all_button - all_fence - netherrack diff --git a/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java b/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java index 1e07ded12..d4c9bd74c 100644 --- a/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java +++ b/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java @@ -100,7 +100,7 @@ final public class CraftType { @NotNull private final Map potionEffectDelays = Collections.emptyMap(); @NotNull private final Set forbiddenHoverOverBlocks; - public CraftType(File f) { + public CraftType(File f) throws CraftTypeException{ final Map data; try { InputStream input = new FileInputStream(f); @@ -367,8 +367,19 @@ public CraftType(File f) { ArrayList objList = (ArrayList) data.get("harvestBlocks"); for (Object i : objList) { if (i instanceof String) { - Material mat = Material.getMaterial(((String) i).toUpperCase()); - harvestBlocks.add(mat); + String str = (String) i; + str = str.toUpperCase(); + if (str.startsWith("ALL")){ + for (Material type : Material.values()){ + if (!type.name().endsWith(str.replace("ALL", ""))){ + continue; + } + harvestBlocks.add(type); + } + } else { + Material mat = Material.getMaterial(str); + harvestBlocks.add(mat); + } } else { Material mat = Material.getMaterial((Integer) i); harvestBlocks.add(mat); @@ -380,8 +391,20 @@ public CraftType(File f) { ArrayList objList = (ArrayList) data.get("harvesterBladeBlocks"); for (Object i : objList) { if (i instanceof String) { - Material mat = Material.getMaterial(((String) i).toUpperCase()); - harvesterBladeBlocks.add(mat); + String str = (String) i; + str = str.toUpperCase(); + if (str.startsWith("ALL")){ + for (Material type : Material.values()){ + if (!type.name().endsWith(str.replace("ALL", ""))){ + continue; + } + harvesterBladeBlocks.add(type); + } + } else { + Material mat = Material.getMaterial(str); + harvesterBladeBlocks.add(mat); + } + } else { Material mat = Material.getMaterial((Integer) i); harvesterBladeBlocks.add(mat); From ec9a6343a4c58a2fc472d61ee5c773ac39572d8c Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Sat, 16 Nov 2019 11:45:41 +0100 Subject: [PATCH 076/304] Fixed Movecraft breaking on startup if WorldEditis not installed --- .../java/net/countercraft/movecraft/Movecraft.java | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java index 8b74acc71..aa676e699 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java @@ -333,7 +333,13 @@ public void onEnable() { wEPlugin = getServer().getPluginManager().getPlugin("FastAsyncWorldEdit"); } } - if (wEPlugin == null || !(wEPlugin instanceof WorldEditPlugin)) { + boolean WEpresent; + try { + WEpresent = wEPlugin == null || !(wEPlugin instanceof WorldEditPlugin); + } catch (Throwable t) { + WEpresent = false; + } + if (!WEpresent) { logger.log(Level.INFO, I18nSupport.getInternationalisedString("Startup - WE Not Found")); Settings.AssaultEnable = false; } else { @@ -361,8 +367,9 @@ public void onEnable() { Settings.AssaultEnable = false; } Settings.RepairMaxPercent = getConfig().getDouble("RepairMaxPercent", 50); + worldEditPlugin = (WorldEditPlugin) wEPlugin; } - worldEditPlugin = (WorldEditPlugin) wEPlugin; + From 725e799f40b9c3d11cbabeb5f87f0ae23818fe4b Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Mon, 18 Nov 2019 02:11:21 +0100 Subject: [PATCH 077/304] Rewrote waterlogging processing, drastically increases performance, fixes #23 --- .../movecraft/async/AsyncManager.java | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java index ffbed8a9b..1b145233c 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java @@ -65,6 +65,7 @@ public class AsyncManager extends BukkitRunnable { private final HashMap> recentContactTracking = new HashMap<>(); private final BlockingQueue finishedAlgorithms = new LinkedBlockingQueue<>(); private final HashSet clearanceSet = new HashSet<>(); + private final Queue waterlogCheckQueue = new LinkedBlockingQueue<>(); private HashMap FireballTracking = new HashMap<>(); private HashMap wrecks = new HashMap<>(); private HashMap wreckWorlds = new HashMap<>(); @@ -302,7 +303,7 @@ private void processAlgorithmQueue() { //c.setMinZ(task.getData().getMinZ()); //c.setHitBox(task.getData().getHitbox()); c.setHitBox(task.getNewHitBox()); - + addToWaterlogQueue(c); // move any cannons that were present if (Movecraft.getInstance().getCannonsPlugin() != null && shipCannons != null) { for (Cannon can : shipCannons) { @@ -347,7 +348,7 @@ private void processAlgorithmQueue() { sentMapUpdate = true; c.setHitBox(task.getNewHitBox()); - + addToWaterlogQueue(c); // rotate any cannons that were present if (Movecraft.getInstance().getCannonsPlugin() != null && shipCannons != null) { Location tloc = task.getOriginPoint().toBukkit(task.getCraft().getW()); @@ -1124,8 +1125,11 @@ public void run() { } private void processWaterlogging() { + if (waterlogCheckQueue.isEmpty()) + return; final Set updates = new HashSet<>(); - for (final Craft craft : CraftManager.getInstance()){ + + final Craft craft = waterlogCheckQueue.poll(); for (MovecraftLocation location : craft.getHitBox()){ final BlockData bData = location.toBukkit(craft.getW()).getBlock().getBlockData(); if (!(bData instanceof Waterlogged)){ @@ -1168,10 +1172,14 @@ else if (waterToSides( location.toBukkit(craft.getW()))){ updates.add(new WaterlogUpdateCommand(location.toBukkit(craft.getW()), true)); } } - } + MapUpdateManager.getInstance().scheduleUpdates(updates); } + private void addToWaterlogQueue(final Craft craft){ + waterlogCheckQueue.add(craft); + } + private void clear(Craft c) { clearanceSet.add(c); From 88a9b842c27fec31d90e47971827aeb24b1b4435 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Mon, 18 Nov 2019 02:52:50 +0100 Subject: [PATCH 078/304] Create maven.yml --- .github/workflows/maven.yml | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 .github/workflows/maven.yml diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml new file mode 100644 index 000000000..91106d3f4 --- /dev/null +++ b/.github/workflows/maven.yml @@ -0,0 +1,17 @@ +name: Java CI + +on: [push] + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v1 + - name: Set up JDK 1.8 + uses: actions/setup-java@v1 + with: + java-version: 1.8 + - name: Build with Maven + run: mvn -B package --file pom.xml From 0f2c395da03cf168a420b3e4268ea5e4e17be707 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Wed, 20 Nov 2019 22:09:38 +0100 Subject: [PATCH 079/304] Fixed entities flying off crafts when cruiseSkipBlocks is a high number --- .../movecraft/async/translation/TranslationTask.java | 2 +- .../update/EntityTranslateUpdateCommand.java | 12 +++++++----- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java index bf2684309..8a52f3f47 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java @@ -411,7 +411,7 @@ public void run() { CraftManager.getInstance().addReleaseTask(craft); } updates.add(new CraftTranslateCommand(craft, new MovecraftLocation(dx, dy, dz))); - updates.add(new EntityTranslateUpdateCommand(craft, dx, dy, dz)); + updates.add(new EntityTranslateUpdateCommand(craft, oldHitBox, dx, dy, dz)); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/EntityTranslateUpdateCommand.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/EntityTranslateUpdateCommand.java index 8e7e95c3f..90de19b07 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/EntityTranslateUpdateCommand.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/EntityTranslateUpdateCommand.java @@ -35,14 +35,16 @@ */ public class EntityTranslateUpdateCommand extends UpdateCommand { private final Craft craft; + private final HitBox oldHitBox; private final double x; private final double y; private final double z; private final float yaw; private final float pitch; - public EntityTranslateUpdateCommand(Craft craft, double x, double y, double z) { + public EntityTranslateUpdateCommand(Craft craft, HitBox oldHitBox, double x, double y, double z) { this.craft = craft; + this.oldHitBox = oldHitBox; this.x = x; this.y = y; this.z = z; @@ -57,7 +59,7 @@ public Craft getCraft() { @Override public void doUpdate() { - if (craft.getHitBox().isEmpty()){ + if (oldHitBox.isEmpty()){ return; } for (Entity entity : getEntitiesOnCraft()){ @@ -75,7 +77,7 @@ public void doUpdate() { @Override public int hashCode() { - return Objects.hash(craft, x, y, z, pitch, yaw); + return Objects.hash(craft, oldHitBox, x, y, z, pitch, yaw); } @Override @@ -89,11 +91,11 @@ public boolean equals(Object obj) { this.z == other.z && this.pitch == other.pitch && this.yaw == other.yaw && - this.craft.equals(other.craft); + this.craft.equals(other.craft) && + this.oldHitBox.equals(other.oldHitBox); } private Collection getEntitiesOnCraft(){ - final HitBox oldHitBox = craft.getHitBox(); final Location midpoint = oldHitBox.getMidPoint().toBukkit(craft.getW()); final Collection entities = craft.getW().getNearbyEntities(midpoint, oldHitBox.getXLength() / 2.0 + 1, oldHitBox.getYLength() / 2.0 + 2, oldHitBox.getZLength() / 2.0 + 1); final Set toMove = new HashSet<>(); From cd8c7e3c465e64962c1cc73f76161f7ab4ffbb88 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Fri, 22 Nov 2019 22:45:32 +0100 Subject: [PATCH 080/304] Minor changes --- .../java/net/countercraft/movecraft/async/AsyncManager.java | 3 ++- .../countercraft/movecraft/compat/v1_13_R2/IWorldHandler.java | 2 ++ .../countercraft/movecraft/compat/v1_14_R1/IWorldHandler.java | 1 - 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java index 1b145233c..227b000da 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java @@ -55,7 +55,8 @@ import java.util.concurrent.LinkedBlockingQueue; import java.util.logging.Level; -import static net.countercraft.movecraft.utils.WaterlogUtils.*; +import static net.countercraft.movecraft.utils.WaterlogUtils.isWaterlogged; +import static net.countercraft.movecraft.utils.WaterlogUtils.waterToSides; @SuppressWarnings("deprecation") public class AsyncManager extends BukkitRunnable { diff --git a/modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/IWorldHandler.java b/modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/IWorldHandler.java index cd9c22fd4..b061a6176 100644 --- a/modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/IWorldHandler.java +++ b/modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/IWorldHandler.java @@ -310,6 +310,8 @@ private void setBlockFast(@NotNull World world, @NotNull BlockPosition position, } + + chunkSection.setType(position.getX()&15, position.getY()&15, position.getZ()&15, data); } diff --git a/modules/v1_14_R1/src/main/java/net/countercraft/movecraft/compat/v1_14_R1/IWorldHandler.java b/modules/v1_14_R1/src/main/java/net/countercraft/movecraft/compat/v1_14_R1/IWorldHandler.java index 8194cf7b7..6e644c697 100644 --- a/modules/v1_14_R1/src/main/java/net/countercraft/movecraft/compat/v1_14_R1/IWorldHandler.java +++ b/modules/v1_14_R1/src/main/java/net/countercraft/movecraft/compat/v1_14_R1/IWorldHandler.java @@ -305,7 +305,6 @@ private void setBlockFast(@NotNull World world, @NotNull BlockPosition position, chunkSection = chunk.getSections()[position.getY() >> 4]; } - chunkSection.setType(position.getX()&15, position.getY()&15, position.getZ()&15, data); } From 5bb4b83f16fd75fb954032ea3b214db5650b2e17 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Sat, 23 Nov 2019 04:00:18 +0100 Subject: [PATCH 081/304] Re-arranged WE repo in api module pom --- modules/api/pom.xml | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/modules/api/pom.xml b/modules/api/pom.xml index 642dd0e14..c480beedb 100644 --- a/modules/api/pom.xml +++ b/modules/api/pom.xml @@ -7,12 +7,7 @@ http://github.com/apdevteam/Movecraft API - - - sk89q-repo - http://maven.sk89q.com/repo/ - - + UTF-8 @@ -28,6 +23,12 @@ parent ../../ + + + sk89q-repo + http://maven.sk89q.com/repo/ + + org.spigotmc From 563843ee7f4cc0863cd3d4e24d58cc1f74204874 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Sat, 23 Nov 2019 04:02:00 +0100 Subject: [PATCH 082/304] fix --- modules/api/pom.xml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/modules/api/pom.xml b/modules/api/pom.xml index c480beedb..5b96410a0 100644 --- a/modules/api/pom.xml +++ b/modules/api/pom.xml @@ -24,6 +24,10 @@ ../../ + + spigot-repo + https://hub.spigotmc.org/nexus/content/repositories/snapshots/ + sk89q-repo http://maven.sk89q.com/repo/ From 0fc7b10d975cb3c033d7cc8098c0edbc1d9a6e7c Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Sat, 23 Nov 2019 11:50:16 +0100 Subject: [PATCH 083/304] fix --- modules/api/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/api/pom.xml b/modules/api/pom.xml index 5b96410a0..f575d2be2 100644 --- a/modules/api/pom.xml +++ b/modules/api/pom.xml @@ -26,7 +26,7 @@ spigot-repo - https://hub.spigotmc.org/nexus/content/repositories/snapshots/ + https://hub.spigotmc.org/nexus/content/groups/public/ sk89q-repo From 5bc16d32fdcea4bf96645bdd68f94f84ee5cf052 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Wed, 27 Nov 2019 18:24:09 +0100 Subject: [PATCH 084/304] Fixed a bug preventing Movecraft from detecting WorldEdit --- .../net/countercraft/movecraft/Movecraft.java | 18 +++------------ .../movecraft/craft/CraftType.java | 22 ++++++++++++++----- .../movecraft/utils/BlockContainer.java | 2 +- 3 files changed, 21 insertions(+), 21 deletions(-) diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java index aa676e699..f2e1acc96 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java @@ -325,21 +325,9 @@ public void onEnable() { //load up WorldEdit if it's present - Plugin wEPlugin = null; - if (getServer().getPluginManager().getPlugin("WorldEdit") != null){ - wEPlugin = getServer().getPluginManager().getPlugin("WorldEdit"); - } else { - if (!Settings.IsLegacy){ - wEPlugin = getServer().getPluginManager().getPlugin("FastAsyncWorldEdit"); - } - } - boolean WEpresent; - try { - WEpresent = wEPlugin == null || !(wEPlugin instanceof WorldEditPlugin); - } catch (Throwable t) { - WEpresent = false; - } - if (!WEpresent) { + Plugin wEPlugin = getServer().getPluginManager().getPlugin("WorldEdit"); + + if (wEPlugin == null || !(wEPlugin instanceof WorldEditPlugin)) { logger.log(Level.INFO, I18nSupport.getInternationalisedString("Startup - WE Not Found")); Settings.AssaultEnable = false; } else { diff --git a/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java b/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java index d4c9bd74c..6fd6287fb 100644 --- a/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java +++ b/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java @@ -369,9 +369,9 @@ public CraftType(File f) throws CraftTypeException{ if (i instanceof String) { String str = (String) i; str = str.toUpperCase(); - if (str.startsWith("ALL")){ + if (str.startsWith("ALL_")){ for (Material type : Material.values()){ - if (!type.name().endsWith(str.replace("ALL", ""))){ + if (!type.name().endsWith(str.replace("ALL_", "_"))){ continue; } harvestBlocks.add(type); @@ -393,9 +393,9 @@ public CraftType(File f) throws CraftTypeException{ if (i instanceof String) { String str = (String) i; str = str.toUpperCase(); - if (str.startsWith("ALL")){ + if (str.startsWith("ALL_")){ for (Material type : Material.values()){ - if (!type.name().endsWith(str.replace("ALL", ""))){ + if (!type.name().endsWith(str.replace("ALL_", "_"))){ continue; } harvesterBladeBlocks.add(type); @@ -476,7 +476,19 @@ public CraftType(File f) throws CraftTypeException{ ArrayList entries = (ArrayList) data.get("dynamicFlyBlocks"); for (Object o : entries) { if (o instanceof String) { - dynamicFlyBlocks.add(Material.getMaterial((String) o)); + String str = (String) o; + str = str.toUpperCase(); + if (str.startsWith("ALL_")){ + str = str.replace("ALL_", "_"); + for (Material type : Material.values()){ + if (!type.name().endsWith(str)){ + continue; + } + dynamicFlyBlocks.add(type); + } + continue; + } + dynamicFlyBlocks.add(Material.getMaterial(str)); } else { dynamicFlyBlocks.add(Material.getMaterial((Integer) o)); } diff --git a/modules/api/src/main/java/net/countercraft/movecraft/utils/BlockContainer.java b/modules/api/src/main/java/net/countercraft/movecraft/utils/BlockContainer.java index b487c3720..335a87150 100644 --- a/modules/api/src/main/java/net/countercraft/movecraft/utils/BlockContainer.java +++ b/modules/api/src/main/java/net/countercraft/movecraft/utils/BlockContainer.java @@ -41,7 +41,7 @@ public BlockContainer(Object obj){ blocks.add(new MovecraftBlock(type, data)); continue; } else if (str.startsWith("ALL_")){ - str = str.replace("ALL_", ""); + str = str.replace("ALL_", "_"); for (Material m : Material.values()){ if (!m.name().endsWith(str)){ continue; From b8087b1e49b3843a662e6f03f7bc8f34fb95c5bd Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Wed, 27 Nov 2019 18:28:38 +0100 Subject: [PATCH 085/304] Started preparing Movecraft for 1.15 --- modules/v1_15_R1/pom.xml | 18 ++++++++++++++++++ pom.xml | 1 + 2 files changed, 19 insertions(+) create mode 100644 modules/v1_15_R1/pom.xml diff --git a/modules/v1_15_R1/pom.xml b/modules/v1_15_R1/pom.xml new file mode 100644 index 000000000..e6a760279 --- /dev/null +++ b/modules/v1_15_R1/pom.xml @@ -0,0 +1,18 @@ + + + + movecraft-parent + net.countercraft + parent + ../../pom.xml + + 4.0.0 + + movecraft-v1_15_R1 + Movecraft-v1_15_R1 + v1_15_R1 + + + \ No newline at end of file diff --git a/pom.xml b/pom.xml index 35ac33af3..4824d6697 100644 --- a/pom.xml +++ b/pom.xml @@ -28,6 +28,7 @@ modules/worldedit/WE6Utils modules/worldedit/WE7Utils modules/Movecraft + modules/v1_15_R1 From aac002326f6e8dc96fe2aeab12ef960e2dc685ed Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Sat, 7 Dec 2019 02:18:16 +0100 Subject: [PATCH 086/304] minor fixes --- .../main/java/net/countercraft/movecraft/craft/ICraft.java | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/ICraft.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/ICraft.java index 077e14d01..f4f2fe43a 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/ICraft.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/ICraft.java @@ -80,11 +80,7 @@ public void translate(int dx, int dy, int dz) { } } }*/ - - - - TranslationTask task = new TranslationTask(this, dx, dy, dz); - Movecraft.getInstance().getAsyncManager().submitTask(task, this); + Movecraft.getInstance().getAsyncManager().submitTask(new TranslationTask(this, dx, dy, dz), this); } @Override From f5b70061cfe809e53dfac14a134aae0ef8fdba8a Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Sat, 7 Dec 2019 02:18:44 +0100 Subject: [PATCH 087/304] minor fixes --- .../countercraft/movecraft/compat/we7/IMovecraftRepair.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/modules/worldedit/WE7Utils/src/main/java/net/countercraft/movecraft/compat/we7/IMovecraftRepair.java b/modules/worldedit/WE7Utils/src/main/java/net/countercraft/movecraft/compat/we7/IMovecraftRepair.java index ca04181a7..a945db2b3 100644 --- a/modules/worldedit/WE7Utils/src/main/java/net/countercraft/movecraft/compat/we7/IMovecraftRepair.java +++ b/modules/worldedit/WE7Utils/src/main/java/net/countercraft/movecraft/compat/we7/IMovecraftRepair.java @@ -34,6 +34,7 @@ import net.countercraft.movecraft.utils.CollectionUtils; import net.countercraft.movecraft.utils.HashHitBox; import net.countercraft.movecraft.utils.HitBox; +import org.bukkit.ChatColor; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.World; @@ -165,7 +166,7 @@ public Clipboard loadCraftRepairStateClipboard(Craft craft, Sign sign) { String s = craft.getNotificationPlayer().getUniqueId().toString() + sign.getLine(1); File dataDirectory = new File(plugin.getDataFolder(), "RepairStates"); File playerDirectory = new File(dataDirectory, craft.getNotificationPlayer().getUniqueId().toString()); - File file = new File(playerDirectory, sign.getLine(1) + ".schematic"); // The schematic file + File file = new File(playerDirectory, ChatColor.stripColor(sign.getLine(1)) + ".schematic"); // The schematic file Clipboard clipboard = null; ClipboardFormat format = ClipboardFormats.findByFile(file); try { From d6c21c0ad6bb477bf3e770c04877a4de820027a9 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Mon, 9 Dec 2019 21:12:02 +0100 Subject: [PATCH 088/304] travis adjustments --- .travis.yml | 2 +- pom.xml | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index ef280969c..2c373ffbd 100644 --- a/.travis.yml +++ b/.travis.yml @@ -33,7 +33,7 @@ deploy: api_key: secure: BAb4F5UKiEUUbJyZkDKAnDlQMF+KJNYlg1Unv9sb/43w8JxdvM3x5uSp8KndVUzwLH1rXLudhY3TPVVvDha4hrsuMW7LzqevKLsrMFXTqXAVJIquJ01ohuvMPa4XV6+6keWVlv0QCCu2F4jjKR861bQRUUYdY5pMSSTc6wmnk8X2IRZNe6E1vK23wdaLNrkx4f9R+msXmo9lsqnktiAxRWKxrE1Btm3TchMgokz+qoCULjvSaZBZZdHEeZjJ93tD80Pmi6w8000NTwTNcEITYsLLJ4tbDfhGS8I2tzBFt7vXjs2UM74YoZIGsHvWf8gGBIv1txSG72Nornf5IX5lOOHfdCb1QxkqTyhdx+poyfL47z6g6IzC6dIHbZH6y6QLGcI95+TVhMxbtszDgttzGfmpxyUv/zDtNSgGLOG7u4ps56Qh132qS0X2+Ky6qoN1ExkuNuaZMhrUBlz0nu9Ze46A18CcXZrSGWSYrC0TQNWIeb3wVla9HQh/kIVa3kIs2LcjsJMtlTW1FKry+lvI3cGlXHsD4Nj2MLfA7M0JftNwO3WQZCF5sPAlJl6+3lsqYpMfN4MZ8Xv/aWRIqopN/J/Aou5L8Bj1hyJN2VwC/z2Oe1+uWFFQqeu2mWHa/WAdRucalMs2wSnBfBcZ92lroYLhGc602z74eN+uWEMSWOg= file: "target/Movecraft.jar" - skip_cleanup: true + skip_cleanup: false on: repo: eirikh1996/Movecraft tags: true diff --git a/pom.xml b/pom.xml index 4824d6697..69a261f9f 100644 --- a/pom.xml +++ b/pom.xml @@ -25,10 +25,11 @@ modules/v1_12_R1 modules/v1_13_R2 modules/v1_14_R1 + modules/v1_15_R1 modules/worldedit/WE6Utils modules/worldedit/WE7Utils modules/Movecraft - modules/v1_15_R1 + From a89ca26b75dae4135c00d27558fd55c58ce69e1b Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Mon, 9 Dec 2019 21:22:18 +0100 Subject: [PATCH 089/304] removed unused dependency FAWEutils --- modules/Movecraft/pom.xml | 6 ------ 1 file changed, 6 deletions(-) diff --git a/modules/Movecraft/pom.xml b/modules/Movecraft/pom.xml index 67175c54c..687b78b88 100644 --- a/modules/Movecraft/pom.xml +++ b/modules/Movecraft/pom.xml @@ -106,12 +106,6 @@ WE7Utils jar - - net.countercraft - movecraft-FAWEUtils - FAWEUtils - jar - net.countercraft movecraft-WE6Utils From 080dc2302faa3dfe444aa94d6a3d769fbbba131a Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Mon, 9 Dec 2019 22:11:10 +0100 Subject: [PATCH 090/304] added draft option to travis --- .travis.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 2c373ffbd..009f70213 100644 --- a/.travis.yml +++ b/.travis.yml @@ -33,7 +33,8 @@ deploy: api_key: secure: BAb4F5UKiEUUbJyZkDKAnDlQMF+KJNYlg1Unv9sb/43w8JxdvM3x5uSp8KndVUzwLH1rXLudhY3TPVVvDha4hrsuMW7LzqevKLsrMFXTqXAVJIquJ01ohuvMPa4XV6+6keWVlv0QCCu2F4jjKR861bQRUUYdY5pMSSTc6wmnk8X2IRZNe6E1vK23wdaLNrkx4f9R+msXmo9lsqnktiAxRWKxrE1Btm3TchMgokz+qoCULjvSaZBZZdHEeZjJ93tD80Pmi6w8000NTwTNcEITYsLLJ4tbDfhGS8I2tzBFt7vXjs2UM74YoZIGsHvWf8gGBIv1txSG72Nornf5IX5lOOHfdCb1QxkqTyhdx+poyfL47z6g6IzC6dIHbZH6y6QLGcI95+TVhMxbtszDgttzGfmpxyUv/zDtNSgGLOG7u4ps56Qh132qS0X2+Ky6qoN1ExkuNuaZMhrUBlz0nu9Ze46A18CcXZrSGWSYrC0TQNWIeb3wVla9HQh/kIVa3kIs2LcjsJMtlTW1FKry+lvI3cGlXHsD4Nj2MLfA7M0JftNwO3WQZCF5sPAlJl6+3lsqYpMfN4MZ8Xv/aWRIqopN/J/Aou5L8Bj1hyJN2VwC/z2Oe1+uWFFQqeu2mWHa/WAdRucalMs2wSnBfBcZ92lroYLhGc602z74eN+uWEMSWOg= file: "target/Movecraft.jar" - skip_cleanup: false + skip_cleanup: true + draft: true on: repo: eirikh1996/Movecraft tags: true From 6ffbefa5b3a99dd5766fd276655b63c18d78e4e0 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Tue, 10 Dec 2019 02:20:26 +0100 Subject: [PATCH 091/304] Fixes --- .../async/translation/TranslationTask.java | 2 +- .../movecraft/craft/CraftType.java | 25 ++++++++++++++----- 2 files changed, 20 insertions(+), 7 deletions(-) diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java index ba27baeb0..0804eeb31 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java @@ -566,7 +566,7 @@ private boolean inclineCraft(HashHitBox hitBox){ collisionBox.add(nl); } for (MovecraftLocation ml : collisionBox){ - if (!ml.toBukkit(craft.getW()).getBlock().getType().equals(Material.AIR) && !craft.getType().getPassthroughBlocks().contains(ml.toBukkit(craft.getW()).getBlock().getType()) && !craft.getType().getHarvestBlocks().contains(ml.toBukkit(craft.getW()).getBlock().getType())){ + if (!ml.toBukkit(craft.getW()).getBlock().getType().name().endsWith("AIR") && !craft.getType().getPassthroughBlocks().contains(ml.toBukkit(craft.getW()).getBlock().getType()) && !craft.getType().getHarvestBlocks().contains(ml.toBukkit(craft.getW()).getBlock().getType())){ return true; } } diff --git a/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java b/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java index 8a0d6cc72..3e69c4c1e 100644 --- a/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java +++ b/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java @@ -20,7 +20,7 @@ import net.countercraft.movecraft.config.Settings; import net.countercraft.movecraft.utils.BlockContainer; import net.countercraft.movecraft.utils.BlockLimitManager; -import org.bukkit.Bukkit; +import net.countercraft.movecraft.utils.LegacyUtils; import org.bukkit.Material; import org.bukkit.potion.PotionEffect; import org.bukkit.potion.PotionEffectType; @@ -158,8 +158,8 @@ public CraftType(File f) throws CraftTypeException{ sinkRateTicks = data.containsKey("sinkSpeed") ? (int) Math.ceil(20 / (doubleFromObject(data.get("sinkSpeed")))) : integerFromObject(data.getOrDefault("sinkTickRate", 0)); keepMovingOnSink = (Boolean) data.getOrDefault("keepMovingOnSink", false); smokeOnSink = integerFromObject(data.getOrDefault("smokeOnSink", 0)); - explodeOnCrash = (float) doubleFromObject(data.getOrDefault("explodeOnCrash", 0F)); - collisionExplosion = (float) doubleFromObject(data.getOrDefault("collisionExplosion", 0F)); + explodeOnCrash = floatFromObject(data.getOrDefault("explodeOnCrash", 0F)); + collisionExplosion = floatFromObject(data.getOrDefault("collisionExplosion", 0F)); minHeightLimit = Math.max(0, integerFromObject(data.getOrDefault("minHeightLimit", 0))); int value = integerFromObject(data.getOrDefault("maxHeightLimit", 254)); if (value <= minHeightLimit) { @@ -236,7 +236,7 @@ public CraftType(File f) throws CraftTypeException{ if (!blockedByWater) { passthroughBlocks.add(Material.WATER); if (Settings.IsLegacy) { - passthroughBlocks.add(Material.STATIONARY_WATER); + passthroughBlocks.add(LegacyUtils.STATIONARY_WATER); } else { passthroughBlocks.add(Material.getMaterial("BUBBLE_COLUMN")); } @@ -291,7 +291,12 @@ public CraftType(File f) throws CraftTypeException{ effectRange = data.containsKey("effectRange") ? integerFromObject(data.get("effectRange")) : 0; if (!canHoverOverWater){ forbiddenHoverOverBlocks.add(Material.WATER); - forbiddenHoverOverBlocks.add(Material.STATIONARY_WATER); + if (Settings.IsLegacy) { + forbiddenHoverOverBlocks.add(LegacyUtils.STATIONARY_WATER); + } else { + forbiddenHoverOverBlocks.add(Material.getMaterial("BUBBLE_COLUMN")); + } + } potionEffectsToApply = data.containsKey("potionEffectsToApply") ? effectListFromObject(data.get("potionEffectsToApply")) : Collections.emptyMap(); allowVerticalTakeoffAndLanding = (boolean) data.getOrDefault("allowVerticalTakeoffAndLanding", true); @@ -313,12 +318,20 @@ private int integerFromObject(Object obj) { return (Integer) obj; } + private float floatFromObject(Object obj) { + if (obj instanceof Double) { + return ((Double) obj).floatValue(); + } else if (obj instanceof Integer) { + return ((Integer) obj).floatValue(); + } + return (float) obj; + } private double doubleFromObject(Object obj) { if (obj instanceof Integer) { return ((Integer) obj).doubleValue(); } - return (Double) obj; + return (double) obj; } private Material materialFromObject(Object obj){ if (obj instanceof Integer){ From afecc6dfdab39b888c596d438f125269422e8794 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Tue, 10 Dec 2019 18:28:05 +0100 Subject: [PATCH 092/304] Added support for 1.9.4 and 1.8.8 --- .travis.yml | 8 + modules/Movecraft/pom.xml | 12 + modules/v1_15_R1/pom.xml | 8 +- modules/v1_8_R3/pom.xml | 63 +++ .../compat/v1_8_R3/IWorldHandler.java | 406 ++++++++++++++++++ .../compat/v1_8_R3/NextTickProvider.java | 68 +++ modules/v1_9_R2/pom.xml | 62 +++ .../compat/v1_9_R2/IWorldHandler.java | 375 ++++++++++++++++ .../compat/v1_9_R2/NextTickProvider.java | 67 +++ pom.xml | 2 + 10 files changed, 1070 insertions(+), 1 deletion(-) create mode 100644 modules/v1_8_R3/pom.xml create mode 100644 modules/v1_8_R3/src/main/java/net/countercraft/movecraft/compat/v1_8_R3/IWorldHandler.java create mode 100644 modules/v1_8_R3/src/main/java/net/countercraft/movecraft/compat/v1_8_R3/NextTickProvider.java create mode 100644 modules/v1_9_R2/pom.xml create mode 100644 modules/v1_9_R2/src/main/java/net/countercraft/movecraft/compat/v1_9_R2/IWorldHandler.java create mode 100644 modules/v1_9_R2/src/main/java/net/countercraft/movecraft/compat/v1_9_R2/NextTickProvider.java diff --git a/.travis.yml b/.travis.yml index 009f70213..21b257f52 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,6 +2,14 @@ cache: directories: - "$HOME/.m2/repository" before_install: | + if [ ! -d "$HOME/.m2/repository/org/spigotmc/spigot/1.8.8-R0.1-SNAPSHOT" ]; then + wget -O BuildTools.jar https://hub.spigotmc.org/jenkins/job/BuildTools/lastSuccessfulBuild/artifact/target/BuildTools.jar + java -jar BuildTools.jar --rev 1.8.8 | grep -vE "[^/ ]*/[^/ ]*\s*KB\s*$" | grep -v "^\s*$" + fi + if [ ! -d "$HOME/.m2/repository/org/spigotmc/spigot/1.9.4-R0.1-SNAPSHOT" ]; then + wget -O BuildTools.jar https://hub.spigotmc.org/jenkins/job/BuildTools/lastSuccessfulBuild/artifact/target/BuildTools.jar + java -jar BuildTools.jar --rev 1.9.4 | grep -vE "[^/ ]*/[^/ ]*\s*KB\s*$" | grep -v "^\s*$" + fi if [ ! -d "$HOME/.m2/repository/org/spigotmc/spigot/1.10.2-R0.1-SNAPSHOT" ]; then wget -O BuildTools.jar https://hub.spigotmc.org/jenkins/job/BuildTools/lastSuccessfulBuild/artifact/target/BuildTools.jar java -jar BuildTools.jar --rev 1.10.2 | grep -vE "[^/ ]*/[^/ ]*\s*KB\s*$" | grep -v "^\s*$" diff --git a/modules/Movecraft/pom.xml b/modules/Movecraft/pom.xml index 687b78b88..267a77073 100644 --- a/modules/Movecraft/pom.xml +++ b/modules/Movecraft/pom.xml @@ -48,6 +48,18 @@ v1_13_R2 jar + + net.countercraft + movecraft-v1_8_R3 + v1_8_R3 + jar + + + net.countercraft + movecraft-v1_9_R2 + v1_9_R2 + jar + net.countercraft movecraft-v1_10_R1 diff --git a/modules/v1_15_R1/pom.xml b/modules/v1_15_R1/pom.xml index e6a760279..ac28953f9 100644 --- a/modules/v1_15_R1/pom.xml +++ b/modules/v1_15_R1/pom.xml @@ -13,6 +13,12 @@ movecraft-v1_15_R1 Movecraft-v1_15_R1 v1_15_R1 - + + + org.bukkit + craftbukkit + 1.15-R0.1-SNAPSHOT + + \ No newline at end of file diff --git a/modules/v1_8_R3/pom.xml b/modules/v1_8_R3/pom.xml new file mode 100644 index 000000000..40f385a63 --- /dev/null +++ b/modules/v1_8_R3/pom.xml @@ -0,0 +1,63 @@ + + + + movecraft-parent + net.countercraft + parent + ../../pom.xml + + 4.0.0 + + movecraft-v1_8_R3 + Movecraft-v1_8_R3 + v1_8_R3 + jar + + + + org.bukkit + craftbukkit + 1.8.8-R0.1-SNAPSHOT + + + net.countercraft + movecraft-api + API + jar + + + org.jetbrains + annotations-java5 + RELEASE + + + + src/main/java + + + org.apache.maven.plugins + maven-compiler-plugin + 3.7.0 + + + net/countercraft/movecraft/compat/v1_8_R3/** + + 1.8 + 1.8 + + + + org.apache.maven.plugins + maven-jar-plugin + 2.4 + + + net/countercraft/movecraft/compat/v1_8_R3/** + + + + + + \ No newline at end of file diff --git a/modules/v1_8_R3/src/main/java/net/countercraft/movecraft/compat/v1_8_R3/IWorldHandler.java b/modules/v1_8_R3/src/main/java/net/countercraft/movecraft/compat/v1_8_R3/IWorldHandler.java new file mode 100644 index 000000000..179f220e8 --- /dev/null +++ b/modules/v1_8_R3/src/main/java/net/countercraft/movecraft/compat/v1_8_R3/IWorldHandler.java @@ -0,0 +1,406 @@ +package net.countercraft.movecraft.compat.v1_8_R3; + +import net.countercraft.movecraft.MovecraftLocation; +import net.countercraft.movecraft.Rotation; +import net.countercraft.movecraft.WorldHandler; +import net.countercraft.movecraft.config.Settings; +import net.countercraft.movecraft.craft.Craft; +import net.countercraft.movecraft.utils.CollectionUtils; +import net.countercraft.movecraft.utils.MathUtils; +import net.minecraft.server.v1_8_R3.*; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.craftbukkit.v1_8_R3.CraftWorld; +import org.bukkit.craftbukkit.v1_8_R3.block.CraftBlockState; +import org.bukkit.craftbukkit.v1_8_R3.entity.CraftPlayer; +import org.bukkit.craftbukkit.v1_8_R3.util.CraftMagicNumbers; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.*; + +public class IWorldHandler extends WorldHandler { + //private static final EnumBlockRotation ROTATION[]; + private final HashMap> bMap = new HashMap<>(); + private MethodHandle internalTeleportMH; + /*static { + ROTATION = new EnumBlockRotation[3]; + ROTATION[Rotation.NONE.ordinal()] = EnumBlockRotation.NONE; + ROTATION[Rotation.CLOCKWISE.ordinal()] = EnumBlockRotation.CLOCKWISE_90; + ROTATION[Rotation.ANTICLOCKWISE.ordinal()] = EnumBlockRotation.COUNTERCLOCKWISE_90; + }*/ + private final NextTickProvider tickProvider = new NextTickProvider(); + + public IWorldHandler() { + MethodHandles.Lookup lookup = MethodHandles.lookup(); + Method teleport = null; + try { + teleport = PlayerConnection.class.getDeclaredMethod("internalTeleport", double.class, double.class, double.class, float.class, float.class, Set.class); + teleport.setAccessible(true); + internalTeleportMH = lookup.unreflect(teleport); + + } catch (NoSuchMethodException | IllegalAccessException e) { + e.printStackTrace(); + } + } + + @Override + public void addPlayerLocation(Player player, double x, double y, double z, float yaw, float pitch){ + EntityPlayer ePlayer = ((CraftPlayer) player).getHandle(); + if(internalTeleportMH == null) { + //something went wrong + super.addPlayerLocation(player, x, y, z, yaw, pitch); + return; + } + try { + internalTeleportMH.invoke(ePlayer.playerConnection, x, y, z, yaw, pitch, EnumSet.allOf(PacketPlayOutPosition.EnumPlayerTeleportFlags.class)); + } catch (Throwable throwable) { + throwable.printStackTrace(); + } + } + + @Override + public void rotateCraft(@NotNull Craft craft, @NotNull MovecraftLocation originPoint, @NotNull Rotation rotation) { + //******************************************* + //* Step one: Convert to Positions * + //******************************************* + HashMap rotatedPositions = new HashMap<>(); + Rotation counterRotation = rotation == Rotation.CLOCKWISE ? Rotation.ANTICLOCKWISE : Rotation.CLOCKWISE; + for(MovecraftLocation newLocation : craft.getHitBox()){ + rotatedPositions.put(locationToPosition(MathUtils.rotateVec(counterRotation, newLocation.subtract(originPoint)).add(originPoint)),locationToPosition(newLocation)); + } + //******************************************* + //* Step two: Get the tiles * + //******************************************* + World nativeWorld = ((CraftWorld) craft.getW()).getHandle(); + List tiles = new ArrayList<>(); + //get the tiles + for(BlockPosition position : rotatedPositions.keySet()){ + //TileEntity tile = nativeWorld.removeTileEntity(position); + TileEntity tile = removeTileEntity(nativeWorld,position); + if(tile == null) + continue; + //tile.a(ROTATION[rotation.ordinal()]); + //get the nextTick to move with the tile + tiles.add(new TileHolder(tile, tickProvider.getNextTick((WorldServer)nativeWorld,position), position)); + } + + //******************************************* + //* Step three: Translate all the blocks * + //******************************************* + // blockedByWater=false means an ocean-going vessel + //TODO: Simplify + //TODO: go by chunks + //TODO: Don't move unnecessary blocks + //get the blocks and rotate them + HashMap blockData = new HashMap<>(); + for(BlockPosition position : rotatedPositions.keySet()){ + blockData.put(position, rotate(rotation, nativeWorld.getType(position))); + } + //create the new block + for(Map.Entry entry : blockData.entrySet()) { + setBlockFast(nativeWorld, rotatedPositions.get(entry.getKey()), entry.getValue()); + } + + + //******************************************* + //* Step four: replace all the tiles * + //******************************************* + //TODO: go by chunks + for(TileHolder tileHolder : tiles){ + moveTileEntity(nativeWorld, rotatedPositions.get(tileHolder.getTilePosition()),tileHolder.getTile()); + if(tileHolder.getNextTick()==null) + continue; + final long currentTime = nativeWorld.worldData.getTime(); + nativeWorld.b(rotatedPositions.get(tileHolder.getNextTick().a), tileHolder.getNextTick().a(), (int) (tileHolder.getNextTick().b - currentTime), tileHolder.getNextTick().c); + } + + //******************************************* + //* Step five: Destroy the leftovers * + //******************************************* + //TODO: add support for pass-through + Collection deletePositions = CollectionUtils.filter(rotatedPositions.keySet(),rotatedPositions.values()); + for(BlockPosition position : deletePositions){ + setBlockFast(nativeWorld, position, Blocks.AIR.getBlockData()); + } + + //******************************************* + //* Step six: Update the blocks * + //******************************************* + for(BlockPosition newPosition : rotatedPositions.values()) { + CraftBlockState.getBlockState(nativeWorld,newPosition.getX(), newPosition.getY(), newPosition.getZ()).update(false,false); + } + for(BlockPosition deletedPosition : deletePositions){ + CraftBlockState.getBlockState(nativeWorld,deletedPosition.getX(), deletedPosition.getY(), deletedPosition.getZ()).update(false,false); + } + //******************************************* + //* Step seven: Send to players * + //******************************************* + List chunks = new ArrayList<>(); + for(BlockPosition position : rotatedPositions.values()){ + Chunk chunk = nativeWorld.getChunkAtWorldCoords(position); + if(!chunks.contains(chunk)){ + chunks.add(chunk); + } + } + for(BlockPosition position : deletePositions){ + Chunk chunk = nativeWorld.getChunkAtWorldCoords(position); + if(!chunks.contains(chunk)){ + chunks.add(chunk); + } + } + } + + @Override + public void translateCraft(@NotNull Craft craft, @NotNull MovecraftLocation displacement) { + //TODO: Add supourt for rotations + //A craftTranslateCommand should only occur if the craft is moving to a valid position + //******************************************* + //* Step one: Convert to Positions * + //******************************************* + BlockPosition translateVector = locationToPosition(displacement); + List positions = new ArrayList<>(); + for(MovecraftLocation movecraftLocation : craft.getHitBox()) { + positions.add(locationToPosition((movecraftLocation)).b(translateVector)); + + } + //******************************************* + //* Step two: Get the tiles * + //******************************************* + World nativeWorld = ((CraftWorld) craft.getW()).getHandle(); + List tiles = new ArrayList<>(); + //get the tiles + for(BlockPosition position : positions){ + if(nativeWorld.getType(position) == Blocks.AIR.getBlockData()) + continue; + //TileEntity tile = nativeWorld.removeTileEntity(position); + TileEntity tile = removeTileEntity(nativeWorld,position); + if(tile == null) + continue; + //get the nextTick to move with the tile + + //nativeWorld.capturedTileEntities.remove(position); + //nativeWorld.getChunkAtWorldCoords(position).getTileEntities().remove(position); + tiles.add(new TileHolder(tile, tickProvider.getNextTick((WorldServer)nativeWorld,position), position)); + + } + //******************************************* + //* Step three: Translate all the blocks * + //******************************************* + // blockedByWater=false means an ocean-going vessel + //TODO: Simplify + //TODO: go by chunks + //TODO: Don't move unnecessary blocks + //get the blocks + List blockData = new ArrayList<>(); + for(BlockPosition position : positions){ + blockData.add(nativeWorld.getType(position)); + } + //translate the positions + List newPositions = new ArrayList<>(); + for(BlockPosition position : positions){ + newPositions.add(position.a(translateVector)); + } + //create the new block + for(int i = 0; i deletePositions = CollectionUtils.filter(positions,newPositions); + for(BlockPosition position : deletePositions){ + setBlockFast(nativeWorld, position, Blocks.AIR.getBlockData()); + } + + //******************************************* + //* Step six: Update the blocks * + //******************************************* + for(BlockPosition newPosition : newPositions) { + CraftBlockState.getBlockState(nativeWorld,newPosition.getX(), newPosition.getY(), newPosition.getZ()).update(false,false); + } + for(BlockPosition deletedPosition : deletePositions){ + CraftBlockState.getBlockState(nativeWorld,deletedPosition.getX(), deletedPosition.getY(), deletedPosition.getZ()).update(false,false); + } + //******************************************* + //* Step seven: Send to players * + //******************************************* + List chunks = new ArrayList<>(); + for(BlockPosition position : newPositions){ + Chunk chunk = nativeWorld.getChunkAtWorldCoords(position); + if(!chunks.contains(chunk)){ + chunks.add(chunk); + } + } + for(BlockPosition position : deletePositions){ + Chunk chunk = nativeWorld.getChunkAtWorldCoords(position); + if(!chunks.contains(chunk)){ + chunks.add(chunk); + } + } + //sendToPlayers(chunks.toArray(new Chunk[0])); + } + + @Nullable + private TileEntity removeTileEntity(@NotNull World world, @NotNull BlockPosition position){ + TileEntity tile = world.getTileEntity(position); + if(tile == null) + return null; + //cleanup + world.capturedTileEntities.remove(position); + world.getChunkAtWorldCoords(position).getTileEntities().remove(position); + if(!Settings.IsPaper) + world.tileEntityList.remove(tile); + world.h.remove(tile); + if(!bMap.containsKey(world)){ + try { + Field bField = World.class.getDeclaredField("b"); + bField.setAccessible(true); + bMap.put(world, (List) bField.get(world)); + } catch (IllegalAccessException | IllegalArgumentException | NoSuchFieldException | SecurityException e1) { + e1.printStackTrace(); + } + } + bMap.get(world).remove(tile); + return tile; + } + + @NotNull + private BlockPosition locationToPosition(@NotNull MovecraftLocation loc) { + return new BlockPosition(loc.getX(), loc.getY(), loc.getZ()); + } + + private void setBlockFast(@NotNull World world, @NotNull BlockPosition position,@NotNull IBlockData data) { + Chunk chunk = world.getChunkAtWorldCoords(position); + ChunkSection chunkSection = chunk.getSections()[position.getY()>>4]; + if (chunkSection == null) { + // Put a GLASS block to initialize the section. It will be replaced next with the real block. + chunk.a(position, Blocks.GLASS.getBlockData()); + chunkSection = chunk.getSections()[position.getY() >> 4]; + } + + chunkSection.setType(position.getX()&15, position.getY()&15, position.getZ()&15, data); + } + + @Override + public void setBlockFast(@NotNull Location location, @NotNull Material material, byte data){ + setBlockFast(location, Rotation.NONE, material, data); + } + + @Override + public void setBlockFast(@NotNull Location location, @NotNull Rotation rotation, @NotNull Material material, byte data) { + IBlockData blockData = CraftMagicNumbers.getBlock(material).fromLegacyData(data); + blockData = rotate(rotation, blockData); + World world = ((CraftWorld)(location.getWorld())).getHandle(); + BlockPosition blockPosition = locationToPosition(bukkit2MovecraftLoc(location)); + setBlockFast(world,blockPosition,blockData); + } + + @Override + public void disableShadow(@NotNull Material type) { + Method method; + try { + Block tempBlock = CraftMagicNumbers.getBlock(type.getId()); + method = Block.class.getDeclaredMethod("d", int.class); + method.setAccessible(true); + method.invoke(tempBlock, 0); + } catch (NoSuchMethodException | InvocationTargetException | IllegalArgumentException | IllegalAccessException | SecurityException e1) { + // TODO Auto-generated catch block + e1.printStackTrace(); + } + } + + private static MovecraftLocation bukkit2MovecraftLoc(Location l) { + return new MovecraftLocation(l.getBlockX(), l.getBlockY(), l.getBlockZ()); + } + + private void moveTileEntity(@NotNull World nativeWorld, @NotNull BlockPosition newPosition, @NotNull TileEntity tile){ + Chunk chunk = nativeWorld.getChunkAtWorldCoords(newPosition); + tile.E(); + if(nativeWorld.captureBlockStates) { + tile.a(nativeWorld); + tile.a(newPosition); + nativeWorld.capturedTileEntities.put(newPosition, tile); + return; + } + tile.a(newPosition); + chunk.tileEntities.put(newPosition, tile); + } + + private IBlockData rotate(final Rotation rotation, IBlockData originalData) { + if (!(originalData.getBlock() instanceof BlockDirectional)) { + return originalData; + } + + EnumDirection eDir = originalData.get(BlockDirectional.FACING); + EnumDirection rotated; + switch (eDir) { + case EAST: + rotated = rotation == Rotation.CLOCKWISE ? EnumDirection.SOUTH : EnumDirection.NORTH; + break; + case WEST: + rotated = rotation == Rotation.CLOCKWISE ? EnumDirection.NORTH : EnumDirection.SOUTH; + break; + case SOUTH: + rotated = rotation == Rotation.CLOCKWISE ? EnumDirection.WEST : EnumDirection.EAST; + break; + case NORTH: + rotated = rotation == Rotation.CLOCKWISE ? EnumDirection.EAST : EnumDirection.WEST; + break; + default: + rotated = eDir; + break; + } + + BlockStateDirection direction = BlockDirectional.FACING; + IBlockData rotatedBlock = originalData.a(direction); + rotatedBlock.set(direction, rotated); + return rotatedBlock; + } + + private class TileHolder{ + @NotNull private final TileEntity tile; + @Nullable + private final NextTickListEntry nextTick; + @NotNull private final BlockPosition tilePosition; + + public TileHolder(@NotNull TileEntity tile, @Nullable NextTickListEntry nextTick, @NotNull BlockPosition tilePosition){ + this.tile = tile; + this.nextTick = nextTick; + this.tilePosition = tilePosition; + } + + + @NotNull + public TileEntity getTile() { + return tile; + } + + @Nullable + public NextTickListEntry getNextTick() { + return nextTick; + } + + @NotNull + public BlockPosition getTilePosition() { + return tilePosition; + } + } +} diff --git a/modules/v1_8_R3/src/main/java/net/countercraft/movecraft/compat/v1_8_R3/NextTickProvider.java b/modules/v1_8_R3/src/main/java/net/countercraft/movecraft/compat/v1_8_R3/NextTickProvider.java new file mode 100644 index 000000000..e42741010 --- /dev/null +++ b/modules/v1_8_R3/src/main/java/net/countercraft/movecraft/compat/v1_8_R3/NextTickProvider.java @@ -0,0 +1,68 @@ +package net.countercraft.movecraft.compat.v1_8_R3; + + +import net.minecraft.server.v1_8_R3.BlockPosition; +import net.minecraft.server.v1_8_R3.NextTickListEntry; +import net.minecraft.server.v1_8_R3.WorldServer; +import org.apache.commons.lang3.tuple.ImmutablePair; +import org.bukkit.craftbukkit.v1_8_R3.util.HashTreeSet; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.lang.ref.WeakReference; +import java.lang.reflect.Field; +import java.util.*; + +public class NextTickProvider { + private Map>,WeakReference>>> tickMap = new HashMap<>(); + + private boolean isRegistered(@NotNull WorldServer world){ + if(!tickMap.containsKey(world)) + return false; + ImmutablePair>, WeakReference>> listPair = tickMap.get(world); + return listPair.right.get() != null && listPair.left.get() != null; + } + + @SuppressWarnings("unchecked") + private void registerWorld(@NotNull WorldServer world){ + List U = new ArrayList<>(); + HashTreeSet nextTickList = new HashTreeSet<>(); + + try { + + Field UField = WorldServer.class.getDeclaredField("U"); + UField.setAccessible(true); + U = (List) UField.get(world); + Field nextTickListField = WorldServer.class.getDeclaredField("nextTickList"); + nextTickListField.setAccessible(true); + nextTickList = (HashTreeSet) nextTickListField.get(world); + } catch (IllegalAccessException | IllegalArgumentException | NoSuchFieldException | SecurityException e1) { + e1.printStackTrace(); + } + tickMap.put(world, new ImmutablePair<>(new WeakReference<>(nextTickList), new WeakReference<>(U))); + } + + @Nullable + @SuppressWarnings("ConstantConditions") + public NextTickListEntry getNextTick(@NotNull WorldServer world, @NotNull BlockPosition position){ + if(!isRegistered(world)) + registerWorld(world); + ImmutablePair>, WeakReference>> listPair = tickMap.get(world); + for(Iterator iterator = listPair.left.get().iterator(); iterator.hasNext();) { + NextTickListEntry listEntry = iterator.next(); + if (position.equals(listEntry.a)) { + iterator.remove(); + return listEntry; + } + } + for(Iterator iterator = listPair.right.get().iterator(); iterator.hasNext();) { + NextTickListEntry listEntry = iterator.next(); + if (position.equals(listEntry.a)) { + iterator.remove(); + return listEntry; + } + } + return null; + + } +} diff --git a/modules/v1_9_R2/pom.xml b/modules/v1_9_R2/pom.xml new file mode 100644 index 000000000..861d4b2bb --- /dev/null +++ b/modules/v1_9_R2/pom.xml @@ -0,0 +1,62 @@ + + + + movecraft-parent + net.countercraft + parent + + 4.0.0 + + Movecraft-v1_9_R2 + movecraft-v1_9_R2 + v1_9_R2 + jar + + + org.bukkit + craftbukkit + 1.9.4-R0.1-SNAPSHOT + + + net.countercraft + movecraft-api + API + jar + + + org.jetbrains + annotations-java5 + RELEASE + + + + src/main/java + + + org.apache.maven.plugins + maven-compiler-plugin + 3.7.0 + + + net/countercraft/movecraft/compat/v1_9_R2/** + + 1.8 + 1.8 + + + + org.apache.maven.plugins + maven-jar-plugin + 2.4 + + + net/countercraft/movecraft/compat/v1_9_R2/** + + + + + + + \ No newline at end of file diff --git a/modules/v1_9_R2/src/main/java/net/countercraft/movecraft/compat/v1_9_R2/IWorldHandler.java b/modules/v1_9_R2/src/main/java/net/countercraft/movecraft/compat/v1_9_R2/IWorldHandler.java new file mode 100644 index 000000000..87333d847 --- /dev/null +++ b/modules/v1_9_R2/src/main/java/net/countercraft/movecraft/compat/v1_9_R2/IWorldHandler.java @@ -0,0 +1,375 @@ +package net.countercraft.movecraft.compat.v1_9_R2; + +import net.countercraft.movecraft.MovecraftLocation; +import net.countercraft.movecraft.Rotation; +import net.countercraft.movecraft.WorldHandler; +import net.countercraft.movecraft.config.Settings; +import net.countercraft.movecraft.craft.Craft; +import net.countercraft.movecraft.utils.CollectionUtils; +import net.countercraft.movecraft.utils.MathUtils; +import net.minecraft.server.v1_9_R2.*; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.craftbukkit.v1_9_R2.CraftWorld; +import org.bukkit.craftbukkit.v1_9_R2.block.CraftBlockState; +import org.bukkit.craftbukkit.v1_9_R2.entity.CraftPlayer; +import org.bukkit.craftbukkit.v1_9_R2.util.CraftMagicNumbers; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.*; + +public class IWorldHandler extends WorldHandler { + private static final EnumBlockRotation ROTATION[]; + private final HashMap> bMap = new HashMap<>(); + private MethodHandle internalTeleportMH; + static { + ROTATION = new EnumBlockRotation[3]; + ROTATION[Rotation.NONE.ordinal()] = EnumBlockRotation.NONE; + ROTATION[Rotation.CLOCKWISE.ordinal()] = EnumBlockRotation.CLOCKWISE_90; + ROTATION[Rotation.ANTICLOCKWISE.ordinal()] = EnumBlockRotation.COUNTERCLOCKWISE_90; + } + private final NextTickProvider tickProvider = new NextTickProvider(); + + public IWorldHandler() { + MethodHandles.Lookup lookup = MethodHandles.lookup(); + Method teleport = null; + try { + teleport = PlayerConnection.class.getDeclaredMethod("internalTeleport", double.class, double.class, double.class, float.class, float.class, Set.class); + teleport.setAccessible(true); + internalTeleportMH = lookup.unreflect(teleport); + + } catch (NoSuchMethodException | IllegalAccessException e) { + e.printStackTrace(); + } + } + + @Override + public void addPlayerLocation(Player player, double x, double y, double z, float yaw, float pitch){ + EntityPlayer ePlayer = ((CraftPlayer) player).getHandle(); + if(internalTeleportMH == null) { + //something went wrong + super.addPlayerLocation(player, x, y, z, yaw, pitch); + return; + } + try { + internalTeleportMH.invoke(ePlayer.playerConnection, x, y, z, yaw, pitch, EnumSet.allOf(PacketPlayOutPosition.EnumPlayerTeleportFlags.class)); + } catch (Throwable throwable) { + throwable.printStackTrace(); + } + } + + @Override + public void rotateCraft(@NotNull Craft craft, @NotNull MovecraftLocation originPoint, @NotNull Rotation rotation) { + //******************************************* + //* Step one: Convert to Positions * + //******************************************* + HashMap rotatedPositions = new HashMap<>(); + Rotation counterRotation = rotation == Rotation.CLOCKWISE ? Rotation.ANTICLOCKWISE : Rotation.CLOCKWISE; + for(MovecraftLocation newLocation : craft.getHitBox()){ + rotatedPositions.put(locationToPosition(MathUtils.rotateVec(counterRotation, newLocation.subtract(originPoint)).add(originPoint)),locationToPosition(newLocation)); + } + //******************************************* + //* Step two: Get the tiles * + //******************************************* + World nativeWorld = ((CraftWorld) craft.getW()).getHandle(); + List tiles = new ArrayList<>(); + //get the tiles + for(BlockPosition position : rotatedPositions.keySet()){ + //TileEntity tile = nativeWorld.removeTileEntity(position); + TileEntity tile = removeTileEntity(nativeWorld,position); + if(tile == null) + continue; + //tile.a(ROTATION[rotation.ordinal()]); + //get the nextTick to move with the tile + tiles.add(new TileHolder(tile, tickProvider.getNextTick((WorldServer)nativeWorld,position), position)); + } + + //******************************************* + //* Step three: Translate all the blocks * + //******************************************* + // blockedByWater=false means an ocean-going vessel + //TODO: Simplify + //TODO: go by chunks + //TODO: Don't move unnecessary blocks + //get the blocks and rotate them + HashMap blockData = new HashMap<>(); + for(BlockPosition position : rotatedPositions.keySet()){ + blockData.put(position,nativeWorld.getType(position).a(ROTATION[rotation.ordinal()])); + } + //create the new block + for(Map.Entry entry : blockData.entrySet()) { + setBlockFast(nativeWorld, rotatedPositions.get(entry.getKey()), entry.getValue()); + } + + + //******************************************* + //* Step four: replace all the tiles * + //******************************************* + //TODO: go by chunks + for(TileHolder tileHolder : tiles){ + moveTileEntity(nativeWorld, rotatedPositions.get(tileHolder.getTilePosition()),tileHolder.getTile()); + if(tileHolder.getNextTick()==null) + continue; + final long currentTime = nativeWorld.worldData.getTime(); + nativeWorld.b(rotatedPositions.get(tileHolder.getNextTick().a), tileHolder.getNextTick().a(), (int) (tileHolder.getNextTick().b - currentTime), tileHolder.getNextTick().c); + } + + //******************************************* + //* Step five: Destroy the leftovers * + //******************************************* + //TODO: add support for pass-through + Collection deletePositions = CollectionUtils.filter(rotatedPositions.keySet(),rotatedPositions.values()); + for(BlockPosition position : deletePositions){ + setBlockFast(nativeWorld, position, Blocks.AIR.getBlockData()); + } + + //******************************************* + //* Step six: Update the blocks * + //******************************************* + for(BlockPosition newPosition : rotatedPositions.values()) { + CraftBlockState.getBlockState(nativeWorld,newPosition.getX(), newPosition.getY(), newPosition.getZ()).update(false,false); + } + for(BlockPosition deletedPosition : deletePositions){ + CraftBlockState.getBlockState(nativeWorld,deletedPosition.getX(), deletedPosition.getY(), deletedPosition.getZ()).update(false,false); + } + //******************************************* + //* Step seven: Send to players * + //******************************************* + List chunks = new ArrayList<>(); + for(BlockPosition position : rotatedPositions.values()){ + Chunk chunk = nativeWorld.getChunkAtWorldCoords(position); + if(!chunks.contains(chunk)){ + chunks.add(chunk); + } + } + for(BlockPosition position : deletePositions){ + Chunk chunk = nativeWorld.getChunkAtWorldCoords(position); + if(!chunks.contains(chunk)){ + chunks.add(chunk); + } + } + } + + @Override + public void translateCraft(@NotNull Craft craft, @NotNull MovecraftLocation displacement) { + //TODO: Add supourt for rotations + //A craftTranslateCommand should only occur if the craft is moving to a valid position + //******************************************* + //* Step one: Convert to Positions * + //******************************************* + BlockPosition translateVector = locationToPosition(displacement); + List positions = new ArrayList<>(); + for(MovecraftLocation movecraftLocation : craft.getHitBox()) { + positions.add(locationToPosition((movecraftLocation)).b(translateVector)); + + } + //******************************************* + //* Step two: Get the tiles * + //******************************************* + World nativeWorld = ((CraftWorld) craft.getW()).getHandle(); + List tiles = new ArrayList<>(); + //get the tiles + for(BlockPosition position : positions){ + if(nativeWorld.getType(position) == Blocks.AIR.getBlockData()) + continue; + //TileEntity tile = nativeWorld.removeTileEntity(position); + TileEntity tile = removeTileEntity(nativeWorld,position); + if(tile == null) + continue; + //get the nextTick to move with the tile + + //nativeWorld.capturedTileEntities.remove(position); + //nativeWorld.getChunkAtWorldCoords(position).getTileEntities().remove(position); + tiles.add(new TileHolder(tile, tickProvider.getNextTick((WorldServer)nativeWorld,position), position)); + + } + //******************************************* + //* Step three: Translate all the blocks * + //******************************************* + // blockedByWater=false means an ocean-going vessel + //TODO: Simplify + //TODO: go by chunks + //TODO: Don't move unnecessary blocks + //get the blocks + List blockData = new ArrayList<>(); + for(BlockPosition position : positions){ + blockData.add(nativeWorld.getType(position)); + } + //translate the positions + List newPositions = new ArrayList<>(); + for(BlockPosition position : positions){ + newPositions.add(position.a(translateVector)); + } + //create the new block + for(int i = 0; i deletePositions = CollectionUtils.filter(positions,newPositions); + for(BlockPosition position : deletePositions){ + setBlockFast(nativeWorld, position, Blocks.AIR.getBlockData()); + } + + //******************************************* + //* Step six: Update the blocks * + //******************************************* + for(BlockPosition newPosition : newPositions) { + CraftBlockState.getBlockState(nativeWorld,newPosition.getX(), newPosition.getY(), newPosition.getZ()).update(false,false); + } + for(BlockPosition deletedPosition : deletePositions){ + CraftBlockState.getBlockState(nativeWorld,deletedPosition.getX(), deletedPosition.getY(), deletedPosition.getZ()).update(false,false); + } + //******************************************* + //* Step seven: Send to players * + //******************************************* + List chunks = new ArrayList<>(); + for(BlockPosition position : newPositions){ + Chunk chunk = nativeWorld.getChunkAtWorldCoords(position); + if(!chunks.contains(chunk)){ + chunks.add(chunk); + } + } + for(BlockPosition position : deletePositions){ + Chunk chunk = nativeWorld.getChunkAtWorldCoords(position); + if(!chunks.contains(chunk)){ + chunks.add(chunk); + } + } + //sendToPlayers(chunks.toArray(new Chunk[0])); + } + + @Nullable + private TileEntity removeTileEntity(@NotNull World world, @NotNull BlockPosition position){ + TileEntity tile = world.getTileEntity(position); + if(tile == null) + return null; + //cleanup + world.capturedTileEntities.remove(position); + world.getChunkAtWorldCoords(position).getTileEntities().remove(position); + if(!Settings.IsPaper) + world.tileEntityList.remove(tile); + world.tileEntityListTick.remove(tile); + if(!bMap.containsKey(world)){ + try { + Field bField = World.class.getDeclaredField("b"); + bField.setAccessible(true); + bMap.put(world, (List) bField.get(world)); + } catch (IllegalAccessException | IllegalArgumentException | NoSuchFieldException | SecurityException e1) { + e1.printStackTrace(); + } + } + bMap.get(world).remove(tile); + return tile; + } + + @NotNull + private BlockPosition locationToPosition(@NotNull MovecraftLocation loc) { + return new BlockPosition(loc.getX(), loc.getY(), loc.getZ()); + } + + private void setBlockFast(@NotNull World world, @NotNull BlockPosition position,@NotNull IBlockData data) { + Chunk chunk = world.getChunkAtWorldCoords(position); + ChunkSection chunkSection = chunk.getSections()[position.getY()>>4]; + if (chunkSection == null) { + // Put a GLASS block to initialize the section. It will be replaced next with the real block. + chunk.a(position, Blocks.GLASS.getBlockData()); + chunkSection = chunk.getSections()[position.getY() >> 4]; + } + + chunkSection.setType(position.getX()&15, position.getY()&15, position.getZ()&15, data); + } + + @Override + public void setBlockFast(@NotNull Location location, @NotNull Material material, byte data){ + setBlockFast(location, Rotation.NONE, material, data); + } + + @Override + public void setBlockFast(@NotNull Location location, @NotNull Rotation rotation, @NotNull Material material, byte data) { + IBlockData blockData = CraftMagicNumbers.getBlock(material).fromLegacyData(data); + blockData = blockData.a(ROTATION[rotation.ordinal()]); + World world = ((CraftWorld)(location.getWorld())).getHandle(); + BlockPosition blockPosition = locationToPosition(bukkit2MovecraftLoc(location)); + setBlockFast(world,blockPosition,blockData); + } + + @Override + public void disableShadow(@NotNull Material type) { + Method method; + try { + Block tempBlock = CraftMagicNumbers.getBlock(type.getId()); + method = Block.class.getDeclaredMethod("d", int.class); + method.setAccessible(true); + method.invoke(tempBlock, 0); + } catch (NoSuchMethodException | InvocationTargetException | IllegalArgumentException | IllegalAccessException | SecurityException e1) { + // TODO Auto-generated catch block + e1.printStackTrace(); + } + } + + private static MovecraftLocation bukkit2MovecraftLoc(Location l) { + return new MovecraftLocation(l.getBlockX(), l.getBlockY(), l.getBlockZ()); + } + + private void moveTileEntity(@NotNull World nativeWorld, @NotNull BlockPosition newPosition, @NotNull TileEntity tile){ + Chunk chunk = nativeWorld.getChunkAtWorldCoords(newPosition); + tile.invalidateBlockCache(); + if(nativeWorld.captureBlockStates) { + tile.a(nativeWorld); + tile.a(newPosition); + nativeWorld.capturedTileEntities.put(newPosition, tile); + return; + } + tile.a(newPosition); + chunk.tileEntities.put(newPosition, tile); + } + + private class TileHolder{ + @NotNull private final TileEntity tile; + @Nullable + private final NextTickListEntry nextTick; + @NotNull private final BlockPosition tilePosition; + + public TileHolder(@NotNull TileEntity tile, @Nullable NextTickListEntry nextTick, @NotNull BlockPosition tilePosition){ + this.tile = tile; + this.nextTick = nextTick; + this.tilePosition = tilePosition; + } + + + @NotNull + public TileEntity getTile() { + return tile; + } + + @Nullable + public NextTickListEntry getNextTick() { + return nextTick; + } + + @NotNull + public BlockPosition getTilePosition() { + return tilePosition; + } + } +} diff --git a/modules/v1_9_R2/src/main/java/net/countercraft/movecraft/compat/v1_9_R2/NextTickProvider.java b/modules/v1_9_R2/src/main/java/net/countercraft/movecraft/compat/v1_9_R2/NextTickProvider.java new file mode 100644 index 000000000..98d5ee3dd --- /dev/null +++ b/modules/v1_9_R2/src/main/java/net/countercraft/movecraft/compat/v1_9_R2/NextTickProvider.java @@ -0,0 +1,67 @@ +package net.countercraft.movecraft.compat.v1_9_R2; + +import net.minecraft.server.v1_9_R2.BlockPosition; +import net.minecraft.server.v1_9_R2.NextTickListEntry; +import net.minecraft.server.v1_9_R2.WorldServer; +import org.apache.commons.lang3.tuple.ImmutablePair; +import org.bukkit.craftbukkit.v1_9_R2.util.HashTreeSet; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.lang.ref.WeakReference; +import java.lang.reflect.Field; +import java.util.*; + +public class NextTickProvider { + private Map>,WeakReference>>> tickMap = new HashMap<>(); + + private boolean isRegistered(@NotNull WorldServer world){ + if(!tickMap.containsKey(world)) + return false; + ImmutablePair>, WeakReference>> listPair = tickMap.get(world); + return listPair.right.get() != null && listPair.left.get() != null; + } + + @SuppressWarnings("unchecked") + private void registerWorld(@NotNull WorldServer world){ + List U = new ArrayList<>(); + HashTreeSet nextTickList = new HashTreeSet<>(); + + try { + + Field UField = WorldServer.class.getDeclaredField("U"); + UField.setAccessible(true); + U = (List) UField.get(world); + Field nextTickListField = WorldServer.class.getDeclaredField("nextTickList"); + nextTickListField.setAccessible(true); + nextTickList = (HashTreeSet) nextTickListField.get(world); + } catch (IllegalAccessException | IllegalArgumentException | NoSuchFieldException | SecurityException e1) { + e1.printStackTrace(); + } + tickMap.put(world, new ImmutablePair<>(new WeakReference<>(nextTickList), new WeakReference<>(U))); + } + + @Nullable + @SuppressWarnings("ConstantConditions") + public NextTickListEntry getNextTick(@NotNull WorldServer world, @NotNull BlockPosition position){ + if(!isRegistered(world)) + registerWorld(world); + ImmutablePair>, WeakReference>> listPair = tickMap.get(world); + for(Iterator iterator = listPair.left.get().iterator(); iterator.hasNext();) { + NextTickListEntry listEntry = iterator.next(); + if (position.equals(listEntry.a)) { + iterator.remove(); + return listEntry; + } + } + for(Iterator iterator = listPair.right.get().iterator(); iterator.hasNext();) { + NextTickListEntry listEntry = iterator.next(); + if (position.equals(listEntry.a)) { + iterator.remove(); + return listEntry; + } + } + return null; + + } +} diff --git a/pom.xml b/pom.xml index 69a261f9f..4ba1ff0c0 100644 --- a/pom.xml +++ b/pom.xml @@ -29,6 +29,8 @@ modules/worldedit/WE6Utils modules/worldedit/WE7Utils modules/Movecraft + modules/v1_9_R2 + modules/v1_8_R3 From f45c2488ae9671d2689735092ba36de91544cd6e Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Wed, 11 Dec 2019 11:39:11 +0100 Subject: [PATCH 093/304] Fixed a problem with pre-1.9 sounds and fixed legacy craft files --- .../net/countercraft/movecraft/Movecraft.java | 3 +- .../movecraft/async/AsyncManager.java | 2 +- .../async/translation/TranslationTask.java | 2 +- .../resources/types/legacy/BigAirship.craft | 233 +++++++++-------- .../types/legacy/BigSubAirship.craft | 233 +++++++++-------- .../types/legacy/LaunchTorpedo.craft | 4 +- .../main/resources/types/legacy/Ship.craft | 232 +++++++++-------- .../resources/types/legacy/SubAirship.craft | 233 +++++++++-------- .../resources/types/legacy/Submarine.craft | 233 +++++++++-------- .../main/resources/types/legacy/Turret.craft | 238 +++++++++--------- .../main/resources/types/legacy/airship.craft | 230 +++++++++-------- .../resources/types/legacy/airskiff.craft | 181 +++++++------ .../resources/types/legacy/elevator.craft | 184 ++++++++------ .../movecraft/config/Settings.java | 1 + .../movecraft/utils/LegacyUtils.java | 3 +- modules/v1_15_R1/pom.xml | 4 +- .../compat/v1_8_R3/NextTickProvider.java | 18 +- modules/v1_9_R2/pom.xml | 1 + pom.xml | 5 +- 19 files changed, 1039 insertions(+), 1001 deletions(-) diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java index f2e1acc96..cf55c7f48 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java @@ -98,8 +98,9 @@ public void onEnable() { String[] parts = version.split("_"); int versionNumber = Integer.valueOf(parts[1]); //Check if the server is 1.12 and lower or 1.13 and higher + Settings.IsPre1_9 = versionNumber < 9; Settings.IsLegacy = versionNumber <= 12; - Settings.is1_14 = versionNumber == 14; + Settings.is1_14 = versionNumber >= 14; // Read in config if (!Settings.IsLegacy) { this.saveDefaultConfig(); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java index 227b000da..da1efde10 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java @@ -557,7 +557,7 @@ private void detectSinking(){ pcraft.setDisabled(true); if (pcraft.getNotificationPlayer() != null) { Location loc = pcraft.getNotificationPlayer().getLocation(); - pcraft.getW().playSound(loc, Settings.IsLegacy ? LegacyUtils.ENITIY_IRONGOLEM_DEATH : Sound.ENTITY_IRON_GOLEM_DEATH , 5.0f, 5.0f); + pcraft.getW().playSound(loc, Settings.IsLegacy ? (Settings.IsPre1_9 ? LegacyUtils.IRONGOLEM_DEATH : LegacyUtils.ENITIY_IRONGOLEM_DEATH) : Sound.ENTITY_IRON_GOLEM_DEATH , 5.0f, 5.0f); } } } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java index 0804eeb31..6c4c1f6cb 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java @@ -438,7 +438,7 @@ private void fail(String message) { craft.getW().playSound(location, Sound.BLOCK_ANVIL_LAND, 1.0f, 0.25f); //craft.setCurTickCooldown(craft.getType().getCruiseTickCooldown()); } else { - craft.getW().playSound(location, Settings.IsLegacy ? LegacyUtils.ENITIY_IRONGOLEM_DEATH : Sound.ENTITY_IRON_GOLEM_DEATH, 5.0f, 5.0f); + craft.getW().playSound(location, Settings.IsLegacy ? (Settings.IsPre1_9 ? LegacyUtils.IRONGOLEM_DEATH : LegacyUtils.ENITIY_IRONGOLEM_DEATH) : Sound.ENTITY_IRON_GOLEM_DEATH, 5.0f, 5.0f); //craft.setCurTickCooldown(craft.getType().getCruiseTickCooldown()); } } diff --git a/modules/Movecraft/src/main/resources/types/legacy/BigAirship.craft b/modules/Movecraft/src/main/resources/types/legacy/BigAirship.craft index b74bec32b..d4ffde00e 100644 --- a/modules/Movecraft/src/main/resources/types/legacy/BigAirship.craft +++ b/modules/Movecraft/src/main/resources/types/legacy/BigAirship.craft @@ -1,124 +1,123 @@ name: BigAirship maxSize: 20000 minSize: 10000 -allowedBlocks: - WOOD: - STATIONARY_WATER: - WATER: - STATIONARY_LAVA: - LAVA: - LOG: - GLASS: - LAPIS_BLOCK: - DISPENSER: - NOTE_BLOCK: - BED_BLOCK: - PISTON_STICKY_BASE: - PISTON_BASE: - PISTON_EXTENSION: - WOOL: - GOLD_BLOCK: - IRON_BLOCK: - DOUBLE_STEP: - STEP: - BOOKSHELF: - TORCH: - FIRE: - WOOD_STAIRS: - CHEST: - REDSTONE_WIRE: - DIAMOND_BLOCK: - WORKBENCH: - FURNACE: - BURNING_FURNACE: - SIGN_POST: - WOOD_DOOR: - LADDER: - WALL_SIGN: - LEVER: - STONE_PLATE: - IRON_DOOR: - WOOD_PLATE: - REDSTONE_TORCH_ON: - REDSTONE_TORCH_OFF: - STONE_BUTTON: - CLAY: - FENCE: - NETHERRACK: - GLOWSTONE: - CAKE_BLOCK: - DIODE_BLOCK_OFF: - DIODE_BLOCK_ON: - STAINED_GLASS: - TRAP_DOOR: - SMOOTH_BRICK: - IRON_FENCE: - THIN_GLASS: - FENCE_GATE: - SMOOTH_STAIRS: - NETHER_BRICK: - NETHER_FENCE: - NETHER_BRICK_STAIRS: - ENCHANTMENT_TABLE: - BREWING_STAND: - CAULDRON: - ENDER_STONE: - DRAGON_EGG: - REDSTONE_LAMP_ON: - REDSTONE_LAMP_OFF: - WOOD_DOUBLE_STEP: - WOOD_STEP: - ENDER_CHEST: - TRIPWIRE_HOOK: - EMERALD_BLOCK: - SPRUCE_WOOD_STAIRS: - BIRCH_WOOD_STAIRS: - JUNGLE_WOOD_STAIRS: - BEACON: - COBBLE_WALL: - FLOWER_POT: - WOOD_BUTTON: - SKULL: - ANVIL: - TRAPPED_CHEST: - GOLD_PLATE: - IRON_PLATE: - REDSTONE_COMPARATOR_OFF: - REDSTONE_COMPARATOR_ON: - DAYLIGHT_SENSOR: - REDSTONE_BLOCK: - HOPPER: - QUARTZ_BLOCK: - QUARTZ_STAIRS: - ACTIVATOR_RAIL: - DROPPER: - STAINED_CLAY: - STAINED_GLASS_PANE: - SLIME_BLOCK: - CARPET: - HARD_CLAY: - COAL_BLOCK: - IRON_TRAPDOOR: - DAYLIGHT_SENSOR_INVERTED: - SPRUCE_FENCE_GATE: - BIRCH_FENCE_GATE: - JUNGLE_FENCE_GATE: - DARK_OAK_FENCE_GATE: - ACACIA_FENCE_GATE: - SPRUCE_FENCE: - BIRCH_FENCE: - JUNGLE_FENCE: - ACACIA_FENCE: - DARK_OAK_FENCE: - SPRUCE_DOOR: - BIRCH_DOOR: - JUNGLE_DOOR: - ACACIA_DOOR: - DARK_OAK_DOOR: - END_BRICKS: +allowedBlocks: + - WOOD + - STATIONARY_WATER + - WATER + - STATIONARY_LAVA + - LAVA + - LOG + - GLASS + - LAPIS_BLOCK + - DISPENSER + - NOTE_BLOCK + - BED_BLOCK + - PISTON_STICKY_BASE + - PISTON_BASE + - PISTON_EXTENSION + - WOOL + - GOLD_BLOCK + - IRON_BLOCK + - DOUBLE_STEP + - STEP + - BOOKSHELF + - TORCH + - FIRE + - WOOD_STAIRS + - CHEST + - REDSTONE_WIRE + - DIAMOND_BLOCK + - WORKBENCH + - FURNACE + - BURNING_FURNACE + - SIGN_POST + - WOOD_DOOR + - LADDER + - WALL_SIGN + - LEVER + - STONE_PLATE + - IRON_DOOR + - WOOD_PLATE + - REDSTONE_TORCH_ON + - REDSTONE_TORCH_OFF + - STONE_BUTTON + - CLAY + - FENCE + - NETHERRACK + - GLOWSTONE + - CAKE_BLOCK + - DIODE_BLOCK_OFF + - DIODE_BLOCK_ON + - STAINED_GLASS + - TRAP_DOOR + - SMOOTH_BRICK + - IRON_FENCE + - THIN_GLASS + - FENCE_GATE + - SMOOTH_STAIRS + - NETHER_BRICK + - NETHER_FENCE + - NETHER_BRICK_STAIRS + - ENCHANTMENT_TABLE + - BREWING_STAND + - CAULDRON + - ENDER_STONE + - DRAGON_EGG + - REDSTONE_LAMP_ON + - REDSTONE_LAMP_OFF + - WOOD_DOUBLE_STEP + - WOOD_STEP + - ENDER_CHEST + - TRIPWIRE_HOOK + - EMERALD_BLOCK + - SPRUCE_WOOD_STAIRS + - BIRCH_WOOD_STAIRS + - JUNGLE_WOOD_STAIRS + - BEACON + - COBBLE_WALL + - FLOWER_POT + - WOOD_BUTTON + - SKULL + - ANVIL + - TRAPPED_CHEST + - GOLD_PLATE + - IRON_PLATE + - REDSTONE_COMPARATOR_OFF + - REDSTONE_COMPARATOR_ON + - DAYLIGHT_SENSOR + - REDSTONE_BLOCK + - HOPPER + - QUARTZ_BLOCK + - QUARTZ_STAIRS + - ACTIVATOR_RAIL + - DROPPER + - STAINED_CLAY + - STAINED_GLASS_PANE + - SLIME_BLOCK + - CARPET + - HARD_CLAY + - COAL_BLOCK + - IRON_TRAPDOOR + - DAYLIGHT_SENSOR_INVERTED + - SPRUCE_FENCE_GATE + - BIRCH_FENCE_GATE + - JUNGLE_FENCE_GATE + - DARK_OAK_FENCE_GATE + - ACACIA_FENCE_GATE + - SPRUCE_FENCE + - BIRCH_FENCE + - JUNGLE_FENCE + - ACACIA_FENCE + - DARK_OAK_FENCE + - SPRUCE_DOOR + - BIRCH_DOOR + - JUNGLE_DOOR + - ACACIA_DOOR + - DARK_OAK_DOOR + - END_BRICKS + -forbiddenBlocks: - PISTON_EXTENSION: canCruise: true rotateAtMidpoint: true diff --git a/modules/Movecraft/src/main/resources/types/legacy/BigSubAirship.craft b/modules/Movecraft/src/main/resources/types/legacy/BigSubAirship.craft index 258fe1b8e..9920f4513 100644 --- a/modules/Movecraft/src/main/resources/types/legacy/BigSubAirship.craft +++ b/modules/Movecraft/src/main/resources/types/legacy/BigSubAirship.craft @@ -1,124 +1,121 @@ name: BigSubAirship maxSize: 20000 minSize: 10000 -allowedBlocks: - WOOD: - STATIONARY_WATER: - WATER: - STATIONARY_LAVA: - LAVA: - LOG: - GLASS: - LAPIS_BLOCK: - DISPENSER: - NOTE_BLOCK: - BED_BLOCK: - PISTON_STICKY_BASE: - PISTON_BASE: - PISTON_EXTENSION: - WOOL: - GOLD_BLOCK: - IRON_BLOCK: - DOUBLE_STEP: - STEP: - BOOKSHELF: - TORCH: - FIRE: - WOOD_STAIRS: - CHEST: - REDSTONE_WIRE: - DIAMOND_BLOCK: - WORKBENCH: - FURNACE: - BURNING_FURNACE: - SIGN_POST: - WOOD_DOOR: - LADDER: - WALL_SIGN: - LEVER: - STONE_PLATE: - IRON_DOOR: - WOOD_PLATE: - REDSTONE_TORCH_ON: - REDSTONE_TORCH_OFF: - STONE_BUTTON: - CLAY: - FENCE: - NETHERRACK: - GLOWSTONE: - CAKE_BLOCK: - DIODE_BLOCK_OFF: - DIODE_BLOCK_ON: - STAINED_GLASS: - TRAP_DOOR: - SMOOTH_BRICK: - IRON_FENCE: - THIN_GLASS: - FENCE_GATE: - SMOOTH_STAIRS: - NETHER_BRICK: - NETHER_FENCE: - NETHER_BRICK_STAIRS: - ENCHANTMENT_TABLE: - BREWING_STAND: - CAULDRON: - ENDER_STONE: - DRAGON_EGG: - REDSTONE_LAMP_ON: - REDSTONE_LAMP_OFF: - WOOD_DOUBLE_STEP: - WOOD_STEP: - ENDER_CHEST: - TRIPWIRE_HOOK: - EMERALD_BLOCK: - SPRUCE_WOOD_STAIRS: - BIRCH_WOOD_STAIRS: - JUNGLE_WOOD_STAIRS: - BEACON: - COBBLE_WALL: - FLOWER_POT: - WOOD_BUTTON: - SKULL: - ANVIL: - TRAPPED_CHEST: - GOLD_PLATE: - IRON_PLATE: - REDSTONE_COMPARATOR_OFF: - REDSTONE_COMPARATOR_ON: - DAYLIGHT_SENSOR: - REDSTONE_BLOCK: - HOPPER: - QUARTZ_BLOCK: - QUARTZ_STAIRS: - ACTIVATOR_RAIL: - DROPPER: - STAINED_CLAY: - STAINED_GLASS_PANE: - SLIME_BLOCK: - CARPET: - HARD_CLAY: - COAL_BLOCK: - IRON_TRAPDOOR: - DAYLIGHT_SENSOR_INVERTED: - SPRUCE_FENCE_GATE: - BIRCH_FENCE_GATE: - JUNGLE_FENCE_GATE: - DARK_OAK_FENCE_GATE: - ACACIA_FENCE_GATE: - SPRUCE_FENCE: - BIRCH_FENCE: - JUNGLE_FENCE: - ACACIA_FENCE: - DARK_OAK_FENCE: - SPRUCE_DOOR: - BIRCH_DOOR: - JUNGLE_DOOR: - ACACIA_DOOR: - DARK_OAK_DOOR: - END_BRICKS: - -forbiddenBlocks: - PISTON_EXTENSION: +allowedBlocks: + - WOOD + - STATIONARY_WATER + - WATER + - STATIONARY_LAVA + - LAVA + - LOG + - GLASS + - LAPIS_BLOCK + - DISPENSER + - NOTE_BLOCK + - BED_BLOCK + - PISTON_STICKY_BASE + - PISTON_BASE + - PISTON_EXTENSION + - WOOL + - GOLD_BLOCK + - IRON_BLOCK + - DOUBLE_STEP + - STEP + - BOOKSHELF + - TORCH + - FIRE + - WOOD_STAIRS + - CHEST + - REDSTONE_WIRE + - DIAMOND_BLOCK + - WORKBENCH + - FURNACE + - BURNING_FURNACE + - SIGN_POST + - WOOD_DOOR + - LADDER + - WALL_SIGN + - LEVER + - STONE_PLATE + - IRON_DOOR + - WOOD_PLATE + - REDSTONE_TORCH_ON + - REDSTONE_TORCH_OFF + - STONE_BUTTON + - CLAY + - FENCE + - NETHERRACK + - GLOWSTONE + - CAKE_BLOCK + - DIODE_BLOCK_OFF + - DIODE_BLOCK_ON + - STAINED_GLASS + - TRAP_DOOR + - SMOOTH_BRICK + - IRON_FENCE + - THIN_GLASS + - FENCE_GATE + - SMOOTH_STAIRS + - NETHER_BRICK + - NETHER_FENCE + - NETHER_BRICK_STAIRS + - ENCHANTMENT_TABLE + - BREWING_STAND + - CAULDRON + - ENDER_STONE + - DRAGON_EGG + - REDSTONE_LAMP_ON + - REDSTONE_LAMP_OFF + - WOOD_DOUBLE_STEP + - WOOD_STEP + - ENDER_CHEST + - TRIPWIRE_HOOK + - EMERALD_BLOCK + - SPRUCE_WOOD_STAIRS + - BIRCH_WOOD_STAIRS + - JUNGLE_WOOD_STAIRS + - BEACON + - COBBLE_WALL + - FLOWER_POT + - WOOD_BUTTON + - SKULL + - ANVIL + - TRAPPED_CHEST + - GOLD_PLATE + - IRON_PLATE + - REDSTONE_COMPARATOR_OFF + - REDSTONE_COMPARATOR_ON + - DAYLIGHT_SENSOR + - REDSTONE_BLOCK + - HOPPER + - QUARTZ_BLOCK + - QUARTZ_STAIRS + - ACTIVATOR_RAIL + - DROPPER + - STAINED_CLAY + - STAINED_GLASS_PANE + - SLIME_BLOCK + - CARPET + - HARD_CLAY + - COAL_BLOCK + - IRON_TRAPDOOR + - DAYLIGHT_SENSOR_INVERTED + - SPRUCE_FENCE_GATE + - BIRCH_FENCE_GATE + - JUNGLE_FENCE_GATE + - DARK_OAK_FENCE_GATE + - ACACIA_FENCE_GATE + - SPRUCE_FENCE + - BIRCH_FENCE + - JUNGLE_FENCE + - ACACIA_FENCE + - DARK_OAK_FENCE + - SPRUCE_DOOR + - BIRCH_DOOR + - JUNGLE_DOOR + - ACACIA_DOOR + - DARK_OAK_DOOR + - END_BRICKS canCruise: true rotateAtMidpoint: true diff --git a/modules/Movecraft/src/main/resources/types/legacy/LaunchTorpedo.craft b/modules/Movecraft/src/main/resources/types/legacy/LaunchTorpedo.craft index 0bd95152b..07d0776cf 100644 --- a/modules/Movecraft/src/main/resources/types/legacy/LaunchTorpedo.craft +++ b/modules/Movecraft/src/main/resources/types/legacy/LaunchTorpedo.craft @@ -2,10 +2,8 @@ name: LaunchTorpedo maxSize: 7 minSize: 1 allowedBlocks: - COAL_BLOCK: + - COAL_BLOCK -forbiddenBlocks: - BEDROCK: canCruise: true cruiseOnPilot: true diff --git a/modules/Movecraft/src/main/resources/types/legacy/Ship.craft b/modules/Movecraft/src/main/resources/types/legacy/Ship.craft index c9bc67f68..9ce74bd21 100644 --- a/modules/Movecraft/src/main/resources/types/legacy/Ship.craft +++ b/modules/Movecraft/src/main/resources/types/legacy/Ship.craft @@ -1,124 +1,122 @@ name: Ship maxSize: 100000 minSize: 10 -allowedBlocks: - WOOD: - STATIONARY_WATER: - WATER: - STATIONARY_LAVA: - LAVA: - LOG: - GLASS: - LAPIS_BLOCK: - DISPENSER: - NOTE_BLOCK: - BED_BLOCK: - PISTON_STICKY_BASE: - PISTON_BASE: - PISTON_EXTENSION: - WOOL: - GOLD_BLOCK: - IRON_BLOCK: - DOUBLE_STEP: - STEP: - BOOKSHELF: - TORCH: - FIRE: - WOOD_STAIRS: - CHEST: - REDSTONE_WIRE: - DIAMOND_BLOCK: - WORKBENCH: - FURNACE: - BURNING_FURNACE: - SIGN_POST: - WOOD_DOOR: - LADDER: - WALL_SIGN: - LEVER: - STONE_PLATE: - IRON_DOOR: - WOOD_PLATE: - REDSTONE_TORCH_ON: - REDSTONE_TORCH_OFF: - STONE_BUTTON: - CLAY: - FENCE: - NETHERRACK: - GLOWSTONE: - CAKE_BLOCK: - DIODE_BLOCK_OFF: - DIODE_BLOCK_ON: - STAINED_GLASS: - TRAP_DOOR: - SMOOTH_BRICK: - IRON_FENCE: - THIN_GLASS: - FENCE_GATE: - SMOOTH_STAIRS: - NETHER_BRICK: - NETHER_FENCE: - NETHER_BRICK_STAIRS: - ENCHANTMENT_TABLE: - BREWING_STAND: - CAULDRON: - ENDER_STONE: - DRAGON_EGG: - REDSTONE_LAMP_ON: - REDSTONE_LAMP_OFF: - WOOD_DOUBLE_STEP: - WOOD_STEP: - ENDER_CHEST: - TRIPWIRE_HOOK: - EMERALD_BLOCK: - SPRUCE_WOOD_STAIRS: - BIRCH_WOOD_STAIRS: - JUNGLE_WOOD_STAIRS: - BEACON: - COBBLE_WALL: - FLOWER_POT: - WOOD_BUTTON: - SKULL: - ANVIL: - TRAPPED_CHEST: - GOLD_PLATE: - IRON_PLATE: - REDSTONE_COMPARATOR_OFF: - REDSTONE_COMPARATOR_ON: - DAYLIGHT_SENSOR: - REDSTONE_BLOCK: - HOPPER: - QUARTZ_BLOCK: - QUARTZ_STAIRS: - ACTIVATOR_RAIL: - DROPPER: - STAINED_CLAY: - STAINED_GLASS_PANE: - SLIME_BLOCK: - CARPET: - HARD_CLAY: - COAL_BLOCK: - IRON_TRAPDOOR: - DAYLIGHT_SENSOR_INVERTED: - SPRUCE_FENCE_GATE: - BIRCH_FENCE_GATE: - JUNGLE_FENCE_GATE: - DARK_OAK_FENCE_GATE: - ACACIA_FENCE_GATE: - SPRUCE_FENCE: - BIRCH_FENCE: - JUNGLE_FENCE: - ACACIA_FENCE: - DARK_OAK_FENCE: - SPRUCE_DOOR: - BIRCH_DOOR: - JUNGLE_DOOR: - ACACIA_DOOR: - DARK_OAK_DOOR: - END_BRICKS: +allowedBlocks: + - WOOD + - STATIONARY_WATER + - WATER + - STATIONARY_LAVA + - LAVA + - LOG + - GLASS + - LAPIS_BLOCK + - DISPENSER + - NOTE_BLOCK + - BED_BLOCK + - PISTON_STICKY_BASE + - PISTON_BASE + - PISTON_EXTENSION + - WOOL + - GOLD_BLOCK + - IRON_BLOCK + - DOUBLE_STEP + - STEP + - BOOKSHELF + - TORCH + - FIRE + - WOOD_STAIRS + - CHEST + - REDSTONE_WIRE + - DIAMOND_BLOCK + - WORKBENCH + - FURNACE + - BURNING_FURNACE + - SIGN_POST + - WOOD_DOOR + - LADDER + - WALL_SIGN + - LEVER + - STONE_PLATE + - IRON_DOOR + - WOOD_PLATE + - REDSTONE_TORCH_ON + - REDSTONE_TORCH_OFF + - STONE_BUTTON + - CLAY + - FENCE + - NETHERRACK + - GLOWSTONE + - CAKE_BLOCK + - DIODE_BLOCK_OFF + - DIODE_BLOCK_ON + - STAINED_GLASS + - TRAP_DOOR + - SMOOTH_BRICK + - IRON_FENCE + - THIN_GLASS + - FENCE_GATE + - SMOOTH_STAIRS + - NETHER_BRICK + - NETHER_FENCE + - NETHER_BRICK_STAIRS + - ENCHANTMENT_TABLE + - BREWING_STAND + - CAULDRON + - ENDER_STONE + - DRAGON_EGG + - REDSTONE_LAMP_ON + - REDSTONE_LAMP_OFF + - WOOD_DOUBLE_STEP + - WOOD_STEP + - ENDER_CHEST + - TRIPWIRE_HOOK + - EMERALD_BLOCK + - SPRUCE_WOOD_STAIRS + - BIRCH_WOOD_STAIRS + - JUNGLE_WOOD_STAIRS + - BEACON + - COBBLE_WALL + - FLOWER_POT + - WOOD_BUTTON + - SKULL + - ANVIL + - TRAPPED_CHEST + - GOLD_PLATE + - IRON_PLATE + - REDSTONE_COMPARATOR_OFF + - REDSTONE_COMPARATOR_ON + - DAYLIGHT_SENSOR + - REDSTONE_BLOCK + - HOPPER + - QUARTZ_BLOCK + - QUARTZ_STAIRS + - ACTIVATOR_RAIL + - DROPPER + - STAINED_CLAY + - STAINED_GLASS_PANE + - SLIME_BLOCK + - CARPET + - HARD_CLAY + - COAL_BLOCK + - IRON_TRAPDOOR + - DAYLIGHT_SENSOR_INVERTED + - SPRUCE_FENCE_GATE + - BIRCH_FENCE_GATE + - JUNGLE_FENCE_GATE + - DARK_OAK_FENCE_GATE + - ACACIA_FENCE_GATE + - SPRUCE_FENCE + - BIRCH_FENCE + - JUNGLE_FENCE + - ACACIA_FENCE + - DARK_OAK_FENCE + - SPRUCE_DOOR + - BIRCH_DOOR + - JUNGLE_DOOR + - ACACIA_DOOR + - DARK_OAK_DOOR + - END_BRICKS -forbiddenBlocks: - BEDROCK: canCruise: true cruiseSkipBlocks: 4 diff --git a/modules/Movecraft/src/main/resources/types/legacy/SubAirship.craft b/modules/Movecraft/src/main/resources/types/legacy/SubAirship.craft index 0983b3fbf..9115aece9 100644 --- a/modules/Movecraft/src/main/resources/types/legacy/SubAirship.craft +++ b/modules/Movecraft/src/main/resources/types/legacy/SubAirship.craft @@ -1,124 +1,121 @@ name: SubAirship maxSize: 5000 minSize: 1000 -allowedBlocks: - WOOD: - STATIONARY_WATER: - WATER: - STATIONARY_LAVA: - LAVA: - LOG: - GLASS: - LAPIS_BLOCK: - DISPENSER: - NOTE_BLOCK: - BED_BLOCK: - PISTON_STICKY_BASE: - PISTON_BASE: - PISTON_EXTENSION: - WOOL: - GOLD_BLOCK: - IRON_BLOCK: - DOUBLE_STEP: - STEP: - BOOKSHELF: - TORCH: - FIRE: - WOOD_STAIRS: - CHEST: - REDSTONE_WIRE: - DIAMOND_BLOCK: - WORKBENCH: - FURNACE: - BURNING_FURNACE: - SIGN_POST: - WOOD_DOOR: - LADDER: - WALL_SIGN: - LEVER: - STONE_PLATE: - IRON_DOOR: - WOOD_PLATE: - REDSTONE_TORCH_ON: - REDSTONE_TORCH_OFF: - STONE_BUTTON: - CLAY: - FENCE: - NETHERRACK: - GLOWSTONE: - CAKE_BLOCK: - DIODE_BLOCK_OFF: - DIODE_BLOCK_ON: - STAINED_GLASS: - TRAP_DOOR: - SMOOTH_BRICK: - IRON_FENCE: - THIN_GLASS: - FENCE_GATE: - SMOOTH_STAIRS: - NETHER_BRICK: - NETHER_FENCE: - NETHER_BRICK_STAIRS: - ENCHANTMENT_TABLE: - BREWING_STAND: - CAULDRON: - ENDER_STONE: - DRAGON_EGG: - REDSTONE_LAMP_ON: - REDSTONE_LAMP_OFF: - WOOD_DOUBLE_STEP: - WOOD_STEP: - ENDER_CHEST: - TRIPWIRE_HOOK: - EMERALD_BLOCK: - SPRUCE_WOOD_STAIRS: - BIRCH_WOOD_STAIRS: - JUNGLE_WOOD_STAIRS: - BEACON: - COBBLE_WALL: - FLOWER_POT: - WOOD_BUTTON: - SKULL: - ANVIL: - TRAPPED_CHEST: - GOLD_PLATE: - IRON_PLATE: - REDSTONE_COMPARATOR_OFF: - REDSTONE_COMPARATOR_ON: - DAYLIGHT_SENSOR: - REDSTONE_BLOCK: - HOPPER: - QUARTZ_BLOCK: - QUARTZ_STAIRS: - ACTIVATOR_RAIL: - DROPPER: - STAINED_CLAY: - STAINED_GLASS_PANE: - SLIME_BLOCK: - CARPET: - HARD_CLAY: - COAL_BLOCK: - IRON_TRAPDOOR: - DAYLIGHT_SENSOR_INVERTED: - SPRUCE_FENCE_GATE: - BIRCH_FENCE_GATE: - JUNGLE_FENCE_GATE: - DARK_OAK_FENCE_GATE: - ACACIA_FENCE_GATE: - SPRUCE_FENCE: - BIRCH_FENCE: - JUNGLE_FENCE: - ACACIA_FENCE: - DARK_OAK_FENCE: - SPRUCE_DOOR: - BIRCH_DOOR: - JUNGLE_DOOR: - ACACIA_DOOR: - DARK_OAK_DOOR: - END_BRICKS: - -forbiddenBlocks: - PISTON_EXTENSION: +allowedBlocks: + - WOOD + - STATIONARY_WATER + - WATER + - STATIONARY_LAVA + - LAVA + - LOG + - GLASS + - LAPIS_BLOCK + - DISPENSER + - NOTE_BLOCK + - BED_BLOCK + - PISTON_STICKY_BASE + - PISTON_BASE + - PISTON_EXTENSION + - WOOL + - GOLD_BLOCK + - IRON_BLOCK + - DOUBLE_STEP + - STEP + - BOOKSHELF + - TORCH + - FIRE + - WOOD_STAIRS + - CHEST + - REDSTONE_WIRE + - DIAMOND_BLOCK + - WORKBENCH + - FURNACE + - BURNING_FURNACE + - SIGN_POST + - WOOD_DOOR + - LADDER + - WALL_SIGN + - LEVER + - STONE_PLATE + - IRON_DOOR + - WOOD_PLATE + - REDSTONE_TORCH_ON + - REDSTONE_TORCH_OFF + - STONE_BUTTON + - CLAY + - FENCE + - NETHERRACK + - GLOWSTONE + - CAKE_BLOCK + - DIODE_BLOCK_OFF + - DIODE_BLOCK_ON + - STAINED_GLASS + - TRAP_DOOR + - SMOOTH_BRICK + - IRON_FENCE + - THIN_GLASS + - FENCE_GATE + - SMOOTH_STAIRS + - NETHER_BRICK + - NETHER_FENCE + - NETHER_BRICK_STAIRS + - ENCHANTMENT_TABLE + - BREWING_STAND + - CAULDRON + - ENDER_STONE + - DRAGON_EGG + - REDSTONE_LAMP_ON + - REDSTONE_LAMP_OFF + - WOOD_DOUBLE_STEP + - WOOD_STEP + - ENDER_CHEST + - TRIPWIRE_HOOK + - EMERALD_BLOCK + - SPRUCE_WOOD_STAIRS + - BIRCH_WOOD_STAIRS + - JUNGLE_WOOD_STAIRS + - BEACON + - COBBLE_WALL + - FLOWER_POT + - WOOD_BUTTON + - SKULL + - ANVIL + - TRAPPED_CHEST + - GOLD_PLATE + - IRON_PLATE + - REDSTONE_COMPARATOR_OFF + - REDSTONE_COMPARATOR_ON + - DAYLIGHT_SENSOR + - REDSTONE_BLOCK + - HOPPER + - QUARTZ_BLOCK + - QUARTZ_STAIRS + - ACTIVATOR_RAIL + - DROPPER + - STAINED_CLAY + - STAINED_GLASS_PANE + - SLIME_BLOCK + - CARPET + - HARD_CLAY + - COAL_BLOCK + - IRON_TRAPDOOR + - DAYLIGHT_SENSOR_INVERTED + - SPRUCE_FENCE_GATE + - BIRCH_FENCE_GATE + - JUNGLE_FENCE_GATE + - DARK_OAK_FENCE_GATE + - ACACIA_FENCE_GATE + - SPRUCE_FENCE + - BIRCH_FENCE + - JUNGLE_FENCE + - ACACIA_FENCE + - DARK_OAK_FENCE + - SPRUCE_DOOR + - BIRCH_DOOR + - JUNGLE_DOOR + - ACACIA_DOOR + - DARK_OAK_DOOR + - END_BRICKS canCruise: true rotateAtMidpoint: true diff --git a/modules/Movecraft/src/main/resources/types/legacy/Submarine.craft b/modules/Movecraft/src/main/resources/types/legacy/Submarine.craft index 750f3f943..d64e80221 100644 --- a/modules/Movecraft/src/main/resources/types/legacy/Submarine.craft +++ b/modules/Movecraft/src/main/resources/types/legacy/Submarine.craft @@ -1,124 +1,121 @@ name: Submarine maxSize: 100000 minSize: 10 -allowedBlocks: - WOOD: - STATIONARY_WATER: - WATER: - STATIONARY_LAVA: - LAVA: - LOG: - GLASS: - LAPIS_BLOCK: - DISPENSER: - NOTE_BLOCK: - BED_BLOCK: - PISTON_STICKY_BASE: - PISTON_BASE: - PISTON_EXTENSION: - WOOL: - GOLD_BLOCK: - IRON_BLOCK: - DOUBLE_STEP: - STEP: - BOOKSHELF: - TORCH: - FIRE: - WOOD_STAIRS: - CHEST: - REDSTONE_WIRE: - DIAMOND_BLOCK: - WORKBENCH: - FURNACE: - BURNING_FURNACE: - SIGN_POST: - WOOD_DOOR: - LADDER: - WALL_SIGN: - LEVER: - STONE_PLATE: - IRON_DOOR: - WOOD_PLATE: - REDSTONE_TORCH_ON: - REDSTONE_TORCH_OFF: - STONE_BUTTON: - CLAY: - FENCE: - NETHERRACK: - GLOWSTONE: - CAKE_BLOCK: - DIODE_BLOCK_OFF: - DIODE_BLOCK_ON: - STAINED_GLASS: - TRAP_DOOR: - SMOOTH_BRICK: - IRON_FENCE: - THIN_GLASS: - FENCE_GATE: - SMOOTH_STAIRS: - NETHER_BRICK: - NETHER_FENCE: - NETHER_BRICK_STAIRS: - ENCHANTMENT_TABLE: - BREWING_STAND: - CAULDRON: - ENDER_STONE: - DRAGON_EGG: - REDSTONE_LAMP_ON: - REDSTONE_LAMP_OFF: - WOOD_DOUBLE_STEP: - WOOD_STEP: - ENDER_CHEST: - TRIPWIRE_HOOK: - EMERALD_BLOCK: - SPRUCE_WOOD_STAIRS: - BIRCH_WOOD_STAIRS: - JUNGLE_WOOD_STAIRS: - BEACON: - COBBLE_WALL: - FLOWER_POT: - WOOD_BUTTON: - SKULL: - ANVIL: - TRAPPED_CHEST: - GOLD_PLATE: - IRON_PLATE: - REDSTONE_COMPARATOR_OFF: - REDSTONE_COMPARATOR_ON: - DAYLIGHT_SENSOR: - REDSTONE_BLOCK: - HOPPER: - QUARTZ_BLOCK: - QUARTZ_STAIRS: - ACTIVATOR_RAIL: - DROPPER: - STAINED_CLAY: - STAINED_GLASS_PANE: - SLIME_BLOCK: - CARPET: - HARD_CLAY: - COAL_BLOCK: - IRON_TRAPDOOR: - DAYLIGHT_SENSOR_INVERTED: - SPRUCE_FENCE_GATE: - BIRCH_FENCE_GATE: - JUNGLE_FENCE_GATE: - DARK_OAK_FENCE_GATE: - ACACIA_FENCE_GATE: - SPRUCE_FENCE: - BIRCH_FENCE: - JUNGLE_FENCE: - ACACIA_FENCE: - DARK_OAK_FENCE: - SPRUCE_DOOR: - BIRCH_DOOR: - JUNGLE_DOOR: - ACACIA_DOOR: - DARK_OAK_DOOR: - END_BRICKS: - -forbiddenBlocks: - PISTON_EXTENSION: +allowedBlocks: + - WOOD + - STATIONARY_WATER + - WATER + - STATIONARY_LAVA + - LAVA + - LOG + - GLASS + - LAPIS_BLOCK + - DISPENSER + - NOTE_BLOCK + - BED_BLOCK + - PISTON_STICKY_BASE + - PISTON_BASE + - PISTON_EXTENSION + - WOOL + - GOLD_BLOCK + - IRON_BLOCK + - DOUBLE_STEP + - STEP + - BOOKSHELF + - TORCH + - FIRE + - WOOD_STAIRS + - CHEST + - REDSTONE_WIRE + - DIAMOND_BLOCK + - WORKBENCH + - FURNACE + - BURNING_FURNACE + - SIGN_POST + - WOOD_DOOR + - LADDER + - WALL_SIGN + - LEVER + - STONE_PLATE + - IRON_DOOR + - WOOD_PLATE + - REDSTONE_TORCH_ON + - REDSTONE_TORCH_OFF + - STONE_BUTTON + - CLAY + - FENCE + - NETHERRACK + - GLOWSTONE + - CAKE_BLOCK + - DIODE_BLOCK_OFF + - DIODE_BLOCK_ON + - STAINED_GLASS + - TRAP_DOOR + - SMOOTH_BRICK + - IRON_FENCE + - THIN_GLASS + - FENCE_GATE + - SMOOTH_STAIRS + - NETHER_BRICK + - NETHER_FENCE + - NETHER_BRICK_STAIRS + - ENCHANTMENT_TABLE + - BREWING_STAND + - CAULDRON + - ENDER_STONE + - DRAGON_EGG + - REDSTONE_LAMP_ON + - REDSTONE_LAMP_OFF + - WOOD_DOUBLE_STEP + - WOOD_STEP + - ENDER_CHEST + - TRIPWIRE_HOOK + - EMERALD_BLOCK + - SPRUCE_WOOD_STAIRS + - BIRCH_WOOD_STAIRS + - JUNGLE_WOOD_STAIRS + - BEACON + - COBBLE_WALL + - FLOWER_POT + - WOOD_BUTTON + - SKULL + - ANVIL + - TRAPPED_CHEST + - GOLD_PLATE + - IRON_PLATE + - REDSTONE_COMPARATOR_OFF + - REDSTONE_COMPARATOR_ON + - DAYLIGHT_SENSOR + - REDSTONE_BLOCK + - HOPPER + - QUARTZ_BLOCK + - QUARTZ_STAIRS + - ACTIVATOR_RAIL + - DROPPER + - STAINED_CLAY + - STAINED_GLASS_PANE + - SLIME_BLOCK + - CARPET + - HARD_CLAY + - COAL_BLOCK + - IRON_TRAPDOOR + - DAYLIGHT_SENSOR_INVERTED + - SPRUCE_FENCE_GATE + - BIRCH_FENCE_GATE + - JUNGLE_FENCE_GATE + - DARK_OAK_FENCE_GATE + - ACACIA_FENCE_GATE + - SPRUCE_FENCE + - BIRCH_FENCE + - JUNGLE_FENCE + - ACACIA_FENCE + - DARK_OAK_FENCE + - SPRUCE_DOOR + - BIRCH_DOOR + - JUNGLE_DOOR + - ACACIA_DOOR + - DARK_OAK_DOOR + - END_BRICKS canCruise: true cruiseSkipBlocks: 4 diff --git a/modules/Movecraft/src/main/resources/types/legacy/Turret.craft b/modules/Movecraft/src/main/resources/types/legacy/Turret.craft index bd1e37d55..1f72cf4c8 100644 --- a/modules/Movecraft/src/main/resources/types/legacy/Turret.craft +++ b/modules/Movecraft/src/main/resources/types/legacy/Turret.craft @@ -1,126 +1,124 @@ name: Turret maxSize: 1000 minSize: 1 -allowedBlocks: - WOOD: - STATIONARY_WATER: - WATER: - STATIONARY_LAVA: - LAVA: - LOG: - GLASS: - LAPIS_BLOCK: - DISPENSER: - NOTE_BLOCK: - BED_BLOCK: - PISTON_STICKY_BASE: - PISTON_BASE: - PISTON_EXTENSION: - WOOL: - - 8 - GOLD_BLOCK: - IRON_BLOCK: - DOUBLE_STEP: - STEP: - BOOKSHELF: - TORCH: - FIRE: - WOOD_STAIRS: - CHEST: - REDSTONE_WIRE: - DIAMOND_BLOCK: - WORKBENCH: - FURNACE: - BURNING_FURNACE: - SIGN_POST: - WOOD_DOOR: - LADDER: - WALL_SIGN: - LEVER: - STONE_PLATE: - IRON_DOOR: - WOOD_PLATE: - STONE_BUTTON: - CLAY: - FENCE: - NETHERRACK: - GLOWSTONE: - CAKE_BLOCK: - DIODE_BLOCK_OFF: - DIODE_BLOCK_ON: - STAINED_GLASS: - TRAP_DOOR: - SMOOTH_BRICK: - IRON_FENCE: - THIN_GLASS: - FENCE_GATE: - SMOOTH_STAIRS: - NETHER_BRICK: - NETHER_FENCE: - NETHER_BRICK_STAIRS: - ENCHANTMENT_TABLE: - BREWING_STAND: - CAULDRON: - ENDER_STONE: - DRAGON_EGG: - REDSTONE_LAMP_ON: - REDSTONE_LAMP_OFF: - WOOD_DOUBLE_STEP: - WOOD_STEP: - ENDER_CHEST: - TRIPWIRE_HOOK: - EMERALD_BLOCK: - SPRUCE_WOOD_STAIRS: - BIRCH_WOOD_STAIRS: - JUNGLE_WOOD_STAIRS: - BEACON: - COBBLE_WALL: - FLOWER_POT: - WOOD_BUTTON: - SKULL: - ANVIL: - TRAPPED_CHEST: - GOLD_PLATE: - IRON_PLATE: - REDSTONE_COMPARATOR_OFF: - REDSTONE_COMPARATOR_ON: - DAYLIGHT_SENSOR: - REDSTONE_BLOCK: - HOPPER: - QUARTZ_BLOCK: - QUARTZ_STAIRS: - ACTIVATOR_RAIL: - DROPPER: - STAINED_CLAY: - - 7 - - 8 - - 15 - STAINED_GLASS_PANE: - SLIME_BLOCK: - CARPET: - HARD_CLAY: - COAL_BLOCK: - IRON_TRAPDOOR: - DAYLIGHT_SENSOR_INVERTED: - SPRUCE_FENCE_GATE: - BIRCH_FENCE_GATE: - JUNGLE_FENCE_GATE: - DARK_OAK_FENCE_GATE: - ACACIA_FENCE_GATE: - SPRUCE_FENCE: - BIRCH_FENCE: - JUNGLE_FENCE: - ACACIA_FENCE: - DARK_OAK_FENCE: - SPRUCE_DOOR: - BIRCH_DOOR: - JUNGLE_DOOR: - ACACIA_DOOR: - DARK_OAK_DOOR: - END_BRICKS: - -forbiddenBlocks: - BEDROCK: +allowedBlocks: + - WOOD + - STATIONARY_WATER + - WATER + - STATIONARY_LAVA + - LAVA + - LOG + - GLASS + - "STAINED_CLAY:7" + - "STAINED_CLAY:8" + - "STAINED_CLAY:15" + - LAPIS_BLOCK + - DISPENSER + - NOTE_BLOCK + - BED_BLOCK + - PISTON_STICKY_BASE + - PISTON_BASE + - PISTON_EXTENSION + - "WOOL:8" + - GOLD_BLOCK + - IRON_BLOCK + - DOUBLE_STEP + - STEP + - BOOKSHELF + - TORCH + - FIRE + - WOOD_STAIRS + - CHEST + - REDSTONE_WIRE + - DIAMOND_BLOCK + - WORKBENCH + - FURNACE + - BURNING_FURNACE + - SIGN_POST + - WOOD_DOOR + - LADDER + - WALL_SIGN + - LEVER + - STONE_PLATE + - IRON_DOOR + - WOOD_PLATE + - REDSTONE_TORCH_ON + - REDSTONE_TORCH_OFF + - STONE_BUTTON + - CLAY + - FENCE + - NETHERRACK + - GLOWSTONE + - CAKE_BLOCK + - DIODE_BLOCK_OFF + - DIODE_BLOCK_ON + - STAINED_GLASS + - TRAP_DOOR + - SMOOTH_BRICK + - IRON_FENCE + - THIN_GLASS + - FENCE_GATE + - SMOOTH_STAIRS + - NETHER_BRICK + - NETHER_FENCE + - NETHER_BRICK_STAIRS + - ENCHANTMENT_TABLE + - BREWING_STAND + - CAULDRON + - ENDER_STONE + - DRAGON_EGG + - REDSTONE_LAMP_ON + - REDSTONE_LAMP_OFF + - WOOD_DOUBLE_STEP + - WOOD_STEP + - ENDER_CHEST + - TRIPWIRE_HOOK + - EMERALD_BLOCK + - SPRUCE_WOOD_STAIRS + - BIRCH_WOOD_STAIRS + - JUNGLE_WOOD_STAIRS + - BEACON + - COBBLE_WALL + - FLOWER_POT + - WOOD_BUTTON + - SKULL + - ANVIL + - TRAPPED_CHEST + - GOLD_PLATE + - IRON_PLATE + - REDSTONE_COMPARATOR_OFF + - REDSTONE_COMPARATOR_ON + - DAYLIGHT_SENSOR + - REDSTONE_BLOCK + - HOPPER + - QUARTZ_BLOCK + - QUARTZ_STAIRS + - ACTIVATOR_RAIL + - DROPPER + - STAINED_CLAY + - STAINED_GLASS_PANE + - SLIME_BLOCK + - CARPET + - HARD_CLAY + - COAL_BLOCK + - IRON_TRAPDOOR + - DAYLIGHT_SENSOR_INVERTED + - SPRUCE_FENCE_GATE + - BIRCH_FENCE_GATE + - JUNGLE_FENCE_GATE + - DARK_OAK_FENCE_GATE + - ACACIA_FENCE_GATE + - SPRUCE_FENCE + - BIRCH_FENCE + - JUNGLE_FENCE + - ACACIA_FENCE + - DARK_OAK_FENCE + - SPRUCE_DOOR + - BIRCH_DOOR + - JUNGLE_DOOR + - ACACIA_DOOR + - DARK_OAK_DOOR + - END_BRICKS canFly: true canCruise: false diff --git a/modules/Movecraft/src/main/resources/types/legacy/airship.craft b/modules/Movecraft/src/main/resources/types/legacy/airship.craft index 7004d30d4..225ce4290 100644 --- a/modules/Movecraft/src/main/resources/types/legacy/airship.craft +++ b/modules/Movecraft/src/main/resources/types/legacy/airship.craft @@ -2,123 +2,121 @@ name: Airship maxSize: 5000 minSize: 1000 allowedBlocks: - WOOD: - STATIONARY_WATER: - WATER: - STATIONARY_LAVA: - LAVA: - LOG: - GLASS: - LAPIS_BLOCK: - DISPENSER: - NOTE_BLOCK: - BED_BLOCK: - PISTON_STICKY_BASE: - PISTON_BASE: - PISTON_EXTENSION: - WOOL: - GOLD_BLOCK: - IRON_BLOCK: - DOUBLE_STEP: - STEP: - BOOKSHELF: - TORCH: - FIRE: - WOOD_STAIRS: - CHEST: - REDSTONE_WIRE: - DIAMOND_BLOCK: - WORKBENCH: - FURNACE: - BURNING_FURNACE: - SIGN_POST: - WOOD_DOOR: - LADDER: - WALL_SIGN: - LEVER: - STONE_PLATE: - IRON_DOOR: - WOOD_PLATE: - REDSTONE_TORCH_ON: - REDSTONE_TORCH_OFF: - STONE_BUTTON: - CLAY: - FENCE: - NETHERRACK: - GLOWSTONE: - CAKE_BLOCK: - DIODE_BLOCK_OFF: - DIODE_BLOCK_ON: - STAINED_GLASS: - TRAP_DOOR: - SMOOTH_BRICK: - IRON_FENCE: - THIN_GLASS: - FENCE_GATE: - SMOOTH_STAIRS: - NETHER_BRICK: - NETHER_FENCE: - NETHER_BRICK_STAIRS: - ENCHANTMENT_TABLE: - BREWING_STAND: - CAULDRON: - ENDER_STONE: - DRAGON_EGG: - REDSTONE_LAMP_ON: - REDSTONE_LAMP_OFF: - WOOD_DOUBLE_STEP: - WOOD_STEP: - ENDER_CHEST: - TRIPWIRE_HOOK: - EMERALD_BLOCK: - SPRUCE_WOOD_STAIRS: - BIRCH_WOOD_STAIRS: - JUNGLE_WOOD_STAIRS: - BEACON: - COBBLE_WALL: - FLOWER_POT: - WOOD_BUTTON: - SKULL: - ANVIL: - TRAPPED_CHEST: - GOLD_PLATE: - IRON_PLATE: - REDSTONE_COMPARATOR_OFF: - REDSTONE_COMPARATOR_ON: - DAYLIGHT_SENSOR: - REDSTONE_BLOCK: - HOPPER: - QUARTZ_BLOCK: - QUARTZ_STAIRS: - ACTIVATOR_RAIL: - DROPPER: - STAINED_CLAY: - STAINED_GLASS_PANE: - SLIME_BLOCK: - CARPET: - HARD_CLAY: - COAL_BLOCK: - IRON_TRAPDOOR: - DAYLIGHT_SENSOR_INVERTED: - SPRUCE_FENCE_GATE: - BIRCH_FENCE_GATE: - JUNGLE_FENCE_GATE: - DARK_OAK_FENCE_GATE: - ACACIA_FENCE_GATE: - SPRUCE_FENCE: - BIRCH_FENCE: - JUNGLE_FENCE: - ACACIA_FENCE: - DARK_OAK_FENCE: - SPRUCE_DOOR: - BIRCH_DOOR: - JUNGLE_DOOR: - ACACIA_DOOR: - DARK_OAK_DOOR: - END_BRICKS: + - WOOD + - STATIONARY_WATER + - WATER + - STATIONARY_LAVA + - LAVA + - LOG + - GLASS + - LAPIS_BLOCK + - DISPENSER + - NOTE_BLOCK + - BED_BLOCK + - PISTON_STICKY_BASE + - PISTON_BASE + - PISTON_EXTENSION + - WOOL + - GOLD_BLOCK + - IRON_BLOCK + - DOUBLE_STEP + - STEP + - BOOKSHELF + - TORCH + - FIRE + - WOOD_STAIRS + - CHEST + - REDSTONE_WIRE + - DIAMOND_BLOCK + - WORKBENCH + - FURNACE + - BURNING_FURNACE + - SIGN_POST + - WOOD_DOOR + - LADDER + - WALL_SIGN + - LEVER + - STONE_PLATE + - IRON_DOOR + - WOOD_PLATE + - REDSTONE_TORCH_ON + - REDSTONE_TORCH_OFF + - STONE_BUTTON + - CLAY + - FENCE + - NETHERRACK + - GLOWSTONE + - CAKE_BLOCK + - DIODE_BLOCK_OFF + - DIODE_BLOCK_ON + - STAINED_GLASS + - TRAP_DOOR + - SMOOTH_BRICK + - IRON_FENCE + - THIN_GLASS + - FENCE_GATE + - SMOOTH_STAIRS + - NETHER_BRICK + - NETHER_FENCE + - NETHER_BRICK_STAIRS + - ENCHANTMENT_TABLE + - BREWING_STAND + - CAULDRON + - ENDER_STONE + - DRAGON_EGG + - REDSTONE_LAMP_ON + - REDSTONE_LAMP_OFF + - WOOD_DOUBLE_STEP + - WOOD_STEP + - ENDER_CHEST + - TRIPWIRE_HOOK + - EMERALD_BLOCK + - SPRUCE_WOOD_STAIRS + - BIRCH_WOOD_STAIRS + - JUNGLE_WOOD_STAIRS + - BEACON + - COBBLE_WALL + - FLOWER_POT + - WOOD_BUTTON + - SKULL + - ANVIL + - TRAPPED_CHEST + - GOLD_PLATE + - IRON_PLATE + - REDSTONE_COMPARATOR_OFF + - REDSTONE_COMPARATOR_ON + - DAYLIGHT_SENSOR + - REDSTONE_BLOCK + - HOPPER + - QUARTZ_BLOCK + - QUARTZ_STAIRS + - ACTIVATOR_RAIL + - DROPPER + - STAINED_CLAY + - STAINED_GLASS_PANE + - SLIME_BLOCK + - CARPET + - HARD_CLAY + - COAL_BLOCK + - IRON_TRAPDOOR + - DAYLIGHT_SENSOR_INVERTED + - SPRUCE_FENCE_GATE + - BIRCH_FENCE_GATE + - JUNGLE_FENCE_GATE + - DARK_OAK_FENCE_GATE + - ACACIA_FENCE_GATE + - SPRUCE_FENCE + - BIRCH_FENCE + - JUNGLE_FENCE + - ACACIA_FENCE + - DARK_OAK_FENCE + - SPRUCE_DOOR + - BIRCH_DOOR + - JUNGLE_DOOR + - ACACIA_DOOR + - DARK_OAK_DOOR + - END_BRICKS -forbiddenBlocks: - PISTON_EXTENSION: canCruise: true rotateAtMidpoint: true diff --git a/modules/Movecraft/src/main/resources/types/legacy/airskiff.craft b/modules/Movecraft/src/main/resources/types/legacy/airskiff.craft index b329b2155..688fafdcc 100644 --- a/modules/Movecraft/src/main/resources/types/legacy/airskiff.craft +++ b/modules/Movecraft/src/main/resources/types/legacy/airskiff.craft @@ -2,84 +2,111 @@ name: Airskiff maxSize: 80 minSize: 10 allowedBlocks: - WOOD: - STATIONARY_WATER: - WATER: - STATIONARY_LAVA: - LAVA: - LOG: - GLASS: - DISPENSER: - NOTE_BLOCK: - BED_BLOCK: - PISTON_STICKY_BASE: - PISTON_BASE: - WOOL: - GOLD_BLOCK: - DOUBLE_STEP: - STEP: - BOOKSHELF: - TORCH: - MOB_SPAWNER: - WOOD_STAIRS: - CHEST: - REDSTONE_WIRE: - DIAMOND_BLOCK: - WORKBENCH: - FURNACE: - BURNING_FURNACE: - SIGN_POST: - WOOD_DOOR: - LADDER: - WALL_SIGN: - LEVER: - STONE_PLATE: - IRON_DOOR: - WOOD_PLATE: - REDSTONE_TORCH_ON: - REDSTONE_TORCH_OFF: - STONE_BUTTON: - FENCE: - CAKE_BLOCK: - DIODE_BLOCK_OFF: - DIODE_BLOCK_ON: - STAINED_GLASS: - TRAP_DOOR: - IRON_FENCE: - THIN_GLASS: - FENCE_GATE: - NETHER_FENCE: - BREWING_STAND: - CAULDRON: - REDSTONE_LAMP_ON: - REDSTONE_LAMP_OFF: - WOOD_DOUBLE_STEP: - WOOD_STEP: - ENDER_CHEST: - TRIPWIRE_HOOK: - EMERALD_BLOCK: - SPRUCE_WOOD_STAIRS: - BIRCH_WOOD_STAIRS: - JUNGLE_WOOD_STAIRS: - BEACON: - WOOD_BUTTON: - SKULL: - ANVIL: - TRAPPED_CHEST: - GOLD_PLATE: - IRON_PLATE: - REDSTONE_COMPARATOR_OFF: - REDSTONE_COMPARATOR_ON: - DAYLIGHT_SENSOR: - REDSTONE_BLOCK: - HOPPER: - ACTIVATOR_RAIL: - SLIME_BLOCK: - CARPET: - COAL_BLOCK: + - WOOD + - STATIONARY_WATER + - WATER + - STATIONARY_LAVA + - LAVA + - LOG + - GLASS + - LAPIS_BLOCK + - DISPENSER + - NOTE_BLOCK + - BED_BLOCK + - PISTON_STICKY_BASE + - PISTON_BASE + - WOOL + - GOLD_BLOCK + - DOUBLE_STEP + - STEP + - BOOKSHELF + - TORCH + - FIRE + - WOOD_STAIRS + - CHEST + - REDSTONE_WIRE + - DIAMOND_BLOCK + - WORKBENCH + - FURNACE + - BURNING_FURNACE + - SIGN_POST + - WOOD_DOOR + - LADDER + - WALL_SIGN + - LEVER + - STONE_PLATE + - IRON_DOOR + - WOOD_PLATE + - REDSTONE_TORCH_ON + - REDSTONE_TORCH_OFF + - STONE_BUTTON + - FENCE + - NETHERRACK + - GLOWSTONE + - CAKE_BLOCK + - DIODE_BLOCK_OFF + - DIODE_BLOCK_ON + - STAINED_GLASS + - TRAP_DOOR + - IRON_FENCE + - THIN_GLASS + - FENCE_GATE + - SMOOTH_STAIRS + - NETHER_FENCE + - ENCHANTMENT_TABLE + - BREWING_STAND + - CAULDRON + - DRAGON_EGG + - REDSTONE_LAMP_ON + - REDSTONE_LAMP_OFF + - WOOD_DOUBLE_STEP + - WOOD_STEP + - ENDER_CHEST + - TRIPWIRE_HOOK + - EMERALD_BLOCK + - SPRUCE_WOOD_STAIRS + - BIRCH_WOOD_STAIRS + - JUNGLE_WOOD_STAIRS + - BEACON + - COBBLE_WALL + - FLOWER_POT + - WOOD_BUTTON + - SKULL + - ANVIL + - TRAPPED_CHEST + - GOLD_PLATE + - IRON_PLATE + - REDSTONE_COMPARATOR_OFF + - REDSTONE_COMPARATOR_ON + - DAYLIGHT_SENSOR + - REDSTONE_BLOCK + - HOPPER + - QUARTZ_BLOCK + - QUARTZ_STAIRS + - ACTIVATOR_RAIL + - DROPPER + - STAINED_GLASS_PANE + - SLIME_BLOCK + - CARPET + - COAL_BLOCK + - IRON_TRAPDOOR + - DAYLIGHT_SENSOR_INVERTED + - SPRUCE_FENCE_GATE + - BIRCH_FENCE_GATE + - JUNGLE_FENCE_GATE + - DARK_OAK_FENCE_GATE + - ACACIA_FENCE_GATE + - SPRUCE_FENCE + - BIRCH_FENCE + - JUNGLE_FENCE + - ACACIA_FENCE + - DARK_OAK_FENCE + - SPRUCE_DOOR + - BIRCH_DOOR + - JUNGLE_DOOR + - ACACIA_DOOR + - DARK_OAK_DOOR -forbiddenBlocks: - PISTON_EXTENSION: canFly: true rotateAtMidpoint: true diff --git a/modules/Movecraft/src/main/resources/types/legacy/elevator.craft b/modules/Movecraft/src/main/resources/types/legacy/elevator.craft index 0d3426acb..b14a60f42 100644 --- a/modules/Movecraft/src/main/resources/types/legacy/elevator.craft +++ b/modules/Movecraft/src/main/resources/types/legacy/elevator.craft @@ -1,85 +1,111 @@ name: elevator maxSize: 1000 minSize: 10 -allowedBlocks: - WOOD: - STATIONARY_WATER: - WATER: - STATIONARY_LAVA: - LAVA: - LOG: - GLASS: - DISPENSER: - NOTE_BLOCK: - BED_BLOCK: - PISTON_STICKY_BASE: - PISTON_BASE: - WOOL: - GOLD_BLOCK: - DOUBLE_STEP: - STEP: - BOOKSHELF: - TORCH: - MOB_SPAWNER: - WOOD_STAIRS: - CHEST: - REDSTONE_WIRE: - DIAMOND_BLOCK: - WORKBENCH: - FURNACE: - BURNING_FURNACE: - SIGN_POST: - WOOD_DOOR: - LADDER: - WALL_SIGN: - LEVER: - STONE_PLATE: - IRON_DOOR: - WOOD_PLATE: - REDSTONE_TORCH_ON: - REDSTONE_TORCH_OFF: - STONE_BUTTON: - FENCE: - CAKE_BLOCK: - DIODE_BLOCK_OFF: - DIODE_BLOCK_ON: - STAINED_GLASS: - TRAP_DOOR: - IRON_FENCE: - THIN_GLASS: - FENCE_GATE: - NETHER_FENCE: - BREWING_STAND: - CAULDRON: - REDSTONE_LAMP_ON: - REDSTONE_LAMP_OFF: - WOOD_DOUBLE_STEP: - WOOD_STEP: - ENDER_CHEST: - TRIPWIRE_HOOK: - EMERALD_BLOCK: - SPRUCE_WOOD_STAIRS: - BIRCH_WOOD_STAIRS: - JUNGLE_WOOD_STAIRS: - BEACON: - WOOD_BUTTON: - SKULL: - ANVIL: - TRAPPED_CHEST: - GOLD_PLATE: - IRON_PLATE: - REDSTONE_COMPARATOR_OFF: - REDSTONE_COMPARATOR_ON: - DAYLIGHT_SENSOR: - REDSTONE_BLOCK: - HOPPER: - ACTIVATOR_RAIL: - SLIME_BLOCK: - CARPET: - COAL_BLOCK: - -forbiddenBlocks: - BEDROCK: +allowedBlocks: + - WOOD + - STATIONARY_WATER + - WATER + - STATIONARY_LAVA + - LAVA + - LOG + - GLASS + - LAPIS_BLOCK + - DISPENSER + - NOTE_BLOCK + - BED_BLOCK + - PISTON_STICKY_BASE + - PISTON_BASE + - WOOL + - GOLD_BLOCK + - DOUBLE_STEP + - STEP + - BOOKSHELF + - TORCH + - FIRE + - WOOD_STAIRS + - CHEST + - REDSTONE_WIRE + - DIAMOND_BLOCK + - WORKBENCH + - FURNACE + - BURNING_FURNACE + - SIGN_POST + - WOOD_DOOR + - LADDER + - WALL_SIGN + - LEVER + - STONE_PLATE + - IRON_DOOR + - WOOD_PLATE + - REDSTONE_TORCH_ON + - REDSTONE_TORCH_OFF + - STONE_BUTTON + - FENCE + - NETHERRACK + - GLOWSTONE + - CAKE_BLOCK + - DIODE_BLOCK_OFF + - DIODE_BLOCK_ON + - STAINED_GLASS + - TRAP_DOOR + - IRON_FENCE + - THIN_GLASS + - FENCE_GATE + - SMOOTH_STAIRS + - NETHER_FENCE + - ENCHANTMENT_TABLE + - BREWING_STAND + - CAULDRON + - DRAGON_EGG + - REDSTONE_LAMP_ON + - REDSTONE_LAMP_OFF + - WOOD_DOUBLE_STEP + - WOOD_STEP + - ENDER_CHEST + - TRIPWIRE_HOOK + - EMERALD_BLOCK + - SPRUCE_WOOD_STAIRS + - BIRCH_WOOD_STAIRS + - JUNGLE_WOOD_STAIRS + - BEACON + - COBBLE_WALL + - FLOWER_POT + - WOOD_BUTTON + - SKULL + - ANVIL + - TRAPPED_CHEST + - GOLD_PLATE + - IRON_PLATE + - REDSTONE_COMPARATOR_OFF + - REDSTONE_COMPARATOR_ON + - DAYLIGHT_SENSOR + - REDSTONE_BLOCK + - HOPPER + - QUARTZ_BLOCK + - QUARTZ_STAIRS + - ACTIVATOR_RAIL + - DROPPER + - STAINED_GLASS_PANE + - SLIME_BLOCK + - CARPET + - COAL_BLOCK + - IRON_TRAPDOOR + - DAYLIGHT_SENSOR_INVERTED + - SPRUCE_FENCE_GATE + - BIRCH_FENCE_GATE + - JUNGLE_FENCE_GATE + - DARK_OAK_FENCE_GATE + - ACACIA_FENCE_GATE + - SPRUCE_FENCE + - BIRCH_FENCE + - JUNGLE_FENCE + - ACACIA_FENCE + - DARK_OAK_FENCE + - SPRUCE_DOOR + - BIRCH_DOOR + - JUNGLE_DOOR + - ACACIA_DOOR + - DARK_OAK_DOOR canFly: true canCruise: false diff --git a/modules/api/src/main/java/net/countercraft/movecraft/config/Settings.java b/modules/api/src/main/java/net/countercraft/movecraft/config/Settings.java index f8152391e..605118376 100644 --- a/modules/api/src/main/java/net/countercraft/movecraft/config/Settings.java +++ b/modules/api/src/main/java/net/countercraft/movecraft/config/Settings.java @@ -68,6 +68,7 @@ public class Settings { public static Map TownProtectionHeightLimits; public static Map DurabilityOverride; public static boolean IsPaper = false; + public static boolean IsPre1_9 = false; public static boolean IsLegacy = true; //false if version is 1.13 or higher public static boolean is1_14 = false; public static boolean UseFAWE = false; diff --git a/modules/api/src/main/java/net/countercraft/movecraft/utils/LegacyUtils.java b/modules/api/src/main/java/net/countercraft/movecraft/utils/LegacyUtils.java index 22b6de7f5..019dc1d5f 100644 --- a/modules/api/src/main/java/net/countercraft/movecraft/utils/LegacyUtils.java +++ b/modules/api/src/main/java/net/countercraft/movecraft/utils/LegacyUtils.java @@ -69,7 +69,8 @@ public class LegacyUtils { public static Material YELLOW_FLOWER = Settings.IsLegacy ? Material.YELLOW_FLOWER : null; //Sounds removed in 1.13 - public static Sound ENITIY_IRONGOLEM_DEATH = Settings.IsLegacy ? Sound.ENTITY_IRONGOLEM_DEATH : null; + public static Sound ENITIY_IRONGOLEM_DEATH = Settings.IsLegacy && !Settings.IsPre1_9 ? Sound.ENTITY_IRONGOLEM_DEATH : null; + public static Sound IRONGOLEM_DEATH = Sound.valueOf("IRONGOLEM_DEATH"); //Methods removed in 1.13 public static Material getMaterial(int id){ try { diff --git a/modules/v1_15_R1/pom.xml b/modules/v1_15_R1/pom.xml index ac28953f9..8e2b425f1 100644 --- a/modules/v1_15_R1/pom.xml +++ b/modules/v1_15_R1/pom.xml @@ -14,11 +14,11 @@ Movecraft-v1_15_R1 v1_15_R1 - + \ No newline at end of file diff --git a/modules/v1_8_R3/src/main/java/net/countercraft/movecraft/compat/v1_8_R3/NextTickProvider.java b/modules/v1_8_R3/src/main/java/net/countercraft/movecraft/compat/v1_8_R3/NextTickProvider.java index e42741010..c5f26aaa9 100644 --- a/modules/v1_8_R3/src/main/java/net/countercraft/movecraft/compat/v1_8_R3/NextTickProvider.java +++ b/modules/v1_8_R3/src/main/java/net/countercraft/movecraft/compat/v1_8_R3/NextTickProvider.java @@ -25,21 +25,21 @@ private boolean isRegistered(@NotNull WorldServer world){ @SuppressWarnings("unchecked") private void registerWorld(@NotNull WorldServer world){ - List U = new ArrayList<>(); - HashTreeSet nextTickList = new HashTreeSet<>(); + List V = new ArrayList<>(); + HashTreeSet M = new HashTreeSet<>(); try { - Field UField = WorldServer.class.getDeclaredField("U"); - UField.setAccessible(true); - U = (List) UField.get(world); - Field nextTickListField = WorldServer.class.getDeclaredField("nextTickList"); - nextTickListField.setAccessible(true); - nextTickList = (HashTreeSet) nextTickListField.get(world); + Field VField = WorldServer.class.getDeclaredField("V"); + VField.setAccessible(true); + V = (List) VField.get(world); + Field MField = WorldServer.class.getDeclaredField("M"); + MField.setAccessible(true); + M = (HashTreeSet) MField.get(world); } catch (IllegalAccessException | IllegalArgumentException | NoSuchFieldException | SecurityException e1) { e1.printStackTrace(); } - tickMap.put(world, new ImmutablePair<>(new WeakReference<>(nextTickList), new WeakReference<>(U))); + tickMap.put(world, new ImmutablePair<>(new WeakReference<>(M), new WeakReference<>(V))); } @Nullable diff --git a/modules/v1_9_R2/pom.xml b/modules/v1_9_R2/pom.xml index 861d4b2bb..c3e517e9f 100644 --- a/modules/v1_9_R2/pom.xml +++ b/modules/v1_9_R2/pom.xml @@ -6,6 +6,7 @@ movecraft-parent net.countercraft parent + ../../ 4.0.0 diff --git a/pom.xml b/pom.xml index 4ba1ff0c0..d54d1fda0 100644 --- a/pom.xml +++ b/pom.xml @@ -20,6 +20,8 @@ modules/api + modules/v1_8_R3 + modules/v1_9_R2 modules/v1_10_R1 modules/v1_11_R1 modules/v1_12_R1 @@ -29,9 +31,6 @@ modules/worldedit/WE6Utils modules/worldedit/WE7Utils modules/Movecraft - modules/v1_9_R2 - modules/v1_8_R3 - From 70e8ec935a87415a0288f990b5d645703215f286 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Wed, 11 Dec 2019 12:27:19 +0100 Subject: [PATCH 094/304] Fixed invalid material IDs in legacy craft files and added 1.15 support --- modules/Movecraft/pom.xml | 6 + .../resources/types/legacy/BigAirship.craft | 4 +- .../types/legacy/BigSubAirship.craft | 4 +- .../main/resources/types/legacy/Ship.craft | 4 +- .../resources/types/legacy/SubAirship.craft | 4 +- .../resources/types/legacy/Submarine.craft | 4 +- .../main/resources/types/legacy/Turret.craft | 220 +++++----- .../main/resources/types/legacy/airship.craft | 4 +- .../resources/types/legacy/airskiff.craft | 4 +- .../resources/types/legacy/elevator.craft | 4 +- .../movecraft/utils/BlockContainer.java | 2 +- modules/v1_15_R1/pom.xml | 45 +- .../compat/v1_15_R1/IWorldHandler.java | 383 ++++++++++++++++++ .../compat/v1_15_R1/NextTickProvider.java | 57 +++ pom.xml | 2 +- 15 files changed, 616 insertions(+), 131 deletions(-) create mode 100644 modules/v1_15_R1/src/main/java/net/countercraft/movecraft/compat/v1_15_R1/IWorldHandler.java create mode 100644 modules/v1_15_R1/src/main/java/net/countercraft/movecraft/compat/v1_15_R1/NextTickProvider.java diff --git a/modules/Movecraft/pom.xml b/modules/Movecraft/pom.xml index 267a77073..624e79ebe 100644 --- a/modules/Movecraft/pom.xml +++ b/modules/Movecraft/pom.xml @@ -35,6 +35,12 @@ + + net.countercraft + movecraft-v1_15_R1 + v1_15_R1 + jar + net.countercraft diff --git a/modules/Movecraft/src/main/resources/types/legacy/BigAirship.craft b/modules/Movecraft/src/main/resources/types/legacy/BigAirship.craft index d4ffde00e..3e2787814 100644 --- a/modules/Movecraft/src/main/resources/types/legacy/BigAirship.craft +++ b/modules/Movecraft/src/main/resources/types/legacy/BigAirship.craft @@ -85,7 +85,7 @@ allowedBlocks: - IRON_PLATE - REDSTONE_COMPARATOR_OFF - REDSTONE_COMPARATOR_ON - - DAYLIGHT_SENSOR + - DAYLIGHT_DETECTOR - REDSTONE_BLOCK - HOPPER - QUARTZ_BLOCK @@ -99,7 +99,7 @@ allowedBlocks: - HARD_CLAY - COAL_BLOCK - IRON_TRAPDOOR - - DAYLIGHT_SENSOR_INVERTED + - DAYLIGHT_DETECTOR_INVERTED - SPRUCE_FENCE_GATE - BIRCH_FENCE_GATE - JUNGLE_FENCE_GATE diff --git a/modules/Movecraft/src/main/resources/types/legacy/BigSubAirship.craft b/modules/Movecraft/src/main/resources/types/legacy/BigSubAirship.craft index 9920f4513..1de0de357 100644 --- a/modules/Movecraft/src/main/resources/types/legacy/BigSubAirship.craft +++ b/modules/Movecraft/src/main/resources/types/legacy/BigSubAirship.craft @@ -85,7 +85,7 @@ allowedBlocks: - IRON_PLATE - REDSTONE_COMPARATOR_OFF - REDSTONE_COMPARATOR_ON - - DAYLIGHT_SENSOR + - DAYLIGHT_DETECTOR - REDSTONE_BLOCK - HOPPER - QUARTZ_BLOCK @@ -99,7 +99,7 @@ allowedBlocks: - HARD_CLAY - COAL_BLOCK - IRON_TRAPDOOR - - DAYLIGHT_SENSOR_INVERTED + - DAYLIGHT_DETECTOR_INVERTED - SPRUCE_FENCE_GATE - BIRCH_FENCE_GATE - JUNGLE_FENCE_GATE diff --git a/modules/Movecraft/src/main/resources/types/legacy/Ship.craft b/modules/Movecraft/src/main/resources/types/legacy/Ship.craft index 9ce74bd21..c22943696 100644 --- a/modules/Movecraft/src/main/resources/types/legacy/Ship.craft +++ b/modules/Movecraft/src/main/resources/types/legacy/Ship.craft @@ -85,7 +85,7 @@ allowedBlocks: - IRON_PLATE - REDSTONE_COMPARATOR_OFF - REDSTONE_COMPARATOR_ON - - DAYLIGHT_SENSOR + - DAYLIGHT_DETECTOR - REDSTONE_BLOCK - HOPPER - QUARTZ_BLOCK @@ -99,7 +99,7 @@ allowedBlocks: - HARD_CLAY - COAL_BLOCK - IRON_TRAPDOOR - - DAYLIGHT_SENSOR_INVERTED + - DAYLIGHT_DETECTOR_INVERTED - SPRUCE_FENCE_GATE - BIRCH_FENCE_GATE - JUNGLE_FENCE_GATE diff --git a/modules/Movecraft/src/main/resources/types/legacy/SubAirship.craft b/modules/Movecraft/src/main/resources/types/legacy/SubAirship.craft index 9115aece9..415f5d73d 100644 --- a/modules/Movecraft/src/main/resources/types/legacy/SubAirship.craft +++ b/modules/Movecraft/src/main/resources/types/legacy/SubAirship.craft @@ -85,7 +85,7 @@ allowedBlocks: - IRON_PLATE - REDSTONE_COMPARATOR_OFF - REDSTONE_COMPARATOR_ON - - DAYLIGHT_SENSOR + - DAYLIGHT_DETECTOR - REDSTONE_BLOCK - HOPPER - QUARTZ_BLOCK @@ -99,7 +99,7 @@ allowedBlocks: - HARD_CLAY - COAL_BLOCK - IRON_TRAPDOOR - - DAYLIGHT_SENSOR_INVERTED + - DAYLIGHT_DETECTOR_INVERTED - SPRUCE_FENCE_GATE - BIRCH_FENCE_GATE - JUNGLE_FENCE_GATE diff --git a/modules/Movecraft/src/main/resources/types/legacy/Submarine.craft b/modules/Movecraft/src/main/resources/types/legacy/Submarine.craft index d64e80221..c814d051e 100644 --- a/modules/Movecraft/src/main/resources/types/legacy/Submarine.craft +++ b/modules/Movecraft/src/main/resources/types/legacy/Submarine.craft @@ -85,7 +85,7 @@ allowedBlocks: - IRON_PLATE - REDSTONE_COMPARATOR_OFF - REDSTONE_COMPARATOR_ON - - DAYLIGHT_SENSOR + - DAYLIGHT_DETECTOR - REDSTONE_BLOCK - HOPPER - QUARTZ_BLOCK @@ -99,7 +99,7 @@ allowedBlocks: - HARD_CLAY - COAL_BLOCK - IRON_TRAPDOOR - - DAYLIGHT_SENSOR_INVERTED + - DAYLIGHT_DETECTOR_INVERTED - SPRUCE_FENCE_GATE - BIRCH_FENCE_GATE - JUNGLE_FENCE_GATE diff --git a/modules/Movecraft/src/main/resources/types/legacy/Turret.craft b/modules/Movecraft/src/main/resources/types/legacy/Turret.craft index 1f72cf4c8..12a9ef3c2 100644 --- a/modules/Movecraft/src/main/resources/types/legacy/Turret.craft +++ b/modules/Movecraft/src/main/resources/types/legacy/Turret.craft @@ -9,116 +9,116 @@ allowedBlocks: - LAVA - LOG - GLASS - - "STAINED_CLAY:7" - - "STAINED_CLAY:8" - - "STAINED_CLAY:15" - - LAPIS_BLOCK - - DISPENSER - - NOTE_BLOCK - - BED_BLOCK - - PISTON_STICKY_BASE - - PISTON_BASE - - PISTON_EXTENSION - - "WOOL:8" - - GOLD_BLOCK - - IRON_BLOCK - - DOUBLE_STEP - - STEP - - BOOKSHELF - - TORCH - - FIRE - - WOOD_STAIRS - - CHEST - - REDSTONE_WIRE - - DIAMOND_BLOCK - - WORKBENCH - - FURNACE - - BURNING_FURNACE - - SIGN_POST - - WOOD_DOOR - - LADDER - - WALL_SIGN - - LEVER - - STONE_PLATE - - IRON_DOOR - - WOOD_PLATE - - REDSTONE_TORCH_ON - - REDSTONE_TORCH_OFF - - STONE_BUTTON - - CLAY - - FENCE - - NETHERRACK - - GLOWSTONE - - CAKE_BLOCK - - DIODE_BLOCK_OFF - - DIODE_BLOCK_ON - - STAINED_GLASS - - TRAP_DOOR - - SMOOTH_BRICK - - IRON_FENCE - - THIN_GLASS - - FENCE_GATE - - SMOOTH_STAIRS - - NETHER_BRICK - - NETHER_FENCE - - NETHER_BRICK_STAIRS - - ENCHANTMENT_TABLE - - BREWING_STAND - - CAULDRON - - ENDER_STONE - - DRAGON_EGG - - REDSTONE_LAMP_ON - - REDSTONE_LAMP_OFF - - WOOD_DOUBLE_STEP - - WOOD_STEP - - ENDER_CHEST - - TRIPWIRE_HOOK - - EMERALD_BLOCK - - SPRUCE_WOOD_STAIRS - - BIRCH_WOOD_STAIRS - - JUNGLE_WOOD_STAIRS - - BEACON - - COBBLE_WALL - - FLOWER_POT - - WOOD_BUTTON - - SKULL - - ANVIL - - TRAPPED_CHEST - - GOLD_PLATE - - IRON_PLATE - - REDSTONE_COMPARATOR_OFF - - REDSTONE_COMPARATOR_ON - - DAYLIGHT_SENSOR - - REDSTONE_BLOCK - - HOPPER - - QUARTZ_BLOCK - - QUARTZ_STAIRS - - ACTIVATOR_RAIL - - DROPPER - - STAINED_CLAY - - STAINED_GLASS_PANE - - SLIME_BLOCK - - CARPET - - HARD_CLAY - - COAL_BLOCK - - IRON_TRAPDOOR - - DAYLIGHT_SENSOR_INVERTED - - SPRUCE_FENCE_GATE - - BIRCH_FENCE_GATE - - JUNGLE_FENCE_GATE - - DARK_OAK_FENCE_GATE - - ACACIA_FENCE_GATE - - SPRUCE_FENCE - - BIRCH_FENCE - - JUNGLE_FENCE - - ACACIA_FENCE - - DARK_OAK_FENCE - - SPRUCE_DOOR - - BIRCH_DOOR - - JUNGLE_DOOR - - ACACIA_DOOR - - DARK_OAK_DOOR - - END_BRICKS + - "STAINED_CLAY:7" + - "STAINED_CLAY:8" + - "STAINED_CLAY:15" + - LAPIS_BLOCK + - DISPENSER + - NOTE_BLOCK + - BED_BLOCK + - PISTON_STICKY_BASE + - PISTON_BASE + - PISTON_EXTENSION + - "WOOL:8" + - GOLD_BLOCK + - IRON_BLOCK + - DOUBLE_STEP + - STEP + - BOOKSHELF + - TORCH + - FIRE + - WOOD_STAIRS + - CHEST + - REDSTONE_WIRE + - DIAMOND_BLOCK + - WORKBENCH + - FURNACE + - BURNING_FURNACE + - SIGN_POST + - WOOD_DOOR + - LADDER + - WALL_SIGN + - LEVER + - STONE_PLATE + - IRON_DOOR + - WOOD_PLATE + - REDSTONE_TORCH_ON + - REDSTONE_TORCH_OFF + - STONE_BUTTON + - CLAY + - FENCE + - NETHERRACK + - GLOWSTONE + - CAKE_BLOCK + - DIODE_BLOCK_OFF + - DIODE_BLOCK_ON + - STAINED_GLASS + - TRAP_DOOR + - SMOOTH_BRICK + - IRON_FENCE + - THIN_GLASS + - FENCE_GATE + - SMOOTH_STAIRS + - NETHER_BRICK + - NETHER_FENCE + - NETHER_BRICK_STAIRS + - ENCHANTMENT_TABLE + - BREWING_STAND + - CAULDRON + - ENDER_STONE + - DRAGON_EGG + - REDSTONE_LAMP_ON + - REDSTONE_LAMP_OFF + - WOOD_DOUBLE_STEP + - WOOD_STEP + - ENDER_CHEST + - TRIPWIRE_HOOK + - EMERALD_BLOCK + - SPRUCE_WOOD_STAIRS + - BIRCH_WOOD_STAIRS + - JUNGLE_WOOD_STAIRS + - BEACON + - COBBLE_WALL + - FLOWER_POT + - WOOD_BUTTON + - SKULL + - ANVIL + - TRAPPED_CHEST + - GOLD_PLATE + - IRON_PLATE + - REDSTONE_COMPARATOR_OFF + - REDSTONE_COMPARATOR_ON + - DAYLIGHT_DETECTOR + - REDSTONE_BLOCK + - HOPPER + - QUARTZ_BLOCK + - QUARTZ_STAIRS + - ACTIVATOR_RAIL + - DROPPER + - STAINED_CLAY + - STAINED_GLASS_PANE + - SLIME_BLOCK + - CARPET + - HARD_CLAY + - COAL_BLOCK + - IRON_TRAPDOOR + - DAYLIGHT_DETECTOR_INVERTED + - SPRUCE_FENCE_GATE + - BIRCH_FENCE_GATE + - JUNGLE_FENCE_GATE + - DARK_OAK_FENCE_GATE + - ACACIA_FENCE_GATE + - SPRUCE_FENCE + - BIRCH_FENCE + - JUNGLE_FENCE + - ACACIA_FENCE + - DARK_OAK_FENCE + - SPRUCE_DOOR + - BIRCH_DOOR + - JUNGLE_DOOR + - ACACIA_DOOR + - DARK_OAK_DOOR + - END_BRICKS canFly: true canCruise: false diff --git a/modules/Movecraft/src/main/resources/types/legacy/airship.craft b/modules/Movecraft/src/main/resources/types/legacy/airship.craft index 225ce4290..1f9ff2ecc 100644 --- a/modules/Movecraft/src/main/resources/types/legacy/airship.craft +++ b/modules/Movecraft/src/main/resources/types/legacy/airship.craft @@ -85,7 +85,7 @@ allowedBlocks: - IRON_PLATE - REDSTONE_COMPARATOR_OFF - REDSTONE_COMPARATOR_ON - - DAYLIGHT_SENSOR + - DAYLIGHT_DETECTOR - REDSTONE_BLOCK - HOPPER - QUARTZ_BLOCK @@ -99,7 +99,7 @@ allowedBlocks: - HARD_CLAY - COAL_BLOCK - IRON_TRAPDOOR - - DAYLIGHT_SENSOR_INVERTED + - DAYLIGHT_DETECTOR_INVERTED - SPRUCE_FENCE_GATE - BIRCH_FENCE_GATE - JUNGLE_FENCE_GATE diff --git a/modules/Movecraft/src/main/resources/types/legacy/airskiff.craft b/modules/Movecraft/src/main/resources/types/legacy/airskiff.craft index 688fafdcc..079bd0b84 100644 --- a/modules/Movecraft/src/main/resources/types/legacy/airskiff.craft +++ b/modules/Movecraft/src/main/resources/types/legacy/airskiff.craft @@ -78,7 +78,7 @@ allowedBlocks: - IRON_PLATE - REDSTONE_COMPARATOR_OFF - REDSTONE_COMPARATOR_ON - - DAYLIGHT_SENSOR + - DAYLIGHT_DETECTOR - REDSTONE_BLOCK - HOPPER - QUARTZ_BLOCK @@ -90,7 +90,7 @@ allowedBlocks: - CARPET - COAL_BLOCK - IRON_TRAPDOOR - - DAYLIGHT_SENSOR_INVERTED + - DAYLIGHT_DETECTOR_INVERTED - SPRUCE_FENCE_GATE - BIRCH_FENCE_GATE - JUNGLE_FENCE_GATE diff --git a/modules/Movecraft/src/main/resources/types/legacy/elevator.craft b/modules/Movecraft/src/main/resources/types/legacy/elevator.craft index b14a60f42..41d5afe4c 100644 --- a/modules/Movecraft/src/main/resources/types/legacy/elevator.craft +++ b/modules/Movecraft/src/main/resources/types/legacy/elevator.craft @@ -78,7 +78,7 @@ allowedBlocks: - IRON_PLATE - REDSTONE_COMPARATOR_OFF - REDSTONE_COMPARATOR_ON - - DAYLIGHT_SENSOR + - DAYLIGHT_DETECTOR - REDSTONE_BLOCK - HOPPER - QUARTZ_BLOCK @@ -90,7 +90,7 @@ allowedBlocks: - CARPET - COAL_BLOCK - IRON_TRAPDOOR - - DAYLIGHT_SENSOR_INVERTED + - DAYLIGHT_DETECTOR_INVERTED - SPRUCE_FENCE_GATE - BIRCH_FENCE_GATE - JUNGLE_FENCE_GATE diff --git a/modules/api/src/main/java/net/countercraft/movecraft/utils/BlockContainer.java b/modules/api/src/main/java/net/countercraft/movecraft/utils/BlockContainer.java index 335a87150..740387f02 100644 --- a/modules/api/src/main/java/net/countercraft/movecraft/utils/BlockContainer.java +++ b/modules/api/src/main/java/net/countercraft/movecraft/utils/BlockContainer.java @@ -37,7 +37,7 @@ public BlockContainer(Object obj){ } catch (Exception e){ throw new IllegalArgumentException("Numerical IDs are not supported by this version: " + Bukkit.getVersion(), e); } - Byte data = Byte.parseByte(parts[1]); + byte data = (byte) Integer.parseInt(parts[1]); blocks.add(new MovecraftBlock(type, data)); continue; } else if (str.startsWith("ALL_")){ diff --git a/modules/v1_15_R1/pom.xml b/modules/v1_15_R1/pom.xml index 8e2b425f1..9dac4f9ce 100644 --- a/modules/v1_15_R1/pom.xml +++ b/modules/v1_15_R1/pom.xml @@ -13,12 +13,51 @@ movecraft-v1_15_R1 Movecraft-v1_15_R1 v1_15_R1 + jar - - + + + + src/main/java + + + org.apache.maven.plugins + maven-compiler-plugin + 3.7.0 + + + net/countercraft/movecraft/compat/v1_15_R1/** + + 1.8 + 1.8 + + + + org.apache.maven.plugins + maven-jar-plugin + 2.4 + + + net/countercraft/movecraft/compat/v1_15_R1/** + + + + + \ No newline at end of file diff --git a/modules/v1_15_R1/src/main/java/net/countercraft/movecraft/compat/v1_15_R1/IWorldHandler.java b/modules/v1_15_R1/src/main/java/net/countercraft/movecraft/compat/v1_15_R1/IWorldHandler.java new file mode 100644 index 000000000..59cbbdf74 --- /dev/null +++ b/modules/v1_15_R1/src/main/java/net/countercraft/movecraft/compat/v1_15_R1/IWorldHandler.java @@ -0,0 +1,383 @@ +package net.countercraft.movecraft.compat.v1_15_R1; + +import net.countercraft.movecraft.MovecraftLocation; +import net.countercraft.movecraft.Rotation; +import net.countercraft.movecraft.WorldHandler; +import net.countercraft.movecraft.config.Settings; +import net.countercraft.movecraft.craft.Craft; +import net.countercraft.movecraft.utils.CollectionUtils; +import net.countercraft.movecraft.utils.MathUtils; +import net.minecraft.server.v1_15_R1.*; +import org.bukkit.Bukkit; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.craftbukkit.v1_15_R1.CraftWorld; +import org.bukkit.craftbukkit.v1_15_R1.block.CraftBlockState; +import org.bukkit.craftbukkit.v1_15_R1.entity.CraftPlayer; +import org.bukkit.craftbukkit.v1_15_R1.util.CraftMagicNumbers; +import org.bukkit.entity.Player; +import org.bukkit.event.player.PlayerMoveEvent; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.*; + +public class IWorldHandler extends WorldHandler { + private static final EnumBlockRotation ROTATION[]; + static { + ROTATION = new EnumBlockRotation[3]; + ROTATION[Rotation.NONE.ordinal()] = EnumBlockRotation.NONE; + ROTATION[Rotation.CLOCKWISE.ordinal()] = EnumBlockRotation.CLOCKWISE_90; + ROTATION[Rotation.ANTICLOCKWISE.ordinal()] = EnumBlockRotation.COUNTERCLOCKWISE_90; + } + private final NextTickProvider tickProvider = new NextTickProvider(); + private final HashMap> bMap = new HashMap<>(); + private MethodHandle internalTeleportMH; + + public IWorldHandler() { + MethodHandles.Lookup lookup = MethodHandles.lookup(); + Method teleport = null; + try { + teleport = PlayerConnection.class.getDeclaredMethod("internalTeleport", double.class, double.class, double.class, float.class, float.class, Set.class); + teleport.setAccessible(true); + internalTeleportMH = lookup.unreflect(teleport); + + } catch (NoSuchMethodException | IllegalAccessException e) { + e.printStackTrace(); + } + } + + @Override + public void rotateCraft(@NotNull Craft craft, @NotNull MovecraftLocation originPoint, @NotNull Rotation rotation) { + //******************************************* + //* Step one: Convert to Positions * + //******************************************* + HashMap rotatedPositions = new HashMap<>(); + Rotation counterRotation = rotation == Rotation.CLOCKWISE ? Rotation.ANTICLOCKWISE : Rotation.CLOCKWISE; + for(MovecraftLocation newLocation : craft.getHitBox()){ + rotatedPositions.put(locationToPosition(MathUtils.rotateVec(counterRotation, newLocation.subtract(originPoint)).add(originPoint)),locationToPosition(newLocation)); + } + //******************************************* + //* Step two: Get the tiles * + //******************************************* + World nativeWorld = ((CraftWorld) craft.getW()).getHandle(); + List tiles = new ArrayList<>(); + //get the tiles + for(BlockPosition position : rotatedPositions.keySet()){ + //TileEntity tile = nativeWorld.removeTileEntity(position); + TileEntity tile = removeTileEntity(nativeWorld,position); + if(tile == null) + continue; + tile.a(ROTATION[rotation.ordinal()]); + //get the nextTick to move with the tile + tiles.add(new TileHolder(tile, tickProvider.getNextTick((WorldServer)nativeWorld,position), position)); + } + + //******************************************* + //* Step three: Translate all the blocks * + //******************************************* + // blockedByWater=false means an ocean-going vessel + //TODO: Simplify + //TODO: go by chunks + //TODO: Don't move unnecessary blocks + //get the blocks and rotate them + HashMap blockData = new HashMap<>(); + for(BlockPosition position : rotatedPositions.keySet()){ + blockData.put(position,nativeWorld.getType(position).a(ROTATION[rotation.ordinal()])); + } + //create the new block + for(Map.Entry entry : blockData.entrySet()) { + setBlockFast(nativeWorld, rotatedPositions.get(entry.getKey()), entry.getValue()); + } + + + //******************************************* + //* Step four: replace all the tiles * + //******************************************* + //TODO: go by chunks + for(TileHolder tileHolder : tiles){ + moveTileEntity(nativeWorld, rotatedPositions.get(tileHolder.getTilePosition()),tileHolder.getTile()); + if(tileHolder.getNextTick()==null) + continue; + final long currentTime = nativeWorld.worldData.getTime(); + //nativeWorld.b(rotatedPositions.get(tileHolder.getNextTick().a), tileHolder.getNextTick().a(), (int) (tileHolder.getNextTick().b - currentTime), tileHolder.getNextTick().c); + //BlockPosition, Object, int, TickListPriority + nativeWorld.b(rotatedPositions.get(tileHolder.getNextTick().a), tileHolder.getTile()); + } + + //******************************************* + //* Step five: Destroy the leftovers * + //******************************************* + //TODO: add support for pass-through + Collection deletePositions = CollectionUtils.filter(rotatedPositions.keySet(),rotatedPositions.values()); + for(BlockPosition position : deletePositions){ + setBlockFast(nativeWorld, position, Blocks.AIR.getBlockData()); + } + + //******************************************* + //* Step six: Update the blocks * + //******************************************* + for(BlockPosition newPosition : rotatedPositions.values()) { + // CraftBlockState.getBlockState(nativeWorld,newPosition.getX(), newPosition.getY(), newPosition.getZ()).update(false,false); + CraftBlockState.getBlockState(nativeWorld, newPosition, 3).update(false, false); + } + for(BlockPosition deletedPosition : deletePositions){ + // CraftBlockState.getBlockState(nativeWorld,deletedPosition.getX(), deletedPosition.getY(), deletedPosition.getZ()).update(false,false); + CraftBlockState.getBlockState(nativeWorld, deletedPosition, 3).update(false, false); + } + //******************************************* + //* Step seven: Send to players * + //******************************************* + List chunks = new ArrayList<>(); + for(BlockPosition position : rotatedPositions.values()){ + Chunk chunk = nativeWorld.getChunkAtWorldCoords(position); + if(!chunks.contains(chunk)){ + chunks.add(chunk); + } + } + for(BlockPosition position : deletePositions){ + Chunk chunk = nativeWorld.getChunkAtWorldCoords(position); + if(!chunks.contains(chunk)){ + chunks.add(chunk); + } + } + } + + @Override + public void translateCraft(@NotNull Craft craft, @NotNull MovecraftLocation displacement) { + //TODO: Add supourt for rotations + //A craftTranslateCommand should only occur if the craft is moving to a valid position + //******************************************* + //* Step one: Convert to Positions * + //******************************************* + BlockPosition translateVector = locationToPosition(displacement); + List positions = new ArrayList<>(); + for(MovecraftLocation movecraftLocation : craft.getHitBox()) { + positions.add(locationToPosition((movecraftLocation)).b(translateVector)); + + } + //******************************************* + //* Step two: Get the tiles * + //******************************************* + World nativeWorld = ((CraftWorld) craft.getW()).getHandle(); + List tiles = new ArrayList<>(); + //get the tiles + for(BlockPosition position : positions){ + if(nativeWorld.getType(position) == Blocks.AIR.getBlockData()) + continue; + //TileEntity tile = nativeWorld.removeTileEntity(position); + TileEntity tile = removeTileEntity(nativeWorld,position); + if(tile == null) + continue; + //get the nextTick to move with the tile + + //nativeWorld.capturedTileEntities.remove(position); + //nativeWorld.getChunkAtWorldCoords(position).getTileEntities().remove(position); + tiles.add(new TileHolder(tile, tickProvider.getNextTick((WorldServer)nativeWorld,position), position)); + + } + //******************************************* + //* Step three: Translate all the blocks * + //******************************************* + // blockedByWater=false means an ocean-going vessel + //TODO: Simplify + //TODO: go by chunks + //TODO: Don't move unnecessary blocks + //get the blocks + List blockData = new ArrayList<>(); + for(BlockPosition position : positions){ + blockData.add(nativeWorld.getType(position)); + } + //translate the positions + List newPositions = new ArrayList<>(); + for(BlockPosition position : positions){ + newPositions.add(position.a(translateVector)); + } + //create the new block + for(int i = 0; i deletePositions = CollectionUtils.filter(positions,newPositions); + for(BlockPosition position : deletePositions){ + setBlockFast(nativeWorld, position, Blocks.AIR.getBlockData()); + } + + //******************************************* + //* Step six: Update the blocks * + //******************************************* + for(BlockPosition newPosition : newPositions) { + CraftBlockState.getBlockState(nativeWorld, newPosition, 3).update(false,false); + } + for(BlockPosition deletedPosition : deletePositions){ + CraftBlockState.getBlockState(nativeWorld, deletedPosition, 3).update(false,false); + } + //******************************************* + //* Step seven: Send to players * + //******************************************* + List chunks = new ArrayList<>(); + for(BlockPosition position : newPositions){ + Chunk chunk = nativeWorld.getChunkAtWorldCoords(position); + if(!chunks.contains(chunk)){ + chunks.add(chunk); + } + } + for(BlockPosition position : deletePositions){ + Chunk chunk = nativeWorld.getChunkAtWorldCoords(position); + if(!chunks.contains(chunk)){ + chunks.add(chunk); + } + } + //sendToPlayers(chunks.toArray(new Chunk[0])); + } + + @Override + public void addPlayerLocation(Player player, double x, double y, double z, float yaw, float pitch){ + EntityPlayer ePlayer = ((CraftPlayer) player).getHandle(); + if(internalTeleportMH == null) { + //something went wrong + super.addPlayerLocation(player, x, y, z, yaw, pitch); + return; + } + try { + final Location oldLoc = player.getLocation().clone(); + final Location newLoc = player.getLocation().add(x,y,z); + internalTeleportMH.invoke(ePlayer.playerConnection, x + player.getLocation().getX(), y + player.getLocation().getY(), z + player.getLocation().getZ(), yaw, pitch, EnumSet.allOf(PacketPlayOutPosition.EnumPlayerTeleportFlags.class)); + Bukkit.getServer().getPluginManager().callEvent(new PlayerMoveEvent(player,oldLoc,newLoc)); + } catch (Throwable throwable) { + throwable.printStackTrace(); + } + } + + @Nullable + private TileEntity removeTileEntity(@NotNull World world, @NotNull BlockPosition position){ + TileEntity tile = world.getTileEntity(position); + if(tile == null) + return null; + //cleanup + world.capturedTileEntities.remove(position); + world.getChunkAtWorldCoords(position).getTileEntities().remove(position); + if(!Settings.IsPaper) + world.tileEntityList.remove(tile); + world.tileEntityListTick.remove(tile); + if(!bMap.containsKey(world)){ + try { + Field bField = World.class.getDeclaredField("tileEntityListPending"); + bField.setAccessible(true); + bMap.put(world, (List) bField.get(world));//TODO bug fix + } catch (IllegalAccessException | IllegalArgumentException | NoSuchFieldException | SecurityException e1) { + e1.printStackTrace(); + } + } + bMap.get(world).remove(tile); + return tile; + } + + @NotNull + private BlockPosition locationToPosition(@NotNull MovecraftLocation loc) { + return new BlockPosition(loc.getX(), loc.getY(), loc.getZ()); + } + + private void setBlockFast(@NotNull World world, @NotNull BlockPosition position,@NotNull IBlockData data) { + Chunk chunk = world.getChunkAtWorldCoords(position); + ChunkSection chunkSection = chunk.getSections()[position.getY()>>4]; + if (chunkSection == null) { + // Put a GLASS block to initialize the section. It will be replaced next with the real block. + chunk.setType(position, Blocks.GLASS.getBlockData(), true); + chunkSection = chunk.getSections()[position.getY() >> 4]; + + } + chunkSection.setType(position.getX()&15, position.getY()&15, position.getZ()&15, data); + } + + @Override + public void setBlockFast(@NotNull Location location, @NotNull Material material, byte data){ + setBlockFast(location, Rotation.NONE, material, data); + } + + @Override + public void setBlockFast(@NotNull Location location, @NotNull Rotation rotation, @NotNull Material material, byte data) { + IBlockData blockData = CraftMagicNumbers.getBlock(material).getBlockData(); + blockData = blockData.a(ROTATION[rotation.ordinal()]); + World world = ((CraftWorld)(location.getWorld())).getHandle(); + BlockPosition blockPosition = locationToPosition(bukkit2MovecraftLoc(location)); + setBlockFast(world,blockPosition,blockData); + } + + @Override + public void disableShadow(@NotNull Material type) { + Method method; + //try { + Block tempBlock = CraftMagicNumbers.getBlock(type); + //method = Block.class.getDeclaredMethod("d", int.class); + //method.setAccessible(true); + //method.invoke(tempBlock, 0); + //} catch (NoSuchMethodException | InvocationTargetException | IllegalArgumentException | IllegalAccessException | SecurityException e1) { + // TODO Auto-generated catch block + // e1.printStackTrace(); + //} + } + + private static MovecraftLocation bukkit2MovecraftLoc(Location l) { + return new MovecraftLocation(l.getBlockX(), l.getBlockY(), l.getBlockZ()); + } + + private void moveTileEntity(@NotNull World nativeWorld, @NotNull BlockPosition newPosition, @NotNull TileEntity tile){ + Chunk chunk = nativeWorld.getChunkAtWorldCoords(newPosition); + tile.invalidateBlockCache(); + if(nativeWorld.captureBlockStates) { + tile.setLocation(nativeWorld, newPosition); + nativeWorld.capturedTileEntities.put(newPosition, tile); + return; + } + tile.setPosition(newPosition); + chunk.tileEntities.put(newPosition, tile); + } + + private class TileHolder{ + @NotNull private final TileEntity tile; + @Nullable + private final NextTickListEntry nextTick; + @NotNull private final BlockPosition tilePosition; + + public TileHolder(@NotNull TileEntity tile, @Nullable NextTickListEntry nextTick, @NotNull BlockPosition tilePosition){ + this.tile = tile; + this.nextTick = nextTick; + this.tilePosition = tilePosition; + } + + + @NotNull + public TileEntity getTile() { + return tile; + } + + @Nullable + public NextTickListEntry getNextTick() { + return nextTick; + } + + @NotNull + public BlockPosition getTilePosition() { + return tilePosition; + } + } +} diff --git a/modules/v1_15_R1/src/main/java/net/countercraft/movecraft/compat/v1_15_R1/NextTickProvider.java b/modules/v1_15_R1/src/main/java/net/countercraft/movecraft/compat/v1_15_R1/NextTickProvider.java new file mode 100644 index 000000000..bfb570a15 --- /dev/null +++ b/modules/v1_15_R1/src/main/java/net/countercraft/movecraft/compat/v1_15_R1/NextTickProvider.java @@ -0,0 +1,57 @@ +package net.countercraft.movecraft.compat.v1_15_R1; + +import net.minecraft.server.v1_15_R1.*; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.lang.reflect.Field; +import java.util.*; + +public class NextTickProvider { + private Map,Collection>> tickMap = new HashMap<>(); + + private boolean isRegistered(@NotNull WorldServer world){ + return tickMap.containsKey(world); + } + + @SuppressWarnings("unchecked") + private void registerWorld(@NotNull WorldServer world){ + Collection W = new ArrayList<>(); + Set nextTickList = new HashSet<>(); + TickListServer blockTickListServer = world.getBlockTickList(); + try { + Field gField = TickListServer.class.getDeclaredField("g"); + gField.setAccessible(true); + W = (Collection) gField.get(blockTickListServer); + Field ntlField = TickListServer.class.getDeclaredField("nextTickList"); + ntlField.setAccessible(true); + nextTickList = (Set) ntlField.get(blockTickListServer); + } catch (IllegalAccessException | IllegalArgumentException | NoSuchFieldException | SecurityException e1) { + e1.printStackTrace(); + } + tickMap.put(world, new AbstractMap.SimpleImmutableEntry<>(nextTickList,W)); + } + + @Nullable + public NextTickListEntry getNextTick(@NotNull WorldServer world,@NotNull BlockPosition position){ + if(!isRegistered(world)) + registerWorld(world); + AbstractMap.SimpleImmutableEntry, Collection> listPair = tickMap.get(world); + for(Iterator iterator = listPair.getKey().iterator(); iterator.hasNext();) { + NextTickListEntry listEntry = iterator.next(); + if (position.equals(listEntry.a)) { + iterator.remove(); + return listEntry; + } + } + for(Iterator iterator = listPair.getValue().iterator(); iterator.hasNext();) { + NextTickListEntry listEntry = iterator.next(); + if (position.equals(listEntry.a)) { + iterator.remove(); + return listEntry; + } + } + return null; + + } +} diff --git a/pom.xml b/pom.xml index d54d1fda0..a99dc57be 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ org.spigotmc spigot-api - 1.14.2-R0.1-SNAPSHOT + 1.15-R0.1-SNAPSHOT Movecraft Parent Pom From 8fea127ec41729f8390f0ae10b64918a72711471 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Wed, 11 Dec 2019 14:47:16 +0100 Subject: [PATCH 095/304] Dropped 1.8.8 support --- .../update/EntityTranslateUpdateCommand.java | 3 +- .../movecraft/utils/BlockContainer.java | 3 +- .../movecraft/utils/BlockUtils.java | 9 + modules/v1_8_R3/pom.xml | 63 --- .../compat/v1_8_R3/IWorldHandler.java | 406 ------------------ .../compat/v1_8_R3/NextTickProvider.java | 68 --- 6 files changed, 13 insertions(+), 539 deletions(-) create mode 100644 modules/api/src/main/java/net/countercraft/movecraft/utils/BlockUtils.java delete mode 100644 modules/v1_8_R3/pom.xml delete mode 100644 modules/v1_8_R3/src/main/java/net/countercraft/movecraft/compat/v1_8_R3/IWorldHandler.java delete mode 100644 modules/v1_8_R3/src/main/java/net/countercraft/movecraft/compat/v1_8_R3/NextTickProvider.java diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/EntityTranslateUpdateCommand.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/EntityTranslateUpdateCommand.java index 90de19b07..b9322ba5e 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/EntityTranslateUpdateCommand.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/EntityTranslateUpdateCommand.java @@ -17,6 +17,7 @@ package net.countercraft.movecraft.mapUpdater.update; +import net.countercraft.movecraft.config.Settings; import net.countercraft.movecraft.craft.Craft; import net.countercraft.movecraft.utils.HitBox; import net.countercraft.movecraft.utils.TeleportUtils; @@ -64,7 +65,7 @@ public void doUpdate() { } for (Entity entity : getEntitiesOnCraft()){ Location playerLoc = entity.getLocation(); - if (!(entity instanceof Player) || yaw > .01 || pitch > .01 || yaw < -.01 || pitch < -.01) { + if (!(entity instanceof Player) || yaw > .01 || pitch > .01 || yaw < -.01 || pitch < -.01 || Settings.IsPre1_9) { entity.teleport(new Location(entity.getWorld(), x + playerLoc.getX(),y + playerLoc.getY(),z + playerLoc.getZ(),yaw + playerLoc.getYaw(),pitch + playerLoc.getPitch())); return; } diff --git a/modules/api/src/main/java/net/countercraft/movecraft/utils/BlockContainer.java b/modules/api/src/main/java/net/countercraft/movecraft/utils/BlockContainer.java index 740387f02..9ab977e54 100644 --- a/modules/api/src/main/java/net/countercraft/movecraft/utils/BlockContainer.java +++ b/modules/api/src/main/java/net/countercraft/movecraft/utils/BlockContainer.java @@ -52,7 +52,8 @@ public BlockContainer(Object obj){ } type = Material.getMaterial(str); if (type == null){ - throw new IllegalArgumentException(str + "is not a valid Material ID"); + Bukkit.getLogger().warning("[Movecraft] " + str + " is not a valid Material ID"); + continue; } blocks.add(new MovecraftBlock(type)); } else if (o instanceof Integer){ diff --git a/modules/api/src/main/java/net/countercraft/movecraft/utils/BlockUtils.java b/modules/api/src/main/java/net/countercraft/movecraft/utils/BlockUtils.java new file mode 100644 index 000000000..358de4ec8 --- /dev/null +++ b/modules/api/src/main/java/net/countercraft/movecraft/utils/BlockUtils.java @@ -0,0 +1,9 @@ +package net.countercraft.movecraft.utils; + +import org.bukkit.block.Block; + +public class BlockUtils { + public void rotateBlock(Block block) { + + } +} diff --git a/modules/v1_8_R3/pom.xml b/modules/v1_8_R3/pom.xml deleted file mode 100644 index 40f385a63..000000000 --- a/modules/v1_8_R3/pom.xml +++ /dev/null @@ -1,63 +0,0 @@ - - - - movecraft-parent - net.countercraft - parent - ../../pom.xml - - 4.0.0 - - movecraft-v1_8_R3 - Movecraft-v1_8_R3 - v1_8_R3 - jar - - - - org.bukkit - craftbukkit - 1.8.8-R0.1-SNAPSHOT - - - net.countercraft - movecraft-api - API - jar - - - org.jetbrains - annotations-java5 - RELEASE - - - - src/main/java - - - org.apache.maven.plugins - maven-compiler-plugin - 3.7.0 - - - net/countercraft/movecraft/compat/v1_8_R3/** - - 1.8 - 1.8 - - - - org.apache.maven.plugins - maven-jar-plugin - 2.4 - - - net/countercraft/movecraft/compat/v1_8_R3/** - - - - - - \ No newline at end of file diff --git a/modules/v1_8_R3/src/main/java/net/countercraft/movecraft/compat/v1_8_R3/IWorldHandler.java b/modules/v1_8_R3/src/main/java/net/countercraft/movecraft/compat/v1_8_R3/IWorldHandler.java deleted file mode 100644 index 179f220e8..000000000 --- a/modules/v1_8_R3/src/main/java/net/countercraft/movecraft/compat/v1_8_R3/IWorldHandler.java +++ /dev/null @@ -1,406 +0,0 @@ -package net.countercraft.movecraft.compat.v1_8_R3; - -import net.countercraft.movecraft.MovecraftLocation; -import net.countercraft.movecraft.Rotation; -import net.countercraft.movecraft.WorldHandler; -import net.countercraft.movecraft.config.Settings; -import net.countercraft.movecraft.craft.Craft; -import net.countercraft.movecraft.utils.CollectionUtils; -import net.countercraft.movecraft.utils.MathUtils; -import net.minecraft.server.v1_8_R3.*; -import org.bukkit.Location; -import org.bukkit.Material; -import org.bukkit.craftbukkit.v1_8_R3.CraftWorld; -import org.bukkit.craftbukkit.v1_8_R3.block.CraftBlockState; -import org.bukkit.craftbukkit.v1_8_R3.entity.CraftPlayer; -import org.bukkit.craftbukkit.v1_8_R3.util.CraftMagicNumbers; -import org.bukkit.entity.Player; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandles; -import java.lang.reflect.Field; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.util.*; - -public class IWorldHandler extends WorldHandler { - //private static final EnumBlockRotation ROTATION[]; - private final HashMap> bMap = new HashMap<>(); - private MethodHandle internalTeleportMH; - /*static { - ROTATION = new EnumBlockRotation[3]; - ROTATION[Rotation.NONE.ordinal()] = EnumBlockRotation.NONE; - ROTATION[Rotation.CLOCKWISE.ordinal()] = EnumBlockRotation.CLOCKWISE_90; - ROTATION[Rotation.ANTICLOCKWISE.ordinal()] = EnumBlockRotation.COUNTERCLOCKWISE_90; - }*/ - private final NextTickProvider tickProvider = new NextTickProvider(); - - public IWorldHandler() { - MethodHandles.Lookup lookup = MethodHandles.lookup(); - Method teleport = null; - try { - teleport = PlayerConnection.class.getDeclaredMethod("internalTeleport", double.class, double.class, double.class, float.class, float.class, Set.class); - teleport.setAccessible(true); - internalTeleportMH = lookup.unreflect(teleport); - - } catch (NoSuchMethodException | IllegalAccessException e) { - e.printStackTrace(); - } - } - - @Override - public void addPlayerLocation(Player player, double x, double y, double z, float yaw, float pitch){ - EntityPlayer ePlayer = ((CraftPlayer) player).getHandle(); - if(internalTeleportMH == null) { - //something went wrong - super.addPlayerLocation(player, x, y, z, yaw, pitch); - return; - } - try { - internalTeleportMH.invoke(ePlayer.playerConnection, x, y, z, yaw, pitch, EnumSet.allOf(PacketPlayOutPosition.EnumPlayerTeleportFlags.class)); - } catch (Throwable throwable) { - throwable.printStackTrace(); - } - } - - @Override - public void rotateCraft(@NotNull Craft craft, @NotNull MovecraftLocation originPoint, @NotNull Rotation rotation) { - //******************************************* - //* Step one: Convert to Positions * - //******************************************* - HashMap rotatedPositions = new HashMap<>(); - Rotation counterRotation = rotation == Rotation.CLOCKWISE ? Rotation.ANTICLOCKWISE : Rotation.CLOCKWISE; - for(MovecraftLocation newLocation : craft.getHitBox()){ - rotatedPositions.put(locationToPosition(MathUtils.rotateVec(counterRotation, newLocation.subtract(originPoint)).add(originPoint)),locationToPosition(newLocation)); - } - //******************************************* - //* Step two: Get the tiles * - //******************************************* - World nativeWorld = ((CraftWorld) craft.getW()).getHandle(); - List tiles = new ArrayList<>(); - //get the tiles - for(BlockPosition position : rotatedPositions.keySet()){ - //TileEntity tile = nativeWorld.removeTileEntity(position); - TileEntity tile = removeTileEntity(nativeWorld,position); - if(tile == null) - continue; - //tile.a(ROTATION[rotation.ordinal()]); - //get the nextTick to move with the tile - tiles.add(new TileHolder(tile, tickProvider.getNextTick((WorldServer)nativeWorld,position), position)); - } - - //******************************************* - //* Step three: Translate all the blocks * - //******************************************* - // blockedByWater=false means an ocean-going vessel - //TODO: Simplify - //TODO: go by chunks - //TODO: Don't move unnecessary blocks - //get the blocks and rotate them - HashMap blockData = new HashMap<>(); - for(BlockPosition position : rotatedPositions.keySet()){ - blockData.put(position, rotate(rotation, nativeWorld.getType(position))); - } - //create the new block - for(Map.Entry entry : blockData.entrySet()) { - setBlockFast(nativeWorld, rotatedPositions.get(entry.getKey()), entry.getValue()); - } - - - //******************************************* - //* Step four: replace all the tiles * - //******************************************* - //TODO: go by chunks - for(TileHolder tileHolder : tiles){ - moveTileEntity(nativeWorld, rotatedPositions.get(tileHolder.getTilePosition()),tileHolder.getTile()); - if(tileHolder.getNextTick()==null) - continue; - final long currentTime = nativeWorld.worldData.getTime(); - nativeWorld.b(rotatedPositions.get(tileHolder.getNextTick().a), tileHolder.getNextTick().a(), (int) (tileHolder.getNextTick().b - currentTime), tileHolder.getNextTick().c); - } - - //******************************************* - //* Step five: Destroy the leftovers * - //******************************************* - //TODO: add support for pass-through - Collection deletePositions = CollectionUtils.filter(rotatedPositions.keySet(),rotatedPositions.values()); - for(BlockPosition position : deletePositions){ - setBlockFast(nativeWorld, position, Blocks.AIR.getBlockData()); - } - - //******************************************* - //* Step six: Update the blocks * - //******************************************* - for(BlockPosition newPosition : rotatedPositions.values()) { - CraftBlockState.getBlockState(nativeWorld,newPosition.getX(), newPosition.getY(), newPosition.getZ()).update(false,false); - } - for(BlockPosition deletedPosition : deletePositions){ - CraftBlockState.getBlockState(nativeWorld,deletedPosition.getX(), deletedPosition.getY(), deletedPosition.getZ()).update(false,false); - } - //******************************************* - //* Step seven: Send to players * - //******************************************* - List chunks = new ArrayList<>(); - for(BlockPosition position : rotatedPositions.values()){ - Chunk chunk = nativeWorld.getChunkAtWorldCoords(position); - if(!chunks.contains(chunk)){ - chunks.add(chunk); - } - } - for(BlockPosition position : deletePositions){ - Chunk chunk = nativeWorld.getChunkAtWorldCoords(position); - if(!chunks.contains(chunk)){ - chunks.add(chunk); - } - } - } - - @Override - public void translateCraft(@NotNull Craft craft, @NotNull MovecraftLocation displacement) { - //TODO: Add supourt for rotations - //A craftTranslateCommand should only occur if the craft is moving to a valid position - //******************************************* - //* Step one: Convert to Positions * - //******************************************* - BlockPosition translateVector = locationToPosition(displacement); - List positions = new ArrayList<>(); - for(MovecraftLocation movecraftLocation : craft.getHitBox()) { - positions.add(locationToPosition((movecraftLocation)).b(translateVector)); - - } - //******************************************* - //* Step two: Get the tiles * - //******************************************* - World nativeWorld = ((CraftWorld) craft.getW()).getHandle(); - List tiles = new ArrayList<>(); - //get the tiles - for(BlockPosition position : positions){ - if(nativeWorld.getType(position) == Blocks.AIR.getBlockData()) - continue; - //TileEntity tile = nativeWorld.removeTileEntity(position); - TileEntity tile = removeTileEntity(nativeWorld,position); - if(tile == null) - continue; - //get the nextTick to move with the tile - - //nativeWorld.capturedTileEntities.remove(position); - //nativeWorld.getChunkAtWorldCoords(position).getTileEntities().remove(position); - tiles.add(new TileHolder(tile, tickProvider.getNextTick((WorldServer)nativeWorld,position), position)); - - } - //******************************************* - //* Step three: Translate all the blocks * - //******************************************* - // blockedByWater=false means an ocean-going vessel - //TODO: Simplify - //TODO: go by chunks - //TODO: Don't move unnecessary blocks - //get the blocks - List blockData = new ArrayList<>(); - for(BlockPosition position : positions){ - blockData.add(nativeWorld.getType(position)); - } - //translate the positions - List newPositions = new ArrayList<>(); - for(BlockPosition position : positions){ - newPositions.add(position.a(translateVector)); - } - //create the new block - for(int i = 0; i deletePositions = CollectionUtils.filter(positions,newPositions); - for(BlockPosition position : deletePositions){ - setBlockFast(nativeWorld, position, Blocks.AIR.getBlockData()); - } - - //******************************************* - //* Step six: Update the blocks * - //******************************************* - for(BlockPosition newPosition : newPositions) { - CraftBlockState.getBlockState(nativeWorld,newPosition.getX(), newPosition.getY(), newPosition.getZ()).update(false,false); - } - for(BlockPosition deletedPosition : deletePositions){ - CraftBlockState.getBlockState(nativeWorld,deletedPosition.getX(), deletedPosition.getY(), deletedPosition.getZ()).update(false,false); - } - //******************************************* - //* Step seven: Send to players * - //******************************************* - List chunks = new ArrayList<>(); - for(BlockPosition position : newPositions){ - Chunk chunk = nativeWorld.getChunkAtWorldCoords(position); - if(!chunks.contains(chunk)){ - chunks.add(chunk); - } - } - for(BlockPosition position : deletePositions){ - Chunk chunk = nativeWorld.getChunkAtWorldCoords(position); - if(!chunks.contains(chunk)){ - chunks.add(chunk); - } - } - //sendToPlayers(chunks.toArray(new Chunk[0])); - } - - @Nullable - private TileEntity removeTileEntity(@NotNull World world, @NotNull BlockPosition position){ - TileEntity tile = world.getTileEntity(position); - if(tile == null) - return null; - //cleanup - world.capturedTileEntities.remove(position); - world.getChunkAtWorldCoords(position).getTileEntities().remove(position); - if(!Settings.IsPaper) - world.tileEntityList.remove(tile); - world.h.remove(tile); - if(!bMap.containsKey(world)){ - try { - Field bField = World.class.getDeclaredField("b"); - bField.setAccessible(true); - bMap.put(world, (List) bField.get(world)); - } catch (IllegalAccessException | IllegalArgumentException | NoSuchFieldException | SecurityException e1) { - e1.printStackTrace(); - } - } - bMap.get(world).remove(tile); - return tile; - } - - @NotNull - private BlockPosition locationToPosition(@NotNull MovecraftLocation loc) { - return new BlockPosition(loc.getX(), loc.getY(), loc.getZ()); - } - - private void setBlockFast(@NotNull World world, @NotNull BlockPosition position,@NotNull IBlockData data) { - Chunk chunk = world.getChunkAtWorldCoords(position); - ChunkSection chunkSection = chunk.getSections()[position.getY()>>4]; - if (chunkSection == null) { - // Put a GLASS block to initialize the section. It will be replaced next with the real block. - chunk.a(position, Blocks.GLASS.getBlockData()); - chunkSection = chunk.getSections()[position.getY() >> 4]; - } - - chunkSection.setType(position.getX()&15, position.getY()&15, position.getZ()&15, data); - } - - @Override - public void setBlockFast(@NotNull Location location, @NotNull Material material, byte data){ - setBlockFast(location, Rotation.NONE, material, data); - } - - @Override - public void setBlockFast(@NotNull Location location, @NotNull Rotation rotation, @NotNull Material material, byte data) { - IBlockData blockData = CraftMagicNumbers.getBlock(material).fromLegacyData(data); - blockData = rotate(rotation, blockData); - World world = ((CraftWorld)(location.getWorld())).getHandle(); - BlockPosition blockPosition = locationToPosition(bukkit2MovecraftLoc(location)); - setBlockFast(world,blockPosition,blockData); - } - - @Override - public void disableShadow(@NotNull Material type) { - Method method; - try { - Block tempBlock = CraftMagicNumbers.getBlock(type.getId()); - method = Block.class.getDeclaredMethod("d", int.class); - method.setAccessible(true); - method.invoke(tempBlock, 0); - } catch (NoSuchMethodException | InvocationTargetException | IllegalArgumentException | IllegalAccessException | SecurityException e1) { - // TODO Auto-generated catch block - e1.printStackTrace(); - } - } - - private static MovecraftLocation bukkit2MovecraftLoc(Location l) { - return new MovecraftLocation(l.getBlockX(), l.getBlockY(), l.getBlockZ()); - } - - private void moveTileEntity(@NotNull World nativeWorld, @NotNull BlockPosition newPosition, @NotNull TileEntity tile){ - Chunk chunk = nativeWorld.getChunkAtWorldCoords(newPosition); - tile.E(); - if(nativeWorld.captureBlockStates) { - tile.a(nativeWorld); - tile.a(newPosition); - nativeWorld.capturedTileEntities.put(newPosition, tile); - return; - } - tile.a(newPosition); - chunk.tileEntities.put(newPosition, tile); - } - - private IBlockData rotate(final Rotation rotation, IBlockData originalData) { - if (!(originalData.getBlock() instanceof BlockDirectional)) { - return originalData; - } - - EnumDirection eDir = originalData.get(BlockDirectional.FACING); - EnumDirection rotated; - switch (eDir) { - case EAST: - rotated = rotation == Rotation.CLOCKWISE ? EnumDirection.SOUTH : EnumDirection.NORTH; - break; - case WEST: - rotated = rotation == Rotation.CLOCKWISE ? EnumDirection.NORTH : EnumDirection.SOUTH; - break; - case SOUTH: - rotated = rotation == Rotation.CLOCKWISE ? EnumDirection.WEST : EnumDirection.EAST; - break; - case NORTH: - rotated = rotation == Rotation.CLOCKWISE ? EnumDirection.EAST : EnumDirection.WEST; - break; - default: - rotated = eDir; - break; - } - - BlockStateDirection direction = BlockDirectional.FACING; - IBlockData rotatedBlock = originalData.a(direction); - rotatedBlock.set(direction, rotated); - return rotatedBlock; - } - - private class TileHolder{ - @NotNull private final TileEntity tile; - @Nullable - private final NextTickListEntry nextTick; - @NotNull private final BlockPosition tilePosition; - - public TileHolder(@NotNull TileEntity tile, @Nullable NextTickListEntry nextTick, @NotNull BlockPosition tilePosition){ - this.tile = tile; - this.nextTick = nextTick; - this.tilePosition = tilePosition; - } - - - @NotNull - public TileEntity getTile() { - return tile; - } - - @Nullable - public NextTickListEntry getNextTick() { - return nextTick; - } - - @NotNull - public BlockPosition getTilePosition() { - return tilePosition; - } - } -} diff --git a/modules/v1_8_R3/src/main/java/net/countercraft/movecraft/compat/v1_8_R3/NextTickProvider.java b/modules/v1_8_R3/src/main/java/net/countercraft/movecraft/compat/v1_8_R3/NextTickProvider.java deleted file mode 100644 index c5f26aaa9..000000000 --- a/modules/v1_8_R3/src/main/java/net/countercraft/movecraft/compat/v1_8_R3/NextTickProvider.java +++ /dev/null @@ -1,68 +0,0 @@ -package net.countercraft.movecraft.compat.v1_8_R3; - - -import net.minecraft.server.v1_8_R3.BlockPosition; -import net.minecraft.server.v1_8_R3.NextTickListEntry; -import net.minecraft.server.v1_8_R3.WorldServer; -import org.apache.commons.lang3.tuple.ImmutablePair; -import org.bukkit.craftbukkit.v1_8_R3.util.HashTreeSet; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.lang.ref.WeakReference; -import java.lang.reflect.Field; -import java.util.*; - -public class NextTickProvider { - private Map>,WeakReference>>> tickMap = new HashMap<>(); - - private boolean isRegistered(@NotNull WorldServer world){ - if(!tickMap.containsKey(world)) - return false; - ImmutablePair>, WeakReference>> listPair = tickMap.get(world); - return listPair.right.get() != null && listPair.left.get() != null; - } - - @SuppressWarnings("unchecked") - private void registerWorld(@NotNull WorldServer world){ - List V = new ArrayList<>(); - HashTreeSet M = new HashTreeSet<>(); - - try { - - Field VField = WorldServer.class.getDeclaredField("V"); - VField.setAccessible(true); - V = (List) VField.get(world); - Field MField = WorldServer.class.getDeclaredField("M"); - MField.setAccessible(true); - M = (HashTreeSet) MField.get(world); - } catch (IllegalAccessException | IllegalArgumentException | NoSuchFieldException | SecurityException e1) { - e1.printStackTrace(); - } - tickMap.put(world, new ImmutablePair<>(new WeakReference<>(M), new WeakReference<>(V))); - } - - @Nullable - @SuppressWarnings("ConstantConditions") - public NextTickListEntry getNextTick(@NotNull WorldServer world, @NotNull BlockPosition position){ - if(!isRegistered(world)) - registerWorld(world); - ImmutablePair>, WeakReference>> listPair = tickMap.get(world); - for(Iterator iterator = listPair.left.get().iterator(); iterator.hasNext();) { - NextTickListEntry listEntry = iterator.next(); - if (position.equals(listEntry.a)) { - iterator.remove(); - return listEntry; - } - } - for(Iterator iterator = listPair.right.get().iterator(); iterator.hasNext();) { - NextTickListEntry listEntry = iterator.next(); - if (position.equals(listEntry.a)) { - iterator.remove(); - return listEntry; - } - } - return null; - - } -} From d92a9de7c0e6d145a113545fd6093158a4691802 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Wed, 11 Dec 2019 15:30:14 +0100 Subject: [PATCH 096/304] Minor changes --- modules/Movecraft/pom.xml | 6 ------ .../countercraft/movecraft/utils/LegacyUtils.java | 2 +- .../movecraft/compat/v1_15_R1/IWorldHandler.java | 15 +++++++++++++-- pom.xml | 1 - 4 files changed, 14 insertions(+), 10 deletions(-) diff --git a/modules/Movecraft/pom.xml b/modules/Movecraft/pom.xml index 624e79ebe..295f61647 100644 --- a/modules/Movecraft/pom.xml +++ b/modules/Movecraft/pom.xml @@ -54,12 +54,6 @@ v1_13_R2 jar - - net.countercraft - movecraft-v1_8_R3 - v1_8_R3 - jar - net.countercraft movecraft-v1_9_R2 diff --git a/modules/api/src/main/java/net/countercraft/movecraft/utils/LegacyUtils.java b/modules/api/src/main/java/net/countercraft/movecraft/utils/LegacyUtils.java index 019dc1d5f..3578c7fa5 100644 --- a/modules/api/src/main/java/net/countercraft/movecraft/utils/LegacyUtils.java +++ b/modules/api/src/main/java/net/countercraft/movecraft/utils/LegacyUtils.java @@ -70,7 +70,7 @@ public class LegacyUtils { //Sounds removed in 1.13 public static Sound ENITIY_IRONGOLEM_DEATH = Settings.IsLegacy && !Settings.IsPre1_9 ? Sound.ENTITY_IRONGOLEM_DEATH : null; - public static Sound IRONGOLEM_DEATH = Sound.valueOf("IRONGOLEM_DEATH"); + public static Sound IRONGOLEM_DEATH = Settings.IsPre1_9 ? Sound.valueOf("IRONGOLEM_DEATH") : null; //Methods removed in 1.13 public static Material getMaterial(int id){ try { diff --git a/modules/v1_15_R1/src/main/java/net/countercraft/movecraft/compat/v1_15_R1/IWorldHandler.java b/modules/v1_15_R1/src/main/java/net/countercraft/movecraft/compat/v1_15_R1/IWorldHandler.java index 59cbbdf74..6c54058f9 100644 --- a/modules/v1_15_R1/src/main/java/net/countercraft/movecraft/compat/v1_15_R1/IWorldHandler.java +++ b/modules/v1_15_R1/src/main/java/net/countercraft/movecraft/compat/v1_15_R1/IWorldHandler.java @@ -195,7 +195,8 @@ public void translateCraft(@NotNull Craft craft, @NotNull MovecraftLocation disp //translate the positions List newPositions = new ArrayList<>(); for(BlockPosition position : positions){ - newPositions.add(position.a(translateVector)); + BlockPosition newPos = position.a(translateVector); + newPositions.add(newPos); } //create the new block for(int i = 0; i modules/api - modules/v1_8_R3 modules/v1_9_R2 modules/v1_10_R1 modules/v1_11_R1 From c8228b43728bd5ae0fcea0ebae9aa7218cdf90d1 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Wed, 11 Dec 2019 20:31:02 +0100 Subject: [PATCH 097/304] Fixed air check in gravity processing --- .../movecraft/async/translation/TranslationTask.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java index 6c4c1f6cb..f0b30ff9e 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java @@ -602,7 +602,7 @@ private boolean isOnGround(HashHitBox hitBox){ translatedBottomLocs.add(bottomLoc.translate(dx, dy, dz)); Material testType = bottomLoc.translate(0, -1, 0).toBukkit(craft.getW()).getBlock().getType(); //If the lowest part of the bottom locs touch the ground, return true anyways - if (testType != Material.AIR && !craft.getType().getPassthroughBlocks().contains(testType)){ + if (!testType.name().endsWith("AIR") && !craft.getType().getPassthroughBlocks().contains(testType)){ bottomLocsOnGround = true; } } From 4aaa47868d45456b6160e4b0db7f38e1f4d52d2e Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Mon, 23 Dec 2019 02:03:27 +0100 Subject: [PATCH 098/304] Updated nexttickproviders --- .../compat/v1_13_R2/NextTickProvider.java | 22 +++++++++++----- .../compat/v1_14_R1/NextTickProvider.java | 21 ++++++++++++---- .../compat/v1_15_R1/NextTickProvider.java | 25 +++++++++++++------ 3 files changed, 50 insertions(+), 18 deletions(-) diff --git a/modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/NextTickProvider.java b/modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/NextTickProvider.java index e1f1e29f2..b9980a4ed 100644 --- a/modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/NextTickProvider.java +++ b/modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/NextTickProvider.java @@ -39,12 +39,13 @@ public NextTickListEntry getNextTick(@NotNull WorldServer world,@NotNull if(!isRegistered(world)) registerWorld(world); ImmutablePair>, List>> listPair = tickMap.get(world); - - for(Iterator> iterator = listPair.left.iterator(); iterator.hasNext();) { - NextTickListEntry listEntry = iterator.next(); - if (position.equals(listEntry.a)) { - iterator.remove(); - return listEntry; + if(listPair.left.contains(fakeEntry(position))) { + for (Iterator> iterator = listPair.left.iterator(); iterator.hasNext(); ) { + NextTickListEntry listEntry = iterator.next(); + if (position.equals(listEntry.a)) { + iterator.remove(); + return listEntry; + } } } for(Iterator> iterator = listPair.right.iterator(); iterator.hasNext();) { @@ -57,4 +58,13 @@ public NextTickListEntry getNextTick(@NotNull WorldServer world,@NotNull return null; } + @NotNull + public Object fakeEntry(@NotNull BlockPosition position){ + return new Object(){ + @Override + public int hashCode() { + return position.hashCode(); + } + }; + } } diff --git a/modules/v1_14_R1/src/main/java/net/countercraft/movecraft/compat/v1_14_R1/NextTickProvider.java b/modules/v1_14_R1/src/main/java/net/countercraft/movecraft/compat/v1_14_R1/NextTickProvider.java index cc9909c03..56acdb718 100644 --- a/modules/v1_14_R1/src/main/java/net/countercraft/movecraft/compat/v1_14_R1/NextTickProvider.java +++ b/modules/v1_14_R1/src/main/java/net/countercraft/movecraft/compat/v1_14_R1/NextTickProvider.java @@ -37,11 +37,13 @@ public NextTickListEntry getNextTick(@NotNull WorldServer world,@NotNull BlockPo if(!isRegistered(world)) registerWorld(world); AbstractMap.SimpleImmutableEntry, Collection> listPair = tickMap.get(world); - for(Iterator iterator = listPair.getKey().iterator(); iterator.hasNext();) { - NextTickListEntry listEntry = iterator.next(); - if (position.equals(listEntry.a)) { - iterator.remove(); - return listEntry; + if(listPair.getKey().contains(fakeEntry(position))) { + for (Iterator iterator = listPair.getKey().iterator(); iterator.hasNext(); ) { + NextTickListEntry listEntry = iterator.next(); + if (position.equals(listEntry.a)) { + iterator.remove(); + return listEntry; + } } } for(Iterator iterator = listPair.getValue().iterator(); iterator.hasNext();) { @@ -54,4 +56,13 @@ public NextTickListEntry getNextTick(@NotNull WorldServer world,@NotNull BlockPo return null; } + @NotNull + public Object fakeEntry(@NotNull BlockPosition position){ + return new Object(){ + @Override + public int hashCode() { + return position.hashCode(); + } + }; + } } diff --git a/modules/v1_15_R1/src/main/java/net/countercraft/movecraft/compat/v1_15_R1/NextTickProvider.java b/modules/v1_15_R1/src/main/java/net/countercraft/movecraft/compat/v1_15_R1/NextTickProvider.java index bfb570a15..e46e96789 100644 --- a/modules/v1_15_R1/src/main/java/net/countercraft/movecraft/compat/v1_15_R1/NextTickProvider.java +++ b/modules/v1_15_R1/src/main/java/net/countercraft/movecraft/compat/v1_15_R1/NextTickProvider.java @@ -33,15 +33,17 @@ private void registerWorld(@NotNull WorldServer world){ } @Nullable - public NextTickListEntry getNextTick(@NotNull WorldServer world,@NotNull BlockPosition position){ - if(!isRegistered(world)) + public NextTickListEntry getNextTick(@NotNull WorldServer world,@NotNull BlockPosition position) { + if (!isRegistered(world)) registerWorld(world); AbstractMap.SimpleImmutableEntry, Collection> listPair = tickMap.get(world); - for(Iterator iterator = listPair.getKey().iterator(); iterator.hasNext();) { - NextTickListEntry listEntry = iterator.next(); - if (position.equals(listEntry.a)) { - iterator.remove(); - return listEntry; + if(listPair.getKey().contains(fakeEntry(position))) { + for (Iterator iterator = listPair.getKey().iterator(); iterator.hasNext(); ) { + NextTickListEntry listEntry = iterator.next(); + if (position.equals(listEntry.a)) { + iterator.remove(); + return listEntry; + } } } for(Iterator iterator = listPair.getValue().iterator(); iterator.hasNext();) { @@ -54,4 +56,13 @@ public NextTickListEntry getNextTick(@NotNull WorldServer world,@NotNull BlockPo return null; } + @NotNull + public Object fakeEntry(@NotNull BlockPosition position){ + return new Object(){ + @Override + public int hashCode() { + return position.hashCode(); + } + }; + } } From 0f65560f957e916fd120e47139ff84466bc3d502 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Mon, 23 Dec 2019 20:17:40 +0100 Subject: [PATCH 099/304] Made it more performance-efficient --- .../movecraft/compat/v1_13_R2/IWorldHandler.java | 1 + .../movecraft/compat/v1_14_R1/IWorldHandler.java | 1 + .../movecraft/compat/v1_14_R1/NextTickProvider.java | 10 ++++++---- .../movecraft/compat/v1_15_R1/IWorldHandler.java | 1 + .../movecraft/compat/v1_15_R1/NextTickProvider.java | 8 ++++---- 5 files changed, 13 insertions(+), 8 deletions(-) diff --git a/modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/IWorldHandler.java b/modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/IWorldHandler.java index 752b46e69..0da9aa4d0 100644 --- a/modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/IWorldHandler.java +++ b/modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/IWorldHandler.java @@ -302,6 +302,7 @@ private void setBlockFast(@NotNull World world, @NotNull BlockPosition position, chunkSection.setType(position.getX()&15, position.getY()&15, position.getZ()&15, data); + world.notify(position, data, data, 3); } @Override diff --git a/modules/v1_14_R1/src/main/java/net/countercraft/movecraft/compat/v1_14_R1/IWorldHandler.java b/modules/v1_14_R1/src/main/java/net/countercraft/movecraft/compat/v1_14_R1/IWorldHandler.java index f7f9f2e82..0fd5e58db 100644 --- a/modules/v1_14_R1/src/main/java/net/countercraft/movecraft/compat/v1_14_R1/IWorldHandler.java +++ b/modules/v1_14_R1/src/main/java/net/countercraft/movecraft/compat/v1_14_R1/IWorldHandler.java @@ -295,6 +295,7 @@ private void setBlockFast(@NotNull World world, @NotNull BlockPosition position, } chunkSection.setType(position.getX()&15, position.getY()&15, position.getZ()&15, data); + world.notify(position, data, data, 3); } @Override diff --git a/modules/v1_14_R1/src/main/java/net/countercraft/movecraft/compat/v1_14_R1/NextTickProvider.java b/modules/v1_14_R1/src/main/java/net/countercraft/movecraft/compat/v1_14_R1/NextTickProvider.java index 56acdb718..bbaba2929 100644 --- a/modules/v1_14_R1/src/main/java/net/countercraft/movecraft/compat/v1_14_R1/NextTickProvider.java +++ b/modules/v1_14_R1/src/main/java/net/countercraft/movecraft/compat/v1_14_R1/NextTickProvider.java @@ -17,15 +17,15 @@ private boolean isRegistered(@NotNull WorldServer world){ @SuppressWarnings("unchecked") private void registerWorld(@NotNull WorldServer world){ Collection W = new ArrayList<>(); - Set nextTickList = new HashSet<>(); + HashSet nextTickList = new HashSet<>(); TickListServer blockTickListServer = world.getBlockTickList(); try { Field gField = TickListServer.class.getDeclaredField("g"); gField.setAccessible(true); - W = (Collection) gField.get(blockTickListServer); + W.addAll((Collection) gField.get(blockTickListServer)) ; Field ntlField = TickListServer.class.getDeclaredField("nextTickList"); ntlField.setAccessible(true); - nextTickList = (Set) ntlField.get(blockTickListServer); + nextTickList.addAll((Collection) ntlField.get(blockTickListServer)); } catch (IllegalAccessException | IllegalArgumentException | NoSuchFieldException | SecurityException e1) { e1.printStackTrace(); } @@ -56,9 +56,11 @@ public NextTickListEntry getNextTick(@NotNull WorldServer world,@NotNull BlockPo return null; } + @NotNull public Object fakeEntry(@NotNull BlockPosition position){ - return new Object(){ + + return new Object() { @Override public int hashCode() { return position.hashCode(); diff --git a/modules/v1_15_R1/src/main/java/net/countercraft/movecraft/compat/v1_15_R1/IWorldHandler.java b/modules/v1_15_R1/src/main/java/net/countercraft/movecraft/compat/v1_15_R1/IWorldHandler.java index 00092529f..b7d9e9846 100644 --- a/modules/v1_15_R1/src/main/java/net/countercraft/movecraft/compat/v1_15_R1/IWorldHandler.java +++ b/modules/v1_15_R1/src/main/java/net/countercraft/movecraft/compat/v1_15_R1/IWorldHandler.java @@ -299,6 +299,7 @@ private void setBlockFast(@NotNull World world, @NotNull BlockPosition position, } chunkSection.setType(position.getX()&15, position.getY()&15, position.getZ()&15, data); + world.notify(position, data, data, 3); } @Override diff --git a/modules/v1_15_R1/src/main/java/net/countercraft/movecraft/compat/v1_15_R1/NextTickProvider.java b/modules/v1_15_R1/src/main/java/net/countercraft/movecraft/compat/v1_15_R1/NextTickProvider.java index e46e96789..e51837852 100644 --- a/modules/v1_15_R1/src/main/java/net/countercraft/movecraft/compat/v1_15_R1/NextTickProvider.java +++ b/modules/v1_15_R1/src/main/java/net/countercraft/movecraft/compat/v1_15_R1/NextTickProvider.java @@ -16,16 +16,16 @@ private boolean isRegistered(@NotNull WorldServer world){ @SuppressWarnings("unchecked") private void registerWorld(@NotNull WorldServer world){ - Collection W = new ArrayList<>(); - Set nextTickList = new HashSet<>(); + final Collection W = new ArrayList<>(); + final Set nextTickList = new HashSet<>(); TickListServer blockTickListServer = world.getBlockTickList(); try { Field gField = TickListServer.class.getDeclaredField("g"); gField.setAccessible(true); - W = (Collection) gField.get(blockTickListServer); + W.addAll((Collection) gField.get(blockTickListServer)); Field ntlField = TickListServer.class.getDeclaredField("nextTickList"); ntlField.setAccessible(true); - nextTickList = (Set) ntlField.get(blockTickListServer); + nextTickList.addAll((Set) ntlField.get(blockTickListServer)); } catch (IllegalAccessException | IllegalArgumentException | NoSuchFieldException | SecurityException e1) { e1.printStackTrace(); } From 938d2c9d200adabbda99477f262675a21b9f9a82 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Sun, 29 Dec 2019 22:00:50 +0100 Subject: [PATCH 100/304] Fixed WorldHandlers for 1.13 - 1.15 --- .../compat/v1_13_R2/IWorldHandler.java | 14 ++----------- .../compat/v1_14_R1/IWorldHandler.java | 20 ++++++------------- .../compat/v1_15_R1/IWorldHandler.java | 12 +++++++---- 3 files changed, 16 insertions(+), 30 deletions(-) diff --git a/modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/IWorldHandler.java b/modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/IWorldHandler.java index 0da9aa4d0..5863ee597 100644 --- a/modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/IWorldHandler.java +++ b/modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/IWorldHandler.java @@ -11,9 +11,8 @@ import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.Material; -import org.bukkit.craftbukkit.v1_13_R2.entity.CraftPlayer; import org.bukkit.craftbukkit.v1_13_R2.CraftWorld; -import org.bukkit.craftbukkit.v1_13_R2.block.CraftBlockState; +import org.bukkit.craftbukkit.v1_13_R2.entity.CraftPlayer; import org.bukkit.craftbukkit.v1_13_R2.util.CraftMagicNumbers; import org.bukkit.entity.Player; import org.bukkit.event.player.PlayerMoveEvent; @@ -214,16 +213,7 @@ public void translateCraft(@NotNull Craft craft, @NotNull MovecraftLocation disp } //******************************************* - //* Step six: Update the blocks * - //******************************************* - for(BlockPosition newPosition : newPositions) { - CraftBlockState.getBlockState(nativeWorld, newPosition, 3).update(false,false); - } - for(BlockPosition deletedPosition : deletePositions){ - CraftBlockState.getBlockState(nativeWorld, deletedPosition, 3).update(false,false); - } - //******************************************* - //* Step seven: Send to players * + //* Step six: Send to players * //******************************************* List chunks = new ArrayList<>(); for(BlockPosition position : newPositions){ diff --git a/modules/v1_14_R1/src/main/java/net/countercraft/movecraft/compat/v1_14_R1/IWorldHandler.java b/modules/v1_14_R1/src/main/java/net/countercraft/movecraft/compat/v1_14_R1/IWorldHandler.java index 0fd5e58db..4685d9533 100644 --- a/modules/v1_14_R1/src/main/java/net/countercraft/movecraft/compat/v1_14_R1/IWorldHandler.java +++ b/modules/v1_14_R1/src/main/java/net/countercraft/movecraft/compat/v1_14_R1/IWorldHandler.java @@ -12,7 +12,6 @@ import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.craftbukkit.v1_14_R1.CraftWorld; -import org.bukkit.craftbukkit.v1_14_R1.block.CraftBlockState; import org.bukkit.craftbukkit.v1_14_R1.entity.CraftPlayer; import org.bukkit.craftbukkit.v1_14_R1.util.CraftMagicNumbers; import org.bukkit.entity.Player; @@ -106,6 +105,7 @@ public void rotateCraft(@NotNull Craft craft, @NotNull MovecraftLocation originP final long currentTime = nativeWorld.worldData.getTime(); //nativeWorld.b(rotatedPositions.get(tileHolder.getNextTick().a), tileHolder.getNextTick().a(), (int) (tileHolder.getNextTick().b - currentTime), tileHolder.getNextTick().c); //BlockPosition, Object, int, TickListPriority + nativeWorld.getBlockTickList().a(rotatedPositions.get(tileHolder.getNextTick().a), tileHolder.getNextTick().b(), (int) (tileHolder.getNextTick().b - currentTime), tileHolder.getNextTick().c); nativeWorld.b(rotatedPositions.get(tileHolder.getNextTick().a), tileHolder.getTile()); } @@ -200,6 +200,7 @@ public void translateCraft(@NotNull Craft craft, @NotNull MovecraftLocation disp continue; final long currentTime = nativeWorld.worldData.getTime(); //nativeWorld.b(tileHolder.getNextTick().a.a(translateVector), tileHolder.getNextTick().a(), (int) (tileHolder.getNextTick().b - currentTime), tileHolder.getNextTick().c); + nativeWorld.getBlockTickList().a(tileHolder.getNextTick().a.a(translateVector), tileHolder.getNextTick().b(), (int) (tileHolder.getNextTick().b - currentTime)); nativeWorld.b(tileHolder.getNextTick().a.a(translateVector), tileHolder.getTile()); } //******************************************* @@ -211,16 +212,7 @@ public void translateCraft(@NotNull Craft craft, @NotNull MovecraftLocation disp } //******************************************* - //* Step six: Update the blocks * - //******************************************* - for(BlockPosition newPosition : newPositions) { - CraftBlockState.getBlockState(nativeWorld, newPosition, 3).update(false,false); - } - for(BlockPosition deletedPosition : deletePositions){ - CraftBlockState.getBlockState(nativeWorld, deletedPosition, 3).update(false,false); - } - //******************************************* - //* Step seven: Send to players * + //* Step six: Send to players * //******************************************* List chunks = new ArrayList<>(); for(BlockPosition position : newPositions){ @@ -346,10 +338,10 @@ private void moveTileEntity(@NotNull World nativeWorld, @NotNull BlockPosition n private class TileHolder{ @NotNull private final TileEntity tile; @Nullable - private final NextTickListEntry nextTick; + private final NextTickListEntry nextTick; @NotNull private final BlockPosition tilePosition; - public TileHolder(@NotNull TileEntity tile, @Nullable NextTickListEntry nextTick, @NotNull BlockPosition tilePosition){ + public TileHolder(@NotNull TileEntity tile, @Nullable NextTickListEntry nextTick, @NotNull BlockPosition tilePosition){ this.tile = tile; this.nextTick = nextTick; this.tilePosition = tilePosition; @@ -362,7 +354,7 @@ public TileEntity getTile() { } @Nullable - public NextTickListEntry getNextTick() { + public NextTickListEntry getNextTick() { return nextTick; } diff --git a/modules/v1_15_R1/src/main/java/net/countercraft/movecraft/compat/v1_15_R1/IWorldHandler.java b/modules/v1_15_R1/src/main/java/net/countercraft/movecraft/compat/v1_15_R1/IWorldHandler.java index b7d9e9846..bb050a33f 100644 --- a/modules/v1_15_R1/src/main/java/net/countercraft/movecraft/compat/v1_15_R1/IWorldHandler.java +++ b/modules/v1_15_R1/src/main/java/net/countercraft/movecraft/compat/v1_15_R1/IWorldHandler.java @@ -106,6 +106,7 @@ public void rotateCraft(@NotNull Craft craft, @NotNull MovecraftLocation originP final long currentTime = nativeWorld.worldData.getTime(); //nativeWorld.b(rotatedPositions.get(tileHolder.getNextTick().a), tileHolder.getNextTick().a(), (int) (tileHolder.getNextTick().b - currentTime), tileHolder.getNextTick().c); //BlockPosition, Object, int, TickListPriority + nativeWorld.getBlockTickList().a(rotatedPositions.get(tileHolder.getNextTick().a), tileHolder.getNextTick().b(), (int) (tileHolder.getNextTick().b - currentTime), tileHolder.getNextTick().c); nativeWorld.b(rotatedPositions.get(tileHolder.getNextTick().a), tileHolder.getTile()); } @@ -174,7 +175,6 @@ public void translateCraft(@NotNull Craft craft, @NotNull MovecraftLocation disp if(tile == null) continue; //get the nextTick to move with the tile - //nativeWorld.capturedTileEntities.remove(position); //nativeWorld.getChunkAtWorldCoords(position).getTileEntities().remove(position); tiles.add(new TileHolder(tile, tickProvider.getNextTick((WorldServer)nativeWorld,position), position)); @@ -212,6 +212,7 @@ public void translateCraft(@NotNull Craft craft, @NotNull MovecraftLocation disp continue; final long currentTime = nativeWorld.worldData.getTime(); //nativeWorld.b(tileHolder.getNextTick().a.a(translateVector), tileHolder.getNextTick().a(), (int) (tileHolder.getNextTick().b - currentTime), tileHolder.getNextTick().c); + nativeWorld.getBlockTickList().a(tileHolder.getNextTick().a.a(translateVector), tileHolder.getNextTick().b(), (int) (tileHolder.getNextTick().b - currentTime)); nativeWorld.b(tileHolder.getNextTick().a.a(translateVector), tileHolder.getTile()); } //******************************************* @@ -291,6 +292,9 @@ private BlockPosition locationToPosition(@NotNull MovecraftLocation loc) { private void setBlockFast(@NotNull World world, @NotNull BlockPosition position,@NotNull IBlockData data) { Chunk chunk = world.getChunkAtWorldCoords(position); + if (!chunk.loaded) { + chunk.setLoaded(true); + } ChunkSection chunkSection = chunk.getSections()[position.getY()>>4]; if (chunkSection == null) { // Put a GLASS block to initialize the section. It will be replaced next with the real block. @@ -349,10 +353,10 @@ private void moveTileEntity(@NotNull World nativeWorld, @NotNull BlockPosition n private class TileHolder{ @NotNull private final TileEntity tile; @Nullable - private final NextTickListEntry nextTick; + private final NextTickListEntry nextTick; @NotNull private final BlockPosition tilePosition; - public TileHolder(@NotNull TileEntity tile, @Nullable NextTickListEntry nextTick, @NotNull BlockPosition tilePosition){ + public TileHolder(@NotNull TileEntity tile, @Nullable NextTickListEntry nextTick, @NotNull BlockPosition tilePosition){ this.tile = tile; this.nextTick = nextTick; this.tilePosition = tilePosition; @@ -365,7 +369,7 @@ public TileEntity getTile() { } @Nullable - public NextTickListEntry getNextTick() { + public NextTickListEntry getNextTick() { return nextTick; } From a041502f600d675bc2d4412748c58e6404096e52 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Sat, 4 Jan 2020 12:49:28 +0100 Subject: [PATCH 101/304] Fixed the WorldHandlers --- .../movecraft/async/AsyncManager.java | 1 + .../update/CraftTranslateCommand.java | 3 ++- .../compat/v1_13_R2/IWorldHandler.java | 3 --- .../compat/v1_14_R1/IWorldHandler.java | 2 -- .../compat/v1_15_R1/IWorldHandler.java | 22 ++++--------------- 5 files changed, 7 insertions(+), 24 deletions(-) diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java index 3432dc977..b23e20e55 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java @@ -139,6 +139,7 @@ public void addWreck(Craft craft){ }*/ public void submitTask(AsyncTask task, Craft c) { + if (c.isNotProcessing()) { c.setProcessing(true); ownershipMap.put(task, c); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftTranslateCommand.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftTranslateCommand.java index ca42bb19e..9563f4e3a 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftTranslateCommand.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftTranslateCommand.java @@ -188,8 +188,9 @@ public void doUpdate() { } } } - if (!craft.isNotProcessing()) + if (!craft.isNotProcessing()) { craft.setProcessing(false); + } time = System.nanoTime() - time; if(Settings.Debug) logger.info("Total time: " + (time / 1e9) + " seconds. Moving with cooldown of " + craft.getTickCooldown() + ". Speed of: " + String.format("%.2f", craft.getSpeed())); diff --git a/modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/IWorldHandler.java b/modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/IWorldHandler.java index 5863ee597..da036fd6a 100644 --- a/modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/IWorldHandler.java +++ b/modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/IWorldHandler.java @@ -107,8 +107,6 @@ public void rotateCraft(@NotNull Craft craft, @NotNull MovecraftLocation originP continue; final long currentTime = nativeWorld.worldData.getTime(); nativeWorld.getBlockTickList().a(rotatedPositions.get(tileHolder.getNextTick().a), tileHolder.getNextTick().a(), (int) (tileHolder.getNextTick().b - currentTime), tileHolder.getNextTick().c); - //BlockPosition, Object, int, TickListPriority - nativeWorld.b(rotatedPositions.get(tileHolder.getNextTick().a), tileHolder.getTile()); } //******************************************* @@ -202,7 +200,6 @@ public void translateCraft(@NotNull Craft craft, @NotNull MovecraftLocation disp continue; final long currentTime = nativeWorld.worldData.getTime(); nativeWorld.getBlockTickList().a(tileHolder.getNextTick().a.a(translateVector), tileHolder.getNextTick().a(), (int) (tileHolder.getNextTick().b - currentTime), tileHolder.getNextTick().c); - nativeWorld.b(tileHolder.getNextTick().a.a(translateVector), tileHolder.getTile()); } //******************************************* //* Step five: Destroy the leftovers * diff --git a/modules/v1_14_R1/src/main/java/net/countercraft/movecraft/compat/v1_14_R1/IWorldHandler.java b/modules/v1_14_R1/src/main/java/net/countercraft/movecraft/compat/v1_14_R1/IWorldHandler.java index 4685d9533..bb115f2a3 100644 --- a/modules/v1_14_R1/src/main/java/net/countercraft/movecraft/compat/v1_14_R1/IWorldHandler.java +++ b/modules/v1_14_R1/src/main/java/net/countercraft/movecraft/compat/v1_14_R1/IWorldHandler.java @@ -106,7 +106,6 @@ public void rotateCraft(@NotNull Craft craft, @NotNull MovecraftLocation originP //nativeWorld.b(rotatedPositions.get(tileHolder.getNextTick().a), tileHolder.getNextTick().a(), (int) (tileHolder.getNextTick().b - currentTime), tileHolder.getNextTick().c); //BlockPosition, Object, int, TickListPriority nativeWorld.getBlockTickList().a(rotatedPositions.get(tileHolder.getNextTick().a), tileHolder.getNextTick().b(), (int) (tileHolder.getNextTick().b - currentTime), tileHolder.getNextTick().c); - nativeWorld.b(rotatedPositions.get(tileHolder.getNextTick().a), tileHolder.getTile()); } //******************************************* @@ -201,7 +200,6 @@ public void translateCraft(@NotNull Craft craft, @NotNull MovecraftLocation disp final long currentTime = nativeWorld.worldData.getTime(); //nativeWorld.b(tileHolder.getNextTick().a.a(translateVector), tileHolder.getNextTick().a(), (int) (tileHolder.getNextTick().b - currentTime), tileHolder.getNextTick().c); nativeWorld.getBlockTickList().a(tileHolder.getNextTick().a.a(translateVector), tileHolder.getNextTick().b(), (int) (tileHolder.getNextTick().b - currentTime)); - nativeWorld.b(tileHolder.getNextTick().a.a(translateVector), tileHolder.getTile()); } //******************************************* //* Step five: Destroy the leftovers * diff --git a/modules/v1_15_R1/src/main/java/net/countercraft/movecraft/compat/v1_15_R1/IWorldHandler.java b/modules/v1_15_R1/src/main/java/net/countercraft/movecraft/compat/v1_15_R1/IWorldHandler.java index bb050a33f..c845010c9 100644 --- a/modules/v1_15_R1/src/main/java/net/countercraft/movecraft/compat/v1_15_R1/IWorldHandler.java +++ b/modules/v1_15_R1/src/main/java/net/countercraft/movecraft/compat/v1_15_R1/IWorldHandler.java @@ -12,7 +12,6 @@ import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.craftbukkit.v1_15_R1.CraftWorld; -import org.bukkit.craftbukkit.v1_15_R1.block.CraftBlockState; import org.bukkit.craftbukkit.v1_15_R1.entity.CraftPlayer; import org.bukkit.craftbukkit.v1_15_R1.util.CraftMagicNumbers; import org.bukkit.entity.Player; @@ -107,7 +106,6 @@ public void rotateCraft(@NotNull Craft craft, @NotNull MovecraftLocation originP //nativeWorld.b(rotatedPositions.get(tileHolder.getNextTick().a), tileHolder.getNextTick().a(), (int) (tileHolder.getNextTick().b - currentTime), tileHolder.getNextTick().c); //BlockPosition, Object, int, TickListPriority nativeWorld.getBlockTickList().a(rotatedPositions.get(tileHolder.getNextTick().a), tileHolder.getNextTick().b(), (int) (tileHolder.getNextTick().b - currentTime), tileHolder.getNextTick().c); - nativeWorld.b(rotatedPositions.get(tileHolder.getNextTick().a), tileHolder.getTile()); } //******************************************* @@ -119,19 +117,9 @@ public void rotateCraft(@NotNull Craft craft, @NotNull MovecraftLocation originP setBlockFast(nativeWorld, position, Blocks.AIR.getBlockData()); } + //******************************************* - //* Step six: Update the blocks * - //******************************************* - for(BlockPosition newPosition : rotatedPositions.values()) { - // CraftBlockState.getBlockState(nativeWorld,newPosition.getX(), newPosition.getY(), newPosition.getZ()).update(false,false); - CraftBlockState.getBlockState(nativeWorld, newPosition, 3).update(false, false); - } - for(BlockPosition deletedPosition : deletePositions){ - // CraftBlockState.getBlockState(nativeWorld,deletedPosition.getX(), deletedPosition.getY(), deletedPosition.getZ()).update(false,false); - CraftBlockState.getBlockState(nativeWorld, deletedPosition, 3).update(false, false); - } - //******************************************* - //* Step seven: Send to players * + //* Step six: Send to players * //******************************************* List chunks = new ArrayList<>(); for(BlockPosition position : rotatedPositions.values()){ @@ -200,6 +188,7 @@ public void translateCraft(@NotNull Craft craft, @NotNull MovecraftLocation disp } //create the new block for(int i = 0; i>4]; if (chunkSection == null) { // Put a GLASS block to initialize the section. It will be replaced next with the real block. From 70cd9658e639b681b917e0e22f2afdc2c918503b Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Fri, 10 Jan 2020 18:38:51 +0100 Subject: [PATCH 102/304] Some small fixes --- .../movecraft/async/AsyncManager.java | 8 +-- .../async/translation/TranslationTask.java | 19 ++++--- .../update/ChunkLoadUpdateCommand.java | 51 +++++++++++++++++++ .../update/CraftTranslateCommand.java | 13 +++++ .../Movecraft/src/main/resources/plugin.yml | 2 +- .../movecraft/events/CraftCollisionEvent.java | 5 ++ .../compat/v1_15_R1/IWorldHandler.java | 25 +++++---- 7 files changed, 101 insertions(+), 22 deletions(-) create mode 100644 modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/ChunkLoadUpdateCommand.java diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java index b23e20e55..3cfb03c6a 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java @@ -139,7 +139,7 @@ public void addWreck(Craft craft){ }*/ public void submitTask(AsyncTask task, Craft c) { - + Bukkit.getLogger().info("Processing: " + !c.isNotProcessing()); if (c.isNotProcessing()) { c.setProcessing(true); ownershipMap.put(task, c); @@ -271,7 +271,7 @@ private void processAlgorithmQueue() { if (task.failed()) { // The craft translation failed - if (notifyP != null && !c.getSinking()) + if (notifyP != null && !c.getSinking() && task.getFailMessage() != null) notifyP.sendMessage(task.getFailMessage()); if (task.isCollisionExplosion()) { @@ -283,7 +283,9 @@ private void processAlgorithmQueue() { CraftManager.getInstance().addReleaseTask(c); } - } else { + } else if (task.areAllChunksLoaded()) { + + // The craft is clear to move, perform the block updates MapUpdateManager.getInstance().scheduleUpdates(task.getUpdates()); // get list of cannons before sending map updates, to avoid diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java index f0b30ff9e..25932d3f3 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java @@ -32,6 +32,7 @@ public class TranslationTask extends AsyncTask { private HashHitBox newHitBox, oldHitBox; private boolean failed; private boolean collisionExplosion = false; + private boolean allChunksLoaded = true; private String failMessage; private Collection updates = new HashSet<>(); @@ -248,10 +249,15 @@ public void run() { final List harvestedBlocks = new ArrayList<>(); final List harvesterBladeBlocks = craft.getType().getHarvesterBladeBlocks(); final HashHitBox collisionBox = new HashHitBox(); + final Set chunkUpdateCmds = new HashSet<>(); for(MovecraftLocation oldLocation : oldHitBox){ final MovecraftLocation newLocation = oldLocation.translate(dx,dy,dz); //If the new location already exists in the old hitbox than this is unnecessary because a craft can't hit //itself + final Chunk origChunk = oldLocation.toBukkit(craft.getW()).getChunk(); + if (!origChunk.isLoaded()) { + allChunksLoaded = false; + } if(oldHitBox.contains(newLocation)){ newHitBox.add(newLocation); continue; @@ -323,7 +329,6 @@ public void run() { this.fail(event.getFailMessage()); return; } - if(craft.getSinking()){ List air = new ArrayList<>(); for(MovecraftLocation location: oldHitBox){ @@ -397,13 +402,7 @@ public void run() { } if(!collisionBox.isEmpty()){ - new BukkitRunnable() { - @Override - public void run() { - Bukkit.getServer().getPluginManager().callEvent(new CraftCollisionEvent(craft, collisionBox)); - } - }.runTask(Movecraft.getInstance()); - + Bukkit.getServer().getPluginManager().callEvent(new CraftCollisionEvent(craft, collisionBox)); } if (oldHitBox.isEmpty()) return; @@ -653,4 +652,8 @@ public int getDz() { public boolean isCollisionExplosion() { return collisionExplosion; } + + public boolean areAllChunksLoaded() { + return allChunksLoaded; + } } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/ChunkLoadUpdateCommand.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/ChunkLoadUpdateCommand.java new file mode 100644 index 000000000..fcca390ca --- /dev/null +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/ChunkLoadUpdateCommand.java @@ -0,0 +1,51 @@ +package net.countercraft.movecraft.mapUpdater.update; + +import org.bukkit.Chunk; + +import java.util.Objects; + +public class ChunkLoadUpdateCommand extends UpdateCommand { + + private final Chunk chunk; + private final boolean forceLoaded; + private final boolean generate; + + public ChunkLoadUpdateCommand(Chunk chunk, boolean forceLoaded, boolean generate) { + this.chunk = chunk; + this.forceLoaded = forceLoaded; + this.generate = generate; + } + + @Override + public void doUpdate() { + chunk.setForceLoaded(forceLoaded); + chunk.load(generate); + } + + public boolean isForceLoaded() { + return forceLoaded; + } + + public boolean isGenerate() { + return generate; + } + + public Chunk getChunk() { + return chunk; + } + + @Override + public boolean equals(Object o) { + if (!(o instanceof ChunkLoadUpdateCommand)) + return false; + ChunkLoadUpdateCommand that = (ChunkLoadUpdateCommand) o; + return forceLoaded == that.forceLoaded && + generate == that.generate && + chunk.equals(that.chunk); + } + + @Override + public int hashCode() { + return Objects.hash(chunk, forceLoaded, generate); + } +} diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftTranslateCommand.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftTranslateCommand.java index 9563f4e3a..f1cd4f184 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftTranslateCommand.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftTranslateCommand.java @@ -9,6 +9,7 @@ import net.countercraft.movecraft.events.SignTranslateEvent; import net.countercraft.movecraft.utils.*; import org.bukkit.Bukkit; +import org.bukkit.Chunk; import org.bukkit.Material; import org.bukkit.block.Block; import org.bukkit.block.Sign; @@ -72,6 +73,14 @@ public void doUpdate() { } } + for (MovecraftLocation ml : craft.getHitBox()) { + Chunk c = ml.toBukkit(craft.getW()).getChunk(); + if (c.isLoaded()) { + continue; + } + c.addPluginChunkTicket(Movecraft.getInstance()); + c.load(true); + } if(passthroughBlocks.isEmpty()){ //translate the craft Movecraft.getInstance().getWorldHandler().translateCraft(craft,displacement); @@ -188,6 +197,10 @@ public void doUpdate() { } } } + for (MovecraftLocation ml : craft.getHitBox()) { + ml.subtract(displacement).toBukkit(craft.getW()).getChunk().removePluginChunkTicket(Movecraft.getInstance()); + } + if (!craft.isNotProcessing()) { craft.setProcessing(false); } diff --git a/modules/Movecraft/src/main/resources/plugin.yml b/modules/Movecraft/src/main/resources/plugin.yml index bf887e0e5..5892fd893 100644 --- a/modules/Movecraft/src/main/resources/plugin.yml +++ b/modules/Movecraft/src/main/resources/plugin.yml @@ -4,7 +4,7 @@ version: ${project.version} api-version: 1.13 #version: ${env.BUILD_NUMBER} description: The original flight and movement plugin for minecraft. -authors: [BaccaYarro, cccm5] +authors: [BaccaYarro, cccm5, eirikh1996] website: http://www.youtube.com/BaccaYarro main: net.countercraft.movecraft.Movecraft database: false diff --git a/modules/api/src/main/java/net/countercraft/movecraft/events/CraftCollisionEvent.java b/modules/api/src/main/java/net/countercraft/movecraft/events/CraftCollisionEvent.java index e232481d5..5617db36b 100644 --- a/modules/api/src/main/java/net/countercraft/movecraft/events/CraftCollisionEvent.java +++ b/modules/api/src/main/java/net/countercraft/movecraft/events/CraftCollisionEvent.java @@ -15,6 +15,11 @@ public CraftCollisionEvent(@NotNull Craft craft, @NotNull HashHitBox hitBox) { this.hitBox = hitBox; } + public CraftCollisionEvent(@NotNull Craft craft, @NotNull HashHitBox hitBox, boolean isAsync) { + super(craft, isAsync); + this.hitBox = hitBox; + } + @NotNull public HashHitBox getHitBox() { return hitBox; diff --git a/modules/v1_15_R1/src/main/java/net/countercraft/movecraft/compat/v1_15_R1/IWorldHandler.java b/modules/v1_15_R1/src/main/java/net/countercraft/movecraft/compat/v1_15_R1/IWorldHandler.java index c845010c9..06775ea69 100644 --- a/modules/v1_15_R1/src/main/java/net/countercraft/movecraft/compat/v1_15_R1/IWorldHandler.java +++ b/modules/v1_15_R1/src/main/java/net/countercraft/movecraft/compat/v1_15_R1/IWorldHandler.java @@ -63,7 +63,7 @@ public void rotateCraft(@NotNull Craft craft, @NotNull MovecraftLocation originP //******************************************* //* Step two: Get the tiles * //******************************************* - World nativeWorld = ((CraftWorld) craft.getW()).getHandle(); + WorldServer nativeWorld = ((CraftWorld) craft.getW()).getHandle(); List tiles = new ArrayList<>(); //get the tiles for(BlockPosition position : rotatedPositions.keySet()){ @@ -145,27 +145,28 @@ public void translateCraft(@NotNull Craft craft, @NotNull MovecraftLocation disp //******************************************* BlockPosition translateVector = locationToPosition(displacement); List positions = new ArrayList<>(); + WorldServer nativeWorld = ((CraftWorld) craft.getW()).getHandle(); for(MovecraftLocation movecraftLocation : craft.getHitBox()) { - positions.add(locationToPosition((movecraftLocation)).b(translateVector)); + BlockPosition origPos = locationToPosition((movecraftLocation)).b(translateVector); + positions.add(origPos); } + //******************************************* //* Step two: Get the tiles * //******************************************* - World nativeWorld = ((CraftWorld) craft.getW()).getHandle(); + List tiles = new ArrayList<>(); //get the tiles for(BlockPosition position : positions){ + nativeWorld.setForceLoaded(position.getX() >> 4, position.getZ() >> 4, true); if(nativeWorld.getType(position) == Blocks.AIR.getBlockData()) continue; - //TileEntity tile = nativeWorld.removeTileEntity(position); TileEntity tile = removeTileEntity(nativeWorld,position); if(tile == null) continue; //get the nextTick to move with the tile - //nativeWorld.capturedTileEntities.remove(position); - //nativeWorld.getChunkAtWorldCoords(position).getTileEntities().remove(position); - tiles.add(new TileHolder(tile, tickProvider.getNextTick((WorldServer)nativeWorld,position), position)); + tiles.add(new TileHolder(tile, tickProvider.getNextTick(nativeWorld, position), position)); } //******************************************* @@ -188,7 +189,6 @@ public void translateCraft(@NotNull Craft craft, @NotNull MovecraftLocation disp } //create the new block for(int i = 0; i deletePositions = CollectionUtils.filter(positions,newPositions); for(BlockPosition position : deletePositions){ + nativeWorld.setForceLoaded(position.getX() >> 4, position.getZ() >> 4, false); setBlockFast(nativeWorld, position, Blocks.AIR.getBlockData()); } @@ -219,6 +220,7 @@ public void translateCraft(@NotNull Craft craft, @NotNull MovecraftLocation disp List chunks = new ArrayList<>(); for(BlockPosition position : newPositions){ Chunk chunk = nativeWorld.getChunkAtWorldCoords(position); + if(!chunks.contains(chunk)){ chunks.add(chunk); } @@ -279,9 +281,12 @@ private BlockPosition locationToPosition(@NotNull MovecraftLocation loc) { return new BlockPosition(loc.getX(), loc.getY(), loc.getZ()); } - private void setBlockFast(@NotNull World world, @NotNull BlockPosition position,@NotNull IBlockData data) { + private void setBlockFast(@NotNull WorldServer world, @NotNull BlockPosition position,@NotNull IBlockData data) { Chunk chunk = world.getChunkAtWorldCoords(position); ChunkSection chunkSection = chunk.getSections()[position.getY()>>4]; + if (!chunk.loaded) { + + } if (chunkSection == null) { // Put a GLASS block to initialize the section. It will be replaced next with the real block. chunk.setType(position, Blocks.GLASS.getBlockData(), true); @@ -301,7 +306,7 @@ public void setBlockFast(@NotNull Location location, @NotNull Material material, public void setBlockFast(@NotNull Location location, @NotNull Rotation rotation, @NotNull Material material, byte data) { IBlockData blockData = CraftMagicNumbers.getBlock(material).getBlockData(); blockData = blockData.a(ROTATION[rotation.ordinal()]); - World world = ((CraftWorld)(location.getWorld())).getHandle(); + WorldServer world = ((CraftWorld)(location.getWorld())).getHandle(); BlockPosition blockPosition = locationToPosition(bukkit2MovecraftLoc(location)); setBlockFast(world,blockPosition,blockData); } From beb0dde6ed2c174cbc24f9992a02ffb92fdec08f Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Mon, 13 Jan 2020 20:48:55 +0100 Subject: [PATCH 103/304] Some small fixes --- .../movecraft/async/AsyncManager.java | 6 ++-- .../async/translation/TranslationTask.java | 14 +++----- .../countercraft/movecraft/craft/ICraft.java | 33 ------------------- 3 files changed, 9 insertions(+), 44 deletions(-) diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java index 3cfb03c6a..9e9f404b3 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java @@ -139,7 +139,9 @@ public void addWreck(Craft craft){ }*/ public void submitTask(AsyncTask task, Craft c) { - Bukkit.getLogger().info("Processing: " + !c.isNotProcessing()); + if (!c.getHitBox().isEmpty()) { + Bukkit.getLogger().info("Is not processing: " + c.isNotProcessing() + ", Center point: " + c.getHitBox().getMidPoint()); + } if (c.isNotProcessing()) { c.setProcessing(true); ownershipMap.put(task, c); @@ -283,7 +285,7 @@ private void processAlgorithmQueue() { CraftManager.getInstance().addReleaseTask(c); } - } else if (task.areAllChunksLoaded()) { + } else { // The craft is clear to move, perform the block updates diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java index 25932d3f3..7825e2400 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java @@ -32,7 +32,6 @@ public class TranslationTask extends AsyncTask { private HashHitBox newHitBox, oldHitBox; private boolean failed; private boolean collisionExplosion = false; - private boolean allChunksLoaded = true; private String failMessage; private Collection updates = new HashSet<>(); @@ -250,18 +249,18 @@ public void run() { final List harvesterBladeBlocks = craft.getType().getHarvesterBladeBlocks(); final HashHitBox collisionBox = new HashHitBox(); final Set chunkUpdateCmds = new HashSet<>(); + boolean structureIntact = true; for(MovecraftLocation oldLocation : oldHitBox){ final MovecraftLocation newLocation = oldLocation.translate(dx,dy,dz); //If the new location already exists in the old hitbox than this is unnecessary because a craft can't hit //itself - final Chunk origChunk = oldLocation.toBukkit(craft.getW()).getChunk(); - if (!origChunk.isLoaded()) { - allChunksLoaded = false; - } if(oldHitBox.contains(newLocation)){ newHitBox.add(newLocation); continue; } + if (oldLocation.toBukkit(craft.getW()).getBlock().getType().name().endsWith("AIR")) { + structureIntact = false; + } final Block b = newLocation.toBukkit(craft.getW()).getBlock(); final Material testMaterial = b.getType(); @@ -310,6 +309,7 @@ public void run() { } } //END OF: if (blockObstructed) } + Bukkit.getLogger().info("Structure intact: " + structureIntact); if (craft.getType().getForbiddenHoverOverBlocks().size() > 0){ MovecraftLocation test = new MovecraftLocation(newHitBox.getMidPoint().getX(), newHitBox.getMinY(), newHitBox.getMidPoint().getZ()); @@ -652,8 +652,4 @@ public int getDz() { public boolean isCollisionExplosion() { return collisionExplosion; } - - public boolean areAllChunksLoaded() { - return allChunksLoaded; - } } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/ICraft.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/ICraft.java index a964501aa..cb97c610b 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/ICraft.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/ICraft.java @@ -52,39 +52,6 @@ public void translate(int dx, int dy, int dz) { } } - // find region that will need to be loaded to translate this craft - /*int cminX = minX; - int cmaxX = minX; - if (dx < 0) - cminX = cminX + dx; - int cminZ = minZ; - int cmaxZ = minZ; - if (dz < 0) - cminZ = cminZ + dz; - for (MovecraftLocation m : blockList) { - if (m.getX() > cmaxX) - cmaxX = m.getX(); - if (m.getZ() > cmaxZ) - cmaxZ = m.getZ(); - } - if (dx > 0) - cmaxX = cmaxX + dx; - if (dz > 0) - cmaxZ = cmaxZ + dz; - cminX = cminX >> 4; - cminZ = cminZ >> 4; - cmaxX = cmaxX >> 4; - cmaxZ = cmaxZ >> 4; - - - // load all chunks that will be needed to translate this craft - for (int posX = cminX - 1; posX <= cmaxX + 1; posX++) { - for (int posZ = cminZ - 1; posZ <= cmaxZ + 1; posZ++) { - if (!this.getW().isChunkLoaded(posX, posZ)) { - this.getW().loadChunk(posX, posZ); - } - } - }*/ Movecraft.getInstance().getAsyncManager().submitTask(new TranslationTask(this, dx, dy, dz), this); } From 08686c6e5393b51a51ba1413bde6198f16eaed99 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Mon, 13 Jan 2020 23:29:16 +0100 Subject: [PATCH 104/304] Fixed that crafts may occasionally beaver and/or vanish, fixes #26 --- .../net/countercraft/movecraft/async/AsyncManager.java | 1 + .../movecraft/async/translation/TranslationTask.java | 3 +++ .../java/net/countercraft/movecraft/craft/ICraft.java | 3 +++ .../mapUpdater/update/CraftTranslateCommand.java | 6 +++--- .../java/net/countercraft/movecraft/craft/Craft.java | 9 +++++++++ 5 files changed, 19 insertions(+), 3 deletions(-) diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java index 9e9f404b3..6cc527338 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java @@ -139,6 +139,7 @@ public void addWreck(Craft craft){ }*/ public void submitTask(AsyncTask task, Craft c) { + if (!c.getHitBox().isEmpty()) { Bukkit.getLogger().info("Is not processing: " + c.isNotProcessing() + ", Center point: " + c.getHitBox().getMidPoint()); } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java index 7825e2400..0f9118ada 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java @@ -441,6 +441,9 @@ private void fail(String message) { //craft.setCurTickCooldown(craft.getType().getCruiseTickCooldown()); } } + if (craft.isTranslating()) { + craft.setTranslating(false); + } } private static final MovecraftLocation[] SHIFTS = { diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/ICraft.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/ICraft.java index cb97c610b..596b17d0a 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/ICraft.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/ICraft.java @@ -51,6 +51,9 @@ public void translate(int dx, int dy, int dz) { return; } } + if (isTranslating()) + return; + setTranslating(true); Movecraft.getInstance().getAsyncManager().submitTask(new TranslationTask(this, dx, dy, dz), this); } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftTranslateCommand.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftTranslateCommand.java index f1cd4f184..842c26680 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftTranslateCommand.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftTranslateCommand.java @@ -197,13 +197,13 @@ public void doUpdate() { } } } - for (MovecraftLocation ml : craft.getHitBox()) { - ml.subtract(displacement).toBukkit(craft.getW()).getChunk().removePluginChunkTicket(Movecraft.getInstance()); - } if (!craft.isNotProcessing()) { craft.setProcessing(false); } + if (craft.isTranslating()) { + craft.setTranslating(false); + } time = System.nanoTime() - time; if(Settings.Debug) logger.info("Total time: " + (time / 1e9) + " seconds. Moving with cooldown of " + craft.getTickCooldown() + ". Speed of: " + String.format("%.2f", craft.getSpeed())); diff --git a/modules/api/src/main/java/net/countercraft/movecraft/craft/Craft.java b/modules/api/src/main/java/net/countercraft/movecraft/craft/Craft.java index efd3f6e61..e9dc1e51c 100644 --- a/modules/api/src/main/java/net/countercraft/movecraft/craft/Craft.java +++ b/modules/api/src/main/java/net/countercraft/movecraft/craft/Craft.java @@ -52,6 +52,7 @@ public abstract class Craft { @NotNull private final AtomicBoolean processing = new AtomicBoolean(); private int maxHeightLimit; private boolean cruising; + private boolean translating = false; private boolean sinking; private boolean disabled; private boolean repairing; @@ -308,6 +309,14 @@ public float getMeanMoveTime() { return meanMoveTime; } + public boolean isTranslating() { + return translating; + } + + public void setTranslating(boolean translating) { + this.translating = translating; + } + public void addMoveTime(float moveTime){ meanMoveTime = (meanMoveTime*numMoves + moveTime)/(++numMoves); } From cf940fb1c1b0ef06474ee64be0d7e5162a7161ce Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Mon, 13 Jan 2020 23:33:50 +0100 Subject: [PATCH 105/304] Removed redundant chunk loading code as vanishing bug was not caused by this --- .../mapUpdater/update/CraftTranslateCommand.java | 9 --------- 1 file changed, 9 deletions(-) diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftTranslateCommand.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftTranslateCommand.java index 842c26680..c67b7e4ce 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftTranslateCommand.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftTranslateCommand.java @@ -9,7 +9,6 @@ import net.countercraft.movecraft.events.SignTranslateEvent; import net.countercraft.movecraft.utils.*; import org.bukkit.Bukkit; -import org.bukkit.Chunk; import org.bukkit.Material; import org.bukkit.block.Block; import org.bukkit.block.Sign; @@ -73,14 +72,6 @@ public void doUpdate() { } } - for (MovecraftLocation ml : craft.getHitBox()) { - Chunk c = ml.toBukkit(craft.getW()).getChunk(); - if (c.isLoaded()) { - continue; - } - c.addPluginChunkTicket(Movecraft.getInstance()); - c.load(true); - } if(passthroughBlocks.isEmpty()){ //translate the craft Movecraft.getInstance().getWorldHandler().translateCraft(craft,displacement); From 0eb991827a1f25435ef550a1badd0440d031c721 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Tue, 14 Jan 2020 21:02:26 +0100 Subject: [PATCH 106/304] Removed debug messages for craft vanishing and fixed #21 --- .../movecraft/async/AsyncManager.java | 4 -- .../async/translation/TranslationTask.java | 8 +--- .../compat/v1_13_R2/IWorldHandler.java | 35 ++++++++++++-- .../compat/v1_14_R1/IWorldHandler.java | 33 ++++++++++++- .../compat/v1_15_R1/IWorldHandler.java | 46 +++++++++++++------ 5 files changed, 97 insertions(+), 29 deletions(-) diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java index 6cc527338..43c65eb16 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java @@ -139,10 +139,6 @@ public void addWreck(Craft craft){ }*/ public void submitTask(AsyncTask task, Craft c) { - - if (!c.getHitBox().isEmpty()) { - Bukkit.getLogger().info("Is not processing: " + c.isNotProcessing() + ", Center point: " + c.getHitBox().getMidPoint()); - } if (c.isNotProcessing()) { c.setProcessing(true); ownershipMap.put(task, c); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java index 0f9118ada..3cd032e16 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java @@ -33,7 +33,7 @@ public class TranslationTask extends AsyncTask { private boolean failed; private boolean collisionExplosion = false; private String failMessage; - private Collection updates = new HashSet<>(); + private Collection updates = new LinkedList<>(); public TranslationTask(Craft c, int dx, int dy, int dz) { super(c); @@ -258,9 +258,6 @@ public void run() { newHitBox.add(newLocation); continue; } - if (oldLocation.toBukkit(craft.getW()).getBlock().getType().name().endsWith("AIR")) { - structureIntact = false; - } final Block b = newLocation.toBukkit(craft.getW()).getBlock(); final Material testMaterial = b.getType(); @@ -309,7 +306,6 @@ public void run() { } } //END OF: if (blockObstructed) } - Bukkit.getLogger().info("Structure intact: " + structureIntact); if (craft.getType().getForbiddenHoverOverBlocks().size() > 0){ MovecraftLocation test = new MovecraftLocation(newHitBox.getMidPoint().getX(), newHitBox.getMinY(), newHitBox.getMidPoint().getZ()); @@ -402,7 +398,7 @@ public void run() { } if(!collisionBox.isEmpty()){ - Bukkit.getServer().getPluginManager().callEvent(new CraftCollisionEvent(craft, collisionBox)); + Bukkit.getServer().getPluginManager().callEvent(new CraftCollisionEvent(craft, collisionBox, true)); } if (oldHitBox.isEmpty()) return; diff --git a/modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/IWorldHandler.java b/modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/IWorldHandler.java index da036fd6a..d86969a85 100644 --- a/modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/IWorldHandler.java +++ b/modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/IWorldHandler.java @@ -186,9 +186,16 @@ public void translateCraft(@NotNull Craft craft, @NotNull MovecraftLocation disp for(BlockPosition position : positions){ newPositions.add(position.a(translateVector)); } + Map redstoneComponents = new HashMap<>(); //create the new block for(int i = 0; i>4]; if (chunkSection == null) { @@ -285,10 +300,11 @@ private void setBlockFast(@NotNull World world, @NotNull BlockPosition position, chunkSection = chunk.getSections()[position.getY() >> 4]; } - - - chunkSection.setType(position.getX()&15, position.getY()&15, position.getZ()&15, data); + if (physics) { + world.notifyAndUpdatePhysics(position, chunk, data, data, data, 3); + return; + } world.notify(position, data, data, 3); } @@ -338,6 +354,17 @@ private void moveTileEntity(@NotNull World nativeWorld, @NotNull BlockPosition n chunk.tileEntities.put(newPosition, tile); } + private boolean isRedstoneComponent(IBlockData blockData) { + final Block block = blockData.getBlock(); + return block instanceof BlockRedstoneComparator || + block instanceof BlockRedstoneWire || + block instanceof BlockRepeater || + block instanceof BlockButtonAbstract || + block instanceof BlockLever || + block instanceof BlockDispenser; + + } + private class TileHolder{ @NotNull private final TileEntity tile; @Nullable diff --git a/modules/v1_14_R1/src/main/java/net/countercraft/movecraft/compat/v1_14_R1/IWorldHandler.java b/modules/v1_14_R1/src/main/java/net/countercraft/movecraft/compat/v1_14_R1/IWorldHandler.java index bb115f2a3..ac6dde694 100644 --- a/modules/v1_14_R1/src/main/java/net/countercraft/movecraft/compat/v1_14_R1/IWorldHandler.java +++ b/modules/v1_14_R1/src/main/java/net/countercraft/movecraft/compat/v1_14_R1/IWorldHandler.java @@ -185,9 +185,16 @@ public void translateCraft(@NotNull Craft craft, @NotNull MovecraftLocation disp for(BlockPosition position : positions){ newPositions.add(position.a(translateVector)); } + Map redstoneComponents = new HashMap<>(); //create the new block for(int i = 0; i>4]; if (chunkSection == null) { @@ -285,6 +301,10 @@ private void setBlockFast(@NotNull World world, @NotNull BlockPosition position, } chunkSection.setType(position.getX()&15, position.getY()&15, position.getZ()&15, data); + if (physics) { + world.notifyAndUpdatePhysics(position, chunk, data, data, data, 3); + return; + } world.notify(position, data, data, 3); } @@ -333,6 +353,17 @@ private void moveTileEntity(@NotNull World nativeWorld, @NotNull BlockPosition n chunk.tileEntities.put(newPosition, tile); } + private boolean isRedstoneComponent(IBlockData blockData) { + final Block block = blockData.getBlock(); + return block instanceof BlockRedstoneComparator || + block instanceof BlockRedstoneWire || + block instanceof BlockRepeater || + block instanceof BlockButtonAbstract || + block instanceof BlockLever || + block instanceof BlockDispenser; + + } + private class TileHolder{ @NotNull private final TileEntity tile; @Nullable diff --git a/modules/v1_15_R1/src/main/java/net/countercraft/movecraft/compat/v1_15_R1/IWorldHandler.java b/modules/v1_15_R1/src/main/java/net/countercraft/movecraft/compat/v1_15_R1/IWorldHandler.java index 06775ea69..3fb50a8d8 100644 --- a/modules/v1_15_R1/src/main/java/net/countercraft/movecraft/compat/v1_15_R1/IWorldHandler.java +++ b/modules/v1_15_R1/src/main/java/net/countercraft/movecraft/compat/v1_15_R1/IWorldHandler.java @@ -32,6 +32,7 @@ public class IWorldHandler extends WorldHandler { ROTATION[Rotation.NONE.ordinal()] = EnumBlockRotation.NONE; ROTATION[Rotation.CLOCKWISE.ordinal()] = EnumBlockRotation.CLOCKWISE_90; ROTATION[Rotation.ANTICLOCKWISE.ordinal()] = EnumBlockRotation.COUNTERCLOCKWISE_90; + } private final NextTickProvider tickProvider = new NextTickProvider(); private final HashMap> bMap = new HashMap<>(); @@ -187,10 +188,18 @@ public void translateCraft(@NotNull Craft craft, @NotNull MovecraftLocation disp BlockPosition newPos = position.a(translateVector); newPositions.add(newPos); } + Map redstoneComponents = new HashMap<>(); //create the new block for(int i = 0; i>4]; - if (!chunk.loaded) { - - } if (chunkSection == null) { // Put a GLASS block to initialize the section. It will be replaced next with the real block. chunk.setType(position, Blocks.GLASS.getBlockData(), true); @@ -294,6 +306,10 @@ private void setBlockFast(@NotNull WorldServer world, @NotNull BlockPosition pos } chunkSection.setType(position.getX()&15, position.getY()&15, position.getZ()&15, data); + if (physics) { + world.notifyAndUpdatePhysics(position, chunk, data, data, data, 3); + return; + } world.notify(position, data, data, 3); } @@ -308,7 +324,7 @@ public void setBlockFast(@NotNull Location location, @NotNull Rotation rotation, blockData = blockData.a(ROTATION[rotation.ordinal()]); WorldServer world = ((CraftWorld)(location.getWorld())).getHandle(); BlockPosition blockPosition = locationToPosition(bukkit2MovecraftLoc(location)); - setBlockFast(world,blockPosition,blockData); + setBlockFast(world,blockPosition,blockData, false); } @Override @@ -370,12 +386,14 @@ public BlockPosition getTilePosition() { } } - private boolean isRedstoneComponent(Block block) { - return block instanceof BlockRedstoneWire - || block instanceof BlockRedstoneComparator - || block instanceof BlockRepeater - || block instanceof BlockRedstoneTorch - || block instanceof BlockLever; + private boolean isRedstoneComponent(IBlockData blockData) { + final Block block = blockData.getBlock(); + return block instanceof BlockRedstoneComparator || + block instanceof BlockRedstoneWire || + block instanceof BlockRepeater || + block instanceof BlockButtonAbstract || + block instanceof BlockLever || + block instanceof BlockDispenser; } } From 82f86d8a5473bcb7374007ee0069a12ffca360e0 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Fri, 17 Jan 2020 01:51:04 +0100 Subject: [PATCH 107/304] Improved entity movement --- .../async/rotation/RotationTask.java | 2 - .../async/translation/TranslationTask.java | 1 - .../mapUpdater/update/CraftRotateCommand.java | 26 +++- .../update/CraftTranslateCommand.java | 21 +++- .../update/EntityRotateUpdateCommand.java | 72 ----------- .../update/EntityTranslateUpdateCommand.java | 116 ------------------ .../update/EntityUpdateCommand.java | 86 +++++++++++++ 7 files changed, 131 insertions(+), 193 deletions(-) delete mode 100644 modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/EntityRotateUpdateCommand.java delete mode 100644 modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/EntityTranslateUpdateCommand.java create mode 100644 modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/EntityUpdateCommand.java diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/rotation/RotationTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/rotation/RotationTask.java index 6d3611e31..c62db3577 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/rotation/RotationTask.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/rotation/RotationTask.java @@ -35,7 +35,6 @@ import net.countercraft.movecraft.events.CraftRotateEvent; import net.countercraft.movecraft.localisation.I18nSupport; import net.countercraft.movecraft.mapUpdater.update.CraftRotateCommand; -import net.countercraft.movecraft.mapUpdater.update.EntityRotateUpdateCommand; import net.countercraft.movecraft.mapUpdater.update.UpdateCommand; import net.countercraft.movecraft.utils.*; import org.bukkit.Bukkit; @@ -212,7 +211,6 @@ public void run() { updates.add(new CraftRotateCommand(getCraft(),originPoint, rotation)); - updates.add(new EntityRotateUpdateCommand(craft, oldHitBox, rotation, originPoint)); if (getCraft().getCruising()) { diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java index 3cd032e16..6e9253510 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java @@ -408,7 +408,6 @@ public void run() { CraftManager.getInstance().addReleaseTask(craft); } updates.add(new CraftTranslateCommand(craft, new MovecraftLocation(dx, dy, dz))); - updates.add(new EntityTranslateUpdateCommand(craft, oldHitBox, dx, dy, dz)); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftRotateCommand.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftRotateCommand.java index bcacfd737..1c06769d4 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftRotateCommand.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftRotateCommand.java @@ -8,11 +8,15 @@ import net.countercraft.movecraft.craft.Craft; import net.countercraft.movecraft.craft.CraftManager; import net.countercraft.movecraft.events.SignTranslateEvent; +import net.countercraft.movecraft.mapUpdater.MapUpdateManager; import net.countercraft.movecraft.utils.*; import org.bukkit.Bukkit; +import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.block.Block; import org.bukkit.block.Sign; +import org.bukkit.entity.Entity; +import org.bukkit.entity.EntityType; import org.jetbrains.annotations.NotNull; import java.util.*; @@ -44,6 +48,7 @@ public void doUpdate() { } long time = System.nanoTime(); final Set passthroughBlocks = new HashSet<>(craft.getType().getPassthroughBlocks()); + final Set toRotate = new HashSet<>(); if(craft.getSinking()){ passthroughBlocks.add(Material.WATER); @@ -70,6 +75,25 @@ public void doUpdate() { passthroughBlocks.add(Material.PEONY); } + } else if (craft.getType().getMoveEntities()) { + Location tOP = new Location(craft.getW(), originLocation.getX(), originLocation.getY(), originLocation.getZ()); + tOP.setX(tOP.getBlockX() + 0.5); + tOP.setZ(tOP.getBlockZ() + 0.5); + Location midpoint = craft.getHitBox().getMidPoint().toBukkit(craft.getW()); + for(Entity entity : craft.getW().getNearbyEntities(midpoint, craft.getHitBox().getZLength()/2.0 + 1, craft.getHitBox().getYLength()/2.0 + 2, craft.getHitBox().getXLength()/2.0 + 1)){ + + // Player is onboard this craft + + Location adjustedPLoc = entity.getLocation().subtract(tOP); + + double[] rotatedCoords = MathUtils.rotateVecNoRound(rotation, adjustedPLoc.getX(), adjustedPLoc.getZ()); + float newYaw = rotation == Rotation.CLOCKWISE ? 90F : -90F; + if ((entity.getType() != EntityType.PLAYER && craft.getType().getOnlyMovePlayers()) || craft.getSinking()) { + continue; + } + EntityUpdateCommand eUp = new EntityUpdateCommand(entity, rotatedCoords[0] + tOP.getX() - entity.getLocation().getX(), 0, rotatedCoords[1] + tOP.getZ() - entity.getLocation().getZ(), newYaw, 0); + toRotate.add(eUp); + } } if (!passthroughBlocks.isEmpty()) { MutableHitBox originalLocations = new HashHitBox(); @@ -181,7 +205,7 @@ public void doUpdate() { //trigger sign events sendSignEvents(); } - + MapUpdateManager.getInstance().scheduleUpdates(toRotate); if (!craft.isNotProcessing()) craft.setProcessing(false); time = System.nanoTime() - time; diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftTranslateCommand.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftTranslateCommand.java index c67b7e4ce..c432cf387 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftTranslateCommand.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftTranslateCommand.java @@ -7,11 +7,15 @@ import net.countercraft.movecraft.craft.Craft; import net.countercraft.movecraft.craft.CraftManager; import net.countercraft.movecraft.events.SignTranslateEvent; +import net.countercraft.movecraft.mapUpdater.MapUpdateManager; import net.countercraft.movecraft.utils.*; import org.bukkit.Bukkit; +import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.block.Block; import org.bukkit.block.Sign; +import org.bukkit.entity.Entity; +import org.bukkit.entity.EntityType; import org.jetbrains.annotations.NotNull; import java.util.*; @@ -39,6 +43,7 @@ public void doUpdate() { } long time = System.nanoTime(); final Set passthroughBlocks = new HashSet<>(craft.getType().getPassthroughBlocks()); + final Set toMove = new HashSet<>(); if(craft.getSinking()){ passthroughBlocks.add(Material.WATER);//Same in the 1.13 API, but other values are different if (Settings.IsLegacy){ //use pre-1.13 values if running on 1.12.2 or lower @@ -71,6 +76,20 @@ public void doUpdate() { passthroughBlocks.add(Material.BUBBLE_COLUMN); } + } else if (craft.getType().getMoveEntities()){ + final Location midpoint = craft.getHitBox().getMidPoint().subtract(displacement).toBukkit(craft.getW()); + final Collection entities = craft.getW().getNearbyEntities(midpoint, craft.getHitBox().getXLength() / 2.0 + 1, craft.getHitBox().getYLength() / 2.0 + 2, craft.getHitBox().getZLength() / 2.0 + 1); + + for (Entity entity : entities){ + if (entity.getType() == EntityType.PLAYER) { + if(craft.getSinking()){ + continue; + } + toMove.add(new EntityUpdateCommand(entity, displacement.getX(), displacement.getY(), displacement.getZ(), 0, 0)); + } else if (!craft.getType().getOnlyMovePlayers() || entity.getType() == EntityType.PRIMED_TNT) { + toMove.add(new EntityUpdateCommand(entity, displacement.getX(), displacement.getY(), displacement.getZ(), 0, 0)); + } + } } if(passthroughBlocks.isEmpty()){ //translate the craft @@ -188,7 +207,7 @@ public void doUpdate() { } } } - + MapUpdateManager.getInstance().scheduleUpdates(toMove); if (!craft.isNotProcessing()) { craft.setProcessing(false); } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/EntityRotateUpdateCommand.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/EntityRotateUpdateCommand.java deleted file mode 100644 index 57fbbb5c5..000000000 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/EntityRotateUpdateCommand.java +++ /dev/null @@ -1,72 +0,0 @@ -package net.countercraft.movecraft.mapUpdater.update; - -import net.countercraft.movecraft.MovecraftLocation; -import net.countercraft.movecraft.Rotation; -import net.countercraft.movecraft.craft.Craft; -import net.countercraft.movecraft.utils.HitBox; -import net.countercraft.movecraft.utils.MathUtils; -import org.bukkit.Location; -import org.bukkit.entity.Entity; -import org.bukkit.entity.EntityType; - -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; - -public class EntityRotateUpdateCommand extends UpdateCommand { - - private final Craft craft; - private final HitBox oldHitBox; - private final Rotation rotation; - private final MovecraftLocation originPoint; - - public EntityRotateUpdateCommand(Craft craft, HitBox oldHitBox, Rotation rotation, MovecraftLocation originPoint) { - this.craft = craft; - this.oldHitBox = oldHitBox; - this.rotation = rotation; - this.originPoint = originPoint; - } - - - @Override - public void doUpdate() { - final Map entities = getEntitiesOnCraft(); - for (Entity entity : entities.keySet()){ - final Location tp = entities.get(entity); - assert tp != null; - entity.teleport(tp); - } - - - } - private Map getEntitiesOnCraft() { - HashMap ret = new HashMap<>(); - if (oldHitBox.isEmpty()) - return Collections.emptyMap(); - Location tOP = new Location(craft.getW(), originPoint.getX(), originPoint.getY(), originPoint.getZ()); - tOP.setX(tOP.getBlockX() + 0.5); - tOP.setZ(tOP.getBlockZ() + 0.5); - - if (craft.getType().getMoveEntities() && !(craft.getSinking() && craft.getType().getOnlyMovePlayers())) { - Location midpoint = new Location( - craft.getW(), - (oldHitBox.getMaxX() + oldHitBox.getMinX())/2.0, - (oldHitBox.getMaxY() + oldHitBox.getMinY())/2.0, - (oldHitBox.getMaxZ() + oldHitBox.getMinZ())/2.0); - for(Entity entity : craft.getW().getNearbyEntities(midpoint, oldHitBox.getXLength()/2.0 + 1, oldHitBox.getYLength()/2.0 + 2, oldHitBox.getZLength()/2.0 + 1)){ - if ((entity.getType() == EntityType.PLAYER && !craft.getSinking()) || !craft.getType().getOnlyMovePlayers()) { - // Player is onboard this craft - - Location adjustedPLoc = entity.getLocation().subtract(tOP); - - double[] rotatedCoords = MathUtils.rotateVecNoRound(rotation, adjustedPLoc.getX(), adjustedPLoc.getZ()); - float newYaw = rotation == Rotation.CLOCKWISE ? 90F : -90F; - Location tpLoc = new Location(craft.getW(), rotatedCoords[0] + tOP.getX(), entity.getLocation().getY(), rotatedCoords[1] + tOP.getZ(), newYaw + entity.getLocation().getYaw() , entity.getLocation().getPitch()); - ret.put(entity, tpLoc); - - } - } - } - return ret; - } -} diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/EntityTranslateUpdateCommand.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/EntityTranslateUpdateCommand.java deleted file mode 100644 index b9322ba5e..000000000 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/EntityTranslateUpdateCommand.java +++ /dev/null @@ -1,116 +0,0 @@ -/* - * This file is part of Movecraft. - * - * Movecraft is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * Movecraft is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Movecraft. If not, see . - */ - -package net.countercraft.movecraft.mapUpdater.update; - -import net.countercraft.movecraft.config.Settings; -import net.countercraft.movecraft.craft.Craft; -import net.countercraft.movecraft.utils.HitBox; -import net.countercraft.movecraft.utils.TeleportUtils; -import org.bukkit.Location; -import org.bukkit.entity.Entity; -import org.bukkit.entity.EntityType; -import org.bukkit.entity.Player; - -import java.util.Collection; -import java.util.HashSet; -import java.util.Objects; -import java.util.Set; - -/** - * Class that stores the data about a single blocks changes to the map in an unspecified world. The world is retrieved contextually from the submitting craft. - */ -public class EntityTranslateUpdateCommand extends UpdateCommand { - private final Craft craft; - private final HitBox oldHitBox; - private final double x; - private final double y; - private final double z; - private final float yaw; - private final float pitch; - - public EntityTranslateUpdateCommand(Craft craft, HitBox oldHitBox, double x, double y, double z) { - this.craft = craft; - this.oldHitBox = oldHitBox; - this.x = x; - this.y = y; - this.z = z; - this.yaw = 0; - this.pitch = 0; - } - - - public Craft getCraft() { - return craft; - } - - @Override - public void doUpdate() { - if (oldHitBox.isEmpty()){ - return; - } - for (Entity entity : getEntitiesOnCraft()){ - Location playerLoc = entity.getLocation(); - if (!(entity instanceof Player) || yaw > .01 || pitch > .01 || yaw < -.01 || pitch < -.01 || Settings.IsPre1_9) { - entity.teleport(new Location(entity.getWorld(), x + playerLoc.getX(),y + playerLoc.getY(),z + playerLoc.getZ(),yaw + playerLoc.getYaw(),pitch + playerLoc.getPitch())); - return; - } - //Movecraft.getInstance().getWorldHandler().addPlayerLocation((Player) entity,x,y,z,yaw,pitch); - TeleportUtils.teleport((Player) entity, new Location(entity.getWorld(), playerLoc.getX() + x, playerLoc.getY() + y, playerLoc.getZ() + z)); - } - - - } - - @Override - public int hashCode() { - return Objects.hash(craft, oldHitBox, x, y, z, pitch, yaw); - } - - @Override - public boolean equals(Object obj) { - if(!(obj instanceof EntityTranslateUpdateCommand)){ - return false; - } - EntityTranslateUpdateCommand other = (EntityTranslateUpdateCommand) obj; - return this.x == other.x && - this.y == other.y && - this.z == other.z && - this.pitch == other.pitch && - this.yaw == other.yaw && - this.craft.equals(other.craft) && - this.oldHitBox.equals(other.oldHitBox); - } - - private Collection getEntitiesOnCraft(){ - final Location midpoint = oldHitBox.getMidPoint().toBukkit(craft.getW()); - final Collection entities = craft.getW().getNearbyEntities(midpoint, oldHitBox.getXLength() / 2.0 + 1, oldHitBox.getYLength() / 2.0 + 2, oldHitBox.getZLength() / 2.0 + 1); - final Set toMove = new HashSet<>(); - for (Entity entity : entities){ - if (entity.getType() == EntityType.PLAYER) { - if(craft.getSinking()){ - continue; - } - toMove.add(entity); - } else if (!craft.getType().getOnlyMovePlayers() || entity.getType() == EntityType.PRIMED_TNT) { - toMove.add(entity); - } - } - return toMove; - } -} - diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/EntityUpdateCommand.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/EntityUpdateCommand.java new file mode 100644 index 000000000..29766e2ef --- /dev/null +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/EntityUpdateCommand.java @@ -0,0 +1,86 @@ +/* + * This file is part of Movecraft. + * + * Movecraft is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Movecraft is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Movecraft. If not, see . + */ + +package net.countercraft.movecraft.mapUpdater.update; + +import net.countercraft.movecraft.config.Settings; +import net.countercraft.movecraft.utils.TeleportUtils; +import org.bukkit.Location; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Player; + +import java.util.Objects; + +/** + * Class that stores the data about a single blocks changes to the map in an unspecified world. The world is retrieved contextually from the submitting craft. + */ +public class EntityUpdateCommand extends UpdateCommand { + private final Entity entity; + private final double x; + private final double y; + private final double z; + private final float yaw; + private final float pitch; + + public EntityUpdateCommand(Entity entity, double dx, double dy, double dz, float yaw, float pitch) { + this.entity = entity; + this.x = dx; + this.y = dy; + this.z = dz; + this.yaw = yaw; + this.pitch = pitch; + } + + + public final Entity getEntity() { + return entity; + } + + @Override + public void doUpdate() { + final Location entityLoc = entity.getLocation(); + if (!(entity instanceof Player) || yaw > .01 || pitch > .01 || yaw < -.01 || pitch < -.01 || Settings.IsPre1_9) { + entity.teleport(new Location(entity.getWorld(), x + entityLoc.getX(),y + entityLoc.getY(),z + entityLoc.getZ(),yaw + entityLoc.getYaw(),pitch + entityLoc.getPitch())); + return; + } + //Movecraft.getInstance().getWorldHandler().addPlayerLocation((Player) entity,x,y,z,yaw,pitch); + TeleportUtils.teleport((Player) entity, new Location(entity.getWorld(), entityLoc.getX() + x, entityLoc.getY() + y, entityLoc.getZ() + z)); + + + + } + + @Override + public int hashCode() { + return Objects.hash(entity, x, y, z, pitch, yaw); + } + + @Override + public boolean equals(Object obj) { + if(!(obj instanceof EntityUpdateCommand)){ + return false; + } + EntityUpdateCommand other = (EntityUpdateCommand) obj; + return this.x == other.x && + this.y == other.y && + this.z == other.z && + this.pitch == other.pitch && + this.yaw == other.yaw && + this.entity.equals(other.entity); + } +} + From 2a1b430a041a0b23305e88a76f2a78c9aa11ddac Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Sat, 18 Jan 2020 00:58:25 +0100 Subject: [PATCH 108/304] Fixed redstone on rotation too --- .../movecraft/compat/v1_15_R1/IWorldHandler.java | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/modules/v1_15_R1/src/main/java/net/countercraft/movecraft/compat/v1_15_R1/IWorldHandler.java b/modules/v1_15_R1/src/main/java/net/countercraft/movecraft/compat/v1_15_R1/IWorldHandler.java index 3fb50a8d8..81927381d 100644 --- a/modules/v1_15_R1/src/main/java/net/countercraft/movecraft/compat/v1_15_R1/IWorldHandler.java +++ b/modules/v1_15_R1/src/main/java/net/countercraft/movecraft/compat/v1_15_R1/IWorldHandler.java @@ -89,9 +89,15 @@ public void rotateCraft(@NotNull Craft craft, @NotNull MovecraftLocation originP for(BlockPosition position : rotatedPositions.keySet()){ blockData.put(position,nativeWorld.getType(position).a(ROTATION[rotation.ordinal()])); } + HashMap redstoneComponents = new HashMap<>(); //create the new block for(Map.Entry entry : blockData.entrySet()) { - setBlockFast(nativeWorld, rotatedPositions.get(entry.getKey()), entry.getValue()); + final BlockPosition newPosition = rotatedPositions.get(entry.getKey()); + final IBlockData iBlockData = entry.getValue(); + if (isRedstoneComponent(iBlockData)) { + redstoneComponents.put(newPosition, iBlockData); + } + setBlockFast(nativeWorld, newPosition, iBlockData); } @@ -118,6 +124,9 @@ public void rotateCraft(@NotNull Craft craft, @NotNull MovecraftLocation originP setBlockFast(nativeWorld, position, Blocks.AIR.getBlockData()); } + for (BlockPosition position : redstoneComponents.keySet()) { + setBlockFast(nativeWorld, position, redstoneComponents.get(position), true); + } //******************************************* //* Step six: Send to players * From 29987f8be42a3d683c0376f248fadfda8ffb0f0f Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Wed, 22 Jan 2020 23:12:15 +0100 Subject: [PATCH 109/304] Merge https://github.com/APDevTeam/Movecraft Crafts can no longer bypass the native world border in the Minecraft world Fixed console spam linked to non-tile blocks having tile entities, which could also cause corruption --- .../java/net/countercraft/movecraft/async/AsyncManager.java | 4 +++- .../countercraft/movecraft/async/rotation/RotationTask.java | 5 +++++ .../movecraft/async/translation/TranslationTask.java | 5 +++++ .../main/resources/localisation/movecraftlang_en.properties | 3 +++ .../movecraft/compat/v1_15_R1/IWorldHandler.java | 6 +++--- 5 files changed, 19 insertions(+), 4 deletions(-) diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java index 2809886cf..d2324c110 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java @@ -308,7 +308,9 @@ private void processAlgorithmQueue() { //c.setMinZ(task.getData().getMinZ()); //c.setHitBox(task.getData().getHitbox()); c.setHitBox(task.getNewHitBox()); - addToWaterlogQueue(c); + if (!c.getSinking()) { + addToWaterlogQueue(c); + } // move any cannons that were present if (Movecraft.getInstance().getCannonsPlugin() != null && shipCannons != null) { for (Cannon can : shipCannons) { diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/rotation/RotationTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/rotation/RotationTask.java index c62db3577..9dee55c4e 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/rotation/RotationTask.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/rotation/RotationTask.java @@ -177,6 +177,11 @@ public void run() { // See if they are permitted to build in the area, if WorldGuard integration is turned on Location plugLoc = newLocation.toBukkit(w); + if (!craft.getW().getWorldBorder().isInside(plugLoc)) { + failMessage = I18nSupport.getInternationalisedString("Rotation - Failed Craft cannot pass world border"); + failed = true; + return; + } //TODO: ADD TOWNY //TODO: ADD FACTIONS diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java index d5717ac04..99d229a9f 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java @@ -256,6 +256,11 @@ else if (craft.getType().getGravityInclineDistance() > -1 && incline > craft.get return; } + if (!craft.getW().getWorldBorder().isInside(newLocation.toBukkit(craft.getW()))) { + fail(I18nSupport.getInternationalisedString("Translation - Failed Craft cannot pass world border")); + return; + } + boolean blockObstructed; if (craft.getSinking()) { blockObstructed = !FALL_THROUGH_BLOCKS.contains(testMaterial); diff --git a/modules/Movecraft/src/main/resources/localisation/movecraftlang_en.properties b/modules/Movecraft/src/main/resources/localisation/movecraftlang_en.properties index cddb16ca8..baf5c531a 100644 --- a/modules/Movecraft/src/main/resources/localisation/movecraftlang_en.properties +++ b/modules/Movecraft/src/main/resources/localisation/movecraftlang_en.properties @@ -138,6 +138,7 @@ Rotation\ -\ NULL\ Player\ Rotation\ Failed=NULL Player rotation failed Rotation\ -\ Turning\ Too\ Quickly=You're turning too quickly\! Rotation\ -\ Already\ Rotating=You are already rotating Rotation\ -\ WorldGuard\ -\ Not\ Permitted\ To\ Build=Rotation - Player is not permitted to build in this WorldGuard region +Rotation\ -\ Failed\ Craft\ cannot\ pass\ world\ border=You cannot move the craft past the world border Scuttle\ -\ Must\ Be\ Online=Player supplied must be online. Scuttle\ -\ Must\ Be\ Player=You must be a player to scuttle your craft. Scuttle\ -\ Craft\ Already\ Sinking=The craft is already sinking\! @@ -199,6 +200,8 @@ Startup\ -\ Essentials\ Found=Found a compatible version of Essentials. Enabling Startup\ -\ Essentials\ Not\ Found=Movecraft did not find a compatible version of Essentials. Disabling Essentials integration. Startup\ -\ Vault\ Found=Found a compatible Vault plugin. Enabling Vault integration. Startup\ -\ Vault\ Not\ Found=Movecraft did not find a compatible Vault plugin. Disabling Vault integration. + +Translation\ -\ Failed\ Craft\ cannot\ pass\ world\ border=You cannot move the craft past the world border Translation\ -\ Failed\ Craft\ hit\ height\ limit=Craft has hit the height limit Translation\ -\ Failed\ Craft\ Is\ Disabled=Craft Is Disabled! Translation\ -\ Failed\ Incline\ too\ steep=The craft cannot move because the incline is too steep\! diff --git a/modules/v1_15_R1/src/main/java/net/countercraft/movecraft/compat/v1_15_R1/IWorldHandler.java b/modules/v1_15_R1/src/main/java/net/countercraft/movecraft/compat/v1_15_R1/IWorldHandler.java index 81927381d..c231b3bca 100644 --- a/modules/v1_15_R1/src/main/java/net/countercraft/movecraft/compat/v1_15_R1/IWorldHandler.java +++ b/modules/v1_15_R1/src/main/java/net/countercraft/movecraft/compat/v1_15_R1/IWorldHandler.java @@ -110,8 +110,6 @@ public void rotateCraft(@NotNull Craft craft, @NotNull MovecraftLocation originP if(tileHolder.getNextTick()==null) continue; final long currentTime = nativeWorld.worldData.getTime(); - //nativeWorld.b(rotatedPositions.get(tileHolder.getNextTick().a), tileHolder.getNextTick().a(), (int) (tileHolder.getNextTick().b - currentTime), tileHolder.getNextTick().c); - //BlockPosition, Object, int, TickListPriority nativeWorld.getBlockTickList().a(rotatedPositions.get(tileHolder.getNextTick().a), tileHolder.getNextTick().b(), (int) (tileHolder.getNextTick().b - currentTime), tileHolder.getNextTick().c); } @@ -204,7 +202,6 @@ public void translateCraft(@NotNull Craft craft, @NotNull MovecraftLocation disp final IBlockData iBlockData = blockData.get(i); if (isRedstoneComponent(iBlockData)) { redstoneComponents.put(newPosition, iBlockData); - //continue; } setBlockFast(nativeWorld, newPosition, iBlockData); } @@ -314,6 +311,9 @@ private void setBlockFast(@NotNull World world, @NotNull BlockPosition position, chunkSection = chunk.getSections()[position.getY() >> 4]; } + if (world.getType(position).getBlock().isTileEntity()) { + removeTileEntity(world, position); + } chunkSection.setType(position.getX()&15, position.getY()&15, position.getZ()&15, data); if (physics) { world.notifyAndUpdatePhysics(position, chunk, data, data, data, 3); From 85c1cde23606d51969b4693d1ffb1abcf9c8fe00 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Wed, 22 Jan 2020 23:40:04 +0100 Subject: [PATCH 110/304] Added craft flag keepMovingOnSinkMaxMove --- .../java/net/countercraft/movecraft/async/AsyncManager.java | 6 ++++-- .../java/net/countercraft/movecraft/craft/CraftType.java | 6 ++++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java index d2324c110..5ea557847 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java @@ -632,8 +632,10 @@ private void processSinking() { int dx = 0; int dz = 0; if (craft.getType().getKeepMovingOnSink()) { - dx = craft.getLastDX(); - dz = craft.getLastDZ(); + final int limit = craft.getType().getKeepMovingOnSinkMaxMove(); + final boolean limitMotion = craft.getType().getKeepMovingOnSinkMaxMove() > -1; + dx = limitMotion ? Math.min(craft.getLastDX(), limit) : craft.getLastDX(); + dz = limitMotion ? Math.min(craft.getLastDZ(), limit) : craft.getLastDZ(); } craft.translate(dx, -1, dz); craft.setLastCruiseUpdate(System.currentTimeMillis() - (craft.getLastCruiseUpdate() != -1 ? 0 : 30000)); diff --git a/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java b/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java index a2cb03a01..6cc6a39cd 100644 --- a/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java +++ b/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java @@ -101,6 +101,7 @@ final public class CraftType { @NotNull private final Set forbiddenHoverOverBlocks; private final int gravityDropDistance; private final int gravityInclineDistance; + private final int keepMovingOnSinkMaxMove; @SuppressWarnings("unchecked") public CraftType(File f) throws CraftTypeException{ @@ -159,6 +160,7 @@ public CraftType(File f) throws CraftTypeException{ underwaterDetectionMultiplier = doubleFromObject(data.getOrDefault("underwaterDetectionMultiplier", detectionMultiplier)); sinkRateTicks = data.containsKey("sinkSpeed") ? (int) Math.ceil(20 / (doubleFromObject(data.get("sinkSpeed")))) : integerFromObject(data.getOrDefault("sinkTickRate", 0)); keepMovingOnSink = (Boolean) data.getOrDefault("keepMovingOnSink", false); + keepMovingOnSinkMaxMove = integerFromObject(data.getOrDefault("keepMovingOnSinkMaxMove", -1)); smokeOnSink = integerFromObject(data.getOrDefault("smokeOnSink", 0)); explodeOnCrash = floatFromObject(data.getOrDefault("explodeOnCrash", 0F)); collisionExplosion = floatFromObject(data.getOrDefault("collisionExplosion", 0F)); @@ -1005,6 +1007,10 @@ public int getGravityInclineDistance() { return gravityInclineDistance; } + public int getKeepMovingOnSinkMaxMove() { + return keepMovingOnSinkMaxMove; + } + private class TypeNotFoundException extends RuntimeException { public TypeNotFoundException(String s) { super(s); From 1fdaf24f92b2fc17ec756bf1f0aa138ed51d996d Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Thu, 23 Jan 2020 12:23:35 +0100 Subject: [PATCH 111/304] Fixed entity rotation for crafts with rotateAtMidpoint: false --- .../movecraft/async/AsyncManager.java | 4 ++-- .../mapUpdater/update/CraftRotateCommand.java | 17 +++++++++-------- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java index 5ea557847..2796c58f0 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java @@ -634,8 +634,8 @@ private void processSinking() { if (craft.getType().getKeepMovingOnSink()) { final int limit = craft.getType().getKeepMovingOnSinkMaxMove(); final boolean limitMotion = craft.getType().getKeepMovingOnSinkMaxMove() > -1; - dx = limitMotion ? Math.min(craft.getLastDX(), limit) : craft.getLastDX(); - dz = limitMotion ? Math.min(craft.getLastDZ(), limit) : craft.getLastDZ(); + dx = limitMotion ? Math.min(craft.getLastDX(), (craft.getLastDX() > 0 ? 1 : -1) * limit) : craft.getLastDX(); + dz = limitMotion ? Math.min(craft.getLastDZ(), (craft.getLastDX() > 0 ? 1 : -1) * limit) : craft.getLastDZ(); } craft.translate(dx, -1, dz); craft.setLastCruiseUpdate(System.currentTimeMillis() - (craft.getLastCruiseUpdate() != -1 ? 0 : 30000)); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftRotateCommand.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftRotateCommand.java index 1c06769d4..ea0495e27 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftRotateCommand.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftRotateCommand.java @@ -49,6 +49,11 @@ public void doUpdate() { long time = System.nanoTime(); final Set passthroughBlocks = new HashSet<>(craft.getType().getPassthroughBlocks()); final Set toRotate = new HashSet<>(); + MutableHitBox originalLocations = new HashHitBox(); + final Rotation counterRotation = rotation == Rotation.CLOCKWISE ? Rotation.ANTICLOCKWISE : Rotation.CLOCKWISE; + for (MovecraftLocation movecraftLocation : craft.getHitBox()) { + originalLocations.add(MathUtils.rotateVec(counterRotation, movecraftLocation.subtract(originLocation)).add(originLocation)); + } if(craft.getSinking()){ passthroughBlocks.add(Material.WATER); @@ -76,11 +81,11 @@ public void doUpdate() { } } else if (craft.getType().getMoveEntities()) { - Location tOP = new Location(craft.getW(), originLocation.getX(), originLocation.getY(), originLocation.getZ()); + Location tOP = originLocation.toBukkit(craft.getW()); tOP.setX(tOP.getBlockX() + 0.5); tOP.setZ(tOP.getBlockZ() + 0.5); - Location midpoint = craft.getHitBox().getMidPoint().toBukkit(craft.getW()); - for(Entity entity : craft.getW().getNearbyEntities(midpoint, craft.getHitBox().getZLength()/2.0 + 1, craft.getHitBox().getYLength()/2.0 + 2, craft.getHitBox().getXLength()/2.0 + 1)){ + Location midpoint = originalLocations.getMidPoint().toBukkit(craft.getW()); + for(Entity entity : craft.getW().getNearbyEntities(midpoint, originalLocations.getXLength()/2.0 + 1, originalLocations.getYLength()/2.0 + 2, originalLocations.getZLength()/2.0 + 1)){ // Player is onboard this craft @@ -96,11 +101,7 @@ public void doUpdate() { } } if (!passthroughBlocks.isEmpty()) { - MutableHitBox originalLocations = new HashHitBox(); - final Rotation counterRotation = rotation == Rotation.CLOCKWISE ? Rotation.ANTICLOCKWISE : Rotation.CLOCKWISE; - for (MovecraftLocation movecraftLocation : craft.getHitBox()) { - originalLocations.add(MathUtils.rotateVec(counterRotation, movecraftLocation.subtract(originLocation)).add(originLocation)); - } + final HitBox to = CollectionUtils.filter(craft.getHitBox(), originalLocations); From 9c63d91e9c2f3518f698ae7cc7b5db3affc98286 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Thu, 23 Jan 2020 20:25:42 +0100 Subject: [PATCH 112/304] Fixed explosions --- .../movecraft/async/translation/TranslationTask.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java index 99d229a9f..2456af761 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java @@ -332,7 +332,7 @@ else if (craft.getType().getGravityInclineDistance() > -1 && incline > craft.get if (System.currentTimeMillis() - craft.getOrigPilotTime() <= 1000) { continue; } - Location loc = location.translate(-dx,-dy,-dz).toBukkit(craft.getW()); + Location loc = location.translate( dx, dy, dz).toBukkit(craft.getW()); if (!loc.getBlock().getType().equals(Material.AIR) && ThreadLocalRandom.current().nextDouble(1) < .05) { updates.add(new ExplosionUpdateCommand( loc, craft.getType().getExplodeOnCrash())); collisionExplosion=true; From c1a8f1abcd2aae218bf729667048cf7ed9534417 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Sun, 26 Jan 2020 18:22:29 +0100 Subject: [PATCH 113/304] Reverted change supposed to go to another branch --- .../movecraft/warfare/siege/SiegeProgressTask.java | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/siege/SiegeProgressTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/siege/SiegeProgressTask.java index b5b5e1826..d498a0234 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/siege/SiegeProgressTask.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/siege/SiegeProgressTask.java @@ -1,20 +1,18 @@ package net.countercraft.movecraft.warfare.siege; -import com.avaje.ebean.validation.NotNull; -import java.util.List; import com.sk89q.worldguard.domains.DefaultDomain; import com.sk89q.worldguard.protection.regions.ProtectedRegion; import net.countercraft.movecraft.Movecraft; -import net.countercraft.movecraft.craft.Craft; import net.countercraft.movecraft.MovecraftLocation; -import net.countercraft.movecraft.craft.CraftManager; import net.countercraft.movecraft.config.Settings; +import net.countercraft.movecraft.craft.Craft; +import net.countercraft.movecraft.craft.CraftManager; import net.countercraft.movecraft.localisation.I18nSupport; import org.bukkit.Bukkit; import org.bukkit.Sound; import org.bukkit.entity.Player; -import java.util.concurrent.atomic.AtomicReference; +import java.util.List; public class SiegeProgressTask extends SiegeTask { From 5840f6b72ffbbb61e4621bf9087359a52bb94c3b Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Fri, 31 Jan 2020 14:07:59 +0100 Subject: [PATCH 114/304] Removing something redundant --- .../movecraft/mapUpdater/update/EntityUpdateCommand.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/EntityUpdateCommand.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/EntityUpdateCommand.java index 29766e2ef..c6e44f963 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/EntityUpdateCommand.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/EntityUpdateCommand.java @@ -17,7 +17,6 @@ package net.countercraft.movecraft.mapUpdater.update; -import net.countercraft.movecraft.config.Settings; import net.countercraft.movecraft.utils.TeleportUtils; import org.bukkit.Location; import org.bukkit.entity.Entity; @@ -53,7 +52,7 @@ public final Entity getEntity() { @Override public void doUpdate() { final Location entityLoc = entity.getLocation(); - if (!(entity instanceof Player) || yaw > .01 || pitch > .01 || yaw < -.01 || pitch < -.01 || Settings.IsPre1_9) { + if (!(entity instanceof Player) || yaw > .01 || pitch > .01 || yaw < -.01 || pitch < -.01 ) { entity.teleport(new Location(entity.getWorld(), x + entityLoc.getX(),y + entityLoc.getY(),z + entityLoc.getZ(),yaw + entityLoc.getYaw(),pitch + entityLoc.getPitch())); return; } From 7b998611354d09961d3b36e728f06fc4d10ac90b Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Fri, 31 Jan 2020 23:54:28 +0100 Subject: [PATCH 115/304] Removed redundant variables --- .../movecraft/async/translation/TranslationTask.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java index 2456af761..2ac07aaec 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java @@ -237,8 +237,6 @@ else if (craft.getType().getGravityInclineDistance() > -1 && incline > craft.get final List harvestedBlocks = new ArrayList<>(); final List harvesterBladeBlocks = craft.getType().getHarvesterBladeBlocks(); final HashHitBox collisionBox = new HashHitBox(); - final Set chunkUpdateCmds = new HashSet<>(); - boolean structureIntact = true; for(MovecraftLocation oldLocation : oldHitBox){ final MovecraftLocation newLocation = oldLocation.translate(dx,dy,dz); //If the new location already exists in the old hitbox than this is unnecessary because a craft can't hit From c3428fc8cebc8c2cf6cc1307920276321c25f5e2 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Sat, 1 Feb 2020 00:16:08 +0100 Subject: [PATCH 116/304] Fixed gravity --- .../async/translation/TranslationTask.java | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java index 2ac07aaec..928217473 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java @@ -217,6 +217,19 @@ else if (craft.getType().getGravityInclineDistance() > -1 && incline > craft.get } else { dy = incline; } + } else if (!isOnGround(oldHitBox) && craft.getType().getCanHover()){ + MovecraftLocation midPoint = oldHitBox.getMidPoint(); + int centreMinY = oldHitBox.getLocalMinY(midPoint.getX(), midPoint.getZ()); + int groundY = centreMinY; + World w = craft.getW(); + while (w.getBlockAt(midPoint.getX(), groundY - 1, midPoint.getZ()).getType() == Material.AIR || craft.getType().getPassthroughBlocks().contains(w.getBlockAt(midPoint.getX(), groundY - 1, midPoint.getZ()).getType())){ + groundY--; + } + if (centreMinY - groundY > craft.getType().getHoverLimit()){ + dy = -1; + } + } else if (!isOnGround(oldHitBox)){ + dy = dropDistance(oldHitBox); } } //Fail the movement if the craft is too high From 0ae7f04654ad0fb6f903a37c27522471c42ff796 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Tue, 4 Feb 2020 19:15:06 +0100 Subject: [PATCH 117/304] Fixed waterlogging and example craft type files --- .../movecraft/async/AsyncManager.java | 4 - .../update/CraftTranslateCommand.java | 7 + .../movecraft/utils/WaterlogUtils.java | 41 +++-- .../resources/types/1_14/BigAirship.craft | 164 +++++++++--------- .../resources/types/1_14/BigSubAirship.craft | 162 ++++++++--------- .../src/main/resources/types/1_14/Ship.craft | 62 +++---- .../resources/types/1_14/SubAirship.craft | 162 ++++++++--------- .../main/resources/types/1_14/Submarine.craft | 62 +++---- .../main/resources/types/1_14/Turret.craft | 54 +++--- .../main/resources/types/1_14/airship.craft | 164 +++++++++--------- .../main/resources/types/1_14/airskiff.craft | 138 +++++++-------- .../main/resources/types/1_14/elevator.craft | 138 +++++++-------- .../src/main/resources/types/BigAirship.craft | 162 ++++++++--------- .../main/resources/types/BigSubAirship.craft | 160 ++++++++--------- .../src/main/resources/types/Ship.craft | 62 +++---- .../src/main/resources/types/SubAirship.craft | 160 ++++++++--------- .../src/main/resources/types/Submarine.craft | 64 +++---- .../src/main/resources/types/Turret.craft | 54 +++--- .../src/main/resources/types/airship.craft | 162 ++++++++--------- .../src/main/resources/types/airskiff.craft | 150 ++++++++-------- .../src/main/resources/types/elevator.craft | 56 +++--- 21 files changed, 1103 insertions(+), 1085 deletions(-) diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java index 2796c58f0..71a718123 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java @@ -308,9 +308,6 @@ private void processAlgorithmQueue() { //c.setMinZ(task.getData().getMinZ()); //c.setHitBox(task.getData().getHitbox()); c.setHitBox(task.getNewHitBox()); - if (!c.getSinking()) { - addToWaterlogQueue(c); - } // move any cannons that were present if (Movecraft.getInstance().getCannonsPlugin() != null && shipCannons != null) { for (Cannon can : shipCannons) { @@ -355,7 +352,6 @@ private void processAlgorithmQueue() { sentMapUpdate = true; c.setHitBox(task.getNewHitBox()); - addToWaterlogQueue(c); // rotate any cannons that were present if (Movecraft.getInstance().getCannonsPlugin() != null && shipCannons != null) { Location tloc = task.getOriginPoint().toBukkit(task.getCraft().getW()); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftTranslateCommand.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftTranslateCommand.java index c432cf387..de14c1f33 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftTranslateCommand.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftTranslateCommand.java @@ -91,6 +91,8 @@ public void doUpdate() { } } } + MutableHitBox interior = new HashHitBox(); + MutableHitBox exterior = new HashHitBox(); if(passthroughBlocks.isEmpty()){ //translate the craft Movecraft.getInstance().getWorldHandler().translateCraft(craft,displacement); @@ -206,8 +208,13 @@ public void doUpdate() { } } + interior.addAll(failed); + } MapUpdateManager.getInstance().scheduleUpdates(toMove); + if (!Settings.IsLegacy) { + WaterlogUtils.waterlogBlocksOnCraft(craft, interior); + } if (!craft.isNotProcessing()) { craft.setProcessing(false); } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/WaterlogUtils.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/WaterlogUtils.java index c97f1635e..67e0f9b9c 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/WaterlogUtils.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/WaterlogUtils.java @@ -1,33 +1,48 @@ package net.countercraft.movecraft.utils; import net.countercraft.movecraft.MovecraftLocation; +import net.countercraft.movecraft.craft.Craft; import org.bukkit.Location; import org.bukkit.Material; -import org.bukkit.World; import org.bukkit.block.Block; +import org.bukkit.block.data.Bisected; import org.bukkit.block.data.Waterlogged; +import org.bukkit.block.data.type.TrapDoor; public class WaterlogUtils { private WaterlogUtils(){ } - public static boolean adjacentToWater(World world, MovecraftLocation ml){ - for (MovecraftLocation shift : SHIFTS){ - final MovecraftLocation test = ml.add(shift); - final Block testBlock = test.toBukkit(world).getBlock(); + public static void waterlogBlocksOnCraft(Craft craft, HitBox interior) { - if (testBlock.getType() == Material.WATER){ - return true; + for (MovecraftLocation ml : craft.getHitBox()) { + boolean waterlog = true; + Block b = ml.toBukkit(craft.getW()).getBlock(); + if (!(b.getBlockData() instanceof Waterlogged)) { + continue; } - else if (testBlock.getBlockData() instanceof Waterlogged){ - Waterlogged wlog = (Waterlogged) testBlock.getBlockData(); - if (!wlog.isWaterlogged()){ - return false; + Waterlogged wLog = (Waterlogged) b.getBlockData(); + boolean exteriorBlock = false; + for (MovecraftLocation shift : SHIFTS) { + if (craft.getHitBox().contains(ml.subtract(shift)) || interior.contains(ml.subtract(shift))) { + continue; } - return true; + exteriorBlock = true; + break; } + if (!exteriorBlock || ml.getY() > craft.getWaterLine()) { + waterlog = false; + } else if (wLog instanceof TrapDoor) { + TrapDoor td = (TrapDoor) wLog; + if (td.getHalf() == Bisected.Half.TOP && (interior.contains(ml.translate(0, -1, 0)) || craft.getHitBox().contains(ml.translate(0, -1, 0)))) { + waterlog = false; + } else if (td.getHalf() == Bisected.Half.BOTTOM && (interior.contains(ml.translate(0, 1, 0)) || craft.getHitBox().contains(ml.translate(0, 1, 0)))) { + waterlog = false; + } + } + wLog.setWaterlogged(waterlog); + b.setBlockData(wLog); } - return false; } public static boolean isWaterlogged(Location location){ diff --git a/modules/Movecraft/src/main/resources/types/1_14/BigAirship.craft b/modules/Movecraft/src/main/resources/types/1_14/BigAirship.craft index 35e083103..d8c8ce2e8 100644 --- a/modules/Movecraft/src/main/resources/types/1_14/BigAirship.craft +++ b/modules/Movecraft/src/main/resources/types/1_14/BigAirship.craft @@ -2,88 +2,88 @@ name: BigAirship maxSize: 20000 minSize: 10000 allowedBlocks: - - ALL_WOOD - - WATER - - LAVA - - ALL_LOG - - all_planks - - GLASS - - LAPIS_BLOCK - - DISPENSER - - NOTE_BLOCK - - ALL_BED - - sticky_piston - - piston_head - - all_wool - - GOLD_BLOCK - - IRON_BLOCK - - all_slab - - BOOKSHELF - - TORCH - - FIRE - - oak_stairs - - birch_stairs - - jungle_stairs - - spruce_stairs - - stone_brick_stairs - - quartz_stairs - - nether_brick_stairs - - chest - - redstone_wire - - diamond_block - - nether_brick_stairs - - furnace - - all_sign - - ladder - - all_door - - lever - - all_pressure_plate - - redstone_torch - - redstone_wall_torch - - all_button - - clay - - all_fence - - netherrack - - glowstone - - cake - - repeater - - all_stained_glass - - all_trapdoor - - all_stone_bricks - - iron_bars - - glass_pane - - all_fence_gate - - nether_bricks - - enchanting_table - - brewing_stand - - cauldron - - end_stone - - dragon_egg - - redstone_lamp - - ender_chest - - TRIPWIRE_HOOK - - EMERALD_BLOCK - - BEACON - - cobblestone_wall - - mossy_cobblestone_wall - - FLOWER_POT - - all_SKULL - - all_ANVIL - - TRAPPED_CHEST - - COMPARATOR - - daylight_detector - - REDSTONE_BLOCK - - HOPPER - - all_QUARTZ_BLOCK - - all_rail - - DROPPER - - ALL_TERRACOTTA - - ALL_STAINED_GLASS_PANE - - SLIME_BLOCK - - ALL_CARPET - - COAL_BLOCK - - END_STONE_BRICKS - - barrel + - all_wood + - water + - lava + - all_log + - all_planks + - glass + - lapis_block + - dispenser + - note_block + - all_bed + - sticky_piston + - piston_head + - all_wool + - gold_block + - iron_block + - all_slab + - bookshelf + - torch + - fire + - oak_stairs + - birch_stairs + - jungle_stairs + - spruce_stairs + - stone_brick_stairs + - quartz_stairs + - nether_brick_stairs + - chest + - redstone_wire + - diamond_block + - nether_brick_stairs + - furnace + - all_sign + - ladder + - all_door + - lever + - all_pressure_plate + - redstone_torch + - redstone_wall_torch + - all_button + - clay + - all_fence + - netherrack + - glowstone + - cake + - repeater + - all_stained_glass + - all_trapdoor + - all_stone_bricks + - iron_bars + - glass_pane + - all_fence_gate + - nether_bricks + - enchanting_table + - brewing_stand + - cauldron + - end_stone + - dragon_egg + - redstone_lamp + - ender_chest + - tripwire_hook + - emerald_block + - beacon + - cobblestone_wall + - mossy_cobblestone_wall + - flower_pot + - all_skull + - all_anvil + - trapped_chest + - comparator + - daylight_detector + - redstone_block + - hopper + - all_quartz_block + - all_rail + - dropper + - all_terracotta + - all_stained_glass_pane + - slime_block + - all_carpet + - coal_block + - end_stone_bricks + - barrel canCruise: true rotateAtMidpoint: true blockRemoteRotate: true diff --git a/modules/Movecraft/src/main/resources/types/1_14/BigSubAirship.craft b/modules/Movecraft/src/main/resources/types/1_14/BigSubAirship.craft index d53767d19..6a0dd5c73 100644 --- a/modules/Movecraft/src/main/resources/types/1_14/BigSubAirship.craft +++ b/modules/Movecraft/src/main/resources/types/1_14/BigSubAirship.craft @@ -2,87 +2,87 @@ name: BigSubAirship maxSize: 20000 minSize: 10000 allowedBlocks: -- ALL_WOOD - - LAVA - - ALL_LOG - - all_planks - - GLASS - - LAPIS_BLOCK - - DISPENSER - - NOTE_BLOCK - - ALL_BED - - sticky_piston - - piston_head - - all_wool - - GOLD_BLOCK - - IRON_BLOCK - - all_slab - - BOOKSHELF - - TORCH - - FIRE - - oak_stairs - - birch_stairs - - jungle_stairs - - spruce_stairs - - stone_brick_stairs - - quartz_stairs - - nether_brick_stairs - - chest - - redstone_wire - - diamond_block - - nether_brick_stairs - - furnace - - all_sign - - ladder - - all_door - - lever - - all_pressure_plate - - redstone_torch - - redstone_wall_torch - - all_button - - clay - - all_fence - - netherrack - - glowstone - - cake - - repeater - - all_stained_glass - - all_trapdoor - - all_stone_bricks - - iron_bars - - glass_pane - - all_fence_gate - - nether_bricks - - enchanting_table - - brewing_stand - - cauldron - - end_stone - - dragon_egg - - redstone_lamp - - ender_chest - - TRIPWIRE_HOOK - - EMERALD_BLOCK - - BEACON - - cobblestone_wall - - mossy_cobblestone_wall - - FLOWER_POT - - all_SKULL - - all_ANVIL - - TRAPPED_CHEST - - COMPARATOR - - daylight_detector - - REDSTONE_BLOCK - - HOPPER - - all_QUARTZ_BLOCK - - all_rail - - DROPPER - - ALL_TERRACOTTA - - ALL_STAINED_GLASS_PANE - - SLIME_BLOCK - - ALL_CARPET - - COAL_BLOCK - - END_STONE_BRICKS - - barrel + - all_wood + - lava + - all_log + - all_planks + - glass + - lapis_block + - dispenser + - note_block + - all_bed + - sticky_piston + - piston_head + - all_wool + - gold_block + - iron_block + - all_slab + - bookshelf + - torch + - fire + - oak_stairs + - birch_stairs + - jungle_stairs + - spruce_stairs + - stone_brick_stairs + - quartz_stairs + - nether_brick_stairs + - chest + - redstone_wire + - diamond_block + - nether_brick_stairs + - furnace + - all_sign + - ladder + - all_door + - lever + - all_pressure_plate + - redstone_torch + - redstone_wall_torch + - all_button + - clay + - all_fence + - netherrack + - glowstone + - cake + - repeater + - all_stained_glass + - all_trapdoor + - all_stone_bricks + - iron_bars + - glass_pane + - all_fence_gate + - nether_bricks + - enchanting_table + - brewing_stand + - cauldron + - end_stone + - dragon_egg + - redstone_lamp + - ender_chest + - tripwire_hook + - emerald_block + - beacon + - cobblestone_wall + - mossy_cobblestone_wall + - flower_pot + - all_skull + - all_anvil + - trapped_chest + - comparator + - daylight_detector + - redstone_block + - hopper + - all_quartz_block + - all_rail + - dropper + - all_terracotta + - all_stained_glass_pane + - slime_block + - all_carpet + - coal_block + - end_stone_bricks + - barrel canCruise: true rotateAtMidpoint: true blockRemoteRotate: true diff --git a/modules/Movecraft/src/main/resources/types/1_14/Ship.craft b/modules/Movecraft/src/main/resources/types/1_14/Ship.craft index d59c2f182..b8c0f2f72 100644 --- a/modules/Movecraft/src/main/resources/types/1_14/Ship.craft +++ b/modules/Movecraft/src/main/resources/types/1_14/Ship.craft @@ -2,24 +2,24 @@ name: Ship maxSize: 100000 minSize: 10 allowedBlocks: -- ALL_WOOD - - LAVA - - ALL_LOG + - all_wood + - lava + - all_log - all_planks - - GLASS - - LAPIS_BLOCK - - DISPENSER - - NOTE_BLOCK - - ALL_BED + - glass + - lapis_block + - dispenser + - note_block + - all_bed - sticky_piston - piston_head - all_wool - - GOLD_BLOCK - - IRON_BLOCK + - gold_block + - iron_block - all_slab - - BOOKSHELF - - TORCH - - FIRE + - bookshelf + - torch + - fire - oak_stairs - birch_stairs - jungle_stairs @@ -60,28 +60,28 @@ allowedBlocks: - dragon_egg - redstone_lamp - ender_chest - - TRIPWIRE_HOOK - - EMERALD_BLOCK - - BEACON + - tripwire_hook + - emerald_block + - beacon - cobblestone_wall - mossy_cobblestone_wall - - FLOWER_POT - - all_SKULL - - all_ANVIL - - TRAPPED_CHEST - - COMPARATOR + - flower_pot + - all_skull + - all_anvil + - trapped_chest + - comparator - daylight_detector - - REDSTONE_BLOCK - - HOPPER - - all_QUARTZ_BLOCK + - redstone_block + - hopper + - all_quartz_block - all_rail - - DROPPER - - ALL_TERRACOTTA - - ALL_STAINED_GLASS_PANE - - SLIME_BLOCK - - ALL_CARPET - - COAL_BLOCK - - END_STONE_BRICKS + - dropper + - all_terracotta + - all_stained_glass_pane + - slime_block + - all_carpet + - coal_block + - end_stone_bricks - barrel canCruise: true cruiseSkipBlocks: 4 diff --git a/modules/Movecraft/src/main/resources/types/1_14/SubAirship.craft b/modules/Movecraft/src/main/resources/types/1_14/SubAirship.craft index 362e8f353..e0432467f 100644 --- a/modules/Movecraft/src/main/resources/types/1_14/SubAirship.craft +++ b/modules/Movecraft/src/main/resources/types/1_14/SubAirship.craft @@ -2,87 +2,87 @@ name: SubAirship maxSize: 5000 minSize: 1000 allowedBlocks: -- ALL_WOOD - - LAVA - - ALL_LOG - - all_planks - - GLASS - - LAPIS_BLOCK - - DISPENSER - - NOTE_BLOCK - - ALL_BED - - sticky_piston - - piston_head - - all_wool - - GOLD_BLOCK - - IRON_BLOCK - - all_slab - - BOOKSHELF - - TORCH - - FIRE - - oak_stairs - - birch_stairs - - jungle_stairs - - spruce_stairs - - stone_brick_stairs - - quartz_stairs - - nether_brick_stairs - - chest - - redstone_wire - - diamond_block - - nether_brick_stairs - - furnace - - all_sign - - ladder - - all_door - - lever - - all_pressure_plate - - redstone_torch - - redstone_wall_torch - - all_button - - clay - - all_fence - - netherrack - - glowstone - - cake - - repeater - - all_stained_glass - - all_trapdoor - - all_stone_bricks - - iron_bars - - glass_pane - - all_fence_gate - - nether_bricks - - enchanting_table - - brewing_stand - - cauldron - - end_stone - - dragon_egg - - redstone_lamp - - ender_chest - - TRIPWIRE_HOOK - - EMERALD_BLOCK - - BEACON - - cobblestone_wall - - mossy_cobblestone_wall - - FLOWER_POT - - all_SKULL - - all_ANVIL - - TRAPPED_CHEST - - COMPARATOR - - daylight_detector - - REDSTONE_BLOCK - - HOPPER - - all_QUARTZ_BLOCK - - all_rail - - DROPPER - - ALL_TERRACOTTA - - ALL_STAINED_GLASS_PANE - - SLIME_BLOCK - - ALL_CARPET - - COAL_BLOCK - - END_STONE_BRICKS - - barrel + - all_wood + - lava + - all_log + - all_planks + - glass + - lapis_block + - dispenser + - note_block + - all_bed + - sticky_piston + - piston_head + - all_wool + - gold_block + - iron_block + - all_slab + - bookshelf + - torch + - fire + - oak_stairs + - birch_stairs + - jungle_stairs + - spruce_stairs + - stone_brick_stairs + - quartz_stairs + - nether_brick_stairs + - chest + - redstone_wire + - diamond_block + - nether_brick_stairs + - furnace + - all_sign + - ladder + - all_door + - lever + - all_pressure_plate + - redstone_torch + - redstone_wall_torch + - all_button + - clay + - all_fence + - netherrack + - glowstone + - cake + - repeater + - all_stained_glass + - all_trapdoor + - all_stone_bricks + - iron_bars + - glass_pane + - all_fence_gate + - nether_bricks + - enchanting_table + - brewing_stand + - cauldron + - end_stone + - dragon_egg + - redstone_lamp + - ender_chest + - tripwire_hook + - emerald_block + - beacon + - cobblestone_wall + - mossy_cobblestone_wall + - flower_pot + - all_skull + - all_anvil + - trapped_chest + - comparator + - daylight_detector + - redstone_block + - hopper + - all_quartz_block + - all_rail + - dropper + - all_terracotta + - all_stained_glass_pane + - slime_block + - all_carpet + - coal_block + - end_stone_bricks + - barrel canCruise: true rotateAtMidpoint: true cruiseSkipBlocks: 4 diff --git a/modules/Movecraft/src/main/resources/types/1_14/Submarine.craft b/modules/Movecraft/src/main/resources/types/1_14/Submarine.craft index a16c67ff7..8f37a39bb 100644 --- a/modules/Movecraft/src/main/resources/types/1_14/Submarine.craft +++ b/modules/Movecraft/src/main/resources/types/1_14/Submarine.craft @@ -2,24 +2,24 @@ name: Submarine maxSize: 100000 minSize: 10 allowedBlocks: -- ALL_WOOD - - LAVA - - ALL_LOG + - all_wood + - lava + - all_log - all_planks - - GLASS - - LAPIS_BLOCK - - DISPENSER - - NOTE_BLOCK - - ALL_BED + - glass + - lapis_block + - dispenser + - note_block + - all_bed - sticky_piston - piston_head - all_wool - - GOLD_BLOCK - - IRON_BLOCK + - gold_block + - iron_block - all_slab - - BOOKSHELF - - TORCH - - FIRE + - bookshelf + - torch + - fire - oak_stairs - birch_stairs - jungle_stairs @@ -60,28 +60,28 @@ allowedBlocks: - dragon_egg - redstone_lamp - ender_chest - - TRIPWIRE_HOOK - - EMERALD_BLOCK - - BEACON + - tripwire_hook + - emerald_block + - beacon - cobblestone_wall - mossy_cobblestone_wall - - FLOWER_POT - - all_SKULL - - all_ANVIL - - TRAPPED_CHEST - - COMPARATOR + - flower_pot + - all_skull + - all_anvil + - trapped_chest + - comparator - daylight_detector - - REDSTONE_BLOCK - - HOPPER - - all_QUARTZ_BLOCK + - redstone_block + - hopper + - all_quartz_block - all_rail - - DROPPER - - ALL_TERRACOTTA - - ALL_STAINED_GLASS_PANE - - SLIME_BLOCK - - ALL_CARPET - - COAL_BLOCK - - END_STONE_BRICKS + - dropper + - all_terracotta + - all_stained_glass_pane + - slime_block + - all_carpet + - coal_block + - end_stone_bricks - barrel canCruise: true cruiseSkipBlocks: 4 diff --git a/modules/Movecraft/src/main/resources/types/1_14/Turret.craft b/modules/Movecraft/src/main/resources/types/1_14/Turret.craft index e1487bdf9..4827f7f29 100644 --- a/modules/Movecraft/src/main/resources/types/1_14/Turret.craft +++ b/modules/Movecraft/src/main/resources/types/1_14/Turret.craft @@ -2,22 +2,22 @@ name: Turret maxSize: 1000 minSize: 1 allowedBlocks: - - ALL_WOOD - - WATER - - LAVA - - ALL_LOG + - all_wood + - water + - lava + - all_log - all_planks - - GLASS - - DISPENSER - - NOTE_BLOCK - - ALL_BED + - glass + - dispenser + - note_block + - all_bed - sticky_piston - piston_head - light_gray_wool - all_slab - - BOOKSHELF - - TORCH - - FIRE + - bookshelf + - torch + - fire - oak_stairs - birch_stairs - jungle_stairs @@ -48,27 +48,27 @@ allowedBlocks: - dragon_egg - redstone_lamp - ender_chest - - TRIPWIRE_HOOK - - EMERALD_BLOCK - - BEACON - - FLOWER_POT - - all_SKULL - - all_ANVIL - - TRAPPED_CHEST - - COMPARATOR + - tripwire_hook + - emerald_block + - beacon + - flower_pot + - all_skull + - all_anvil + - trapped_chest + - comparator - daylight_detector - - REDSTONE_BLOCK - - HOPPER + - redstone_block + - hopper - all_rail - - DROPPER + - dropper - light_gray_terracotta - gray_terracotta - black_terracotta - - ALL_STAINED_GLASS_PANE - - SLIME_BLOCK - - ALL_CARPET - - COAL_BLOCK - - END_STONE_BRICKS + - all_stained_glass_pane + - slime_block + - all_carpet + - coal_block + - end_stone_bricks canFly: true diff --git a/modules/Movecraft/src/main/resources/types/1_14/airship.craft b/modules/Movecraft/src/main/resources/types/1_14/airship.craft index 91d538986..5699fe5e6 100644 --- a/modules/Movecraft/src/main/resources/types/1_14/airship.craft +++ b/modules/Movecraft/src/main/resources/types/1_14/airship.craft @@ -2,88 +2,88 @@ name: Airship maxSize: 5000 minSize: 1000 allowedBlocks: - - ALL_WOOD - - WATER - - LAVA - - ALL_LOG - - all_planks - - GLASS - - LAPIS_BLOCK - - DISPENSER - - NOTE_BLOCK - - ALL_BED - - sticky_piston - - piston_head - - all_wool - - GOLD_BLOCK - - IRON_BLOCK - - all_slab - - BOOKSHELF - - TORCH - - FIRE - - oak_stairs - - birch_stairs - - jungle_stairs - - spruce_stairs - - stone_brick_stairs - - quartz_stairs - - nether_brick_stairs - - chest - - redstone_wire - - diamond_block - - nether_brick_stairs - - furnace - - all_sign - - ladder - - all_door - - lever - - all_pressure_plate - - redstone_torch - - redstone_wall_torch - - all_button - - clay - - all_fence - - netherrack - - glowstone - - cake - - repeater - - all_stained_glass - - all_trapdoor - - all_stone_bricks - - iron_bars - - glass_pane - - all_fence_gate - - nether_bricks - - enchanting_table - - brewing_stand - - cauldron - - end_stone - - dragon_egg - - redstone_lamp - - ender_chest - - TRIPWIRE_HOOK - - EMERALD_BLOCK - - BEACON - - cobblestone_wall - - mossy_cobblestone_wall - - FLOWER_POT - - all_SKULL - - all_ANVIL - - TRAPPED_CHEST - - COMPARATOR - - daylight_detector - - REDSTONE_BLOCK - - HOPPER - - all_QUARTZ_BLOCK - - all_rail - - DROPPER - - ALL_TERRACOTTA - - ALL_STAINED_GLASS_PANE - - SLIME_BLOCK - - ALL_CARPET - - COAL_BLOCK - - END_STONE_BRICKS - - barrel + - all_wood + - water + - lava + - all_log + - all_planks + - glass + - lapis_block + - dispenser + - note_block + - all_bed + - sticky_piston + - piston_head + - all_wool + - gold_block + - iron_block + - all_slab + - bookshelf + - torch + - fire + - oak_stairs + - birch_stairs + - jungle_stairs + - spruce_stairs + - stone_brick_stairs + - quartz_stairs + - nether_brick_stairs + - chest + - redstone_wire + - diamond_block + - nether_brick_stairs + - furnace + - all_sign + - ladder + - all_door + - lever + - all_pressure_plate + - redstone_torch + - redstone_wall_torch + - all_button + - clay + - all_fence + - netherrack + - glowstone + - cake + - repeater + - all_stained_glass + - all_trapdoor + - all_stone_bricks + - iron_bars + - glass_pane + - all_fence_gate + - nether_bricks + - enchanting_table + - brewing_stand + - cauldron + - end_stone + - dragon_egg + - redstone_lamp + - ender_chest + - tripwire_hook + - emerald_block + - beacon + - cobblestone_wall + - mossy_cobblestone_wall + - flower_pot + - all_skull + - all_anvil + - trapped_chest + - comparator + - daylight_detector + - redstone_block + - hopper + - all_quartz_block + - all_rail + - dropper + - all_terracotta + - all_stained_glass_pane + - slime_block + - all_carpet + - coal_block + - end_stone_bricks + - barrel canCruise: true rotateAtMidpoint: true diff --git a/modules/Movecraft/src/main/resources/types/1_14/airskiff.craft b/modules/Movecraft/src/main/resources/types/1_14/airskiff.craft index 9c866fdee..bcc537f0b 100644 --- a/modules/Movecraft/src/main/resources/types/1_14/airskiff.craft +++ b/modules/Movecraft/src/main/resources/types/1_14/airskiff.craft @@ -2,75 +2,75 @@ name: Airskiff maxSize: 80 minSize: 10 allowedBlocks: - - ALL_WOOD - - WATER - - LAVA - - ALL_LOG - - all_planks - - GLASS - - DISPENSER - - NOTE_BLOCK - - ALL_BED - - sticky_piston - - piston_head - - all_wool - - all_slab - - BOOKSHELF - - TORCH - - FIRE - - oak_stairs - - birch_stairs - - jungle_stairs - - spruce_stairs - - chest - - redstone_wire - - nether_brick_stairs - - furnace - - all_sign - - ladder - - all_door - - lever - - all_pressure_plate - - redstone_torch - - redstone_wall_torch - - all_button - - all_fence - - netherrack - - glowstone - - cake - - repeater - - all_stained_glass - - all_trapdoor - - all_stone_bricks - - iron_bars - - glass_pane - - all_fence_gate - - enchanting_table - - brewing_stand - - cauldron - - dragon_egg - - redstone_lamp - - ender_chest - - TRIPWIRE_HOOK - - EMERALD_BLOCK - - BEACON - - FLOWER_POT - - all_SKULL - - all_ANVIL - - TRAPPED_CHEST - - COMPARATOR - - daylight_detector - - REDSTONE_BLOCK - - HOPPER - - all_QUARTZ_BLOCK - - all_rail - - DROPPER - - ALL_STAINED_GLASS_PANE - - SLIME_BLOCK - - ALL_CARPET - - COAL_BLOCK - - END_STONE_BRICKS - - barrel + - all_wood + - water + - lava + - all_log + - all_planks + - glass + - dispenser + - note_block + - all_bed + - sticky_piston + - piston_head + - all_wool + - all_slab + - bookshelf + - torch + - fire + - oak_stairs + - birch_stairs + - jungle_stairs + - spruce_stairs + - chest + - redstone_wire + - nether_brick_stairs + - furnace + - all_sign + - ladder + - all_door + - lever + - all_pressure_plate + - redstone_torch + - redstone_wall_torch + - all_button + - all_fence + - netherrack + - glowstone + - cake + - repeater + - all_stained_glass + - all_trapdoor + - all_stone_bricks + - iron_bars + - glass_pane + - all_fence_gate + - enchanting_table + - brewing_stand + - cauldron + - dragon_egg + - redstone_lamp + - ender_chest + - tripwire_hook + - emerald_block + - beacon + - flower_pot + - all_skull + - all_anvil + - trapped_chest + - comparator + - daylight_detector + - redstone_block + - hopper + - all_quartz_block + - all_rail + - dropper + - all_stained_glass_pane + - slime_block + - all_carpet + - coal_block + - end_stone_bricks + - barrel forbiddenBlocks: - PISTON_HEAD diff --git a/modules/Movecraft/src/main/resources/types/1_14/elevator.craft b/modules/Movecraft/src/main/resources/types/1_14/elevator.craft index 9377f8684..9ad552575 100644 --- a/modules/Movecraft/src/main/resources/types/1_14/elevator.craft +++ b/modules/Movecraft/src/main/resources/types/1_14/elevator.craft @@ -2,75 +2,75 @@ name: elevator maxSize: 1000 minSize: 10 allowedBlocks: - - ALL_WOOD - - WATER - - LAVA - - ALL_LOG - - all_planks - - GLASS - - DISPENSER - - NOTE_BLOCK - - ALL_BED - - sticky_piston - - piston_head - - all_wool - - all_slab - - BOOKSHELF - - TORCH - - FIRE - - oak_stairs - - birch_stairs - - jungle_stairs - - spruce_stairs - - chest - - redstone_wire - - nether_brick_stairs - - furnace - - all_sign - - ladder - - all_door - - lever - - all_pressure_plate - - redstone_torch - - redstone_wall_torch - - all_button - - all_fence - - netherrack - - glowstone - - cake - - repeater - - all_stained_glass - - all_trapdoor - - all_stone_bricks - - iron_bars - - glass_pane - - all_fence_gate - - enchanting_table - - brewing_stand - - cauldron - - dragon_egg - - redstone_lamp - - ender_chest - - TRIPWIRE_HOOK - - EMERALD_BLOCK - - BEACON - - FLOWER_POT - - all_SKULL - - all_ANVIL - - TRAPPED_CHEST - - COMPARATOR - - daylight_detector - - REDSTONE_BLOCK - - HOPPER - - all_QUARTZ_BLOCK - - all_rail - - DROPPER - - ALL_STAINED_GLASS_PANE - - SLIME_BLOCK - - ALL_CARPET - - COAL_BLOCK - - END_STONE_BRICKS - - barrel + - all_wood + - water + - lava + - all_log + - all_planks + - glass + - dispenser + - note_block + - all_bed + - sticky_piston + - piston_head + - all_wool + - all_slab + - bookshelf + - torch + - fire + - oak_stairs + - birch_stairs + - jungle_stairs + - spruce_stairs + - chest + - redstone_wire + - nether_brick_stairs + - furnace + - all_sign + - ladder + - all_door + - lever + - all_pressure_plate + - redstone_torch + - redstone_wall_torch + - all_button + - all_fence + - netherrack + - glowstone + - cake + - repeater + - all_stained_glass + - all_trapdoor + - all_stone_bricks + - iron_bars + - glass_pane + - all_fence_gate + - enchanting_table + - brewing_stand + - cauldron + - dragon_egg + - redstone_lamp + - ender_chest + - tripwire_hook + - emerald_block + - beacon + - flower_pot + - all_skull + - all_anvil + - trapped_chest + - comparator + - daylight_detector + - redstone_block + - hopper + - all_quartz_block + - all_rail + - dropper + - all_stained_glass_pane + - slime_block + - all_carpet + - coal_block + - end_stone_bricks + - barrel canFly: true canCruise: false collisionExplosion: 0.0 diff --git a/modules/Movecraft/src/main/resources/types/BigAirship.craft b/modules/Movecraft/src/main/resources/types/BigAirship.craft index 4283f3bdd..9281ae92a 100644 --- a/modules/Movecraft/src/main/resources/types/BigAirship.craft +++ b/modules/Movecraft/src/main/resources/types/BigAirship.craft @@ -2,87 +2,87 @@ name: BigAirship maxSize: 20000 minSize: 10000 allowedBlocks: -- ALL_WOOD - - WATER - - LAVA - - ALL_LOG - - all_planks - - GLASS - - LAPIS_BLOCK - - DISPENSER - - NOTE_BLOCK - - ALL_BED - - sticky_piston - - piston_head - - all_wool - - GOLD_BLOCK - - IRON_BLOCK - - all_slab - - BOOKSHELF - - TORCH - - FIRE - - oak_stairs - - birch_stairs - - jungle_stairs - - spruce_stairs - - stone_brick_stairs - - quartz_stairs - - nether_brick_stairs - - chest - - redstone_wire - - diamond_block - - nether_brick_stairs - - furnace - - all_sign - - ladder - - all_door - - lever - - all_pressure_plate - - redstone_torch - - redstone_wall_torch - - all_button - - clay - - all_fence - - netherrack - - glowstone - - cake - - repeater - - all_stained_glass - - all_trapdoor - - all_stone_bricks - - iron_bars - - glass_pane - - all_fence_gate - - nether_bricks - - enchanting_table - - brewing_stand - - cauldron - - end_stone - - dragon_egg - - redstone_lamp - - ender_chest - - TRIPWIRE_HOOK - - EMERALD_BLOCK - - BEACON - - cobblestone_wall - - mossy_cobblestone_wall - - FLOWER_POT - - all_SKULL - - all_ANVIL - - TRAPPED_CHEST - - COMPARATOR - - daylight_detector - - REDSTONE_BLOCK - - HOPPER - - all_QUARTZ_BLOCK - - all_rail - - DROPPER - - ALL_TERRACOTTA - - ALL_STAINED_GLASS_PANE - - SLIME_BLOCK - - ALL_CARPET - - COAL_BLOCK - - END_STONE_BRICKS + - all_wood + - water + - lava + - all_log + - all_planks + - glass + - lapis_block + - dispenser + - note_block + - all_bed + - sticky_piston + - piston_head + - all_wool + - gold_block + - iron_block + - all_slab + - bookshelf + - torch + - fire + - oak_stairs + - birch_stairs + - jungle_stairs + - spruce_stairs + - stone_brick_stairs + - quartz_stairs + - nether_brick_stairs + - chest + - redstone_wire + - diamond_block + - nether_brick_stairs + - furnace + - all_sign + - ladder + - all_door + - lever + - all_pressure_plate + - redstone_torch + - redstone_wall_torch + - all_button + - clay + - all_fence + - netherrack + - glowstone + - cake + - repeater + - all_stained_glass + - all_trapdoor + - all_stone_bricks + - iron_bars + - glass_pane + - all_fence_gate + - nether_bricks + - enchanting_table + - brewing_stand + - cauldron + - end_stone + - dragon_egg + - redstone_lamp + - ender_chest + - tripwire_hook + - emerald_block + - beacon + - cobblestone_wall + - mossy_cobblestone_wall + - flower_pot + - all_skull + - all_anvil + - trapped_chest + - comparator + - daylight_detector + - redstone_block + - hopper + - all_quartz_block + - all_rail + - dropper + - all_terracotta + - all_stained_glass_pane + - slime_block + - all_carpet + - coal_block + - end_stone_bricks canCruise: true rotateAtMidpoint: true blockRemoteRotate: true diff --git a/modules/Movecraft/src/main/resources/types/BigSubAirship.craft b/modules/Movecraft/src/main/resources/types/BigSubAirship.craft index 66f2d2ea4..b314fcdd3 100644 --- a/modules/Movecraft/src/main/resources/types/BigSubAirship.craft +++ b/modules/Movecraft/src/main/resources/types/BigSubAirship.craft @@ -2,86 +2,86 @@ name: BigSubAirship maxSize: 20000 minSize: 10000 allowedBlocks: -- ALL_WOOD - - LAVA - - ALL_LOG - - all_planks - - GLASS - - LAPIS_BLOCK - - DISPENSER - - NOTE_BLOCK - - ALL_BED - - sticky_piston - - piston_head - - all_wool - - GOLD_BLOCK - - IRON_BLOCK - - all_slab - - BOOKSHELF - - TORCH - - FIRE - - oak_stairs - - birch_stairs - - jungle_stairs - - spruce_stairs - - stone_brick_stairs - - quartz_stairs - - nether_brick_stairs - - chest - - redstone_wire - - diamond_block - - nether_brick_stairs - - furnace - - all_sign - - ladder - - all_door - - lever - - all_pressure_plate - - redstone_torch - - redstone_wall_torch - - all_button - - clay - - all_fence - - netherrack - - glowstone - - cake - - repeater - - all_stained_glass - - all_trapdoor - - all_stone_bricks - - iron_bars - - glass_pane - - all_fence_gate - - nether_bricks - - enchanting_table - - brewing_stand - - cauldron - - end_stone - - dragon_egg - - redstone_lamp - - ender_chest - - TRIPWIRE_HOOK - - EMERALD_BLOCK - - BEACON - - cobblestone_wall - - mossy_cobblestone_wall - - FLOWER_POT - - all_SKULL - - all_ANVIL - - TRAPPED_CHEST - - COMPARATOR - - daylight_detector - - REDSTONE_BLOCK - - HOPPER - - all_QUARTZ_BLOCK - - all_rail - - DROPPER - - ALL_TERRACOTTA - - ALL_STAINED_GLASS_PANE - - SLIME_BLOCK - - ALL_CARPET - - COAL_BLOCK - - END_STONE_BRICKS + - all_wood + - lava + - all_log + - all_planks + - glass + - lapis_block + - dispenser + - note_block + - all_bed + - sticky_piston + - piston_head + - all_wool + - gold_block + - iron_block + - all_slab + - bookshelf + - torch + - fire + - oak_stairs + - birch_stairs + - jungle_stairs + - spruce_stairs + - stone_brick_stairs + - quartz_stairs + - nether_brick_stairs + - chest + - redstone_wire + - diamond_block + - nether_brick_stairs + - furnace + - all_sign + - ladder + - all_door + - lever + - all_pressure_plate + - redstone_torch + - redstone_wall_torch + - all_button + - clay + - all_fence + - netherrack + - glowstone + - cake + - repeater + - all_stained_glass + - all_trapdoor + - all_stone_bricks + - iron_bars + - glass_pane + - all_fence_gate + - nether_bricks + - enchanting_table + - brewing_stand + - cauldron + - end_stone + - dragon_egg + - redstone_lamp + - ender_chest + - tripwire_hook + - emerald_block + - beacon + - cobblestone_wall + - mossy_cobblestone_wall + - flower_pot + - all_skull + - all_anvil + - trapped_chest + - comparator + - daylight_detector + - redstone_block + - hopper + - all_quartz_block + - all_rail + - dropper + - all_terracotta + - all_stained_glass_pane + - slime_block + - all_carpet + - coal_block + - end_stone_bricks canCruise: true rotateAtMidpoint: true blockRemoteRotate: true diff --git a/modules/Movecraft/src/main/resources/types/Ship.craft b/modules/Movecraft/src/main/resources/types/Ship.craft index 4e26be709..8fc0fc225 100644 --- a/modules/Movecraft/src/main/resources/types/Ship.craft +++ b/modules/Movecraft/src/main/resources/types/Ship.craft @@ -2,24 +2,24 @@ name: Ship maxSize: 100000 minSize: 10 allowedBlocks: -- ALL_WOOD - - LAVA - - ALL_LOG + - all_wood + - lava + - all_log - all_planks - - GLASS - - LAPIS_BLOCK - - DISPENSER - - NOTE_BLOCK - - ALL_BED + - glass + - lapis_block + - dispenser + - note_block + - all_bed - sticky_piston - piston_head - all_wool - - GOLD_BLOCK - - IRON_BLOCK + - gold_block + - iron_block - all_slab - - BOOKSHELF - - TORCH - - FIRE + - bookshelf + - torch + - fire - oak_stairs - birch_stairs - jungle_stairs @@ -60,28 +60,28 @@ allowedBlocks: - dragon_egg - redstone_lamp - ender_chest - - TRIPWIRE_HOOK - - EMERALD_BLOCK - - BEACON + - tripwire_hook + - emerald_block + - beacon - cobblestone_wall - mossy_cobblestone_wall - - FLOWER_POT - - all_SKULL - - all_ANVIL - - TRAPPED_CHEST - - COMPARATOR + - flower_pot + - all_skull + - all_anvil + - trapped_chest + - comparator - daylight_detector - - REDSTONE_BLOCK - - HOPPER - - all_QUARTZ_BLOCK + - redstone_block + - hopper + - all_quartz_block - all_rail - - DROPPER - - ALL_TERRACOTTA - - ALL_STAINED_GLASS_PANE - - SLIME_BLOCK - - ALL_CARPET - - COAL_BLOCK - - END_STONE_BRICKS + - dropper + - all_terracotta + - all_stained_glass_pane + - slime_block + - all_carpet + - coal_block + - end_stone_bricks canCruise: true cruiseSkipBlocks: 4 canFly: false diff --git a/modules/Movecraft/src/main/resources/types/SubAirship.craft b/modules/Movecraft/src/main/resources/types/SubAirship.craft index 3d4904282..2c844f361 100644 --- a/modules/Movecraft/src/main/resources/types/SubAirship.craft +++ b/modules/Movecraft/src/main/resources/types/SubAirship.craft @@ -2,86 +2,86 @@ name: SubAirship maxSize: 5000 minSize: 1000 allowedBlocks: -- ALL_WOOD - - LAVA - - ALL_LOG - - all_planks - - GLASS - - LAPIS_BLOCK - - DISPENSER - - NOTE_BLOCK - - ALL_BED - - sticky_piston - - piston_head - - all_wool - - GOLD_BLOCK - - IRON_BLOCK - - all_slab - - BOOKSHELF - - TORCH - - FIRE - - oak_stairs - - birch_stairs - - jungle_stairs - - spruce_stairs - - stone_brick_stairs - - quartz_stairs - - nether_brick_stairs - - chest - - redstone_wire - - diamond_block - - nether_brick_stairs - - furnace - - all_sign - - ladder - - all_door - - lever - - all_pressure_plate - - redstone_torch - - redstone_wall_torch - - all_button - - clay - - all_fence - - netherrack - - glowstone - - cake - - repeater - - all_stained_glass - - all_trapdoor - - all_stone_bricks - - iron_bars - - glass_pane - - all_fence_gate - - nether_bricks - - enchanting_table - - brewing_stand - - cauldron - - end_stone - - dragon_egg - - redstone_lamp - - ender_chest - - TRIPWIRE_HOOK - - EMERALD_BLOCK - - BEACON - - cobblestone_wall - - mossy_cobblestone_wall - - FLOWER_POT - - all_SKULL - - all_ANVIL - - TRAPPED_CHEST - - COMPARATOR - - daylight_detector - - REDSTONE_BLOCK - - HOPPER - - all_QUARTZ_BLOCK - - all_rail - - DROPPER - - ALL_TERRACOTTA - - ALL_STAINED_GLASS_PANE - - SLIME_BLOCK - - ALL_CARPET - - COAL_BLOCK - - END_STONE_BRICKS + - all_wood + - lava + - all_log + - all_planks + - glass + - lapis_block + - dispenser + - note_block + - all_bed + - sticky_piston + - piston_head + - all_wool + - gold_block + - iron_block + - all_slab + - bookshelf + - torch + - fire + - oak_stairs + - birch_stairs + - jungle_stairs + - spruce_stairs + - stone_brick_stairs + - quartz_stairs + - nether_brick_stairs + - chest + - redstone_wire + - diamond_block + - nether_brick_stairs + - furnace + - all_sign + - ladder + - all_door + - lever + - all_pressure_plate + - redstone_torch + - redstone_wall_torch + - all_button + - clay + - all_fence + - netherrack + - glowstone + - cake + - repeater + - all_stained_glass + - all_trapdoor + - all_stone_bricks + - iron_bars + - glass_pane + - all_fence_gate + - nether_bricks + - enchanting_table + - brewing_stand + - cauldron + - end_stone + - dragon_egg + - redstone_lamp + - ender_chest + - tripwire_hook + - emerald_block + - beacon + - cobblestone_wall + - mossy_cobblestone_wall + - flower_pot + - all_skull + - all_anvil + - trapped_chest + - comparator + - daylight_detector + - redstone_block + - hopper + - all_quartz_block + - all_rail + - dropper + - all_terracotta + - all_stained_glass_pane + - slime_block + - all_carpet + - coal_block + - end_stone_bricks canCruise: true rotateAtMidpoint: true cruiseSkipBlocks: 4 diff --git a/modules/Movecraft/src/main/resources/types/Submarine.craft b/modules/Movecraft/src/main/resources/types/Submarine.craft index 4da6dc66d..a288c5a30 100644 --- a/modules/Movecraft/src/main/resources/types/Submarine.craft +++ b/modules/Movecraft/src/main/resources/types/Submarine.craft @@ -2,25 +2,25 @@ name: Submarine maxSize: 100000 minSize: 10 allowedBlocks: -- ALL_WOOD - - WATER - - LAVA - - ALL_LOG + - all_wood + - water + - lava + - all_log - all_planks - - GLASS - - LAPIS_BLOCK - - DISPENSER - - NOTE_BLOCK - - ALL_BED + - glass + - lapis_block + - dispenser + - note_block + - all_bed - sticky_piston - piston_head - all_wool - - GOLD_BLOCK - - IRON_BLOCK + - gold_block + - iron_block - all_slab - - BOOKSHELF - - TORCH - - FIRE + - bookshelf + - torch + - fire - oak_stairs - birch_stairs - jungle_stairs @@ -61,28 +61,28 @@ allowedBlocks: - dragon_egg - redstone_lamp - ender_chest - - TRIPWIRE_HOOK - - EMERALD_BLOCK - - BEACON + - tripwire_hook + - emerald_block + - beacon - cobblestone_wall - mossy_cobblestone_wall - - FLOWER_POT - - all_SKULL - - all_ANVIL - - TRAPPED_CHEST - - COMPARATOR + - flower_pot + - all_skull + - all_anvil + - trapped_chest + - comparator - daylight_detector - - REDSTONE_BLOCK - - HOPPER - - all_QUARTZ_BLOCK + - redstone_block + - hopper + - all_quartz_block - all_rail - - DROPPER - - ALL_TERRACOTTA - - ALL_STAINED_GLASS_PANE - - SLIME_BLOCK - - ALL_CARPET - - COAL_BLOCK - - END_STONE_BRICKS + - dropper + - all_terracotta + - all_stained_glass_pane + - slime_block + - all_carpet + - coal_block + - end_stone_bricks canCruise: true cruiseSkipBlocks: 4 canFly: false diff --git a/modules/Movecraft/src/main/resources/types/Turret.craft b/modules/Movecraft/src/main/resources/types/Turret.craft index 625064c53..c1eb4a14a 100644 --- a/modules/Movecraft/src/main/resources/types/Turret.craft +++ b/modules/Movecraft/src/main/resources/types/Turret.craft @@ -2,22 +2,22 @@ name: Turret maxSize: 1000 minSize: 1 allowedBlocks: - - ALL_WOOD - - WATER - - LAVA - - ALL_LOG + - all_wood + - water + - lava + - all_log - all_planks - - GLASS - - DISPENSER - - NOTE_BLOCK - - ALL_BED + - glass + - dispenser + - note_block + - all_bed - sticky_piston - piston_head - light_gray_wool - all_slab - - BOOKSHELF - - TORCH - - FIRE + - bookshelf + - torch + - fire - oak_stairs - birch_stairs - jungle_stairs @@ -48,27 +48,27 @@ allowedBlocks: - dragon_egg - redstone_lamp - ender_chest - - TRIPWIRE_HOOK - - EMERALD_BLOCK - - BEACON - - FLOWER_POT - - all_SKULL - - all_ANVIL - - TRAPPED_CHEST - - COMPARATOR + - tripwire_hook + - emerald_block + - beacon + - flower_pot + - all_skull + - all_anvil + - trapped_chest + - comparator - daylight_detector - - REDSTONE_BLOCK - - HOPPER + - redstone_block + - hopper - all_rail - - DROPPER + - dropper - light_gray_terracotta - gray_terracotta - black_terracotta - - ALL_STAINED_GLASS_PANE - - SLIME_BLOCK - - ALL_CARPET - - COAL_BLOCK - - END_STONE_BRICKS + - all_stained_glass_pane + - slime_block + - all_carpet + - coal_block + - end_stone_bricks forbiddenBlocks: - PISTON_HEAD diff --git a/modules/Movecraft/src/main/resources/types/airship.craft b/modules/Movecraft/src/main/resources/types/airship.craft index b596ddbd9..d2c3be7e3 100644 --- a/modules/Movecraft/src/main/resources/types/airship.craft +++ b/modules/Movecraft/src/main/resources/types/airship.craft @@ -2,87 +2,87 @@ name: Airship maxSize: 5000 minSize: 1000 allowedBlocks: -- ALL_WOOD - - WATER - - LAVA - - ALL_LOG - - all_planks - - GLASS - - LAPIS_BLOCK - - DISPENSER - - NOTE_BLOCK - - ALL_BED - - sticky_piston - - piston_head - - all_wool - - GOLD_BLOCK - - IRON_BLOCK - - all_slab - - BOOKSHELF - - TORCH - - FIRE - - oak_stairs - - birch_stairs - - jungle_stairs - - spruce_stairs - - stone_brick_stairs - - quartz_stairs - - nether_brick_stairs - - chest - - redstone_wire - - diamond_block - - nether_brick_stairs - - furnace - - all_sign - - ladder - - all_door - - lever - - all_pressure_plate - - redstone_torch - - redstone_wall_torch - - all_button - - clay - - all_fence - - netherrack - - glowstone - - cake - - repeater - - all_stained_glass - - all_trapdoor - - all_stone_bricks - - iron_bars - - glass_pane - - all_fence_gate - - nether_bricks - - enchanting_table - - brewing_stand - - cauldron - - end_stone - - dragon_egg - - redstone_lamp - - ender_chest - - TRIPWIRE_HOOK - - EMERALD_BLOCK - - BEACON - - cobblestone_wall - - mossy_cobblestone_wall - - FLOWER_POT - - all_SKULL - - all_ANVIL - - TRAPPED_CHEST - - COMPARATOR - - daylight_detector - - REDSTONE_BLOCK - - HOPPER - - all_QUARTZ_BLOCK - - all_rail - - DROPPER - - ALL_TERRACOTTA - - ALL_STAINED_GLASS_PANE - - SLIME_BLOCK - - ALL_CARPET - - COAL_BLOCK - - END_STONE_BRICKS + - all_wood + - water + - lava + - all_log + - all_planks + - glass + - lapis_block + - dispenser + - note_block + - all_bed + - sticky_piston + - piston_head + - all_wool + - gold_block + - iron_block + - all_slab + - bookshelf + - torch + - fire + - oak_stairs + - birch_stairs + - jungle_stairs + - spruce_stairs + - stone_brick_stairs + - quartz_stairs + - nether_brick_stairs + - chest + - redstone_wire + - diamond_block + - nether_brick_stairs + - furnace + - all_sign + - ladder + - all_door + - lever + - all_pressure_plate + - redstone_torch + - redstone_wall_torch + - all_button + - clay + - all_fence + - netherrack + - glowstone + - cake + - repeater + - all_stained_glass + - all_trapdoor + - all_stone_bricks + - iron_bars + - glass_pane + - all_fence_gate + - nether_bricks + - enchanting_table + - brewing_stand + - cauldron + - end_stone + - dragon_egg + - redstone_lamp + - ender_chest + - tripwire_hook + - emerald_block + - beacon + - cobblestone_wall + - mossy_cobblestone_wall + - flower_pot + - all_skull + - all_anvil + - trapped_chest + - comparator + - daylight_detector + - redstone_block + - hopper + - all_quartz_block + - all_rail + - dropper + - all_terracotta + - all_stained_glass_pane + - slime_block + - all_carpet + - coal_block + - end_stone_bricks canCruise: true rotateAtMidpoint: true diff --git a/modules/Movecraft/src/main/resources/types/airskiff.craft b/modules/Movecraft/src/main/resources/types/airskiff.craft index d9771c0b7..b365dfba6 100644 --- a/modules/Movecraft/src/main/resources/types/airskiff.craft +++ b/modules/Movecraft/src/main/resources/types/airskiff.craft @@ -2,76 +2,76 @@ name: Airskiff maxSize: 80 minSize: 10 allowedBlocks: -- ALL_WOOD - - WATER - - LAVA - - ALL_LOG - - all_planks - - GLASS - - DISPENSER - - NOTE_BLOCK - - ALL_BED - - sticky_piston - - piston_head - - all_wool - - all_slab - - BOOKSHELF - - TORCH - - FIRE - - oak_stairs - - birch_stairs - - jungle_stairs - - spruce_stairs - - chest - - redstone_wire - - nether_brick_stairs - - furnace - - all_sign - - ladder - - all_door - - lever - - all_pressure_plate - - redstone_torch - - redstone_wall_torch - - all_button - - all_fence - - netherrack - - glowstone - - cake - - repeater - - all_stained_glass - - all_trapdoor - - all_stone_bricks - - iron_bars - - glass_pane - - all_fence_gate - - enchanting_table - - brewing_stand - - cauldron - - dragon_egg - - redstone_lamp - - ender_chest - - TRIPWIRE_HOOK - - EMERALD_BLOCK - - BEACON - - FLOWER_POT - - all_SKULL - - all_ANVIL - - TRAPPED_CHEST - - COMPARATOR - - daylight_detector - - REDSTONE_BLOCK - - HOPPER - - all_QUARTZ_BLOCK - - all_rail - - DROPPER - - ALL_STAINED_GLASS_PANE - - SLIME_BLOCK - - ALL_CARPET - - COAL_BLOCK - - END_STONE_BRICKS + - all_wood + - water + - lava + - all_log + - all_planks + - glass + - dispenser + - note_block + - all_bed + - sticky_piston + - piston_head + - all_wool + - all_slab + - bookshelf + - torch + - fire + - oak_stairs + - birch_stairs + - jungle_stairs + - spruce_stairs + - chest + - redstone_wire + - nether_brick_stairs + - furnace + - all_sign + - ladder + - all_door + - lever + - all_pressure_plate + - redstone_torch + - redstone_wall_torch + - all_button + - all_fence + - netherrack + - glowstone + - cake + - repeater + - all_stained_glass + - all_trapdoor + - all_stone_bricks + - iron_bars + - glass_pane + - all_fence_gate + - enchanting_table + - brewing_stand + - cauldron + - dragon_egg + - redstone_lamp + - ender_chest + - tripwire_hook + - emerald_block + - beacon + - flower_pot + - all_skull + - all_anvil + - trapped_chest + - comparator + - daylight_detector + - redstone_block + - hopper + - all_quartz_block + - all_rail + - dropper + - all_stained_glass_pane + - slime_block + - all_carpet + - coal_block + - end_stone_bricks forbiddenBlocks: - - PISTON_HEAD + - piston_head canFly: true rotateAtMidpoint: true @@ -98,21 +98,21 @@ flyblocks: all_wool: #wool represents lift - 50.0 - 100.0 - [CHEST,TRAPPED_CHEST]: # limit chests to make big airships important for merchant missions + [chest,trapped_chest]: # limit chests to make big airships important for merchant missions - 0.0 - N2 - [DISPENSER,HOPPER]: # dispensers and hoppers can be used for inventory too, so limit them as well + [dispenser,hopper]: # dispensers and hoppers can be used for inventory too, so limit them as well - 0.0 - 6.0 - REDSTONE_BLOCK: # redstone represents engines + redstone_block: # redstone represents engines - 8.0 - 100.0 - ANVIL: # anvils are OP armor, so limit it + anvil: # anvils are OP armor, so limit it - 0.0 - 1.0 - OBSIDIAN: # so is obsidian + obsidian: # so is obsidian - 0.0 - 1.0 - WATER: # so is water + water: # so is water - 0.0 - 1.0 diff --git a/modules/Movecraft/src/main/resources/types/elevator.craft b/modules/Movecraft/src/main/resources/types/elevator.craft index 97934e00a..e2dcdee49 100644 --- a/modules/Movecraft/src/main/resources/types/elevator.craft +++ b/modules/Movecraft/src/main/resources/types/elevator.craft @@ -2,22 +2,22 @@ name: elevator maxSize: 1000 minSize: 10 allowedBlocks: -- ALL_WOOD - - WATER - - LAVA - - ALL_LOG + - all_wood + - water + - lava + - all_log - all_planks - - GLASS - - DISPENSER - - NOTE_BLOCK - - ALL_BED + - glass + - dispenser + - note_block + - all_bed - sticky_piston - piston_head - all_wool - all_slab - - BOOKSHELF - - TORCH - - FIRE + - bookshelf + - torch + - fire - oak_stairs - birch_stairs - jungle_stairs @@ -51,25 +51,25 @@ allowedBlocks: - dragon_egg - redstone_lamp - ender_chest - - TRIPWIRE_HOOK - - EMERALD_BLOCK - - BEACON - - FLOWER_POT - - SKULL - - all_ANVIL - - TRAPPED_CHEST - - COMPARATOR + - tripwire_hook + - emerald_block + - beacon + - flower_pot + - skull + - all_anvil + - trapped_chest + - comparator - daylight_detector - - REDSTONE_BLOCK - - HOPPER - - all_QUARTZ_BLOCK + - redstone_block + - hopper + - all_quartz_block - all_rail - - DROPPER - - ALL_STAINED_GLASS_PANE - - SLIME_BLOCK - - ALL_CARPET - - COAL_BLOCK - - END_STONE_BRICKS + - dropper + - all_stained_glass_pane + - slime_block + - all_carpet + - coal_block + - end_stone_bricks canFly: true canCruise: false collisionExplosion: 0.0 From 990475d6e4462236ebaf6935e9d84503a0ad2f49 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Tue, 4 Feb 2020 19:23:22 +0100 Subject: [PATCH 118/304] Improved translation in world handlers --- .../movecraft/compat/v1_10_R1/IWorldHandler.java | 8 ++------ .../movecraft/compat/v1_11_R1/IWorldHandler.java | 14 +++++--------- .../movecraft/compat/v1_12_R1/IWorldHandler.java | 7 ++----- .../movecraft/compat/v1_13_R2/IWorldHandler.java | 7 ++----- .../movecraft/compat/v1_14_R1/IWorldHandler.java | 7 ++----- .../movecraft/compat/v1_15_R1/IWorldHandler.java | 10 +++------- .../movecraft/compat/v1_9_R2/IWorldHandler.java | 7 ++----- 7 files changed, 18 insertions(+), 42 deletions(-) diff --git a/modules/v1_10_R1/src/main/java/net/countercraft/movecraft/compat/v1_10_R1/IWorldHandler.java b/modules/v1_10_R1/src/main/java/net/countercraft/movecraft/compat/v1_10_R1/IWorldHandler.java index a75a8e927..ce3a51d33 100644 --- a/modules/v1_10_R1/src/main/java/net/countercraft/movecraft/compat/v1_10_R1/IWorldHandler.java +++ b/modules/v1_10_R1/src/main/java/net/countercraft/movecraft/compat/v1_10_R1/IWorldHandler.java @@ -11,7 +11,6 @@ import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.craftbukkit.v1_10_R1.CraftWorld; -import org.bukkit.craftbukkit.v1_10_R1.block.CraftBlockState; import org.bukkit.craftbukkit.v1_10_R1.entity.CraftPlayer; import org.bukkit.craftbukkit.v1_10_R1.util.CraftMagicNumbers; import org.bukkit.entity.Player; @@ -188,14 +187,11 @@ public void translateCraft(@NotNull Craft craft, @NotNull MovecraftLocation disp //TODO: Simplify //TODO: go by chunks //TODO: Don't move unnecessary blocks - //get the blocks + //get the blocks and translate the positions List blockData = new ArrayList<>(); - for(BlockPosition position : positions){ - blockData.add(nativeWorld.getType(position)); - } - //translate the positions List newPositions = new ArrayList<>(); for(BlockPosition position : positions){ + blockData.add(nativeWorld.getType(position)); newPositions.add(position.a(translateVector)); } //create the new block diff --git a/modules/v1_11_R1/src/main/java/net/countercraft/movecraft/compat/v1_11_R1/IWorldHandler.java b/modules/v1_11_R1/src/main/java/net/countercraft/movecraft/compat/v1_11_R1/IWorldHandler.java index a558cf156..f9d39b66b 100644 --- a/modules/v1_11_R1/src/main/java/net/countercraft/movecraft/compat/v1_11_R1/IWorldHandler.java +++ b/modules/v1_11_R1/src/main/java/net/countercraft/movecraft/compat/v1_11_R1/IWorldHandler.java @@ -1,17 +1,16 @@ package net.countercraft.movecraft.compat.v1_11_R1; -import net.countercraft.movecraft.config.Settings; -import net.countercraft.movecraft.utils.MathUtils; import net.countercraft.movecraft.MovecraftLocation; import net.countercraft.movecraft.Rotation; -import net.countercraft.movecraft.utils.CollectionUtils; import net.countercraft.movecraft.WorldHandler; +import net.countercraft.movecraft.config.Settings; import net.countercraft.movecraft.craft.Craft; +import net.countercraft.movecraft.utils.CollectionUtils; +import net.countercraft.movecraft.utils.MathUtils; import net.minecraft.server.v1_11_R1.*; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.craftbukkit.v1_11_R1.CraftWorld; -import org.bukkit.craftbukkit.v1_11_R1.block.CraftBlockState; import org.bukkit.craftbukkit.v1_11_R1.entity.CraftPlayer; import org.bukkit.craftbukkit.v1_11_R1.util.CraftMagicNumbers; import org.bukkit.entity.Player; @@ -188,14 +187,11 @@ public void translateCraft(@NotNull Craft craft, @NotNull MovecraftLocation disp //TODO: Simplify //TODO: go by chunks //TODO: Don't move unnecessary blocks - //get the blocks + //get the blocks and translate the positions List blockData = new ArrayList<>(); - for(BlockPosition position : positions){ - blockData.add(nativeWorld.getType(position)); - } - //translate the positions List newPositions = new ArrayList<>(); for(BlockPosition position : positions){ + blockData.add(nativeWorld.getType(position)); newPositions.add(position.a(translateVector)); } //create the new block diff --git a/modules/v1_12_R1/src/main/java/net/countercraft/movecraft/compat/v1_12_R1/IWorldHandler.java b/modules/v1_12_R1/src/main/java/net/countercraft/movecraft/compat/v1_12_R1/IWorldHandler.java index e0af44666..dc848b696 100644 --- a/modules/v1_12_R1/src/main/java/net/countercraft/movecraft/compat/v1_12_R1/IWorldHandler.java +++ b/modules/v1_12_R1/src/main/java/net/countercraft/movecraft/compat/v1_12_R1/IWorldHandler.java @@ -192,14 +192,11 @@ public void translateCraft(@NotNull Craft craft, @NotNull MovecraftLocation disp //TODO: Simplify //TODO: go by chunks //TODO: Don't move unnecessary blocks - //get the blocks + //get the blocks and translate the positions List blockData = new ArrayList<>(); - for(BlockPosition position : positions){ - blockData.add(nativeWorld.getType(position)); - } - //translate the positions List newPositions = new ArrayList<>(); for(BlockPosition position : positions){ + blockData.add(nativeWorld.getType(position)); newPositions.add(position.a(translateVector)); } //create the new block diff --git a/modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/IWorldHandler.java b/modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/IWorldHandler.java index d86969a85..e4da1ff9e 100644 --- a/modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/IWorldHandler.java +++ b/modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/IWorldHandler.java @@ -176,14 +176,11 @@ public void translateCraft(@NotNull Craft craft, @NotNull MovecraftLocation disp //TODO: Simplify //TODO: go by chunks //TODO: Don't move unnecessary blocks - //get the blocks + //get the blocks and translate the positions List blockData = new ArrayList<>(); - for(BlockPosition position : positions){ - blockData.add(nativeWorld.getType(position)); - } - //translate the positions List newPositions = new ArrayList<>(); for(BlockPosition position : positions){ + blockData.add(nativeWorld.getType(position)); newPositions.add(position.a(translateVector)); } Map redstoneComponents = new HashMap<>(); diff --git a/modules/v1_14_R1/src/main/java/net/countercraft/movecraft/compat/v1_14_R1/IWorldHandler.java b/modules/v1_14_R1/src/main/java/net/countercraft/movecraft/compat/v1_14_R1/IWorldHandler.java index ac6dde694..0e9b65ba3 100644 --- a/modules/v1_14_R1/src/main/java/net/countercraft/movecraft/compat/v1_14_R1/IWorldHandler.java +++ b/modules/v1_14_R1/src/main/java/net/countercraft/movecraft/compat/v1_14_R1/IWorldHandler.java @@ -175,14 +175,11 @@ public void translateCraft(@NotNull Craft craft, @NotNull MovecraftLocation disp //TODO: Simplify //TODO: go by chunks //TODO: Don't move unnecessary blocks - //get the blocks + //get the blocks and translate the positions List blockData = new ArrayList<>(); - for(BlockPosition position : positions){ - blockData.add(nativeWorld.getType(position)); - } - //translate the positions List newPositions = new ArrayList<>(); for(BlockPosition position : positions){ + blockData.add(nativeWorld.getType(position)); newPositions.add(position.a(translateVector)); } Map redstoneComponents = new HashMap<>(); diff --git a/modules/v1_15_R1/src/main/java/net/countercraft/movecraft/compat/v1_15_R1/IWorldHandler.java b/modules/v1_15_R1/src/main/java/net/countercraft/movecraft/compat/v1_15_R1/IWorldHandler.java index c231b3bca..32308b7d0 100644 --- a/modules/v1_15_R1/src/main/java/net/countercraft/movecraft/compat/v1_15_R1/IWorldHandler.java +++ b/modules/v1_15_R1/src/main/java/net/countercraft/movecraft/compat/v1_15_R1/IWorldHandler.java @@ -184,16 +184,12 @@ public void translateCraft(@NotNull Craft craft, @NotNull MovecraftLocation disp //TODO: Simplify //TODO: go by chunks //TODO: Don't move unnecessary blocks - //get the blocks + //get the blocks and translate the positions List blockData = new ArrayList<>(); - for(BlockPosition position : positions){ - blockData.add(nativeWorld.getType(position)); - } - //translate the positions List newPositions = new ArrayList<>(); for(BlockPosition position : positions){ - BlockPosition newPos = position.a(translateVector); - newPositions.add(newPos); + blockData.add(nativeWorld.getType(position)); + newPositions.add(position.a(translateVector)); } Map redstoneComponents = new HashMap<>(); //create the new block diff --git a/modules/v1_9_R2/src/main/java/net/countercraft/movecraft/compat/v1_9_R2/IWorldHandler.java b/modules/v1_9_R2/src/main/java/net/countercraft/movecraft/compat/v1_9_R2/IWorldHandler.java index 87333d847..cb952b0b2 100644 --- a/modules/v1_9_R2/src/main/java/net/countercraft/movecraft/compat/v1_9_R2/IWorldHandler.java +++ b/modules/v1_9_R2/src/main/java/net/countercraft/movecraft/compat/v1_9_R2/IWorldHandler.java @@ -197,14 +197,11 @@ public void translateCraft(@NotNull Craft craft, @NotNull MovecraftLocation disp //TODO: Simplify //TODO: go by chunks //TODO: Don't move unnecessary blocks - //get the blocks + //get the blocks and translate the positions List blockData = new ArrayList<>(); - for(BlockPosition position : positions){ - blockData.add(nativeWorld.getType(position)); - } - //translate the positions List newPositions = new ArrayList<>(); for(BlockPosition position : positions){ + blockData.add(nativeWorld.getType(position)); newPositions.add(position.a(translateVector)); } //create the new block From f2084ca737cef47b82834c363d7f9dcb6173ca28 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Fri, 7 Feb 2020 21:15:06 +0100 Subject: [PATCH 119/304] Fixed waterlogging and added 1.8.8-9 support --- modules/Movecraft/pom.xml | 6 + .../movecraft/async/AsyncManager.java | 69 --- .../async/rotation/RotationTask.java | 11 +- .../movecraft/utils/WaterlogUtils.java | 22 +- .../countercraft/movecraft/craft/Craft.java | 7 +- modules/v1_8_R3/pom.xml | 57 +++ .../compat/v1_8_R3/IWorldHandler.java | 408 ++++++++++++++++++ .../compat/v1_8_R3/NextTickProvider.java | 80 ++++ .../compat/v1_9_R2/NextTickProvider.java | 25 +- pom.xml | 4 + 10 files changed, 600 insertions(+), 89 deletions(-) create mode 100644 modules/v1_8_R3/pom.xml create mode 100644 modules/v1_8_R3/src/main/java/net/countercraft/movecraft/compat/v1_8_R3/IWorldHandler.java create mode 100644 modules/v1_8_R3/src/main/java/net/countercraft/movecraft/compat/v1_8_R3/NextTickProvider.java diff --git a/modules/Movecraft/pom.xml b/modules/Movecraft/pom.xml index af02c3cea..74f561d95 100644 --- a/modules/Movecraft/pom.xml +++ b/modules/Movecraft/pom.xml @@ -54,6 +54,12 @@ v1_13_R2 jar + + net.countercraft + movecraft-v1_8_R3 + v1_8_R3 + jar + net.countercraft movecraft-v1_9_R2 diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java index 71a718123..d35a9044c 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java @@ -33,17 +33,10 @@ import net.countercraft.movecraft.mapUpdater.MapUpdateManager; import net.countercraft.movecraft.mapUpdater.update.BlockCreateCommand; import net.countercraft.movecraft.mapUpdater.update.UpdateCommand; -import net.countercraft.movecraft.mapUpdater.update.WaterlogUpdateCommand; import net.countercraft.movecraft.utils.*; import org.bukkit.*; import org.bukkit.block.Block; import org.bukkit.block.BlockFace; -import org.bukkit.block.data.Bisected; -import org.bukkit.block.data.BlockData; -import org.bukkit.block.data.Waterlogged; -import org.bukkit.block.data.type.Slab; -import org.bukkit.block.data.type.Stairs; -import org.bukkit.block.data.type.TrapDoor; import org.bukkit.entity.Player; import org.bukkit.entity.SmallFireball; import org.bukkit.entity.TNTPrimed; @@ -55,9 +48,6 @@ import java.util.concurrent.LinkedBlockingQueue; import java.util.logging.Level; -import static net.countercraft.movecraft.utils.WaterlogUtils.isWaterlogged; -import static net.countercraft.movecraft.utils.WaterlogUtils.waterToSides; - @SuppressWarnings("deprecation") public class AsyncManager extends BukkitRunnable { //private static AsyncManager instance = new AsyncManager(); @@ -1095,9 +1085,6 @@ public void run() { processFadingBlocks(); processDetection(); processAlgorithmQueue(); - if (!Settings.IsLegacy){ - processWaterlogging(); - } //processScheduledBlockChanges(); // if(Settings.CompatibilityMode==false) // FastBlockChanger.getInstance().run(); @@ -1120,62 +1107,6 @@ public void run() { } - private void processWaterlogging() { - if (waterlogCheckQueue.isEmpty()) - return; - final Set updates = new HashSet<>(); - - final Craft craft = waterlogCheckQueue.poll(); - for (MovecraftLocation location : craft.getHitBox()){ - final BlockData bData = location.toBukkit(craft.getW()).getBlock().getBlockData(); - if (!(bData instanceof Waterlogged)){ - continue; - } - final Waterlogged wLog = (Waterlogged) bData; - boolean waterlog = false; - if (wLog.isWaterlogged() && location.getY() > craft.getWaterLine()){ - updates.add(new WaterlogUpdateCommand(location.toBukkit(craft.getW()), false)); - } else if (!wLog.isWaterlogged() && location.getY() <= craft.getWaterLine() ){ - if (wLog instanceof TrapDoor){ - final TrapDoor trapDoor = (TrapDoor) wLog; - final Location testLoc = location.translate(0, (trapDoor.getHalf() == Bisected.Half.TOP ? -1 : 1), 0).toBukkit(craft.getW()); - if (testLoc.getBlock().getType() == Material.WATER || isWaterlogged(testLoc)){ - waterlog = true; - } - } else if (wLog instanceof Slab){ - final Slab slab = (Slab) wLog; - if (slab.getType() == Slab.Type.DOUBLE){ - continue; - } - final Location testLoc = location.translate(0, (slab.getType() == Slab.Type.TOP ? -1 : 1), 0).toBukkit(craft.getW()); - if (testLoc.getBlock().getType() == Material.WATER || isWaterlogged(testLoc) || waterToSides(location.toBukkit(craft.getW()))){ - waterlog = true; - } - - } else if (wLog instanceof Stairs){ - final Stairs stairs = (Stairs) wLog; - Block testBlock = location.toBukkit(craft.getW()).getBlock().getRelative(stairs.getFacing().getOppositeFace()); - Block yTest = location.translate(0, (stairs.getHalf() == Bisected.Half.TOP ? -1 : 1), 0).toBukkit(craft.getW()).getBlock(); - waterlog = testBlock.getType() == Material.WATER || isWaterlogged(testBlock.getLocation()) || yTest.getType() == Material.WATER || isWaterlogged(yTest.getLocation()); - } - - else if (waterToSides( location.toBukkit(craft.getW()))){ - waterlog = true; - } - - } - if (waterlog){ - updates.add(new WaterlogUpdateCommand(location.toBukkit(craft.getW()), true)); - } - } - - MapUpdateManager.getInstance().scheduleUpdates(updates); - } - - private void addToWaterlogQueue(final Craft craft){ - waterlogCheckQueue.add(craft); - } - private void clear(Craft c) { clearanceSet.add(c); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/rotation/RotationTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/rotation/RotationTask.java index 9dee55c4e..f8f6a7a97 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/rotation/RotationTask.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/rotation/RotationTask.java @@ -37,10 +37,7 @@ import net.countercraft.movecraft.mapUpdater.update.CraftRotateCommand; import net.countercraft.movecraft.mapUpdater.update.UpdateCommand; import net.countercraft.movecraft.utils.*; -import org.bukkit.Bukkit; -import org.bukkit.Location; -import org.bukkit.Material; -import org.bukkit.World; +import org.bukkit.*; import org.bukkit.block.Block; import org.bukkit.block.BlockFace; import org.bukkit.block.Furnace; @@ -176,8 +173,12 @@ public void run() { // See if they are permitted to build in the area, if WorldGuard integration is turned on Location plugLoc = newLocation.toBukkit(w); + WorldBorder border = craft.getW().getWorldBorder(); + boolean inside = Settings.IsPre1_9 ? plugLoc.subtract(border.getCenter()).getBlockX() <= border.getSize() && + plugLoc.subtract(border.getCenter()).getBlockZ() <= border.getSize() : + craft.getW().getWorldBorder().isInside(plugLoc); - if (!craft.getW().getWorldBorder().isInside(plugLoc)) { + if (!inside) { failMessage = I18nSupport.getInternationalisedString("Rotation - Failed Craft cannot pass world border"); failed = true; return; diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/WaterlogUtils.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/WaterlogUtils.java index 67e0f9b9c..565c6f2e2 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/WaterlogUtils.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/WaterlogUtils.java @@ -7,6 +7,7 @@ import org.bukkit.block.Block; import org.bukkit.block.data.Bisected; import org.bukkit.block.data.Waterlogged; +import org.bukkit.block.data.type.Slab; import org.bukkit.block.data.type.TrapDoor; public class WaterlogUtils { @@ -30,7 +31,7 @@ public static void waterlogBlocksOnCraft(Craft craft, HitBox interior) { exteriorBlock = true; break; } - if (!exteriorBlock || ml.getY() > craft.getWaterLine()) { + if (!exteriorBlock || ml.getY() > craft.getWaterLine() || !adjacentToWater(ml.toBukkit(craft.getW()))) { waterlog = false; } else if (wLog instanceof TrapDoor) { TrapDoor td = (TrapDoor) wLog; @@ -39,13 +40,20 @@ public static void waterlogBlocksOnCraft(Craft craft, HitBox interior) { } else if (td.getHalf() == Bisected.Half.BOTTOM && (interior.contains(ml.translate(0, 1, 0)) || craft.getHitBox().contains(ml.translate(0, 1, 0)))) { waterlog = false; } + } else if (wLog instanceof Slab) { + Slab s = (Slab) wLog; + if (s.getType() == Slab.Type.TOP && (interior.contains(ml.translate(0, -1, 0)) || craft.getHitBox().contains(ml.translate(0, -1, 0)))) { + waterlog = false; + } else if (s.getType() == Slab.Type.BOTTOM && (interior.contains(ml.translate(0, 1, 0)) || craft.getHitBox().contains(ml.translate(0, 1, 0)))) { + waterlog = false; + } } wLog.setWaterlogged(waterlog); b.setBlockData(wLog); } } - public static boolean isWaterlogged(Location location){ + private static boolean isWaterlogged(Location location){ if (!(location.getBlock().getBlockData() instanceof Waterlogged)){ return false; } @@ -53,17 +61,17 @@ public static boolean isWaterlogged(Location location){ return wlog.isWaterlogged(); } - public static boolean waterToSides(Location location){ + private static boolean adjacentToWater(Location location){ for (MovecraftLocation shift : SHIFTS){ - if (shift.getY() != 0){ - continue; - } final Block test = location.add(shift.toBukkit(location.getWorld())).getBlock(); if (test.getType() == Material.WATER){ return true; } else if (test.getBlockData() instanceof Waterlogged){ final Waterlogged wlog = (Waterlogged) test.getBlockData(); - return wlog.isWaterlogged(); + if (!wlog.isWaterlogged()) { + continue; + } + return true; } } return false; diff --git a/modules/api/src/main/java/net/countercraft/movecraft/craft/Craft.java b/modules/api/src/main/java/net/countercraft/movecraft/craft/Craft.java index e9dc1e51c..e4abff3de 100644 --- a/modules/api/src/main/java/net/countercraft/movecraft/craft/Craft.java +++ b/modules/api/src/main/java/net/countercraft/movecraft/craft/Craft.java @@ -143,8 +143,11 @@ public boolean getCruising() { public void setCruising(boolean cruising) { if(notificationPlayer!=null){ - - notificationPlayer.spigot().sendMessage(ChatMessageType.ACTION_BAR, new TextComponent("Cruising " + (cruising ? "enabled" : "disabled"))); + if (Settings.IsPre1_9) { + notificationPlayer.sendMessage("Cruising " + (cruising ? "enabled" : "disabled")); + } else { + notificationPlayer.spigot().sendMessage(ChatMessageType.ACTION_BAR, new TextComponent("Cruising " + (cruising ? "enabled" : "disabled"))); + } } this.cruising = cruising; } diff --git a/modules/v1_8_R3/pom.xml b/modules/v1_8_R3/pom.xml new file mode 100644 index 000000000..e4747c36b --- /dev/null +++ b/modules/v1_8_R3/pom.xml @@ -0,0 +1,57 @@ + + + + movecraft-parent + net.countercraft + parent + + 4.0.0 + + Movecraft-v1_8_R3 + movecraft-v1_8_R3 + v1_8_R3 + jar + + + org.bukkit + craftbukkit + 1.8.8-R0.1-SNAPSHOT + + + net.countercraft + movecraft-api + API + jar + + + + src/main/java + + + org.apache.maven.plugins + maven-compiler-plugin + 3.7.0 + + + net/countercraft/movecraft/compat/v1_8_R3/** + + 1.8 + 1.8 + + + + org.apache.maven.plugins + maven-jar-plugin + 2.4 + + + net/countercraft/movecraft/compat/v1_8_R3/** + + + + + + + \ No newline at end of file diff --git a/modules/v1_8_R3/src/main/java/net/countercraft/movecraft/compat/v1_8_R3/IWorldHandler.java b/modules/v1_8_R3/src/main/java/net/countercraft/movecraft/compat/v1_8_R3/IWorldHandler.java new file mode 100644 index 000000000..060ce8e4c --- /dev/null +++ b/modules/v1_8_R3/src/main/java/net/countercraft/movecraft/compat/v1_8_R3/IWorldHandler.java @@ -0,0 +1,408 @@ +package net.countercraft.movecraft.compat.v1_8_R3; + +import net.countercraft.movecraft.MovecraftLocation; +import net.countercraft.movecraft.Rotation; +import net.countercraft.movecraft.WorldHandler; +import net.countercraft.movecraft.config.Settings; +import net.countercraft.movecraft.craft.Craft; +import net.countercraft.movecraft.utils.CollectionUtils; +import net.countercraft.movecraft.utils.MathUtils; +import net.minecraft.server.v1_8_R3.*; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.craftbukkit.v1_8_R3.CraftWorld; +import org.bukkit.craftbukkit.v1_8_R3.block.CraftBlockState; +import org.bukkit.craftbukkit.v1_8_R3.entity.CraftPlayer; +import org.bukkit.craftbukkit.v1_8_R3.util.CraftMagicNumbers; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.reflect.Field; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.*; + +public class IWorldHandler extends WorldHandler { + private final HashMap> bMap = new HashMap<>(); + private MethodHandle internalTeleportMH; + private final NextTickProvider tickProvider = new NextTickProvider(); + + public IWorldHandler() { + MethodHandles.Lookup lookup = MethodHandles.lookup(); + Method teleport = null; + try { + teleport = PlayerConnection.class.getDeclaredMethod("internalTeleport", double.class, double.class, double.class, float.class, float.class, Set.class); + teleport.setAccessible(true); + internalTeleportMH = lookup.unreflect(teleport); + + } catch (NoSuchMethodException | IllegalAccessException e) { + e.printStackTrace(); + } + } + + @Override + public void addPlayerLocation(Player player, double x, double y, double z, float yaw, float pitch){ + EntityPlayer ePlayer = ((CraftPlayer) player).getHandle(); + if(internalTeleportMH == null) { + //something went wrong + super.addPlayerLocation(player, x, y, z, yaw, pitch); + return; + } + try { + internalTeleportMH.invoke(ePlayer.playerConnection, x, y, z, yaw, pitch, EnumSet.allOf(PacketPlayOutPosition.EnumPlayerTeleportFlags.class)); + } catch (Throwable throwable) { + throwable.printStackTrace(); + } + } + + @Override + public void rotateCraft(@NotNull Craft craft, @NotNull MovecraftLocation originPoint, @NotNull Rotation rotation) { + //******************************************* + //* Step one: Convert to Positions * + //******************************************* + HashMap rotatedPositions = new HashMap<>(); + Rotation counterRotation = rotation == Rotation.CLOCKWISE ? Rotation.ANTICLOCKWISE : Rotation.CLOCKWISE; + for(MovecraftLocation newLocation : craft.getHitBox()){ + rotatedPositions.put(locationToPosition(MathUtils.rotateVec(counterRotation, newLocation.subtract(originPoint)).add(originPoint)),locationToPosition(newLocation)); + } + //******************************************* + //* Step two: Get the tiles * + //******************************************* + World nativeWorld = ((CraftWorld) craft.getW()).getHandle(); + List tiles = new ArrayList<>(); + //get the tiles + for(BlockPosition position : rotatedPositions.keySet()){ + //TileEntity tile = nativeWorld.removeTileEntity(position); + TileEntity tile = removeTileEntity(nativeWorld,position); + if(tile == null) + continue; + //tile.a(ROTATION[rotation.ordinal()]); + //get the nextTick to move with the tile + tiles.add(new TileHolder(tile, tickProvider.getNextTick((WorldServer)nativeWorld,position), position)); + } + + //******************************************* + //* Step three: Translate all the blocks * + //******************************************* + // blockedByWater=false means an ocean-going vessel + //TODO: Simplify + //TODO: go by chunks + //TODO: Don't move unnecessary blocks + //get the blocks and rotate them + HashMap blockData = new HashMap<>(); + for(BlockPosition position : rotatedPositions.keySet()){ + IBlockData rotated = nativeWorld.getType(position); + //rotate directional blocks + if (rotated.a().contains(BlockStateDirection.of("facing"))) { + blockData.put(position, rotated.set(BlockStateDirection.of("facing"), rotateBlock(rotation, rotated))); + continue; + } + //rotate logs too + if (rotated.getBlock() instanceof BlockLogAbstract) { + BlockStateEnum axis = BlockStateEnum.of("axis", BlockLogAbstract.EnumLogRotation.class); + BlockLogAbstract.EnumLogRotation logRotation = rotated.get(axis); + if (logRotation != BlockLogAbstract.EnumLogRotation.NONE && logRotation != BlockLogAbstract.EnumLogRotation.Y) { + blockData.put(position, rotated.set(axis, logRotation == BlockLogAbstract.EnumLogRotation.Z ? BlockLogAbstract.EnumLogRotation.X : BlockLogAbstract.EnumLogRotation.Z)); + continue; + } + } + blockData.put(position, rotated); + } + //create the new block + for(Map.Entry entry : blockData.entrySet()) { + setBlockFast(nativeWorld, rotatedPositions.get(entry.getKey()), entry.getValue()); + } + + + //******************************************* + //* Step four: replace all the tiles * + //******************************************* + //TODO: go by chunks + for(TileHolder tileHolder : tiles){ + moveTileEntity(nativeWorld, rotatedPositions.get(tileHolder.getTilePosition()),tileHolder.getTile()); + if(tileHolder.getNextTick()==null) + continue; + final long currentTime = nativeWorld.worldData.getTime(); + nativeWorld.b(rotatedPositions.get(tileHolder.getNextTick().a), tileHolder.getNextTick().a(), (int) (tileHolder.getNextTick().b - currentTime), tileHolder.getNextTick().c); + } + + //******************************************* + //* Step five: Destroy the leftovers * + //******************************************* + //TODO: add support for pass-through + Collection deletePositions = CollectionUtils.filter(rotatedPositions.keySet(),rotatedPositions.values()); + for(BlockPosition position : deletePositions){ + setBlockFast(nativeWorld, position, Blocks.AIR.getBlockData()); + } + + //******************************************* + //* Step six: Update the blocks * + //******************************************* + for(BlockPosition newPosition : rotatedPositions.values()) { + CraftBlockState.getBlockState(nativeWorld,newPosition.getX(), newPosition.getY(), newPosition.getZ()).update(false,false); + } + for(BlockPosition deletedPosition : deletePositions){ + CraftBlockState.getBlockState(nativeWorld,deletedPosition.getX(), deletedPosition.getY(), deletedPosition.getZ()).update(false,false); + } + //******************************************* + //* Step seven: Send to players * + //******************************************* + List chunks = new ArrayList<>(); + for(BlockPosition position : rotatedPositions.values()){ + Chunk chunk = nativeWorld.getChunkAtWorldCoords(position); + if(!chunks.contains(chunk)){ + chunks.add(chunk); + } + } + for(BlockPosition position : deletePositions){ + Chunk chunk = nativeWorld.getChunkAtWorldCoords(position); + if(!chunks.contains(chunk)){ + chunks.add(chunk); + } + } + } + + @Override + public void translateCraft(@NotNull Craft craft, @NotNull MovecraftLocation displacement) { + //TODO: Add supourt for rotations + //A craftTranslateCommand should only occur if the craft is moving to a valid position + //******************************************* + //* Step one: Convert to Positions * + //******************************************* + BlockPosition translateVector = locationToPosition(displacement); + List positions = new ArrayList<>(); + for(MovecraftLocation movecraftLocation : craft.getHitBox()) { + positions.add(locationToPosition((movecraftLocation)).b(translateVector)); + + } + //******************************************* + //* Step two: Get the tiles * + //******************************************* + World nativeWorld = ((CraftWorld) craft.getW()).getHandle(); + List tiles = new ArrayList<>(); + //get the tiles + for(BlockPosition position : positions){ + if(nativeWorld.getType(position) == Blocks.AIR.getBlockData()) + continue; + //TileEntity tile = nativeWorld.removeTileEntity(position); + TileEntity tile = removeTileEntity(nativeWorld,position); + if(tile == null) + continue; + //get the nextTick to move with the tile + + //nativeWorld.capturedTileEntities.remove(position); + //nativeWorld.getChunkAtWorldCoords(position).getTileEntities().remove(position); + tiles.add(new TileHolder(tile, tickProvider.getNextTick((WorldServer)nativeWorld,position), position)); + + } + //******************************************* + //* Step three: Translate all the blocks * + //******************************************* + // blockedByWater=false means an ocean-going vessel + //TODO: Simplify + //TODO: go by chunks + //TODO: Don't move unnecessary blocks + //get the blocks and translate the positions + List blockData = new ArrayList<>(); + List newPositions = new ArrayList<>(); + for(BlockPosition position : positions){ + blockData.add(nativeWorld.getType(position)); + newPositions.add(position.a(translateVector)); + } + //create the new block + for(int i = 0; i deletePositions = CollectionUtils.filter(positions,newPositions); + for(BlockPosition position : deletePositions){ + setBlockFast(nativeWorld, position, Blocks.AIR.getBlockData()); + } + + //******************************************* + //* Step six: Update the blocks * + //******************************************* + for(BlockPosition newPosition : newPositions) { + CraftBlockState.getBlockState(nativeWorld,newPosition.getX(), newPosition.getY(), newPosition.getZ()).update(false,false); + } + for(BlockPosition deletedPosition : deletePositions){ + CraftBlockState.getBlockState(nativeWorld,deletedPosition.getX(), deletedPosition.getY(), deletedPosition.getZ()).update(false,false); + } + //******************************************* + //* Step seven: Send to players * + //******************************************* + List chunks = new ArrayList<>(); + for(BlockPosition position : newPositions){ + Chunk chunk = nativeWorld.getChunkAtWorldCoords(position); + if(!chunks.contains(chunk)){ + chunks.add(chunk); + } + } + for(BlockPosition position : deletePositions){ + Chunk chunk = nativeWorld.getChunkAtWorldCoords(position); + if(!chunks.contains(chunk)){ + chunks.add(chunk); + } + } + //sendToPlayers(chunks.toArray(new Chunk[0])); + } + + @Nullable + private TileEntity removeTileEntity(@NotNull World world, @NotNull BlockPosition position){ + TileEntity tile = world.getTileEntity(position); + if(tile == null) + return null; + //cleanup + world.capturedTileEntities.remove(position); + world.getChunkAtWorldCoords(position).getTileEntities().remove(position); + if(!Settings.IsPaper) + world.tileEntityList.remove(tile); + world.h.remove(tile); + if(!bMap.containsKey(world)){ + try { + Field bField = World.class.getDeclaredField("b"); + bField.setAccessible(true); + bMap.put(world, (List) bField.get(world)); + } catch (IllegalAccessException | IllegalArgumentException | NoSuchFieldException | SecurityException e1) { + e1.printStackTrace(); + } + } + bMap.get(world).remove(tile); + return tile; + } + + @NotNull + private BlockPosition locationToPosition(@NotNull MovecraftLocation loc) { + return new BlockPosition(loc.getX(), loc.getY(), loc.getZ()); + } + + private void setBlockFast(@NotNull World world, @NotNull BlockPosition position,@NotNull IBlockData data) { + Chunk chunk = world.getChunkAtWorldCoords(position); + ChunkSection chunkSection = chunk.getSections()[position.getY()>>4]; + if (chunkSection == null) { + // Put a GLASS block to initialize the section. It will be replaced next with the real block. + chunk.a(position, Blocks.GLASS.getBlockData()); + chunkSection = chunk.getSections()[position.getY() >> 4]; + } + + chunkSection.setType(position.getX()&15, position.getY()&15, position.getZ()&15, data); + } + + @Override + public void setBlockFast(@NotNull Location location, @NotNull Material material, byte data){ + setBlockFast(location, Rotation.NONE, material, data); + } + + @Override + public void setBlockFast(@NotNull Location location, @NotNull Rotation rotation, @NotNull Material material, byte data) { + IBlockData blockData = CraftMagicNumbers.getBlock(material).fromLegacyData(data); + //blockData = blockData.a(ROTATION[rotation.ordinal()]); + World world = ((CraftWorld)(location.getWorld())).getHandle(); + BlockPosition blockPosition = locationToPosition(bukkit2MovecraftLoc(location)); + setBlockFast(world,blockPosition,blockData); + } + + @Override + public void disableShadow(@NotNull Material type) { + Method method; + try { + Block tempBlock = CraftMagicNumbers.getBlock(type.getId()); + method = Block.class.getDeclaredMethod("e", int.class); + method.setAccessible(true); + method.invoke(tempBlock, 0); + } catch (NoSuchMethodException | InvocationTargetException | IllegalArgumentException | IllegalAccessException | SecurityException e1) { + // TODO Auto-generated catch block + e1.printStackTrace(); + } + } + + private static MovecraftLocation bukkit2MovecraftLoc(Location l) { + return new MovecraftLocation(l.getBlockX(), l.getBlockY(), l.getBlockZ()); + } + + private void moveTileEntity(@NotNull World nativeWorld, @NotNull BlockPosition newPosition, @NotNull TileEntity tile){ + Chunk chunk = nativeWorld.getChunkAtWorldCoords(newPosition); + tile.E(); + if(nativeWorld.captureBlockStates) { + tile.a(nativeWorld); + tile.a(newPosition); + nativeWorld.capturedTileEntities.put(newPosition, tile); + return; + } + tile.a(newPosition); + chunk.tileEntities.put(newPosition, tile); + } + + private EnumDirection rotateBlock(Rotation rotation, IBlockData blockData) { + final EnumDirection eDir = blockData.get(BlockStateDirection.of("facing")); + if (rotation == Rotation.CLOCKWISE) { + switch (eDir) { + case EAST: + return EnumDirection.SOUTH; + case SOUTH: + return EnumDirection.WEST; + case WEST: + return EnumDirection.NORTH; + case NORTH: + return EnumDirection.EAST; + } + } else if (rotation == Rotation.ANTICLOCKWISE) { + switch (eDir) { + case EAST: + return EnumDirection.NORTH; + case SOUTH: + return EnumDirection.EAST; + case WEST: + return EnumDirection.SOUTH; + case NORTH: + return EnumDirection.WEST; + } + } + return eDir; + } + + private class TileHolder{ + @NotNull private final TileEntity tile; + @Nullable + private final NextTickListEntry nextTick; + @NotNull private final BlockPosition tilePosition; + + public TileHolder(@NotNull TileEntity tile, @Nullable NextTickListEntry nextTick, @NotNull BlockPosition tilePosition){ + this.tile = tile; + this.nextTick = nextTick; + this.tilePosition = tilePosition; + } + + + @NotNull + public TileEntity getTile() { + return tile; + } + + @Nullable + public NextTickListEntry getNextTick() { + return nextTick; + } + + @NotNull + public BlockPosition getTilePosition() { + return tilePosition; + } + } +} diff --git a/modules/v1_8_R3/src/main/java/net/countercraft/movecraft/compat/v1_8_R3/NextTickProvider.java b/modules/v1_8_R3/src/main/java/net/countercraft/movecraft/compat/v1_8_R3/NextTickProvider.java new file mode 100644 index 000000000..ebeec8681 --- /dev/null +++ b/modules/v1_8_R3/src/main/java/net/countercraft/movecraft/compat/v1_8_R3/NextTickProvider.java @@ -0,0 +1,80 @@ +package net.countercraft.movecraft.compat.v1_8_R3; + +import net.minecraft.server.v1_8_R3.BlockPosition; +import net.minecraft.server.v1_8_R3.NextTickListEntry; +import net.minecraft.server.v1_8_R3.WorldServer; +import org.apache.commons.lang3.tuple.ImmutablePair; +import org.bukkit.craftbukkit.v1_8_R3.util.HashTreeSet; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.lang.ref.WeakReference; +import java.lang.reflect.Field; +import java.util.*; + +public class NextTickProvider { + private Map>,WeakReference>>> tickMap = new HashMap<>(); + + private boolean isRegistered(@NotNull WorldServer world){ + if(!tickMap.containsKey(world)) + return false; + ImmutablePair>, WeakReference>> listPair = tickMap.get(world); + return listPair.right.get() != null && listPair.left.get() != null; + } + + @SuppressWarnings("unchecked") + private void registerWorld(@NotNull WorldServer world){ + List U = new ArrayList<>(); + HashTreeSet nextTickList = new HashTreeSet<>(); + + try { + + Field UField = WorldServer.class.getDeclaredField("V"); + UField.setAccessible(true); + U = (List) UField.get(world); + Field nextTickListField = WorldServer.class.getDeclaredField("M"); + nextTickListField.setAccessible(true); + nextTickList = (HashTreeSet) nextTickListField.get(world); + } catch (IllegalAccessException | IllegalArgumentException | NoSuchFieldException | SecurityException e1) { + e1.printStackTrace(); + } + tickMap.put(world, new ImmutablePair<>(new WeakReference<>(nextTickList), new WeakReference<>(U))); + } + + @Nullable + @SuppressWarnings("ConstantConditions") + public NextTickListEntry getNextTick(@NotNull WorldServer world,@NotNull BlockPosition position){ + if(!isRegistered(world)) + registerWorld(world); + ImmutablePair>, WeakReference>> listPair = tickMap.get(world); + if(listPair.left.get().contains(fakeEntry(position))) { + for (Iterator iterator = listPair.left.get().iterator(); iterator.hasNext(); ) { + NextTickListEntry listEntry = iterator.next(); + if (position.equals(listEntry.a)) { + iterator.remove(); + return listEntry; + } + } + } + + for(Iterator iterator = listPair.right.get().iterator(); iterator.hasNext();) { + NextTickListEntry listEntry = iterator.next(); + if (position.equals(listEntry.a)) { + iterator.remove(); + return listEntry; + } + } + return null; + + } + + @NotNull + public Object fakeEntry(@NotNull BlockPosition position){ + return new Object(){ + @Override + public int hashCode() { + return position.hashCode(); + } + }; + } +} diff --git a/modules/v1_9_R2/src/main/java/net/countercraft/movecraft/compat/v1_9_R2/NextTickProvider.java b/modules/v1_9_R2/src/main/java/net/countercraft/movecraft/compat/v1_9_R2/NextTickProvider.java index 98d5ee3dd..f73286e67 100644 --- a/modules/v1_9_R2/src/main/java/net/countercraft/movecraft/compat/v1_9_R2/NextTickProvider.java +++ b/modules/v1_9_R2/src/main/java/net/countercraft/movecraft/compat/v1_9_R2/NextTickProvider.java @@ -43,17 +43,20 @@ private void registerWorld(@NotNull WorldServer world){ @Nullable @SuppressWarnings("ConstantConditions") - public NextTickListEntry getNextTick(@NotNull WorldServer world, @NotNull BlockPosition position){ + public NextTickListEntry getNextTick(@NotNull WorldServer world,@NotNull BlockPosition position){ if(!isRegistered(world)) registerWorld(world); ImmutablePair>, WeakReference>> listPair = tickMap.get(world); - for(Iterator iterator = listPair.left.get().iterator(); iterator.hasNext();) { - NextTickListEntry listEntry = iterator.next(); - if (position.equals(listEntry.a)) { - iterator.remove(); - return listEntry; + if(listPair.left.get().contains(fakeEntry(position))) { + for (Iterator iterator = listPair.left.get().iterator(); iterator.hasNext(); ) { + NextTickListEntry listEntry = iterator.next(); + if (position.equals(listEntry.a)) { + iterator.remove(); + return listEntry; + } } } + for(Iterator iterator = listPair.right.get().iterator(); iterator.hasNext();) { NextTickListEntry listEntry = iterator.next(); if (position.equals(listEntry.a)) { @@ -64,4 +67,14 @@ public NextTickListEntry getNextTick(@NotNull WorldServer world, @NotNull BlockP return null; } + + @NotNull + public Object fakeEntry(@NotNull BlockPosition position){ + return new Object(){ + @Override + public int hashCode() { + return position.hashCode(); + } + }; + } } diff --git a/pom.xml b/pom.xml index cf73595dc..25670b593 100644 --- a/pom.xml +++ b/pom.xml @@ -20,6 +20,8 @@ modules/api + modules/v1_7_R4 + modules/v1_8_R3 modules/v1_9_R2 modules/v1_10_R1 modules/v1_11_R1 @@ -30,6 +32,8 @@ modules/worldedit/WE6Utils modules/worldedit/WE7Utils modules/Movecraft + + From a2a1344e3797ef53a3c6ae0a881bccd8e36e83e0 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Fri, 7 Feb 2020 23:10:27 +0100 Subject: [PATCH 120/304] Added "all_" to passthroughblocks and improved all_ --- .../countercraft/movecraft/craft/Craft.java | 2 +- .../movecraft/craft/CraftType.java | 31 ++++++++++++++++--- .../movecraft/utils/BlockContainer.java | 2 ++ .../movecraft/utils/BlockLimitManager.java | 6 +++- pom.xml | 1 - 5 files changed, 35 insertions(+), 7 deletions(-) diff --git a/modules/api/src/main/java/net/countercraft/movecraft/craft/Craft.java b/modules/api/src/main/java/net/countercraft/movecraft/craft/Craft.java index e4abff3de..c238ce5b6 100644 --- a/modules/api/src/main/java/net/countercraft/movecraft/craft/Craft.java +++ b/modules/api/src/main/java/net/countercraft/movecraft/craft/Craft.java @@ -332,7 +332,7 @@ public int getTickCooldown() { Material mat = location.toBukkit(w).getBlock().getType(); counter.put(mat, counter.getOrDefault(mat, 0) + 1); } - double chestPenalty = counter.getOrDefault(Material.CHEST, 0) + counter.getOrDefault(Material.TRAPPED_CHEST, 0); + double chestPenalty = counter.getOrDefault(Material.CHEST, 0) + counter.getOrDefault(Material.TRAPPED_CHEST, 0) + counter.getOrDefault(Material.getMaterial("BARREL"), 0); chestPenalty*=type.getChestPenalty(); if(!cruising) return type.getTickCooldown()+(int)chestPenalty; diff --git a/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java b/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java index 6cc6a39cd..8c21599fa 100644 --- a/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java +++ b/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java @@ -188,9 +188,16 @@ public CraftType(File f) throws CraftTypeException{ String str = (String) i; if (str.startsWith("ALL_")) { str = str.replace("ALL_", ""); - for (Material type : Material.values()) { - + for (Material type : Material.values()){ + str = str.replace("ALL", ""); + if (!type.name().endsWith(str)){ + continue; + } else if (type.name().split("_").length == 1 && !type.name().endsWith(str.substring(1))) { + continue; + } + harvestBlocks.add(type); } + continue; } Material mat = Material.getMaterial((String) i); harvestBlocks.add(mat); @@ -209,7 +216,10 @@ public CraftType(File f) throws CraftTypeException{ str = str.toUpperCase(); if (str.startsWith("ALL_")){ for (Material type : Material.values()){ - if (!type.name().endsWith(str.replace("ALL_", "_"))){ + str = str.replace("ALL", ""); + if (!type.name().endsWith(str)){ + continue; + } else if (type.name().split("_").length == 1 && !type.name().endsWith(str.substring(1))) { continue; } harvesterBladeBlocks.add(type); @@ -230,7 +240,20 @@ public CraftType(File f) throws CraftTypeException{ ArrayList objList = (ArrayList) data.get("passthroughBlocks"); for (Object i : objList) { if (i instanceof String) { - Material mat = Material.getMaterial(((String) i).toUpperCase()); + String str = ((String) i).toUpperCase(); + if (str.startsWith("ALL_")) { + str = str.replace("ALL", ""); + for (Material type : Material.values()) { + if (!type.name().endsWith(str)) { + continue; + } else if (type.name().split("_").length == 1 && !type.name().endsWith(str.substring(1))) { + continue; + } + passthroughBlocks.add(type); + } + continue; + } + Material mat = Material.getMaterial(str); passthroughBlocks.add(mat); } else { Material mat = Material.getMaterial((Integer) i); diff --git a/modules/api/src/main/java/net/countercraft/movecraft/utils/BlockContainer.java b/modules/api/src/main/java/net/countercraft/movecraft/utils/BlockContainer.java index 9ab977e54..62b14d780 100644 --- a/modules/api/src/main/java/net/countercraft/movecraft/utils/BlockContainer.java +++ b/modules/api/src/main/java/net/countercraft/movecraft/utils/BlockContainer.java @@ -45,6 +45,8 @@ public BlockContainer(Object obj){ for (Material m : Material.values()){ if (!m.name().endsWith(str)){ continue; + } else if (m.name().split("_").length == 1 && m.name().endsWith(str.substring(1))) { + continue; } blocks.add(new MovecraftBlock(m)); } diff --git a/modules/api/src/main/java/net/countercraft/movecraft/utils/BlockLimitManager.java b/modules/api/src/main/java/net/countercraft/movecraft/utils/BlockLimitManager.java index d2aa0e3c3..707d74e9e 100644 --- a/modules/api/src/main/java/net/countercraft/movecraft/utils/BlockLimitManager.java +++ b/modules/api/src/main/java/net/countercraft/movecraft/utils/BlockLimitManager.java @@ -50,6 +50,8 @@ public BlockLimitManager(Object obj){ for (Material m : Material.values()){ if (!m.name().endsWith(string)){ continue; + } else if (m.name().split("_").length == 1 && m.name().endsWith(string.substring(1))) { + continue; } blocks.add(new MovecraftBlock(m)); } @@ -101,10 +103,12 @@ public BlockLimitManager(Object obj){ dataList = new ArrayList<>(); dataList.add(data); } else if (string.toUpperCase().startsWith("ALL_")){ - string = string.replace("ALL_", ""); + string = string.replace("ALL", ""); for (Material m : Material.values()){ if (!m.name().endsWith(string)){ continue; + } else if (m.name().split("_").length == 1 && m.name().endsWith(string.substring(1))) { + continue; } blocks.add(new MovecraftBlock(m)); } diff --git a/pom.xml b/pom.xml index 25670b593..69cbfb288 100644 --- a/pom.xml +++ b/pom.xml @@ -20,7 +20,6 @@ modules/api - modules/v1_7_R4 modules/v1_8_R3 modules/v1_9_R2 modules/v1_10_R1 From 1411c4b1133282cf2fb9ea7488ea3fe3e5d1b6c4 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Sat, 22 Feb 2020 01:05:56 +0100 Subject: [PATCH 121/304] some fixes --- .../main/java/net/countercraft/movecraft/craft/CraftType.java | 4 ++-- .../countercraft/movecraft/compat/v1_15_R1/IWorldHandler.java | 4 +--- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java b/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java index 8c21599fa..011fdbd68 100644 --- a/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java +++ b/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java @@ -187,7 +187,7 @@ public CraftType(File f) throws CraftTypeException{ if (i instanceof String) { String str = (String) i; if (str.startsWith("ALL_")) { - str = str.replace("ALL_", ""); + str = str.replace("ALL_", "").toUpperCase(); for (Material type : Material.values()){ str = str.replace("ALL", ""); if (!type.name().endsWith(str)){ @@ -199,7 +199,7 @@ public CraftType(File f) throws CraftTypeException{ } continue; } - Material mat = Material.getMaterial((String) i); + Material mat = Material.getMaterial(((String) i).toUpperCase()); harvestBlocks.add(mat); } else { Material mat = Material.getMaterial((Integer) i); diff --git a/modules/v1_15_R1/src/main/java/net/countercraft/movecraft/compat/v1_15_R1/IWorldHandler.java b/modules/v1_15_R1/src/main/java/net/countercraft/movecraft/compat/v1_15_R1/IWorldHandler.java index 32308b7d0..5bcdad910 100644 --- a/modules/v1_15_R1/src/main/java/net/countercraft/movecraft/compat/v1_15_R1/IWorldHandler.java +++ b/modules/v1_15_R1/src/main/java/net/countercraft/movecraft/compat/v1_15_R1/IWorldHandler.java @@ -307,9 +307,7 @@ private void setBlockFast(@NotNull World world, @NotNull BlockPosition position, chunkSection = chunk.getSections()[position.getY() >> 4]; } - if (world.getType(position).getBlock().isTileEntity()) { - removeTileEntity(world, position); - } + chunkSection.setType(position.getX()&15, position.getY()&15, position.getZ()&15, data); if (physics) { world.notifyAndUpdatePhysics(position, chunk, data, data, data, 3); From 5e63ca5cbeba8eb6941f212234a24e217e6d69aa Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Fri, 28 Feb 2020 08:49:47 +0100 Subject: [PATCH 122/304] Fixed fire processing and an issue with tile entities --- .../async/translation/TranslationTask.java | 15 ++++++ .../compat/v1_13_R2/IWorldHandler.java | 23 ++++++++ .../compat/v1_14_R1/IWorldHandler.java | 23 ++++++++ .../compat/v1_15_R1/IWorldHandler.java | 53 +++++++++++-------- .../compat/v1_8_R3/IWorldHandler.java | 29 +++++----- .../compat/v1_9_R2/IWorldHandler.java | 30 ++++++----- 6 files changed, 125 insertions(+), 48 deletions(-) diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java index 5dd2995e4..2f208e0b0 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java @@ -102,6 +102,21 @@ public TranslationTask(Craft c, int dx, int dy, int dz) { FALL_THROUGH_BLOCKS.add(Material.KELP_PLANT); FALL_THROUGH_BLOCKS.add(Material.SEAGRASS); FALL_THROUGH_BLOCKS.add(Material.TALL_SEAGRASS); + //Leaves + FALL_THROUGH_BLOCKS.add(Material.ACACIA_LEAVES); + FALL_THROUGH_BLOCKS.add(Material.BIRCH_LEAVES); + FALL_THROUGH_BLOCKS.add(Material.DARK_OAK_LEAVES); + FALL_THROUGH_BLOCKS.add(Material.JUNGLE_LEAVES); + FALL_THROUGH_BLOCKS.add(Material.OAK_LEAVES); + FALL_THROUGH_BLOCKS.add(Material.SPRUCE_LEAVES); + //Grass + FALL_THROUGH_BLOCKS.add(Material.GRASS); + //Double plants + FALL_THROUGH_BLOCKS.add(Material.ROSE_BUSH); + FALL_THROUGH_BLOCKS.add(Material.SUNFLOWER); + FALL_THROUGH_BLOCKS.add(Material.LILAC); + FALL_THROUGH_BLOCKS.add(Material.PEONY); + FALL_THROUGH_BLOCKS.add(Material.SEA_PICKLE); } } diff --git a/modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/IWorldHandler.java b/modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/IWorldHandler.java index e4da1ff9e..f79b2b097 100644 --- a/modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/IWorldHandler.java +++ b/modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/IWorldHandler.java @@ -118,6 +118,17 @@ public void rotateCraft(@NotNull Craft craft, @NotNull MovecraftLocation originP setBlockFast(nativeWorld, position, Blocks.AIR.getBlockData()); } + //******************************************* + //* Step six: Process fire spread * + //******************************************* + for (BlockPosition position : rotatedPositions.values()) { + IBlockData type = nativeWorld.getType(position); + if (!(type.getBlock() instanceof BlockFire)) { + continue; + } + BlockFire fire = (BlockFire) type.getBlock(); + fire.a(type, nativeWorld, position, nativeWorld.random); + } //******************************************* //* Step six: Send to players * //******************************************* @@ -217,6 +228,18 @@ public void translateCraft(@NotNull Craft craft, @NotNull MovecraftLocation disp for (BlockPosition position : redstoneComponents.keySet()) { setBlockFast(nativeWorld, position, redstoneComponents.get(position), true); } + + //******************************************* + //* Step six: Process fire spread * + //******************************************* + for (BlockPosition position : newPositions) { + IBlockData type = nativeWorld.getType(position); + if (!(type.getBlock() instanceof BlockFire)) { + continue; + } + BlockFire fire = (BlockFire) type.getBlock(); + fire.a(type, nativeWorld, position, nativeWorld.random); + } //******************************************* //* Step six: Send to players * //******************************************* diff --git a/modules/v1_14_R1/src/main/java/net/countercraft/movecraft/compat/v1_14_R1/IWorldHandler.java b/modules/v1_14_R1/src/main/java/net/countercraft/movecraft/compat/v1_14_R1/IWorldHandler.java index 0e9b65ba3..ecbfc20d0 100644 --- a/modules/v1_14_R1/src/main/java/net/countercraft/movecraft/compat/v1_14_R1/IWorldHandler.java +++ b/modules/v1_14_R1/src/main/java/net/countercraft/movecraft/compat/v1_14_R1/IWorldHandler.java @@ -117,6 +117,17 @@ public void rotateCraft(@NotNull Craft craft, @NotNull MovecraftLocation originP setBlockFast(nativeWorld, position, Blocks.AIR.getBlockData()); } + //******************************************* + //* Step six: Process fire spread * + //******************************************* + for (BlockPosition position : rotatedPositions.values()) { + IBlockData type = nativeWorld.getType(position); + if (!(type.getBlock() instanceof BlockFire)) { + continue; + } + BlockFire fire = (BlockFire) type.getBlock(); + fire.tick(type, nativeWorld, position, nativeWorld.random); + } //******************************************* //* Step six: Send to players * //******************************************* @@ -218,6 +229,18 @@ public void translateCraft(@NotNull Craft craft, @NotNull MovecraftLocation disp setBlockFast(nativeWorld, position, redstoneComponents.get(position), true); } + //******************************************* + //* Step six: Process fire spread * + //******************************************* + for (BlockPosition position : newPositions) { + IBlockData type = nativeWorld.getType(position); + if (!(type.getBlock() instanceof BlockFire)) { + continue; + } + BlockFire fire = (BlockFire) type.getBlock(); + fire.tick(type, nativeWorld, position, nativeWorld.random); + } + //******************************************* //* Step six: Send to players * //******************************************* diff --git a/modules/v1_15_R1/src/main/java/net/countercraft/movecraft/compat/v1_15_R1/IWorldHandler.java b/modules/v1_15_R1/src/main/java/net/countercraft/movecraft/compat/v1_15_R1/IWorldHandler.java index 5bcdad910..6c6c155f8 100644 --- a/modules/v1_15_R1/src/main/java/net/countercraft/movecraft/compat/v1_15_R1/IWorldHandler.java +++ b/modules/v1_15_R1/src/main/java/net/countercraft/movecraft/compat/v1_15_R1/IWorldHandler.java @@ -97,6 +97,7 @@ public void rotateCraft(@NotNull Craft craft, @NotNull MovecraftLocation originP if (isRedstoneComponent(iBlockData)) { redstoneComponents.put(newPosition, iBlockData); } + setBlockFast(nativeWorld, newPosition, iBlockData); } @@ -122,8 +123,16 @@ public void rotateCraft(@NotNull Craft craft, @NotNull MovecraftLocation originP setBlockFast(nativeWorld, position, Blocks.AIR.getBlockData()); } - for (BlockPosition position : redstoneComponents.keySet()) { - setBlockFast(nativeWorld, position, redstoneComponents.get(position), true); + //******************************************* + //* Step six: Process fire spread * + //******************************************* + for (BlockPosition position : rotatedPositions.values()) { + IBlockData type = nativeWorld.getType(position); + if (!(type.getBlock() instanceof BlockFire)) { + continue; + } + BlockFire fire = (BlockFire) type.getBlock(); + fire.tick(type, nativeWorld, position, nativeWorld.random); } //******************************************* @@ -191,13 +200,13 @@ public void translateCraft(@NotNull Craft craft, @NotNull MovecraftLocation disp blockData.add(nativeWorld.getType(position)); newPositions.add(position.a(translateVector)); } - Map redstoneComponents = new HashMap<>(); //create the new block for(int i = 0; i>4]; if (chunkSection == null) { @@ -309,10 +324,6 @@ private void setBlockFast(@NotNull World world, @NotNull BlockPosition position, } chunkSection.setType(position.getX()&15, position.getY()&15, position.getZ()&15, data); - if (physics) { - world.notifyAndUpdatePhysics(position, chunk, data, data, data, 3); - return; - } world.notify(position, data, data, 3); } @@ -327,7 +338,7 @@ public void setBlockFast(@NotNull Location location, @NotNull Rotation rotation, blockData = blockData.a(ROTATION[rotation.ordinal()]); WorldServer world = ((CraftWorld)(location.getWorld())).getHandle(); BlockPosition blockPosition = locationToPosition(bukkit2MovecraftLoc(location)); - setBlockFast(world,blockPosition,blockData, false); + setBlockFast(world,blockPosition,blockData); } @Override @@ -391,12 +402,10 @@ public BlockPosition getTilePosition() { private boolean isRedstoneComponent(IBlockData blockData) { final Block block = blockData.getBlock(); - return block instanceof BlockRedstoneComparator || - block instanceof BlockRedstoneWire || - block instanceof BlockRepeater || + return block instanceof BlockRedstoneWire || + block instanceof BlockDiodeAbstract || block instanceof BlockButtonAbstract || - block instanceof BlockLever || - block instanceof BlockDispenser; + block instanceof BlockLever; } } diff --git a/modules/v1_8_R3/src/main/java/net/countercraft/movecraft/compat/v1_8_R3/IWorldHandler.java b/modules/v1_8_R3/src/main/java/net/countercraft/movecraft/compat/v1_8_R3/IWorldHandler.java index 060ce8e4c..908525962 100644 --- a/modules/v1_8_R3/src/main/java/net/countercraft/movecraft/compat/v1_8_R3/IWorldHandler.java +++ b/modules/v1_8_R3/src/main/java/net/countercraft/movecraft/compat/v1_8_R3/IWorldHandler.java @@ -11,7 +11,6 @@ import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.craftbukkit.v1_8_R3.CraftWorld; -import org.bukkit.craftbukkit.v1_8_R3.block.CraftBlockState; import org.bukkit.craftbukkit.v1_8_R3.entity.CraftPlayer; import org.bukkit.craftbukkit.v1_8_R3.util.CraftMagicNumbers; import org.bukkit.entity.Player; @@ -139,13 +138,15 @@ public void rotateCraft(@NotNull Craft craft, @NotNull MovecraftLocation originP } //******************************************* - //* Step six: Update the blocks * + //* Step six: Process fire spread * //******************************************* - for(BlockPosition newPosition : rotatedPositions.values()) { - CraftBlockState.getBlockState(nativeWorld,newPosition.getX(), newPosition.getY(), newPosition.getZ()).update(false,false); - } - for(BlockPosition deletedPosition : deletePositions){ - CraftBlockState.getBlockState(nativeWorld,deletedPosition.getX(), deletedPosition.getY(), deletedPosition.getZ()).update(false,false); + for (BlockPosition position : rotatedPositions.values()) { + IBlockData type = nativeWorld.getType(position); + if (!(type.getBlock() instanceof BlockFire)) { + continue; + } + BlockFire fire = (BlockFire) type.getBlock(); + fire.b(nativeWorld, position, type, nativeWorld.random); } //******************************************* //* Step seven: Send to players * @@ -236,13 +237,15 @@ public void translateCraft(@NotNull Craft craft, @NotNull MovecraftLocation disp } //******************************************* - //* Step six: Update the blocks * + //* Step six: Process fire spread * //******************************************* - for(BlockPosition newPosition : newPositions) { - CraftBlockState.getBlockState(nativeWorld,newPosition.getX(), newPosition.getY(), newPosition.getZ()).update(false,false); - } - for(BlockPosition deletedPosition : deletePositions){ - CraftBlockState.getBlockState(nativeWorld,deletedPosition.getX(), deletedPosition.getY(), deletedPosition.getZ()).update(false,false); + for (BlockPosition position : newPositions) { + IBlockData type = nativeWorld.getType(position); + if (!(type.getBlock() instanceof BlockFire)) { + continue; + } + BlockFire fire = (BlockFire) type.getBlock(); + fire.b(nativeWorld, position, type, nativeWorld.random); } //******************************************* //* Step seven: Send to players * diff --git a/modules/v1_9_R2/src/main/java/net/countercraft/movecraft/compat/v1_9_R2/IWorldHandler.java b/modules/v1_9_R2/src/main/java/net/countercraft/movecraft/compat/v1_9_R2/IWorldHandler.java index cb952b0b2..c1168ab5b 100644 --- a/modules/v1_9_R2/src/main/java/net/countercraft/movecraft/compat/v1_9_R2/IWorldHandler.java +++ b/modules/v1_9_R2/src/main/java/net/countercraft/movecraft/compat/v1_9_R2/IWorldHandler.java @@ -11,7 +11,6 @@ import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.craftbukkit.v1_9_R2.CraftWorld; -import org.bukkit.craftbukkit.v1_9_R2.block.CraftBlockState; import org.bukkit.craftbukkit.v1_9_R2.entity.CraftPlayer; import org.bukkit.craftbukkit.v1_9_R2.util.CraftMagicNumbers; import org.bukkit.entity.Player; @@ -131,13 +130,15 @@ public void rotateCraft(@NotNull Craft craft, @NotNull MovecraftLocation originP } //******************************************* - //* Step six: Update the blocks * + //* Step six: Process fire spread * //******************************************* - for(BlockPosition newPosition : rotatedPositions.values()) { - CraftBlockState.getBlockState(nativeWorld,newPosition.getX(), newPosition.getY(), newPosition.getZ()).update(false,false); - } - for(BlockPosition deletedPosition : deletePositions){ - CraftBlockState.getBlockState(nativeWorld,deletedPosition.getX(), deletedPosition.getY(), deletedPosition.getZ()).update(false,false); + for (BlockPosition position : rotatedPositions.values()) { + IBlockData type = nativeWorld.getType(position); + if (!(type.getBlock() instanceof BlockFire)) { + continue; + } + BlockFire fire = (BlockFire) type.getBlock(); + fire.b(nativeWorld, position, type, nativeWorld.random); } //******************************************* //* Step seven: Send to players * @@ -228,13 +229,15 @@ public void translateCraft(@NotNull Craft craft, @NotNull MovecraftLocation disp } //******************************************* - //* Step six: Update the blocks * + //* Step six: Process fire spread * //******************************************* - for(BlockPosition newPosition : newPositions) { - CraftBlockState.getBlockState(nativeWorld,newPosition.getX(), newPosition.getY(), newPosition.getZ()).update(false,false); - } - for(BlockPosition deletedPosition : deletePositions){ - CraftBlockState.getBlockState(nativeWorld,deletedPosition.getX(), deletedPosition.getY(), deletedPosition.getZ()).update(false,false); + for (BlockPosition position : newPositions) { + IBlockData type = nativeWorld.getType(position); + if (!(type.getBlock() instanceof BlockFire)) { + continue; + } + BlockFire fire = (BlockFire) type.getBlock(); + fire.b(nativeWorld, position, type, nativeWorld.random); } //******************************************* //* Step seven: Send to players * @@ -294,6 +297,7 @@ private void setBlockFast(@NotNull World world, @NotNull BlockPosition position, } chunkSection.setType(position.getX()&15, position.getY()&15, position.getZ()&15, data); + world.notify(position, data, data, 3); } @Override From 787b5ce7ca654975a1216428eb09dbe7c008dd0a Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Fri, 28 Feb 2020 15:34:04 +0100 Subject: [PATCH 123/304] Tile entities are now fully fixed, so is redstone processing --- .../async/translation/TranslationTask.java | 14 +++++ .../compat/v1_13_R2/IWorldHandler.java | 54 ++++++++++++----- .../compat/v1_14_R1/IWorldHandler.java | 53 +++++++++++----- .../compat/v1_15_R1/IWorldHandler.java | 60 ++++++++++++++++--- 4 files changed, 146 insertions(+), 35 deletions(-) diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java index 2f208e0b0..7d9419f09 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java @@ -78,6 +78,12 @@ public TranslationTask(Craft c, int dx, int dy, int dz) { FALL_THROUGH_BLOCKS.add(Material.SNOW); FALL_THROUGH_BLOCKS.add(Material.CARROT); FALL_THROUGH_BLOCKS.add(Material.POTATO); + for (Material type : Material.values()) { + if (!type.name().endsWith("FENCE")) { + continue; + } + FALL_THROUGH_BLOCKS.add(type); + } if (Settings.IsLegacy) { FALL_THROUGH_BLOCKS.add(LegacyUtils.STATIONARY_WATER); FALL_THROUGH_BLOCKS.add(LegacyUtils.STATIONARY_LAVA); @@ -117,6 +123,14 @@ public TranslationTask(Craft c, int dx, int dy, int dz) { FALL_THROUGH_BLOCKS.add(Material.LILAC); FALL_THROUGH_BLOCKS.add(Material.PEONY); FALL_THROUGH_BLOCKS.add(Material.SEA_PICKLE); + FALL_THROUGH_BLOCKS.add(Material.REPEATER); + FALL_THROUGH_BLOCKS.add(Material.COMPARATOR); + for (Material type : Material.values()) { + if (!type.name().endsWith("BUTTON") && !type.name().endsWith("PRESSURE_PLATE") && !type.name().endsWith("CARPET")) { + continue; + } + FALL_THROUGH_BLOCKS.add(type); + } } } diff --git a/modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/IWorldHandler.java b/modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/IWorldHandler.java index f79b2b097..79881f79c 100644 --- a/modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/IWorldHandler.java +++ b/modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/IWorldHandler.java @@ -91,9 +91,18 @@ public void rotateCraft(@NotNull Craft craft, @NotNull MovecraftLocation originP for(BlockPosition position : rotatedPositions.keySet()){ blockData.put(position,nativeWorld.getType(position).a(ROTATION[rotation.ordinal()])); } + HashMap redstoneComponents = new HashMap<>(); //create the new block for(Map.Entry entry : blockData.entrySet()) { - setBlockFast(nativeWorld, rotatedPositions.get(entry.getKey()), entry.getValue()); + final BlockPosition newPosition = rotatedPositions.get(entry.getKey()); + final IBlockData iBlockData = entry.getValue(); + if (nativeWorld.getTileEntity(newPosition) != null) { + removeTileEntity(nativeWorld, newPosition); + } + if (isRedstoneComponent(iBlockData)) + redstoneComponents.put(newPosition, iBlockData); + + setBlockFast(nativeWorld, newPosition, iBlockData); } @@ -129,6 +138,21 @@ public void rotateCraft(@NotNull Craft craft, @NotNull MovecraftLocation originP BlockFire fire = (BlockFire) type.getBlock(); fire.a(type, nativeWorld, position, nativeWorld.random); } + + for (Map.Entry entry : redstoneComponents.entrySet()) { + final BlockPosition position = entry.getKey(); + final IBlockData data = entry.getValue(); + Chunk chunk = nativeWorld.getChunkAtWorldCoords(position); + ChunkSection chunkSection = chunk.getSections()[position.getY()>>4]; + if (chunkSection == null) { + // Put a GLASS block to initialize the section. It will be replaced next with the real block. + chunk.setType(position, Blocks.GLASS.getBlockData(), true); + chunkSection = chunk.getSections()[position.getY() >> 4]; + + } + chunkSection.setType(position.getX()&15, position.getY()&15, position.getZ()&15, data); + nativeWorld.notifyAndUpdatePhysics(position, chunk, data, data, data, 3); + } //******************************************* //* Step six: Send to players * //******************************************* @@ -224,11 +248,6 @@ public void translateCraft(@NotNull Craft craft, @NotNull MovecraftLocation disp setBlockFast(nativeWorld, position, Blocks.AIR.getBlockData()); } - //Place redstone blocks and apply physics - for (BlockPosition position : redstoneComponents.keySet()) { - setBlockFast(nativeWorld, position, redstoneComponents.get(position), true); - } - //******************************************* //* Step six: Process fire spread * //******************************************* @@ -240,6 +259,21 @@ public void translateCraft(@NotNull Craft craft, @NotNull MovecraftLocation disp BlockFire fire = (BlockFire) type.getBlock(); fire.a(type, nativeWorld, position, nativeWorld.random); } + + for (Map.Entry entry : redstoneComponents.entrySet()) { + final BlockPosition position = entry.getKey(); + final IBlockData data = entry.getValue(); + Chunk chunk = nativeWorld.getChunkAtWorldCoords(position); + ChunkSection chunkSection = chunk.getSections()[position.getY()>>4]; + if (chunkSection == null) { + // Put a GLASS block to initialize the section. It will be replaced next with the real block. + chunk.setType(position, Blocks.GLASS.getBlockData(), true); + chunkSection = chunk.getSections()[position.getY() >> 4]; + + } + chunkSection.setType(position.getX()&15, position.getY()&15, position.getZ()&15, data); + nativeWorld.notifyAndUpdatePhysics(position, chunk, data, data, data, 3); + } //******************************************* //* Step six: Send to players * //******************************************* @@ -308,10 +342,6 @@ private BlockPosition locationToPosition(@NotNull MovecraftLocation loc) { } private void setBlockFast(@NotNull World world, @NotNull BlockPosition position,@NotNull IBlockData data) { - setBlockFast(world, position, data, false); - } - - private void setBlockFast(@NotNull World world, @NotNull BlockPosition position,@NotNull IBlockData data, boolean physics) { Chunk chunk = world.getChunkAtWorldCoords(position); ChunkSection chunkSection = chunk.getSections()[position.getY()>>4]; if (chunkSection == null) { @@ -321,10 +351,6 @@ private void setBlockFast(@NotNull World world, @NotNull BlockPosition position, } chunkSection.setType(position.getX()&15, position.getY()&15, position.getZ()&15, data); - if (physics) { - world.notifyAndUpdatePhysics(position, chunk, data, data, data, 3); - return; - } world.notify(position, data, data, 3); } diff --git a/modules/v1_14_R1/src/main/java/net/countercraft/movecraft/compat/v1_14_R1/IWorldHandler.java b/modules/v1_14_R1/src/main/java/net/countercraft/movecraft/compat/v1_14_R1/IWorldHandler.java index ecbfc20d0..38f53703d 100644 --- a/modules/v1_14_R1/src/main/java/net/countercraft/movecraft/compat/v1_14_R1/IWorldHandler.java +++ b/modules/v1_14_R1/src/main/java/net/countercraft/movecraft/compat/v1_14_R1/IWorldHandler.java @@ -88,9 +88,18 @@ public void rotateCraft(@NotNull Craft craft, @NotNull MovecraftLocation originP for(BlockPosition position : rotatedPositions.keySet()){ blockData.put(position,nativeWorld.getType(position).a(ROTATION[rotation.ordinal()])); } + HashMap redstoneComponents = new HashMap<>(); //create the new block for(Map.Entry entry : blockData.entrySet()) { - setBlockFast(nativeWorld, rotatedPositions.get(entry.getKey()), entry.getValue()); + final BlockPosition newPosition = rotatedPositions.get(entry.getKey()); + final IBlockData iBlockData = entry.getValue(); + if (nativeWorld.getTileEntity(newPosition) != null) { + removeTileEntity(nativeWorld, newPosition); + } + if (isRedstoneComponent(iBlockData)) + redstoneComponents.put(newPosition, iBlockData); + + setBlockFast(nativeWorld, newPosition, iBlockData); } @@ -128,6 +137,21 @@ public void rotateCraft(@NotNull Craft craft, @NotNull MovecraftLocation originP BlockFire fire = (BlockFire) type.getBlock(); fire.tick(type, nativeWorld, position, nativeWorld.random); } + + for (Map.Entry entry : redstoneComponents.entrySet()) { + final BlockPosition position = entry.getKey(); + final IBlockData data = entry.getValue(); + Chunk chunk = nativeWorld.getChunkAtWorldCoords(position); + ChunkSection chunkSection = chunk.getSections()[position.getY()>>4]; + if (chunkSection == null) { + // Put a GLASS block to initialize the section. It will be replaced next with the real block. + chunk.setType(position, Blocks.GLASS.getBlockData(), true); + chunkSection = chunk.getSections()[position.getY() >> 4]; + + } + chunkSection.setType(position.getX()&15, position.getY()&15, position.getZ()&15, data); + nativeWorld.notifyAndUpdatePhysics(position, chunk, data, data, data, 3); + } //******************************************* //* Step six: Send to players * //******************************************* @@ -224,11 +248,6 @@ public void translateCraft(@NotNull Craft craft, @NotNull MovecraftLocation disp setBlockFast(nativeWorld, position, Blocks.AIR.getBlockData()); } - //Place redstone blocks and apply physics - for (BlockPosition position : redstoneComponents.keySet()) { - setBlockFast(nativeWorld, position, redstoneComponents.get(position), true); - } - //******************************************* //* Step six: Process fire spread * //******************************************* @@ -241,6 +260,20 @@ public void translateCraft(@NotNull Craft craft, @NotNull MovecraftLocation disp fire.tick(type, nativeWorld, position, nativeWorld.random); } + for (Map.Entry entry : redstoneComponents.entrySet()) { + final BlockPosition position = entry.getKey(); + final IBlockData data = entry.getValue(); + Chunk chunk = nativeWorld.getChunkAtWorldCoords(position); + ChunkSection chunkSection = chunk.getSections()[position.getY()>>4]; + if (chunkSection == null) { + // Put a GLASS block to initialize the section. It will be replaced next with the real block. + chunk.setType(position, Blocks.GLASS.getBlockData(), true); + chunkSection = chunk.getSections()[position.getY() >> 4]; + + } + chunkSection.setType(position.getX()&15, position.getY()&15, position.getZ()&15, data); + nativeWorld.notifyAndUpdatePhysics(position, chunk, data, data, data, 3); + } //******************************************* //* Step six: Send to players * //******************************************* @@ -308,10 +341,6 @@ private BlockPosition locationToPosition(@NotNull MovecraftLocation loc) { } private void setBlockFast(@NotNull World world, @NotNull BlockPosition position,@NotNull IBlockData data) { - setBlockFast(world, position, data, false); - } - - private void setBlockFast(@NotNull World world, @NotNull BlockPosition position,@NotNull IBlockData data, boolean physics) { Chunk chunk = world.getChunkAtWorldCoords(position); ChunkSection chunkSection = chunk.getSections()[position.getY()>>4]; if (chunkSection == null) { @@ -321,10 +350,6 @@ private void setBlockFast(@NotNull World world, @NotNull BlockPosition position, } chunkSection.setType(position.getX()&15, position.getY()&15, position.getZ()&15, data); - if (physics) { - world.notifyAndUpdatePhysics(position, chunk, data, data, data, 3); - return; - } world.notify(position, data, data, 3); } diff --git a/modules/v1_15_R1/src/main/java/net/countercraft/movecraft/compat/v1_15_R1/IWorldHandler.java b/modules/v1_15_R1/src/main/java/net/countercraft/movecraft/compat/v1_15_R1/IWorldHandler.java index 6c6c155f8..34194e82f 100644 --- a/modules/v1_15_R1/src/main/java/net/countercraft/movecraft/compat/v1_15_R1/IWorldHandler.java +++ b/modules/v1_15_R1/src/main/java/net/countercraft/movecraft/compat/v1_15_R1/IWorldHandler.java @@ -74,7 +74,7 @@ public void rotateCraft(@NotNull Craft craft, @NotNull MovecraftLocation originP continue; tile.a(ROTATION[rotation.ordinal()]); //get the nextTick to move with the tile - tiles.add(new TileHolder(tile, tickProvider.getNextTick((WorldServer)nativeWorld,position), position)); + tiles.add(new TileHolder(tile, tickProvider.getNextTick(nativeWorld,position), position)); } //******************************************* @@ -87,6 +87,7 @@ public void rotateCraft(@NotNull Craft craft, @NotNull MovecraftLocation originP //get the blocks and rotate them HashMap blockData = new HashMap<>(); for(BlockPosition position : rotatedPositions.keySet()){ + blockData.put(position,nativeWorld.getType(position).a(ROTATION[rotation.ordinal()])); } HashMap redstoneComponents = new HashMap<>(); @@ -94,9 +95,11 @@ public void rotateCraft(@NotNull Craft craft, @NotNull MovecraftLocation originP for(Map.Entry entry : blockData.entrySet()) { final BlockPosition newPosition = rotatedPositions.get(entry.getKey()); final IBlockData iBlockData = entry.getValue(); - if (isRedstoneComponent(iBlockData)) { - redstoneComponents.put(newPosition, iBlockData); + if (nativeWorld.getTileEntity(newPosition) != null) { + removeTileEntity(nativeWorld, newPosition); } + if (isRedstoneComponent(iBlockData)) + redstoneComponents.put(newPosition, iBlockData); setBlockFast(nativeWorld, newPosition, iBlockData); } @@ -135,6 +138,21 @@ public void rotateCraft(@NotNull Craft craft, @NotNull MovecraftLocation originP fire.tick(type, nativeWorld, position, nativeWorld.random); } + for (Map.Entry entry : redstoneComponents.entrySet()) { + final BlockPosition position = entry.getKey(); + final IBlockData data = entry.getValue(); + Chunk chunk = nativeWorld.getChunkAtWorldCoords(position); + ChunkSection chunkSection = chunk.getSections()[position.getY()>>4]; + if (chunkSection == null) { + // Put a GLASS block to initialize the section. It will be replaced next with the real block. + chunk.setType(position, Blocks.GLASS.getBlockData(), true); + chunkSection = chunk.getSections()[position.getY() >> 4]; + + } + chunkSection.setType(position.getX()&15, position.getY()&15, position.getZ()&15, data); + nativeWorld.notifyAndUpdatePhysics(position, chunk, data, data, data, 3); + } + //******************************************* //* Step six: Send to players * //******************************************* @@ -200,6 +218,7 @@ public void translateCraft(@NotNull Craft craft, @NotNull MovecraftLocation disp blockData.add(nativeWorld.getType(position)); newPositions.add(position.a(translateVector)); } + Map redstoneComponents = new HashMap<>(); //create the new block for(int i = 0; i entry : redstoneComponents.entrySet()) { + final BlockPosition position = entry.getKey(); + final IBlockData data = entry.getValue(); + Chunk chunk = nativeWorld.getChunkAtWorldCoords(position); + ChunkSection chunkSection = chunk.getSections()[position.getY()>>4]; + if (chunkSection == null) { + // Put a GLASS block to initialize the section. It will be replaced next with the real block. + chunk.setType(position, Blocks.GLASS.getBlockData(), true); + chunkSection = chunk.getSections()[position.getY() >> 4]; + + } + chunkSection.setType(position.getX()&15, position.getY()&15, position.getZ()&15, data); + nativeWorld.notifyAndUpdatePhysics(position, chunk, data, data, data, 3); + } //******************************************* //* Step six: Send to players * //******************************************* @@ -322,8 +355,7 @@ private void setBlockFast(@NotNull World world, @NotNull BlockPosition position, chunkSection = chunk.getSections()[position.getY() >> 4]; } - - chunkSection.setType(position.getX()&15, position.getY()&15, position.getZ()&15, data); + chunkSection.setType(position.getX() & 15, position.getY() & 15, position.getZ() & 15, data); world.notify(position, data, data, 3); } @@ -338,6 +370,9 @@ public void setBlockFast(@NotNull Location location, @NotNull Rotation rotation, blockData = blockData.a(ROTATION[rotation.ordinal()]); WorldServer world = ((CraftWorld)(location.getWorld())).getHandle(); BlockPosition blockPosition = locationToPosition(bukkit2MovecraftLoc(location)); + if (world.getTileEntity(blockPosition) != null) { + removeTileEntity(world, blockPosition); + } setBlockFast(world,blockPosition,blockData); } @@ -408,4 +443,15 @@ private boolean isRedstoneComponent(IBlockData blockData) { block instanceof BlockLever; } + + private boolean isPowered (IBlockData data) { + if (data.getBlock() instanceof BlockRedstoneWire) { + return data.get(BlockRedstoneWire.POWER) > 0; + } else if (data.getBlock() instanceof BlockDiodeAbstract) { + return data.get(BlockDiodeAbstract.c); + } else if (data.getBlock() instanceof BlockButtonAbstract || data.getBlock() instanceof BlockLever) { + return data.get(BlockButtonAbstract.POWERED); + } + return false; + } } From 2ee62a627bb31548d5c70d62f91401196ab93d71 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Sun, 22 Mar 2020 13:12:01 +0100 Subject: [PATCH 124/304] Some fixes from upstream --- .../movecraft/async/detection/DetectionTask.java | 3 +-- .../java/net/countercraft/movecraft/sign/StatusSign.java | 7 +++---- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/detection/DetectionTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/detection/DetectionTask.java index e2da8cf4d..efe98fcde 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/detection/DetectionTask.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/detection/DetectionTask.java @@ -32,7 +32,6 @@ import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.World; -import org.bukkit.block.Block; import org.bukkit.block.BlockState; import org.bukkit.block.Sign; import org.bukkit.entity.Player; @@ -178,7 +177,7 @@ public void run() { p = data.getPlayer(); } if (p != null) { - if (testID == 8 || testID == 9 || testID == 10 || testID == 11) { + if (testType.name().endsWith("WATER") || testType.name().endsWith("LAVA")) { fluidList.add(workingLocation); } addToBlockList(workingLocation); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/StatusSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/StatusSign.java index bfd43926c..12f9a2ece 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/StatusSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/StatusSign.java @@ -17,6 +17,7 @@ import org.bukkit.event.Listener; import org.bukkit.inventory.ItemStack; +import java.util.ArrayList; import java.util.HashMap; import java.util.Map; @@ -101,7 +102,8 @@ public final void onSignTranslate(SignTranslateEvent event) { } else { signText += ChatColor.RED; } - signText += Settings.StatusSignMarkers.get(flyBlocks); + String[] parts = new ArrayList<>(entry.getBlocks()).get(0).getType().name().split("_"); + signText += parts[ entry.getBlocks().size() > 1 ? parts.length - 1 : 0 ].charAt(0); signText += " "; signText += (int) percentPresent; signText += "/"; @@ -119,9 +121,6 @@ public final void onSignTranslate(SignTranslateEvent event) { } } - if (signLine < 3 && signColumn == 1){ - signLine++; - } if (signLine < 3 && signColumn == 1){ signLine++; } From 5653224bd05c24763bcc0abaaa3f6863a201837f Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Mon, 23 Mar 2020 13:27:25 +0100 Subject: [PATCH 125/304] Removed unused variable --- .../src/main/java/net/countercraft/movecraft/Movecraft.java | 1 - 1 file changed, 1 deletion(-) diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java index 01ef4e9c7..58c0fc2d7 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java @@ -524,7 +524,6 @@ public void onEnable() { getServer().getPluginManager().registerEvents(new InteractListener(), this); if (worldEditPlugin != null) { - final Class clazz; if (movecraftRepair != null){ repairManager = new RepairManager(); repairManager.runTaskTimerAsynchronously(this, 0, 1); From ff8c33ef60d4b906af4523dd6daef46523986ac8 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Wed, 25 Mar 2020 18:49:45 +0100 Subject: [PATCH 126/304] Fixed a bug with the BlockListener on 1.12.2 and earlier versions and typos in legacy craft files --- .../movecraft/listener/BlockListener.java | 112 +++++++++++------- .../resources/types/legacy/BigAirship.craft | 2 +- .../types/legacy/BigSubAirship.craft | 2 +- .../main/resources/types/legacy/airship.craft | 2 +- .../movecraft/utils/LegacyUtils.java | 98 +++++++-------- 5 files changed, 120 insertions(+), 96 deletions(-) diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/BlockListener.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/BlockListener.java index b042a2c76..6c7fe4a2d 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/BlockListener.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/BlockListener.java @@ -31,14 +31,11 @@ import net.countercraft.movecraft.utils.LegacyUtils; import net.countercraft.movecraft.utils.MathUtils; import net.countercraft.movecraft.utils.WorldguardUtils; -import net.countercraft.movecraft.warfare.assault.AssaultUtils; -import net.countercraft.movecraft.utils.MathUtils; import net.countercraft.movecraft.warfare.assault.Assault; import org.bukkit.*; -import org.bukkit.block.Block; -import org.bukkit.block.BlockFace; -import org.bukkit.block.Hopper; -import org.bukkit.block.Sign; +import org.bukkit.block.*; +import org.bukkit.block.data.BlockData; +import org.bukkit.block.data.Directional; import org.bukkit.entity.Entity; import org.bukkit.entity.EntityType; import org.bukkit.entity.Player; @@ -57,7 +54,6 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.Arrays; import java.util.Iterator; import java.util.List; import java.util.Random; @@ -66,26 +62,17 @@ public class BlockListener implements Listener { private long lastDamagesUpdate; - final Material[] fragileBlocks = Settings.IsLegacy ? new Material[]{LegacyUtils.BED_BLOCK, LegacyUtils.PISTON_EXTENSION, Material.TORCH, Material.REDSTONE_WIRE, LegacyUtils.SIGN_POST, LegacyUtils.WOOD_DOOR, Material.LADDER, Material.getMaterial("WALL_SIGN"), - Material.BIRCH_SIGN,Material.OAK_SIGN,Material.DARK_OAK_SIGN,Material.JUNGLE_SIGN,Material.SPRUCE_SIGN,Material.ACACIA_SIGN,Material.BIRCH_WALL_SIGN - ,Material.OAK_WALL_SIGN,Material.DARK_OAK_WALL_SIGN, Material.JUNGLE_WALL_SIGN, Material.SPRUCE_WALL_SIGN, Material.ACACIA_WALL_SIGN, Material.LEVER, LegacyUtils.STONE_PLATE, LegacyUtils.IRON_DOOR_BLOCK, LegacyUtils.WOOD_PLATE, LegacyUtils.REDSTONE_TORCH_OFF, LegacyUtils.REDSTONE_TORCH_ON, Material.STONE_BUTTON, LegacyUtils.DIODE_BLOCK_OFF, LegacyUtils.DIODE_BLOCK_ON, LegacyUtils.TRAP_DOOR, Material.TRIPWIRE_HOOK, - Material.TRIPWIRE, LegacyUtils.WOOD_BUTTON, LegacyUtils.GOLD_PLATE, LegacyUtils.IRON_PLATE, LegacyUtils.REDSTONE_COMPARATOR_OFF, LegacyUtils.REDSTONE_COMPARATOR_ON, Material.DAYLIGHT_DETECTOR, LegacyUtils.CARPET, LegacyUtils.DAYLIGHT_DETECTOR_INVERTED, Material.SPRUCE_DOOR, Material.BIRCH_DOOR, Material.JUNGLE_DOOR, Material.ACACIA_DOOR, Material.DARK_OAK_DOOR} + final Material[] fragileBlocks = Settings.IsLegacy ? new Material[]{ + + } : new Material[] //Beds - {Material.CYAN_BED, Material.BLACK_BED, Material.BLUE_BED, - Material.BROWN_BED, Material.GRAY_BED, Material.GREEN_BED, Material.LIGHT_BLUE_BED, Material.LIGHT_GRAY_BED, Material.LIME_BED, Material.MAGENTA_BED, - Material.ORANGE_BED, Material.PINK_BED, Material.PURPLE_BED, Material.RED_BED, Material.WHITE_BED, Material.YELLOW_BED, + { //Redstone components - Material.REDSTONE_WIRE, Material.REPEATER, Material.COMPARATOR, Material.REDSTONE_TORCH, Material.REDSTONE_WALL_TORCH, Material.TRIPWIRE_HOOK, - //Pressure plates - Material.STONE_PRESSURE_PLATE, Material.ACACIA_PRESSURE_PLATE, Material.BIRCH_PRESSURE_PLATE, Material.DARK_OAK_PRESSURE_PLATE, Material.HEAVY_WEIGHTED_PRESSURE_PLATE, Material.LIGHT_WEIGHTED_PRESSURE_PLATE, Material.JUNGLE_PRESSURE_PLATE, Material.OAK_PRESSURE_PLATE, Material.SPRUCE_PRESSURE_PLATE, - //Buttons - Material.STONE_BUTTON, Material.BIRCH_BUTTON, Material.ACACIA_BUTTON, Material.DARK_OAK_BUTTON, Material.JUNGLE_BUTTON, Material.OAK_BUTTON, Material.SPRUCE_BUTTON, - //Doors - Material.SPRUCE_DOOR, Material.BIRCH_DOOR, Material.JUNGLE_DOOR, Material.ACACIA_DOOR, Material.DARK_OAK_DOOR, Material.OAK_DOOR, Material.IRON_DOOR, - //Trapdoors - Material.IRON_TRAPDOOR, Material.ACACIA_TRAPDOOR, Material.BIRCH_TRAPDOOR}; + + + }; @EventHandler public void onBlockPlace(final BlockPlaceEvent e) { @@ -250,36 +237,36 @@ public void onPhysics(BlockPhysicsEvent event) { } Block block = event.getBlock(); - - final Material[] fragileBlocks = Settings.IsLegacy ? new Material[]{LegacyUtils.BED_BLOCK, LegacyUtils.PISTON_EXTENSION, Material.TORCH, Material.REDSTONE_WIRE, LegacyUtils.SIGN_POST, LegacyUtils.WOOD_DOOR, Material.LADDER, Material.getMaterial("WALL_SIGN"), Material.LEVER, LegacyUtils.STONE_PLATE, LegacyUtils.IRON_DOOR_BLOCK, LegacyUtils.WOOD_PLATE, LegacyUtils.REDSTONE_TORCH_OFF, LegacyUtils.REDSTONE_TORCH_ON, Material.STONE_BUTTON, LegacyUtils.DIODE_BLOCK_OFF, LegacyUtils.DIODE_BLOCK_ON, LegacyUtils.TRAP_DOOR, Material.TRIPWIRE_HOOK, - Material.TRIPWIRE, LegacyUtils.WOOD_BUTTON, LegacyUtils.GOLD_PLATE, LegacyUtils.IRON_PLATE, LegacyUtils.REDSTONE_COMPARATOR_OFF, LegacyUtils.REDSTONE_COMPARATOR_ON, Material.DAYLIGHT_DETECTOR, LegacyUtils.CARPET, LegacyUtils.DAYLIGHT_DETECTOR_INVERTED, Material.SPRUCE_DOOR, Material.BIRCH_DOOR, Material.JUNGLE_DOOR, Material.ACACIA_DOOR, Material.DARK_OAK_DOOR} - : null; - CraftManager.getInstance().getCraftsInWorld(block.getWorld()); for (Craft tcraft : CraftManager.getInstance().getCraftsInWorld(block.getWorld())) { MovecraftLocation mloc = new MovecraftLocation(block.getX(), block.getY(), block.getZ()); if (!MathUtils.locIsNearCraftFast(tcraft, mloc)) { continue; } - if (Settings.IsLegacy) { - if (Arrays.binarySearch(fragileBlocks, block.getType()) >= 0) { + if (isFragileBlock(block)) { + BlockFace face = BlockFace.DOWN; + boolean faceAlwaysDown = false; + if (Settings.IsLegacy) { MaterialData m = block.getState().getData(); - BlockFace face = BlockFace.DOWN; - boolean faceAlwaysDown = false; if (block.getType() == LegacyUtils.REDSTONE_COMPARATOR_ON || block.getType() == LegacyUtils.REDSTONE_COMPARATOR_OFF || block.getType() == LegacyUtils.DIODE_BLOCK_ON|| block.getType() == LegacyUtils.DIODE_BLOCK_OFF) faceAlwaysDown = true; if (m instanceof Attachable && !faceAlwaysDown) { face = ((Attachable) m).getAttachedFace(); } - if (!event.getBlock().getRelative(face).getType().isSolid()) { + } else { + BlockData data = block.getBlockData(); + if (block.getType() == Material.REPEATER || block.getType() == Material.COMPARATOR) + faceAlwaysDown = true; + if (data instanceof Directional && !faceAlwaysDown) + face = ((Directional) data).getFacing().getOppositeFace(); + } + if (!event.getBlock().getRelative(face).getType().isSolid()) { // if(event.getEventName().equals("BlockPhysicsEvent")) { - event.setCancelled(true); - return; - } + event.setCancelled(true); + return; } - } else { - } + } } @@ -426,12 +413,12 @@ private void processAssault(EntityExplodeEvent e){ b.getLocation().getBlockZ() < min.getBlockZ() || b.getLocation().getBlockZ() > max.getBlockZ() || !Settings.AssaultDestroyableBlocks.contains(b.getType()) || - Arrays.binarySearch(fragileBlocks, b.getRelative(BlockFace.SOUTH).getType()) >= 0 || - Arrays.binarySearch(fragileBlocks, b.getRelative(BlockFace.DOWN).getType()) >= 0 || - Arrays.binarySearch(fragileBlocks, b.getRelative(BlockFace.UP).getType()) >= 0 || - Arrays.binarySearch(fragileBlocks, b.getRelative(BlockFace.EAST).getType()) >= 0 || - Arrays.binarySearch(fragileBlocks, b.getRelative(BlockFace.WEST).getType()) >= 0 || - Arrays.binarySearch(fragileBlocks, b.getRelative(BlockFace.NORTH).getType()) >= 0 ) { + isFragileBlock(b.getRelative(BlockFace.SOUTH)) || + isFragileBlock(b.getRelative(BlockFace.DOWN)) || + isFragileBlock(b.getRelative(BlockFace.UP)) || + isFragileBlock(b.getRelative(BlockFace.EAST)) || + isFragileBlock(b.getRelative(BlockFace.WEST)) || + isFragileBlock(b.getRelative(BlockFace.NORTH)) ) { i.remove(); } @@ -498,4 +485,41 @@ private boolean pistonFacingLocation(Location loc) { } return false; } + private boolean isFragileBlock(Block block) { + Material type = block.getType(); + BlockState state = block.getState(); + return type.name().endsWith("_BED") || + state instanceof Sign || + type.name().endsWith("DOOR") || + type.name().endsWith("BUTTON") || + type.name().endsWith("_PLATE") || + type == Material.REDSTONE_WIRE || + type.name().endsWith("TORCH") || + type == Material.TRIPWIRE || + type == Material.TRIPWIRE_HOOK || + type == Material.LADDER || + type == Material.LEVER || + type == Material.DAYLIGHT_DETECTOR || + (Settings.IsLegacy ? + (type == LegacyUtils.BED_BLOCK|| + type == LegacyUtils.PISTON_EXTENSION|| + type == LegacyUtils.SIGN_POST|| + type == LegacyUtils.WOOD_DOOR|| + type == LegacyUtils.WALL_SIGN|| + type == LegacyUtils.IRON_DOOR_BLOCK|| + type == LegacyUtils.REDSTONE_TORCH_OFF|| + type == LegacyUtils.REDSTONE_TORCH_ON|| + type == LegacyUtils.DIODE_BLOCK_OFF|| + type == LegacyUtils.DIODE_BLOCK_ON|| + type == LegacyUtils.TRAP_DOOR || + type == LegacyUtils.REDSTONE_COMPARATOR_OFF|| + type == LegacyUtils.REDSTONE_COMPARATOR_ON || + type == LegacyUtils.CARPET|| + type == LegacyUtils.DAYLIGHT_DETECTOR_INVERTED) + : + (type == Material.REPEATER || + type == Material.COMPARATOR ) + ); + + } } diff --git a/modules/Movecraft/src/main/resources/types/legacy/BigAirship.craft b/modules/Movecraft/src/main/resources/types/legacy/BigAirship.craft index 3e2787814..9f778b99d 100644 --- a/modules/Movecraft/src/main/resources/types/legacy/BigAirship.craft +++ b/modules/Movecraft/src/main/resources/types/legacy/BigAirship.craft @@ -139,7 +139,7 @@ tryNudge: false canStaticMove: true maxStaticMove: 2 moveblocks: - REDSTONNE_BLOCK: # redstone represents engines + REDSTONE_BLOCK: # redstone represents engines - 1.0 - 100.0 flyblocks: diff --git a/modules/Movecraft/src/main/resources/types/legacy/BigSubAirship.craft b/modules/Movecraft/src/main/resources/types/legacy/BigSubAirship.craft index 1de0de357..0bf1035de 100644 --- a/modules/Movecraft/src/main/resources/types/legacy/BigSubAirship.craft +++ b/modules/Movecraft/src/main/resources/types/legacy/BigSubAirship.craft @@ -137,7 +137,7 @@ sinkPercent: 99.0 overallSinkPercent: 60.0 halfSpeedUnderwater: true moveblocks: - REDSTONNE_BLOCK: # redstone represents engines + REDSTONE_BLOCK: # redstone represents engines - 1.0 - 100.0 flyblocks: diff --git a/modules/Movecraft/src/main/resources/types/legacy/airship.craft b/modules/Movecraft/src/main/resources/types/legacy/airship.craft index 1f9ff2ecc..f385f1b89 100644 --- a/modules/Movecraft/src/main/resources/types/legacy/airship.craft +++ b/modules/Movecraft/src/main/resources/types/legacy/airship.craft @@ -137,7 +137,7 @@ tryNudge: false canStaticMove: true maxStaticMove: 2 moveblocks: - REDSTONNE_BLOCK: # redstone represents engines + REDSTONE_BLOCK: # redstone represents engines - 1.0 - 100.0 flyblocks: diff --git a/modules/api/src/main/java/net/countercraft/movecraft/utils/LegacyUtils.java b/modules/api/src/main/java/net/countercraft/movecraft/utils/LegacyUtils.java index 3578c7fa5..932d4dbe6 100644 --- a/modules/api/src/main/java/net/countercraft/movecraft/utils/LegacyUtils.java +++ b/modules/api/src/main/java/net/countercraft/movecraft/utils/LegacyUtils.java @@ -17,56 +17,56 @@ public class LegacyUtils { - public static final Material WALL_SIGN = Material.WALL_SIGN; + public static final Material WALL_SIGN = !Settings.is1_14 ? Material.WALL_SIGN : null; //Materials removed in 1.13 - public static Material BED_BLOCK = Settings.IsLegacy ? Material.BED_BLOCK : null; - public static Material CARPET = Settings.IsLegacy ? Material.CARPET : null; - public static Material CROPS = Settings.IsLegacy ? Material.CROPS : null; - public static Material DAYLIGHT_DETECTOR_INVERTED = Settings.IsLegacy ? Material.DAYLIGHT_DETECTOR_INVERTED : null; - public static Material DIODE = Settings.IsLegacy ? Material.DIODE : null; - public static Material DIODE_BLOCK_OFF = Settings.IsLegacy ? Material.DIODE_BLOCK_OFF : null; - public static Material DIODE_BLOCK_ON = Settings.IsLegacy ? Material.DIODE_BLOCK_ON : null; - public static Material DOUBLE_PLANT = Settings.IsLegacy ? Material.DOUBLE_PLANT : null; - public static Material FENCE = Settings.IsLegacy ? Material.FENCE : null; - public static Material FIREBALL = Settings.IsLegacy ? Material.FIREBALL : null; - public static Material GOLD_PLATE = Settings.IsLegacy ? Material.GOLD_PLATE : null; - public static Material IRON_DOOR_BLOCK = Settings.IsLegacy ? Material.IRON_DOOR_BLOCK : null; - public static Material IRON_FENCE = Settings.IsLegacy ? Material.IRON_FENCE : null; - public static Material IRON_PLATE = Settings.IsLegacy ? Material.IRON_PLATE : null; - public static Material LEAVES = Settings.IsLegacy ? Material.LEAVES : null; - public static Material LEAVES_2 = Settings.IsLegacy ? Material.LEAVES_2 : null; - public static Material LOG = Settings.IsLegacy ? Material.LOG : null; - public static Material LOG_2 = Settings.IsLegacy ? Material.LOG_2 : null; - public static Material LONG_GRASS = Settings.IsLegacy ? Material.LONG_GRASS : null; - public static Material PISTON_BASE = Settings.IsLegacy ? Material.PISTON_BASE : null; - public static Material PISTON_EXTENSION = Settings.IsLegacy ? Material.PISTON_EXTENSION : null; - public static Material PISTON_STICKY_BASE = Settings.IsLegacy ? Material.PISTON_STICKY_BASE : null; - public static Material RED_ROSE = Settings.IsLegacy ? Material.RED_ROSE : null; - public static Material REDSTONE_COMPARATOR = Settings.IsLegacy ? Material.REDSTONE_COMPARATOR : null; - public static Material REDSTONE_COMPARATOR_OFF = Settings.IsLegacy ? Material.REDSTONE_COMPARATOR_OFF : null; - public static Material REDSTONE_COMPARATOR_ON = Settings.IsLegacy ? Material.REDSTONE_COMPARATOR_ON : null; - public static Material REDSTONE_TORCH_ON = Settings.IsLegacy ? Material.REDSTONE_TORCH_ON : null; - public static Material REDSTONE_TORCH_OFF = Settings.IsLegacy ? Material.REDSTONE_TORCH_OFF : null; - public static Material SEEDS = Settings.IsLegacy ? Material.SEEDS : null; - public static Material SMOOTH_STAIRS = Settings.IsLegacy ? Material.SMOOTH_STAIRS : null; - public static Material STAINED_GLASS = Settings.IsLegacy ? Material.STAINED_GLASS : null; - public static Material STAINED_GLASS_PANE = Settings.IsLegacy ? Material.STAINED_GLASS_PANE : null; - public static Material STATIONARY_WATER = Settings.IsLegacy ? Material.STATIONARY_WATER : null; - public static Material STATIONARY_LAVA = Settings.IsLegacy ? Material.STATIONARY_LAVA : null; - public static Material STEP = Settings.IsLegacy ? Material.STEP : null; - public static Material STONE_PLATE = Settings.IsLegacy ? Material.STONE_PLATE : null; - public static Material SIGN_POST = Settings.IsLegacy ? Material.SIGN_POST : null; - public static Material SUGAR_CANE_BLOCK = Settings.IsLegacy ? Material.SUGAR_CANE_BLOCK : null; - public static Material THIN_GLASS = Settings.IsLegacy ? Material.THIN_GLASS : null; - public static Material TRAP_DOOR = Settings.IsLegacy ? Material.TRAP_DOOR : null; - public static Material WATER_LILY = Settings.IsLegacy ? Material.WATER_LILY : null; - public static Material WEB = Settings.IsLegacy ? Material.WEB : null; - public static Material WOOL = Settings.IsLegacy ? Material.WOOL : null; - public static Material WOOD = Settings.IsLegacy ? Material.WOOD : null; - public static Material WOOD_BUTTON = Settings.IsLegacy ? Material.WOOD_BUTTON : null; - public static Material WOOD_DOOR = Settings.IsLegacy ? Material.WOOD_DOOR : null; - public static Material WOOD_PLATE = Settings.IsLegacy ? Material.WOOD_PLATE : null; - public static Material YELLOW_FLOWER = Settings.IsLegacy ? Material.YELLOW_FLOWER : null; + public static final Material BED_BLOCK = Settings.IsLegacy ? Material.BED_BLOCK : null; + public static final Material CARPET = Settings.IsLegacy ? Material.CARPET : null; + public static final Material CROPS = Settings.IsLegacy ? Material.CROPS : null; + public static final Material DAYLIGHT_DETECTOR_INVERTED = Settings.IsLegacy ? Material.DAYLIGHT_DETECTOR_INVERTED : null; + public static final Material DIODE = Settings.IsLegacy ? Material.DIODE : null; + public static final Material DIODE_BLOCK_OFF = Settings.IsLegacy ? Material.DIODE_BLOCK_OFF : null; + public static final Material DIODE_BLOCK_ON = Settings.IsLegacy ? Material.DIODE_BLOCK_ON : null; + public static final Material DOUBLE_PLANT = Settings.IsLegacy ? Material.DOUBLE_PLANT : null; + public static final Material FENCE = Settings.IsLegacy ? Material.FENCE : null; + public static final Material FIREBALL = Settings.IsLegacy ? Material.FIREBALL : null; + public static final Material GOLD_PLATE = Settings.IsLegacy ? Material.GOLD_PLATE : null; + public static final Material IRON_DOOR_BLOCK = Settings.IsLegacy ? Material.IRON_DOOR_BLOCK : null; + public static final Material IRON_FENCE = Settings.IsLegacy ? Material.IRON_FENCE : null; + public static final Material IRON_PLATE = Settings.IsLegacy ? Material.IRON_PLATE : null; + public static final Material LEAVES = Settings.IsLegacy ? Material.LEAVES : null; + public static final Material LEAVES_2 = Settings.IsLegacy ? Material.LEAVES_2 : null; + public static final Material LOG = Settings.IsLegacy ? Material.LOG : null; + public static final Material LOG_2 = Settings.IsLegacy ? Material.LOG_2 : null; + public static final Material LONG_GRASS = Settings.IsLegacy ? Material.LONG_GRASS : null; + public static final Material PISTON_BASE = Settings.IsLegacy ? Material.PISTON_BASE : null; + public static final Material PISTON_EXTENSION = Settings.IsLegacy ? Material.PISTON_EXTENSION : null; + public static final Material PISTON_STICKY_BASE = Settings.IsLegacy ? Material.PISTON_STICKY_BASE : null; + public static final Material RED_ROSE = Settings.IsLegacy ? Material.RED_ROSE : null; + public static final Material REDSTONE_COMPARATOR = Settings.IsLegacy ? Material.REDSTONE_COMPARATOR : null; + public static final Material REDSTONE_COMPARATOR_OFF = Settings.IsLegacy ? Material.REDSTONE_COMPARATOR_OFF : null; + public static final Material REDSTONE_COMPARATOR_ON = Settings.IsLegacy ? Material.REDSTONE_COMPARATOR_ON : null; + public static final Material REDSTONE_TORCH_ON = Settings.IsLegacy ? Material.REDSTONE_TORCH_ON : null; + public static final Material REDSTONE_TORCH_OFF = Settings.IsLegacy ? Material.REDSTONE_TORCH_OFF : null; + public static final Material SEEDS = Settings.IsLegacy ? Material.SEEDS : null; + public static final Material SMOOTH_STAIRS = Settings.IsLegacy ? Material.SMOOTH_STAIRS : null; + public static final Material STAINED_GLASS = Settings.IsLegacy ? Material.STAINED_GLASS : null; + public static final Material STAINED_GLASS_PANE = Settings.IsLegacy ? Material.STAINED_GLASS_PANE : null; + public static final Material STATIONARY_WATER = Settings.IsLegacy ? Material.STATIONARY_WATER : null; + public static final Material STATIONARY_LAVA = Settings.IsLegacy ? Material.STATIONARY_LAVA : null; + public static final Material STEP = Settings.IsLegacy ? Material.STEP : null; + public static final Material STONE_PLATE = Settings.IsLegacy ? Material.STONE_PLATE : null; + public static final Material SIGN_POST = Settings.IsLegacy ? Material.SIGN_POST : null; + public static final Material SUGAR_CANE_BLOCK = Settings.IsLegacy ? Material.SUGAR_CANE_BLOCK : null; + public static final Material THIN_GLASS = Settings.IsLegacy ? Material.THIN_GLASS : null; + public static final Material TRAP_DOOR = Settings.IsLegacy ? Material.TRAP_DOOR : null; + public static final Material WATER_LILY = Settings.IsLegacy ? Material.WATER_LILY : null; + public static final Material WEB = Settings.IsLegacy ? Material.WEB : null; + public static final Material WOOL = Settings.IsLegacy ? Material.WOOL : null; + public static final Material WOOD = Settings.IsLegacy ? Material.WOOD : null; + public static final Material WOOD_BUTTON = Settings.IsLegacy ? Material.WOOD_BUTTON : null; + public static final Material WOOD_DOOR = Settings.IsLegacy ? Material.WOOD_DOOR : null; + public static final Material WOOD_PLATE = Settings.IsLegacy ? Material.WOOD_PLATE : null; + public static final Material YELLOW_FLOWER = Settings.IsLegacy ? Material.YELLOW_FLOWER : null; //Sounds removed in 1.13 public static Sound ENITIY_IRONGOLEM_DEATH = Settings.IsLegacy && !Settings.IsPre1_9 ? Sound.ENTITY_IRONGOLEM_DEATH : null; From eabc67f6d932244c07f6e39d939f6f673ee7c056 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Sun, 5 Apr 2020 21:35:24 +0200 Subject: [PATCH 127/304] Added update checking and automatic update of localisation files --- modules/Movecraft/pom.xml | 3 +- .../net/countercraft/movecraft/Movecraft.java | 3 + .../movecraft/localisation/I18nSupport.java | 30 ++++ .../movecraft/utils/UpdateManager.java | 128 ++++++++++++++++++ .../localisation/movecraftlang_en.properties | 5 +- 5 files changed, 166 insertions(+), 3 deletions(-) create mode 100644 modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/UpdateManager.java diff --git a/modules/Movecraft/pom.xml b/modules/Movecraft/pom.xml index 74f561d95..2059643de 100644 --- a/modules/Movecraft/pom.xml +++ b/modules/Movecraft/pom.xml @@ -9,7 +9,8 @@ UTF-8 - 7.0.0_beta_2 + + 7.0.0_for_1.8.8-1.15.2_beta_14 diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java index 6cb453f01..2ba61581c 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java @@ -26,6 +26,7 @@ import com.sk89q.worldguard.protection.flags.StateFlag; import net.countercraft.movecraft.async.AsyncManager; import net.countercraft.movecraft.commands.*; +import net.countercraft.movecraft.utils.UpdateManager; import net.countercraft.movecraft.worldguard.WorldGuardCompatManager; import net.countercraft.movecraft.config.Settings; import net.countercraft.movecraft.craft.CraftManager; @@ -569,6 +570,8 @@ public void onEnable() { getServer().getPluginManager().registerEvents(new SubcraftRotateSign(), this); getServer().getPluginManager().registerEvents(new TeleportSign(), this); + //Start the update manager + UpdateManager.getInstance(); logger.log(Level.INFO, String.format( I18nSupport.getInternationalisedString("Startup - Enabled message"), getDescription().getVersion())); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/localisation/I18nSupport.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/localisation/I18nSupport.java index aedb0de5e..d784c4722 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/localisation/I18nSupport.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/localisation/I18nSupport.java @@ -59,6 +59,36 @@ public static void init() { } catch (IOException e) { e.printStackTrace(); } + InputStream resource = Movecraft.getInstance().getResource("localisation/movecraftlang" + "_" + Settings.LOCALE + ".properties"); + Properties jarLangFile = new Properties(); + if (resource == null) { + return; + } + try { + jarLangFile.load(resource); + resource.close(); + } catch (IOException e) { + if (Settings.Debug) + e.printStackTrace(); + return; + } + boolean updated = false; + for (Object key : jarLangFile.keySet()) { + if (languageFile.contains(key)) { + continue; + } + languageFile.setProperty((String) key, (String) jarLangFile.get(key)); + updated = true; + } + if (!updated) + return; + try { + OutputStream output = new FileOutputStream(localisationDirectory.getAbsolutePath() + "/movecraftlang" + "_" + Settings.LOCALE + ".properties"); + languageFile.store(output, null); + output.close(); + } catch (IOException e) { + e.printStackTrace(); + } } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/UpdateManager.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/UpdateManager.java new file mode 100644 index 000000000..3a5b384a1 --- /dev/null +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/UpdateManager.java @@ -0,0 +1,128 @@ +package net.countercraft.movecraft.utils; + +import com.google.gson.Gson; +import net.countercraft.movecraft.Movecraft; +import net.countercraft.movecraft.localisation.I18nSupport; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerJoinEvent; +import org.bukkit.scheduler.BukkitRunnable; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.URL; +import java.net.URLConnection; +import java.util.List; +import java.util.Map; +import java.util.logging.Logger; + +import static net.countercraft.movecraft.utils.ChatUtils.MOVECRAFT_COMMAND_PREFIX; + +public class UpdateManager extends BukkitRunnable implements Listener { + private static UpdateManager instance; + + private UpdateManager() { + runTaskTimerAsynchronously(Movecraft.getInstance(), 40, 36000); + Bukkit.getPluginManager().registerEvents(this, Movecraft.getInstance()); + } + + @NotNull + public static UpdateManager getInstance() { + if (instance == null) { + instance = new UpdateManager(); + } + return instance; + } + + @Override + public void run() { + final Logger log = Movecraft.getInstance().getLogger(); + log.info(I18nSupport.getInternationalisedString("Update - Checking for updates")); + new BukkitRunnable() { + @Override + public void run() { + String newVersion = getNewVersion(); + if (newVersion == null) { + log.info(I18nSupport.getInternationalisedString("Update - Up to date")); + return; + } + Bukkit.broadcast(MOVECRAFT_COMMAND_PREFIX + I18nSupport.getInternationalisedString("Update - Update available"), "movecraft.update"); + Bukkit.broadcast("https://github.com/eirikh1996/Movecraft/releases/tag/" + newVersion, "movecraft.update"); + log.warning(I18nSupport.getInternationalisedString("Update - Update available")); + log.warning("https://github.com/eirikh1996/Movecraft/releases/tag/" + newVersion); + } + }.runTaskLaterAsynchronously(Movecraft.getInstance(), 100); + + } + + @EventHandler + public void onPlayerJoin(PlayerJoinEvent event) { + final Player p = event.getPlayer(); + if (!p.hasPermission("movecraft.update")) { + return; + } + new BukkitRunnable() { + @Override + public void run() { + String newVersion = getNewVersion(); + if (newVersion == null) { + return; + } + p.sendMessage(MOVECRAFT_COMMAND_PREFIX + I18nSupport.getInternationalisedString("Update - Update available")); + p.sendMessage("https://github.com/eirikh1996/Movecraft/releases/tag/" + newVersion); + } + }.runTaskLaterAsynchronously(Movecraft.getInstance(), 100); + } + + @Nullable + private String getNewVersion() { + try { + final URL url = new URL("https://api.github.com/repos/eirikh1996/Movecraft/releases"); + final URLConnection conn = url.openConnection(); + conn.setConnectTimeout(6000); + conn.addRequestProperty("User-Agent", "Movecraft update checker"); + conn.setDoOutput(true); + final BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream())); + final String response = reader.readLine(); + final Gson gson = new Gson(); + List objList = gson.fromJson(response, List.class); + if (objList.size() == 0) { + Movecraft.getInstance().getLogger().severe(I18nSupport.getInternationalisedString("Update - No update or bad URL")); + return null; + } + Map data = (Map) objList.get(0); + //Get the new version + String newVersion = (String) data.get("tag_name"); + int betaNo = 0; + if (newVersion.contains("beta")) { + String beta = newVersion.substring(newVersion.lastIndexOf("-") + 1); + betaNo = Integer.parseInt(beta); + } + String baseVersion = newVersion.split("-")[0]; + baseVersion = baseVersion.replace("v", "").replace(".", ""); + int nv = Integer.parseInt(baseVersion) * 100; + nv += betaNo; + //Then get the current version + String currentVersion = Movecraft.getInstance().getDescription().getVersion(); + int currBetaNo = 0; + if (currentVersion.contains("beta")) { + String beta = currentVersion.substring(currentVersion.lastIndexOf("_") + 1); + currBetaNo = Integer.parseInt(beta); + } + String currBaseVersion = currentVersion.split("_")[0].replace(".", "").replace("v", ""); + int cv = Integer.parseInt(currBaseVersion) * 100; + cv += currBetaNo; + if (nv > cv) { + return newVersion; + } + } catch (IOException e) { + e.printStackTrace(); + } + return null; + } +} diff --git a/modules/Movecraft/src/main/resources/localisation/movecraftlang_en.properties b/modules/Movecraft/src/main/resources/localisation/movecraftlang_en.properties index 71113f247..c534aa795 100644 --- a/modules/Movecraft/src/main/resources/localisation/movecraftlang_en.properties +++ b/modules/Movecraft/src/main/resources/localisation/movecraftlang_en.properties @@ -257,5 +257,6 @@ WGCustomFlags\ -\ Translation\ Failed=Translation Failed - You are not permitted WGCustomFlags\ -\ Rotation\ Failed=Rotation Failed - You are not permitterd to rotate a craft in this WorldGuard region WGCustomFlags\ -\ Detection\ Failed=Detection Failed - You are not permitted to pilot a craft in this WorldGuard region WGCustomFlags\ -\ Sinking\ a\ craft\ is\ not\ allowed\ in\ this\ WorldGuard\ region=Sinking is not allowed in this WorldGuard region\! -Factions\ -\ Translation\ Failed\ Faction\ Has\ No\ Access=Translation Failed - Your faction is not permitted to move a craft in the territory of {FACTION}\! -Factions\ -\ Translation\ Failed\ Player\ Has\ No\ Access=Translation Failed - Your are not permitted to move a craft in the territory of {FACTION}\! \ No newline at end of file +Update\ -\ Checking\ for\ updates=Checking for updates +Update\ -\ Up\ to\ date=You are up to date +Update\ -\ Update\ available=A new update of Movecraft is available for download \ No newline at end of file From 80c1248540f371f6e855e1a13a2c569d7b9ea05d Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Sun, 5 Apr 2020 23:47:14 +0200 Subject: [PATCH 128/304] Removed original world border check code and using upstream one instead --- .../movecraft/async/rotation/RotationTask.java | 13 ------------- .../async/translation/TranslationTask.java | 5 ----- 2 files changed, 18 deletions(-) diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/rotation/RotationTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/rotation/RotationTask.java index 9a42c48fa..1305c7787 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/rotation/RotationTask.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/rotation/RotationTask.java @@ -177,19 +177,6 @@ public void run() { break; } - // See if they are permitted to build in the area, if WorldGuard integration is turned on - Location plugLoc = newLocation.toBukkit(w); - WorldBorder border = craft.getW().getWorldBorder(); - boolean inside = Settings.IsPre1_9 ? plugLoc.subtract(border.getCenter()).getBlockX() <= border.getSize() && - plugLoc.subtract(border.getCenter()).getBlockZ() <= border.getSize() : - craft.getW().getWorldBorder().isInside(plugLoc); - - if (!inside) { - failMessage = I18nSupport.getInternationalisedString("Rotation - Failed Craft cannot pass world border"); - failed = true; - return; - } - //TODO: ADD TOWNY //TODO: ADD FACTIONS //isTownyBlock(plugLoc,craftPilot); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java index 83f3cb9ad..a11113a99 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java @@ -315,11 +315,6 @@ public void run() { return; } - if (!craft.getW().getWorldBorder().isInside(newLocation.toBukkit(craft.getW()))) { - fail(I18nSupport.getInternationalisedString("Translation - Failed Craft cannot pass world border")); - return; - } - boolean blockObstructed; if (craft.getSinking()) { blockObstructed = !FALL_THROUGH_BLOCKS.contains(testMaterial); From bbcdc48ae7c798ee3745ce62e63a72b239e7a6a4 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Tue, 7 Apr 2020 01:15:07 +0200 Subject: [PATCH 129/304] Added static detection ranges --- .../net/countercraft/movecraft/craft/ICraft.java | 16 +++++++++++++--- .../movecraft/listener/BlockListener.java | 11 ----------- .../countercraft/movecraft/craft/CraftType.java | 12 ++++++++++++ 3 files changed, 25 insertions(+), 14 deletions(-) diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/ICraft.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/ICraft.java index 5c98b28dd..9616067eb 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/ICraft.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/ICraft.java @@ -7,6 +7,7 @@ import net.countercraft.movecraft.async.rotation.RotationTask; import net.countercraft.movecraft.async.translation.TranslationTask; import net.countercraft.movecraft.localisation.I18nSupport; +import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.World; import org.bukkit.block.Block; @@ -83,15 +84,24 @@ public void rotate(Rotation rotation, MovecraftLocation originPoint, boolean isS public Set getContacts() { final Set contacts = new HashSet<>(); for (Craft contact : CraftManager.getInstance().getCraftsInWorld(w)) { + if (contact.getNotificationPlayer() == this.getNotificationPlayer()) { + continue; + } MovecraftLocation ccenter = this.getHitBox().getMidPoint(); MovecraftLocation tcenter = contact.getHitBox().getMidPoint(); int distsquared = ccenter.distanceSquared(tcenter); int detectionRange = (int) (contact.getOrigBlockCount() * (tcenter.getY() > 65 ? contact.getType().getDetectionMultiplier() : contact.getType().getUnderwaterDetectionMultiplier())); detectionRange = detectionRange * 10; - if (distsquared > detectionRange || contact.getNotificationPlayer() == this.getNotificationPlayer()) { - continue; + int staticDetectionRange = (int) ((tcenter.getY() > 65 ? contact.getType().getStaticDetectionRange() : contact.getType().getUnderwaterStaticDetectionRange())); + staticDetectionRange = staticDetectionRange * staticDetectionRange; + Bukkit.broadcastMessage("Static detection range: " + staticDetectionRange + " Distance Squared: " + distsquared); + if (distsquared <= staticDetectionRange) { + contacts.add(contact); } - contacts.add(contact); + if (distsquared <= detectionRange) { + contacts.add(contact); + } + } return contacts; } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/BlockListener.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/BlockListener.java index 6c7fe4a2d..03e808d24 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/BlockListener.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/BlockListener.java @@ -62,17 +62,6 @@ public class BlockListener implements Listener { private long lastDamagesUpdate; - final Material[] fragileBlocks = Settings.IsLegacy ? new Material[]{ - - } - : - new Material[] - //Beds - { - //Redstone components - - - }; @EventHandler public void onBlockPlace(final BlockPlaceEvent e) { diff --git a/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java b/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java index 011fdbd68..eef1adbe8 100644 --- a/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java +++ b/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java @@ -79,6 +79,8 @@ final public class CraftType { private final double fuelBurnRate; private final double sinkPercent; private final double overallSinkPercent; + private final double staticDetectionRange; + private final double underwaterStaticDetectionRange; private final double detectionMultiplier; private final double underwaterDetectionMultiplier; private final double dynamicLagSpeedFactor; @@ -181,6 +183,8 @@ public CraftType(File f) throws CraftTypeException{ hoverLimit = Math.max(0, integerFromObject(data.getOrDefault("hoverLimit", 0))); harvestBlocks = new ArrayList<>(); harvesterBladeBlocks = new ArrayList<>(); + staticDetectionRange = doubleFromObject(data.getOrDefault("staticDetectionRange", 0d)); + underwaterStaticDetectionRange = doubleFromObject(data.getOrDefault("underwaterStaticDetectionRange", 0d)); if (data.containsKey("harvestBlocks")) { ArrayList objList = (ArrayList) data.get("harvestBlocks"); for (Object i : objList) { @@ -1034,6 +1038,14 @@ public int getKeepMovingOnSinkMaxMove() { return keepMovingOnSinkMaxMove; } + public double getUnderwaterStaticDetectionRange() { + return underwaterStaticDetectionRange; + } + + public double getStaticDetectionRange() { + return staticDetectionRange; + } + private class TypeNotFoundException extends RuntimeException { public TypeNotFoundException(String s) { super(s); From 8112f0bb11dafd4888e332ec8811f9f7877bdf11 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Sat, 11 Apr 2020 19:57:27 +0200 Subject: [PATCH 130/304] WorldHandler can now set BlockData on 1.13+ --- .../movecraft/async/AsyncManager.java | 17 ++++++++++------- .../async/translation/TranslationTask.java | 15 +++++++++++---- .../mapUpdater/update/BlockCreateCommand.java | 2 +- .../mapUpdater/update/CraftRotateCommand.java | 18 +++++++++--------- .../update/CraftTranslateCommand.java | 17 ++++++++--------- .../countercraft/movecraft/WorldHandler.java | 4 ++-- .../countercraft/movecraft/craft/Craft.java | 7 ++++--- .../compat/v1_10_R1/IWorldHandler.java | 9 ++++++--- .../compat/v1_11_R1/IWorldHandler.java | 9 ++++++--- .../compat/v1_12_R1/IWorldHandler.java | 9 ++++++--- .../compat/v1_13_R2/IWorldHandler.java | 13 ++++++++++--- .../compat/v1_14_R1/IWorldHandler.java | 13 ++++++++++--- .../compat/v1_15_R1/IWorldHandler.java | 14 +++++++++++--- .../compat/v1_8_R3/IWorldHandler.java | 9 ++++++--- .../compat/v1_9_R2/IWorldHandler.java | 9 ++++++--- 15 files changed, 106 insertions(+), 59 deletions(-) diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java index e7677ee68..b0b73bf93 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java @@ -33,10 +33,10 @@ import net.countercraft.movecraft.mapUpdater.update.BlockCreateCommand; import net.countercraft.movecraft.mapUpdater.update.UpdateCommand; import net.countercraft.movecraft.utils.*; -import org.apache.commons.lang3.tuple.ImmutablePair; import org.bukkit.*; import org.bukkit.block.Block; import org.bukkit.block.BlockFace; +import org.bukkit.block.data.BlockData; import org.bukkit.entity.Player; import org.bukkit.entity.SmallFireball; import org.bukkit.entity.TNTPrimed; @@ -60,7 +60,7 @@ public class AsyncManager extends BukkitRunnable { private HashMap FireballTracking = new HashMap<>(); private HashMap wrecks = new HashMap<>(); private HashMap wreckWorlds = new HashMap<>(); - private HashMap>> wreckPhases = new HashMap<>(); + private HashMap>> wreckPhases = new HashMap<>(); private Map cooldownCache = new WeakHashMap<>(); private long lastTracerUpdate = 0; private long lastFireballCheck = 0; @@ -262,7 +262,7 @@ private void processAlgorithmQueue() { for(MovecraftLocation location : entireHitbox){ if(location.getY() <= waterLine){ - c.getPhaseBlocks().put(location, new ImmutablePair<>(Material.WATER, (byte) 0)); + c.getPhaseBlocks().put(location, new AbstractMap.SimpleImmutableEntry<>(Material.WATER, Settings.IsLegacy ? (byte) 0 : Bukkit.createBlockData(Material.WATER))); } } @@ -935,13 +935,16 @@ private void processFadingBlocks() { continue; } final HitBox hitBox = entry.getKey(); - final Map> phaseBlocks = wreckPhases.get(hitBox); + final Map> phaseBlocks = wreckPhases.get(hitBox); final World world = wreckWorlds.get(hitBox); ArrayList commands = new ArrayList<>(); for (MovecraftLocation location : hitBox){ - ImmutablePair phaseBlock = phaseBlocks.getOrDefault(location, new ImmutablePair<>(Material.AIR, (byte) 0)); - commands.add(new BlockCreateCommand(world, location, phaseBlock.getKey(), phaseBlock.getValue())); - + AbstractMap.SimpleImmutableEntry phaseBlock = phaseBlocks.getOrDefault(location, new AbstractMap.SimpleImmutableEntry<>(Material.AIR, Settings.IsLegacy ? (byte) 0 : Bukkit.createBlockData(Material.AIR))); + if (Settings.IsLegacy) { + commands.add(new BlockCreateCommand(world, location, phaseBlock.getKey(), (byte) phaseBlock.getValue())); + continue; + } + commands.add(new BlockCreateCommand(world, location, phaseBlock.getKey(), (BlockData) phaseBlock.getValue())); } MapUpdateManager.getInstance().scheduleUpdates(commands); processed.add(hitBox); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java index 0575b77af..50342432e 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java @@ -17,9 +17,12 @@ import net.countercraft.movecraft.utils.HitBox; import net.countercraft.movecraft.utils.LegacyUtils; import net.countercraft.movecraft.utils.MutableHitBox; -import org.apache.commons.lang3.tuple.ImmutablePair; import org.bukkit.*; -import org.bukkit.block.*; +import org.bukkit.block.Barrel; +import org.bukkit.block.Block; +import org.bukkit.block.Chest; +import org.bukkit.block.Furnace; +import org.bukkit.block.data.BlockData; import org.bukkit.entity.Player; import org.bukkit.inventory.Inventory; import org.bukkit.inventory.InventoryHolder; @@ -436,8 +439,12 @@ public void run() { if(!collisionBox.isEmpty() && craft.getType().getCruiseOnPilot()){ CraftManager.getInstance().removeCraft(craft); for(MovecraftLocation location : oldHitBox){ - ImmutablePair phaseBlock = craft.getPhaseBlocks().getOrDefault(location, new ImmutablePair<>(Material.AIR, (byte) 0)); - updates.add(new BlockCreateCommand(craft.getW(), location, phaseBlock.getKey(), phaseBlock.getValue())); + AbstractMap.SimpleImmutableEntry phaseBlock = craft.getPhaseBlocks().getOrDefault(location, new AbstractMap.SimpleImmutableEntry<>(Material.AIR, Settings.IsLegacy ? (byte) 0 : Bukkit.createBlockData(Material.AIR))); + if (Settings.IsLegacy) { + updates.add(new BlockCreateCommand(craft.getW(), location, phaseBlock.getKey(), (byte) phaseBlock.getValue())); + continue; + } + updates.add(new BlockCreateCommand(craft.getW(), location, phaseBlock.getKey(), (BlockData) phaseBlock.getValue())); } newHitBox = new HashHitBox(); } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/BlockCreateCommand.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/BlockCreateCommand.java index 05f9a7993..685c02750 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/BlockCreateCommand.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/BlockCreateCommand.java @@ -60,7 +60,7 @@ public BlockCreateCommand(@NotNull World world, @NotNull MovecraftLocation newBl @SuppressWarnings("deprecation") public void doUpdate() { // now do the block updates, move entities when you set the block they are on - Movecraft.getInstance().getWorldHandler().setBlockFast(newBlockLocation.toBukkit(world),type,dataID); + Movecraft.getInstance().getWorldHandler().setBlockFast(newBlockLocation.toBukkit(world),type, Settings.IsLegacy ? dataID : bData); //craft.incrementBlockUpdates(); newBlockLocation.toBukkit(world).getBlock().getState().update(false, false); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftRotateCommand.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftRotateCommand.java index d334a7971..981970de0 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftRotateCommand.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftRotateCommand.java @@ -10,7 +10,7 @@ import net.countercraft.movecraft.events.SignTranslateEvent; import net.countercraft.movecraft.mapUpdater.MapUpdateManager; import net.countercraft.movecraft.utils.*; -import org.apache.commons.lang3.tuple.ImmutablePair; + import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.Material; @@ -109,9 +109,9 @@ public void doUpdate() { for (MovecraftLocation location : to) { Block b = location.toBukkit(craft.getW()).getBlock(); Material material = b.getType(); - byte data = b.getData(); + Object data = Settings.IsLegacy ? b.getData() : b.getBlockData(); if (passthroughBlocks.contains(material)) { - craft.getPhaseBlocks().put(location, new ImmutablePair<>(material, data)); + craft.getPhaseBlocks().put(location, new AbstractMap.SimpleImmutableEntry<>(material, data)); } } //The subtraction of the set of coordinates in the HitBox cube and the HitBox itself @@ -168,11 +168,11 @@ public void doUpdate() { for (MovecraftLocation location : CollectionUtils.filter(invertedHitBox, exterior)) { Block b = location.toBukkit(craft.getW()).getBlock(); Material material = b.getType(); - byte data = b.getData(); + Object data = Settings.IsLegacy ? b.getData() : b.getBlockData(); if (!passthroughBlocks.contains(material)) { continue; } - craft.getPhaseBlocks().put(location, new ImmutablePair<>(material, data)); + craft.getPhaseBlocks().put(location, new AbstractMap.SimpleImmutableEntry<>(material, data)); } //translate the craft @@ -186,14 +186,14 @@ public void doUpdate() { if (!craft.getPhaseBlocks().containsKey(location)) { continue; } - ImmutablePair phaseBlock = craft.getPhaseBlocks().remove(location); + AbstractMap.SimpleImmutableEntry phaseBlock = craft.getPhaseBlocks().remove(location); handler.setBlockFast(location.toBukkit(craft.getW()), phaseBlock.getKey(), phaseBlock.getValue()); craft.getPhaseBlocks().remove(location); } for(MovecraftLocation location : originalLocations.boundingHitBox()){ if(!craft.getHitBox().inBounds(location) && craft.getPhaseBlocks().containsKey(location)){ - ImmutablePair phaseBlock = craft.getPhaseBlocks().remove(location); + AbstractMap.SimpleImmutableEntry phaseBlock = craft.getPhaseBlocks().remove(location); handler.setBlockFast(location.toBukkit(craft.getW()), phaseBlock.getKey(), phaseBlock.getValue()); } } @@ -201,9 +201,9 @@ public void doUpdate() { for (MovecraftLocation location : interior) { Block b = location.toBukkit(craft.getW()).getBlock(); Material material = b.getType(); - byte data = b.getData(); + Object data = Settings.IsLegacy ? b.getData() : b.getBlockData(); if (passthroughBlocks.contains(material)) { - craft.getPhaseBlocks().put(location, new ImmutablePair<>(material, data)); + craft.getPhaseBlocks().put(location, new AbstractMap.SimpleImmutableEntry<>(material, data)); handler.setBlockFast(location.toBukkit(craft.getW()), Material.AIR, (byte) 0); } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftTranslateCommand.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftTranslateCommand.java index 255fc819b..9417ec6f6 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftTranslateCommand.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftTranslateCommand.java @@ -9,7 +9,6 @@ import net.countercraft.movecraft.events.SignTranslateEvent; import net.countercraft.movecraft.mapUpdater.MapUpdateManager; import net.countercraft.movecraft.utils.*; -import org.apache.commons.lang3.tuple.ImmutablePair; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.Material; @@ -109,9 +108,9 @@ public void doUpdate() { for (MovecraftLocation location : to) { Block b = location.toBukkit(craft.getW()).getBlock(); Material material = b.getType(); - byte data = b.getData(); + Object data = Settings.IsLegacy ? b.getData() : b.getBlockData(); if (passthroughBlocks.contains(material)) { - craft.getPhaseBlocks().put(location, new ImmutablePair<>(material, data)); + craft.getPhaseBlocks().put(location, new AbstractMap.SimpleImmutableEntry<>(material, data)); } } //The subtraction of the set of coordinates in the HitBox cube and the HitBox itself @@ -166,11 +165,11 @@ public void doUpdate() { for (MovecraftLocation location : CollectionUtils.filter(invertedHitBox, confirmed)) { Block b = location.toBukkit(craft.getW()).getBlock(); Material material = b.getType(); - byte data = b.getData(); + Object data = Settings.IsLegacy ? b.getData() : b.getBlockData(); if (!passthroughBlocks.contains(material)) { continue; } - craft.getPhaseBlocks().put(location, new ImmutablePair<>(material, data)); + craft.getPhaseBlocks().put(location, new AbstractMap.SimpleImmutableEntry<>(material, data)); } //translate the craft @@ -195,14 +194,14 @@ public void doUpdate() { //Do not place if it is at a collapsed HitBox location if (!craft.getCollapsedHitBox().isEmpty() && craft.getCollapsedHitBox().contains(location)) continue; - ImmutablePair phaseBlock = craft.getPhaseBlocks().remove(location); + AbstractMap.SimpleImmutableEntry phaseBlock = craft.getPhaseBlocks().remove(location); handler.setBlockFast(location.toBukkit(craft.getW()), phaseBlock.getKey(), phaseBlock.getValue()); craft.getPhaseBlocks().remove(location); } for(MovecraftLocation location : originalLocations){ if(!craft.getHitBox().contains(location) && craft.getPhaseBlocks().containsKey(location)){ - ImmutablePair phaseBlock = craft.getPhaseBlocks().remove(location); + AbstractMap.SimpleImmutableEntry phaseBlock = craft.getPhaseBlocks().remove(location); handler.setBlockFast(location.toBukkit(craft.getW()), phaseBlock.getKey(), phaseBlock.getValue()); } } @@ -210,9 +209,9 @@ public void doUpdate() { for (MovecraftLocation location : failed) { Block b = location.toBukkit(craft.getW()).getBlock(); Material material = b.getType(); - byte data = b.getData(); + Object data = Settings.IsLegacy ? b.getData() : b.getBlockData(); if (passthroughBlocks.contains(material)) { - craft.getPhaseBlocks().put(location, new ImmutablePair<>(material, data)); + craft.getPhaseBlocks().put(location, new AbstractMap.SimpleImmutableEntry<>(material, data)); handler.setBlockFast(location.toBukkit(craft.getW()), Material.AIR, (byte) 0); } diff --git a/modules/api/src/main/java/net/countercraft/movecraft/WorldHandler.java b/modules/api/src/main/java/net/countercraft/movecraft/WorldHandler.java index 18c02ef8d..58a823f1c 100644 --- a/modules/api/src/main/java/net/countercraft/movecraft/WorldHandler.java +++ b/modules/api/src/main/java/net/countercraft/movecraft/WorldHandler.java @@ -11,8 +11,8 @@ public abstract class WorldHandler { public abstract void rotateCraft(@NotNull Craft craft, @NotNull MovecraftLocation originLocation, @NotNull Rotation rotation); public abstract void translateCraft(@NotNull Craft craft, @NotNull MovecraftLocation newLocation); - public abstract void setBlockFast(@NotNull Location location, @NotNull Material material, byte data); - public abstract void setBlockFast(@NotNull Location location, @NotNull Rotation rotation, @NotNull Material material, byte data); + public abstract void setBlockFast(@NotNull Location location, @NotNull Material material, Object data); + public abstract void setBlockFast(@NotNull Location location, @NotNull Rotation rotation, @NotNull Material material, Object data); public abstract void disableShadow(@NotNull Material type); public void addPlayerLocation(Player player, double x, double y, double z, float yaw, float pitch){ Location playerLoc = player.getLocation(); diff --git a/modules/api/src/main/java/net/countercraft/movecraft/craft/Craft.java b/modules/api/src/main/java/net/countercraft/movecraft/craft/Craft.java index ca38e4e45..74843f6bb 100644 --- a/modules/api/src/main/java/net/countercraft/movecraft/craft/Craft.java +++ b/modules/api/src/main/java/net/countercraft/movecraft/craft/Craft.java @@ -24,7 +24,6 @@ import net.countercraft.movecraft.utils.HashHitBox; import net.md_5.bungee.api.ChatMessageType; import net.md_5.bungee.api.chat.TextComponent; -import org.apache.commons.lang3.tuple.ImmutablePair; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.Material; @@ -40,6 +39,8 @@ + + public abstract class Craft { @NotNull protected final CraftType type; //protected int[][][] hitBox; @@ -73,7 +74,7 @@ public abstract class Craft { @Nullable private Player AADirector; private float meanMoveTime; private int numMoves; - @NotNull private final Map> phaseBlocks = new HashMap<>(); + @NotNull private final Map> phaseBlocks = new HashMap<>(); @NotNull private final HashMap crewSigns = new HashMap<>(); @NotNull private String name = ""; @@ -432,7 +433,7 @@ public int getWaterLine(){ } @NotNull - public Map> getPhaseBlocks(){ + public Map> getPhaseBlocks(){ return phaseBlocks; } diff --git a/modules/v1_10_R1/src/main/java/net/countercraft/movecraft/compat/v1_10_R1/IWorldHandler.java b/modules/v1_10_R1/src/main/java/net/countercraft/movecraft/compat/v1_10_R1/IWorldHandler.java index 358e05bea..7846ca19a 100644 --- a/modules/v1_10_R1/src/main/java/net/countercraft/movecraft/compat/v1_10_R1/IWorldHandler.java +++ b/modules/v1_10_R1/src/main/java/net/countercraft/movecraft/compat/v1_10_R1/IWorldHandler.java @@ -300,13 +300,16 @@ private void setBlockFast(@NotNull World world, @NotNull BlockPosition position, } @Override - public void setBlockFast(@NotNull Location location, @NotNull Material material, byte data){ + public void setBlockFast(@NotNull Location location, @NotNull Material material, Object data){ setBlockFast(location, Rotation.NONE, material, data); } @Override - public void setBlockFast(@NotNull Location location, @NotNull Rotation rotation, @NotNull Material material, byte data) { - IBlockData blockData = CraftMagicNumbers.getBlock(material).fromLegacyData(data); + public void setBlockFast(@NotNull Location location, @NotNull Rotation rotation, @NotNull Material material, Object data) { + if (!(data instanceof Byte)) { + throw new IllegalArgumentException("data must be byte value for v1_10_R1"); + } + IBlockData blockData = CraftMagicNumbers.getBlock(material).fromLegacyData((byte) data); blockData = blockData.a(ROTATION[rotation.ordinal()]); World world = ((CraftWorld)(location.getWorld())).getHandle(); BlockPosition blockPosition = locationToPosition(bukkit2MovecraftLoc(location)); diff --git a/modules/v1_11_R1/src/main/java/net/countercraft/movecraft/compat/v1_11_R1/IWorldHandler.java b/modules/v1_11_R1/src/main/java/net/countercraft/movecraft/compat/v1_11_R1/IWorldHandler.java index 2c3876068..a70c2e483 100644 --- a/modules/v1_11_R1/src/main/java/net/countercraft/movecraft/compat/v1_11_R1/IWorldHandler.java +++ b/modules/v1_11_R1/src/main/java/net/countercraft/movecraft/compat/v1_11_R1/IWorldHandler.java @@ -301,13 +301,16 @@ private void setBlockFast(@NotNull World world, @NotNull BlockPosition position, } @Override - public void setBlockFast(@NotNull Location location, @NotNull Material material, byte data){ + public void setBlockFast(@NotNull Location location, @NotNull Material material, Object data){ setBlockFast(location, Rotation.NONE, material, data); } @Override - public void setBlockFast(@NotNull Location location, @NotNull Rotation rotation, @NotNull Material material, byte data) { - IBlockData blockData = CraftMagicNumbers.getBlock(material).fromLegacyData(data); + public void setBlockFast(@NotNull Location location, @NotNull Rotation rotation, @NotNull Material material, Object data) { + if (!(data instanceof Byte)) { + throw new IllegalArgumentException("data must be byte value for v1_11_R1"); + } + IBlockData blockData = CraftMagicNumbers.getBlock(material).fromLegacyData((byte) data); blockData = blockData.a(ROTATION[rotation.ordinal()]); World world = ((CraftWorld)(location.getWorld())).getHandle(); BlockPosition blockPosition = locationToPosition(bukkit2MovecraftLoc(location)); diff --git a/modules/v1_12_R1/src/main/java/net/countercraft/movecraft/compat/v1_12_R1/IWorldHandler.java b/modules/v1_12_R1/src/main/java/net/countercraft/movecraft/compat/v1_12_R1/IWorldHandler.java index 2447d9fa9..30df8c736 100644 --- a/modules/v1_12_R1/src/main/java/net/countercraft/movecraft/compat/v1_12_R1/IWorldHandler.java +++ b/modules/v1_12_R1/src/main/java/net/countercraft/movecraft/compat/v1_12_R1/IWorldHandler.java @@ -306,13 +306,16 @@ private void setBlockFast(@NotNull World world, @NotNull BlockPosition position, } @Override - public void setBlockFast(@NotNull Location location, @NotNull Material material, byte data){ + public void setBlockFast(@NotNull Location location, @NotNull Material material, Object data){ setBlockFast(location, Rotation.NONE, material, data); } @Override - public void setBlockFast(@NotNull Location location, @NotNull Rotation rotation, @NotNull Material material, byte data) { - IBlockData blockData = CraftMagicNumbers.getBlock(material).fromLegacyData(data); + public void setBlockFast(@NotNull Location location, @NotNull Rotation rotation, @NotNull Material material, Object data) { + if (!(data instanceof Byte)) { + throw new IllegalArgumentException("data must be byte value for v1_12_R1"); + } + IBlockData blockData = CraftMagicNumbers.getBlock(material).fromLegacyData((byte) data); blockData = blockData.a(ROTATION[rotation.ordinal()]); World world = ((CraftWorld)(location.getWorld())).getHandle(); BlockPosition blockPosition = locationToPosition(bukkit2MovecraftLoc(location)); diff --git a/modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/IWorldHandler.java b/modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/IWorldHandler.java index 79881f79c..79b6d385c 100644 --- a/modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/IWorldHandler.java +++ b/modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/IWorldHandler.java @@ -11,7 +11,9 @@ import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.Material; +import org.bukkit.block.data.BlockData; import org.bukkit.craftbukkit.v1_13_R2.CraftWorld; +import org.bukkit.craftbukkit.v1_13_R2.block.data.CraftBlockData; import org.bukkit.craftbukkit.v1_13_R2.entity.CraftPlayer; import org.bukkit.craftbukkit.v1_13_R2.util.CraftMagicNumbers; import org.bukkit.entity.Player; @@ -355,13 +357,18 @@ private void setBlockFast(@NotNull World world, @NotNull BlockPosition position, } @Override - public void setBlockFast(@NotNull Location location, @NotNull Material material, byte data){ + public void setBlockFast(@NotNull Location location, @NotNull Material material, Object data){ setBlockFast(location, Rotation.NONE, material, data); } @Override - public void setBlockFast(@NotNull Location location, @NotNull Rotation rotation, @NotNull Material material, byte data) { - IBlockData blockData = CraftMagicNumbers.getBlock(material).getBlockData(); + public void setBlockFast(@NotNull Location location, @NotNull Rotation rotation, @NotNull Material material, Object data) { + IBlockData blockData; + if (!(data instanceof BlockData)) { + blockData = CraftMagicNumbers.getBlock(material).getBlockData(); + } else { + blockData = ((CraftBlockData) data).getState(); + } blockData = blockData.a(ROTATION[rotation.ordinal()]); World world = ((CraftWorld)(location.getWorld())).getHandle(); BlockPosition blockPosition = locationToPosition(bukkit2MovecraftLoc(location)); diff --git a/modules/v1_14_R1/src/main/java/net/countercraft/movecraft/compat/v1_14_R1/IWorldHandler.java b/modules/v1_14_R1/src/main/java/net/countercraft/movecraft/compat/v1_14_R1/IWorldHandler.java index 38f53703d..a4537325d 100644 --- a/modules/v1_14_R1/src/main/java/net/countercraft/movecraft/compat/v1_14_R1/IWorldHandler.java +++ b/modules/v1_14_R1/src/main/java/net/countercraft/movecraft/compat/v1_14_R1/IWorldHandler.java @@ -11,7 +11,9 @@ import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.Material; +import org.bukkit.block.data.BlockData; import org.bukkit.craftbukkit.v1_14_R1.CraftWorld; +import org.bukkit.craftbukkit.v1_14_R1.block.data.CraftBlockData; import org.bukkit.craftbukkit.v1_14_R1.entity.CraftPlayer; import org.bukkit.craftbukkit.v1_14_R1.util.CraftMagicNumbers; import org.bukkit.entity.Player; @@ -354,13 +356,18 @@ private void setBlockFast(@NotNull World world, @NotNull BlockPosition position, } @Override - public void setBlockFast(@NotNull Location location, @NotNull Material material, byte data){ + public void setBlockFast(@NotNull Location location, @NotNull Material material, Object data){ setBlockFast(location, Rotation.NONE, material, data); } @Override - public void setBlockFast(@NotNull Location location, @NotNull Rotation rotation, @NotNull Material material, byte data) { - IBlockData blockData = CraftMagicNumbers.getBlock(material).getBlockData(); + public void setBlockFast(@NotNull Location location, @NotNull Rotation rotation, @NotNull Material material, Object data) { + IBlockData blockData; + if (!(data instanceof BlockData)) { + blockData = CraftMagicNumbers.getBlock(material).getBlockData(); + } else { + blockData = ((CraftBlockData) data).getState(); + } blockData = blockData.a(ROTATION[rotation.ordinal()]); World world = ((CraftWorld)(location.getWorld())).getHandle(); BlockPosition blockPosition = locationToPosition(bukkit2MovecraftLoc(location)); diff --git a/modules/v1_15_R1/src/main/java/net/countercraft/movecraft/compat/v1_15_R1/IWorldHandler.java b/modules/v1_15_R1/src/main/java/net/countercraft/movecraft/compat/v1_15_R1/IWorldHandler.java index 34194e82f..c9efa6e77 100644 --- a/modules/v1_15_R1/src/main/java/net/countercraft/movecraft/compat/v1_15_R1/IWorldHandler.java +++ b/modules/v1_15_R1/src/main/java/net/countercraft/movecraft/compat/v1_15_R1/IWorldHandler.java @@ -11,7 +11,9 @@ import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.Material; +import org.bukkit.block.data.BlockData; import org.bukkit.craftbukkit.v1_15_R1.CraftWorld; +import org.bukkit.craftbukkit.v1_15_R1.block.data.CraftBlockData; import org.bukkit.craftbukkit.v1_15_R1.entity.CraftPlayer; import org.bukkit.craftbukkit.v1_15_R1.util.CraftMagicNumbers; import org.bukkit.entity.Player; @@ -360,13 +362,19 @@ private void setBlockFast(@NotNull World world, @NotNull BlockPosition position, } @Override - public void setBlockFast(@NotNull Location location, @NotNull Material material, byte data){ + public void setBlockFast(@NotNull Location location, @NotNull Material material, Object data){ setBlockFast(location, Rotation.NONE, material, data); } @Override - public void setBlockFast(@NotNull Location location, @NotNull Rotation rotation, @NotNull Material material, byte data) { - IBlockData blockData = CraftMagicNumbers.getBlock(material).getBlockData(); + public void setBlockFast(@NotNull Location location, @NotNull Rotation rotation, @NotNull Material material, Object data) { + IBlockData blockData; + if (!(data instanceof BlockData)) { + blockData = CraftMagicNumbers.getBlock(material).getBlockData(); + } else { + blockData = ((CraftBlockData) data).getState(); + } + blockData = blockData.a(ROTATION[rotation.ordinal()]); WorldServer world = ((CraftWorld)(location.getWorld())).getHandle(); BlockPosition blockPosition = locationToPosition(bukkit2MovecraftLoc(location)); diff --git a/modules/v1_8_R3/src/main/java/net/countercraft/movecraft/compat/v1_8_R3/IWorldHandler.java b/modules/v1_8_R3/src/main/java/net/countercraft/movecraft/compat/v1_8_R3/IWorldHandler.java index 908525962..e1ff0f8d3 100644 --- a/modules/v1_8_R3/src/main/java/net/countercraft/movecraft/compat/v1_8_R3/IWorldHandler.java +++ b/modules/v1_8_R3/src/main/java/net/countercraft/movecraft/compat/v1_8_R3/IWorldHandler.java @@ -308,13 +308,16 @@ private void setBlockFast(@NotNull World world, @NotNull BlockPosition position, } @Override - public void setBlockFast(@NotNull Location location, @NotNull Material material, byte data){ + public void setBlockFast(@NotNull Location location, @NotNull Material material, Object data){ setBlockFast(location, Rotation.NONE, material, data); } @Override - public void setBlockFast(@NotNull Location location, @NotNull Rotation rotation, @NotNull Material material, byte data) { - IBlockData blockData = CraftMagicNumbers.getBlock(material).fromLegacyData(data); + public void setBlockFast(@NotNull Location location, @NotNull Rotation rotation, @NotNull Material material, Object data) { + if (!(data instanceof Byte)) { + throw new IllegalArgumentException("data must be byte value for v1_8_R3"); + } + IBlockData blockData = CraftMagicNumbers.getBlock(material).fromLegacyData((byte) data); //blockData = blockData.a(ROTATION[rotation.ordinal()]); World world = ((CraftWorld)(location.getWorld())).getHandle(); BlockPosition blockPosition = locationToPosition(bukkit2MovecraftLoc(location)); diff --git a/modules/v1_9_R2/src/main/java/net/countercraft/movecraft/compat/v1_9_R2/IWorldHandler.java b/modules/v1_9_R2/src/main/java/net/countercraft/movecraft/compat/v1_9_R2/IWorldHandler.java index c1168ab5b..85f53b2f5 100644 --- a/modules/v1_9_R2/src/main/java/net/countercraft/movecraft/compat/v1_9_R2/IWorldHandler.java +++ b/modules/v1_9_R2/src/main/java/net/countercraft/movecraft/compat/v1_9_R2/IWorldHandler.java @@ -301,13 +301,16 @@ private void setBlockFast(@NotNull World world, @NotNull BlockPosition position, } @Override - public void setBlockFast(@NotNull Location location, @NotNull Material material, byte data){ + public void setBlockFast(@NotNull Location location, @NotNull Material material, Object data){ setBlockFast(location, Rotation.NONE, material, data); } @Override - public void setBlockFast(@NotNull Location location, @NotNull Rotation rotation, @NotNull Material material, byte data) { - IBlockData blockData = CraftMagicNumbers.getBlock(material).fromLegacyData(data); + public void setBlockFast(@NotNull Location location, @NotNull Rotation rotation, @NotNull Material material, Object data) { + if (!(data instanceof Byte)) { + throw new IllegalArgumentException("data must be byte value for v1_9_R2"); + } + IBlockData blockData = CraftMagicNumbers.getBlock(material).fromLegacyData((byte) data); blockData = blockData.a(ROTATION[rotation.ordinal()]); World world = ((CraftWorld)(location.getWorld())).getHandle(); BlockPosition blockPosition = locationToPosition(bukkit2MovecraftLoc(location)); From 838106844ddc633b5830f003f1ac86a45ea779f2 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Sun, 12 Apr 2020 14:28:15 +0200 Subject: [PATCH 131/304] Removed debug message from static detection range system --- .../src/main/java/net/countercraft/movecraft/craft/ICraft.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/ICraft.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/ICraft.java index 9616067eb..415a3f9de 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/ICraft.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/ICraft.java @@ -7,7 +7,6 @@ import net.countercraft.movecraft.async.rotation.RotationTask; import net.countercraft.movecraft.async.translation.TranslationTask; import net.countercraft.movecraft.localisation.I18nSupport; -import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.World; import org.bukkit.block.Block; @@ -94,7 +93,6 @@ public Set getContacts() { detectionRange = detectionRange * 10; int staticDetectionRange = (int) ((tcenter.getY() > 65 ? contact.getType().getStaticDetectionRange() : contact.getType().getUnderwaterStaticDetectionRange())); staticDetectionRange = staticDetectionRange * staticDetectionRange; - Bukkit.broadcastMessage("Static detection range: " + staticDetectionRange + " Distance Squared: " + distsquared); if (distsquared <= staticDetectionRange) { contacts.add(contact); } From a8493c47cc2335eeb5bac21a7b233542979ba450 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Sun, 12 Apr 2020 18:07:02 +0200 Subject: [PATCH 132/304] Chunks changed in worldhandlers for 1.13+ are also marked dirty, fixing parts of ships being left behind in the previous chunks --- .../countercraft/movecraft/compat/v1_13_R2/IWorldHandler.java | 1 + .../countercraft/movecraft/compat/v1_14_R1/IWorldHandler.java | 1 + .../countercraft/movecraft/compat/v1_15_R1/IWorldHandler.java | 1 + 3 files changed, 3 insertions(+) diff --git a/modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/IWorldHandler.java b/modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/IWorldHandler.java index 79b6d385c..e9eaa2337 100644 --- a/modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/IWorldHandler.java +++ b/modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/IWorldHandler.java @@ -354,6 +354,7 @@ private void setBlockFast(@NotNull World world, @NotNull BlockPosition position, } chunkSection.setType(position.getX()&15, position.getY()&15, position.getZ()&15, data); world.notify(position, data, data, 3); + chunk.markDirty(); } @Override diff --git a/modules/v1_14_R1/src/main/java/net/countercraft/movecraft/compat/v1_14_R1/IWorldHandler.java b/modules/v1_14_R1/src/main/java/net/countercraft/movecraft/compat/v1_14_R1/IWorldHandler.java index a4537325d..31595688d 100644 --- a/modules/v1_14_R1/src/main/java/net/countercraft/movecraft/compat/v1_14_R1/IWorldHandler.java +++ b/modules/v1_14_R1/src/main/java/net/countercraft/movecraft/compat/v1_14_R1/IWorldHandler.java @@ -353,6 +353,7 @@ private void setBlockFast(@NotNull World world, @NotNull BlockPosition position, } chunkSection.setType(position.getX()&15, position.getY()&15, position.getZ()&15, data); world.notify(position, data, data, 3); + chunk.markDirty(); } @Override diff --git a/modules/v1_15_R1/src/main/java/net/countercraft/movecraft/compat/v1_15_R1/IWorldHandler.java b/modules/v1_15_R1/src/main/java/net/countercraft/movecraft/compat/v1_15_R1/IWorldHandler.java index c9efa6e77..f824accf9 100644 --- a/modules/v1_15_R1/src/main/java/net/countercraft/movecraft/compat/v1_15_R1/IWorldHandler.java +++ b/modules/v1_15_R1/src/main/java/net/countercraft/movecraft/compat/v1_15_R1/IWorldHandler.java @@ -359,6 +359,7 @@ private void setBlockFast(@NotNull World world, @NotNull BlockPosition position, } chunkSection.setType(position.getX() & 15, position.getY() & 15, position.getZ() & 15, data); world.notify(position, data, data, 3); + chunk.markDirty(); } @Override From f4346d4ace98ad538bce1084845084cd762244c4 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Sun, 12 Apr 2020 18:09:43 +0200 Subject: [PATCH 133/304] Chunks changed in worldhandlers for 1.8.8 and 1.9.4 are also marked dirty, fixing parts of ships being left behind in the previous chunks --- .../countercraft/movecraft/compat/v1_8_R3/IWorldHandler.java | 2 ++ .../countercraft/movecraft/compat/v1_9_R2/IWorldHandler.java | 1 + 2 files changed, 3 insertions(+) diff --git a/modules/v1_8_R3/src/main/java/net/countercraft/movecraft/compat/v1_8_R3/IWorldHandler.java b/modules/v1_8_R3/src/main/java/net/countercraft/movecraft/compat/v1_8_R3/IWorldHandler.java index e1ff0f8d3..4b804ee91 100644 --- a/modules/v1_8_R3/src/main/java/net/countercraft/movecraft/compat/v1_8_R3/IWorldHandler.java +++ b/modules/v1_8_R3/src/main/java/net/countercraft/movecraft/compat/v1_8_R3/IWorldHandler.java @@ -305,6 +305,8 @@ private void setBlockFast(@NotNull World world, @NotNull BlockPosition position, } chunkSection.setType(position.getX()&15, position.getY()&15, position.getZ()&15, data); + world.notify(position); + chunk.e(); } @Override diff --git a/modules/v1_9_R2/src/main/java/net/countercraft/movecraft/compat/v1_9_R2/IWorldHandler.java b/modules/v1_9_R2/src/main/java/net/countercraft/movecraft/compat/v1_9_R2/IWorldHandler.java index 85f53b2f5..4659611be 100644 --- a/modules/v1_9_R2/src/main/java/net/countercraft/movecraft/compat/v1_9_R2/IWorldHandler.java +++ b/modules/v1_9_R2/src/main/java/net/countercraft/movecraft/compat/v1_9_R2/IWorldHandler.java @@ -298,6 +298,7 @@ private void setBlockFast(@NotNull World world, @NotNull BlockPosition position, chunkSection.setType(position.getX()&15, position.getY()&15, position.getZ()&15, data); world.notify(position, data, data, 3); + chunk.e(); } @Override From 05d01a813d394e67d49c6b034bfcf14d633e926c Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Sun, 12 Apr 2020 18:35:06 +0200 Subject: [PATCH 134/304] Updated WE 7 repair module to 1.15.2, adding new 1.14.4 signs to the repair, fixes #34 --- modules/worldedit/WE7Utils/pom.xml | 5 +++++ .../compat/we7/IMovecraftRepair.java | 22 +++++++++++++++---- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/modules/worldedit/WE7Utils/pom.xml b/modules/worldedit/WE7Utils/pom.xml index 072cddd69..d406aa2e4 100644 --- a/modules/worldedit/WE7Utils/pom.xml +++ b/modules/worldedit/WE7Utils/pom.xml @@ -44,6 +44,11 @@ worldguard-bukkit 7.0.1-SNAPSHOT + + org.bukkit + bukkit + 1.15.2-R0.1-SNAPSHOT + net.countercraft movecraft-api diff --git a/modules/worldedit/WE7Utils/src/main/java/net/countercraft/movecraft/compat/we7/IMovecraftRepair.java b/modules/worldedit/WE7Utils/src/main/java/net/countercraft/movecraft/compat/we7/IMovecraftRepair.java index a945db2b3..5b99c9c9e 100644 --- a/modules/worldedit/WE7Utils/src/main/java/net/countercraft/movecraft/compat/we7/IMovecraftRepair.java +++ b/modules/worldedit/WE7Utils/src/main/java/net/countercraft/movecraft/compat/we7/IMovecraftRepair.java @@ -145,8 +145,7 @@ public boolean saveRegionRepairState(World world, ProtectedRegion region) { BlockArrayClipboard clipboard = new BlockArrayClipboard(weRegion); Extent source = WorldEdit.getInstance().getEditSessionFactory().getEditSession(weWorld, -1); - Extent destination = clipboard; - ForwardExtentCopy copy = new ForwardExtentCopy(source, weRegion, destination, weMinPos); + ForwardExtentCopy copy = new ForwardExtentCopy(source, weRegion, clipboard, weMinPos); BlockTypeMask mask = new BlockTypeMask(source, blockTypeSet); copy.setSourceMask(mask); Operations.completeLegacy(copy); @@ -242,8 +241,23 @@ public Clipboard loadCraftRepairStateClipboard(Craft craft, Sign sign) { } } } - if (type.equals(Material.WALL_SIGN)){ - typeToConsume = Material.SIGN; + if (type.name().equals("WALL_SIGN")){ + typeToConsume = Material.getMaterial("SIGN"); + } + if (type == Material.ACACIA_WALL_SIGN){ + typeToConsume = Material.ACACIA_SIGN; + } + if (type == Material.BIRCH_WALL_SIGN){ + typeToConsume = Material.BIRCH_SIGN; + } + if (type == Material.DARK_OAK_WALL_SIGN){ + typeToConsume = Material.DARK_OAK_SIGN; + } + if (type == Material.OAK_WALL_SIGN){ + typeToConsume = Material.OAK_SIGN; + } + if (type == Material.SPRUCE_WALL_SIGN){ + typeToConsume = Material.SPRUCE_SIGN; } if (type.equals(Material.REDSTONE_WALL_TORCH)){ typeToConsume = Material.REDSTONE_TORCH; From fb8476362b667fd37ef7b7c35a7f40f02d1a1f49 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Sun, 12 Apr 2020 18:36:53 +0200 Subject: [PATCH 135/304] bump version --- modules/Movecraft/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/Movecraft/pom.xml b/modules/Movecraft/pom.xml index 2059643de..ad0cbe87f 100644 --- a/modules/Movecraft/pom.xml +++ b/modules/Movecraft/pom.xml @@ -10,7 +10,7 @@ UTF-8 - 7.0.0_for_1.8.8-1.15.2_beta_14 + 7.0.0_for_1.8.8-1.15.2_beta_16 From 7bf68456baeb9f6471cbfe569f4290b41067507f Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Mon, 13 Apr 2020 00:39:49 +0200 Subject: [PATCH 136/304] Fixed localisation auto update issue --- modules/Movecraft/pom.xml | 2 +- .../net/countercraft/movecraft/localisation/I18nSupport.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/Movecraft/pom.xml b/modules/Movecraft/pom.xml index ad0cbe87f..b9040ee89 100644 --- a/modules/Movecraft/pom.xml +++ b/modules/Movecraft/pom.xml @@ -10,7 +10,7 @@ UTF-8 - 7.0.0_for_1.8.8-1.15.2_beta_16 + 7.0.0_for_1.8.8-1.15.2_beta_17 diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/localisation/I18nSupport.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/localisation/I18nSupport.java index d784c4722..2baf9574b 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/localisation/I18nSupport.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/localisation/I18nSupport.java @@ -74,7 +74,7 @@ public static void init() { } boolean updated = false; for (Object key : jarLangFile.keySet()) { - if (languageFile.contains(key)) { + if (languageFile.containsKey(key)) { continue; } languageFile.setProperty((String) key, (String) jarLangFile.get(key)); From 4d304f6cfa04353c9b5745a1d83921b41cabab49 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Tue, 14 Apr 2020 00:06:15 +0200 Subject: [PATCH 137/304] Simplified CruiseSign --- .../movecraft/sign/CruiseSign.java | 26 ++----------------- 1 file changed, 2 insertions(+), 24 deletions(-) diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CruiseSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CruiseSign.java index a347287b1..d30b1b762 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CruiseSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CruiseSign.java @@ -6,12 +6,12 @@ import net.countercraft.movecraft.craft.CraftManager; import net.countercraft.movecraft.events.CraftDetectEvent; import net.countercraft.movecraft.localisation.I18nSupport; +import net.countercraft.movecraft.utils.SignUtils; import org.bukkit.ChatColor; import org.bukkit.World; import org.bukkit.block.Block; import org.bukkit.block.BlockFace; import org.bukkit.block.Sign; -import org.bukkit.block.data.type.WallSign; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.EventPriority; @@ -60,29 +60,7 @@ public final void onSignClick(PlayerInteractEvent event) { sign.setLine(0, "Cruise: ON"); sign.update(true); - final BlockFace direction; - if (Settings.IsLegacy){ - if (sign.getData() instanceof org.bukkit.material.Sign){ - org.bukkit.material.Sign signData = (org.bukkit.material.Sign) sign.getData(); - if (signData.isWallSign()) { - direction = signData.getAttachedFace(); - } else { - direction = signData.getFacing().getOppositeFace(); - } - }else { - direction = null; - } - } else { - if (sign.getBlockData() instanceof org.bukkit.block.data.type.Sign){ - org.bukkit.block.data.type.Sign signData = (org.bukkit.block.data.type.Sign)sign.getBlockData(); - direction = signData.getRotation().getOppositeFace(); - }else if (sign.getBlockData() instanceof org.bukkit.block.data.type.WallSign){ - WallSign signData = (WallSign)sign.getBlockData(); - direction = signData.getFacing().getOppositeFace(); - } else { - direction = null; - } - } + final BlockFace direction = SignUtils.getFacing(sign); c.setCruiseDirection(direction); c.setLastCruiseUpdate(System.currentTimeMillis()); c.setCruising(true); From d1228ab24df4e417e2a1036765de022718a0b2b6 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Tue, 14 Apr 2020 17:01:25 +0200 Subject: [PATCH 138/304] Tasks now only starts when starting up --- .../java/net/countercraft/movecraft/Movecraft.java | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java index 2ba61581c..8a2ea26ce 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java @@ -73,6 +73,7 @@ public class Movecraft extends JavaPlugin { private static Essentials essentialsPlugin = null; private Logger logger; private boolean shuttingDown; + private boolean startup = true; private WorldHandler worldHandler; private MovecraftRepair movecraftRepair; @@ -472,11 +473,13 @@ public void onEnable() { // Startup procedure asyncManager = new AsyncManager(); - asyncManager.runTaskTimer(this, 0, 1); + if (startup) + asyncManager.runTaskTimer(this, 0, 1); MapUpdateManager.getInstance().runTaskTimer(this, 0, 1); if(Settings.AssaultEnable) { assaultManager = new AssaultManager(this); - assaultManager.runTaskTimerAsynchronously(this, 0, 20); + if (startup) + assaultManager.runTaskTimerAsynchronously(this, 0, 20); } if(Settings.SiegeEnable) { @@ -517,7 +520,8 @@ public void onEnable() { logger.log(Level.INFO, "Siege configuration loaded."); } - siegeManager.runTaskTimerAsynchronously(this, 0, 20); + if (startup) + siegeManager.runTaskTimerAsynchronously(this, 0, 20); } CraftManager.initialize(); @@ -526,7 +530,8 @@ public void onEnable() { if (worldEditPlugin != null) { if (movecraftRepair != null){ repairManager = new RepairManager(); - repairManager.runTaskTimerAsynchronously(this, 0, 1); + if (startup) + repairManager.runTaskTimerAsynchronously(this, 0, 1); repairManager.convertOldCraftRepairStates(); } } @@ -576,6 +581,7 @@ public void onEnable() { I18nSupport.getInternationalisedString("Startup - Enabled message"), getDescription().getVersion())); } + startup = false; } @Override From 3e10a7754eef62e2558013a50830021afa58723f Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Tue, 14 Apr 2020 17:23:41 +0200 Subject: [PATCH 139/304] Implemented better method for checking signs --- .../mapUpdater/update/CraftRotateCommand.java | 2 +- .../update/CraftTranslateCommand.java | 2 +- .../sign/AntiAircraftDirectorSign.java | 8 +++--- .../movecraft/sign/AscendSign.java | 16 +++++++----- .../movecraft/sign/CannonDirectorSign.java | 4 +-- .../movecraft/sign/ContactsSign.java | 18 +++++++------ .../movecraft/sign/CraftSign.java | 3 ++- .../countercraft/movecraft/sign/CrewSign.java | 9 ++++--- .../movecraft/sign/CruiseSign.java | 15 ++++++----- .../movecraft/sign/DescendSign.java | 16 +++++++----- .../countercraft/movecraft/sign/HelmSign.java | 3 ++- .../countercraft/movecraft/sign/MoveSign.java | 3 ++- .../countercraft/movecraft/sign/NameSign.java | 3 ++- .../movecraft/sign/PilotSign.java | 19 -------------- .../movecraft/sign/RelativeMoveSign.java | 2 +- .../movecraft/sign/ReleaseSign.java | 6 ++--- .../movecraft/sign/RemoteSign.java | 3 ++- .../movecraft/sign/RepairSign.java | 8 +++--- .../movecraft/sign/SpeedSign.java | 18 +++++++------ .../movecraft/sign/StatusSign.java | 18 +++++++------ .../movecraft/sign/SubcraftRotateSign.java | 3 ++- .../movecraft/sign/TeleportSign.java | 6 ++--- .../movecraft/utils/SignUtils.java | 26 ++++++++++++++++--- 23 files changed, 112 insertions(+), 99 deletions(-) diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftRotateCommand.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftRotateCommand.java index 981970de0..65c481c3f 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftRotateCommand.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftRotateCommand.java @@ -228,7 +228,7 @@ private void sendSignEvents(){ Map> signs = new HashMap<>(); for (MovecraftLocation location : craft.getHitBox()) { Block block = location.toBukkit(craft.getW()).getBlock(); - if (block.getState() instanceof Sign) { + if (SignUtils.isSign(block)) { Sign sign = (Sign) block.getState(); if(!signs.containsKey(sign.getLines())) signs.put(sign.getLines(), new ArrayList<>()); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftTranslateCommand.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftTranslateCommand.java index 9417ec6f6..bb1090396 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftTranslateCommand.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftTranslateCommand.java @@ -239,7 +239,7 @@ private void sendSignEvents(){ Map> signs = new HashMap<>(); for (MovecraftLocation location : craft.getHitBox()) { Block block = location.toBukkit(craft.getW()).getBlock(); - if (block.getState() instanceof Sign) { + if (SignUtils.isSign(block)) { Sign sign = (Sign) block.getState(); if(!signs.containsKey(sign.getLines())) signs.put(sign.getLines(), new ArrayList<>()); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/AntiAircraftDirectorSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/AntiAircraftDirectorSign.java index daea35bef..5a5c8f428 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/AntiAircraftDirectorSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/AntiAircraftDirectorSign.java @@ -1,13 +1,11 @@ package net.countercraft.movecraft.sign; -import net.countercraft.movecraft.config.Settings; import net.countercraft.movecraft.craft.Craft; -import net.countercraft.movecraft.utils.LegacyUtils; -import net.countercraft.movecraft.utils.MathUtils; import net.countercraft.movecraft.craft.CraftManager; import net.countercraft.movecraft.localisation.I18nSupport; +import net.countercraft.movecraft.utils.MathUtils; +import net.countercraft.movecraft.utils.SignUtils; import org.bukkit.ChatColor; -import org.bukkit.Material; import org.bukkit.block.Block; import org.bukkit.block.Sign; import org.bukkit.event.EventHandler; @@ -26,7 +24,7 @@ public final void onSignClick(PlayerInteractEvent event) { return; } Block block = event.getClickedBlock(); - if (!(block.getState() instanceof Sign)){ + if (!SignUtils.isSign(block)){ return; } Sign sign = (Sign) event.getClickedBlock().getState(); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/AscendSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/AscendSign.java index 140c7f1d4..3aeabf395 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/AscendSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/AscendSign.java @@ -4,6 +4,7 @@ import net.countercraft.movecraft.craft.Craft; import net.countercraft.movecraft.craft.CraftManager; import net.countercraft.movecraft.events.CraftDetectEvent; +import net.countercraft.movecraft.utils.SignUtils; import org.bukkit.ChatColor; import org.bukkit.World; import org.bukkit.block.Block; @@ -21,12 +22,13 @@ public void onCraftDetect(CraftDetectEvent event){ World world = event.getCraft().getW(); for(MovecraftLocation location: event.getCraft().getHitBox()){ Block block = location.toBukkit(world).getBlock(); - if(block.getState() instanceof Sign){ - Sign sign = (Sign) block.getState(); - if (ChatColor.stripColor(sign.getLine(0)).equalsIgnoreCase("Ascend: ON")) { - sign.setLine(0, "Ascend: OFF"); - sign.update(); - } + if(!SignUtils.isSign(block)){ + return; + } + Sign sign = (Sign) block.getState(); + if (ChatColor.stripColor(sign.getLine(0)).equalsIgnoreCase("Ascend: ON")) { + sign.setLine(0, "Ascend: OFF"); + sign.update(); } } } @@ -38,7 +40,7 @@ public void onSignClickEvent(PlayerInteractEvent event){ return; } Block block = event.getClickedBlock(); - if (!(event.getClickedBlock().getState() instanceof Sign)){ + if (!SignUtils.isSign(block)){ return; } Sign sign = (Sign) event.getClickedBlock().getState(); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CannonDirectorSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CannonDirectorSign.java index 799a876b2..5af90d453 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CannonDirectorSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CannonDirectorSign.java @@ -1,10 +1,10 @@ package net.countercraft.movecraft.sign; -import net.countercraft.movecraft.MovecraftLocation; import net.countercraft.movecraft.craft.Craft; import net.countercraft.movecraft.craft.CraftManager; import net.countercraft.movecraft.localisation.I18nSupport; import net.countercraft.movecraft.utils.MathUtils; +import net.countercraft.movecraft.utils.SignUtils; import org.bukkit.ChatColor; import org.bukkit.block.Block; import org.bukkit.block.Sign; @@ -24,7 +24,7 @@ public final void onSignClick(PlayerInteractEvent event) { return; } Block block = event.getClickedBlock(); - if (!(block.getState() instanceof Sign)) { + if (!SignUtils.isSign(block)) { return; } Sign sign = (Sign) event.getClickedBlock().getState(); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/ContactsSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/ContactsSign.java index 386c75a6f..62b4748ef 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/ContactsSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/ContactsSign.java @@ -4,6 +4,7 @@ import net.countercraft.movecraft.craft.Craft; import net.countercraft.movecraft.events.CraftDetectEvent; import net.countercraft.movecraft.events.SignTranslateEvent; +import net.countercraft.movecraft.utils.SignUtils; import org.bukkit.ChatColor; import org.bukkit.World; import org.bukkit.block.Block; @@ -18,14 +19,15 @@ public void onCraftDetect(CraftDetectEvent event){ World world = event.getCraft().getW(); for(MovecraftLocation location: event.getCraft().getHitBox()){ Block block = location.toBukkit(world).getBlock(); - if(block.getState() instanceof Sign){ - Sign sign = (Sign) block.getState(); - if (ChatColor.stripColor(sign.getLine(0)).equalsIgnoreCase("Contacts:")) { - sign.setLine(1, ""); - sign.setLine(2, ""); - sign.setLine(3, ""); - sign.update(); - } + if(!SignUtils.isSign(block)){ + continue; + } + Sign sign = (Sign) block.getState(); + if (ChatColor.stripColor(sign.getLine(0)).equalsIgnoreCase("Contacts:")) { + sign.setLine(1, ""); + sign.setLine(2, ""); + sign.setLine(3, ""); + sign.update(); } } } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CraftSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CraftSign.java index 47cc5cd14..4ca0223d4 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CraftSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CraftSign.java @@ -9,6 +9,7 @@ import net.countercraft.movecraft.craft.ICraft; import net.countercraft.movecraft.events.CraftPilotEvent; import net.countercraft.movecraft.localisation.I18nSupport; +import net.countercraft.movecraft.utils.SignUtils; import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.Location; @@ -46,7 +47,7 @@ public final void onSignClick(PlayerInteractEvent event) { return; } Block block = event.getClickedBlock(); - if (!(block.getState() instanceof Sign)) { + if (!SignUtils.isSign(block)) { return; } Sign sign = (Sign) event.getClickedBlock().getState(); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CrewSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CrewSign.java index 71a3e9845..1fd231653 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CrewSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CrewSign.java @@ -8,9 +8,9 @@ import net.countercraft.movecraft.craft.CraftManager; import net.countercraft.movecraft.events.CraftDetectEvent; import net.countercraft.movecraft.events.SignTranslateEvent; -import net.countercraft.movecraft.utils.LegacyUtils; import net.countercraft.movecraft.localisation.I18nSupport; -import net.countercraft.movecraft.utils.MathUtils; +import net.countercraft.movecraft.utils.LegacyUtils; +import net.countercraft.movecraft.utils.SignUtils; import org.bukkit.*; import org.bukkit.block.Block; import org.bukkit.block.Sign; @@ -72,10 +72,11 @@ public final void onSignRightClick(PlayerInteractEvent event) { } Player player = event.getPlayer(); - if (!player.isSneaking() || !(event.getClickedBlock().getState() instanceof Sign)) { + final Block block = event.getClickedBlock(); + if (!player.isSneaking() || !SignUtils.isSign(block)) { return; } - Sign sign = (Sign) event.getClickedBlock().getState(); + Sign sign = (Sign) block.getState(); if (!sign.getLine(0).equalsIgnoreCase("Crew:")) { return; } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CruiseSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CruiseSign.java index d30b1b762..63725dc21 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CruiseSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CruiseSign.java @@ -27,12 +27,13 @@ public void onCraftDetect(CraftDetectEvent event){ World world = event.getCraft().getW(); for(MovecraftLocation location: event.getCraft().getHitBox()){ Block block = location.toBukkit(world).getBlock(); - if(block.getState() instanceof Sign){ - Sign sign = (Sign) block.getState(); - if (ChatColor.stripColor(sign.getLine(0)).equalsIgnoreCase("Cruise: ON")) { - sign.setLine(0, "Cruise: OFF"); - sign.update(); - } + if(SignUtils.isSign(block)){ + return; + } + Sign sign = (Sign) block.getState(); + if (ChatColor.stripColor(sign.getLine(0)).equalsIgnoreCase("Cruise: ON")) { + sign.setLine(0, "Cruise: OFF"); + sign.update(); } } } @@ -43,7 +44,7 @@ public final void onSignClick(PlayerInteractEvent event) { return; } Block block = event.getClickedBlock(); - if (!(block.getState() instanceof Sign)) { + if (!SignUtils.isSign(block)) { return; } Sign sign = (Sign) event.getClickedBlock().getState(); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/DescendSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/DescendSign.java index bebb6fd16..bd44c76ab 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/DescendSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/DescendSign.java @@ -4,6 +4,7 @@ import net.countercraft.movecraft.craft.Craft; import net.countercraft.movecraft.craft.CraftManager; import net.countercraft.movecraft.events.CraftDetectEvent; +import net.countercraft.movecraft.utils.SignUtils; import org.bukkit.ChatColor; import org.bukkit.World; import org.bukkit.block.Block; @@ -21,12 +22,13 @@ public void onCraftDetect(CraftDetectEvent event){ World world = event.getCraft().getW(); for(MovecraftLocation location: event.getCraft().getHitBox()){ Block block = location.toBukkit(world).getBlock(); - if(block.getState() instanceof Sign){ - Sign sign = (Sign) block.getState(); - if (ChatColor.stripColor(sign.getLine(0)).equalsIgnoreCase("Descend: ON")) { - sign.setLine(0, "Descend: OFF"); - sign.update(); - } + if(!SignUtils.isSign(block)){ + return; + } + Sign sign = (Sign) block.getState(); + if (ChatColor.stripColor(sign.getLine(0)).equalsIgnoreCase("Descend: ON")) { + sign.setLine(0, "Descend: OFF"); + sign.update(); } } } @@ -37,7 +39,7 @@ public final void onSignClick(PlayerInteractEvent event) { return; } Block block = event.getClickedBlock(); - if (!(event.getClickedBlock().getState() instanceof Sign)){ + if (!SignUtils.isSign(block)){ return; } Sign sign = (Sign) event.getClickedBlock().getState(); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/HelmSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/HelmSign.java index d25adb1ce..e393d3fc3 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/HelmSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/HelmSign.java @@ -5,6 +5,7 @@ import net.countercraft.movecraft.utils.MathUtils; import net.countercraft.movecraft.craft.CraftManager; import net.countercraft.movecraft.localisation.I18nSupport; +import net.countercraft.movecraft.utils.SignUtils; import org.bukkit.ChatColor; import org.bukkit.block.Block; import org.bukkit.block.Sign; @@ -37,7 +38,7 @@ public final void onSignClick(PlayerInteractEvent event) { return; } Block block = event.getClickedBlock(); - if (!(block.getState() instanceof Sign)) { + if (!SignUtils.isSign(block)) { return; } Sign sign = (Sign) event.getClickedBlock().getState(); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/MoveSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/MoveSign.java index 74eba96f4..2cc5d3f23 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/MoveSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/MoveSign.java @@ -2,6 +2,7 @@ import net.countercraft.movecraft.craft.CraftManager; import net.countercraft.movecraft.localisation.I18nSupport; +import net.countercraft.movecraft.utils.SignUtils; import org.bukkit.ChatColor; import org.bukkit.block.Block; import org.bukkit.block.Sign; @@ -19,7 +20,7 @@ public final void onSignClick(PlayerInteractEvent event) { return; } Block block = event.getClickedBlock(); - if (!(block.getState() instanceof Sign)) { + if (!SignUtils.isSign(block)) { return; } Sign sign = (Sign) event.getClickedBlock().getState(); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/NameSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/NameSign.java index 78ad827fa..4beafc8f1 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/NameSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/NameSign.java @@ -5,6 +5,7 @@ import net.countercraft.movecraft.craft.Craft; import net.countercraft.movecraft.events.CraftDetectEvent; import net.countercraft.movecraft.utils.ChatUtils; +import net.countercraft.movecraft.utils.SignUtils; import org.bukkit.World; import org.bukkit.block.Block; import org.bukkit.block.Sign; @@ -28,7 +29,7 @@ public void onCraftDetect(@NotNull CraftDetectEvent event) { for (MovecraftLocation location : c.getHitBox()) { Block b = location.toBukkit(w).getBlock(); - if (b.getState() instanceof Sign) { + if (SignUtils.isSign(b)) { Sign s = (Sign) b.getState(); String name = ""; if (s.getLine(0).equalsIgnoreCase(HEADER)) { diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/PilotSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/PilotSign.java index 96e955e3d..6233a00e5 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/PilotSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/PilotSign.java @@ -1,8 +1,6 @@ package net.countercraft.movecraft.sign; import org.bukkit.ChatColor; -import org.bukkit.block.Block; -import org.bukkit.block.Sign; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; import org.bukkit.event.block.SignChangeEvent; @@ -18,21 +16,4 @@ public final void onSignChange(SignChangeEvent event){ } } } - - public static synchronized boolean containsPilot(String name, Block signBlock){ - if (!(signBlock.getState() instanceof Sign)){ - throw new IllegalArgumentException("Block must be a sign!"); - } - Sign sign = (Sign) signBlock.getState(); - boolean contains = false; - if (sign.getLine(0).equalsIgnoreCase(HEADER)){ - for (int i = 1; i <= 3; i++){ - if (sign.getLine(i).equals(name)){ - contains = true; - break; - } - } - } - return contains; - } } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RelativeMoveSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RelativeMoveSign.java index b9a0982d0..0144e8155 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RelativeMoveSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RelativeMoveSign.java @@ -20,7 +20,7 @@ public final void onSignClick(PlayerInteractEvent event) { return; } Block block = event.getClickedBlock(); - if (!(block.getState() instanceof Sign)) { + if (!SignUtils.isSign(block)) { return; } Sign sign = (Sign) event.getClickedBlock().getState(); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/ReleaseSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/ReleaseSign.java index a89627b1f..e053df8b4 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/ReleaseSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/ReleaseSign.java @@ -1,11 +1,9 @@ package net.countercraft.movecraft.sign; -import net.countercraft.movecraft.config.Settings; import net.countercraft.movecraft.craft.Craft; import net.countercraft.movecraft.craft.CraftManager; -import net.countercraft.movecraft.utils.LegacyUtils; +import net.countercraft.movecraft.utils.SignUtils; import org.bukkit.ChatColor; -import org.bukkit.Material; import org.bukkit.block.Block; import org.bukkit.block.Sign; import org.bukkit.event.EventHandler; @@ -22,7 +20,7 @@ public final void onSignClick(PlayerInteractEvent event) { return; } Block block = event.getClickedBlock(); - if (!(block.getState() instanceof Sign)) { + if (!SignUtils.isSign(block)) { return; } Sign sign = (Sign) event.getClickedBlock().getState(); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RemoteSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RemoteSign.java index 5c565abcc..ba534058f 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RemoteSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RemoteSign.java @@ -7,6 +7,7 @@ import net.countercraft.movecraft.craft.CraftManager; import net.countercraft.movecraft.localisation.I18nSupport; import net.countercraft.movecraft.utils.MathUtils; +import net.countercraft.movecraft.utils.SignUtils; import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.block.Block; @@ -55,7 +56,7 @@ public final void onSignClick(PlayerInteractEvent event) { return; } Block block = event.getClickedBlock(); - if (!(block.getState() instanceof Sign)) { + if (!SignUtils.isSign(block)) { return; } Sign sign = (Sign) event.getClickedBlock().getState(); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RepairSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RepairSign.java index f8d4f4e47..80164a850 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RepairSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RepairSign.java @@ -17,11 +17,11 @@ import net.countercraft.movecraft.repair.RepairManager; import net.countercraft.movecraft.repair.RepairUtils; import net.countercraft.movecraft.utils.LegacyUtils; +import net.countercraft.movecraft.utils.SignUtils; import net.countercraft.movecraft.utils.WorldEditUtils; import org.bukkit.ChatColor; import org.bukkit.Material; import org.bukkit.block.Block; -import org.bukkit.block.BlockState; import org.bukkit.block.Sign; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; @@ -57,11 +57,11 @@ public void onSignClick(PlayerInteractEvent event){ if (event.getAction() != Action.RIGHT_CLICK_BLOCK && event.getAction() != Action.LEFT_CLICK_BLOCK) { return; } - BlockState state = event.getClickedBlock().getState(); - if (!(state instanceof Sign)) { + Block block = event.getClickedBlock(); + if (!SignUtils.isSign(block)) { return; } - Sign sign = (Sign) event.getClickedBlock().getState(); + Sign sign = (Sign) block.getState(); String signText = ChatColor.stripColor(sign.getLine(0)); if (signText == null) { return; diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/SpeedSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/SpeedSign.java index 5986635aa..c26294879 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/SpeedSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/SpeedSign.java @@ -4,6 +4,7 @@ import net.countercraft.movecraft.craft.Craft; import net.countercraft.movecraft.events.CraftDetectEvent; import net.countercraft.movecraft.events.SignTranslateEvent; +import net.countercraft.movecraft.utils.SignUtils; import org.bukkit.ChatColor; import org.bukkit.World; import org.bukkit.block.Block; @@ -17,14 +18,15 @@ public void onCraftDetect(CraftDetectEvent event){ World world = event.getCraft().getW(); for(MovecraftLocation location: event.getCraft().getHitBox()){ Block block = location.toBukkit(world).getBlock(); - if(block.getState() instanceof Sign) { - Sign sign = (Sign) block.getState(); - if (ChatColor.stripColor(sign.getLine(0)).equalsIgnoreCase("Speed:")) { - sign.setLine(1, "0 m/s"); - sign.setLine(2, "0ms"); - sign.setLine(3, "0T"); - sign.update(); - } + if(!SignUtils.isSign(block)) { + return; + } + Sign sign = (Sign) block.getState(); + if (ChatColor.stripColor(sign.getLine(0)).equalsIgnoreCase("Speed:")) { + sign.setLine(1, "0 m/s"); + sign.setLine(2, "0ms"); + sign.setLine(3, "0T"); + sign.update(); } } } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/StatusSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/StatusSign.java index 12f9a2ece..d0f9e71b9 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/StatusSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/StatusSign.java @@ -6,6 +6,7 @@ import net.countercraft.movecraft.events.CraftDetectEvent; import net.countercraft.movecraft.events.SignTranslateEvent; import net.countercraft.movecraft.utils.BlockLimitManager; +import net.countercraft.movecraft.utils.SignUtils; import org.bukkit.ChatColor; import org.bukkit.Location; import org.bukkit.Material; @@ -28,14 +29,15 @@ public void onCraftDetect(CraftDetectEvent event){ World world = event.getCraft().getW(); for(MovecraftLocation location: event.getCraft().getHitBox()){ Block block = location.toBukkit(world).getBlock(); - if(block.getState() instanceof Sign){ - Sign sign = (Sign) block.getState(); - if (ChatColor.stripColor(sign.getLine(0)).equalsIgnoreCase("Status:")) { - sign.setLine(1, ""); - sign.setLine(2, ""); - sign.setLine(3, ""); - sign.update(); - } + if(!SignUtils.isSign(block)){ + return; + } + Sign sign = (Sign) block.getState(); + if (ChatColor.stripColor(sign.getLine(0)).equalsIgnoreCase("Status:")) { + sign.setLine(1, ""); + sign.setLine(2, ""); + sign.setLine(3, ""); + sign.update(); } } } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/SubcraftRotateSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/SubcraftRotateSign.java index 31bb6314a..49ebe674d 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/SubcraftRotateSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/SubcraftRotateSign.java @@ -11,6 +11,7 @@ import net.countercraft.movecraft.events.CraftReleaseEvent; import net.countercraft.movecraft.localisation.I18nSupport; import net.countercraft.movecraft.utils.MathUtils; +import net.countercraft.movecraft.utils.SignUtils; import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.Location; @@ -39,7 +40,7 @@ public final void onSignClick(PlayerInteractEvent event) { return; } Block block = event.getClickedBlock(); - if (!(block.getState() instanceof Sign)) { + if (!SignUtils.isSign(block)) { return; } Sign sign = (Sign) event.getClickedBlock().getState(); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/TeleportSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/TeleportSign.java index 2161f2bed..79ef734f8 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/TeleportSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/TeleportSign.java @@ -1,11 +1,9 @@ package net.countercraft.movecraft.sign; -import net.countercraft.movecraft.config.Settings; import net.countercraft.movecraft.craft.CraftManager; import net.countercraft.movecraft.localisation.I18nSupport; -import net.countercraft.movecraft.utils.LegacyUtils; +import net.countercraft.movecraft.utils.SignUtils; import org.bukkit.ChatColor; -import org.bukkit.Material; import org.bukkit.block.Block; import org.bukkit.block.Sign; import org.bukkit.event.EventHandler; @@ -21,7 +19,7 @@ public final void onSignClick(PlayerInteractEvent event) { return; } Block block = event.getClickedBlock(); - if (!(block.getState() instanceof Sign)) { + if (!SignUtils.isSign(block)) { return; } Sign sign = (Sign) event.getClickedBlock().getState(); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/SignUtils.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/SignUtils.java index f8a1c3a8f..6f19ad6da 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/SignUtils.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/SignUtils.java @@ -1,19 +1,22 @@ package net.countercraft.movecraft.utils; import net.countercraft.movecraft.config.Settings; +import org.bukkit.Material; import org.bukkit.block.Block; import org.bukkit.block.BlockFace; import org.bukkit.block.Sign; import org.bukkit.block.data.BlockData; import org.bukkit.block.data.type.WallSign; import org.bukkit.material.MaterialData; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; public class SignUtils { /** * @param sign * @return */ - public static BlockFace getFacing(Sign sign) { + public static BlockFace getFacing(@NotNull Sign sign) { if (Settings.IsLegacy) { MaterialData materialData = sign.getData(); org.bukkit.material.Sign matSign = (org.bukkit.material.Sign) materialData; @@ -28,7 +31,24 @@ public static BlockFace getFacing(Sign sign) { return s.getRotation(); } - public static boolean isSign(Block block){ - return (block.getState() instanceof Sign); + public static boolean isSign(@Nullable Block block){ + if (block == null) + return false; + final Material type = block.getType(); + + return type.name().equals("SIGN_POST") || + type.name().equals("SIGN") || + type.name().equals("WALL_SIGN") || + type.name().endsWith("_SIGN") || + type.name().endsWith("_WALL_SIGN"); + } + + public static boolean isWallSign(@Nullable Block block) { + if (block == null) + return false; + final Material type = block.getType(); + + return type.name().equals("WALL_SIGN") || + type.name().endsWith("_WALL_SIGN"); } } From dd0d760e14f3dc7069d4be7c38489d52146a2f73 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Tue, 14 Apr 2020 18:20:36 +0200 Subject: [PATCH 140/304] Fixed a bug causing backwards cruising --- .../main/java/net/countercraft/movecraft/sign/CruiseSign.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CruiseSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CruiseSign.java index 63725dc21..7e3daef01 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CruiseSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CruiseSign.java @@ -61,7 +61,7 @@ public final void onSignClick(PlayerInteractEvent event) { sign.setLine(0, "Cruise: ON"); sign.update(true); - final BlockFace direction = SignUtils.getFacing(sign); + final BlockFace direction = SignUtils.getFacing(sign).getOppositeFace(); c.setCruiseDirection(direction); c.setLastCruiseUpdate(System.currentTimeMillis()); c.setCruising(true); From 3d628ef32588be32a0bfd7f272668aac286fedca Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Tue, 14 Apr 2020 18:28:29 +0200 Subject: [PATCH 141/304] Fixed a bug where sign checking was not inverted --- .../main/java/net/countercraft/movecraft/sign/CruiseSign.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CruiseSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CruiseSign.java index 7e3daef01..e361913eb 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CruiseSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CruiseSign.java @@ -27,7 +27,7 @@ public void onCraftDetect(CraftDetectEvent event){ World world = event.getCraft().getW(); for(MovecraftLocation location: event.getCraft().getHitBox()){ Block block = location.toBukkit(world).getBlock(); - if(SignUtils.isSign(block)){ + if(!SignUtils.isSign(block)){ return; } Sign sign = (Sign) block.getState(); From 275d14b790ccb20a67377947bc1170bc7c9d32d6 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Wed, 15 Apr 2020 01:13:10 +0200 Subject: [PATCH 142/304] Optimized waterlogging --- .../countercraft/movecraft/commands/CraftReportCommand.java | 1 + .../net/countercraft/movecraft/utils/WaterlogUtils.java | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/CraftReportCommand.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/CraftReportCommand.java index 713dbc637..ff62b7b32 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/CraftReportCommand.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/CraftReportCommand.java @@ -39,6 +39,7 @@ public boolean onCommand(CommandSender commandSender, Command command, String s, TopicPaginator paginator = new TopicPaginator(I18nSupport.getInternationalisedString("Craft Report")); for (Craft craft : CraftManager.getInstance()) { HashHitBox hitBox = craft.getHitBox(); + paginator.addLine((craft.getSinking() ? ChatColor.RED : craft.getDisabled() ? ChatColor.BLUE : "") + craft.getType().getCraftName() + " " + ChatColor.RESET + diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/WaterlogUtils.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/WaterlogUtils.java index 565c6f2e2..a545f995e 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/WaterlogUtils.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/WaterlogUtils.java @@ -10,7 +10,10 @@ import org.bukkit.block.data.type.Slab; import org.bukkit.block.data.type.TrapDoor; +import java.util.AbstractMap; + public class WaterlogUtils { + private static AbstractMap.SimpleImmutableEntry DEFAULT_PHASE_BLOCK = new AbstractMap.SimpleImmutableEntry<>(Material.WATER, 0); private WaterlogUtils(){ } @@ -31,7 +34,8 @@ public static void waterlogBlocksOnCraft(Craft craft, HitBox interior) { exteriorBlock = true; break; } - if (!exteriorBlock || ml.getY() > craft.getWaterLine() || !adjacentToWater(ml.toBukkit(craft.getW()))) { + final Material phaseBlock = craft.getPhaseBlocks().getOrDefault(ml, DEFAULT_PHASE_BLOCK).getKey(); + if (!exteriorBlock || phaseBlock != Material.WATER || !adjacentToWater(ml.toBukkit(craft.getW()))) { waterlog = false; } else if (wLog instanceof TrapDoor) { TrapDoor td = (TrapDoor) wLog; From 5a7290e7d06426bb5f7acb20910944da255bd4d6 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Fri, 17 Apr 2020 12:37:14 +0200 Subject: [PATCH 143/304] Fixed stuff with WorldGuard, siege and doors --- modules/Movecraft/pom.xml | 3 +- .../net/countercraft/movecraft/Movecraft.java | 55 ++------ .../movecraft/async/AsyncManager.java | 18 +-- .../async/rotation/RotationTask.java | 68 +-------- .../movecraft/commands/SiegeCommand.java | 36 ++++- .../movecraft/listener/BlockListener.java | 4 +- .../movecraft/utils/WGCustomFlagsUtils.java | 4 +- .../movecraft/warfare/siege/Siege.java | 9 ++ .../warfare/siege/SiegePreparationTask.java | 2 + .../warfare/siege/SiegeProgressTask.java | 6 +- .../movecraft/warfare/siege/SiegeTask.java | 8 ++ .../worldguard/WorldGuardCompatManager.java | 132 +++++++++++++++++- .../countercraft/movecraft/craft/Craft.java | 1 + 13 files changed, 213 insertions(+), 133 deletions(-) diff --git a/modules/Movecraft/pom.xml b/modules/Movecraft/pom.xml index b9040ee89..588b91bee 100644 --- a/modules/Movecraft/pom.xml +++ b/modules/Movecraft/pom.xml @@ -97,7 +97,8 @@ com.sk89q.worldedit worldedit-bukkit - 7.0.0-SNAPSHOT + 7.0.1-SNAPSHOT + compile com.sk89q.worldguard diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java index 8a2ea26ce..2bd4e4249 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java @@ -23,11 +23,8 @@ import com.palmergames.bukkit.towny.Towny; import com.sk89q.worldedit.bukkit.WorldEditPlugin; import com.sk89q.worldguard.bukkit.WorldGuardPlugin; -import com.sk89q.worldguard.protection.flags.StateFlag; import net.countercraft.movecraft.async.AsyncManager; import net.countercraft.movecraft.commands.*; -import net.countercraft.movecraft.utils.UpdateManager; -import net.countercraft.movecraft.worldguard.WorldGuardCompatManager; import net.countercraft.movecraft.config.Settings; import net.countercraft.movecraft.craft.CraftManager; import net.countercraft.movecraft.listener.BlockListener; @@ -37,13 +34,14 @@ import net.countercraft.movecraft.mapUpdater.MapUpdateManager; import net.countercraft.movecraft.repair.RepairManager; import net.countercraft.movecraft.sign.*; -import net.countercraft.movecraft.utils.LegacyUtils; import net.countercraft.movecraft.towny.TownyCompatManager; +import net.countercraft.movecraft.utils.LegacyUtils; import net.countercraft.movecraft.utils.TownyUtils; -import net.countercraft.movecraft.utils.WGCustomFlagsUtils; +import net.countercraft.movecraft.utils.UpdateManager; import net.countercraft.movecraft.warfare.assault.AssaultManager; import net.countercraft.movecraft.warfare.siege.Siege; import net.countercraft.movecraft.warfare.siege.SiegeManager; +import net.countercraft.movecraft.worldguard.WorldGuardCompatManager; import net.milkbowl.vault.economy.Economy; import org.bukkit.Material; import org.bukkit.configuration.file.FileConfiguration; @@ -59,10 +57,7 @@ import java.util.logging.Logger; public class Movecraft extends JavaPlugin { - public static StateFlag FLAG_PILOT = null; //new StateFlag("movecraft-pilot", true); - public static StateFlag FLAG_MOVE = null; //new StateFlag("movecraft-move", true); - public static StateFlag FLAG_ROTATE = null; //new StateFlag("movecraft-rotate", true); - public static StateFlag FLAG_SINK = null; //new StateFlag("movecraft-sink", true); + private static Movecraft instance; private static WorldGuardPlugin worldGuardPlugin; private static WorldEditPlugin worldEditPlugin; @@ -320,20 +315,16 @@ public void onEnable() { } } //load up WorldGuard if it's present - Plugin wGPlugin = getServer().getPluginManager().getPlugin("WorldGuard"); - if (!(wGPlugin instanceof WorldGuardPlugin)) { + if (worldGuardPlugin == null) { logger.log(Level.INFO, I18nSupport.getInternationalisedString("Startup - WG Not Found")); Settings.SiegeEnable = false; Settings.AssaultEnable = false; Settings.RestrictSiBsToRegions = false; - worldGuardPlugin = null; } else { logger.log(Level.INFO, I18nSupport.getInternationalisedString("Startup - WG Found")); Settings.WorldGuardBlockMoveOnBuildPerm = getConfig().getBoolean("WorldGuardBlockMoveOnBuildPerm", false); Settings.WorldGuardBlockSinkOnPVPPerm = getConfig().getBoolean("WorldGuardBlockSinkOnPVPPerm", false); logger.log(Level.INFO, "Settings: WorldGuardBlockMoveOnBuildPerm - {0}, WorldGuardBlockSinkOnPVPPerm - {1}", new Object[]{Settings.WorldGuardBlockMoveOnBuildPerm, Settings.WorldGuardBlockSinkOnPVPPerm}); - getServer().getPluginManager().registerEvents(new WorldGuardCompatManager(), this); - worldGuardPlugin = (WorldGuardPlugin) wGPlugin; } @@ -385,31 +376,6 @@ public void onEnable() { } else { logger.log(Level.INFO, I18nSupport.getInternationalisedString("Startup - Cannons Not Found")); } - if (worldGuardPlugin != null && worldGuardPlugin instanceof WorldGuardPlugin) { - if (worldGuardPlugin.isEnabled()) { - Plugin tempWGCustomFlagsPlugin = getServer().getPluginManager().getPlugin("WGCustomFlags"); - if (tempWGCustomFlagsPlugin != null && tempWGCustomFlagsPlugin instanceof WGCustomFlagsPlugin) { - logger.log(Level.INFO, I18nSupport.getInternationalisedString("Startup - WGCF Found")); - wgCustomFlagsPlugin = (WGCustomFlagsPlugin) tempWGCustomFlagsPlugin; - WGCustomFlagsUtils WGCFU = new WGCustomFlagsUtils(); - FLAG_PILOT = WGCFU.getNewStateFlag("movecraft-pilot", true); - FLAG_MOVE = WGCFU.getNewStateFlag("movecraft-move", true); - FLAG_ROTATE = WGCFU.getNewStateFlag("movecraft-rotate", true); - FLAG_SINK = WGCFU.getNewStateFlag("movecraft-sink", true); - WGCFU.init(); - Settings.WGCustomFlagsUsePilotFlag = getConfig().getBoolean("WGCustomFlagsUsePilotFlag", false); - Settings.WGCustomFlagsUseMoveFlag = getConfig().getBoolean("WGCustomFlagsUseMoveFlag", false); - Settings.WGCustomFlagsUseRotateFlag = getConfig().getBoolean("WGCustomFlagsUseRotateFlag", false); - Settings.WGCustomFlagsUseSinkFlag = getConfig().getBoolean("WGCustomFlagsUseSinkFlag", false); - logger.log(Level.INFO, "Settings: WGCustomFlagsUsePilotFlag - {0}", Settings.WGCustomFlagsUsePilotFlag); - logger.log(Level.INFO, "Settings: WGCustomFlagsUseMoveFlag - {0}", Settings.WGCustomFlagsUseMoveFlag); - logger.log(Level.INFO, "Settings: WGCustomFlagsUseRotateFlag - {0}", Settings.WGCustomFlagsUseRotateFlag); - logger.log(Level.INFO, "Settings: WGCustomFlagsUseSinkFlag - {0}", Settings.WGCustomFlagsUseSinkFlag); - } else { - logger.log(Level.INFO, I18nSupport.getInternationalisedString("Startup - WGCF Not Found")); - } - } - } //Towny Plugin tempTownyPlugin = getServer().getPluginManager().getPlugin("Towny"); if (tempTownyPlugin != null && tempTownyPlugin instanceof Towny) { @@ -473,9 +439,10 @@ public void onEnable() { // Startup procedure asyncManager = new AsyncManager(); - if (startup) + if (startup) { asyncManager.runTaskTimer(this, 0, 1); - MapUpdateManager.getInstance().runTaskTimer(this, 0, 1); + MapUpdateManager.getInstance().runTaskTimer(this, 0, 1); + } if(Settings.AssaultEnable) { assaultManager = new AssaultManager(this); if (startup) @@ -589,6 +556,12 @@ public void onLoad() { super.onLoad(); instance = this; logger = getLogger(); + //load up WorldGuard if it's present + Plugin wGPlugin = getServer().getPluginManager().getPlugin("WorldGuard"); + if (wGPlugin instanceof WorldGuardPlugin) { + worldGuardPlugin = (WorldGuardPlugin) wGPlugin; + getServer().getPluginManager().registerEvents(new WorldGuardCompatManager(), this); + } } private void saveLegacyConfig(){ diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java index 818fda0b6..514042efa 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java @@ -280,23 +280,11 @@ private void processAlgorithmQueue() { I18nSupport.getInternationalisedString("Detection - Successfully piloted craft") + " Size: " + c.getHitBox().size()); if (!failed) { - Movecraft.getInstance().getLogger().log(Level.INFO, - String.format( - I18nSupport.getInternationalisedString( - "Detection - Success - Log Output"), - notifyP.getName(), c.getType().getCraftName(), c.getHitBox().size(), - c.getHitBox().getMinX(), c.getHitBox().getMinZ())); + Movecraft.getInstance().getLogger().log(Level.INFO, String.format(I18nSupport.getInternationalisedString("Detection - Success - Log Output"), notifyP.getName(), c.getType().getCraftName(), c.getHitBox().size(), c.getHitBox().getMinX(), c.getHitBox().getMinZ())); } } else { - Movecraft.getInstance().getLogger().log(Level.INFO, failed ? - I18nSupport.getInternationalisedString("Detection - NULL Player Detection Failed") + ": " + event.getFailMessage() - : - String.format( - I18nSupport.getInternationalisedString( - "Detection - Success - Log Output"), - "NULL PLAYER", c.getType().getCraftName(), c.getHitBox().size(), - c.getHitBox().getMinX(), c.getHitBox().getMinZ())); + Movecraft.getInstance().getLogger().log(Level.INFO, failed ? I18nSupport.getInternationalisedString("Detection - NULL Player Detection Failed") + ": " + event.getFailMessage() : String.format(I18nSupport.getInternationalisedString("Detection - Success - Log Output"), "NULL PLAYER", c.getType().getCraftName(), c.getHitBox().size(), c.getHitBox().getMinX(), c.getHitBox().getMinZ())); } if (!failed) CraftManager.getInstance().addCraft(c, p); @@ -675,7 +663,7 @@ private void processSinking() { int dz = 0; if (craft.getType().getKeepMovingOnSink()) { final int limit = craft.getType().getKeepMovingOnSinkMaxMove(); - final boolean limitMotion = craft.getType().getKeepMovingOnSinkMaxMove() > -1; + final boolean limitMotion = limit > -1; dx = limitMotion ? Math.min(craft.getLastDX(), (craft.getLastDX() > 0 ? 1 : -1) * limit) : craft.getLastDX(); dz = limitMotion ? Math.min(craft.getLastDZ(), (craft.getLastDX() > 0 ? 1 : -1) * limit) : craft.getLastDZ(); } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/rotation/RotationTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/rotation/RotationTask.java index 1305c7787..805e01279 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/rotation/RotationTask.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/rotation/RotationTask.java @@ -17,14 +17,8 @@ package net.countercraft.movecraft.async.rotation; -import com.palmergames.bukkit.towny.object.Town; import com.palmergames.bukkit.towny.object.TownBlock; import com.palmergames.bukkit.towny.object.TownyWorld; -import com.sk89q.worldedit.bukkit.BukkitAdapter; -import com.sk89q.worldedit.math.BlockVector3; -import com.sk89q.worldguard.LocalPlayer; -import com.sk89q.worldguard.WorldGuard; -import com.sk89q.worldguard.protection.ApplicableRegionSet; import net.countercraft.movecraft.Movecraft; import net.countercraft.movecraft.MovecraftLocation; import net.countercraft.movecraft.Rotation; @@ -37,7 +31,9 @@ import net.countercraft.movecraft.mapUpdater.update.CraftRotateCommand; import net.countercraft.movecraft.mapUpdater.update.UpdateCommand; import net.countercraft.movecraft.utils.*; -import org.bukkit.*; +import org.bukkit.Bukkit; +import org.bukkit.Material; +import org.bukkit.World; import org.bukkit.block.Block; import org.bukkit.block.BlockFace; import org.bukkit.block.Furnace; @@ -355,64 +351,6 @@ public boolean getIsSubCraft() { return isSubCraft; } - private void isTownyBlock(Location plugLoc, Player craftPilot){ - //towny - Player p = craftPilot == null ? getCraft().getNotificationPlayer() : craftPilot; - if (p == null) { - return; - } - if (Movecraft.getInstance().getWorldGuardPlugin() != null && Movecraft.getInstance().getWGCustomFlagsPlugin() != null && Settings.WGCustomFlagsUsePilotFlag) { - LocalPlayer lp = Movecraft.getInstance().getWorldGuardPlugin().wrapPlayer(p); - WGCustomFlagsUtils WGCFU = new WGCustomFlagsUtils(); - if (!WGCFU.validateFlag(plugLoc, Movecraft.FLAG_ROTATE, lp)) { - failed = true; - failMessage = String.format(I18nSupport.getInternationalisedString("WGCustomFlags - Rotation Failed") + " @ %d,%d,%d", plugLoc.getX(), plugLoc.getY(), plugLoc.getZ()); - return; - } - } - - if (!townyEnabled) { - return; - } - TownBlock townBlock = TownyUtils.getTownBlock(plugLoc); - if (townBlock == null || townBlockSet.contains(townBlock)) { - return; - } - if (TownyUtils.validateCraftMoveEvent(p, plugLoc, townyWorld)) { - townBlockSet.add(townBlock); - return; - } - Town town = TownyUtils.getTown(townBlock); - if (town == null) { - return; - } - Location locSpawn = TownyUtils.getTownSpawn(townBlock); - if (locSpawn == null || !townyWorldHeightLimits.validate(newHitBox.getMaxY(), locSpawn.getBlockY())) { - failed = true; - } - if (failed) { - if (Movecraft.getInstance().getWorldGuardPlugin() != null && Movecraft.getInstance().getWGCustomFlagsPlugin() != null && Settings.WGCustomFlagsUsePilotFlag) { - LocalPlayer lp = Movecraft.getInstance().getWorldGuardPlugin().wrapPlayer(p); - ApplicableRegionSet regions; - if (Settings.IsLegacy){ - regions = LegacyUtils.getApplicableRegions(LegacyUtils.getRegionManager(Movecraft.getInstance().getWorldGuardPlugin(), plugLoc.getWorld()), plugLoc);//.getApplicableRegions(); - } else { - regions = WorldGuard.getInstance().getPlatform().getRegionContainer().get(BukkitAdapter.adapt(plugLoc.getWorld())).getApplicableRegions(BlockVector3.at(plugLoc.getBlockX(), plugLoc.getBlockY(), plugLoc.getBlockZ())); - } - - if (regions.size() != 0) { - WGCustomFlagsUtils WGCFU = new WGCustomFlagsUtils(); - if (WGCFU.validateFlag(plugLoc, Movecraft.FLAG_ROTATE, lp)) { - failed = false; - } - } - } - } - if (failed) { - failMessage = String.format(I18nSupport.getInternationalisedString("Towny - Rotation Failed") + " %s @ %d,%d,%d", town.getName(), plugLoc.getX(), plugLoc.getY(), plugLoc.getZ()); - } - } - private boolean checkChests(Material mBlock, MovecraftLocation newLoc) { Material testMaterial; diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/SiegeCommand.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/SiegeCommand.java index b6a7ac753..8fb55a401 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/SiegeCommand.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/SiegeCommand.java @@ -23,8 +23,8 @@ import org.bukkit.boss.BarFlag; import org.bukkit.boss.BarStyle; import org.bukkit.command.Command; -import org.bukkit.command.CommandExecutor; import org.bukkit.command.CommandSender; +import org.bukkit.command.TabExecutor; import org.bukkit.entity.Player; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -35,7 +35,7 @@ import static net.countercraft.movecraft.utils.ChatUtils.MOVECRAFT_COMMAND_PREFIX; -public class SiegeCommand implements CommandExecutor { +public class SiegeCommand implements TabExecutor { //TODO: Add tab complete private final NumberFormat currencyFormat = NumberFormat.getCurrencyInstance(); private final Map playerTimeMap = new HashMap<>(); @@ -194,6 +194,7 @@ private void startSiege(Siege siege, Player player, long cost) { Movecraft.getInstance().getEconomy().withdrawPlayer(player, cost); siege.setProgressBar(Bukkit.createBossBar(siege.getName(), BarColor.BLUE, BarStyle.SEGMENTED_20, BarFlag.DARKEN_SKY)); siege.getProgressBar().setProgress(0.0); + siege.getProgressBar().setVisible(true); siege.setPlayerUUID(player.getUniqueId()); siege.setStartTime(System.currentTimeMillis()); siege.setStage(SiegeStage.PREPERATION); @@ -384,4 +385,35 @@ private String formatMinutes(int seconds) { } } + + @Nullable + @Override + public List onTabComplete(@NotNull CommandSender commandSender, @NotNull Command command, @NotNull String s, @NotNull String[] strings) { + if (!commandSender.hasPermission("movecraft.siege")) { + return Collections.emptyList(); + } + ArrayList tabCompletions = new ArrayList<>(); + if (strings.length <= 1) { + tabCompletions.add("begin"); + tabCompletions.add("info"); + tabCompletions.add("abort"); + tabCompletions.add("list"); + } else if (strings[0].equalsIgnoreCase("info")) { + for (Siege siege : Movecraft.getInstance().getSiegeManager().getSieges()) { + tabCompletions.add(siege.getName()); + } + } + Collections.sort(tabCompletions); + if (strings.length == 0) { + return tabCompletions; + } + List completions = new ArrayList<>(); + for (String tabCompletion : tabCompletions) { + if (!tabCompletion.startsWith(strings[strings.length - 1])) + continue; + completions.add(tabCompletion); + } + Collections.sort(completions); + return completions; + } } \ No newline at end of file diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/BlockListener.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/BlockListener.java index 03e808d24..7791d6a30 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/BlockListener.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/BlockListener.java @@ -36,6 +36,7 @@ import org.bukkit.block.*; import org.bukkit.block.data.BlockData; import org.bukkit.block.data.Directional; +import org.bukkit.block.data.type.Door; import org.bukkit.entity.Entity; import org.bukkit.entity.EntityType; import org.bukkit.entity.Player; @@ -246,11 +247,10 @@ public void onPhysics(BlockPhysicsEvent event) { BlockData data = block.getBlockData(); if (block.getType() == Material.REPEATER || block.getType() == Material.COMPARATOR) faceAlwaysDown = true; - if (data instanceof Directional && !faceAlwaysDown) + if (data instanceof Directional && !faceAlwaysDown && !(data instanceof Door)) face = ((Directional) data).getFacing().getOppositeFace(); } if (!event.getBlock().getRelative(face).getType().isSolid()) { -// if(event.getEventName().equals("BlockPhysicsEvent")) { event.setCancelled(true); return; } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/WGCustomFlagsUtils.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/WGCustomFlagsUtils.java index 35df171c3..15ada2b33 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/WGCustomFlagsUtils.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/WGCustomFlagsUtils.java @@ -58,7 +58,7 @@ public boolean registerStageFlag(Object o) { public void init() { - if (Movecraft.FLAG_PILOT != null) { + /*if (Movecraft.FLAG_PILOT != null) { this.registerStageFlag(Movecraft.FLAG_PILOT); } if (Movecraft.FLAG_MOVE != null) { @@ -69,7 +69,7 @@ public void init() { } if (Movecraft.FLAG_SINK != null) { this.registerStageFlag(Movecraft.FLAG_SINK); - } + }*/ } public boolean validateFlag(Location loc, Object flag) { diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/siege/Siege.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/siege/Siege.java index c7e2d75ee..810fb8bfa 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/siege/Siege.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/siege/Siege.java @@ -16,6 +16,7 @@ public class Siege { private long startTime; private int lastUpdate; private long lastPayout; + private boolean progressTaskStarted; private final boolean doubleCostPerOwnedSiegeRegion; private UUID playerUUID; private BossBar progressBar; @@ -166,4 +167,12 @@ public BossBar getProgressBar() { public void setProgressBar(BossBar progressBar) { this.progressBar = progressBar; } + + public boolean isProgressTaskStarted() { + return progressTaskStarted; + } + + public void setProgressTaskStarted(boolean progressTaskStarted) { + this.progressTaskStarted = progressTaskStarted; + } } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/siege/SiegePreparationTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/siege/SiegePreparationTask.java index 75f8ed9db..a0a466cbe 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/siege/SiegePreparationTask.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/siege/SiegePreparationTask.java @@ -16,6 +16,7 @@ public SiegePreparationTask(Siege siege) { @Override public void run() { siege.getProgressBar().setVisible(true); + addPlayersToProgressBar(); int timePassed = ((int)(System.currentTimeMillis() - siege.getStartTime())); //time passed in milliseconds int timePassedInSeconds = timePassed / 1000; double progress = (double) timePassedInSeconds / (double) siege.getDelayBeforeStart(); @@ -23,6 +24,7 @@ public void run() { if (timePassedInSeconds >= siege.getDelayBeforeStart()){ siege.getProgressBar().setProgress(0.0); siege.setStage(SiegeStage.IN_PROGRESS); + return; } if ((siege.getDelayBeforeStart() - timePassedInSeconds) % Settings.SiegeTaskSeconds != 0 || timePassed < 3000){ return; diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/siege/SiegeProgressTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/siege/SiegeProgressTask.java index a4ee34e32..7752920d8 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/siege/SiegeProgressTask.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/siege/SiegeProgressTask.java @@ -26,6 +26,7 @@ public SiegeProgressTask(Siege siege) { //every 20 ticks = 1 second public void run() { + addPlayersToProgressBar(); int timeLeft = (siege.getDuration() - (int) ((System.currentTimeMillis() - siege.getStartTime())/1000)); double progress = (double) (siege.getDelayBeforeStart() - timeLeft) / (double) (siege.getDuration() - siege.getDelayBeforeStart()); siege.getProgressBar().setProgress(Math.min(progress, 1.0)); @@ -34,10 +35,10 @@ public void run() { BarColor bColor = leaderPilotingShip(siegeCraft) && leaderShipInRegion(siegeCraft, siegeLeader) ? BarColor.GREEN : BarColor.RED; siege.getProgressBar().setColor(bColor); - if (timeLeft % Settings.SiegeTaskSeconds != 0) { + if (timeLeft % Settings.SiegeTaskSeconds != 0 && siege.isProgressTaskStarted()) { return; } - + siege.setProgressTaskStarted(true); if (timeLeft > 10) { @@ -88,6 +89,7 @@ private void endSiege(Craft siegeCraft, Player siegeLeader) { } siege.getProgressBar().setVisible(false); siege.getProgressBar().setColor(BarColor.BLUE); + siege.setProgressTaskStarted(false); siege.setStage(SiegeStage.INACTIVE); } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/siege/SiegeTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/siege/SiegeTask.java index ec5b295c8..0229bb253 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/siege/SiegeTask.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/siege/SiegeTask.java @@ -1,5 +1,7 @@ package net.countercraft.movecraft.warfare.siege; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; import org.bukkit.scheduler.BukkitRunnable; import net.countercraft.movecraft.localisation.I18nSupport; @@ -13,6 +15,12 @@ protected SiegeTask(Siege siege) { @Override public abstract void run(); + protected void addPlayersToProgressBar() { + for (Player p : Bukkit.getOnlinePlayers()) { + siege.getProgressBar().addPlayer(p); + } + } + public String formatMinutes(int seconds) { if (seconds < 60) { if (seconds > 0) { diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/worldguard/WorldGuardCompatManager.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/worldguard/WorldGuardCompatManager.java index cc5c5cfa3..725380458 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/worldguard/WorldGuardCompatManager.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/worldguard/WorldGuardCompatManager.java @@ -8,6 +8,8 @@ import com.sk89q.worldguard.WorldGuard; import com.sk89q.worldguard.bukkit.WorldGuardPlugin; import com.sk89q.worldguard.protection.ApplicableRegionSet; +import com.sk89q.worldguard.protection.flags.StateFlag; +import com.sk89q.worldguard.protection.flags.registry.FlagRegistry; import com.sk89q.worldguard.protection.managers.RegionManager; import com.sk89q.worldguard.protection.regions.ProtectedRegion; import com.sk89q.worldguard.protection.regions.RegionContainer; @@ -16,6 +18,7 @@ import net.countercraft.movecraft.MovecraftLocation; import net.countercraft.movecraft.config.Settings; import net.countercraft.movecraft.craft.Craft; +import net.countercraft.movecraft.events.CraftDetectEvent; import net.countercraft.movecraft.events.CraftRotateEvent; import net.countercraft.movecraft.events.CraftSinkEvent; import net.countercraft.movecraft.events.CraftTranslateEvent; @@ -27,7 +30,33 @@ import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; +import java.lang.reflect.Method; + public class WorldGuardCompatManager implements Listener { + public static StateFlag FLAG_PILOT = new StateFlag("movecraft-pilot", true); + public static StateFlag FLAG_MOVE = new StateFlag("movecraft-move", true); + public static StateFlag FLAG_ROTATE = new StateFlag("movecraft-rotate", true); + public static StateFlag FLAG_SINK = new StateFlag("movecraft-sink", true); + + public WorldGuardCompatManager() { + FlagRegistry flags; + if (Settings.IsLegacy) { + try { + final Method getFlagRegistry = WorldGuardPlugin.class.getDeclaredMethod("getFlagRegistry"); + flags = (FlagRegistry) getFlagRegistry.invoke(Movecraft.getInstance().getWorldGuardPlugin()); + } catch (Exception e) { + return; + } + + } else { + flags = WorldGuard.getInstance().getFlagRegistry(); + } + flags.register(FLAG_MOVE); + flags.register(FLAG_PILOT); + flags.register(FLAG_ROTATE); + flags.register(FLAG_SINK); + } + @EventHandler public void onCraftTranslateEvent(CraftTranslateEvent event){ if(!Settings.WorldGuardBlockMoveOnBuildPerm) @@ -35,6 +64,10 @@ public void onCraftTranslateEvent(CraftTranslateEvent event){ if(event.getCraft().getNotificationPlayer() == null) return; for(MovecraftLocation location : event.getNewHitBox()){ + if (canMoveInRegion(location, event.getCraft().getW())) { + continue; + } + if(!pilotHasAccessToRegion(event.getCraft().getNotificationPlayer(), location, event.getCraft().getW())){ event.setCancelled(true); event.setFailMessage(String.format( I18nSupport.getInternationalisedString( "Translation - WorldGuard - Not Permitted To Build" )+" @ %d,%d,%d", location.getX(), location.getY(), location.getZ() ) ); @@ -51,6 +84,9 @@ public void onCraftRotateEvent(CraftRotateEvent event){ if(event.getCraft().getNotificationPlayer() == null) return; for(MovecraftLocation location : event.getNewHitBox()){ + if (canRotateInRegion(location, event.getCraft().getW())) { + continue; + } if(!pilotHasAccessToRegion(event.getCraft().getNotificationPlayer(), location, event.getCraft().getW())){ event.setCancelled(true); event.setFailMessage(String.format( I18nSupport.getInternationalisedString("Rotation - WorldGuard - Not Permitted To Build" )+" @ %d,%d,%d", location.getX(), location.getY(), location.getZ())); @@ -66,11 +102,50 @@ private boolean pilotHasAccessToRegion(Player player, MovecraftLocation location LocalPlayer lPlayer = Movecraft.getInstance().getWorldGuardPlugin().wrapPlayer(player); com.sk89q.worldedit.world.World weWorld = new BukkitWorld(world); Location wgLoc = new Location(weWorld, location.getX(), location.getY(), location.getZ()); - return query.getApplicableRegions(wgLoc).isOwnerOfAll(lPlayer) || query.getApplicableRegions(wgLoc).isMemberOfAll(lPlayer) || + ApplicableRegionSet regions = query.getApplicableRegions(wgLoc); + return regions.isOwnerOfAll(lPlayer) || regions.isMemberOfAll(lPlayer) || player.hasPermission("worldguard.build.*"); } } + private boolean canRotateInRegion(MovecraftLocation location, World world) { + RegionManager manager; + ApplicableRegionSet regions; + if (Settings.IsLegacy) { + manager = LegacyUtils.getRegionManager(Movecraft.getInstance().getWorldGuardPlugin(), world); + regions = LegacyUtils.getApplicableRegions(manager, location.toBukkit(world)); + } else { + RegionContainer container = WorldGuard.getInstance().getPlatform().getRegionContainer(); + manager = container.get(BukkitAdapter.adapt(world)); + regions = manager.getApplicableRegions(BlockVector3.at(location.getX(), location.getY(), location.getZ())); + } + for (ProtectedRegion region : regions) { + if (region.getFlag(FLAG_ROTATE) == StateFlag.State.DENY) + return false; + } + return true; + } + + private boolean canMoveInRegion(MovecraftLocation location, World world) { + RegionManager manager; + if (Settings.IsLegacy) { + manager = LegacyUtils.getRegionManager(Movecraft.getInstance().getWorldGuardPlugin(), world); + } else { + RegionContainer container = WorldGuard.getInstance().getPlatform().getRegionContainer(); + manager = container.get(BukkitAdapter.adapt(world)); + } + if (manager == null) { + return true; + } + ApplicableRegionSet regions = Settings.IsLegacy ? LegacyUtils.getApplicableRegions(manager, location.toBukkit(world)) : manager.getApplicableRegions(BlockVector3.at(location.getX(), location.getY(), location.getZ())); + for (ProtectedRegion region : regions) { + if (region.getFlag(FLAG_MOVE) == StateFlag.State.DENY) + return false; + } + return true; + } + + @EventHandler public void onCraftSink(CraftSinkEvent event){ Craft pcraft = event.getCraft(); Player notifyP = event.getCraft().getNotificationPlayer(); @@ -92,7 +167,7 @@ public void onCraftSink(CraftSinkEvent event){ regions = regionManager.getApplicableRegions(BlockVector3.at(location.getX(), location.getY(), location.getZ())); } for (ProtectedRegion pr : regions.getRegions()){ - if (WorldguardUtils.pvpAllowed(pr)){ + if (WorldguardUtils.pvpAllowed(pr) || pr.getFlag(FLAG_SINK) == StateFlag.State.DENY){ region = pr; break; } @@ -101,11 +176,62 @@ public void onCraftSink(CraftSinkEvent event){ break; } } - if (region != null && Settings.WorldGuardBlockSinkOnPVPPerm && WorldguardUtils.pvpAllowed(region) && notifyP != null){ + if (region == null) { + return; + } + if (notifyP == null) { + return; + } + if (Settings.WorldGuardBlockSinkOnPVPPerm && !WorldguardUtils.pvpAllowed(region)){ notifyP.sendMessage(I18nSupport.getInternationalisedString("Player- Craft should sink but PVP is not allowed in this WorldGuard region")); event.setCancelled(true); } + if (region.getFlag(FLAG_SINK) == StateFlag.State.DENY) { + notifyP.sendMessage(I18nSupport.getInternationalisedString("WGCustomFlags - Sinking a craft is not allowed in this WorldGuard region")); + event.setCancelled(true); + } } } + @EventHandler + public void onCraftDetect(CraftDetectEvent event) { + Craft pcraft = event.getCraft(); + Player notifyP = pcraft.getNotificationPlayer(); + WorldGuardPlugin wgPlugin = Movecraft.getInstance().getWorldGuardPlugin(); + ProtectedRegion region = null; + RegionManager regionManager; + if (Settings.IsLegacy){ + regionManager = LegacyUtils.getRegionManager(wgPlugin, pcraft.getW()); + } else { + RegionContainer container = WorldGuard.getInstance().getPlatform().getRegionContainer(); + regionManager = container.get(BukkitAdapter.adapt(pcraft.getW())); + } + for (MovecraftLocation location : pcraft.getHitBox()){ + ApplicableRegionSet regions; + if (Settings.IsLegacy) + regions = LegacyUtils.getApplicableRegions(regionManager, location.toBukkit(pcraft.getW())); + else { + regions = regionManager.getApplicableRegions(BlockVector3.at(location.getX(), location.getY(), location.getZ())); + } + for (ProtectedRegion pr : regions.getRegions()){ + if (WorldguardUtils.pvpAllowed(pr) || pr.getFlag(FLAG_SINK) == StateFlag.State.DENY){ + region = pr; + break; + } + } + if (region != null){ + break; + } + } + if (region == null) { + return; + } + if (notifyP == null) { + return; + } + if (region.getFlag(FLAG_PILOT) == StateFlag.State.DENY) { + notifyP.sendMessage(I18nSupport.getInternationalisedString("WGCustomFlags - Detection Failed")); + event.setCancelled(true); + } + } } diff --git a/modules/api/src/main/java/net/countercraft/movecraft/craft/Craft.java b/modules/api/src/main/java/net/countercraft/movecraft/craft/Craft.java index 74843f6bb..6f5fa8c4a 100644 --- a/modules/api/src/main/java/net/countercraft/movecraft/craft/Craft.java +++ b/modules/api/src/main/java/net/countercraft/movecraft/craft/Craft.java @@ -101,6 +101,7 @@ public Craft(@NotNull CraftType type, @NotNull World world) { this.disabled = false; this.origPilotTime = System.currentTimeMillis(); numMoves = 0; + fluidLocations = new HashHitBox(); } public boolean isNotProcessing() { From e18afdf7ae7e8e009792a799f64a5df1a8d2b3a6 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Fri, 17 Apr 2020 12:43:38 +0200 Subject: [PATCH 144/304] Fixed problem with WorldGuardCompatManager --- .../src/main/java/net/countercraft/movecraft/Movecraft.java | 3 ++- .../movecraft/worldguard/WorldGuardCompatManager.java | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java index 2bd4e4249..cb184e591 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java @@ -325,6 +325,7 @@ public void onEnable() { Settings.WorldGuardBlockMoveOnBuildPerm = getConfig().getBoolean("WorldGuardBlockMoveOnBuildPerm", false); Settings.WorldGuardBlockSinkOnPVPPerm = getConfig().getBoolean("WorldGuardBlockSinkOnPVPPerm", false); logger.log(Level.INFO, "Settings: WorldGuardBlockMoveOnBuildPerm - {0}, WorldGuardBlockSinkOnPVPPerm - {1}", new Object[]{Settings.WorldGuardBlockMoveOnBuildPerm, Settings.WorldGuardBlockSinkOnPVPPerm}); + getServer().getPluginManager().registerEvents(new WorldGuardCompatManager(), this); } @@ -560,7 +561,7 @@ public void onLoad() { Plugin wGPlugin = getServer().getPluginManager().getPlugin("WorldGuard"); if (wGPlugin instanceof WorldGuardPlugin) { worldGuardPlugin = (WorldGuardPlugin) wGPlugin; - getServer().getPluginManager().registerEvents(new WorldGuardCompatManager(), this); + WorldGuardCompatManager.registerFlags(); } } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/worldguard/WorldGuardCompatManager.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/worldguard/WorldGuardCompatManager.java index 725380458..cd572a340 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/worldguard/WorldGuardCompatManager.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/worldguard/WorldGuardCompatManager.java @@ -38,7 +38,7 @@ public class WorldGuardCompatManager implements Listener { public static StateFlag FLAG_ROTATE = new StateFlag("movecraft-rotate", true); public static StateFlag FLAG_SINK = new StateFlag("movecraft-sink", true); - public WorldGuardCompatManager() { + public static void registerFlags() { FlagRegistry flags; if (Settings.IsLegacy) { try { From 670ce8c0ae84943b54adecaea8f138e7674b159c Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Wed, 22 Apr 2020 13:56:34 +0200 Subject: [PATCH 145/304] Made it so that entities riding another entity can be teleported. This fixes #35 --- .../mapUpdater/update/CraftRotateCommand.java | 35 +++++++++++--- .../update/CraftTranslateCommand.java | 21 +++++++-- .../update/EntityUpdateCommand.java | 8 ++-- .../movecraft/utils/TeleportUtils.java | 47 +++++++++++++++++-- 4 files changed, 93 insertions(+), 18 deletions(-) diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftRotateCommand.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftRotateCommand.java index 65c481c3f..cbb9b4719 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftRotateCommand.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftRotateCommand.java @@ -81,24 +81,47 @@ public void doUpdate() { passthroughBlocks.add(Material.PEONY); } - } else if (craft.getType().getMoveEntities()) { + } else if (craft.getType().getMoveEntities() && !craft.getSinking()) { Location tOP = originLocation.toBukkit(craft.getW()); tOP.setX(tOP.getBlockX() + 0.5); tOP.setZ(tOP.getBlockZ() + 0.5); Location midpoint = originalLocations.getMidPoint().toBukkit(craft.getW()); + Entity vehicle; + Entity playerVehicle = null; for(Entity entity : craft.getW().getNearbyEntities(midpoint, originalLocations.getXLength()/2.0 + 1, originalLocations.getYLength()/2.0 + 2, originalLocations.getZLength()/2.0 + 1)){ - // Player is onboard this craft Location adjustedPLoc = entity.getLocation().subtract(tOP); + if (entity.getVehicle() != null) { + adjustedPLoc = entity.getVehicle().getLocation().subtract(tOP); + } double[] rotatedCoords = MathUtils.rotateVecNoRound(rotation, adjustedPLoc.getX(), adjustedPLoc.getZ()); float newYaw = rotation == Rotation.CLOCKWISE ? 90F : -90F; - if ((entity.getType() != EntityType.PLAYER && craft.getType().getOnlyMovePlayers()) || craft.getSinking()) { - continue; + vehicle = entity.getVehicle(); + + if (entity.getType() == EntityType.PLAYER) { + + if (playerVehicle != null && playerVehicle.getPassengers().contains(entity)) { + continue; + } + playerVehicle = entity.getVehicle(); + toRotate.add(new EntityUpdateCommand(entity, rotatedCoords[0] + tOP.getX() - entity.getLocation().getX(), 0, rotatedCoords[1] + tOP.getZ() - entity.getLocation().getZ(), newYaw, 0)); + } else if (!craft.getType().getOnlyMovePlayers() || entity.getType() == EntityType.PRIMED_TNT) { + boolean isPlayerVehicle = false; + for (Entity pass : entity.getPassengers()) { + if (pass.getType() != EntityType.PLAYER) { + continue; + } + isPlayerVehicle = true; + break; + } + if (vehicle != null && vehicle.getPassengers().contains(entity) || entity == playerVehicle || isPlayerVehicle) { + continue; + } + toRotate.add(new EntityUpdateCommand(entity, rotatedCoords[0] + tOP.getX() - entity.getLocation().getX(), 0, rotatedCoords[1] + tOP.getZ() - entity.getLocation().getZ(), newYaw, 0)); } - EntityUpdateCommand eUp = new EntityUpdateCommand(entity, rotatedCoords[0] + tOP.getX() - entity.getLocation().getX(), 0, rotatedCoords[1] + tOP.getZ() - entity.getLocation().getZ(), newYaw, 0); - toRotate.add(eUp); + } } if (!passthroughBlocks.isEmpty()) { diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftTranslateCommand.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftTranslateCommand.java index bb1090396..0567cdef6 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftTranslateCommand.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftTranslateCommand.java @@ -76,17 +76,32 @@ public void doUpdate() { passthroughBlocks.add(Material.BUBBLE_COLUMN); } - } else if (craft.getType().getMoveEntities()){ + } else if (craft.getType().getMoveEntities() && !craft.getSinking()){ final Location midpoint = craft.getHitBox().getMidPoint().subtract(displacement).toBukkit(craft.getW()).add(.5,.5,.5); final Collection entities = craft.getW().getNearbyEntities(midpoint, craft.getHitBox().getXLength() / 2.0 + 1, craft.getHitBox().getYLength() / 2.0 + 2, craft.getHitBox().getZLength() / 2.0 + 1); - + Entity vehicle; + Entity playerVehicle = null; for (Entity entity : entities){ + vehicle = entity.getVehicle(); if (entity.getType() == EntityType.PLAYER) { - if(craft.getSinking()){ + + if (playerVehicle != null && playerVehicle.getPassengers().contains(entity)) { continue; } + playerVehicle = entity.getVehicle(); toMove.add(new EntityUpdateCommand(entity, displacement.getX(), displacement.getY(), displacement.getZ(), 0, 0)); } else if (!craft.getType().getOnlyMovePlayers() || entity.getType() == EntityType.PRIMED_TNT) { + boolean isPlayerVehicle = false; + for (Entity pass : entity.getPassengers()) { + if (pass.getType() != EntityType.PLAYER) { + continue; + } + isPlayerVehicle = true; + break; + } + if (vehicle != null && vehicle.getPassengers().contains(entity) || entity == playerVehicle || isPlayerVehicle) { + continue; + } toMove.add(new EntityUpdateCommand(entity, displacement.getX(), displacement.getY(), displacement.getZ(), 0, 0)); } } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/EntityUpdateCommand.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/EntityUpdateCommand.java index c6e44f963..ed761302e 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/EntityUpdateCommand.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/EntityUpdateCommand.java @@ -51,13 +51,13 @@ public final Entity getEntity() { @Override public void doUpdate() { - final Location entityLoc = entity.getLocation(); - if (!(entity instanceof Player) || yaw > .01 || pitch > .01 || yaw < -.01 || pitch < -.01 ) { - entity.teleport(new Location(entity.getWorld(), x + entityLoc.getX(),y + entityLoc.getY(),z + entityLoc.getZ(),yaw + entityLoc.getYaw(),pitch + entityLoc.getPitch())); + final Location entityLoc = entity.getVehicle() != null ? entity.getVehicle().getLocation() : entity.getLocation(); + if (!(entity instanceof Player)) { + TeleportUtils.teleportEntity(entity, new Location(entity.getWorld(), entityLoc.getX() + x, entityLoc.getY() + y, entityLoc.getZ() + z,yaw + entityLoc.getYaw(),pitch + entityLoc.getPitch())); return; } //Movecraft.getInstance().getWorldHandler().addPlayerLocation((Player) entity,x,y,z,yaw,pitch); - TeleportUtils.teleport((Player) entity, new Location(entity.getWorld(), entityLoc.getX() + x, entityLoc.getY() + y, entityLoc.getZ() + z)); + TeleportUtils.teleport((Player) entity, new Location(entity.getWorld(), entityLoc.getX() + x, entityLoc.getY() + y, entityLoc.getZ() + z), yaw); diff --git a/modules/api/src/main/java/net/countercraft/movecraft/utils/TeleportUtils.java b/modules/api/src/main/java/net/countercraft/movecraft/utils/TeleportUtils.java index 5dbb6f510..0598de35b 100644 --- a/modules/api/src/main/java/net/countercraft/movecraft/utils/TeleportUtils.java +++ b/modules/api/src/main/java/net/countercraft/movecraft/utils/TeleportUtils.java @@ -3,6 +3,7 @@ import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.entity.Entity; +import org.bukkit.entity.EntityType; import org.bukkit.entity.Player; import java.lang.reflect.Constructor; @@ -21,11 +22,13 @@ public class TeleportUtils { private static Set teleportFlags; private static Constructor packetConstructor; + private static Constructor vehiclePacketConstructor; private static Constructor vec3D; private static Method position; private static Method closeInventory; private static Method sendMethod; + private static Method getBukkitEntity; private static Field connectionField; private static Field justTeleportedField; @@ -48,12 +51,14 @@ public class TeleportUtils { Class entityHuman = getNmsClass("EntityHuman"); Class connectionClass = getNmsClass("PlayerConnection"); Class packetClass = getNmsClass("PacketPlayOutPosition"); + Class vehiclePacket = getNmsClass("PacketPlayOutVehicleMove"); Class vecClass = getNmsClass("Vec3D"); try { sendMethod = connectionClass.getMethod("sendPacket", packet); position = entity.getDeclaredMethod("setLocation", Double.TYPE, Double.TYPE, Double.TYPE, Float.TYPE, Float.TYPE); closeInventory = entityPlayer.getDeclaredMethod("closeInventory"); + getBukkitEntity = entity.getDeclaredMethod("getBukkitEntity"); yaw = getField(entity, "yaw"); pitch = getField(entity, "pitch"); @@ -64,6 +69,8 @@ public class TeleportUtils { packetConstructor = packetClass.getConstructor(Double.TYPE, Double.TYPE, Double.TYPE, Float.TYPE, Float.TYPE, Set.class, Integer.TYPE); vec3D = vecClass.getConstructor(Double.TYPE, Double.TYPE, Double.TYPE); + vehiclePacketConstructor = vehiclePacket.getConstructor(entity); + Object[] enumObjects = getNmsClass("PacketPlayOutPosition$EnumPlayerTeleportFlags").getEnumConstants(); teleportFlags = Collections.unmodifiableSet(new HashSet<>(Arrays.asList(enumObjects[4], enumObjects[3]))); @@ -86,15 +93,33 @@ private static Field getField(Class clazz, String name) throws NoSuchFieldExc return field; } - public static void teleport(Player player, Location location) { + public static void teleportEntity(Entity entity, Location location) { double x = location.getX(); double y = location.getY(); double z = location.getZ(); - Object handle = getHandle(player); + Entity vehicle = entity.getVehicle(); + Object handle = getHandle(vehicle == null ? entity : vehicle); + try { + position.invoke(handle, x,y,z, location.getYaw(), location.getPitch()); + } catch (Exception e) { + e.printStackTrace(); + } + } + + public static void teleport(Player player, Location location, float yawChange) { + double x = location.getX(); + double y = location.getY(); + double z = location.getZ(); + Entity vehicle = player.getVehicle(); + Object handle = getHandle(vehicle == null ? player : vehicle); + Object pHandle = getHandle(player); + try { - if(activeContainer.get(handle) != defaultContainer.get(handle)) closeInventory.invoke(handle); + if(activeContainer.get(pHandle) != defaultContainer.get(pHandle)) closeInventory.invoke(pHandle); + Bukkit.broadcastMessage(String.valueOf(yaw.getFloat(handle))); position.invoke(handle, x,y,z, yaw.get(handle), pitch.get(handle)); - Object connection = connectionField.get(handle); + yaw.set(handle, yaw.getFloat(handle) + yawChange); + Object connection = connectionField.get(pHandle); justTeleportedField.set(connection, true); teleportPosField.set(connection, vec3D.newInstance(x, y, z)); lastPosXField.set(connection, x); @@ -105,8 +130,20 @@ public static void teleport(Player player, Location location) { teleportAwaitField.set(connection, teleportAwait); AField.set(connection, eField.get(connection)); - Object packet = packetConstructor.newInstance(x, y, z, 0, 0, teleportFlags, teleportAwait); + Object packet = packetConstructor.newInstance(x, y, z, yawChange, 0, teleportFlags, teleportAwait); sendPacket(packet, player); + if (vehicle == null) + return; + Object vehiclePacket = vehiclePacketConstructor.newInstance(handle); + sendPacket(vehiclePacket, player); + for (Entity pass : vehicle.getPassengers()) { + if (pass.getType() != EntityType.PLAYER || pass.equals(player)) { + continue; + } + Player p = (Player) pass; + sendPacket(packet, p); + sendPacket(vehiclePacket, p); + } } catch (Exception e) { e.printStackTrace(); } From 11ac82fc73777e498186c15e69c9026207ce4d3f Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Wed, 22 Apr 2020 14:04:56 +0200 Subject: [PATCH 146/304] Fixed a potential bypass of onlyMovePlayers flag --- .../movecraft/mapUpdater/update/CraftRotateCommand.java | 4 ++++ .../movecraft/mapUpdater/update/CraftTranslateCommand.java | 6 +++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftRotateCommand.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftRotateCommand.java index cbb9b4719..3f802247a 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftRotateCommand.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftRotateCommand.java @@ -106,6 +106,10 @@ public void doUpdate() { continue; } playerVehicle = entity.getVehicle(); + //If player has a vehicle and craft should only move players, eject its passengers + if (playerVehicle != null && craft.getType().getOnlyMovePlayers()) { + playerVehicle.eject(); + } toRotate.add(new EntityUpdateCommand(entity, rotatedCoords[0] + tOP.getX() - entity.getLocation().getX(), 0, rotatedCoords[1] + tOP.getZ() - entity.getLocation().getZ(), newYaw, 0)); } else if (!craft.getType().getOnlyMovePlayers() || entity.getType() == EntityType.PRIMED_TNT) { boolean isPlayerVehicle = false; diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftTranslateCommand.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftTranslateCommand.java index 0567cdef6..1d1f53707 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftTranslateCommand.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftTranslateCommand.java @@ -84,11 +84,15 @@ public void doUpdate() { for (Entity entity : entities){ vehicle = entity.getVehicle(); if (entity.getType() == EntityType.PLAYER) { - + //Only teleport one player if more players ride the same vehicle if (playerVehicle != null && playerVehicle.getPassengers().contains(entity)) { continue; } playerVehicle = entity.getVehicle(); + //If player has a vehicle and craft should only move players, eject its passengers + if (playerVehicle != null && craft.getType().getOnlyMovePlayers()) { + playerVehicle.eject(); + } toMove.add(new EntityUpdateCommand(entity, displacement.getX(), displacement.getY(), displacement.getZ(), 0, 0)); } else if (!craft.getType().getOnlyMovePlayers() || entity.getType() == EntityType.PRIMED_TNT) { boolean isPlayerVehicle = false; From f552ccf875adffe2f1ac49f7a8f8cea16a426ad6 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Wed, 22 Apr 2020 14:12:03 +0200 Subject: [PATCH 147/304] Further optimized waterlog code --- .../movecraft/utils/WaterlogUtils.java | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/WaterlogUtils.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/WaterlogUtils.java index a545f995e..4ebbce595 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/WaterlogUtils.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/WaterlogUtils.java @@ -8,6 +8,7 @@ import org.bukkit.block.data.Bisected; import org.bukkit.block.data.Waterlogged; import org.bukkit.block.data.type.Slab; +import org.bukkit.block.data.type.Stairs; import org.bukkit.block.data.type.TrapDoor; import java.util.AbstractMap; @@ -35,7 +36,7 @@ public static void waterlogBlocksOnCraft(Craft craft, HitBox interior) { break; } final Material phaseBlock = craft.getPhaseBlocks().getOrDefault(ml, DEFAULT_PHASE_BLOCK).getKey(); - if (!exteriorBlock || phaseBlock != Material.WATER || !adjacentToWater(ml.toBukkit(craft.getW()))) { + if (!exteriorBlock || phaseBlock != Material.WATER) { waterlog = false; } else if (wLog instanceof TrapDoor) { TrapDoor td = (TrapDoor) wLog; @@ -51,6 +52,17 @@ public static void waterlogBlocksOnCraft(Craft craft, HitBox interior) { } else if (s.getType() == Slab.Type.BOTTOM && (interior.contains(ml.translate(0, 1, 0)) || craft.getHitBox().contains(ml.translate(0, 1, 0)))) { waterlog = false; } + } else if (wLog instanceof Stairs) { + Stairs s = (Stairs) wLog; + MovecraftLocation facingLoc = MathUtils.bukkit2MovecraftLoc(b.getRelative(s.getFacing()).getLocation()); + if (interior.contains(facingLoc) || craft.getHitBox().contains(facingLoc)) { + waterlog = false; + } + if (s.getHalf() == Bisected.Half.TOP && (interior.contains(ml.translate(0, -1, 0)) || craft.getHitBox().contains(ml.translate(0, -1, 0)))) { + waterlog = false; + } else if (s.getHalf() == Bisected.Half.BOTTOM && (interior.contains(ml.translate(0, 1, 0)) || craft.getHitBox().contains(ml.translate(0, 1, 0)))) { + waterlog = false; + } } wLog.setWaterlogged(waterlog); b.setBlockData(wLog); From 331553d66a2084b4a1214ecc8cb626efc40bc837 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Wed, 22 Apr 2020 14:31:24 +0200 Subject: [PATCH 148/304] Removed teleportation debug message, added possibility to edit on-board inventories while in motion --- .../net/countercraft/movecraft/utils/WaterlogUtils.java | 9 +++++---- .../net/countercraft/movecraft/utils/TeleportUtils.java | 3 +-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/WaterlogUtils.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/WaterlogUtils.java index 4ebbce595..8f826377e 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/WaterlogUtils.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/WaterlogUtils.java @@ -54,15 +54,16 @@ public static void waterlogBlocksOnCraft(Craft craft, HitBox interior) { } } else if (wLog instanceof Stairs) { Stairs s = (Stairs) wLog; - MovecraftLocation facingLoc = MathUtils.bukkit2MovecraftLoc(b.getRelative(s.getFacing()).getLocation()); - if (interior.contains(facingLoc) || craft.getHitBox().contains(facingLoc)) { - waterlog = false; - } + MovecraftLocation facingLoc = MathUtils.bukkit2MovecraftLoc(b.getRelative(s.getFacing().getOppositeFace()).getLocation()); + if (s.getHalf() == Bisected.Half.TOP && (interior.contains(ml.translate(0, -1, 0)) || craft.getHitBox().contains(ml.translate(0, -1, 0)))) { waterlog = false; } else if (s.getHalf() == Bisected.Half.BOTTOM && (interior.contains(ml.translate(0, 1, 0)) || craft.getHitBox().contains(ml.translate(0, 1, 0)))) { waterlog = false; } + if (interior.contains(facingLoc) || craft.getHitBox().contains(facingLoc)) { + waterlog = false; + } } wLog.setWaterlogged(waterlog); b.setBlockData(wLog); diff --git a/modules/api/src/main/java/net/countercraft/movecraft/utils/TeleportUtils.java b/modules/api/src/main/java/net/countercraft/movecraft/utils/TeleportUtils.java index 0598de35b..f475370d3 100644 --- a/modules/api/src/main/java/net/countercraft/movecraft/utils/TeleportUtils.java +++ b/modules/api/src/main/java/net/countercraft/movecraft/utils/TeleportUtils.java @@ -115,8 +115,7 @@ public static void teleport(Player player, Location location, float yawChange) { Object pHandle = getHandle(player); try { - if(activeContainer.get(pHandle) != defaultContainer.get(pHandle)) closeInventory.invoke(pHandle); - Bukkit.broadcastMessage(String.valueOf(yaw.getFloat(handle))); + //if(activeContainer.get(pHandle) != defaultContainer.get(pHandle)) closeInventory.invoke(pHandle); position.invoke(handle, x,y,z, yaw.get(handle), pitch.get(handle)); yaw.set(handle, yaw.getFloat(handle) + yawChange); Object connection = connectionField.get(pHandle); From 7134903917f8a1093f30815e1a26fe862499d425 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Wed, 22 Apr 2020 14:35:14 +0200 Subject: [PATCH 149/304] bump version --- modules/Movecraft/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/Movecraft/pom.xml b/modules/Movecraft/pom.xml index 588b91bee..acc97d542 100644 --- a/modules/Movecraft/pom.xml +++ b/modules/Movecraft/pom.xml @@ -10,7 +10,7 @@ UTF-8 - 7.0.0_for_1.8.8-1.15.2_beta_17 + 7.0.0_for_1.8.8-1.15.2_beta_18 From 2ae44cecd57a8d093d423a81f13f87a726885396 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Thu, 23 Apr 2020 01:45:37 +0200 Subject: [PATCH 150/304] Fixes #38 --- .../countercraft/movecraft/utils/WaterlogUtils.java | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/WaterlogUtils.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/WaterlogUtils.java index 8f826377e..4a8adf825 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/WaterlogUtils.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/WaterlogUtils.java @@ -14,14 +14,15 @@ import java.util.AbstractMap; public class WaterlogUtils { - private static AbstractMap.SimpleImmutableEntry DEFAULT_PHASE_BLOCK = new AbstractMap.SimpleImmutableEntry<>(Material.WATER, 0); + private static AbstractMap.SimpleImmutableEntry DEFAULT_PHASE_BLOCK = new AbstractMap.SimpleImmutableEntry<>(Material.AIR, 0); private WaterlogUtils(){ } public static void waterlogBlocksOnCraft(Craft craft, HitBox interior) { for (MovecraftLocation ml : craft.getHitBox()) { - boolean waterlog = true; + final Material phaseBlock = craft.getPhaseBlocks().getOrDefault(ml, DEFAULT_PHASE_BLOCK).getKey(); + boolean waterlog = phaseBlock == Material.WATER; Block b = ml.toBukkit(craft.getW()).getBlock(); if (!(b.getBlockData() instanceof Waterlogged)) { continue; @@ -35,10 +36,11 @@ public static void waterlogBlocksOnCraft(Craft craft, HitBox interior) { exteriorBlock = true; break; } - final Material phaseBlock = craft.getPhaseBlocks().getOrDefault(ml, DEFAULT_PHASE_BLOCK).getKey(); - if (!exteriorBlock || phaseBlock != Material.WATER) { + + if (!exteriorBlock) { waterlog = false; - } else if (wLog instanceof TrapDoor) { + } + if (wLog instanceof TrapDoor) { TrapDoor td = (TrapDoor) wLog; if (td.getHalf() == Bisected.Half.TOP && (interior.contains(ml.translate(0, -1, 0)) || craft.getHitBox().contains(ml.translate(0, -1, 0)))) { waterlog = false; From 9ddb36f19c54a1e3332eb5b73eadcbafff4f99d7 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Thu, 23 Apr 2020 22:54:34 +0200 Subject: [PATCH 151/304] Fixed custom flags --- modules/Movecraft/pom.xml | 2 +- .../net/countercraft/movecraft/Movecraft.java | 15 ++++++++------- .../worldguard/WorldGuardCompatManager.java | 1 + 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/modules/Movecraft/pom.xml b/modules/Movecraft/pom.xml index acc97d542..27ad149d3 100644 --- a/modules/Movecraft/pom.xml +++ b/modules/Movecraft/pom.xml @@ -10,7 +10,7 @@ UTF-8 - 7.0.0_for_1.8.8-1.15.2_beta_18 + 7.0.0_for_1.8.8-1.15.2_beta_19 diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java index cb184e591..f37917fd3 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java @@ -93,12 +93,6 @@ public void onEnable() { saveLocaleFiles(); String packageName = this.getServer().getClass().getPackage().getName(); String version = packageName.substring(packageName.lastIndexOf('.') + 1); - String[] parts = version.split("_"); - int versionNumber = Integer.valueOf(parts[1]); - //Check if the server is 1.12 and lower or 1.13 and higher - Settings.IsPre1_9 = versionNumber < 9; - Settings.IsLegacy = versionNumber <= 12; - Settings.is1_14 = versionNumber >= 14; // Read in config if (!Settings.IsLegacy) { this.saveDefaultConfig(); @@ -554,7 +548,14 @@ public void onEnable() { @Override public void onLoad() { - super.onLoad(); + String packageName = this.getServer().getClass().getPackage().getName(); + String version = packageName.substring(packageName.lastIndexOf('.') + 1); + String[] parts = version.split("_"); + int versionNumber = Integer.valueOf(parts[1]); + //Check if the server is 1.12 and lower or 1.13 and higher + Settings.IsPre1_9 = versionNumber < 9; + Settings.IsLegacy = versionNumber <= 12; + Settings.is1_14 = versionNumber >= 14; instance = this; logger = getLogger(); //load up WorldGuard if it's present diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/worldguard/WorldGuardCompatManager.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/worldguard/WorldGuardCompatManager.java index cd572a340..21aad4a56 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/worldguard/WorldGuardCompatManager.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/worldguard/WorldGuardCompatManager.java @@ -51,6 +51,7 @@ public static void registerFlags() { } else { flags = WorldGuard.getInstance().getFlagRegistry(); } + Movecraft.getInstance().getLogger().info("Registered custom flags"); flags.register(FLAG_MOVE); flags.register(FLAG_PILOT); flags.register(FLAG_ROTATE); From 2cbcf66b004ced34df682e9407864f846935acee Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Sat, 25 Apr 2020 02:54:27 +0200 Subject: [PATCH 152/304] Fixed siege --- .../net/countercraft/movecraft/Movecraft.java | 18 ++++++++++--- .../movecraft/commands/SiegeCommand.java | 20 +++++++++++--- .../movecraft/utils/WorldguardUtils.java | 27 ++++++++++++------- .../movecraft/warfare/siege/Siege.java | 21 +++++++++------ .../warfare/siege/SiegePreparationTask.java | 1 + .../warfare/siege/SiegeProgressTask.java | 12 +++------ .../localisation/movecraftlang_en.properties | 5 ++++ 7 files changed, 70 insertions(+), 34 deletions(-) diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java index f37917fd3..9aca62bb0 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java @@ -38,6 +38,7 @@ import net.countercraft.movecraft.utils.LegacyUtils; import net.countercraft.movecraft.utils.TownyUtils; import net.countercraft.movecraft.utils.UpdateManager; +import net.countercraft.movecraft.utils.WorldguardUtils; import net.countercraft.movecraft.warfare.assault.AssaultManager; import net.countercraft.movecraft.warfare.siege.Siege; import net.countercraft.movecraft.warfare.siege.SiegeManager; @@ -462,10 +463,20 @@ public void onEnable() { List sieges = siegeManager.getSieges(); for (Map.Entry> entry : siegesMap.entrySet()) { Map siegeMap = (Map) entry.getValue(); + final String regionToControl = (String) siegeMap.get("RegionToControl"); + if (!WorldguardUtils.regionExists(regionToControl)) { + logger.severe(String.format(I18nSupport.getInternationalisedString("Startup - Siege Invalid region name"), "RegionToControl", regionToControl)); + continue; + } + final String siegeRegion = (String) siegeMap.get("SiegeRegion"); + if (!WorldguardUtils.regionExists(siegeRegion)) { + logger.severe(String.format(I18nSupport.getInternationalisedString("Startup - Siege Invalid region name"), "SiegeRegion", regionToControl)); + continue; + } sieges.add(new Siege( entry.getKey(), - (String) siegeMap.get("RegionToControl"), - (String) siegeMap.get("SiegeRegion"), + regionToControl, + siegeRegion, (Integer) siegeMap.get("ScheduleStart"), (Integer) siegeMap.get("ScheduleEnd"), (Integer) siegeMap.getOrDefault("DelayBeforeStart", 0), @@ -477,7 +488,8 @@ public void onEnable() { (List) siegeMap.getOrDefault("CraftsToWin", Collections.emptyList()), (List) siegeMap.getOrDefault("SiegeCommandsOnStart", Collections.emptyList()), (List) siegeMap.getOrDefault("SiegeCommandsOnWin", Collections.emptyList()), - (List) siegeMap.getOrDefault("SiegeCommandsOnLose", Collections.emptyList()))); + (List) siegeMap.getOrDefault("SiegeCommandsOnLose", Collections.emptyList()), + (Integer) siegeMap.getOrDefault("Cooldown", 0))); } logger.log(Level.INFO, "Siege configuration loaded."); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/SiegeCommand.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/SiegeCommand.java index 8fb55a401..f0cf50a43 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/SiegeCommand.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/SiegeCommand.java @@ -160,7 +160,11 @@ private boolean beginCommand(CommandSender commandSender){ return true; } if(!siege.getCraftsToWin().contains(siegeCraft.getType().getCraftName())) { - player.sendMessage(MOVECRAFT_COMMAND_PREFIX + I18nSupport.getInternationalisedString("You must be piloting a craft that can siege!")); + player.sendMessage(MOVECRAFT_COMMAND_PREFIX + I18nSupport.getInternationalisedString("Siege - Must pilot siege craft"));// + return true; + } + if (siege.getCooldown() > ((System.currentTimeMillis() - siege.getStartTime()) / 1000) + siege.getDuration()) { + player.sendMessage(MOVECRAFT_COMMAND_PREFIX + I18nSupport.getInternationalisedString("Siege - Siege has recently taken place")); return true; } MovecraftLocation mid = siegeCraft.getHitBox().getMidPoint(); @@ -171,7 +175,7 @@ private boolean beginCommand(CommandSender commandSender){ siegeRegion = WorldGuard.getInstance().getPlatform().getRegionContainer().get(BukkitAdapter.adapt(player.getWorld())).getRegion(siege.getAttackRegion()); } if(!siegeRegion.contains(mid.getX(), mid.getY(), mid.getZ())) { - player.sendMessage(MOVECRAFT_COMMAND_PREFIX + I18nSupport.getInternationalisedString("You must be piloting a craft in the siege region!")); + player.sendMessage(MOVECRAFT_COMMAND_PREFIX + I18nSupport.getInternationalisedString("Siege - Must pilot siege craft in region")); return true; } @@ -252,12 +256,16 @@ private String militaryTimeIntToString(int militaryTime) { } private String secondsIntToString(int seconds) { - return String.format("%02d", seconds / 60) + ":" + String.format("%02d",seconds % 60); + int minutes = seconds / 60; + int hours = minutes / 60; + int days = hours / 24; + return (days > 0 ? String.format("%d days ", days) : "") + String.format("%02d", hours) + ":" + String.format("%02d", minutes) + ":" + String.format("%02d",seconds % 60); } private boolean abortCommand(CommandSender sender){ if (!(sender instanceof Player)){ sender.sendMessage(MOVECRAFT_COMMAND_PREFIX + "you need to be a player to abort a siege"); + return true; } List sieges = Movecraft.getInstance().getSiegeManager().getSieges(); UUID playerID = ((Player)sender).getUniqueId(); @@ -281,6 +289,7 @@ private boolean abortCommand(CommandSender sender){ if (confirm){ Bukkit.broadcastMessage(String.format("The siege of %s has been aborted!", activeSiege.getName())); activeSiege.setStage(SiegeStage.INACTIVE); + activeSiege.getProgressBar().setVisible(false); if (activeSiege.getCommandsOnLose() != null) for (String command : activeSiege.getCommandsOnLose()) { Bukkit.getServer().dispatchCommand(Bukkit.getServer().getConsoleSender(), command @@ -345,7 +354,7 @@ private String daysOfWeekString(@NotNull List days) { private void displayInfo(@NotNull CommandSender sender, @NotNull Siege siege) { sender.sendMessage("" + ChatColor.YELLOW + ChatColor.BOLD + "----- " + ChatColor.RESET + ChatColor.GOLD + siege.getName() + ChatColor.YELLOW + ChatColor.BOLD +" -----"); - ChatColor cost, start, end; + ChatColor cost, start, end, cooldown; if(sender instanceof Player) { cost = Movecraft.getInstance().getEconomy().has((Player) sender, siege.getCost()) ? ChatColor.GREEN : ChatColor.RED; @@ -357,12 +366,15 @@ private void displayInfo(@NotNull CommandSender sender, @NotNull Siege siege) { start = siege.getScheduleStart() < getMilitaryTime() ? ChatColor.GREEN : ChatColor.RED; end = siege.getScheduleEnd() > getMilitaryTime() ? ChatColor.GREEN : ChatColor.RED; + cooldown = siege.getCooldown() > (System.currentTimeMillis() - siege.getStartTime()) / 1000 ? ChatColor.RED : ChatColor.GREEN; + sender.sendMessage(I18nSupport.getInternationalisedString("Siege - Siege Cost") + cost + currencyFormat.format(siege.getCost())); sender.sendMessage(I18nSupport.getInternationalisedString("Siege - Daily Income") + ChatColor.WHITE + currencyFormat.format(siege.getDailyIncome())); sender.sendMessage(I18nSupport.getInternationalisedString("Siege - Day of Week") + daysOfWeekString(siege.getDaysOfWeek())); sender.sendMessage(I18nSupport.getInternationalisedString("Siege - Start Time") + start + militaryTimeIntToString(siege.getScheduleStart()) + " UTC"); sender.sendMessage(I18nSupport.getInternationalisedString("Siege - End Time") + end + militaryTimeIntToString(siege.getScheduleEnd()) + " " + Settings.SiegeTimeZone); sender.sendMessage(I18nSupport.getInternationalisedString("Siege - Duration") + ChatColor.WHITE + secondsIntToString(siege.getDuration())); + sender.sendMessage(I18nSupport.getInternationalisedString("Siege - Cooldown") + cooldown + secondsIntToString(siege.getCooldown())); } private String formatMinutes(int seconds) { diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/WorldguardUtils.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/WorldguardUtils.java index 1dc147e62..5e250e32c 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/WorldguardUtils.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/WorldguardUtils.java @@ -51,6 +51,17 @@ public static String getRegionOwnerList(ProtectedRegion tRegion) { } return output.toString(); } + public static boolean regionExists(String regionName) { + for (World bukkitWorld : Bukkit.getWorlds()) { + final RegionManager rm = getRegionManager(bukkitWorld); + if (rm.hasRegion(regionName)) { + return true; + } + + } + return false; + } + public static boolean pvpAllowed(ProtectedRegion region){ if (Settings.IsLegacy) { return region.getFlag(DefaultFlag.PVP) == StateFlag.State.ALLOW; @@ -97,28 +108,22 @@ public static boolean allowFireSpread(Location loc){ } return true; } + public static ApplicableRegionSet getRegionsAt(Location loc){ World world = loc.getWorld(); ApplicableRegionSet regions; + RegionManager rm = getRegionManager(world); if (Settings.IsLegacy) { - RegionManager rm = LegacyUtils.getRegionManager(Movecraft.getInstance().getWorldGuardPlugin(), world); regions = LegacyUtils.getApplicableRegions(rm, loc); } else { - RegionQuery query = WorldGuard.getInstance().getPlatform().getRegionContainer().createQuery(); - com.sk89q.worldedit.world.World weWorld = new BukkitWorld(world); - com.sk89q.worldedit.util.Location wgLoc = new com.sk89q.worldedit.util.Location(weWorld, loc.getX(), loc.getY(), loc.getZ()); - regions = query.getApplicableRegions(wgLoc); + regions = rm.getApplicableRegions(BlockVector3.at(loc.getX(), loc.getY(), loc.getZ())); } return regions; } public static RegionManager getRegionManager(World world){ RegionManager manager; if (Settings.IsLegacy){ - try { - manager = LegacyUtils.getRegionManager(Movecraft.getInstance().getWorldGuardPlugin(), world); - } catch (Throwable t){ - manager = null; - } + manager = LegacyUtils.getRegionManager(Movecraft.getInstance().getWorldGuardPlugin(), world); } else { com.sk89q.worldedit.world.World weWorld = new BukkitWorld(world); manager = WorldGuard.getInstance().getPlatform().getRegionContainer().get(weWorld); @@ -129,4 +134,6 @@ public Flag flag(String string){ return null; } + + } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/siege/Siege.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/siege/Siege.java index 810fb8bfa..793d9d336 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/siege/Siege.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/siege/Siege.java @@ -10,13 +10,13 @@ public class Siege { @NotNull private final List daysOfWeek; @NotNull private final List craftsToWin, commandsOnStart, commandsOnLose, commandsOnWin; - private final int scheduleStart, scheduleEnd, delayBeforeStart, duration, dailyIncome, cost; + private final int scheduleStart, scheduleEnd, delayBeforeStart, duration, dailyIncome, cost, cooldown; @NotNull private final String attackRegion, captureRegion, name; @NotNull private final AtomicReference stage; private long startTime; private int lastUpdate; private long lastPayout; - private boolean progressTaskStarted; + private boolean justCommenced; private final boolean doubleCostPerOwnedSiegeRegion; private UUID playerUUID; private BossBar progressBar; @@ -26,8 +26,8 @@ public Siege( int scheduleStart, int scheduleEnd, int delayBeforeStart, int duration, int dailyIncome, int cost, boolean doubleCostPerOwnedSiegeRegion, @NotNull List daysOfWeek, - @NotNull List craftsToWin, @NotNull List commandsOnStart, @NotNull List commandsOnWin, @NotNull List commandsOnLose - ) { + @NotNull List craftsToWin, @NotNull List commandsOnStart, @NotNull List commandsOnWin, @NotNull List commandsOnLose, + int cooldown) { this.commandsOnWin = commandsOnWin; this.commandsOnLose = commandsOnLose; this.craftsToWin = craftsToWin; @@ -43,6 +43,7 @@ public Siege( this.captureRegion = captureRegion; this.name = name; this.commandsOnStart = commandsOnStart; + this.cooldown = cooldown; startTime = 0; lastUpdate = 0; stage = new AtomicReference<>(); @@ -168,11 +169,15 @@ public void setProgressBar(BossBar progressBar) { this.progressBar = progressBar; } - public boolean isProgressTaskStarted() { - return progressTaskStarted; + public boolean isJustCommenced() { + return justCommenced; } - public void setProgressTaskStarted(boolean progressTaskStarted) { - this.progressTaskStarted = progressTaskStarted; + public int getCooldown() { + return cooldown; + } + + void setJustCommenced(boolean justCommenced) { + this.justCommenced = justCommenced; } } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/siege/SiegePreparationTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/siege/SiegePreparationTask.java index a0a466cbe..cb86ac5e6 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/siege/SiegePreparationTask.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/siege/SiegePreparationTask.java @@ -23,6 +23,7 @@ public void run() { siege.getProgressBar().setProgress(Math.min(progress, 1.0)); if (timePassedInSeconds >= siege.getDelayBeforeStart()){ siege.getProgressBar().setProgress(0.0); + siege.setJustCommenced(true); siege.setStage(SiegeStage.IN_PROGRESS); return; } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/siege/SiegeProgressTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/siege/SiegeProgressTask.java index 7752920d8..21fd99336 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/siege/SiegeProgressTask.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/siege/SiegeProgressTask.java @@ -35,18 +35,14 @@ public void run() { BarColor bColor = leaderPilotingShip(siegeCraft) && leaderShipInRegion(siegeCraft, siegeLeader) ? BarColor.GREEN : BarColor.RED; siege.getProgressBar().setColor(bColor); - if (timeLeft % Settings.SiegeTaskSeconds != 0 && siege.isProgressTaskStarted()) { + if (timeLeft % Settings.SiegeTaskSeconds != 0 && !siege.isJustCommenced()) { return; } - siege.setProgressTaskStarted(true); + siege.setJustCommenced(false); if (timeLeft > 10) { - if (!leaderPilotingShip(siegeCraft)) { - return; - } - - if (leaderShipInRegion(siegeCraft, siegeLeader)) { + if (leaderPilotingShip(siegeCraft) && leaderShipInRegion(siegeCraft, siegeLeader)) { MovecraftLocation mid = siegeCraft.getHitBox().getMidPoint(); Bukkit.getServer().broadcastMessage(String.format( I18nSupport.getInternationalisedString("Siege - Flagship In Box"), @@ -61,7 +57,6 @@ public void run() { siege.getName(), siegeLeader.getDisplayName()) + formatMinutes(timeLeft)); } - return; } else { endSiege(siegeCraft, siegeLeader); } @@ -89,7 +84,6 @@ private void endSiege(Craft siegeCraft, Player siegeLeader) { } siege.getProgressBar().setVisible(false); siege.getProgressBar().setColor(BarColor.BLUE); - siege.setProgressTaskStarted(false); siege.setStage(SiegeStage.INACTIVE); } diff --git a/modules/Movecraft/src/main/resources/localisation/movecraftlang_en.properties b/modules/Movecraft/src/main/resources/localisation/movecraftlang_en.properties index 6f4be165e..7690578c4 100644 --- a/modules/Movecraft/src/main/resources/localisation/movecraftlang_en.properties +++ b/modules/Movecraft/src/main/resources/localisation/movecraftlang_en.properties @@ -169,6 +169,10 @@ Siege\ -\ Insufficient\ Funds=You do not have enough money. You need %d Siege\ -\ No\ Configuration\ Found=Could not find a siege configuration for the region you are in. Siege\ -\ Siege\ Region\ Not\ Found=Siege region not found. Use '/siege list' to find valid siege regions. Siege\ -\ Ownership\ Payout\ Console=Player %s paid %d for their ownership in %s +Siege\ -\ Siege\ have\ recently\ taken\ place=This siege has recently taken place +Siege\ -\ Must\ pilot\ siege\ craft=You must be piloting a craft that can siege! +Siege\ -\ Must\ pilot\ siege\ craft\ in\ region=You must be piloting a craft in the siege region! +Siege\ -\ Cooldown=Cooldown: Siege\ -\ Monday=Monday Siege\ -\ Tuesday=Tuesday Siege\ -\ Wednesday=Wednesday @@ -192,6 +196,7 @@ Startup\ -\ WE\ Found=Found a compatible version of WorldEdit. Enabling WorldEdi Startup\ -\ WE\ Not\ Found=Movecraft did not find a compatible version of WorldEdit. Disabling WorldEdit integration. Startup\ -\ Cannons\ Found=Found a compatible version of Cannons. Enabling Cannons integration. Startup\ -\ Cannons\ Not\ Found=Movecraft did not find a compatible version of Cannons. Disabling Cannons integration. +Startup\ -\ Siege\ Invalid\ region\ name=Invalid region name for %s: %s Startup\ -\ WGCF\ Found=Found a compatible version of WGCustomFlags. Enabling WGCustomFlags integration. Startup\ -\ WGCF\ Not\ Found=Movecraft did not find a compatible version of WGCustomFlags. Disabling WGCustomFlags integration. Startup\ -\ Towny\ Found=Found a compatible version of Towny. Enabling Towny integration. From c661c6987b659a2e8335e16107022d1a8e79aed5 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Sat, 25 Apr 2020 17:38:56 +0200 Subject: [PATCH 153/304] WorldHandler optimization --- .../compat/v1_13_R2/IWorldHandler.java | 164 +++++++++-------- .../compat/v1_14_R1/IWorldHandler.java | 165 +++++++++-------- .../compat/v1_15_R1/IWorldHandler.java | 172 +++++++++--------- .../compat/v1_8_R3/IWorldHandler.java | 98 ++++++---- .../compat/v1_9_R2/IWorldHandler.java | 98 ++++++---- 5 files changed, 375 insertions(+), 322 deletions(-) diff --git a/modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/IWorldHandler.java b/modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/IWorldHandler.java index e9eaa2337..ca56764d7 100644 --- a/modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/IWorldHandler.java +++ b/modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/IWorldHandler.java @@ -8,16 +8,12 @@ import net.countercraft.movecraft.utils.CollectionUtils; import net.countercraft.movecraft.utils.MathUtils; import net.minecraft.server.v1_13_R2.*; -import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.block.data.BlockData; import org.bukkit.craftbukkit.v1_13_R2.CraftWorld; import org.bukkit.craftbukkit.v1_13_R2.block.data.CraftBlockData; -import org.bukkit.craftbukkit.v1_13_R2.entity.CraftPlayer; import org.bukkit.craftbukkit.v1_13_R2.util.CraftMagicNumbers; -import org.bukkit.entity.Player; -import org.bukkit.event.player.PlayerMoveEvent; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -189,23 +185,8 @@ public void translateCraft(@NotNull Craft craft, @NotNull MovecraftLocation disp //******************************************* //* Step two: Get the tiles * //******************************************* - World nativeWorld = ((CraftWorld) craft.getW()).getHandle(); - List tiles = new ArrayList<>(); - //get the tiles - for(BlockPosition position : positions){ - if(nativeWorld.getType(position) == Blocks.AIR.getBlockData()) - continue; - //TileEntity tile = nativeWorld.removeTileEntity(position); - TileEntity tile = removeTileEntity(nativeWorld,position); - if(tile == null) - continue; - //get the nextTick to move with the tile - - //nativeWorld.capturedTileEntities.remove(position); - //nativeWorld.getChunkAtWorldCoords(position).getTileEntities().remove(position); - tiles.add(new TileHolder(tile, tickProvider.getNextTick((WorldServer)nativeWorld,position), position)); - - } + WorldServer nativeWorld = ((CraftWorld) craft.getW()).getHandle(); + List tiles = getTiles(positions, nativeWorld); //******************************************* //* Step three: Translate all the blocks * //******************************************* @@ -220,62 +201,26 @@ public void translateCraft(@NotNull Craft craft, @NotNull MovecraftLocation disp blockData.add(nativeWorld.getType(position)); newPositions.add(position.a(translateVector)); } - Map redstoneComponents = new HashMap<>(); //create the new block - for(int i = 0; i deletePositions = CollectionUtils.filter(positions,newPositions); - for(BlockPosition position : deletePositions){ - setBlockFast(nativeWorld, position, Blocks.AIR.getBlockData()); - } - + setAir(deletePositions, nativeWorld); //******************************************* //* Step six: Process fire spread * //******************************************* - for (BlockPosition position : newPositions) { - IBlockData type = nativeWorld.getType(position); - if (!(type.getBlock() instanceof BlockFire)) { - continue; - } - BlockFire fire = (BlockFire) type.getBlock(); - fire.a(type, nativeWorld, position, nativeWorld.random); - } - - for (Map.Entry entry : redstoneComponents.entrySet()) { - final BlockPosition position = entry.getKey(); - final IBlockData data = entry.getValue(); - Chunk chunk = nativeWorld.getChunkAtWorldCoords(position); - ChunkSection chunkSection = chunk.getSections()[position.getY()>>4]; - if (chunkSection == null) { - // Put a GLASS block to initialize the section. It will be replaced next with the real block. - chunk.setType(position, Blocks.GLASS.getBlockData(), true); - chunkSection = chunk.getSections()[position.getY() >> 4]; - - } - chunkSection.setType(position.getX()&15, position.getY()&15, position.getZ()&15, data); - nativeWorld.notifyAndUpdatePhysics(position, chunk, data, data, data, 3); - } + processFireSpread(newPositions, nativeWorld); + //******************************************* + //* Step six: Process redstone * + //******************************************* + processRedstone(newPositions, nativeWorld); //******************************************* //* Step six: Send to players * //******************************************* @@ -295,21 +240,82 @@ public void translateCraft(@NotNull Craft craft, @NotNull MovecraftLocation disp //sendToPlayers(chunks.toArray(new Chunk[0])); } - @Override - public void addPlayerLocation(Player player, double x, double y, double z, float yaw, float pitch){ - EntityPlayer ePlayer = ((CraftPlayer) player).getHandle(); - if(internalTeleportMH == null) { - //something went wrong - super.addPlayerLocation(player, x, y, z, yaw, pitch); - return; + + private void setBlocks(List newPositions, List blockData, World nativeWorld){ + Map redstoneComponents = new HashMap<>(); + for(int i = 0; i getTiles(Iterable positions, WorldServer nativeWorld){ + List tiles = new ArrayList<>(); + //get the tiles + for(BlockPosition position : positions){ + if(nativeWorld.getType(position) == Blocks.AIR.getBlockData()) + continue; + //TileEntity tile = nativeWorld.removeTileEntity(position); + TileEntity tile = removeTileEntity(nativeWorld,position); + if(tile == null) + continue; + //get the nextTick to move with the tile + + //nativeWorld.capturedTileEntities.remove(position); + //nativeWorld.getChunkAtWorldCoords(position).getTileEntities().remove(position); + tiles.add(new TileHolder(tile, tickProvider.getNextTick(nativeWorld, position), position)); + + } + return tiles; + } + + private void processTiles(Iterable tiles, World world, BlockPosition translateVector){ + for(TileHolder tileHolder : tiles){ + moveTileEntity(world, tileHolder.getTilePosition().a(translateVector),tileHolder.getTile()); + if(tileHolder.getNextTick()==null) + continue; + final long currentTime = world.worldData.getTime(); + world.getBlockTickList().a(tileHolder.getNextTick().a.a(translateVector), tileHolder.getNextTick().a(), (int) (tileHolder.getNextTick().b - currentTime), tileHolder.getNextTick().c); + } + } + + private void processFireSpread(Iterable positions, World world){ + for (BlockPosition position : positions) { + IBlockData type = world.getType(position); + if (!(type.getBlock() instanceof BlockFire)) { + continue; + } + BlockFire fire = (BlockFire) type.getBlock(); + fire.a(type, world, position, world.random); + } + } + + private void processRedstone(List redstone, World world) { + Map redstoneComponents = new HashMap<>(); + for (int i = 0 ; i < redstone.size(); i++) { + BlockPosition pos = redstone.get(i); + IBlockData data = world.getType(pos); + if (isRedstoneComponent(data)) + redstoneComponents.put(pos, data); + } + for (Map.Entry entry : redstoneComponents.entrySet()) { + final BlockPosition position = entry.getKey(); + final IBlockData data = entry.getValue(); + Chunk chunk = world.getChunkAtWorldCoords(position); + ChunkSection chunkSection = chunk.getSections()[position.getY()>>4]; + if (chunkSection == null) { + // Put a GLASS block to initialize the section. It will be replaced next with the real block. + chunk.setType(position, Blocks.GLASS.getBlockData(), true); + chunkSection = chunk.getSections()[position.getY() >> 4]; + + } + chunkSection.setType(position.getX()&15, position.getY()&15, position.getZ()&15, data); + world.notifyAndUpdatePhysics(position, chunk, data, data, data, 3); + } + } + + private void setAir(Iterable positions, World world){ + for(BlockPosition position : positions){ + setBlockFast(world, position, Blocks.AIR.getBlockData()); } } diff --git a/modules/v1_14_R1/src/main/java/net/countercraft/movecraft/compat/v1_14_R1/IWorldHandler.java b/modules/v1_14_R1/src/main/java/net/countercraft/movecraft/compat/v1_14_R1/IWorldHandler.java index 31595688d..6445e87bc 100644 --- a/modules/v1_14_R1/src/main/java/net/countercraft/movecraft/compat/v1_14_R1/IWorldHandler.java +++ b/modules/v1_14_R1/src/main/java/net/countercraft/movecraft/compat/v1_14_R1/IWorldHandler.java @@ -8,16 +8,12 @@ import net.countercraft.movecraft.utils.CollectionUtils; import net.countercraft.movecraft.utils.MathUtils; import net.minecraft.server.v1_14_R1.*; -import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.block.data.BlockData; import org.bukkit.craftbukkit.v1_14_R1.CraftWorld; import org.bukkit.craftbukkit.v1_14_R1.block.data.CraftBlockData; -import org.bukkit.craftbukkit.v1_14_R1.entity.CraftPlayer; import org.bukkit.craftbukkit.v1_14_R1.util.CraftMagicNumbers; -import org.bukkit.entity.Player; -import org.bukkit.event.player.PlayerMoveEvent; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -188,23 +184,8 @@ public void translateCraft(@NotNull Craft craft, @NotNull MovecraftLocation disp //******************************************* //* Step two: Get the tiles * //******************************************* - World nativeWorld = ((CraftWorld) craft.getW()).getHandle(); - List tiles = new ArrayList<>(); - //get the tiles - for(BlockPosition position : positions){ - if(nativeWorld.getType(position) == Blocks.AIR.getBlockData()) - continue; - //TileEntity tile = nativeWorld.removeTileEntity(position); - TileEntity tile = removeTileEntity(nativeWorld,position); - if(tile == null) - continue; - //get the nextTick to move with the tile - - //nativeWorld.capturedTileEntities.remove(position); - //nativeWorld.getChunkAtWorldCoords(position).getTileEntities().remove(position); - tiles.add(new TileHolder(tile, tickProvider.getNextTick((WorldServer)nativeWorld,position), position)); - - } + WorldServer nativeWorld = ((CraftWorld) craft.getW()).getHandle(); + List tiles = getTiles(positions, nativeWorld); //******************************************* //* Step three: Translate all the blocks * //******************************************* @@ -219,63 +200,26 @@ public void translateCraft(@NotNull Craft craft, @NotNull MovecraftLocation disp blockData.add(nativeWorld.getType(position)); newPositions.add(position.a(translateVector)); } - Map redstoneComponents = new HashMap<>(); //create the new block - for(int i = 0; i deletePositions = CollectionUtils.filter(positions,newPositions); - for(BlockPosition position : deletePositions){ - setBlockFast(nativeWorld, position, Blocks.AIR.getBlockData()); - } - + setAir(deletePositions, nativeWorld); //******************************************* //* Step six: Process fire spread * //******************************************* - for (BlockPosition position : newPositions) { - IBlockData type = nativeWorld.getType(position); - if (!(type.getBlock() instanceof BlockFire)) { - continue; - } - BlockFire fire = (BlockFire) type.getBlock(); - fire.tick(type, nativeWorld, position, nativeWorld.random); - } - - for (Map.Entry entry : redstoneComponents.entrySet()) { - final BlockPosition position = entry.getKey(); - final IBlockData data = entry.getValue(); - Chunk chunk = nativeWorld.getChunkAtWorldCoords(position); - ChunkSection chunkSection = chunk.getSections()[position.getY()>>4]; - if (chunkSection == null) { - // Put a GLASS block to initialize the section. It will be replaced next with the real block. - chunk.setType(position, Blocks.GLASS.getBlockData(), true); - chunkSection = chunk.getSections()[position.getY() >> 4]; - - } - chunkSection.setType(position.getX()&15, position.getY()&15, position.getZ()&15, data); - nativeWorld.notifyAndUpdatePhysics(position, chunk, data, data, data, 3); - } + processFireSpread(newPositions, nativeWorld); + //******************************************* + //* Step six: Process redstone * + //******************************************* + processRedstone(newPositions, nativeWorld); //******************************************* //* Step six: Send to players * //******************************************* @@ -295,21 +239,82 @@ public void translateCraft(@NotNull Craft craft, @NotNull MovecraftLocation disp //sendToPlayers(chunks.toArray(new Chunk[0])); } - @Override - public void addPlayerLocation(Player player, double x, double y, double z, float yaw, float pitch){ - EntityPlayer ePlayer = ((CraftPlayer) player).getHandle(); - if(internalTeleportMH == null) { - //something went wrong - super.addPlayerLocation(player, x, y, z, yaw, pitch); - return; + + private void setBlocks(List newPositions, List blockData, World nativeWorld){ + Map redstoneComponents = new HashMap<>(); + for(int i = 0; i getTiles(Iterable positions, WorldServer nativeWorld){ + List tiles = new ArrayList<>(); + //get the tiles + for(BlockPosition position : positions){ + if(nativeWorld.getType(position) == Blocks.AIR.getBlockData()) + continue; + //TileEntity tile = nativeWorld.removeTileEntity(position); + TileEntity tile = removeTileEntity(nativeWorld,position); + if(tile == null) + continue; + //get the nextTick to move with the tile + + //nativeWorld.capturedTileEntities.remove(position); + //nativeWorld.getChunkAtWorldCoords(position).getTileEntities().remove(position); + tiles.add(new TileHolder(tile, tickProvider.getNextTick(nativeWorld, position), position)); + + } + return tiles; + } + + private void processTiles(Iterable tiles, World world, BlockPosition translateVector){ + for(TileHolder tileHolder : tiles){ + moveTileEntity(world, tileHolder.getTilePosition().a(translateVector),tileHolder.getTile()); + if(tileHolder.getNextTick()==null) + continue; + final long currentTime = world.worldData.getTime(); + world.getBlockTickList().a(tileHolder.getNextTick().a.a(translateVector), tileHolder.getNextTick().b(), (int) (tileHolder.getNextTick().b - currentTime), tileHolder.getNextTick().c); + } + } + + private void processFireSpread(Iterable positions, World world){ + for (BlockPosition position : positions) { + IBlockData type = world.getType(position); + if (!(type.getBlock() instanceof BlockFire)) { + continue; + } + BlockFire fire = (BlockFire) type.getBlock(); + fire.tick(type, world, position, world.random); + } + } + + private void processRedstone(List redstone, World world) { + Map redstoneComponents = new HashMap<>(); + for (int i = 0 ; i < redstone.size(); i++) { + BlockPosition pos = redstone.get(i); + IBlockData data = world.getType(pos); + if (isRedstoneComponent(data)) + redstoneComponents.put(pos, data); + } + for (Map.Entry entry : redstoneComponents.entrySet()) { + final BlockPosition position = entry.getKey(); + final IBlockData data = entry.getValue(); + Chunk chunk = world.getChunkAtWorldCoords(position); + ChunkSection chunkSection = chunk.getSections()[position.getY()>>4]; + if (chunkSection == null) { + // Put a GLASS block to initialize the section. It will be replaced next with the real block. + chunk.setType(position, Blocks.GLASS.getBlockData(), true); + chunkSection = chunk.getSections()[position.getY() >> 4]; + + } + chunkSection.setType(position.getX()&15, position.getY()&15, position.getZ()&15, data); + world.notifyAndUpdatePhysics(position, chunk, data, data, data, 3); + } + } + + private void setAir(Iterable positions, World world){ + for(BlockPosition position : positions){ + setBlockFast(world, position, Blocks.AIR.getBlockData()); } } diff --git a/modules/v1_15_R1/src/main/java/net/countercraft/movecraft/compat/v1_15_R1/IWorldHandler.java b/modules/v1_15_R1/src/main/java/net/countercraft/movecraft/compat/v1_15_R1/IWorldHandler.java index f824accf9..9f56e091b 100644 --- a/modules/v1_15_R1/src/main/java/net/countercraft/movecraft/compat/v1_15_R1/IWorldHandler.java +++ b/modules/v1_15_R1/src/main/java/net/countercraft/movecraft/compat/v1_15_R1/IWorldHandler.java @@ -8,16 +8,12 @@ import net.countercraft.movecraft.utils.CollectionUtils; import net.countercraft.movecraft.utils.MathUtils; import net.minecraft.server.v1_15_R1.*; -import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.block.data.BlockData; import org.bukkit.craftbukkit.v1_15_R1.CraftWorld; import org.bukkit.craftbukkit.v1_15_R1.block.data.CraftBlockData; -import org.bukkit.craftbukkit.v1_15_R1.entity.CraftPlayer; import org.bukkit.craftbukkit.v1_15_R1.util.CraftMagicNumbers; -import org.bukkit.entity.Player; -import org.bukkit.event.player.PlayerMoveEvent; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -182,7 +178,6 @@ public void translateCraft(@NotNull Craft craft, @NotNull MovecraftLocation disp //******************************************* BlockPosition translateVector = locationToPosition(displacement); List positions = new ArrayList<>(); - WorldServer nativeWorld = ((CraftWorld) craft.getW()).getHandle(); for(MovecraftLocation movecraftLocation : craft.getHitBox()) { BlockPosition origPos = locationToPosition((movecraftLocation)).b(translateVector); positions.add(origPos); @@ -192,20 +187,8 @@ public void translateCraft(@NotNull Craft craft, @NotNull MovecraftLocation disp //******************************************* //* Step two: Get the tiles * //******************************************* - - List tiles = new ArrayList<>(); - //get the tiles - for(BlockPosition position : positions){ - nativeWorld.setForceLoaded(position.getX() >> 4, position.getZ() >> 4, true); - if(nativeWorld.getType(position) == Blocks.AIR.getBlockData()) - continue; - TileEntity tile = removeTileEntity(nativeWorld,position); - if(tile == null) - continue; - //get the nextTick to move with the tile - tiles.add(new TileHolder(tile, tickProvider.getNextTick(nativeWorld, position), position)); - - } + WorldServer nativeWorld = ((CraftWorld) craft.getW()).getHandle(); + List tiles = getTiles(positions, nativeWorld); //******************************************* //* Step three: Translate all the blocks * //******************************************* @@ -220,57 +203,106 @@ public void translateCraft(@NotNull Craft craft, @NotNull MovecraftLocation disp blockData.add(nativeWorld.getType(position)); newPositions.add(position.a(translateVector)); } - Map redstoneComponents = new HashMap<>(); //create the new block - for(int i = 0; i deletePositions = CollectionUtils.filter(positions,newPositions); + setAir(deletePositions, nativeWorld); + //******************************************* + //* Step six: Process fire spread * + //******************************************* + processFireSpread(newPositions, nativeWorld); + //******************************************* + //* Step six: Process redstone * + //******************************************* + processRedstone(newPositions, nativeWorld); + //******************************************* + //* Step six: Send to players * + //******************************************* + List chunks = new ArrayList<>(); + for(BlockPosition position : newPositions){ + Chunk chunk = nativeWorld.getChunkAtWorldCoords(position); + if(!chunks.contains(chunk)){ + chunks.add(chunk); + } + } for(BlockPosition position : deletePositions){ - nativeWorld.setForceLoaded(position.getX() >> 4, position.getZ() >> 4, false); - setBlockFast(nativeWorld, position, Blocks.AIR.getBlockData()); + Chunk chunk = nativeWorld.getChunkAtWorldCoords(position); + if(!chunks.contains(chunk)){ + chunks.add(chunk); + } } + //sendToPlayers(chunks.toArray(new Chunk[0])); + } - //********************************************** - //* Step six: Process fire spread and redstone * - //********************************************** - for (BlockPosition position : newPositions) { - IBlockData type = nativeWorld.getType(position); - if (type.getBlock() instanceof BlockFire) { - type.getBlock().tick(type, nativeWorld, position, nativeWorld.random); - } + private void setBlocks(List newPositions, List blockData, World nativeWorld){ + Map redstoneComponents = new HashMap<>(); + for(int i = 0; i getTiles(Iterable positions, WorldServer nativeWorld){ + List tiles = new ArrayList<>(); + //get the tiles + for(BlockPosition position : positions){ + if(nativeWorld.getType(position) == Blocks.AIR.getBlockData()) + continue; + //TileEntity tile = nativeWorld.removeTileEntity(position); + TileEntity tile = removeTileEntity(nativeWorld,position); + if(tile == null) + continue; + //get the nextTick to move with the tile + + //nativeWorld.capturedTileEntities.remove(position); + //nativeWorld.getChunkAtWorldCoords(position).getTileEntities().remove(position); + tiles.add(new TileHolder(tile, tickProvider.getNextTick(nativeWorld, position), position)); + + } + return tiles; + } + + private void processTiles(Iterable tiles, World world, BlockPosition translateVector){ + for(TileHolder tileHolder : tiles){ + moveTileEntity(world, tileHolder.getTilePosition().a(translateVector),tileHolder.getTile()); + if(tileHolder.getNextTick()==null) + continue; + final long currentTime = world.worldData.getTime(); + world.getBlockTickList().a(tileHolder.getNextTick().a.a(translateVector), tileHolder.getNextTick().b(), (int) (tileHolder.getNextTick().b - currentTime), tileHolder.getNextTick().c); } + } + private void processFireSpread(Iterable positions, WorldServer world){ + for (BlockPosition position : positions) { + IBlockData type = world.getType(position); + if (!(type.getBlock() instanceof BlockFire)) { + continue; + } + BlockFire fire = (BlockFire) type.getBlock(); + fire.tick(type, world, position, world.random); + } + } + + private void processRedstone(List redstone, World world) { + Map redstoneComponents = new HashMap<>(); + for (int i = 0 ; i < redstone.size(); i++) { + BlockPosition pos = redstone.get(i); + IBlockData data = world.getType(pos); + if (isRedstoneComponent(data)) + redstoneComponents.put(pos, data); + } for (Map.Entry entry : redstoneComponents.entrySet()) { final BlockPosition position = entry.getKey(); final IBlockData data = entry.getValue(); - Chunk chunk = nativeWorld.getChunkAtWorldCoords(position); + Chunk chunk = world.getChunkAtWorldCoords(position); ChunkSection chunkSection = chunk.getSections()[position.getY()>>4]; if (chunkSection == null) { // Put a GLASS block to initialize the section. It will be replaced next with the real block. @@ -279,43 +311,13 @@ public void translateCraft(@NotNull Craft craft, @NotNull MovecraftLocation disp } chunkSection.setType(position.getX()&15, position.getY()&15, position.getZ()&15, data); - nativeWorld.notifyAndUpdatePhysics(position, chunk, data, data, data, 3); - } - //******************************************* - //* Step six: Send to players * - //******************************************* - List chunks = new ArrayList<>(); - for(BlockPosition position : newPositions){ - Chunk chunk = nativeWorld.getChunkAtWorldCoords(position); - - if(!chunks.contains(chunk)){ - chunks.add(chunk); - } - } - for(BlockPosition position : deletePositions){ - Chunk chunk = nativeWorld.getChunkAtWorldCoords(position); - if(!chunks.contains(chunk)){ - chunks.add(chunk); - } + world.notifyAndUpdatePhysics(position, chunk, data, data, data, 3); } - //sendToPlayers(chunks.toArray(new Chunk[0])); } - @Override - public void addPlayerLocation(Player player, double x, double y, double z, float yaw, float pitch){ - EntityPlayer ePlayer = ((CraftPlayer) player).getHandle(); - if(internalTeleportMH == null) { - //something went wrong - super.addPlayerLocation(player, x, y, z, yaw, pitch); - return; - } - try { - final Location oldLoc = player.getLocation().clone(); - final Location newLoc = player.getLocation().add(x,y,z); - internalTeleportMH.invoke(ePlayer.playerConnection, x + player.getLocation().getX(), y + player.getLocation().getY(), z + player.getLocation().getZ(), yaw, pitch, EnumSet.allOf(PacketPlayOutPosition.EnumPlayerTeleportFlags.class)); - Bukkit.getServer().getPluginManager().callEvent(new PlayerMoveEvent(player,oldLoc,newLoc)); - } catch (Throwable throwable) { - throwable.printStackTrace(); + private void setAir(Iterable positions, World world){ + for(BlockPosition position : positions){ + setBlockFast(world, position, Blocks.AIR.getBlockData()); } } diff --git a/modules/v1_8_R3/src/main/java/net/countercraft/movecraft/compat/v1_8_R3/IWorldHandler.java b/modules/v1_8_R3/src/main/java/net/countercraft/movecraft/compat/v1_8_R3/IWorldHandler.java index 4b804ee91..e9969ceb4 100644 --- a/modules/v1_8_R3/src/main/java/net/countercraft/movecraft/compat/v1_8_R3/IWorldHandler.java +++ b/modules/v1_8_R3/src/main/java/net/countercraft/movecraft/compat/v1_8_R3/IWorldHandler.java @@ -182,23 +182,8 @@ public void translateCraft(@NotNull Craft craft, @NotNull MovecraftLocation disp //******************************************* //* Step two: Get the tiles * //******************************************* - World nativeWorld = ((CraftWorld) craft.getW()).getHandle(); - List tiles = new ArrayList<>(); - //get the tiles - for(BlockPosition position : positions){ - if(nativeWorld.getType(position) == Blocks.AIR.getBlockData()) - continue; - //TileEntity tile = nativeWorld.removeTileEntity(position); - TileEntity tile = removeTileEntity(nativeWorld,position); - if(tile == null) - continue; - //get the nextTick to move with the tile - - //nativeWorld.capturedTileEntities.remove(position); - //nativeWorld.getChunkAtWorldCoords(position).getTileEntities().remove(position); - tiles.add(new TileHolder(tile, tickProvider.getNextTick((WorldServer)nativeWorld,position), position)); - - } + WorldServer nativeWorld = ((CraftWorld) craft.getW()).getHandle(); + List tiles = getTiles(positions, nativeWorld); //******************************************* //* Step three: Translate all the blocks * //******************************************* @@ -214,39 +199,21 @@ public void translateCraft(@NotNull Craft craft, @NotNull MovecraftLocation disp newPositions.add(position.a(translateVector)); } //create the new block - for(int i = 0; i deletePositions = CollectionUtils.filter(positions,newPositions); - for(BlockPosition position : deletePositions){ - setBlockFast(nativeWorld, position, Blocks.AIR.getBlockData()); - } - + setAir(deletePositions, nativeWorld); //******************************************* //* Step six: Process fire spread * //******************************************* - for (BlockPosition position : newPositions) { - IBlockData type = nativeWorld.getType(position); - if (!(type.getBlock() instanceof BlockFire)) { - continue; - } - BlockFire fire = (BlockFire) type.getBlock(); - fire.b(nativeWorld, position, type, nativeWorld.random); - } + processFireSpread(newPositions, nativeWorld); //******************************************* //* Step seven: Send to players * //******************************************* @@ -266,6 +233,59 @@ public void translateCraft(@NotNull Craft craft, @NotNull MovecraftLocation disp //sendToPlayers(chunks.toArray(new Chunk[0])); } + private void setBlocks(List newPositions, List blockData, World nativeWorld){ + for(int i = 0; i getTiles(Iterable positions, WorldServer nativeWorld){ + List tiles = new ArrayList<>(); + //get the tiles + for(BlockPosition position : positions){ + if(nativeWorld.getType(position) == Blocks.AIR.getBlockData()) + continue; + //TileEntity tile = nativeWorld.removeTileEntity(position); + TileEntity tile = removeTileEntity(nativeWorld,position); + if(tile == null) + continue; + //get the nextTick to move with the tile + + //nativeWorld.capturedTileEntities.remove(position); + //nativeWorld.getChunkAtWorldCoords(position).getTileEntities().remove(position); + tiles.add(new TileHolder(tile, tickProvider.getNextTick(nativeWorld, position), position)); + + } + return tiles; + } + + private void processTiles(Iterable tiles, World world, BlockPosition translateVector){ + for(TileHolder tileHolder : tiles){ + moveTileEntity(world, tileHolder.getTilePosition().a(translateVector),tileHolder.getTile()); + if(tileHolder.getNextTick()==null) + continue; + final long currentTime = world.worldData.getTime(); + world.b(tileHolder.getNextTick().a.a(translateVector), tileHolder.getNextTick().a(), (int) (tileHolder.getNextTick().b - currentTime), tileHolder.getNextTick().c); + } + } + + private void processFireSpread(Iterable positions, World world){ + for (BlockPosition position : positions) { + IBlockData type = world.getType(position); + if (!(type.getBlock() instanceof BlockFire)) { + continue; + } + BlockFire fire = (BlockFire) type.getBlock(); + fire.b(world, position, type, world.random); + } + } + + private void setAir(Iterable positions, World world){ + for(BlockPosition position : positions){ + setBlockFast(world, position, Blocks.AIR.getBlockData()); + } + } + @Nullable private TileEntity removeTileEntity(@NotNull World world, @NotNull BlockPosition position){ TileEntity tile = world.getTileEntity(position); diff --git a/modules/v1_9_R2/src/main/java/net/countercraft/movecraft/compat/v1_9_R2/IWorldHandler.java b/modules/v1_9_R2/src/main/java/net/countercraft/movecraft/compat/v1_9_R2/IWorldHandler.java index 4659611be..05303752b 100644 --- a/modules/v1_9_R2/src/main/java/net/countercraft/movecraft/compat/v1_9_R2/IWorldHandler.java +++ b/modules/v1_9_R2/src/main/java/net/countercraft/movecraft/compat/v1_9_R2/IWorldHandler.java @@ -174,23 +174,8 @@ public void translateCraft(@NotNull Craft craft, @NotNull MovecraftLocation disp //******************************************* //* Step two: Get the tiles * //******************************************* - World nativeWorld = ((CraftWorld) craft.getW()).getHandle(); - List tiles = new ArrayList<>(); - //get the tiles - for(BlockPosition position : positions){ - if(nativeWorld.getType(position) == Blocks.AIR.getBlockData()) - continue; - //TileEntity tile = nativeWorld.removeTileEntity(position); - TileEntity tile = removeTileEntity(nativeWorld,position); - if(tile == null) - continue; - //get the nextTick to move with the tile - - //nativeWorld.capturedTileEntities.remove(position); - //nativeWorld.getChunkAtWorldCoords(position).getTileEntities().remove(position); - tiles.add(new TileHolder(tile, tickProvider.getNextTick((WorldServer)nativeWorld,position), position)); - - } + WorldServer nativeWorld = ((CraftWorld) craft.getW()).getHandle(); + List tiles = getTiles(positions, nativeWorld); //******************************************* //* Step three: Translate all the blocks * //******************************************* @@ -206,39 +191,21 @@ public void translateCraft(@NotNull Craft craft, @NotNull MovecraftLocation disp newPositions.add(position.a(translateVector)); } //create the new block - for(int i = 0; i deletePositions = CollectionUtils.filter(positions,newPositions); - for(BlockPosition position : deletePositions){ - setBlockFast(nativeWorld, position, Blocks.AIR.getBlockData()); - } - + setAir(deletePositions, nativeWorld); //******************************************* //* Step six: Process fire spread * //******************************************* - for (BlockPosition position : newPositions) { - IBlockData type = nativeWorld.getType(position); - if (!(type.getBlock() instanceof BlockFire)) { - continue; - } - BlockFire fire = (BlockFire) type.getBlock(); - fire.b(nativeWorld, position, type, nativeWorld.random); - } + processFireSpread(newPositions, nativeWorld); //******************************************* //* Step seven: Send to players * //******************************************* @@ -258,6 +225,59 @@ public void translateCraft(@NotNull Craft craft, @NotNull MovecraftLocation disp //sendToPlayers(chunks.toArray(new Chunk[0])); } + private void setBlocks(List newPositions, List blockData, World nativeWorld){ + for(int i = 0; i getTiles(Iterable positions, WorldServer nativeWorld){ + List tiles = new ArrayList<>(); + //get the tiles + for(BlockPosition position : positions){ + if(nativeWorld.getType(position) == Blocks.AIR.getBlockData()) + continue; + //TileEntity tile = nativeWorld.removeTileEntity(position); + TileEntity tile = removeTileEntity(nativeWorld,position); + if(tile == null) + continue; + //get the nextTick to move with the tile + + //nativeWorld.capturedTileEntities.remove(position); + //nativeWorld.getChunkAtWorldCoords(position).getTileEntities().remove(position); + tiles.add(new TileHolder(tile, tickProvider.getNextTick(nativeWorld, position), position)); + + } + return tiles; + } + + private void processTiles(Iterable tiles, World world, BlockPosition translateVector){ + for(TileHolder tileHolder : tiles){ + moveTileEntity(world, tileHolder.getTilePosition().a(translateVector),tileHolder.getTile()); + if(tileHolder.getNextTick()==null) + continue; + final long currentTime = world.worldData.getTime(); + world.b(tileHolder.getNextTick().a.a(translateVector), tileHolder.getNextTick().a(), (int) (tileHolder.getNextTick().b - currentTime), tileHolder.getNextTick().c); + } + } + + private void processFireSpread(Iterable positions, World world){ + for (BlockPosition position : positions) { + IBlockData type = world.getType(position); + if (!(type.getBlock() instanceof BlockFire)) { + continue; + } + BlockFire fire = (BlockFire) type.getBlock(); + fire.b(world, position, type, world.random); + } + } + + private void setAir(Iterable positions, World world){ + for(BlockPosition position : positions){ + setBlockFast(world, position, Blocks.AIR.getBlockData()); + } + } + @Nullable private TileEntity removeTileEntity(@NotNull World world, @NotNull BlockPosition position){ TileEntity tile = world.getTileEntity(position); From 9091920e95874f6557161372232c8261ae7dbd24 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Sun, 26 Apr 2020 18:07:38 +0200 Subject: [PATCH 154/304] Release time is now configurable --- .../net/countercraft/movecraft/listener/PlayerListener.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/PlayerListener.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/PlayerListener.java index 2dd299c35..bb6993ad2 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/PlayerListener.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/PlayerListener.java @@ -144,7 +144,7 @@ public void onPlayerMove(PlayerMoveEvent event) { } else { p.sendMessage(I18nSupport.getInternationalisedString("Release - Player has left craft")); } - timeToReleaseAfter.put(c, System.currentTimeMillis() + 30000); //30 seconds to release TODO: config + timeToReleaseAfter.put(c, System.currentTimeMillis() + (Settings.ManOverboardTimeout * 1000)); //30 seconds to release TODO: config } } } From 54150eb10ff22f72f716b0976b8377d851835850 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Tue, 28 Apr 2020 17:47:40 +0200 Subject: [PATCH 155/304] Merge https://github.com/APDevTeam/Movecraft # Conflicts: # modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java # modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java # modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftRotateCommand.java # modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftTranslateCommand.java # modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/WorldEditUpdateCommand.java # modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RepairSign.java # modules/api/src/main/java/net/countercraft/movecraft/MovecraftRepair.java # modules/api/src/main/java/net/countercraft/movecraft/craft/Craft.java # modules/api/src/main/java/net/countercraft/movecraft/utils/Pair.java # pom.xml Added ability to limit signs containing certain strings and limit how many cannons a craft can carry --- modules/Movecraft/dependency-reduced-pom.xml | 161 ++++-- modules/Movecraft/pom.xml | 42 ++ .../movecraft/async/AsyncManager.java | 20 +- .../async/detection/DetectionTask.java | 102 +++- .../async/rotation/RotationTask.java | 16 +- .../async/translation/TranslationTask.java | 64 +-- .../commands/ManOverboardCommand.java | 4 +- .../movecraft/craft/CraftManager.java | 2 +- .../countercraft/movecraft/craft/ICraft.java | 8 +- .../movecraft/listener/InteractListener.java | 2 +- .../movecraft/listener/PlayerListener.java | 2 +- .../mapUpdater/update/BlockCreateCommand.java | 2 +- .../mapUpdater/update/CraftRotateCommand.java | 22 +- .../update/CraftTranslateCommand.java | 20 +- .../update/WorldEdit7UpdateCommand.java | 4 +- .../update/WorldEditUpdateCommand.java | 2 +- .../movecraft/sign/AscendSign.java | 2 +- .../movecraft/sign/ContactsSign.java | 2 +- .../countercraft/movecraft/sign/CrewSign.java | 6 +- .../movecraft/sign/CruiseSign.java | 2 +- .../movecraft/sign/DescendSign.java | 2 +- .../countercraft/movecraft/sign/NameSign.java | 2 +- .../movecraft/sign/RepairSign.java | 2 +- .../movecraft/sign/SpeedSign.java | 2 +- .../movecraft/sign/StatusSign.java | 4 +- .../movecraft/towny/TownyCompatManager.java | 26 +- .../movecraft/utils/WaterlogUtils.java | 8 +- .../worldguard/WorldGuardCompatManager.java | 20 +- .../localisation/movecraftlang_en.properties | 3 + .../countercraft/movecraft/craft/Craft.java | 35 +- .../movecraft/craft/CraftType.java | 502 ++++++------------ .../movecraft/utils/MathUtils.java | 2 +- .../movecraft/utils/TeleportUtils.java | 9 +- .../compat/v1_10_R1/IWorldHandler.java | 5 +- .../compat/v1_11_R1/IWorldHandler.java | 4 +- .../compat/v1_12_R1/IWorldHandler.java | 4 +- .../compat/v1_13_R2/IWorldHandler.java | 4 +- .../compat/v1_14_R1/IWorldHandler.java | 4 +- .../compat/v1_15_R1/IWorldHandler.java | 4 +- .../compat/v1_8_R3/IWorldHandler.java | 4 +- .../compat/v1_9_R2/IWorldHandler.java | 4 +- .../compat/we6/IMovecraftRepair.java | 6 +- .../compat/we7/IMovecraftRepair.java | 4 +- 43 files changed, 596 insertions(+), 549 deletions(-) diff --git a/modules/Movecraft/dependency-reduced-pom.xml b/modules/Movecraft/dependency-reduced-pom.xml index f0ae205e1..d634d443f 100644 --- a/modules/Movecraft/dependency-reduced-pom.xml +++ b/modules/Movecraft/dependency-reduced-pom.xml @@ -37,6 +37,9 @@ maven-jar-plugin 2.4 + + true + maven-compiler-plugin @@ -55,14 +58,91 @@ maven-shade-plugin - 2.2 + 3.2.3 package shade - + + + + it.unimi + net.countercraft.movecraft.libs.it.unimi + + + true + + + net.countercraft:movecraft-WE6Utils + + ** + + + + net.countercraft:movecraft-WE7Utils + + ** + + + + net.countercraft:movecraft-v1_8_R3 + + ** + + + + net.countercraft:movecraft-v1_9_R2 + + ** + + + + net.countercraft:movecraft-v1_11_R1 + + ** + + + + net.countercraft:movecraft-v1_10_R1 + + ** + + + + net.countercraft:movecraft-v1_12_R1 + + ** + + + + net.countercraft:movecraft-v1_13_R2 + + ** + + + + net.countercraft:movecraft-v1_14_R1 + + ** + + + + net.countercraft:movecraft-v1_15_R1 + + ** + + + + + + net.countercraft:movecraft* + org.roaringbitmap:* + it.unimi.dsi:fastutil* + + + @@ -91,17 +171,35 @@ + + com.sk89q.worldedit + worldedit-bukkit + 7.0.1-SNAPSHOT + compile + + + com.sk89q.worldguard + worldguard-core + 7.0.1-SNAPSHOT + compile + + + com.sk89q.worldguard + worldguard-bukkit + 7.0.1-SNAPSHOT + compile + com.sk89q worldguard 6.1.1-SNAPSHOT provided - - - bukkit-classloader-check - com.sk89q.spigot - - + + + com.sk89q + worldedit + 6.0.0-SNAPSHOT + compile at.pavlov @@ -119,6 +217,12 @@ + + org.yaml + snakeyaml + 1.10 + compile + net.milkbowl.vault VaultAPI @@ -130,54 +234,29 @@ EssentialsX 2.16.1 provided - - - NMSProvider - net.ess3 - - - UpdatedMetaProvider - net.ess3 - - - 1_8_R1Provider - net.ess3 - - - 1_8_R2Provider - net.ess3 - - - LegacyProvider - net.ess3 - - - ReflectionProvider - net.ess3 - - - FlattenedProvider - net.ess3 - - + + + org.jetbrains + annotations-java5 + RELEASE + compile com.palmergames Towny LATEST system - C:\Users\eirik\IdeaProjects\Movecraft\modules\Movecraft/../../libs/Towny.jar + ${project.basedir}/../../libs/Towny.jar com.mewin WGCustomFlags LATEST system - C:\Users\eirik\IdeaProjects\Movecraft\modules\Movecraft/../../libs/WGCustomFlags.jar + ${project.basedir}/../../libs/WGCustomFlags.jar UTF-8 - diff --git a/modules/Movecraft/pom.xml b/modules/Movecraft/pom.xml index e531d6dc1..9924a965a 100644 --- a/modules/Movecraft/pom.xml +++ b/modules/Movecraft/pom.xml @@ -276,6 +276,30 @@ true + + net.countercraft:movecraft-WE6Utils + + ** + + + + net.countercraft:movecraft-WE7Utils + + ** + + + + net.countercraft:movecraft-v1_8_R3 + + ** + + + + net.countercraft:movecraft-v1_9_R2 + + ** + + net.countercraft:movecraft-v1_11_R1 @@ -294,6 +318,24 @@ ** + + net.countercraft:movecraft-v1_13_R2 + + ** + + + + net.countercraft:movecraft-v1_14_R1 + + ** + + + + net.countercraft:movecraft-v1_15_R1 + + ** + + diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java index dff7298fb..909fe0290 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java @@ -121,7 +121,7 @@ public void addWreck(Craft craft){ return; } wrecks.put(craft.getCollapsedHitBox(), System.currentTimeMillis()); - wreckWorlds.put(craft.getCollapsedHitBox(), craft.getW()); + wreckWorlds.put(craft.getCollapsedHitBox(), craft.getWorld()); wreckPhases.put(craft.getCollapsedHitBox(), craft.getPhaseBlocks()); } @@ -174,7 +174,7 @@ private void processAlgorithmQueue() { } else { - Set craftsInWorld = CraftManager.getInstance().getCraftsInWorld(c.getW()); + Set craftsInWorld = CraftManager.getInstance().getCraftsInWorld(c.getWorld()); boolean isSubcraft = false; @@ -313,7 +313,7 @@ private void processAlgorithmQueue() { c.setHitBox(task.getNewHitBox()); c.setFluidLocations(task.getNewFluidList()); //c.setBlockList(task.getData().getHitBox()); - //boolean failed = MapUpdateManager.getInstance().addWorldUpdate(c.getW(), updates, null, null, exUpdates); + //boolean failed = MapUpdateManager.getInstance().addWorldUpdate(c.getWorld(), updates, null, null, exUpdates); MapUpdateManager.getInstance().scheduleUpdates(task.getUpdates()); sentMapUpdate = true; CraftManager.getInstance().addReleaseTask(c); @@ -331,7 +331,7 @@ private void processAlgorithmQueue() { // convert blocklist to location list List shipLocations = new ArrayList<>(); for (MovecraftLocation loc : c.getHitBox()) { - Location tloc = new Location(c.getW(), loc.getX(), loc.getY(), loc.getZ()); + Location tloc = new Location(c.getWorld(), loc.getX(), loc.getY(), loc.getZ()); shipLocations.add(tloc); } shipCannons = Movecraft.getInstance().getCannonsPlugin().getCannonsAPI() @@ -378,7 +378,7 @@ private void processAlgorithmQueue() { // convert blocklist to location list List shipLocations = new ArrayList<>(); for (MovecraftLocation loc : c.getHitBox()) { - shipLocations.add(loc.toBukkit(c.getW())); + shipLocations.add(loc.toBukkit(c.getWorld())); } shipCannons = Movecraft.getInstance().getCannonsPlugin().getCannonsAPI() .getCannons(shipLocations, c.getNotificationPlayer().getUniqueId(), true); @@ -392,7 +392,7 @@ private void processAlgorithmQueue() { c.setFluidLocations(task.getNewFluidList()); // rotate any cannons that were present if (Movecraft.getInstance().getCannonsPlugin() != null && shipCannons != null) { - Location tloc = task.getOriginPoint().toBukkit(task.getCraft().getW()); + Location tloc = task.getOriginPoint().toBukkit(task.getCraft().getWorld()); for (Cannon can : shipCannons) { if (task.getRotation() == Rotation.CLOCKWISE) can.rotateRight(tloc.toVector()); @@ -422,7 +422,7 @@ private void processCruise() { continue; } long ticksElapsed = (System.currentTimeMillis() - pcraft.getLastCruiseUpdate()) / 50; - World w = pcraft.getW(); + World w = pcraft.getWorld(); // if the craft should go slower underwater, make // time pass more slowly there if (pcraft.getType().getHalfSpeedUnderwater() && pcraft.getHitBox().getMinY() < w.getSeaLevel()) @@ -559,7 +559,7 @@ private void detectSinking(){ if (ticksElapsed <= Settings.SinkCheckTicks) { continue; } - final World w = pcraft.getW(); + final World w = pcraft.getWorld(); int totalNonAirBlocks = 0; int totalNonAirWaterBlocks = 0; HashMap, Integer> foundFlyBlocks = new HashMap<>(); @@ -623,7 +623,7 @@ private void detectSinking(){ pcraft.setDisabled(true); if (pcraft.getNotificationPlayer() != null) { Location loc = pcraft.getNotificationPlayer().getLocation(); - pcraft.getW().playSound(loc, Settings.IsLegacy ? (Settings.IsPre1_9 ? LegacyUtils.IRONGOLEM_DEATH : LegacyUtils.ENITIY_IRONGOLEM_DEATH) : Sound.ENTITY_IRON_GOLEM_DEATH , 5.0f, 5.0f); + pcraft.getWorld().playSound(loc, Settings.IsLegacy ? (Settings.IsPre1_9 ? LegacyUtils.IRONGOLEM_DEATH : LegacyUtils.ENITIY_IRONGOLEM_DEATH) : Sound.ENTITY_IRON_GOLEM_DEATH , 5.0f, 5.0f); } } } @@ -1062,7 +1062,7 @@ private void processGravity(){ //Check if there are any solid blocks below the craft for (int x = minX ; x <= maxX ; x++){ for (int z = minZ ; z <= maxZ ; z++){ - if (pCraft.getW().getBlockAt(x,minY,z).getType().isSolid()){ + if (pCraft.getWorld().getBlockAt(x,minY,z).getType().isSolid()){ onGround = true; break; } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/detection/DetectionTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/detection/DetectionTask.java index 9d78d1df1..ac8e905c5 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/detection/DetectionTask.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/detection/DetectionTask.java @@ -18,6 +18,8 @@ package net.countercraft.movecraft.async.detection; +import at.pavlov.cannons.API.CannonsAPI; +import at.pavlov.cannons.cannon.Cannon; import net.countercraft.movecraft.Movecraft; import net.countercraft.movecraft.MovecraftBlock; import net.countercraft.movecraft.MovecraftLocation; @@ -25,15 +27,8 @@ import net.countercraft.movecraft.config.Settings; import net.countercraft.movecraft.craft.Craft; import net.countercraft.movecraft.localisation.I18nSupport; -import net.countercraft.movecraft.utils.BlockContainer; -import net.countercraft.movecraft.utils.BlockLimitManager; -import net.countercraft.movecraft.utils.BitmapHitBox; -import net.countercraft.movecraft.utils.HashHitBox; -import net.countercraft.movecraft.utils.LegacyUtils; -import org.bukkit.Bukkit; -import org.bukkit.Location; -import org.bukkit.Material; -import org.bukkit.World; +import net.countercraft.movecraft.utils.*; +import org.bukkit.*; import org.bukkit.block.BlockState; import org.bukkit.block.Sign; import org.bukkit.entity.Player; @@ -52,6 +47,8 @@ public class DetectionTask extends AsyncTask { @NotNull private final BitmapHitBox hitBox = new BitmapHitBox(); @NotNull private final HashSet visited = new HashSet<>(); @NotNull private final HashMap, Integer> blockTypeCount = new HashMap<>(); + @NotNull private final HashMap, Integer> signWithStringCount = new HashMap<>(); + @NotNull private final HashMap, Integer> cannonsCount = new HashMap<>(); @NotNull private final World world; @Nullable private final Player player, notificationPlayer; private final BlockContainer allowedBlocks; @@ -73,7 +70,7 @@ public DetectionTask(Craft c, MovecraftLocation startLocation, Player player) { this.startLocation = startLocation; this.minSize = craft.getType().getMinSize(); this.maxSize = craft.getType().getMaxSize(); - this.world = craft.getW(); + this.world = craft.getWorld(); this.player = player; this.notificationPlayer = craft.getNotificationPlayer(); this.allowedBlocks = craft.getType().getAllowedBlocks(); @@ -115,6 +112,8 @@ public void execute() { if (!confirmStructureRequirements(flyBlocks, blockTypeCount)) { return; } + checkMaxSignLimits(); + checkMaxCannons(); long endTime = System.currentTimeMillis(); if (Settings.Debug){ Bukkit.broadcastMessage("Detection took (ms): " + (endTime - startTime)); @@ -134,6 +133,7 @@ private void detectBlock(int x, int y, int z) { testType = world.getBlockAt(x, y, z).getType(); } catch (Exception e) { fail(String.format(I18nSupport.getInternationalisedString("Detection - Craft too large"), maxSize)); + return; } if ((testType == Material.WATER) || (testType == LegacyUtils.STATIONARY_WATER)) { @@ -157,6 +157,31 @@ public void run() { fail(I18nSupport.getInternationalisedString( "Detection - Not Registered Pilot")); } + + } + String previous = ""; + for (String line : s.getLines()) { + if (line.length() == 0) { + continue; + } + line = ChatColor.stripColor(line); + if (isForbiddenSignString(line)) { + fail(I18nSupport.getInternationalisedString("Detection - Forbidden sign string found")); + return; + } + if (previous.equals(line)) { + continue; + } + for (List limitedStrings : craft.getType().getMaxSignsWithString().keySet()) { + if (!limitedStrings.contains(line.toLowerCase())) { + continue; + } + int count = signWithStringCount.getOrDefault(limitedStrings, 0); + count++; + signWithStringCount.put(limitedStrings, count); + previous = line; + } + } } } @@ -376,6 +401,63 @@ private boolean confirmStructureRequirements(BlockLimitManager flyBlocks, return true; } + private void checkMaxSignLimits() { + for (Map.Entry, Double> entry : craft.getType().getMaxSignsWithString().entrySet()) { + final double limit = entry.getValue(); + int count = signWithStringCount.get(entry.getKey()); + if (limit >= 10000.0) { + int max = (int) (limit - 10000.0); + if (count <= max) { + continue; + } + fail(I18nSupport.getInternationalisedString("Detection - Too many signs with string") + " " + String.join(", ", entry.getKey()) + ": " + count + " > " + max); + } else { + int maxCount = (int) (hitBox.size() * (limit / 100.0)); + //double ratio = ((double) count / (double) hitBox.size()) * 100.0; + if (count <= maxCount) { + continue; + } + fail(I18nSupport.getInternationalisedString("Detection - Too many signs with string") + " " + String.join(", ", entry.getKey()) + ": " + count + "% > " + maxCount + "%"); + } + } + } + + private void checkMaxCannons() { + for (Cannon can : CannonsAPI.getCannonsInBox(hitBox.getMidPoint().toBukkit(world), hitBox.getXLength(), hitBox.getYLength(), hitBox.getZLength())) { + for (Location barrelLoc : can.getCannonDesign().getBarrelBlocks(can)) { + if (!hitBox.contains(MathUtils.bukkit2MovecraftLoc(barrelLoc))) { + continue; + } + break; + } + for (List limitedCannonNames : craft.getType().getMaxCannons().keySet()) { + if (!limitedCannonNames.contains(can.getCannonDesign().getDesignName().toLowerCase())) { + continue; + } + int count = cannonsCount.getOrDefault(limitedCannonNames, 0); + count++; + cannonsCount.put(limitedCannonNames, count); + } + } + for (List limitedCannonNames : craft.getType().getMaxCannons().keySet()) { + final double limit = craft.getType().getMaxCannons().get(limitedCannonNames); + int count = cannonsCount.get(limitedCannonNames); + if (limit >= 10000.0) { + int max = (int) (limit - 10000.0); + if (count <= max) { + continue; + } + fail(I18nSupport.getInternationalisedString("Detection - Too many cannons") + " " + String.join(", ", limitedCannonNames) + ": " + count + " > " + max); + } else { + int maxCount = (int) (hitBox.size() * (limit / 100.0)); + if (count <= maxCount) { + continue; + } + fail(I18nSupport.getInternationalisedString("Detection - Too many cannons") + " " + String.join(", ", limitedCannonNames) + ": " + count + " > " + maxCount ); + } + } + } + private void fail(String message) { failed = true; failMessage = message; diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/rotation/RotationTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/rotation/RotationTask.java index 7c3a7e38c..4506c22e1 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/rotation/RotationTask.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/rotation/RotationTask.java @@ -114,7 +114,7 @@ public void run() { } Block fuelHolder = null; for (MovecraftLocation bTest : oldHitBox) { - Block b = craft.getW().getBlockAt(bTest.getX(), bTest.getY(), bTest.getZ()); + Block b = craft.getWorld().getBlockAt(bTest.getX(), bTest.getY(), bTest.getZ()); //Get all fuel holders if (b.getType() == Material.FURNACE) { InventoryHolder holder = (InventoryHolder) b.getState(); @@ -151,7 +151,7 @@ public void run() { } // if a subcraft, find the parent craft. If not a subcraft, it is it's own parent - Set craftsInWorld = CraftManager.getInstance().getCraftsInWorld(getCraft().getW()); + Set craftsInWorld = CraftManager.getInstance().getCraftsInWorld(getCraft().getWorld()); Craft parentCraft = getCraft(); for (Craft craft : craftsInWorld) { if ( craft != getCraft() && !craft.getHitBox().intersection(oldHitBox).isEmpty()) { @@ -176,7 +176,7 @@ public void run() { //TODO: ADD TOWNY //TODO: ADD FACTIONS //isTownyBlock(plugLoc,craftPilot); - if (!withinWorldBorder(craft.getW(), newLocation)) { + if (!withinWorldBorder(craft.getWorld(), newLocation)) { failMessage = I18nSupport.getInternationalisedString("Rotation - Failed Craft cannot pass world border") + String.format(" @ %d,%d,%d", newLocation.getX(), newLocation.getY(), newLocation.getZ()); failed = true; return; @@ -298,7 +298,7 @@ public void run() { } getCraft().getNotificationPlayer().sendMessage(faceMessage); - craftsInWorld = CraftManager.getInstance().getCraftsInWorld(getCraft().getW()); + craftsInWorld = CraftManager.getInstance().getCraftsInWorld(getCraft().getWorld()); for (Craft craft : craftsInWorld) { if (!newHitBox.intersection(craft.getHitBox()).isEmpty() && craft != getCraft()) { //newHitBox.addAll(CollectionUtils.filter(craft.getHitBox(),newHitBox)); @@ -357,7 +357,7 @@ private boolean checkChests(Material mBlock, MovecraftLocation newLoc) { MovecraftLocation aroundNewLoc; aroundNewLoc = newLoc.translate(1, 0, 0); - testMaterial = craft.getW().getBlockAt(aroundNewLoc.getX(), aroundNewLoc.getY(), aroundNewLoc.getZ()).getType(); + testMaterial = craft.getWorld().getBlockAt(aroundNewLoc.getX(), aroundNewLoc.getY(), aroundNewLoc.getZ()).getType(); if (testMaterial.equals(mBlock)) { if (!oldHitBox.contains(aroundNewLoc)) { return false; @@ -365,7 +365,7 @@ private boolean checkChests(Material mBlock, MovecraftLocation newLoc) { } aroundNewLoc = newLoc.translate(-1, 0, 0); - testMaterial = craft.getW().getBlockAt(aroundNewLoc.getX(), aroundNewLoc.getY(), aroundNewLoc.getZ()).getType(); + testMaterial = craft.getWorld().getBlockAt(aroundNewLoc.getX(), aroundNewLoc.getY(), aroundNewLoc.getZ()).getType(); if (testMaterial.equals(mBlock)) { if (!oldHitBox.contains(aroundNewLoc)) { return false; @@ -373,7 +373,7 @@ private boolean checkChests(Material mBlock, MovecraftLocation newLoc) { } aroundNewLoc = newLoc.translate(0, 0, 1); - testMaterial = craft.getW().getBlockAt(aroundNewLoc.getX(), aroundNewLoc.getY(), aroundNewLoc.getZ()).getType(); + testMaterial = craft.getWorld().getBlockAt(aroundNewLoc.getX(), aroundNewLoc.getY(), aroundNewLoc.getZ()).getType(); if (testMaterial.equals(mBlock)) { if (!oldHitBox.contains(aroundNewLoc)) { return false; @@ -381,7 +381,7 @@ private boolean checkChests(Material mBlock, MovecraftLocation newLoc) { } aroundNewLoc = newLoc.translate(0, 0, -1); - testMaterial = craft.getW().getBlockAt(aroundNewLoc.getX(), aroundNewLoc.getY(), aroundNewLoc.getZ()).getType(); + testMaterial = craft.getWorld().getBlockAt(aroundNewLoc.getX(), aroundNewLoc.getY(), aroundNewLoc.getZ()).getType(); return !testMaterial.equals(mBlock) || oldHitBox.contains(aroundNewLoc); } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java index 6cbfd8288..3d91f285a 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java @@ -180,7 +180,7 @@ protected void execute() { int testY = minY; while (testY > 0){ testY--; - if (!craft.getW().getBlockAt(middle.getX(),testY,middle.getZ()).getType().name().endsWith("AIR")) + if (!craft.getWorld().getBlockAt(middle.getX(),testY,middle.getZ()).getType().name().endsWith("AIR")) break; } if (minY - testY > craft.getType().getMaxHeightAboveGround()) { @@ -215,7 +215,7 @@ public void run() { } Block fuelHolder = null; for (MovecraftLocation bTest : oldHitBox) { - Block b = craft.getW().getBlockAt(bTest.getX(), bTest.getY(), bTest.getZ()); + Block b = craft.getWorld().getBlockAt(bTest.getX(), bTest.getY(), bTest.getZ()); //Get all fuel holders if (b.getType() == Material.FURNACE) { InventoryHolder holder = (InventoryHolder) b.getState(); @@ -265,7 +265,7 @@ public void run() { MovecraftLocation midPoint = oldHitBox.getMidPoint(); int centreMinY = oldHitBox.getLocalMinY(midPoint.getX(), midPoint.getZ()); int groundY = centreMinY; - World w = craft.getW(); + World w = craft.getWorld(); while (w.getBlockAt(midPoint.getX(), groundY - 1, midPoint.getZ()).getType() == Material.AIR || craft.getType().getPassthroughBlocks().contains(w.getBlockAt(midPoint.getX(), groundY - 1, midPoint.getZ()).getType())){ groundY--; } @@ -304,15 +304,15 @@ public void run() { newHitBox.add(newLocation); continue; } - final Block b = newLocation.toBukkit(craft.getW()).getBlock(); + final Block b = newLocation.toBukkit(craft.getWorld()).getBlock(); final Material testMaterial = b.getType(); if ((testMaterial.equals(Material.CHEST) || testMaterial.equals(Material.TRAPPED_CHEST)) && checkChests(testMaterial, newLocation)) { //prevent chests collision - fail(String.format(I18nSupport.getInternationalisedString("Translation - Failed Craft is obstructed") + " @ %d,%d,%d,%s", newLocation.getX(), newLocation.getY(), newLocation.getZ(), newLocation.toBukkit(craft.getW()).getBlock().getType().toString())); + fail(String.format(I18nSupport.getInternationalisedString("Translation - Failed Craft is obstructed") + " @ %d,%d,%d,%s", newLocation.getX(), newLocation.getY(), newLocation.getZ(), newLocation.toBukkit(craft.getWorld()).getBlock().getType().toString())); return; } - if (!withinWorldBorder(craft.getW(), newLocation)) { + if (!withinWorldBorder(craft.getWorld(), newLocation)) { fail(I18nSupport.getInternationalisedString("Translation - Failed Craft cannot pass world border") + String.format(" @ %d,%d,%d", newLocation.getX(), newLocation.getY(), newLocation.getZ())); return; } @@ -330,12 +330,12 @@ public void run() { boolean ignoreBlock = false; // air never obstructs anything (changed 4/18/2017 to prevent drilling machines) - if (oldLocation.toBukkit(craft.getW()).getBlock().getType().equals(Material.AIR) && blockObstructed) { + if (oldLocation.toBukkit(craft.getWorld()).getBlock().getType().equals(Material.AIR) && blockObstructed) { ignoreBlock = true; } if (blockObstructed && !harvestBlocks.isEmpty() && harvestBlocks.contains(testMaterial)) { - Material tmpType = oldLocation.toBukkit(craft.getW()).getBlock().getType(); + Material tmpType = oldLocation.toBukkit(craft.getWorld()).getBlock().getType(); if (harvesterBladeBlocks.size() > 0 && harvesterBladeBlocks.contains(tmpType)) { blockObstructed = false; harvestedBlocks.add(newLocation); @@ -366,10 +366,10 @@ public void run() { if (craft.getType().getForbiddenHoverOverBlocks().size() > 0){ MovecraftLocation test = new MovecraftLocation(newHitBox.getMidPoint().getX(), newHitBox.getMinY(), newHitBox.getMidPoint().getZ()); test = test.translate(0, -1, 0); - while (test.toBukkit(craft.getW()).getBlock().getType() == Material.AIR){ + while (test.toBukkit(craft.getWorld()).getBlock().getType() == Material.AIR){ test = test.translate(0, -1, 0); } - Material testType = test.toBukkit(craft.getW()).getBlock().getType(); + Material testType = test.toBukkit(craft.getWorld()).getBlock().getType(); if (craft.getType().getForbiddenHoverOverBlocks().contains(testType)){ fail(String.format(I18nSupport.getInternationalisedString("Translation - Failed Craft over block"), testType.name().toLowerCase().replace("_", " "))); } @@ -384,7 +384,7 @@ public void run() { if(craft.getSinking()){ List air = new ArrayList<>(); for(MovecraftLocation location: oldHitBox){ - if(location.toBukkit(craft.getW()).getBlock().getType() == Material.AIR){ + if(location.toBukkit(craft.getWorld()).getBlock().getType() == Material.AIR){ air.add(location.translate(dx,dy,dz)); } } @@ -394,7 +394,7 @@ public void run() { if (System.currentTimeMillis() - craft.getOrigPilotTime() <= 1000) { continue; } - Location loc = location.toBukkit(craft.getW()); + Location loc = location.toBukkit(craft.getWorld()); if (!loc.getBlock().getType().equals(Material.AIR) && ThreadLocalRandom.current().nextDouble(1) < .05) { updates.add(new ExplosionUpdateCommand( loc, craft.getType().getExplodeOnCrash())); collisionExplosion = true; @@ -421,8 +421,8 @@ public void run() { }*/ int potEffRange = craft.getType().getEffectRange(); Map potionEffects = craft.getType().getPotionEffectsToApply(); - Location oldLocation = location.translate(-dx,-dy,-dz).toBukkit(craft.getW()); - Location newLocation = location.toBukkit(craft.getW()); + Location oldLocation = location.translate(-dx,-dy,-dz).toBukkit(craft.getWorld()); + Location newLocation = location.toBukkit(craft.getWorld()); if (!oldLocation.getBlock().getType().equals(Material.AIR)) { updates.add(new ExplosionUpdateCommand(newLocation, explosionForce)); if (potEffRange != 0 && !potionEffects.isEmpty()) @@ -439,10 +439,10 @@ public void run() { for(MovecraftLocation location : oldHitBox){ Pair phaseBlock = craft.getPhaseBlocks().getOrDefault(location, new Pair<>(Material.AIR, Settings.IsLegacy ? (byte) 0 : Bukkit.createBlockData(Material.AIR))); if (Settings.IsLegacy) { - updates.add(new BlockCreateCommand(craft.getW(), location, phaseBlock.getLeft(), (byte) phaseBlock.getRight())); + updates.add(new BlockCreateCommand(craft.getWorld(), location, phaseBlock.getLeft(), (byte) phaseBlock.getRight())); continue; } - updates.add(new BlockCreateCommand(craft.getW(), location, phaseBlock.getLeft(), (BlockData) phaseBlock.getRight())); + updates.add(new BlockCreateCommand(craft.getWorld(), location, phaseBlock.getLeft(), (BlockData) phaseBlock.getRight())); } newHitBox = new BitmapHitBox(); @@ -489,13 +489,13 @@ private void fail(@NotNull String message, boolean playSound) { craft.setTranslating(false); } if (craft.getDisabled()) { - craft.getW().playSound(location, Settings.IsLegacy ? (Settings.IsPre1_9 ? LegacyUtils.IRONGOLEM_DEATH : LegacyUtils.ENITIY_IRONGOLEM_DEATH) : Sound.ENTITY_IRON_GOLEM_DEATH, 5.0f, 5.0f); + craft.getWorld().playSound(location, Settings.IsLegacy ? (Settings.IsPre1_9 ? LegacyUtils.IRONGOLEM_DEATH : LegacyUtils.ENITIY_IRONGOLEM_DEATH) : Sound.ENTITY_IRON_GOLEM_DEATH, 5.0f, 5.0f); return; } if (!playSound) { return; } - craft.getW().playSound(location, craft.getType().getCollisionSound(), 1.0f, 0.25f); + craft.getWorld().playSound(location, craft.getType().getCollisionSound(), 1.0f, 0.25f); } private static final MovecraftLocation[] SHIFTS = { @@ -507,7 +507,7 @@ private void fail(@NotNull String message, boolean playSound) { private boolean checkChests(Material mBlock, MovecraftLocation newLoc) { for(MovecraftLocation shift : SHIFTS){ MovecraftLocation aroundNewLoc = newLoc.add(shift); - Material testMaterial = craft.getW().getBlockAt(aroundNewLoc.getX(), aroundNewLoc.getY(), aroundNewLoc.getZ()).getType(); + Material testMaterial = craft.getWorld().getBlockAt(aroundNewLoc.getX(), aroundNewLoc.getY(), aroundNewLoc.getZ()).getType(); if (testMaterial.equals(mBlock) && !oldHitBox.contains(aroundNewLoc)) { return true; } @@ -525,14 +525,14 @@ public void run() { ArrayList chests = new ArrayList<>(); //find chests for (MovecraftLocation loc : oldHitBox) { - Block block = craft.getW().getBlockAt(loc.getX(), loc.getY(), loc.getZ()); + Block block = craft.getWorld().getBlockAt(loc.getX(), loc.getY(), loc.getZ()); if (block.getType() == Material.CHEST || block.getType() == Material.TRAPPED_CHEST) chests.add(((InventoryHolder) (block.getState())).getInventory()); } for (MovecraftLocation harvestedBlock : harvestedBlocks) { - Block block = craft.getW().getBlockAt(harvestedBlock.getX(), harvestedBlock.getY(), harvestedBlock.getZ()); + Block block = craft.getWorld().getBlockAt(harvestedBlock.getX(), harvestedBlock.getY(), harvestedBlock.getZ()); List drops = new ArrayList<>(block.getDrops()); if (Settings.IsLegacy) { @@ -567,13 +567,13 @@ public void run() { } } //call event - final ItemHarvestEvent harvestEvent = new ItemHarvestEvent(craft, drops, harvestedBlock.toBukkit(craft.getW())); + final ItemHarvestEvent harvestEvent = new ItemHarvestEvent(craft, drops, harvestedBlock.toBukkit(craft.getWorld())); Bukkit.getServer().getPluginManager().callEvent(harvestEvent); for (ItemStack drop : drops) { ItemStack retStack = putInToChests(drop, chests); if (retStack != null) //drop items on position - updates.add(new ItemDropUpdateCommand(new Location(craft.getW(), harvestedBlock.getX(), harvestedBlock.getY(), harvestedBlock.getZ()), retStack)); + updates.add(new ItemDropUpdateCommand(new Location(craft.getWorld(), harvestedBlock.getX(), harvestedBlock.getY(), harvestedBlock.getZ()), retStack)); } } } @@ -614,7 +614,7 @@ private MovecraftLocation surfaceLoc(MovecraftLocation ml) { Material testType; do { surfaceLoc = surfaceLoc.translate(0, 1, 0); - testType = surfaceLoc.toBukkit(craft.getW()).getBlock().getType(); + testType = surfaceLoc.toBukkit(craft.getWorld()).getBlock().getType(); } while ((testType != Material.AIR && !craft.getType().getPassthroughBlocks().contains(testType) && !oldHitBox.contains(surfaceLoc)) && @@ -636,11 +636,11 @@ private int inclineCraft(BitmapHitBox hitBox){ int elevation = 0; for (MovecraftLocation ml : collisionBox){ - Material testType = ml.toBukkit(craft.getW()).getBlock().getType(); + Material testType = ml.toBukkit(craft.getWorld()).getBlock().getType(); if (testType == Material.AIR || craft.getType().getPassthroughBlocks().contains(testType) || (craft.getType().getHarvestBlocks().contains(testType) && - craft.getType().getHarvesterBladeBlocks().contains(ml.translate(-dx, -dy, -dz).toBukkit(craft.getW()).getBlock().getType()))) { + craft.getType().getHarvesterBladeBlocks().contains(ml.translate(-dx, -dy, -dz).toBukkit(craft.getWorld()).getBlock().getType()))) { continue; } MovecraftLocation surfaceLoc = surfaceLoc(ml); @@ -680,11 +680,11 @@ private int dropDistance (BitmapHitBox hitBox) { final MovecraftLocation translated = ml.translate(dx, dy, dz); //This has to be subtracted by one, or non-passthrough blocks will be within the y drop path //obstructing the craft - Material testType = translated.translate(0, dropDistance , 0).toBukkit(craft.getW()).getBlock().getType(); + Material testType = translated.translate(0, dropDistance , 0).toBukkit(craft.getWorld()).getBlock().getType(); hitGround = testType != Material.AIR && !craft.getType().getPassthroughBlocks().contains(testType) && !(craft.getType().getHarvestBlocks().contains(testType) && - craft.getType().getHarvesterBladeBlocks().contains(ml.translate(0, 1, 0).toBukkit(craft.getW()).getBlock().getType())) || + craft.getType().getHarvesterBladeBlocks().contains(ml.translate(0, 1, 0).toBukkit(craft.getWorld()).getBlock().getType())) || craft.getType().getMinHeightLimit() == translated.translate(0, dropDistance + 1 , 0).getY(); if (hitGround) { @@ -720,13 +720,13 @@ private boolean isOnGround(BitmapHitBox hitBox){ boolean bottomLocsOnGround = false; for (MovecraftLocation bottomLoc : bottomLocs){ translatedBottomLocs.add(bottomLoc.translate(dx, dy, dz)); - Material testType = bottomLoc.translate(0, -1, 0).toBukkit(craft.getW()).getBlock().getType(); + Material testType = bottomLoc.translate(0, -1, 0).toBukkit(craft.getWorld()).getBlock().getType(); //If the lowest part of the bottom locs touch the ground, return true anyways if (testType.name().endsWith("AIR")){ continue; } else if (craft.getType().getPassthroughBlocks().contains(testType)) { continue; - } else if (craft.getType().getHarvestBlocks().contains(testType) && craft.getType().getHarvesterBladeBlocks().contains(bottomLoc.toBukkit(craft.getW()).getBlock().getType())) { + } else if (craft.getType().getHarvestBlocks().contains(testType) && craft.getType().getHarvesterBladeBlocks().contains(bottomLoc.toBukkit(craft.getWorld()).getBlock().getType())) { continue; } @@ -735,13 +735,13 @@ private boolean isOnGround(BitmapHitBox hitBox){ boolean translatedBottomLocsInAir = true; for (MovecraftLocation translatedBottomLoc : translatedBottomLocs){ MovecraftLocation beneath = translatedBottomLoc.translate(0, -1, 0); - Material testType = beneath.toBukkit(craft.getW()).getBlock().getType(); + Material testType = beneath.toBukkit(craft.getWorld()).getBlock().getType(); final CraftType type = craft.getType(); if (hitBox.contains(beneath) || bottomLocs.contains(beneath) || testType == Material.AIR || type.getPassthroughBlocks().contains(testType) || - (type.getHarvestBlocks().contains(testType) && type.getHarvesterBladeBlocks().contains(translatedBottomLoc.translate(-dx, -dy, -dz).toBukkit(craft.getW()).getBlock().getType()))){ + (type.getHarvestBlocks().contains(testType) && type.getHarvesterBladeBlocks().contains(translatedBottomLoc.translate(-dx, -dy, -dz).toBukkit(craft.getWorld()).getBlock().getType()))){ continue; } translatedBottomLocsInAir = false; diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/ManOverboardCommand.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/ManOverboardCommand.java index faee9bbed..7b9170cbb 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/ManOverboardCommand.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/ManOverboardCommand.java @@ -47,7 +47,7 @@ public boolean onCommand(CommandSender commandSender, Command command, String s, } else { telPoint = getCraftTeleportPoint(craft); } - if (craft.getW() != player.getWorld()) { + if (craft.getWorld() != player.getWorld()) { player.sendMessage(MOVECRAFT_COMMAND_PREFIX + I18nSupport.getInternationalisedString("ManOverboard - Other World")); return true; } @@ -76,6 +76,6 @@ private Location getCraftTeleportPoint(Craft craft) { double telX = (craft.getHitBox().getMinX() + craft.getHitBox().getMaxX())/2D; double telZ = (craft.getHitBox().getMinZ() + craft.getHitBox().getMaxZ())/2D; double telY = craft.getHitBox().getMaxY(); - return new Location(craft.getW(), telX, telY, telZ); + return new Location(craft.getWorld(), telX, telY, telZ); } } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/CraftManager.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/CraftManager.java index 198a4494f..a52ec78a4 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/CraftManager.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/CraftManager.java @@ -200,7 +200,7 @@ public void forceRemoveCraft(@NotNull Craft c) { public Set getCraftsInWorld(@NotNull World w) { Set crafts = new HashSet<>(); for(Craft c : this.craftList){ - if(c.getW() == w) + if(c.getWorld() == w) crafts.add(c); } return crafts; diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/ICraft.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/ICraft.java index 415a3f9de..5c8440410 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/ICraft.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/ICraft.java @@ -68,13 +68,13 @@ public void rotate(Rotation rotation, MovecraftLocation originPoint) { return; } setLastRotateTime(System.nanoTime()); - RotationTask task = new RotationTask(this, originPoint, rotation, this.getW()); + RotationTask task = new RotationTask(this, originPoint, rotation, this.getWorld()); Movecraft.getInstance().getAsyncManager().submitTask(task, this); } @Override public void rotate(Rotation rotation, MovecraftLocation originPoint, boolean isSubCraft) { - RotationTask task = new RotationTask(this, originPoint, rotation, this.getW(), isSubCraft); + RotationTask task = new RotationTask(this, originPoint, rotation, this.getWorld(), isSubCraft); Movecraft.getInstance().getAsyncManager().submitTask(task, this); } @@ -82,7 +82,7 @@ public void rotate(Rotation rotation, MovecraftLocation originPoint, boolean isS @Override public Set getContacts() { final Set contacts = new HashSet<>(); - for (Craft contact : CraftManager.getInstance().getCraftsInWorld(w)) { + for (Craft contact : CraftManager.getInstance().getCraftsInWorld(world)) { if (contact.getNotificationPlayer() == this.getNotificationPlayer()) { continue; } @@ -107,7 +107,7 @@ public Set getContacts() { @Override public void resetSigns(@NotNull Sign clicked) { for (final MovecraftLocation ml : hitBox) { - final Block b = ml.toBukkit(w).getBlock(); + final Block b = ml.toBukkit(world).getBlock(); if (!(b.getState() instanceof Sign)) { continue; } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/InteractListener.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/InteractListener.java index d07b0c098..ac5331e38 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/InteractListener.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/InteractListener.java @@ -87,7 +87,7 @@ public void onPlayerInteractStick(PlayerInteractEvent event) { // if the craft should go slower underwater, make time // pass more slowly there - if (craft.getType().getHalfSpeedUnderwater() && craft.getHitBox().getMinY() < craft.getW().getSeaLevel()) + if (craft.getType().getHalfSpeedUnderwater() && craft.getHitBox().getMinY() < craft.getWorld().getSeaLevel()) ticksElapsed = ticksElapsed >> 1; if (Math.abs(ticksElapsed) < craft.getType().getTickCooldown()) { diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/PlayerListener.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/PlayerListener.java index bb6993ad2..db2c339b0 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/PlayerListener.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/PlayerListener.java @@ -72,7 +72,7 @@ private String checkCraftBorders(Craft craft) { if (craft.getHitBox().contains(test)){ continue; } - Block testBlock = test.toBukkit(craft.getW()).getBlock(); + Block testBlock = test.toBukkit(craft.getWorld()).getBlock(); Material type = testBlock.getType(); byte metaData = testBlock.getData(); //Break the loop if an allowed block is found adjacent to the craft's hitbox diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/BlockCreateCommand.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/BlockCreateCommand.java index 685c02750..4cd6ead67 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/BlockCreateCommand.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/BlockCreateCommand.java @@ -26,7 +26,7 @@ public BlockCreateCommand(@NotNull MovecraftLocation newBlockLocation, @NotNull this.newBlockLocation = newBlockLocation; this.type = type; this.dataID = dataID; - this.world = craft.getW(); + this.world = craft.getWorld(); bData = null; } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftRotateCommand.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftRotateCommand.java index 3a7ac5dd5..fd5945502 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftRotateCommand.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftRotateCommand.java @@ -81,13 +81,13 @@ public void doUpdate() { } } else if (craft.getType().getMoveEntities() && !craft.getSinking()) { - Location tOP = originLocation.toBukkit(craft.getW()); + Location tOP = originLocation.toBukkit(craft.getWorld()); tOP.setX(tOP.getBlockX() + 0.5); tOP.setZ(tOP.getBlockZ() + 0.5); - Location midpoint = originalLocations.getMidPoint().toBukkit(craft.getW()); + Location midpoint = originalLocations.getMidPoint().toBukkit(craft.getWorld()); Entity vehicle; Entity playerVehicle = null; - for(Entity entity : craft.getW().getNearbyEntities(midpoint, originalLocations.getXLength()/2.0 + 1, originalLocations.getYLength()/2.0 + 2, originalLocations.getZLength()/2.0 + 1)){ + for(Entity entity : craft.getWorld().getNearbyEntities(midpoint, originalLocations.getXLength()/2.0 + 1, originalLocations.getYLength()/2.0 + 2, originalLocations.getZLength()/2.0 + 1)){ // Player is onboard this craft Location adjustedPLoc = entity.getLocation().subtract(tOP); @@ -135,7 +135,7 @@ public void doUpdate() { final HitBox to = craft.getHitBox().difference(originalLocations); for (MovecraftLocation location : to) { - Block b = location.toBukkit(craft.getW()).getBlock(); + Block b = location.toBukkit(craft.getWorld()).getBlock(); Material material = b.getType(); Object data = Settings.IsLegacy ? b.getData() : b.getBlockData(); if (passthroughBlocks.contains(material)) { @@ -194,7 +194,7 @@ public void doUpdate() { final WorldHandler handler = Movecraft.getInstance().getWorldHandler(); for (MovecraftLocation location : invertedHitBox.difference(exterior)) { - Block b = location.toBukkit(craft.getW()).getBlock(); + Block b = location.toBukkit(craft.getWorld()).getBlock(); Material material = b.getType(); Object data = Settings.IsLegacy ? b.getData() : b.getBlockData(); if (!passthroughBlocks.contains(material)) { @@ -215,24 +215,24 @@ public void doUpdate() { continue; } Pair phaseBlock = craft.getPhaseBlocks().remove(location); - handler.setBlockFast(location.toBukkit(craft.getW()), phaseBlock.getLeft(), phaseBlock.getRight()); + handler.setBlockFast(location.toBukkit(craft.getWorld()), phaseBlock.getLeft(), phaseBlock.getRight()); craft.getPhaseBlocks().remove(location); } for(MovecraftLocation location : originalLocations.boundingHitBox()){ if(!craft.getHitBox().inBounds(location) && craft.getPhaseBlocks().containsKey(location)){ Pair phaseBlock = craft.getPhaseBlocks().remove(location); - handler.setBlockFast(location.toBukkit(craft.getW()), phaseBlock.getLeft(), phaseBlock.getRight()); + handler.setBlockFast(location.toBukkit(craft.getWorld()), phaseBlock.getLeft(), phaseBlock.getRight()); } } for (MovecraftLocation location : interior) { - Block b = location.toBukkit(craft.getW()).getBlock(); + Block b = location.toBukkit(craft.getWorld()).getBlock(); Material material = b.getType(); Object data = Settings.IsLegacy ? b.getData() : b.getBlockData(); if (passthroughBlocks.contains(material)) { craft.getPhaseBlocks().put(location, new Pair<>(material, data)); - handler.setBlockFast(location.toBukkit(craft.getW()), Material.AIR, (byte) 0); + handler.setBlockFast(location.toBukkit(craft.getWorld()), Material.AIR, (byte) 0); } } @@ -254,7 +254,7 @@ public void doUpdate() { private void sendSignEvents(){ Map> signs = new HashMap<>(); for (MovecraftLocation location : craft.getHitBox()) { - Block block = location.toBukkit(craft.getW()).getBlock(); + Block block = location.toBukkit(craft.getWorld()).getBlock(); if (SignUtils.isSign(block)) { Sign sign = (Sign) block.getState(); if(!signs.containsKey(sign.getLines())) @@ -265,7 +265,7 @@ private void sendSignEvents(){ for(Map.Entry> entry : signs.entrySet()){ Bukkit.getServer().getPluginManager().callEvent(new SignTranslateEvent(craft, entry.getKey(), entry.getValue())); for(MovecraftLocation loc : entry.getValue()){ - Block block = loc.toBukkit(craft.getW()).getBlock(); + Block block = loc.toBukkit(craft.getWorld()).getBlock(); if (!SignUtils.isSign(block)) { continue; } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftTranslateCommand.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftTranslateCommand.java index aa016a9e5..3dd7f71e0 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftTranslateCommand.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftTranslateCommand.java @@ -78,8 +78,8 @@ public void doUpdate() { } } else if (craft.getType().getMoveEntities() && !craft.getSinking()){ - final Location midpoint = craft.getHitBox().getMidPoint().subtract(displacement).toBukkit(craft.getW()).add(.5,.5,.5); - final Collection entities = craft.getW().getNearbyEntities(midpoint, craft.getHitBox().getXLength() / 2.0 + 1, craft.getHitBox().getYLength() / 2.0 + 2, craft.getHitBox().getZLength() / 2.0 + 1); + final Location midpoint = craft.getHitBox().getMidPoint().subtract(displacement).toBukkit(craft.getWorld()).add(.5,.5,.5); + final Collection entities = craft.getWorld().getNearbyEntities(midpoint, craft.getHitBox().getXLength() / 2.0 + 1, craft.getHitBox().getYLength() / 2.0 + 2, craft.getHitBox().getZLength() / 2.0 + 1); Entity vehicle; Entity playerVehicle = null; for (Entity entity : entities){ @@ -126,7 +126,7 @@ public void doUpdate() { final HitBox to = craft.getHitBox().difference(originalLocations); //place phased blocks for (MovecraftLocation location : to) { - Block b = location.toBukkit(craft.getW()).getBlock(); + Block b = location.toBukkit(craft.getWorld()).getBlock(); Material material = b.getType(); Object data = Settings.IsLegacy ? b.getData() : b.getBlockData(); if (passthroughBlocks.contains(material)) { @@ -183,7 +183,7 @@ public void doUpdate() { final WorldHandler handler = Movecraft.getInstance().getWorldHandler(); for (MovecraftLocation location : invertedHitBox.difference(confirmed)) { - Block b = location.toBukkit(craft.getW()).getBlock(); + Block b = location.toBukkit(craft.getWorld()).getBlock(); Material material = b.getType(); Object data = Settings.IsLegacy ? b.getData() : b.getBlockData(); if (!passthroughBlocks.contains(material)) { @@ -216,24 +216,24 @@ public void doUpdate() { continue; Pair phaseBlock = craft.getPhaseBlocks().remove(location); - handler.setBlockFast(location.toBukkit(craft.getW()), phaseBlock.getLeft(), phaseBlock.getRight()); + handler.setBlockFast(location.toBukkit(craft.getWorld()), phaseBlock.getLeft(), phaseBlock.getRight()); craft.getPhaseBlocks().remove(location); } for(MovecraftLocation location : originalLocations){ if(!craft.getHitBox().contains(location) && craft.getPhaseBlocks().containsKey(location)){ Pair phaseBlock = craft.getPhaseBlocks().remove(location); - handler.setBlockFast(location.toBukkit(craft.getW()), phaseBlock.getLeft(), phaseBlock.getRight()); + handler.setBlockFast(location.toBukkit(craft.getWorld()), phaseBlock.getLeft(), phaseBlock.getRight()); } } for (MovecraftLocation location : failed) { - Block b = location.toBukkit(craft.getW()).getBlock(); + Block b = location.toBukkit(craft.getWorld()).getBlock(); Material material = b.getType(); Object data = Settings.IsLegacy ? b.getData() : b.getBlockData(); if (passthroughBlocks.contains(material)) { craft.getPhaseBlocks().put(location, new Pair<>(material, data)); - handler.setBlockFast(location.toBukkit(craft.getW()), Material.AIR, (byte) 0); + handler.setBlockFast(location.toBukkit(craft.getWorld()), Material.AIR, (byte) 0); } } @@ -262,7 +262,7 @@ public void doUpdate() { private void sendSignEvents(){ Map> signs = new HashMap<>(); for (MovecraftLocation location : craft.getHitBox()) { - Block block = location.toBukkit(craft.getW()).getBlock(); + Block block = location.toBukkit(craft.getWorld()).getBlock(); if (SignUtils.isSign(block)) { Sign sign = (Sign) block.getState(); if(!signs.containsKey(sign.getLines())) @@ -273,7 +273,7 @@ private void sendSignEvents(){ for(Map.Entry> entry : signs.entrySet()){ Bukkit.getServer().getPluginManager().callEvent(new SignTranslateEvent(craft, entry.getKey(), entry.getValue())); for(MovecraftLocation loc : entry.getValue()){ - Block block = loc.toBukkit(craft.getW()).getBlock(); + Block block = loc.toBukkit(craft.getWorld()).getBlock(); if (!(block.getState() instanceof Sign)) { continue; } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/WorldEdit7UpdateCommand.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/WorldEdit7UpdateCommand.java index 4beaafeae..f5871d9c0 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/WorldEdit7UpdateCommand.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/WorldEdit7UpdateCommand.java @@ -36,10 +36,10 @@ public WorldEdit7UpdateCommand(BaseBlock baseBlock, World world, MovecraftLocati @Override public void doUpdate() { Block block = world.getBlockAt(location.getX(), location.getY(), location.getZ()); - block.setType(type); + block.setType(type, false); assert baseBlock != null; BlockData bData = BukkitAdapter.adapt(baseBlock); - block.setBlockData(bData); + block.setBlockData(bData, false); if (Settings.Debug){ Bukkit.broadcastMessage(String.format("Material: %s, Location: %s",type.name().toLowerCase().replace("_", " "),location.toString())); } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/WorldEditUpdateCommand.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/WorldEditUpdateCommand.java index a117bd86b..b47343c2a 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/WorldEditUpdateCommand.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/WorldEditUpdateCommand.java @@ -35,7 +35,7 @@ public WorldEditUpdateCommand(BaseBlock worldEditBaseBlock, World world, Movecra @Override public void doUpdate() { - world.getBlockAt(location.getX(), location.getY(), location.getZ()).setType(type); + world.getBlockAt(location.getX(), location.getY(), location.getZ()).setType(type, false); LegacyUtils.setData(world.getBlockAt(location.getX(), location.getY(), location.getZ()), data); Block block = location.toBukkit(world).getBlock(); // put inventory into dispensers if its a repair diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/AscendSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/AscendSign.java index 3aeabf395..9da8ffa6d 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/AscendSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/AscendSign.java @@ -19,7 +19,7 @@ public class AscendSign implements Listener { @EventHandler public void onCraftDetect(CraftDetectEvent event){ - World world = event.getCraft().getW(); + World world = event.getCraft().getWorld(); for(MovecraftLocation location: event.getCraft().getHitBox()){ Block block = location.toBukkit(world).getBlock(); if(!SignUtils.isSign(block)){ diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/ContactsSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/ContactsSign.java index 62b4748ef..449c10d84 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/ContactsSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/ContactsSign.java @@ -16,7 +16,7 @@ public class ContactsSign implements Listener{ @EventHandler public void onCraftDetect(CraftDetectEvent event){ - World world = event.getCraft().getW(); + World world = event.getCraft().getWorld(); for(MovecraftLocation location: event.getCraft().getHitBox()){ Block block = location.toBukkit(world).getBlock(); if(!SignUtils.isSign(block)){ diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CrewSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CrewSign.java index 1fd231653..974a093df 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CrewSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CrewSign.java @@ -52,8 +52,8 @@ public final void onSignTranslate(SignTranslateEvent event) { } Location valid = null; for(MovecraftLocation location : event.getLocations()){ - Location bedLoc = location.toBukkit(craft.getW()).subtract(0,1,0); - Material bedType = craft.getW().getBlockAt(bedLoc).getType(); + Location bedLoc = location.toBukkit(craft.getWorld()).subtract(0,1,0); + Material bedType = craft.getWorld().getBlockAt(bedLoc).getType(); if (Settings.IsLegacy ? bedType.equals(LegacyUtils.BED_BLOCK) : Arrays.binarySearch(beds, bedType) >= 0) { valid = bedLoc; break; @@ -128,7 +128,7 @@ public final void onPlayerRespawn(PlayerRespawnEvent event) { @EventHandler public void onCraftDetect(CraftDetectEvent event){ - World world = event.getCraft().getW(); + World world = event.getCraft().getWorld(); for(MovecraftLocation location: event.getCraft().getHitBox()){ Block block = location.toBukkit(world).getBlock(); if (!(block.getState() instanceof Sign)) { diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CruiseSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CruiseSign.java index e361913eb..3e1e9fbe0 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CruiseSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CruiseSign.java @@ -24,7 +24,7 @@ public final class CruiseSign implements Listener{ @EventHandler public void onCraftDetect(CraftDetectEvent event){ - World world = event.getCraft().getW(); + World world = event.getCraft().getWorld(); for(MovecraftLocation location: event.getCraft().getHitBox()){ Block block = location.toBukkit(world).getBlock(); if(!SignUtils.isSign(block)){ diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/DescendSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/DescendSign.java index bd44c76ab..334c84a2b 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/DescendSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/DescendSign.java @@ -19,7 +19,7 @@ public final class DescendSign implements Listener{ @EventHandler public void onCraftDetect(CraftDetectEvent event){ - World world = event.getCraft().getW(); + World world = event.getCraft().getWorld(); for(MovecraftLocation location: event.getCraft().getHitBox()){ Block block = location.toBukkit(world).getBlock(); if(!SignUtils.isSign(block)){ diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/NameSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/NameSign.java index 4beafc8f1..0f7a6000a 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/NameSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/NameSign.java @@ -25,7 +25,7 @@ public void onCraftDetect(@NotNull CraftDetectEvent event) { return; } - World w = c.getW(); + World w = c.getWorld(); for (MovecraftLocation location : c.getHitBox()) { Block b = location.toBukkit(w).getBlock(); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RepairSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RepairSign.java index d652ad58a..19ec81027 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RepairSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RepairSign.java @@ -152,7 +152,7 @@ private void signRightClick(PlayerInteractEvent event){ int remainingQty = (int) longRemQty; ArrayList chests = new ArrayList<>(); for (MovecraftLocation loc : pCraft.getHitBox()) { - Block b = pCraft.getW().getBlockAt(loc.getX(), loc.getY(), loc.getZ()); + Block b = pCraft.getWorld().getBlockAt(loc.getX(), loc.getY(), loc.getZ()); if ((b.getType() == Material.CHEST) || (b.getType() == Material.TRAPPED_CHEST)) { InventoryHolder inventoryHolder = (InventoryHolder) b.getState(); if (inventoryHolder.getInventory().contains(type.getLeft()) && remainingQty > 0) { diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/SpeedSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/SpeedSign.java index 1c8416d08..3c6f2a940 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/SpeedSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/SpeedSign.java @@ -15,7 +15,7 @@ public final class SpeedSign implements Listener{ @EventHandler public void onCraftDetect(CraftDetectEvent event){ - World world = event.getCraft().getW(); + World world = event.getCraft().getWorld(); for(MovecraftLocation location: event.getCraft().getHitBox()){ Block block = location.toBukkit(world).getBlock(); if(!SignUtils.isSign(block)) { diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/StatusSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/StatusSign.java index adeaaffd0..3c33c3f3e 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/StatusSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/StatusSign.java @@ -26,7 +26,7 @@ public final class StatusSign implements Listener{ @EventHandler public void onCraftDetect(CraftDetectEvent event){ - World world = event.getCraft().getW(); + World world = event.getCraft().getWorld(); for(MovecraftLocation location: event.getCraft().getHitBox()){ Block block = location.toBukkit(world).getBlock(); if(!SignUtils.isSign(block)){ @@ -55,7 +55,7 @@ public final void onSignTranslate(SignTranslateEvent event) { final BlockLimitManager flyBlocks = craft.getType().getFlyBlocks(); Map foundFlyBlocks = new HashMap<>(); for (MovecraftLocation ml : craft.getHitBox()){ - Location loc = ml.toBukkit(craft.getW()); + Location loc = ml.toBukkit(craft.getWorld()); Material testType = loc.getBlock().getType(); byte data = 0; if (Settings.IsLegacy){ diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/towny/TownyCompatManager.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/towny/TownyCompatManager.java index cdd44044d..1ff895989 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/towny/TownyCompatManager.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/towny/TownyCompatManager.java @@ -25,23 +25,23 @@ public class TownyCompatManager implements Listener { public void onCraftTranslate(CraftTranslateEvent event){ final Set townBlocks = new HashSet<>(); final Craft craft = event.getCraft(); - final TownyWorld townyWorld = TownyUtils.getTownyWorld(craft.getW()); + final TownyWorld townyWorld = TownyUtils.getTownyWorld(craft.getWorld()); if (!Settings.TownyBlockMoveOnSwitchPerm) return; for (MovecraftLocation ml : event.getNewHitBox()) { - TownBlock townBlock = TownyUtils.getTownBlock(ml.toBukkit(event.getCraft().getW())); + TownBlock townBlock = TownyUtils.getTownBlock(ml.toBukkit(event.getCraft().getWorld())); if (townBlock == null || townBlocks.contains(townBlock)) { continue; } - if (TownyUtils.validateCraftMoveEvent(craft.getNotificationPlayer(), ml.toBukkit(craft.getW()), townyWorld)) { + if (TownyUtils.validateCraftMoveEvent(craft.getNotificationPlayer(), ml.toBukkit(craft.getWorld()), townyWorld)) { townBlocks.add(townBlock); continue; } Town town = TownyUtils.getTown(townBlock); if (town == null) continue; - final TownyWorldHeightLimits whLim = TownyUtils.getWorldLimits(event.getCraft().getW()); + final TownyWorldHeightLimits whLim = TownyUtils.getWorldLimits(event.getCraft().getWorld()); final Location spawnLoc = TownyUtils.getTownSpawn(townBlock); if (whLim.validate(ml.getY(), spawnLoc.getBlockY())) { continue; @@ -57,23 +57,23 @@ public void onCraftTranslate(CraftTranslateEvent event){ public void onCraftRotate(CraftRotateEvent event) { final Set townBlocks = new HashSet<>(); final Craft craft = event.getCraft(); - final TownyWorld townyWorld = TownyUtils.getTownyWorld(craft.getW()); + final TownyWorld townyWorld = TownyUtils.getTownyWorld(craft.getWorld()); if (!Settings.TownyBlockMoveOnSwitchPerm) return; for (MovecraftLocation ml : event.getNewHitBox()) { - TownBlock townBlock = TownyUtils.getTownBlock(ml.toBukkit(event.getCraft().getW())); + TownBlock townBlock = TownyUtils.getTownBlock(ml.toBukkit(event.getCraft().getWorld())); if (townBlock == null || townBlocks.contains(townBlock)) { continue; } - if (TownyUtils.validateCraftMoveEvent(craft.getNotificationPlayer(), ml.toBukkit(craft.getW()), townyWorld)) { + if (TownyUtils.validateCraftMoveEvent(craft.getNotificationPlayer(), ml.toBukkit(craft.getWorld()), townyWorld)) { townBlocks.add(townBlock); continue; } Town town = TownyUtils.getTown(townBlock); if (town == null) continue; - final TownyWorldHeightLimits whLim = TownyUtils.getWorldLimits(event.getCraft().getW()); + final TownyWorldHeightLimits whLim = TownyUtils.getWorldLimits(event.getCraft().getWorld()); final Location spawnLoc = TownyUtils.getTownSpawn(townBlock); if (whLim.validate(ml.getY(), spawnLoc.getBlockY())) { continue; @@ -88,21 +88,21 @@ public void onCraftRotate(CraftRotateEvent event) { public void onHitboxDetect(CraftDetectEvent event) { final Set townBlocks = new HashSet<>(); final Craft craft = event.getCraft(); - final TownyWorld townyWorld = TownyUtils.getTownyWorld(craft.getW()); + final TownyWorld townyWorld = TownyUtils.getTownyWorld(craft.getWorld()); for (MovecraftLocation ml : event.getCraft().getHitBox()) { - TownBlock townBlock = TownyUtils.getTownBlock(ml.toBukkit(event.getCraft().getW())); + TownBlock townBlock = TownyUtils.getTownBlock(ml.toBukkit(event.getCraft().getWorld())); if (townBlock == null || townBlocks.contains(townBlock)) { continue; } - if (TownyUtils.validateCraftMoveEvent(craft.getNotificationPlayer(), ml.toBukkit(craft.getW()), townyWorld)) { + if (TownyUtils.validateCraftMoveEvent(craft.getNotificationPlayer(), ml.toBukkit(craft.getWorld()), townyWorld)) { townBlocks.add(townBlock); continue; } Town town = TownyUtils.getTown(townBlock); if (town == null) continue; - final TownyWorldHeightLimits whLim = TownyUtils.getWorldLimits(event.getCraft().getW()); + final TownyWorldHeightLimits whLim = TownyUtils.getWorldLimits(event.getCraft().getWorld()); final Location spawnLoc = TownyUtils.getTownSpawn(townBlock); if (whLim.validate(ml.getY(), spawnLoc.getBlockY())) { continue; @@ -124,7 +124,7 @@ public void onCraftSink(CraftSinkEvent event) { return; for (MovecraftLocation ml : hitBox) { - TownBlock townBlock = TownyUtils.getTownBlock(ml.toBukkit(event.getCraft().getW())); + TownBlock townBlock = TownyUtils.getTownBlock(ml.toBukkit(event.getCraft().getWorld())); if (townBlock == null || townBlocks.contains(townBlock)) { continue; } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/WaterlogUtils.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/WaterlogUtils.java index 4a8adf825..1f10402fc 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/WaterlogUtils.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/WaterlogUtils.java @@ -11,19 +11,17 @@ import org.bukkit.block.data.type.Stairs; import org.bukkit.block.data.type.TrapDoor; -import java.util.AbstractMap; - public class WaterlogUtils { - private static AbstractMap.SimpleImmutableEntry DEFAULT_PHASE_BLOCK = new AbstractMap.SimpleImmutableEntry<>(Material.AIR, 0); + private static Pair DEFAULT_PHASE_BLOCK = new Pair<>(Material.AIR, 0); private WaterlogUtils(){ } public static void waterlogBlocksOnCraft(Craft craft, HitBox interior) { for (MovecraftLocation ml : craft.getHitBox()) { - final Material phaseBlock = craft.getPhaseBlocks().getOrDefault(ml, DEFAULT_PHASE_BLOCK).getKey(); + final Material phaseBlock = craft.getPhaseBlocks().getOrDefault(ml, DEFAULT_PHASE_BLOCK).getLeft(); boolean waterlog = phaseBlock == Material.WATER; - Block b = ml.toBukkit(craft.getW()).getBlock(); + Block b = ml.toBukkit(craft.getWorld()).getBlock(); if (!(b.getBlockData() instanceof Waterlogged)) { continue; } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/worldguard/WorldGuardCompatManager.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/worldguard/WorldGuardCompatManager.java index 21aad4a56..8593eb8f1 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/worldguard/WorldGuardCompatManager.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/worldguard/WorldGuardCompatManager.java @@ -65,11 +65,11 @@ public void onCraftTranslateEvent(CraftTranslateEvent event){ if(event.getCraft().getNotificationPlayer() == null) return; for(MovecraftLocation location : event.getNewHitBox()){ - if (canMoveInRegion(location, event.getCraft().getW())) { + if (canMoveInRegion(location, event.getCraft().getWorld())) { continue; } - if(!pilotHasAccessToRegion(event.getCraft().getNotificationPlayer(), location, event.getCraft().getW())){ + if(!pilotHasAccessToRegion(event.getCraft().getNotificationPlayer(), location, event.getCraft().getWorld())){ event.setCancelled(true); event.setFailMessage(String.format( I18nSupport.getInternationalisedString( "Translation - WorldGuard - Not Permitted To Build" )+" @ %d,%d,%d", location.getX(), location.getY(), location.getZ() ) ); return; @@ -85,10 +85,10 @@ public void onCraftRotateEvent(CraftRotateEvent event){ if(event.getCraft().getNotificationPlayer() == null) return; for(MovecraftLocation location : event.getNewHitBox()){ - if (canRotateInRegion(location, event.getCraft().getW())) { + if (canRotateInRegion(location, event.getCraft().getWorld())) { continue; } - if(!pilotHasAccessToRegion(event.getCraft().getNotificationPlayer(), location, event.getCraft().getW())){ + if(!pilotHasAccessToRegion(event.getCraft().getNotificationPlayer(), location, event.getCraft().getWorld())){ event.setCancelled(true); event.setFailMessage(String.format( I18nSupport.getInternationalisedString("Rotation - WorldGuard - Not Permitted To Build" )+" @ %d,%d,%d", location.getX(), location.getY(), location.getZ())); return; @@ -155,15 +155,15 @@ public void onCraftSink(CraftSinkEvent event){ ProtectedRegion region = null; RegionManager regionManager; if (Settings.IsLegacy){ - regionManager = LegacyUtils.getRegionManager(wgPlugin, pcraft.getW()); + regionManager = LegacyUtils.getRegionManager(wgPlugin, pcraft.getWorld()); } else { RegionContainer container = WorldGuard.getInstance().getPlatform().getRegionContainer(); - regionManager = container.get(BukkitAdapter.adapt(pcraft.getW())); + regionManager = container.get(BukkitAdapter.adapt(pcraft.getWorld())); } for (MovecraftLocation location : pcraft.getHitBox()){ ApplicableRegionSet regions; if (Settings.IsLegacy) - regions = LegacyUtils.getApplicableRegions(regionManager, location.toBukkit(pcraft.getW())); + regions = LegacyUtils.getApplicableRegions(regionManager, location.toBukkit(pcraft.getWorld())); else { regions = regionManager.getApplicableRegions(BlockVector3.at(location.getX(), location.getY(), location.getZ())); } @@ -202,15 +202,15 @@ public void onCraftDetect(CraftDetectEvent event) { ProtectedRegion region = null; RegionManager regionManager; if (Settings.IsLegacy){ - regionManager = LegacyUtils.getRegionManager(wgPlugin, pcraft.getW()); + regionManager = LegacyUtils.getRegionManager(wgPlugin, pcraft.getWorld()); } else { RegionContainer container = WorldGuard.getInstance().getPlatform().getRegionContainer(); - regionManager = container.get(BukkitAdapter.adapt(pcraft.getW())); + regionManager = container.get(BukkitAdapter.adapt(pcraft.getWorld())); } for (MovecraftLocation location : pcraft.getHitBox()){ ApplicableRegionSet regions; if (Settings.IsLegacy) - regions = LegacyUtils.getApplicableRegions(regionManager, location.toBukkit(pcraft.getW())); + regions = LegacyUtils.getApplicableRegions(regionManager, location.toBukkit(pcraft.getWorld())); else { regions = regionManager.getApplicableRegions(BlockVector3.at(location.getX(), location.getY(), location.getZ())); } diff --git a/modules/Movecraft/src/main/resources/localisation/movecraftlang_en.properties b/modules/Movecraft/src/main/resources/localisation/movecraftlang_en.properties index 7690578c4..2971dbfa1 100644 --- a/modules/Movecraft/src/main/resources/localisation/movecraftlang_en.properties +++ b/modules/Movecraft/src/main/resources/localisation/movecraftlang_en.properties @@ -87,6 +87,9 @@ Detection\ -\ Too\ much\ flyblock=Too much flyblock Detection\ -\ Not\ Registered\ Pilot=Not one of the registered pilots on this craft Detection\ -\ Craft\ Type\ Cannot\ Be\ Named=Crafts of this type cannot be named Detection\ -\ Failed\ -\ Water\ contact\ required\ but\ not\ found=Detection failed\: Water contact required but not found +Detection\ -\ Forbidden\ sign\ string\ found=Detection Failed\! Forbidden strings found on signs on this craft +Detection\ -\ Too\ many\ signs\ with\ string=Detection Failed\! Too many signs containing the following string(s): +Detection\ -\ Too\ many\ cannons=Detection Failed\! You have too many cannons of the following type on this craft: Economy\ -\ Not\ Enough\ Money=You do not have enough money Internal\ -\ Error\ -\ Processor\ thread\ encountered\ an\ error=Async task generated an exception ManOverboard\ -\ No\ Craft\ Found=No valid craft to ManOverboard to. diff --git a/modules/api/src/main/java/net/countercraft/movecraft/craft/Craft.java b/modules/api/src/main/java/net/countercraft/movecraft/craft/Craft.java index b3236a102..a27cf37f4 100644 --- a/modules/api/src/main/java/net/countercraft/movecraft/craft/Craft.java +++ b/modules/api/src/main/java/net/countercraft/movecraft/craft/Craft.java @@ -54,7 +54,7 @@ public abstract class Craft { @NotNull protected final BitmapHitBox collapsedHitBox; @NotNull protected BitmapHitBox fluidLocations; @NotNull protected final Counter materials; - @NotNull protected World w; + @NotNull protected World world; @NotNull private final AtomicBoolean processing = new AtomicBoolean(); private int maxHeightLimit; private boolean cruising; @@ -85,12 +85,12 @@ public abstract class Craft { public Craft(@NotNull CraftType type, @NotNull World world) { this.type = type; - this.w = world; + this.world = world; this.hitBox = new BitmapHitBox(); this.collapsedHitBox = new BitmapHitBox(); this.fluidLocations = new BitmapHitBox(); - if (type.getMaxHeightLimit() > w.getMaxHeight() - 1) { - this.maxHeightLimit = w.getMaxHeight() - 1; + if (type.getMaxHeightLimit() > world.getMaxHeight() - 1) { + this.maxHeightLimit = world.getMaxHeight() - 1; } else { this.maxHeightLimit = type.getMaxHeightLimit(); } @@ -132,9 +132,23 @@ public CraftType getType() { return type; } + /** + * @deprecated Use getWorld instead + * @return the world this craft is in + */ + @Deprecated @NotNull public World getW() { - return w; + return world; + } + + /** + * Gets the world the craft is currently in + * @return the world this craft is in + */ + @NotNull + public World getWorld() { + return world; } public abstract void detect(Player player, Player notificationPlayer, MovecraftLocation startPoint); @@ -347,7 +361,7 @@ public int getTickCooldown() { // Map counter = new HashMap<>(); if(materials.isEmpty()){ for(MovecraftLocation location : hitBox){ - materials.add(location.toBukkit(w).getBlock().getType()); + materials.add(location.toBukkit(world).getBlock().getType()); } } @@ -428,7 +442,7 @@ public int getWaterLine(){ int posZ; posZ = hitBox.getMinZ() - 1; for (posX = hitBox.getMinX() - 1; posX <= hitBox.getMaxX() + 1; posX++) { - Material type = w.getBlockAt(posX, posY, posZ).getType(); + Material type = world.getBlockAt(posX, posY, posZ).getType(); if (Settings.IsLegacy ? type == Material.STATIONARY_WATER : type == Material.WATER) numWater++; if (Settings.IsLegacy ? type == Material.AIR : (type == Material.AIR || type == Material.getMaterial("CAVE_AIR") || type == Material.getMaterial("VOID_AIR"))) @@ -436,7 +450,7 @@ public int getWaterLine(){ } posZ = hitBox.getMaxZ() + 1; for (posX = hitBox.getMinX() - 1; posX <= hitBox.getMaxX() + 1; posX++) { - Material type = w.getBlockAt(posX, posY, posZ).getType(); + Material type = world.getBlockAt(posX, posY, posZ).getType(); if (Settings.IsLegacy ? type == Material.STATIONARY_WATER : type == Material.WATER) numWater++; if (Settings.IsLegacy ? type == Material.AIR : (type == Material.AIR || type == Material.getMaterial("CAVE_AIR") || type == Material.getMaterial("VOID_AIR"))) @@ -444,7 +458,7 @@ public int getWaterLine(){ } posX = hitBox.getMinX() - 1; for (posZ = hitBox.getMinZ(); posZ <= hitBox.getMaxZ(); posZ++) { - Material type = w.getBlockAt(posX, posY, posZ).getType(); + Material type = world.getBlockAt(posX, posY, posZ).getType(); if (Settings.IsLegacy ? type == Material.STATIONARY_WATER : type == Material.WATER) numWater++; if (Settings.IsLegacy ? type == Material.AIR : (type == Material.AIR || type == Material.getMaterial("CAVE_AIR") || type == Material.getMaterial("VOID_AIR"))) @@ -452,7 +466,7 @@ public int getWaterLine(){ } posX = hitBox.getMaxX() + 1; for (posZ = hitBox.getMinZ(); posZ <= hitBox.getMaxZ(); posZ++) { - Material type = w.getBlockAt(posX, posY, posZ).getType(); + Material type = world.getBlockAt(posX, posY, posZ).getType(); if (Settings.IsLegacy ? type == Material.STATIONARY_WATER : type == Material.WATER) numWater++; if (Settings.IsLegacy ? type == Material.AIR : (type == Material.AIR || type == Material.getMaterial("CAVE_AIR") || type == Material.getMaterial("VOID_AIR"))) @@ -479,6 +493,7 @@ public Map getCrewSigns(){ public String getName(){ return name; } + public void setName(@NotNull String name){ this.name = name; } diff --git a/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java b/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java index 5233facd1..a8efca953 100644 --- a/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java +++ b/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java @@ -23,9 +23,9 @@ import net.countercraft.movecraft.utils.LegacyUtils; import org.bukkit.Bukkit; import org.bukkit.Material; +import org.bukkit.Sound; import org.bukkit.potion.PotionEffect; import org.bukkit.potion.PotionEffectType; -import org.bukkit.Sound; import org.jetbrains.annotations.NotNull; import org.yaml.snakeyaml.Yaml; @@ -34,7 +34,6 @@ import java.io.IOException; import java.io.InputStream; import java.util.*; -import java.util.logging.Level; final public class CraftType { private final boolean blockedByWater; @@ -104,7 +103,8 @@ final public class CraftType { @NotNull private final Set passthroughBlocks; @NotNull private final int effectRange; @NotNull private final Map potionEffectsToApply; - @NotNull private final Map potionEffectDelays = Collections.emptyMap(); + @NotNull private final Map, Double> maxSignsWithString; + @NotNull private final Map, Double> maxCannons; @NotNull private final Set forbiddenHoverOverBlocks; private final int gravityDropDistance; private final int gravityInclineDistance; @@ -125,114 +125,87 @@ public CraftType(File f) throws CraftTypeException{ try { - //Required craft flags - craftName = (String) data.get("name"); - maxSize = integerFromObject(data.get("maxSize")); - minSize = integerFromObject(data.get("minSize")); - allowedBlocks = new BlockContainer(data.get("allowedBlocks")); - - forbiddenBlocks = data.containsKey("forbiddenBlocks") ? new BlockContainer(data.get("forbiddenBlocks")) : new BlockContainer();; - forbiddenSignStrings = stringListFromObject(data.get("forbiddenSignStrings")); - tickCooldown = (int) Math.ceil(20 / (doubleFromObject(data.get("speed")))); - flyBlocks = new BlockLimitManager(data.get("flyblocks")); - - //Optional craft flags - blockedByWater = (boolean) (data.containsKey("canFly") ? data.get("canFly") : data.getOrDefault("blockedByWater", true)); - requireWaterContact = (boolean) data.getOrDefault("requireWaterContact", false); - tryNudge = (boolean) data.getOrDefault("tryNudge", false); - moveBlocks = new BlockLimitManager(data.getOrDefault("moveblocks", new HashMap<>())); - canCruise = (boolean) data.getOrDefault("canCruise", false); - canTeleport = (boolean) data.getOrDefault("canTeleport", false); - canBeNamed = (boolean) data.getOrDefault("canBeNamed", true); - cruiseOnPilot = (boolean) data.getOrDefault("cruiseOnPilot", false); - cruiseOnPilotVertMove = integerFromObject(data.getOrDefault("cruiseOnPilotVertMove", 0)); - allowVerticalMovement = (boolean) data.getOrDefault("allowVerticalMovement", true); - rotateAtMidpoint = (boolean) data.getOrDefault("rotateAtMidpoint", false); - allowHorizontalMovement = (boolean) data.getOrDefault("allowHorizontalMovement", true); - allowRemoteSign = (boolean) data.getOrDefault("allowRemoteSign", true); - allowCannonDirectorSign = (boolean) data.getOrDefault("allowCannonDirectorSign", true); - allowAADirectorSign = (boolean) data.getOrDefault("allowAADirectorSign", true); - canStaticMove = (boolean) data.getOrDefault("canStaticMove", false); - maxStaticMove = integerFromObject(data.getOrDefault("maxStaticMove", 10000)); - cruiseSkipBlocks = integerFromObject(data.getOrDefault("cruiseSkipBlocks", 0)); - vertCruiseSkipBlocks = integerFromObject(data.getOrDefault("vertCruiseSkipBlocks", cruiseSkipBlocks)); - halfSpeedUnderwater = (boolean) data.getOrDefault("halfSpeedUnderwater", false); - focusedExplosion = (boolean) data.getOrDefault("focusedExplosion", false); - mustBeSubcraft = (boolean) data.getOrDefault("mustBeSubcraft", false); - staticWaterLevel = integerFromObject(data.getOrDefault("staticWaterLevel", 0)); - fuelBurnRate = doubleFromObject(data.getOrDefault("fuelBurnRate", 0d)); - sinkPercent = doubleFromObject(data.getOrDefault("sinkPercent", 0d)); - overallSinkPercent = doubleFromObject(data.getOrDefault("overallSinkPercent", 0d)); - detectionMultiplier = doubleFromObject(data.getOrDefault("detectionMultiplier", 0d)); - underwaterDetectionMultiplier = doubleFromObject(data.getOrDefault("underwaterDetectionMultiplier", detectionMultiplier)); - sinkRateTicks = data.containsKey("sinkSpeed") ? (int) Math.ceil(20 / (doubleFromObject(data.get("sinkSpeed")))) : integerFromObject(data.getOrDefault("sinkTickRate", 0)); - keepMovingOnSink = (Boolean) data.getOrDefault("keepMovingOnSink", false); - keepMovingOnSinkMaxMove = integerFromObject(data.getOrDefault("keepMovingOnSinkMaxMove", -1)); - smokeOnSink = integerFromObject(data.getOrDefault("smokeOnSink", 0)); - explodeOnCrash = floatFromObject(data.getOrDefault("explodeOnCrash", 0F)); - collisionExplosion = floatFromObject(data.getOrDefault("collisionExplosion", 0F)); - minHeightLimit = Math.max(0, integerFromObject(data.getOrDefault("minHeightLimit", 0))); - - double cruiseSpeed = doubleFromObject(data.getOrDefault("cruiseSpeed", 20.0 / tickCooldown)); - cruiseTickCooldown = (int) Math.round((1.0 + cruiseSkipBlocks) * 20.0 / cruiseSpeed); - if(Settings.Debug) { - Bukkit.getLogger().info("Craft: " + craftName); - Bukkit.getLogger().info("CruiseSpeed: " + cruiseSpeed); - Bukkit.getLogger().info("Cooldown: " + cruiseTickCooldown); - } - - int value = Math.min(integerFromObject(data.getOrDefault("maxHeightLimit", 254)), 255); - if (value <= minHeightLimit) { - value = 255; - } - - maxHeightLimit = value; - maxHeightAboveGround = integerFromObject(data.getOrDefault("maxHeightAboveGround", -1)); - canDirectControl = (boolean) data.getOrDefault("canDirectControl", true); - canHover = (boolean) data.getOrDefault("canHover", false); - canHoverOverWater = (boolean) data.getOrDefault("canHoverOverWater", true); - moveEntities = (boolean) data.getOrDefault("moveEntities", true); - onlyMovePlayers = (boolean) data.getOrDefault("onlyMovePlayers", true); - useGravity = (boolean) data.getOrDefault("useGravity", false); - hoverLimit = Math.max(0, integerFromObject(data.getOrDefault("hoverLimit", 0))); - harvestBlocks = new ArrayList<>(); - harvesterBladeBlocks = new ArrayList<>(); - staticDetectionRange = doubleFromObject(data.getOrDefault("staticDetectionRange", 0d)); - underwaterStaticDetectionRange = doubleFromObject(data.getOrDefault("underwaterStaticDetectionRange", 0d)); - if (data.containsKey("harvestBlocks")) { - ArrayList objList = (ArrayList) data.get("harvestBlocks"); - for (Object i : objList) { - if (i instanceof String) { - String str = (String) i; - if (str.startsWith("ALL_")) { - str = str.replace("ALL_", "").toUpperCase(); - for (Material type : Material.values()){ - str = str.replace("ALL", ""); - if (!type.name().endsWith(str)){ - continue; - } else if (type.name().split("_").length == 1 && !type.name().endsWith(str.substring(1))) { - continue; - } - harvestBlocks.add(type); - } - continue; - } - Material mat = Material.getMaterial(((String) i).toUpperCase()); - harvestBlocks.add(mat); - } else { - Material mat = Material.getMaterial((Integer) i); - harvestBlocks.add(mat); - } + //Required craft flags + craftName = (String) data.get("name"); + maxSize = integerFromObject(data.get("maxSize")); + minSize = integerFromObject(data.get("minSize")); + allowedBlocks = new BlockContainer(data.get("allowedBlocks")); + + forbiddenBlocks = data.containsKey("forbiddenBlocks") ? new BlockContainer(data.get("forbiddenBlocks")) : new BlockContainer();; + forbiddenSignStrings = stringListFromObject(data.get("forbiddenSignStrings")); + tickCooldown = (int) Math.ceil(20 / (doubleFromObject(data.get("speed")))); + flyBlocks = new BlockLimitManager(data.get("flyblocks")); + + //Optional craft flags + blockedByWater = (boolean) (data.containsKey("canFly") ? data.get("canFly") : data.getOrDefault("blockedByWater", true)); + requireWaterContact = (boolean) data.getOrDefault("requireWaterContact", false); + tryNudge = (boolean) data.getOrDefault("tryNudge", false); + moveBlocks = new BlockLimitManager(data.getOrDefault("moveblocks", new HashMap<>())); + canCruise = (boolean) data.getOrDefault("canCruise", false); + canTeleport = (boolean) data.getOrDefault("canTeleport", false); + canBeNamed = (boolean) data.getOrDefault("canBeNamed", true); + cruiseOnPilot = (boolean) data.getOrDefault("cruiseOnPilot", false); + cruiseOnPilotVertMove = integerFromObject(data.getOrDefault("cruiseOnPilotVertMove", 0)); + allowVerticalMovement = (boolean) data.getOrDefault("allowVerticalMovement", true); + rotateAtMidpoint = (boolean) data.getOrDefault("rotateAtMidpoint", false); + allowHorizontalMovement = (boolean) data.getOrDefault("allowHorizontalMovement", true); + allowRemoteSign = (boolean) data.getOrDefault("allowRemoteSign", true); + allowCannonDirectorSign = (boolean) data.getOrDefault("allowCannonDirectorSign", true); + allowAADirectorSign = (boolean) data.getOrDefault("allowAADirectorSign", true); + canStaticMove = (boolean) data.getOrDefault("canStaticMove", false); + maxStaticMove = integerFromObject(data.getOrDefault("maxStaticMove", 10000)); + cruiseSkipBlocks = integerFromObject(data.getOrDefault("cruiseSkipBlocks", 0)); + vertCruiseSkipBlocks = integerFromObject(data.getOrDefault("vertCruiseSkipBlocks", cruiseSkipBlocks)); + halfSpeedUnderwater = (boolean) data.getOrDefault("halfSpeedUnderwater", false); + focusedExplosion = (boolean) data.getOrDefault("focusedExplosion", false); + mustBeSubcraft = (boolean) data.getOrDefault("mustBeSubcraft", false); + staticWaterLevel = integerFromObject(data.getOrDefault("staticWaterLevel", 0)); + fuelBurnRate = doubleFromObject(data.getOrDefault("fuelBurnRate", 0d)); + sinkPercent = doubleFromObject(data.getOrDefault("sinkPercent", 0d)); + overallSinkPercent = doubleFromObject(data.getOrDefault("overallSinkPercent", 0d)); + detectionMultiplier = doubleFromObject(data.getOrDefault("detectionMultiplier", 0d)); + underwaterDetectionMultiplier = doubleFromObject(data.getOrDefault("underwaterDetectionMultiplier", detectionMultiplier)); + sinkRateTicks = data.containsKey("sinkSpeed") ? (int) Math.ceil(20 / (doubleFromObject(data.get("sinkSpeed")))) : integerFromObject(data.getOrDefault("sinkTickRate", 0)); + keepMovingOnSink = (Boolean) data.getOrDefault("keepMovingOnSink", false); + keepMovingOnSinkMaxMove = integerFromObject(data.getOrDefault("keepMovingOnSinkMaxMove", -1)); + smokeOnSink = integerFromObject(data.getOrDefault("smokeOnSink", 0)); + explodeOnCrash = floatFromObject(data.getOrDefault("explodeOnCrash", 0F)); + collisionExplosion = floatFromObject(data.getOrDefault("collisionExplosion", 0F)); + minHeightLimit = Math.max(0, integerFromObject(data.getOrDefault("minHeightLimit", 0))); + + double cruiseSpeed = doubleFromObject(data.getOrDefault("cruiseSpeed", 20.0 / tickCooldown)); + cruiseTickCooldown = (int) Math.round((1.0 + cruiseSkipBlocks) * 20.0 / cruiseSpeed); + if(Settings.Debug) { + Bukkit.getLogger().info("Craft: " + craftName); + Bukkit.getLogger().info("CruiseSpeed: " + cruiseSpeed); + Bukkit.getLogger().info("Cooldown: " + cruiseTickCooldown); + } + int value = Math.min(integerFromObject(data.getOrDefault("maxHeightLimit", 254)), 255); + if (value <= minHeightLimit) { + value = 255; } - } - if (data.containsKey("harvesterBladeBlocks")) { - ArrayList objList = (ArrayList) data.get("harvesterBladeBlocks"); + + maxHeightLimit = value; + maxHeightAboveGround = integerFromObject(data.getOrDefault("maxHeightAboveGround", -1)); + canDirectControl = (boolean) data.getOrDefault("canDirectControl", true); + canHover = (boolean) data.getOrDefault("canHover", false); + canHoverOverWater = (boolean) data.getOrDefault("canHoverOverWater", true); + moveEntities = (boolean) data.getOrDefault("moveEntities", true); + onlyMovePlayers = (boolean) data.getOrDefault("onlyMovePlayers", true); + useGravity = (boolean) data.getOrDefault("useGravity", false); + hoverLimit = Math.max(0, integerFromObject(data.getOrDefault("hoverLimit", 0))); + harvestBlocks = new ArrayList<>(); + harvesterBladeBlocks = new ArrayList<>(); + staticDetectionRange = doubleFromObject(data.getOrDefault("staticDetectionRange", 0d)); + underwaterStaticDetectionRange = doubleFromObject(data.getOrDefault("underwaterStaticDetectionRange", 0d)); + if (data.containsKey("harvestBlocks")) { + ArrayList objList = (ArrayList) data.get("harvestBlocks"); for (Object i : objList) { if (i instanceof String) { String str = (String) i; - str = str.toUpperCase(); - if (str.startsWith("ALL_")){ + if (str.startsWith("ALL_")) { + str = str.replace("ALL_", "").toUpperCase(); for (Material type : Material.values()){ str = str.replace("ALL", ""); if (!type.name().endsWith(str)){ @@ -240,19 +213,46 @@ public CraftType(File f) throws CraftTypeException{ } else if (type.name().split("_").length == 1 && !type.name().endsWith(str.substring(1))) { continue; } - harvesterBladeBlocks.add(type); + harvestBlocks.add(type); } - } else { - Material mat = Material.getMaterial(str); - harvesterBladeBlocks.add(mat); + continue; } - + Material mat = Material.getMaterial(((String) i).toUpperCase()); + harvestBlocks.add(mat); } else { Material mat = Material.getMaterial((Integer) i); - harvesterBladeBlocks.add(mat); + harvestBlocks.add(mat); } + } - } + } + if (data.containsKey("harvesterBladeBlocks")) { + ArrayList objList = (ArrayList) data.get("harvesterBladeBlocks"); + for (Object i : objList) { + if (i instanceof String) { + String str = (String) i; + str = str.toUpperCase(); + if (str.startsWith("ALL_")){ + for (Material type : Material.values()){ + str = str.replace("ALL", ""); + if (!type.name().endsWith(str)){ + continue; + } else if (type.name().split("_").length == 1 && !type.name().endsWith(str.substring(1))) { + continue; + } + harvesterBladeBlocks.add(type); + } + } else { + Material mat = Material.getMaterial(str); + harvesterBladeBlocks.add(mat); + } + + } else { + Material mat = Material.getMaterial((Integer) i); + harvesterBladeBlocks.add(mat); + } + } + } passthroughBlocks = new HashSet<>(); if (data.containsKey("passthroughBlocks")) { ArrayList objList = (ArrayList) data.get("passthroughBlocks"); @@ -355,6 +355,8 @@ public CraftType(File f) throws CraftTypeException{ int dropdist = integerFromObject(data.getOrDefault("gravityDropDistance", -8)); gravityDropDistance = dropdist > 0 ? -dropdist : dropdist; collisionSound = Sound.valueOf((String) data.getOrDefault("collisionSound", "BLOCK_ANVIL_LAND")); + maxSignsWithString = stringDoubleMapFromObject(data.getOrDefault("maxSignsWithString", new HashMap<>())); + maxCannons = stringDoubleMapFromObject(data.getOrDefault("maxCannons", new HashMap<>())); } catch (Exception e){ throw new CraftTypeException("Craft file " + f.getName() + " is malformed", e); } @@ -392,6 +394,43 @@ private Material materialFromObject(Object obj){ } } + + private Map, Double> stringDoubleMapFromObject(Object obj) { + Map objMap = (Map) obj; + Map, Double> retMap = new HashMap<>(); + for (Object k : objMap.keySet()) { + final List key = new ArrayList<>(); + if (k instanceof List) { + List strings = (List) k; + for (Object i : strings) { + if (i instanceof String) { + key.add(((String) i).toLowerCase()); + } else { + key.add(String.valueOf(i).toLowerCase()); + } + } + } else if (k instanceof String) { + key.add(((String) k).toLowerCase()); + } else { + key.add(String.valueOf(k).toLowerCase()); + } + final Object v = objMap.get(k); + final double value; + if (v instanceof String) { + final String str = (String) v; + if (str.startsWith("N")) { + value = 10000.0 + Double.parseDouble(str.substring(1)); + } else { + value = Double.parseDouble(str); + } + } else { + value = (double) v; + } + retMap.put(key, value); + } + return retMap; + } + private HashMap effectListFromObject(Object obj){ Map objMap = (Map) obj; HashMap ret = new HashMap<>(); @@ -441,233 +480,6 @@ private String[] stringListFromObject(Object obj) { } return returnList.toArray(new String[1]); } - private Map>, List> materialMapListFromObject(Object obj){ - HashMap>, List> returnMap = new HashMap<>(); - HashMap objMap = (HashMap) obj; - for (Object i : objMap.keySet()) { - HashMap> materialMap = new HashMap<>(); - if (i instanceof ArrayList) { - for (Object o : (ArrayList) i) { - if (o instanceof Integer) { - Integer typeID = (Integer) o; - Material type = Material.getMaterial(typeID); - materialMap.put(type, new ArrayList<>()); - } else if (o instanceof String) { - String string = (String) o; - string = string.toUpperCase(); - if (string.contains(":")) { - String[] parts = string.split(":"); - Material type; - Integer data = Integer.valueOf(parts[1]); - if (parts[0].contains("0") || parts[0].contains("1") || parts[0].contains("2") || parts[0].contains("3") || parts[0].contains("4") || parts[0].contains("5") || parts[0].contains("6") || parts[0].contains("7") || parts[0].contains("8") || parts[0].contains("9")) { - Integer typeID = Integer.valueOf(parts[0]); - type = Material.getMaterial(typeID); - - } else { - type = Material.getMaterial(parts[0]); - } - if (materialMap.containsKey(type)) { - List dataList = materialMap.get(type); - dataList.add(data); - materialMap.put(type, dataList); - } else { - List dataList = new ArrayList<>(); - dataList.add(data); - materialMap.put(type, dataList); - } - - } else if (string.toUpperCase().startsWith("ALL_")){ - string = string.replace("ALL_", ""); - for (Material m : Material.values()){ - if (!m.name().endsWith(string)){ - continue; - } - materialMap.put(m, new ArrayList<>()); - } - } else { - Material type; - if (string.contains("0") || string.contains("1") || string.contains("2") || string.contains("3") || string.contains("4") || string.contains("5") || string.contains("6") || string.contains("7") || string.contains("8") || string.contains("9")) { - Integer typeID = Integer.valueOf(string); - type = Material.getMaterial(typeID); - - } else { - type = Material.getMaterial(string); - } - materialMap.put(type, new ArrayList<>()); - } - } else { - Material type = (Material) o; - materialMap.put(type, new ArrayList<>()); - } - } - } else if (i instanceof Map) { - HashMap objMapKey = (HashMap) i; - for (Object o : objMapKey.keySet()) { - if (o instanceof Integer) { - Integer typeID = (Integer) o; - Material type = Material.getMaterial(typeID); - List dataList = (List) objMapKey.get(o); - materialMap.put(type, dataList); - } else { - Material type = (Material) o; - List dataList = (List) objMapKey.get(o); - materialMap.put(type, dataList); - } - } - } else if (i instanceof Integer) { - if (!Settings.IsLegacy){ - throw new IllegalArgumentException("Numerical IDs are not supported by the current server version!"); - } - Integer typeID = (Integer) i; - Material type = Material.getMaterial(typeID); - materialMap.put(type, new ArrayList<>()); - } else if (i instanceof String) { - String string = (String) i; - string = string.toUpperCase(); - if (string.contains(":")) { - String[] parts = string.split(":"); - Material type; - Integer data = Integer.valueOf(parts[1]); - if (parts[0].contains("0") || parts[0].contains("1") || parts[0].contains("2") || parts[0].contains("3") || parts[0].contains("4") || parts[0].contains("5") || parts[0].contains("6") || parts[0].contains("7") || parts[0].contains("8") || parts[0].contains("9")) { - Integer typeID = Integer.valueOf(parts[0]); - type = Material.getMaterial(typeID); - - } else { - type = Material.getMaterial(parts[0]); - } - if (materialMap.containsKey(type)) { - List dataList = materialMap.get(type); - dataList.add(data); - materialMap.put(type, dataList); - } else { - List dataList = new ArrayList<>(); - dataList.add(data); - materialMap.put(type, dataList); - } - } else { - Material type; - boolean all = false; - if (string.toUpperCase().startsWith("ALL_")) { - string = string.replace("ALL_", ""); - for (Material m : Material.values()){ - if (m.name().endsWith(string)){ - materialMap.put(m, new ArrayList<>()); - } - all = true; - } - } - if (string.contains("0") || string.contains("1") || string.contains("2") || string.contains("3") || string.contains("4") || string.contains("5") || string.contains("6") || string.contains("7") || string.contains("8") || string.contains("9")) { - Integer typeID = Integer.valueOf(string); - type = Material.getMaterial(typeID); - - } else { - type = Material.getMaterial(string); - } - if (!all) { - if (materialMap.containsKey(type)) { - List dataList = materialMap.get(type); - materialMap.put(type, dataList); - } else { - List dataList = new ArrayList<>(); - materialMap.put(type, dataList); - } - } - } - } else { - Material type = (Material) i; - materialMap.put(type, new ArrayList<>()); - } - - // then read in the limitation values, low and high - ArrayList objList = (ArrayList) objMap.get(i); - ArrayList limitList = new ArrayList<>(); - for (Object limitObj : objList) { - if (limitObj instanceof String) { - String str = (String) limitObj; - if (str.contains("N")) { // a # indicates a specific quantity, IE: #2 for exactly 2 of the block - String[] parts = str.split("N"); - Double val = Double.valueOf(parts[1]); - limitList.add(10000d + val); // limit greater than 10000 indicates an specific quantity (not a ratio) - } else { - Double val = Double.valueOf(str); - limitList.add(val); - } - } else if (limitObj instanceof Integer) { - Double ret = ((Integer) limitObj).doubleValue(); - limitList.add(ret); - } else { - limitList.add((Double) limitObj); - } - } - returnMap.put(materialMap, limitList); - } - return returnMap; - } - private Map, List> blockIDMapListFromObject(Object obj) { - HashMap, List> returnMap = new HashMap<>(); - HashMap objMap = (HashMap) obj; - for (Object i : objMap.keySet()) { - ArrayList rowList = new ArrayList<>(); - - // first read in the list of the blocks that type of flyblock. It could be a single string (with or without a ":") or integer, or it could be multiple of them - if (i instanceof ArrayList) { - for (Object o : (ArrayList) i) { - if (o instanceof String) { - String str = (String) o; - if (str.contains(":")) { - String[] parts = str.split(":"); - Integer typeID = Integer.valueOf(parts[0]); - Integer metaData = Integer.valueOf(parts[1]); - rowList.add(10000 + (typeID << 4) + metaData); // id greater than 10000 indicates it has a meta data / damage value - } else { - Integer typeID = Integer.valueOf(str); - rowList.add(typeID); - } - } else { - Integer typeID = (Integer) o; - rowList.add(typeID); - } - } - } else if (i instanceof String) { - String str = (String) i; - if (str.contains(":")) { - String[] parts = str.split(":"); - Integer typeID = Integer.valueOf(parts[0]); - Integer metaData = Integer.valueOf(parts[1]); - rowList.add(10000 + (typeID << 4) + metaData); // id greater than 10000 indicates it has a meta data / damage value - } else { - Integer typeID = Integer.valueOf(str); - rowList.add(typeID); - } - } else { - Integer typeID = (Integer) i; - rowList.add(typeID); - } - - // then read in the limitation values, low and high - ArrayList objList = (ArrayList) objMap.get(i); - ArrayList limitList = new ArrayList<>(); - for (Object limitObj : objList) { - if (limitObj instanceof String) { - String str = (String) limitObj; - if (str.contains("N")) { // a # indicates a specific quantity, IE: #2 for exactly 2 of the block - String[] parts = str.split("N"); - Double val = Double.valueOf(parts[1]); - limitList.add(10000d + val); // limit greater than 10000 indicates an specific quantity (not a ratio) - } else { - Double val = Double.valueOf(str); - limitList.add(val); - } - } else if (limitObj instanceof Integer) { - Double ret = ((Integer) limitObj).doubleValue(); - limitList.add(ret); - } else - limitList.add((Double) limitObj); - } - returnMap.put(rowList, limitList); - } - return returnMap; - } @NotNull public String getCraftName() { @@ -967,6 +779,16 @@ public Sound getCollisionSound() { return collisionSound; } + @NotNull + public Map, Double> getMaxSignsWithString() { + return maxSignsWithString; + } + + @NotNull + public Map, Double> getMaxCannons() { + return maxCannons; + } + private static class TypeNotFoundException extends RuntimeException { public TypeNotFoundException(String s) { super(s); diff --git a/modules/api/src/main/java/net/countercraft/movecraft/utils/MathUtils.java b/modules/api/src/main/java/net/countercraft/movecraft/utils/MathUtils.java index 7321dd85d..2056b50c2 100644 --- a/modules/api/src/main/java/net/countercraft/movecraft/utils/MathUtils.java +++ b/modules/api/src/main/java/net/countercraft/movecraft/utils/MathUtils.java @@ -98,7 +98,7 @@ public static boolean locationNearHitBox(@NotNull final HitBox hitBox, @NotNull @Contract(pure=true) public static boolean locIsNearCraftFast(@NotNull final Craft craft, @NotNull final MovecraftLocation location) { // optimized to be as fast as possible, it checks the easy ones first, then the more computationally intensive later - return locationNearHitBox(craft.getHitBox(), location.toBukkit(craft.getW()), 3); + return locationNearHitBox(craft.getHitBox(), location.toBukkit(craft.getWorld()), 3); } /** diff --git a/modules/api/src/main/java/net/countercraft/movecraft/utils/TeleportUtils.java b/modules/api/src/main/java/net/countercraft/movecraft/utils/TeleportUtils.java index f475370d3..1fb14a309 100644 --- a/modules/api/src/main/java/net/countercraft/movecraft/utils/TeleportUtils.java +++ b/modules/api/src/main/java/net/countercraft/movecraft/utils/TeleportUtils.java @@ -13,6 +13,7 @@ import java.util.Collections; import java.util.HashSet; import java.util.Set; +import java.util.List; /** * Code taken with permission from MicleBrick @@ -135,7 +136,13 @@ public static void teleport(Player player, Location location, float yawChange) { return; Object vehiclePacket = vehiclePacketConstructor.newInstance(handle); sendPacket(vehiclePacket, player); - for (Entity pass : vehicle.getPassengers()) { + List passengers; + try { + passengers = (List) Entity.class.getDeclaredMethod("getPassengers").invoke(vehicle); + } catch (Exception e) { + return; + } + for (Entity pass : passengers) { if (pass.getType() != EntityType.PLAYER || pass.equals(player)) { continue; } diff --git a/modules/v1_10_R1/src/main/java/net/countercraft/movecraft/compat/v1_10_R1/IWorldHandler.java b/modules/v1_10_R1/src/main/java/net/countercraft/movecraft/compat/v1_10_R1/IWorldHandler.java index 9de4e6858..15b05c91b 100644 --- a/modules/v1_10_R1/src/main/java/net/countercraft/movecraft/compat/v1_10_R1/IWorldHandler.java +++ b/modules/v1_10_R1/src/main/java/net/countercraft/movecraft/compat/v1_10_R1/IWorldHandler.java @@ -19,7 +19,6 @@ import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; -import java.lang.invoke.MethodType; import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; @@ -79,7 +78,7 @@ public void rotateCraft(@NotNull Craft craft, @NotNull MovecraftLocation originP //******************************************* //* Step two: Get the tiles * //******************************************* - World nativeWorld = ((CraftWorld) craft.getW()).getHandle(); + World nativeWorld = ((CraftWorld) craft.getWorld()).getHandle(); List tiles = new ArrayList<>(); //get the tiles for(BlockPosition position : rotatedPositions.keySet()){ @@ -174,7 +173,7 @@ public void translateCraft(@NotNull Craft craft, @NotNull MovecraftLocation disp //******************************************* //* Step two: Get the tiles * //******************************************* - WorldServer nativeWorld = ((CraftWorld) craft.getW()).getHandle(); + WorldServer nativeWorld = ((CraftWorld) craft.getWorld()).getHandle(); List tiles = getTiles(positions, nativeWorld); //******************************************* //* Step three: Translate all the blocks * diff --git a/modules/v1_11_R1/src/main/java/net/countercraft/movecraft/compat/v1_11_R1/IWorldHandler.java b/modules/v1_11_R1/src/main/java/net/countercraft/movecraft/compat/v1_11_R1/IWorldHandler.java index 69e4f6205..60efc0015 100644 --- a/modules/v1_11_R1/src/main/java/net/countercraft/movecraft/compat/v1_11_R1/IWorldHandler.java +++ b/modules/v1_11_R1/src/main/java/net/countercraft/movecraft/compat/v1_11_R1/IWorldHandler.java @@ -78,7 +78,7 @@ public void rotateCraft(@NotNull Craft craft, @NotNull MovecraftLocation originP //******************************************* //* Step two: Get the tiles * //******************************************* - World nativeWorld = ((CraftWorld) craft.getW()).getHandle(); + World nativeWorld = ((CraftWorld) craft.getWorld()).getHandle(); List tiles = new ArrayList<>(); //get the tiles for(BlockPosition position : rotatedPositions.keySet()){ @@ -174,7 +174,7 @@ public void translateCraft(@NotNull Craft craft, @NotNull MovecraftLocation disp //******************************************* //* Step two: Get the tiles * //******************************************* - World nativeWorld = ((CraftWorld) craft.getW()).getHandle(); + World nativeWorld = ((CraftWorld) craft.getWorld()).getHandle(); List tiles = new ArrayList<>(); //get the tiles for(BlockPosition position : positions){ diff --git a/modules/v1_12_R1/src/main/java/net/countercraft/movecraft/compat/v1_12_R1/IWorldHandler.java b/modules/v1_12_R1/src/main/java/net/countercraft/movecraft/compat/v1_12_R1/IWorldHandler.java index 54bc795bb..33a77943c 100644 --- a/modules/v1_12_R1/src/main/java/net/countercraft/movecraft/compat/v1_12_R1/IWorldHandler.java +++ b/modules/v1_12_R1/src/main/java/net/countercraft/movecraft/compat/v1_12_R1/IWorldHandler.java @@ -83,7 +83,7 @@ public void rotateCraft(@NotNull Craft craft, @NotNull MovecraftLocation originP //******************************************* //* Step two: Get the tiles * //******************************************* - World nativeWorld = ((CraftWorld) craft.getW()).getHandle(); + World nativeWorld = ((CraftWorld) craft.getWorld()).getHandle(); List tiles = new ArrayList<>(); //get the tiles for(BlockPosition position : rotatedPositions.keySet()){ @@ -179,7 +179,7 @@ public void translateCraft(@NotNull Craft craft, @NotNull MovecraftLocation disp //******************************************* //* Step two: Get the tiles * //******************************************* - World nativeWorld = ((CraftWorld) craft.getW()).getHandle(); + World nativeWorld = ((CraftWorld) craft.getWorld()).getHandle(); List tiles = new ArrayList<>(); //get the tiles for(BlockPosition position : positions){ diff --git a/modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/IWorldHandler.java b/modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/IWorldHandler.java index ca56764d7..d5d4f89d0 100644 --- a/modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/IWorldHandler.java +++ b/modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/IWorldHandler.java @@ -62,7 +62,7 @@ public void rotateCraft(@NotNull Craft craft, @NotNull MovecraftLocation originP //******************************************* //* Step two: Get the tiles * //******************************************* - World nativeWorld = ((CraftWorld) craft.getW()).getHandle(); + World nativeWorld = ((CraftWorld) craft.getWorld()).getHandle(); List tiles = new ArrayList<>(); //get the tiles for(BlockPosition position : rotatedPositions.keySet()){ @@ -185,7 +185,7 @@ public void translateCraft(@NotNull Craft craft, @NotNull MovecraftLocation disp //******************************************* //* Step two: Get the tiles * //******************************************* - WorldServer nativeWorld = ((CraftWorld) craft.getW()).getHandle(); + WorldServer nativeWorld = ((CraftWorld) craft.getWorld()).getHandle(); List tiles = getTiles(positions, nativeWorld); //******************************************* //* Step three: Translate all the blocks * diff --git a/modules/v1_14_R1/src/main/java/net/countercraft/movecraft/compat/v1_14_R1/IWorldHandler.java b/modules/v1_14_R1/src/main/java/net/countercraft/movecraft/compat/v1_14_R1/IWorldHandler.java index 6445e87bc..246924ae1 100644 --- a/modules/v1_14_R1/src/main/java/net/countercraft/movecraft/compat/v1_14_R1/IWorldHandler.java +++ b/modules/v1_14_R1/src/main/java/net/countercraft/movecraft/compat/v1_14_R1/IWorldHandler.java @@ -61,7 +61,7 @@ public void rotateCraft(@NotNull Craft craft, @NotNull MovecraftLocation originP //******************************************* //* Step two: Get the tiles * //******************************************* - World nativeWorld = ((CraftWorld) craft.getW()).getHandle(); + World nativeWorld = ((CraftWorld) craft.getWorld()).getHandle(); List tiles = new ArrayList<>(); //get the tiles for(BlockPosition position : rotatedPositions.keySet()){ @@ -184,7 +184,7 @@ public void translateCraft(@NotNull Craft craft, @NotNull MovecraftLocation disp //******************************************* //* Step two: Get the tiles * //******************************************* - WorldServer nativeWorld = ((CraftWorld) craft.getW()).getHandle(); + WorldServer nativeWorld = ((CraftWorld) craft.getWorld()).getHandle(); List tiles = getTiles(positions, nativeWorld); //******************************************* //* Step three: Translate all the blocks * diff --git a/modules/v1_15_R1/src/main/java/net/countercraft/movecraft/compat/v1_15_R1/IWorldHandler.java b/modules/v1_15_R1/src/main/java/net/countercraft/movecraft/compat/v1_15_R1/IWorldHandler.java index 9f56e091b..a6e79f63e 100644 --- a/modules/v1_15_R1/src/main/java/net/countercraft/movecraft/compat/v1_15_R1/IWorldHandler.java +++ b/modules/v1_15_R1/src/main/java/net/countercraft/movecraft/compat/v1_15_R1/IWorldHandler.java @@ -62,7 +62,7 @@ public void rotateCraft(@NotNull Craft craft, @NotNull MovecraftLocation originP //******************************************* //* Step two: Get the tiles * //******************************************* - WorldServer nativeWorld = ((CraftWorld) craft.getW()).getHandle(); + WorldServer nativeWorld = ((CraftWorld) craft.getWorld()).getHandle(); List tiles = new ArrayList<>(); //get the tiles for(BlockPosition position : rotatedPositions.keySet()){ @@ -187,7 +187,7 @@ public void translateCraft(@NotNull Craft craft, @NotNull MovecraftLocation disp //******************************************* //* Step two: Get the tiles * //******************************************* - WorldServer nativeWorld = ((CraftWorld) craft.getW()).getHandle(); + WorldServer nativeWorld = ((CraftWorld) craft.getWorld()).getHandle(); List tiles = getTiles(positions, nativeWorld); //******************************************* //* Step three: Translate all the blocks * diff --git a/modules/v1_8_R3/src/main/java/net/countercraft/movecraft/compat/v1_8_R3/IWorldHandler.java b/modules/v1_8_R3/src/main/java/net/countercraft/movecraft/compat/v1_8_R3/IWorldHandler.java index e9969ceb4..ddff5cbff 100644 --- a/modules/v1_8_R3/src/main/java/net/countercraft/movecraft/compat/v1_8_R3/IWorldHandler.java +++ b/modules/v1_8_R3/src/main/java/net/countercraft/movecraft/compat/v1_8_R3/IWorldHandler.java @@ -70,7 +70,7 @@ public void rotateCraft(@NotNull Craft craft, @NotNull MovecraftLocation originP //******************************************* //* Step two: Get the tiles * //******************************************* - World nativeWorld = ((CraftWorld) craft.getW()).getHandle(); + World nativeWorld = ((CraftWorld) craft.getWorld()).getHandle(); List tiles = new ArrayList<>(); //get the tiles for(BlockPosition position : rotatedPositions.keySet()){ @@ -182,7 +182,7 @@ public void translateCraft(@NotNull Craft craft, @NotNull MovecraftLocation disp //******************************************* //* Step two: Get the tiles * //******************************************* - WorldServer nativeWorld = ((CraftWorld) craft.getW()).getHandle(); + WorldServer nativeWorld = ((CraftWorld) craft.getWorld()).getHandle(); List tiles = getTiles(positions, nativeWorld); //******************************************* //* Step three: Translate all the blocks * diff --git a/modules/v1_9_R2/src/main/java/net/countercraft/movecraft/compat/v1_9_R2/IWorldHandler.java b/modules/v1_9_R2/src/main/java/net/countercraft/movecraft/compat/v1_9_R2/IWorldHandler.java index 05303752b..c5983754c 100644 --- a/modules/v1_9_R2/src/main/java/net/countercraft/movecraft/compat/v1_9_R2/IWorldHandler.java +++ b/modules/v1_9_R2/src/main/java/net/countercraft/movecraft/compat/v1_9_R2/IWorldHandler.java @@ -77,7 +77,7 @@ public void rotateCraft(@NotNull Craft craft, @NotNull MovecraftLocation originP //******************************************* //* Step two: Get the tiles * //******************************************* - World nativeWorld = ((CraftWorld) craft.getW()).getHandle(); + World nativeWorld = ((CraftWorld) craft.getWorld()).getHandle(); List tiles = new ArrayList<>(); //get the tiles for(BlockPosition position : rotatedPositions.keySet()){ @@ -174,7 +174,7 @@ public void translateCraft(@NotNull Craft craft, @NotNull MovecraftLocation disp //******************************************* //* Step two: Get the tiles * //******************************************* - WorldServer nativeWorld = ((CraftWorld) craft.getW()).getHandle(); + WorldServer nativeWorld = ((CraftWorld) craft.getWorld()).getHandle(); List tiles = getTiles(positions, nativeWorld); //******************************************* //* Step three: Translate all the blocks * diff --git a/modules/worldedit/WE6Utils/src/main/java/net/countercraft/movecraft/compat/we6/IMovecraftRepair.java b/modules/worldedit/WE6Utils/src/main/java/net/countercraft/movecraft/compat/we6/IMovecraftRepair.java index 8b558b1ed..01d7521ef 100644 --- a/modules/worldedit/WE6Utils/src/main/java/net/countercraft/movecraft/compat/we6/IMovecraftRepair.java +++ b/modules/worldedit/WE6Utils/src/main/java/net/countercraft/movecraft/compat/we6/IMovecraftRepair.java @@ -58,7 +58,7 @@ public IMovecraftRepair(Plugin plugin) { public boolean saveCraftRepairState(Craft craft, Sign sign) { BitmapHitBox hitBox = craft.getHitBox(); File saveDirectory = new File(plugin.getDataFolder(), "RepairStates"); - World world = craft.getW(); + World world = craft.getWorld(); com.sk89q.worldedit.world.World weWorld = new BukkitWorld(world); WorldData worldData = weWorld.getWorldData(); com.sk89q.worldedit.Vector origin = new com.sk89q.worldedit.Vector(sign.getX(),sign.getY(),sign.getZ()); @@ -76,7 +76,7 @@ public boolean saveCraftRepairState(Craft craft, Sign sign) { repairName += ".schematic"; File repairStateFile = new File(playerDirectory, repairName); Set blockSet = baseBlocksFromCraft(craft); - final HitBox outsideLocs = CollectionUtils.filter(solidBlockLocs(craft.getW(), cRegion), hitBox); + final HitBox outsideLocs = CollectionUtils.filter(solidBlockLocs(craft.getWorld(), cRegion), hitBox); try { BlockArrayClipboard clipboard = new BlockArrayClipboard(cRegion); @@ -590,7 +590,7 @@ public long getNumDiffBlocks(String s) { private Set baseBlocksFromCraft(Craft craft) { HashSet returnSet = new HashSet<>(); BitmapHitBox hitBox = craft.getHitBox(); - World w = craft.getW(); + World w = craft.getWorld(); for (MovecraftLocation location : hitBox) { int id = w.getBlockTypeIdAt(location.toBukkit(w)); byte data = w.getBlockAt(location.getX(), location.getY(), location.getZ()).getData(); diff --git a/modules/worldedit/WE7Utils/src/main/java/net/countercraft/movecraft/compat/we7/IMovecraftRepair.java b/modules/worldedit/WE7Utils/src/main/java/net/countercraft/movecraft/compat/we7/IMovecraftRepair.java index 03de0ef67..19f2eb70e 100644 --- a/modules/worldedit/WE7Utils/src/main/java/net/countercraft/movecraft/compat/we7/IMovecraftRepair.java +++ b/modules/worldedit/WE7Utils/src/main/java/net/countercraft/movecraft/compat/we7/IMovecraftRepair.java @@ -62,7 +62,7 @@ public IMovecraftRepair(Plugin plugin) { public boolean saveCraftRepairState(Craft craft, Sign sign) { BitmapHitBox hitBox = craft.getHitBox(); File saveDirectory = new File(plugin.getDataFolder(), "RepairStates"); - World world = craft.getW(); + World world = craft.getWorld(); if (!saveDirectory.exists()){ saveDirectory.mkdirs(); } @@ -463,7 +463,7 @@ public long getNumDiffBlocks(String s) { private Set baseBlocksFromCraft(Craft craft) { HashSet returnSet = new HashSet<>(); BitmapHitBox hitBox = craft.getHitBox(); - World w = craft.getW(); + World w = craft.getWorld(); for (MovecraftLocation location : hitBox) { Material type = w.getBlockAt(location.toBukkit(w)).getType(); returnSet.add(BukkitAdapter.asBlockType(type).getDefaultState().toBaseBlock()); From 4a7006838a4d6efca108533b6e9fa8a07968aff0 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Tue, 28 Apr 2020 18:20:11 +0200 Subject: [PATCH 156/304] Bump version and fix NPE in searching for cannons on a craft --- modules/Movecraft/dependency-reduced-pom.xml | 2 +- modules/Movecraft/pom.xml | 2 +- .../movecraft/async/detection/DetectionTask.java | 3 +++ .../worldguard/WorldGuardCompatManager.java | 12 ++++++++---- 4 files changed, 13 insertions(+), 6 deletions(-) diff --git a/modules/Movecraft/dependency-reduced-pom.xml b/modules/Movecraft/dependency-reduced-pom.xml index d634d443f..b10319667 100644 --- a/modules/Movecraft/dependency-reduced-pom.xml +++ b/modules/Movecraft/dependency-reduced-pom.xml @@ -4,7 +4,7 @@ net.countercraft movecraft Movecraft - 7.0.0_for_1.8.8-1.15.2_beta_19 + 7.0.0_for_1.8.8-1.15.2_beta_20 http://github.com/apdevteam/Movecraft src/main/java diff --git a/modules/Movecraft/pom.xml b/modules/Movecraft/pom.xml index 9924a965a..c0f3c2efb 100644 --- a/modules/Movecraft/pom.xml +++ b/modules/Movecraft/pom.xml @@ -10,7 +10,7 @@ UTF-8 - 7.0.0_for_1.8.8-1.15.2_beta_19 + 7.0.0_for_1.8.8-1.15.2_beta_20 spigot-repo diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/detection/DetectionTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/detection/DetectionTask.java index ac8e905c5..b209a9296 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/detection/DetectionTask.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/detection/DetectionTask.java @@ -439,6 +439,9 @@ private void checkMaxCannons() { cannonsCount.put(limitedCannonNames, count); } } + if (cannonsCount.isEmpty()) { + return; + } for (List limitedCannonNames : craft.getType().getMaxCannons().keySet()) { final double limit = craft.getType().getMaxCannons().get(limitedCannonNames); int count = cannonsCount.get(limitedCannonNames); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/worldguard/WorldGuardCompatManager.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/worldguard/WorldGuardCompatManager.java index 8593eb8f1..6479a5fa6 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/worldguard/WorldGuardCompatManager.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/worldguard/WorldGuardCompatManager.java @@ -66,7 +66,9 @@ public void onCraftTranslateEvent(CraftTranslateEvent event){ return; for(MovecraftLocation location : event.getNewHitBox()){ if (canMoveInRegion(location, event.getCraft().getWorld())) { - continue; + event.setFailMessage(I18nSupport.getInternationalisedString("WGCustomFlags - Translation Failed")); + event.setCancelled(true); + return; } if(!pilotHasAccessToRegion(event.getCraft().getNotificationPlayer(), location, event.getCraft().getWorld())){ @@ -85,8 +87,10 @@ public void onCraftRotateEvent(CraftRotateEvent event){ if(event.getCraft().getNotificationPlayer() == null) return; for(MovecraftLocation location : event.getNewHitBox()){ - if (canRotateInRegion(location, event.getCraft().getWorld())) { - continue; + if (!canRotateInRegion(location, event.getCraft().getWorld())) { + event.setFailMessage(I18nSupport.getInternationalisedString("WGCustomFlags - Rotation Failed")); + event.setCancelled(true); + return; } if(!pilotHasAccessToRegion(event.getCraft().getNotificationPlayer(), location, event.getCraft().getWorld())){ event.setCancelled(true); @@ -215,7 +219,7 @@ public void onCraftDetect(CraftDetectEvent event) { regions = regionManager.getApplicableRegions(BlockVector3.at(location.getX(), location.getY(), location.getZ())); } for (ProtectedRegion pr : regions.getRegions()){ - if (WorldguardUtils.pvpAllowed(pr) || pr.getFlag(FLAG_SINK) == StateFlag.State.DENY){ + if (pr.getFlag(FLAG_PILOT) == StateFlag.State.DENY){ region = pr; break; } From f5ee698ac8a21e8d4e07a14d96b5073f8b0fc2c0 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Tue, 28 Apr 2020 18:27:37 +0200 Subject: [PATCH 157/304] Fixed potential NPE in checking for signs --- .../countercraft/movecraft/async/detection/DetectionTask.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/detection/DetectionTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/detection/DetectionTask.java index b209a9296..3d18b9f6e 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/detection/DetectionTask.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/detection/DetectionTask.java @@ -402,6 +402,9 @@ private boolean confirmStructureRequirements(BlockLimitManager flyBlocks, } private void checkMaxSignLimits() { + if (signWithStringCount.isEmpty()) { + return; + } for (Map.Entry, Double> entry : craft.getType().getMaxSignsWithString().entrySet()) { final double limit = entry.getValue(); int count = signWithStringCount.get(entry.getKey()); From ded8206f6d02afa1c8cedfcbbbc125a423a5e051 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Tue, 28 Apr 2020 23:02:10 +0200 Subject: [PATCH 158/304] Fixed custom movecraft flags --- .../movecraft/utils/WorldguardUtils.java | 16 +- .../worldguard/WorldGuardCompatManager.java | 178 +++++------------- 2 files changed, 57 insertions(+), 137 deletions(-) diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/WorldguardUtils.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/WorldguardUtils.java index 5e250e32c..cd0b1bc89 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/WorldguardUtils.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/WorldguardUtils.java @@ -62,11 +62,19 @@ public static boolean regionExists(String regionName) { return false; } - public static boolean pvpAllowed(ProtectedRegion region){ - if (Settings.IsLegacy) { - return region.getFlag(DefaultFlag.PVP) == StateFlag.State.ALLOW; + public static boolean pvpAllowed(ApplicableRegionSet regions){ + boolean allowed = true; + for (ProtectedRegion region : regions) { + if (Settings.IsLegacy) { + allowed = region.getFlag(DefaultFlag.PVP) == StateFlag.State.ALLOW; + } else { + allowed = region.getFlag(Flags.PVP) == StateFlag.State.ALLOW; + } + if (!allowed) + break; } - return region.getFlag(Flags.PVP) == StateFlag.State.ALLOW; + return allowed; + } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/worldguard/WorldGuardCompatManager.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/worldguard/WorldGuardCompatManager.java index 6479a5fa6..f195cd689 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/worldguard/WorldGuardCompatManager.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/worldguard/WorldGuardCompatManager.java @@ -1,19 +1,13 @@ package net.countercraft.movecraft.worldguard; -import com.sk89q.worldedit.bukkit.BukkitAdapter; -import com.sk89q.worldedit.bukkit.BukkitWorld; -import com.sk89q.worldedit.math.BlockVector3; -import com.sk89q.worldedit.util.Location; import com.sk89q.worldguard.LocalPlayer; import com.sk89q.worldguard.WorldGuard; import com.sk89q.worldguard.bukkit.WorldGuardPlugin; import com.sk89q.worldguard.protection.ApplicableRegionSet; +import com.sk89q.worldguard.protection.association.RegionAssociable; +import com.sk89q.worldguard.protection.flags.Flags; import com.sk89q.worldguard.protection.flags.StateFlag; import com.sk89q.worldguard.protection.flags.registry.FlagRegistry; -import com.sk89q.worldguard.protection.managers.RegionManager; -import com.sk89q.worldguard.protection.regions.ProtectedRegion; -import com.sk89q.worldguard.protection.regions.RegionContainer; -import com.sk89q.worldguard.protection.regions.RegionQuery; import net.countercraft.movecraft.Movecraft; import net.countercraft.movecraft.MovecraftLocation; import net.countercraft.movecraft.config.Settings; @@ -65,16 +59,20 @@ public void onCraftTranslateEvent(CraftTranslateEvent event){ if(event.getCraft().getNotificationPlayer() == null) return; for(MovecraftLocation location : event.getNewHitBox()){ - if (canMoveInRegion(location, event.getCraft().getWorld())) { + final ApplicableRegionSet regions = WorldguardUtils.getRegionsAt(location.toBukkit(event.getCraft().getWorld())); + final LocalPlayer lp = Movecraft.getInstance().getWorldGuardPlugin().wrapPlayer(event.getCraft().getNotificationPlayer()); + final StateFlag.State state = regions.queryValue(lp, FLAG_MOVE); + if (state == StateFlag.State.ALLOW) { + continue; + } else if (state == StateFlag.State.DENY) { event.setFailMessage(I18nSupport.getInternationalisedString("WGCustomFlags - Translation Failed")); event.setCancelled(true); - return; + break; } - - if(!pilotHasAccessToRegion(event.getCraft().getNotificationPlayer(), location, event.getCraft().getWorld())){ + else if (!pilotHasAccessToRegion(event.getCraft().getNotificationPlayer(), location, event.getCraft().getWorld())){ event.setCancelled(true); event.setFailMessage(String.format( I18nSupport.getInternationalisedString( "Translation - WorldGuard - Not Permitted To Build" )+" @ %d,%d,%d", location.getX(), location.getY(), location.getZ() ) ); - return; + break; } } @@ -82,118 +80,57 @@ public void onCraftTranslateEvent(CraftTranslateEvent event){ @EventHandler public void onCraftRotateEvent(CraftRotateEvent event){ - if(!Settings.WorldGuardBlockMoveOnBuildPerm) - return; + if(event.getCraft().getNotificationPlayer() == null) return; for(MovecraftLocation location : event.getNewHitBox()){ - if (!canRotateInRegion(location, event.getCraft().getWorld())) { + final ApplicableRegionSet regions = WorldguardUtils.getRegionsAt(location.toBukkit(event.getCraft().getWorld())); + final LocalPlayer lp = Movecraft.getInstance().getWorldGuardPlugin().wrapPlayer(event.getCraft().getNotificationPlayer()); + if (regions.queryValue(lp, FLAG_ROTATE) == StateFlag.State.ALLOW) { + continue; + } else if (regions.queryValue(lp, FLAG_ROTATE) == StateFlag.State.DENY) { event.setFailMessage(I18nSupport.getInternationalisedString("WGCustomFlags - Rotation Failed")); event.setCancelled(true); - return; - } - if(!pilotHasAccessToRegion(event.getCraft().getNotificationPlayer(), location, event.getCraft().getWorld())){ + break; + } else if(!pilotHasAccessToRegion(event.getCraft().getNotificationPlayer(), location, event.getCraft().getWorld())){ event.setCancelled(true); event.setFailMessage(String.format( I18nSupport.getInternationalisedString("Rotation - WorldGuard - Not Permitted To Build" )+" @ %d,%d,%d", location.getX(), location.getY(), location.getZ())); - return; + break; } } } private boolean pilotHasAccessToRegion(Player player, MovecraftLocation location, World world){ + if(!Settings.WorldGuardBlockMoveOnBuildPerm) + return true; + ApplicableRegionSet regions = WorldguardUtils.getRegionsAt(location.toBukkit(world)); if (Settings.IsLegacy){ return LegacyUtils.canBuild(Movecraft.getInstance().getWorldGuardPlugin(), world, location, player); } else { - RegionQuery query = WorldGuard.getInstance().getPlatform().getRegionContainer().createQuery(); - LocalPlayer lPlayer = Movecraft.getInstance().getWorldGuardPlugin().wrapPlayer(player); - com.sk89q.worldedit.world.World weWorld = new BukkitWorld(world); - Location wgLoc = new Location(weWorld, location.getX(), location.getY(), location.getZ()); - ApplicableRegionSet regions = query.getApplicableRegions(wgLoc); - return regions.isOwnerOfAll(lPlayer) || regions.isMemberOfAll(lPlayer) || - player.hasPermission("worldguard.build.*"); - } - } - private boolean canRotateInRegion(MovecraftLocation location, World world) { - RegionManager manager; - ApplicableRegionSet regions; - if (Settings.IsLegacy) { - manager = LegacyUtils.getRegionManager(Movecraft.getInstance().getWorldGuardPlugin(), world); - regions = LegacyUtils.getApplicableRegions(manager, location.toBukkit(world)); - } else { - RegionContainer container = WorldGuard.getInstance().getPlatform().getRegionContainer(); - manager = container.get(BukkitAdapter.adapt(world)); - regions = manager.getApplicableRegions(BlockVector3.at(location.getX(), location.getY(), location.getZ())); - } - for (ProtectedRegion region : regions) { - if (region.getFlag(FLAG_ROTATE) == StateFlag.State.DENY) - return false; + final RegionAssociable associable = Movecraft.getInstance().getWorldGuardPlugin().wrapPlayer(player); + return regions.queryValue(associable, Flags.BUILD) == StateFlag.State.ALLOW; } - return true; } - private boolean canMoveInRegion(MovecraftLocation location, World world) { - RegionManager manager; - if (Settings.IsLegacy) { - manager = LegacyUtils.getRegionManager(Movecraft.getInstance().getWorldGuardPlugin(), world); - } else { - RegionContainer container = WorldGuard.getInstance().getPlatform().getRegionContainer(); - manager = container.get(BukkitAdapter.adapt(world)); - } - if (manager == null) { - return true; - } - ApplicableRegionSet regions = Settings.IsLegacy ? LegacyUtils.getApplicableRegions(manager, location.toBukkit(world)) : manager.getApplicableRegions(BlockVector3.at(location.getX(), location.getY(), location.getZ())); - for (ProtectedRegion region : regions) { - if (region.getFlag(FLAG_MOVE) == StateFlag.State.DENY) - return false; - } - return true; - } @EventHandler public void onCraftSink(CraftSinkEvent event){ Craft pcraft = event.getCraft(); Player notifyP = event.getCraft().getNotificationPlayer(); - if (Movecraft.getInstance().getWorldGuardPlugin() != null){ - WorldGuardPlugin wgPlugin = Movecraft.getInstance().getWorldGuardPlugin(); - ProtectedRegion region = null; - RegionManager regionManager; - if (Settings.IsLegacy){ - regionManager = LegacyUtils.getRegionManager(wgPlugin, pcraft.getWorld()); - } else { - RegionContainer container = WorldGuard.getInstance().getPlatform().getRegionContainer(); - regionManager = container.get(BukkitAdapter.adapt(pcraft.getWorld())); - } - for (MovecraftLocation location : pcraft.getHitBox()){ - ApplicableRegionSet regions; - if (Settings.IsLegacy) - regions = LegacyUtils.getApplicableRegions(regionManager, location.toBukkit(pcraft.getWorld())); - else { - regions = regionManager.getApplicableRegions(BlockVector3.at(location.getX(), location.getY(), location.getZ())); - } - for (ProtectedRegion pr : regions.getRegions()){ - if (WorldguardUtils.pvpAllowed(pr) || pr.getFlag(FLAG_SINK) == StateFlag.State.DENY){ - region = pr; - break; - } - } - if (region != null){ - break; - } - } - if (region == null) { - return; - } - if (notifyP == null) { - return; - } - if (Settings.WorldGuardBlockSinkOnPVPPerm && !WorldguardUtils.pvpAllowed(region)){ - notifyP.sendMessage(I18nSupport.getInternationalisedString("Player- Craft should sink but PVP is not allowed in this WorldGuard region")); - event.setCancelled(true); - } - if (region.getFlag(FLAG_SINK) == StateFlag.State.DENY) { + for (MovecraftLocation location : pcraft.getHitBox()) { + ApplicableRegionSet regions = WorldguardUtils.getRegionsAt(location.toBukkit(pcraft.getWorld())); + final LocalPlayer lp = Movecraft.getInstance().getWorldGuardPlugin().wrapPlayer(event.getCraft().getNotificationPlayer()); + final StateFlag.State state = regions.queryValue(lp, FLAG_SINK); + if (state == StateFlag.State.ALLOW) { + continue; + } else if (state == StateFlag.State.DENY) { notifyP.sendMessage(I18nSupport.getInternationalisedString("WGCustomFlags - Sinking a craft is not allowed in this WorldGuard region")); event.setCancelled(true); + break; + } else if (Settings.WorldGuardBlockSinkOnPVPPerm && !WorldguardUtils.pvpAllowed(regions)) { + notifyP.sendMessage(I18nSupport.getInternationalisedString("Player- Craft should sink but PVP is not allowed in this WorldGuard region")); + event.setCancelled(true); + break; } } } @@ -202,41 +139,16 @@ public void onCraftSink(CraftSinkEvent event){ public void onCraftDetect(CraftDetectEvent event) { Craft pcraft = event.getCraft(); Player notifyP = pcraft.getNotificationPlayer(); - WorldGuardPlugin wgPlugin = Movecraft.getInstance().getWorldGuardPlugin(); - ProtectedRegion region = null; - RegionManager regionManager; - if (Settings.IsLegacy){ - regionManager = LegacyUtils.getRegionManager(wgPlugin, pcraft.getWorld()); - } else { - RegionContainer container = WorldGuard.getInstance().getPlatform().getRegionContainer(); - regionManager = container.get(BukkitAdapter.adapt(pcraft.getWorld())); - } - for (MovecraftLocation location : pcraft.getHitBox()){ - ApplicableRegionSet regions; - if (Settings.IsLegacy) - regions = LegacyUtils.getApplicableRegions(regionManager, location.toBukkit(pcraft.getWorld())); - else { - regions = regionManager.getApplicableRegions(BlockVector3.at(location.getX(), location.getY(), location.getZ())); - } - for (ProtectedRegion pr : regions.getRegions()){ - if (pr.getFlag(FLAG_PILOT) == StateFlag.State.DENY){ - region = pr; - break; - } - } - if (region != null){ + for (MovecraftLocation location : pcraft.getHitBox()) { + ApplicableRegionSet regions = WorldguardUtils.getRegionsAt(location.toBukkit(pcraft.getWorld())); + final LocalPlayer lp = Movecraft.getInstance().getWorldGuardPlugin().wrapPlayer(event.getCraft().getNotificationPlayer()); + final StateFlag.State state = regions.queryValue(lp, FLAG_PILOT); + if (state == StateFlag.State.DENY) { + notifyP.sendMessage(I18nSupport.getInternationalisedString("WGCustomFlags - Detection Failed")); + event.setCancelled(true); break; } } - if (region == null) { - return; - } - if (notifyP == null) { - return; - } - if (region.getFlag(FLAG_PILOT) == StateFlag.State.DENY) { - notifyP.sendMessage(I18nSupport.getInternationalisedString("WGCustomFlags - Detection Failed")); - event.setCancelled(true); - } + } } From de41c7a83ef373097f25b5de6a758815f7e94138 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Wed, 29 Apr 2020 00:03:38 +0200 Subject: [PATCH 159/304] Fixed Movecraft breaking without cannons and bumped version --- modules/Movecraft/dependency-reduced-pom.xml | 2 +- modules/Movecraft/pom.xml | 2 +- .../movecraft/async/detection/DetectionTask.java | 5 ++++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/modules/Movecraft/dependency-reduced-pom.xml b/modules/Movecraft/dependency-reduced-pom.xml index b10319667..2b64b9be5 100644 --- a/modules/Movecraft/dependency-reduced-pom.xml +++ b/modules/Movecraft/dependency-reduced-pom.xml @@ -4,7 +4,7 @@ net.countercraft movecraft Movecraft - 7.0.0_for_1.8.8-1.15.2_beta_20 + 7.0.0_for_1.8.8-1.15.2_beta_21 http://github.com/apdevteam/Movecraft src/main/java diff --git a/modules/Movecraft/pom.xml b/modules/Movecraft/pom.xml index c0f3c2efb..09b6f51c7 100644 --- a/modules/Movecraft/pom.xml +++ b/modules/Movecraft/pom.xml @@ -10,7 +10,7 @@ UTF-8 - 7.0.0_for_1.8.8-1.15.2_beta_20 + 7.0.0_for_1.8.8-1.15.2_beta_21 spigot-repo diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/detection/DetectionTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/detection/DetectionTask.java index 3d18b9f6e..55a9da0c0 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/detection/DetectionTask.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/detection/DetectionTask.java @@ -407,7 +407,7 @@ private void checkMaxSignLimits() { } for (Map.Entry, Double> entry : craft.getType().getMaxSignsWithString().entrySet()) { final double limit = entry.getValue(); - int count = signWithStringCount.get(entry.getKey()); + int count = signWithStringCount.getOrDefault(entry.getKey(), 0); if (limit >= 10000.0) { int max = (int) (limit - 10000.0); if (count <= max) { @@ -426,6 +426,9 @@ private void checkMaxSignLimits() { } private void checkMaxCannons() { + if (Movecraft.getInstance().getCannonsPlugin() == null) { + return; + } for (Cannon can : CannonsAPI.getCannonsInBox(hitBox.getMidPoint().toBukkit(world), hitBox.getXLength(), hitBox.getYLength(), hitBox.getZLength())) { for (Location barrelLoc : can.getCannonDesign().getBarrelBlocks(can)) { if (!hitBox.contains(MathUtils.bukkit2MovecraftLoc(barrelLoc))) { From 3b454df163bc688a41d8204f897d2e19a4ff8a66 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Wed, 29 Apr 2020 03:43:15 +0200 Subject: [PATCH 160/304] Fixed IllegalArgumentException due to negative progress in SiegeProgressTask --- .../countercraft/movecraft/warfare/siege/SiegeProgressTask.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/siege/SiegeProgressTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/siege/SiegeProgressTask.java index 21fd99336..dba489832 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/siege/SiegeProgressTask.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/siege/SiegeProgressTask.java @@ -28,7 +28,7 @@ public SiegeProgressTask(Siege siege) { public void run() { addPlayersToProgressBar(); int timeLeft = (siege.getDuration() - (int) ((System.currentTimeMillis() - siege.getStartTime())/1000)); - double progress = (double) (siege.getDelayBeforeStart() - timeLeft) / (double) (siege.getDuration() - siege.getDelayBeforeStart()); + double progress = (double) (siege.getDelayBeforeStart() - timeLeft) / (double) siege.getDuration(); siege.getProgressBar().setProgress(Math.min(progress, 1.0)); Player siegeLeader = Movecraft.getInstance().getServer().getPlayer(siege.getPlayerUUID()); Craft siegeCraft = CraftManager.getInstance().getCraftByPlayer(siegeLeader); From 2b46ad62df54faedd2a346fe062ddc5b86c5226a Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Wed, 29 Apr 2020 15:37:22 +0200 Subject: [PATCH 161/304] Bump version --- modules/Movecraft/dependency-reduced-pom.xml | 2 +- modules/Movecraft/pom.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/Movecraft/dependency-reduced-pom.xml b/modules/Movecraft/dependency-reduced-pom.xml index 2b64b9be5..d4546c3e0 100644 --- a/modules/Movecraft/dependency-reduced-pom.xml +++ b/modules/Movecraft/dependency-reduced-pom.xml @@ -4,7 +4,7 @@ net.countercraft movecraft Movecraft - 7.0.0_for_1.8.8-1.15.2_beta_21 + 7.0.0_for_1.8.8-1.15.2_beta_22 http://github.com/apdevteam/Movecraft src/main/java diff --git a/modules/Movecraft/pom.xml b/modules/Movecraft/pom.xml index 09b6f51c7..bda0c3b3b 100644 --- a/modules/Movecraft/pom.xml +++ b/modules/Movecraft/pom.xml @@ -10,7 +10,7 @@ UTF-8 - 7.0.0_for_1.8.8-1.15.2_beta_21 + 7.0.0_for_1.8.8-1.15.2_beta_22 spigot-repo From 11c4604c9806f7168c80b1291c949bb6906ad3b6 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Mon, 4 May 2020 12:06:51 +0200 Subject: [PATCH 162/304] Fixed siege among other things --- .../net/countercraft/movecraft/Movecraft.java | 1 + .../movecraft/async/AsyncManager.java | 40 ------------------- .../async/detection/DetectionTask.java | 10 +---- .../movecraft/listener/InteractListener.java | 3 ++ .../update/CraftTranslateCommand.java | 4 +- .../movecraft/utils/CannonsUtils.java | 30 ++++++++++++++ .../warfare/siege/SiegeProgressTask.java | 3 +- .../Movecraft/src/main/resources/config.yml | 1 + .../movecraft/config/Settings.java | 1 + 9 files changed, 42 insertions(+), 51 deletions(-) create mode 100644 modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/CannonsUtils.java diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java index 9aca62bb0..1c66b2598 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java @@ -229,6 +229,7 @@ public void onEnable() { Settings.RequireNamePerm = getConfig().getBoolean("RequireNamePerm", false); Settings.TNTContactExplosives = getConfig().getBoolean("TNTContactExplosives", true); Settings.FadeWrecksAfter = getConfig().getInt("FadeWrecksAfter", 0); + Settings.RequireSneakingForDirectControl = getConfig().getBoolean("RequireSneakingForDirectControl", false); if (getConfig().contains("FuelTypes")){ Map fuelTypes = getConfig().getConfigurationSection("FuelTypes").getValues(false); int numFuelTypes = 0; diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java index 909fe0290..c35598953 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java @@ -1078,43 +1078,6 @@ private void processGravity(){ } } - //Removed for refactor - /*private void processScheduledBlockChanges() { - for (World w : Bukkit.getWorlds()) { - if (w != null && CraftManager.getInstance().getCraftsInWorld(w) != null) { - ArrayList updateCommands = new ArrayList<>(); - for (Craft pcraft : CraftManager.getInstance().getCraftsInWorld(w)) { - HashMap scheduledBlockChanges = pcraft.getScheduledBlockChanges(); - if (scheduledBlockChanges != null) { - Iterator mucI = scheduledBlockChanges.keySet().iterator(); - boolean madeChanges = false; - while (mucI.hasNext()) { - BlockTranslateCommand muc = mucI.next(); - if ((pcraft.getScheduledBlockChanges().get(muc) < System.currentTimeMillis()) && (pcraft.isNotProcessing())) { - int cx = muc.getNewBlockLocation().getX() >> 4; - int cz = muc.getNewBlockLocation().getZ() >> 4; - if (!w.isChunkLoaded(cx, cz)) { - w.loadChunk(cx, cz); - } - if (w.getBlockAt(muc.getNewBlockLocation().getX(), muc.getNewBlockLocation().getY(), muc.getNewBlockLocation().getZ()).getType() == muc.getType()) { - // if the block you will be updating later has changed type, something went horribly wrong: it burned away, was flooded, or was destroyed. Don't update it - updateCommands.add(muc); - } - mucI.remove(); - madeChanges = true; - } - } - if (madeChanges) { - pcraft.setScheduledBlockChanges(scheduledBlockChanges); - } - } - } - if (updateCommands.size() > 0) { - MapUpdateManager.getInstance().scheduleUpdates(updateCommands.toArray(new BlockTranslateCommand[1])); - } - } - } - }*/ public void run() { clearAll(); @@ -1128,9 +1091,6 @@ public void run() { processFadingBlocks(); processDetection(); processAlgorithmQueue(); - //processScheduledBlockChanges(); -// if(Settings.CompatibilityMode==false) -// FastBlockChanger.getInstance().run(); // now cleanup craft that are bugged and have not moved in the past 60 seconds, but have no pilot or are still processing for (Craft pcraft : CraftManager.getInstance()) { diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/detection/DetectionTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/detection/DetectionTask.java index 55a9da0c0..8a77c1d6f 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/detection/DetectionTask.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/detection/DetectionTask.java @@ -18,7 +18,6 @@ package net.countercraft.movecraft.async.detection; -import at.pavlov.cannons.API.CannonsAPI; import at.pavlov.cannons.cannon.Cannon; import net.countercraft.movecraft.Movecraft; import net.countercraft.movecraft.MovecraftBlock; @@ -429,13 +428,8 @@ private void checkMaxCannons() { if (Movecraft.getInstance().getCannonsPlugin() == null) { return; } - for (Cannon can : CannonsAPI.getCannonsInBox(hitBox.getMidPoint().toBukkit(world), hitBox.getXLength(), hitBox.getYLength(), hitBox.getZLength())) { - for (Location barrelLoc : can.getCannonDesign().getBarrelBlocks(can)) { - if (!hitBox.contains(MathUtils.bukkit2MovecraftLoc(barrelLoc))) { - continue; - } - break; - } + for (Cannon can : CannonsUtils.getCannonsInHitBox(hitBox, world)) { + for (List limitedCannonNames : craft.getType().getMaxCannons().keySet()) { if (!limitedCannonNames.contains(can.getCannonDesign().getDesignName().toLowerCase())) { continue; diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/InteractListener.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/InteractListener.java index ac5331e38..befb49eed 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/InteractListener.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/InteractListener.java @@ -143,6 +143,9 @@ public void onPlayerInteractStick(PlayerInteractEvent event) { if (event.getItem() == null || event.getItem().getType() != Settings.PilotTool) { return; } + if (Settings.RequireSneakingForDirectControl && !event.getPlayer().isSneaking()) { + return; + } Craft craft = CraftManager.getInstance().getCraftByPlayer(event.getPlayer()); if (craft == null) { return; diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftTranslateCommand.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftTranslateCommand.java index 3dd7f71e0..c8a367011 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftTranslateCommand.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftTranslateCommand.java @@ -111,8 +111,8 @@ public void doUpdate() { } } } - MutableHitBox interior = new HashHitBox(); - MutableHitBox exterior = new HashHitBox(); + MutableHitBox interior = new BitmapHitBox(); + MutableHitBox exterior = new BitmapHitBox(); if(passthroughBlocks.isEmpty()){ //translate the craft Movecraft.getInstance().getWorldHandler().translateCraft(craft,displacement); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/CannonsUtils.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/CannonsUtils.java new file mode 100644 index 000000000..a51396a0e --- /dev/null +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/CannonsUtils.java @@ -0,0 +1,30 @@ +package net.countercraft.movecraft.utils; + +import at.pavlov.cannons.API.CannonsAPI; +import at.pavlov.cannons.cannon.Cannon; +import net.countercraft.movecraft.craft.Craft; +import org.bukkit.Location; +import org.bukkit.World; + +import java.util.HashSet; +import java.util.Set; + +public class CannonsUtils { + public static Set getCannonsInHitBox(HitBox hitBox, World world) { + Set foundCannons = new HashSet<>(); + for (Cannon can : CannonsAPI.getCannonsInBox(hitBox.getMidPoint().toBukkit(world), hitBox.getXLength(), hitBox.getYLength(), hitBox.getZLength())) { + for (Location barrelLoc : can.getCannonDesign().getBarrelBlocks(can)) { + if (!hitBox.contains(MathUtils.bukkit2MovecraftLoc(barrelLoc))) { + continue; + } + foundCannons.add(can); + break; + } + } + return foundCannons; + } + + public static Set getCannonsOnCraft(Craft c) { + return getCannonsInHitBox(c.getHitBox(), c.getWorld()); + } +} diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/siege/SiegeProgressTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/siege/SiegeProgressTask.java index dba489832..cc2a83ffa 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/siege/SiegeProgressTask.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/warfare/siege/SiegeProgressTask.java @@ -28,7 +28,8 @@ public SiegeProgressTask(Siege siege) { public void run() { addPlayersToProgressBar(); int timeLeft = (siege.getDuration() - (int) ((System.currentTimeMillis() - siege.getStartTime())/1000)); - double progress = (double) (siege.getDelayBeforeStart() - timeLeft) / (double) siege.getDuration(); + int timePassed = (siege.getDuration() - siege.getDelayBeforeStart()) - timeLeft; + double progress = (double) timePassed / ((double) siege.getDuration() - siege.getDelayBeforeStart()); siege.getProgressBar().setProgress(Math.min(progress, 1.0)); Player siegeLeader = Movecraft.getInstance().getServer().getPlayer(siege.getPlayerUUID()); Craft siegeCraft = CraftManager.getInstance().getCraftByPlayer(siegeLeader); diff --git a/modules/Movecraft/src/main/resources/config.yml b/modules/Movecraft/src/main/resources/config.yml index 776576016..b3a436e88 100644 --- a/modules/Movecraft/src/main/resources/config.yml +++ b/modules/Movecraft/src/main/resources/config.yml @@ -14,6 +14,7 @@ FireballPenetration: true ProtectPilotedCrafts: true DisableSpillProtection: false RequireCreatePerm: false # require users to have the movecract..create permission in order to place command signs +RequireSneakingForDirectControl: false #Require if player should sneak in order to activate direct control TNTContactExplosives: true DisableCrates: true FadeWrecksAfter: 600 diff --git a/modules/api/src/main/java/net/countercraft/movecraft/config/Settings.java b/modules/api/src/main/java/net/countercraft/movecraft/config/Settings.java index 6cea4ee05..f95ef6759 100644 --- a/modules/api/src/main/java/net/countercraft/movecraft/config/Settings.java +++ b/modules/api/src/main/java/net/countercraft/movecraft/config/Settings.java @@ -44,6 +44,7 @@ public class Settings { public static boolean RequireCreatePerm = false; public static boolean RequireNamePerm = false; public static boolean TNTContactExplosives = true; + public static boolean RequireSneakingForDirectControl = false; public static HashSet ForbiddenRemoteSigns; public static int FadeWrecksAfter = 0; public static int ManOverboardTimeout = 60; From d5330f94e22f7a0f84a85168b175e91ddd569dd8 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Mon, 4 May 2020 21:19:36 +0200 Subject: [PATCH 163/304] bump version --- modules/Movecraft/dependency-reduced-pom.xml | 2 +- modules/Movecraft/pom.xml | 2 +- modules/Movecraft/src/main/resources/config_legacy.yml | 1 + 3 files changed, 3 insertions(+), 2 deletions(-) diff --git a/modules/Movecraft/dependency-reduced-pom.xml b/modules/Movecraft/dependency-reduced-pom.xml index d4546c3e0..693c75ec2 100644 --- a/modules/Movecraft/dependency-reduced-pom.xml +++ b/modules/Movecraft/dependency-reduced-pom.xml @@ -4,7 +4,7 @@ net.countercraft movecraft Movecraft - 7.0.0_for_1.8.8-1.15.2_beta_22 + 7.0.0_for_1.8.8-1.15.2_beta_23 http://github.com/apdevteam/Movecraft src/main/java diff --git a/modules/Movecraft/pom.xml b/modules/Movecraft/pom.xml index bda0c3b3b..133288841 100644 --- a/modules/Movecraft/pom.xml +++ b/modules/Movecraft/pom.xml @@ -10,7 +10,7 @@ UTF-8 - 7.0.0_for_1.8.8-1.15.2_beta_22 + 7.0.0_for_1.8.8-1.15.2_beta_23 spigot-repo diff --git a/modules/Movecraft/src/main/resources/config_legacy.yml b/modules/Movecraft/src/main/resources/config_legacy.yml index 224f420ef..992fa8f03 100644 --- a/modules/Movecraft/src/main/resources/config_legacy.yml +++ b/modules/Movecraft/src/main/resources/config_legacy.yml @@ -12,6 +12,7 @@ FireballPenetration: true ProtectPilotedCrafts: true DisableSpillProtection: false RequireCreatePerm: false # require users to have the movecract..create permission in order to place command signs +RequireSneakingForDirectControl: false #Require if player should sneak in order to activate direct control RequireNamePerm: false TNTContactExplosives: true DisableCrates: true From ff3b1ec46e581f4213525d62d0963fb4b211fc33 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Tue, 5 May 2020 18:39:47 +0200 Subject: [PATCH 164/304] Fixed subcraft rotate being broken --- .../net/countercraft/movecraft/sign/SubcraftRotateSign.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/SubcraftRotateSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/SubcraftRotateSign.java index 49ebe674d..816050c32 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/SubcraftRotateSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/SubcraftRotateSign.java @@ -95,14 +95,14 @@ public void run() { public void run() { subCraft.rotate(rotation, startPoint, true); } - }.runTaskLater(Movecraft.getInstance(), 3); + }.runTaskLater(Movecraft.getInstance(), 4); new BukkitRunnable() { @Override public void run() { rotatingCrafts.remove(startPoint); CraftManager.getInstance().removeCraft(subCraft); } - }.runTaskLater(Movecraft.getInstance(), 6); + }.runTaskLater(Movecraft.getInstance(), 7); event.setCancelled(true); } From 0732ab63049d97e95447e156df23af752cfd8566 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Tue, 5 May 2020 21:12:45 +0200 Subject: [PATCH 165/304] small fix --- modules/Movecraft/src/main/resources/plugin.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/modules/Movecraft/src/main/resources/plugin.yml b/modules/Movecraft/src/main/resources/plugin.yml index 5892fd893..f6e215e1e 100644 --- a/modules/Movecraft/src/main/resources/plugin.yml +++ b/modules/Movecraft/src/main/resources/plugin.yml @@ -2,7 +2,6 @@ name: Movecraft softdepend: [WorldGuard, WorldEdit, FastAsyncWorldEdit, Cannons, Vault ,Essentials, WGCustomFlags, Towny] version: ${project.version} api-version: 1.13 -#version: ${env.BUILD_NUMBER} description: The original flight and movement plugin for minecraft. authors: [BaccaYarro, cccm5, eirikh1996] website: http://www.youtube.com/BaccaYarro @@ -35,7 +34,7 @@ commands: usage: /manoverboard siege: description: If the region you are standing in is configured for Siege, lays siege to it - usage: /siege + usage: /siege assaultinfo: description: Gives you information about the region(s) you are in, and if they are available for Assault usage: /assaultinfo From 104b88b8db620e73f79c00130657786ba7a0986b Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Thu, 7 May 2020 12:26:30 +0200 Subject: [PATCH 166/304] Fixed private BitmapHitBox constructor not recalculating bounds --- .../main/java/net/countercraft/movecraft/utils/BitmapHitBox.java | 1 + 1 file changed, 1 insertion(+) diff --git a/modules/api/src/main/java/net/countercraft/movecraft/utils/BitmapHitBox.java b/modules/api/src/main/java/net/countercraft/movecraft/utils/BitmapHitBox.java index d00e7de00..cade406dd 100644 --- a/modules/api/src/main/java/net/countercraft/movecraft/utils/BitmapHitBox.java +++ b/modules/api/src/main/java/net/countercraft/movecraft/utils/BitmapHitBox.java @@ -31,6 +31,7 @@ public BitmapHitBox() { private BitmapHitBox(Roaring64NavigableMap backing) { this.backing = backing; localMinY = new Long2IntOpenHashMap(); + validateBounds(); } public BitmapHitBox(HitBox hitBox){ From 3e17673cbc71ac83b4b1be9c7dd38ea50cad96ad Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Thu, 7 May 2020 21:21:15 +0200 Subject: [PATCH 167/304] Fixed repair bug causing certain blocks to be ommitted --- modules/api/dependency-reduced-pom.xml | 4 ++++ .../countercraft/movecraft/compat/we7/IMovecraftRepair.java | 6 ++---- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/modules/api/dependency-reduced-pom.xml b/modules/api/dependency-reduced-pom.xml index 2b987050a..5ac148d35 100644 --- a/modules/api/dependency-reduced-pom.xml +++ b/modules/api/dependency-reduced-pom.xml @@ -81,6 +81,10 @@ + + spigot-repo + https://hub.spigotmc.org/nexus/content/groups/public/ + sk89q-repo http://maven.sk89q.com/repo/ diff --git a/modules/worldedit/WE7Utils/src/main/java/net/countercraft/movecraft/compat/we7/IMovecraftRepair.java b/modules/worldedit/WE7Utils/src/main/java/net/countercraft/movecraft/compat/we7/IMovecraftRepair.java index 19f2eb70e..cfa86f161 100644 --- a/modules/worldedit/WE7Utils/src/main/java/net/countercraft/movecraft/compat/we7/IMovecraftRepair.java +++ b/modules/worldedit/WE7Utils/src/main/java/net/countercraft/movecraft/compat/we7/IMovecraftRepair.java @@ -12,8 +12,8 @@ import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard; import com.sk89q.worldedit.extent.clipboard.Clipboard; import com.sk89q.worldedit.extent.clipboard.io.*; -import com.sk89q.worldedit.function.mask.BlockMask; import com.sk89q.worldedit.function.mask.BlockTypeMask; +import com.sk89q.worldedit.function.mask.ExistingBlockMask; import com.sk89q.worldedit.function.operation.ForwardExtentCopy; import com.sk89q.worldedit.function.operation.Operations; import com.sk89q.worldedit.math.BlockVector3; @@ -51,7 +51,6 @@ public class IMovecraftRepair extends MovecraftRepair { private final HashMap>> locMissingBlocksMap = new HashMap<>(); private final HashMap numDiffBlocksMap = new HashMap<>(); private final HashMap, Double>> missingBlocksMap = new HashMap<>(); - private final HashMap distanceMap = new HashMap<>(); private final Plugin plugin; public IMovecraftRepair(Plugin plugin) { @@ -79,7 +78,7 @@ public boolean saveCraftRepairState(Craft craft, Sign sign) { clipboard.setOrigin(origin); Extent source = WorldEdit.getInstance().getEditSessionFactory().getEditSession(weWorld, -1); ForwardExtentCopy copy = new ForwardExtentCopy(source, region, clipboard.getOrigin(), clipboard, clipboard.getOrigin()); - BlockMask mask = new BlockMask(source, baseBlocksFromCraft(craft)); + ExistingBlockMask mask = new ExistingBlockMask(source); copy.setSourceMask(mask); final HitBox outsideLocs = CollectionUtils.filter(solidBlockLocs(world, region), hitBox); try { @@ -227,7 +226,6 @@ public Clipboard loadCraftRepairStateClipboard(Craft craft, Sign sign) { qtyToConsume = 0; } if (type.name().endsWith("_SLAB")){ - plugin.getLogger().info(type.name()); for (Property property : block.getStates().keySet()){ if (!(property instanceof EnumProperty)){ continue; From db2ff207741600ddab6beed5596195d7e7aa909f Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Thu, 7 May 2020 21:21:49 +0200 Subject: [PATCH 168/304] bump version --- modules/Movecraft/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/Movecraft/pom.xml b/modules/Movecraft/pom.xml index 133288841..cd84c8d2e 100644 --- a/modules/Movecraft/pom.xml +++ b/modules/Movecraft/pom.xml @@ -10,7 +10,7 @@ UTF-8 - 7.0.0_for_1.8.8-1.15.2_beta_23 + 7.0.0_for_1.8.8-1.15.2_beta_24 spigot-repo From 50b437906f6c6f5d22a0d37fe5a9eb40e50fc0bb Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Thu, 7 May 2020 21:30:45 +0200 Subject: [PATCH 169/304] bump version --- modules/Movecraft/dependency-reduced-pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/Movecraft/dependency-reduced-pom.xml b/modules/Movecraft/dependency-reduced-pom.xml index 693c75ec2..3332b3f58 100644 --- a/modules/Movecraft/dependency-reduced-pom.xml +++ b/modules/Movecraft/dependency-reduced-pom.xml @@ -4,7 +4,7 @@ net.countercraft movecraft Movecraft - 7.0.0_for_1.8.8-1.15.2_beta_23 + 7.0.0_for_1.8.8-1.15.2_beta_24 http://github.com/apdevteam/Movecraft src/main/java From c46a3cebefbfa92a737dec070571f50dc72885f0 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Sun, 24 May 2020 18:41:32 +0200 Subject: [PATCH 170/304] Replaced broken VaultAPI reference with one that actually works --- modules/Movecraft/dependency-reduced-pom.xml | 6 +++--- modules/Movecraft/pom.xml | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/modules/Movecraft/dependency-reduced-pom.xml b/modules/Movecraft/dependency-reduced-pom.xml index 3332b3f58..6b6cf2997 100644 --- a/modules/Movecraft/dependency-reduced-pom.xml +++ b/modules/Movecraft/dependency-reduced-pom.xml @@ -162,8 +162,8 @@ https://github.com/DerPavlov/mvn-repo/raw/master/ - vault-repo - http://nexus.hc.to/content/repositories/pub_releases + jitpack.io + https://jitpack.io ess-repo @@ -224,7 +224,7 @@ compile - net.milkbowl.vault + com.github.MilkBowl VaultAPI 1.7 provided diff --git a/modules/Movecraft/pom.xml b/modules/Movecraft/pom.xml index cd84c8d2e..cf0ecf91d 100644 --- a/modules/Movecraft/pom.xml +++ b/modules/Movecraft/pom.xml @@ -25,8 +25,8 @@ https://github.com/DerPavlov/mvn-repo/raw/master/ - vault-repo - http://nexus.hc.to/content/repositories/pub_releases + jitpack.io + https://jitpack.io ess-repo @@ -157,7 +157,7 @@ - net.milkbowl.vault + com.github.MilkBowl VaultAPI 1.7 provided From b73b023c5edcd7c927bad98ec14b591e7cf972e6 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Sun, 14 Jun 2020 00:56:44 +0200 Subject: [PATCH 171/304] Merge https://github.com/APDevTeam/Movecraft # Conflicts: # modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java # modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/BlockListener.java # modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/EntityUpdateCommand.java # modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/NameSign.java # modules/api/src/main/java/net/countercraft/movecraft/craft/Craft.java # modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java # modules/api/src/main/java/net/countercraft/movecraft/utils/TeleportUtils.java --- .../update/EntityUpdateCommand.java | 13 ----- modules/v1_16_R1/pom.xml | 53 +++++++++++++++++++ pom.xml | 1 + 3 files changed, 54 insertions(+), 13 deletions(-) create mode 100644 modules/v1_16_R1/pom.xml diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/EntityUpdateCommand.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/EntityUpdateCommand.java index 991032705..72241921d 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/EntityUpdateCommand.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/EntityUpdateCommand.java @@ -51,7 +51,6 @@ public final Entity getEntity() { @Override public void doUpdate() { -<<<<<<< HEAD final Location entityLoc = entity.getVehicle() != null ? entity.getVehicle().getLocation() : entity.getLocation(); if (!(entity instanceof Player)) { TeleportUtils.teleportEntity(entity, new Location(entity.getWorld(), entityLoc.getX() + x, entityLoc.getY() + y, entityLoc.getZ() + z,yaw + entityLoc.getYaw(),pitch + entityLoc.getPitch())); @@ -59,18 +58,6 @@ public void doUpdate() { } //Movecraft.getInstance().getWorldHandler().addPlayerLocation((Player) entity,x,y,z,yaw,pitch); TeleportUtils.teleport((Player) entity, new Location(entity.getWorld(), entityLoc.getX() + x, entityLoc.getY() + y, entityLoc.getZ() + z), yaw); - - - -======= - Location playerLoc = entity.getLocation(); - if (!(entity instanceof Player)) { - entity.teleport(new Location(entity.getWorld(), x + playerLoc.getX(),y + playerLoc.getY(),z + playerLoc.getZ(),yaw + playerLoc.getYaw(),pitch + playerLoc.getPitch())); - return; - } - //Movecraft.getInstance().getWorldHandler().addPlayerLocation((Player) entity,x,y,z,yaw,pitch); - TeleportUtils.teleport((Player) entity, new Location(entity.getWorld(), playerLoc.getX() + x, playerLoc.getY() + y, playerLoc.getZ() + z), yaw); ->>>>>>> 9060ed04dbd6a53dbdabac97c8ce3f40e572ee93 } @Override diff --git a/modules/v1_16_R1/pom.xml b/modules/v1_16_R1/pom.xml new file mode 100644 index 000000000..c8350c2e0 --- /dev/null +++ b/modules/v1_16_R1/pom.xml @@ -0,0 +1,53 @@ + + + + movecraft-parent + net.countercraft + parent + ../../pom.xml + + 4.0.0 + + movecraft-v1_16_R1 + Movecraft-v1_16_R1 + v1_16_R1 + jar + + + net.countercraft + movecraft-api + API + jar + + + + src/main/java + + + org.apache.maven.plugins + maven-compiler-plugin + 3.7.0 + + + net/countercraft/movecraft/compat/v1_16_R1/** + + 1.8 + 1.8 + + + + org.apache.maven.plugins + maven-jar-plugin + 2.4 + + + net/countercraft/movecraft/compat/v1_16_R1/** + + + + + + + \ No newline at end of file diff --git a/pom.xml b/pom.xml index 69cbfb288..e62dc4bb7 100644 --- a/pom.xml +++ b/pom.xml @@ -31,6 +31,7 @@ modules/worldedit/WE6Utils modules/worldedit/WE7Utils modules/Movecraft + modules/v1_16_R1 From ec41de3b90cbfe32ecff6af9c7fa498d4323939a Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Sun, 14 Jun 2020 12:13:42 +0200 Subject: [PATCH 172/304] Fixed changes that was reverted in multiworld merge --- .../movecraft/commands/SiegeCommand.java | 2 +- .../countercraft/movecraft/craft/ICraft.java | 4 +- .../countercraft/movecraft/craft/Craft.java | 12 ++--- .../movecraft/craft/CraftType.java | 45 +++++++++++++++++-- .../compat/v1_8_R3/IWorldHandler.java | 12 ++--- .../compat/v1_9_R2/IWorldHandler.java | 12 ++--- 6 files changed, 65 insertions(+), 22 deletions(-) diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/SiegeCommand.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/SiegeCommand.java index f0cf50a43..a7bee1afa 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/SiegeCommand.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/SiegeCommand.java @@ -163,7 +163,7 @@ private boolean beginCommand(CommandSender commandSender){ player.sendMessage(MOVECRAFT_COMMAND_PREFIX + I18nSupport.getInternationalisedString("Siege - Must pilot siege craft"));// return true; } - if (siege.getCooldown() > ((System.currentTimeMillis() - siege.getStartTime()) / 1000) + siege.getDuration()) { + if (siege.getCooldown() > ((System.currentTimeMillis() - siege.getStartTime()) / 1000) - siege.getDuration()) { player.sendMessage(MOVECRAFT_COMMAND_PREFIX + I18nSupport.getInternationalisedString("Siege - Siege has recently taken place")); return true; } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/ICraft.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/ICraft.java index d8262e67c..c8bd610c1 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/ICraft.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/ICraft.java @@ -95,9 +95,9 @@ public Set getContacts() { MovecraftLocation ccenter = this.getHitBox().getMidPoint(); MovecraftLocation tcenter = contact.getHitBox().getMidPoint(); int distsquared = ccenter.distanceSquared(tcenter); - int detectionRange = (int) (contact.getOrigBlockCount() * (tcenter.getY() > 65 ? contact.getType().getDetectionMultiplier(contact.getW()) : contact.getType().getUnderwaterDetectionMultiplier(contact.getW()))); + int detectionRange = (int) (contact.getOrigBlockCount() * (tcenter.getY() > 65 ? contact.getType().getDetectionMultiplier(world) : contact.getType().getUnderwaterDetectionMultiplier(world))); detectionRange = detectionRange * 10; - int staticDetectionRange = (int) ((tcenter.getY() > 65 ? contact.getType().getStaticDetectionRange() : contact.getType().getUnderwaterStaticDetectionRange())); + int staticDetectionRange = (int) ((tcenter.getY() > 65 ? contact.getType().getStaticDetectionRange(world) : contact.getType().getUnderwaterStaticDetectionRange(world))); staticDetectionRange = staticDetectionRange * staticDetectionRange; if (distsquared <= staticDetectionRange) { contacts.add(contact); diff --git a/modules/api/src/main/java/net/countercraft/movecraft/craft/Craft.java b/modules/api/src/main/java/net/countercraft/movecraft/craft/Craft.java index a6626e4c9..08cf65e86 100644 --- a/modules/api/src/main/java/net/countercraft/movecraft/craft/Craft.java +++ b/modules/api/src/main/java/net/countercraft/movecraft/craft/Craft.java @@ -373,11 +373,13 @@ public int getTickCooldown() { } // Dynamic Fly Block Speed - if(type.getDynamicFlyBlockSpeedFactor() != 0){ - Material flyBlockMaterial = Material.getMaterial(type.getDynamicFlyBlock()); - double count = materials.get(flyBlockMaterial); - double woolRatio = count / hitBox.size(); - return Math.max((int)Math.round((20.0 * (type.getCruiseSkipBlocks(world) + 1)) / ((type.getDynamicFlyBlockSpeedFactor() * 1.5) * (woolRatio - .5) + (20.0 / type.getCruiseTickCooldown(world)) + 1)), 1); + if(type.getDynamicFlyBlockSpeedFactor() != 0) { + double count = 0.0, woolRatio = 0.0; + for (Material flyBlockMaterial : type.getDynamicFlyBlocks()) { + count += materials.get(flyBlockMaterial); + woolRatio += count / hitBox.size(); + } + return Math.max((int) Math.round((20.0 * (type.getCruiseSkipBlocks(world) + 1)) / ((type.getDynamicFlyBlockSpeedFactor() * 1.5) * (woolRatio - .5) + (20.0 / type.getCruiseTickCooldown(world)) + 1)), 1); } if(type.getDynamicLagSpeedFactor() == 0.0 || type.getDynamicLagPowerFactor() == 0.0 || Math.abs(type.getDynamicLagPowerFactor()) > 1.0) diff --git a/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java b/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java index f6c968887..b75906b56 100644 --- a/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java +++ b/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java @@ -86,7 +86,7 @@ final public class CraftType { private final int tickCooldown; @NotNull private final Map perWorldTickCooldown; // speed setting private final int hoverLimit; - private final int dynamicFlyBlock; + private final Set dynamicFlyBlocks; private final double fuelBurnRate; @NotNull private final Map perWorldFuelBurnRate; private final double sinkPercent; @@ -319,7 +319,36 @@ public CraftType(File f) { dynamicLagPowerFactor = doubleFromObject(data.getOrDefault("dynamicLagPowerFactor", 0d)); dynamicLagMinSpeed = doubleFromObject((data.getOrDefault("dynamicLagMinSpeed", 0d))); dynamicFlyBlockSpeedFactor = doubleFromObject(data.getOrDefault("dynamicFlyBlockSpeedFactor", 0d)); - dynamicFlyBlock = integerFromObject(data.getOrDefault("dynamicFlyBlock", 0)); + dynamicFlyBlocks = new HashSet<>(); + if (data.containsKey("dynamicFlyBlock")) { + Object d = data.get("dynamicFlyBlock"); + Material type; + if (d instanceof Integer) { + type = Material.getMaterial((int) d); + } else { + type = Material.getMaterial((String) d); + } + dynamicFlyBlocks.add(type); + } + if (data.containsKey("dynamicFlyBlocks")) { + Object d = data.get("dynamicFlyBlocks"); + if (d instanceof Integer) { + dynamicFlyBlocks.add(Material.getMaterial((int) d)); + } else if (d instanceof String){ + dynamicFlyBlocks.add(Material.getMaterial((String) d)); + } else if (d instanceof List) { + List l = (List) d; + for (Object i : l) { + Material type; + if (i instanceof Integer) { + type = Material.getMaterial((int) d); + } else { + type = Material.getMaterial((String) d); + } + dynamicFlyBlocks.add(type); + } + } + } chestPenalty = doubleFromObject(data.getOrDefault("chestPenalty", 0)); gravityInclineDistance = integerFromObject(data.getOrDefault("gravityInclineDistance", -1)); int dropdist = integerFromObject(data.getOrDefault("gravityDropDistance", -8)); @@ -852,8 +881,8 @@ public double getDynamicFlyBlockSpeedFactor() { return dynamicFlyBlockSpeedFactor; } - public int getDynamicFlyBlock() { - return dynamicFlyBlock; + public Set getDynamicFlyBlocks() { + return dynamicFlyBlocks; } public double getChestPenalty() { @@ -906,6 +935,10 @@ public Map, Double> getMaxCannons() { return maxCannons; } + /** + * @deprecated + */ + @Deprecated public double getStaticDetectionRange() { return staticDetectionRange; } @@ -914,6 +947,10 @@ public double getStaticDetectionRange(World world) { return perWorldStaticDetectionRange.getOrDefault(world.getName(), staticDetectionRange); } + /** + * @deprecated + */ + @Deprecated public double getUnderwaterStaticDetectionRange() { return underwaterStaticDetectionRange; } diff --git a/modules/v1_8_R3/src/main/java/net/countercraft/movecraft/compat/v1_8_R3/IWorldHandler.java b/modules/v1_8_R3/src/main/java/net/countercraft/movecraft/compat/v1_8_R3/IWorldHandler.java index 1c252fcdf..d802d47bb 100644 --- a/modules/v1_8_R3/src/main/java/net/countercraft/movecraft/compat/v1_8_R3/IWorldHandler.java +++ b/modules/v1_8_R3/src/main/java/net/countercraft/movecraft/compat/v1_8_R3/IWorldHandler.java @@ -151,7 +151,7 @@ public void rotateCraft(@NotNull Craft craft, @NotNull MovecraftLocation originP } @Override - public void translateCraft(@NotNull Craft craft, @NotNull MovecraftLocation displacement) { + public void translateCraft(@NotNull Craft craft, @NotNull MovecraftLocation displacement, org.bukkit.World world) { //TODO: Add supourt for rotations //A craftTranslateCommand should only occur if the craft is moving to a valid position //******************************************* @@ -163,11 +163,13 @@ public void translateCraft(@NotNull Craft craft, @NotNull MovecraftLocation disp positions.add(locationToPosition((movecraftLocation)).b(translateVector)); } + WorldServer oldNativeWorld = ((CraftWorld) craft.getWorld()).getHandle(); + WorldServer nativeWorld = ((CraftWorld) world).getHandle(); //******************************************* //* Step two: Get the tiles * //******************************************* - WorldServer nativeWorld = ((CraftWorld) craft.getWorld()).getHandle(); - List tiles = getTiles(positions, nativeWorld); + + List tiles = getTiles(positions, oldNativeWorld); //******************************************* //* Step three: Translate all the blocks * //******************************************* @@ -179,7 +181,7 @@ public void translateCraft(@NotNull Craft craft, @NotNull MovecraftLocation disp List blockData = new ArrayList<>(); List newPositions = new ArrayList<>(); for(BlockPosition position : positions){ - blockData.add(nativeWorld.getType(position)); + blockData.add(oldNativeWorld.getType(position)); newPositions.add(position.a(translateVector)); } //create the new block @@ -192,7 +194,7 @@ public void translateCraft(@NotNull Craft craft, @NotNull MovecraftLocation disp //******************************************* //* Step five: Destroy the leftovers * //******************************************* - Collection deletePositions = CollectionUtils.filter(positions,newPositions); + Collection deletePositions = oldNativeWorld == nativeWorld ? CollectionUtils.filter(positions,newPositions) : positions; setAir(deletePositions, nativeWorld); //******************************************* //* Step six: Process fire spread * diff --git a/modules/v1_9_R2/src/main/java/net/countercraft/movecraft/compat/v1_9_R2/IWorldHandler.java b/modules/v1_9_R2/src/main/java/net/countercraft/movecraft/compat/v1_9_R2/IWorldHandler.java index 79c7a3be2..929aedb01 100644 --- a/modules/v1_9_R2/src/main/java/net/countercraft/movecraft/compat/v1_9_R2/IWorldHandler.java +++ b/modules/v1_9_R2/src/main/java/net/countercraft/movecraft/compat/v1_9_R2/IWorldHandler.java @@ -143,7 +143,7 @@ public void rotateCraft(@NotNull Craft craft, @NotNull MovecraftLocation originP } @Override - public void translateCraft(@NotNull Craft craft, @NotNull MovecraftLocation displacement) { + public void translateCraft(@NotNull Craft craft, @NotNull MovecraftLocation displacement, org.bukkit.World world) { //TODO: Add supourt for rotations //A craftTranslateCommand should only occur if the craft is moving to a valid position //******************************************* @@ -155,11 +155,13 @@ public void translateCraft(@NotNull Craft craft, @NotNull MovecraftLocation disp positions.add(locationToPosition((movecraftLocation)).b(translateVector)); } + WorldServer oldNativeWorld = ((CraftWorld) craft.getWorld()).getHandle(); + WorldServer nativeWorld = ((CraftWorld) world).getHandle(); //******************************************* //* Step two: Get the tiles * //******************************************* - WorldServer nativeWorld = ((CraftWorld) craft.getWorld()).getHandle(); - List tiles = getTiles(positions, nativeWorld); + + List tiles = getTiles(positions, oldNativeWorld); //******************************************* //* Step three: Translate all the blocks * //******************************************* @@ -171,7 +173,7 @@ public void translateCraft(@NotNull Craft craft, @NotNull MovecraftLocation disp List blockData = new ArrayList<>(); List newPositions = new ArrayList<>(); for(BlockPosition position : positions){ - blockData.add(nativeWorld.getType(position)); + blockData.add(oldNativeWorld.getType(position)); newPositions.add(position.a(translateVector)); } //create the new block @@ -184,7 +186,7 @@ public void translateCraft(@NotNull Craft craft, @NotNull MovecraftLocation disp //******************************************* //* Step five: Destroy the leftovers * //******************************************* - Collection deletePositions = CollectionUtils.filter(positions,newPositions); + Collection deletePositions = oldNativeWorld == nativeWorld ? CollectionUtils.filter(positions,newPositions) : positions; setAir(deletePositions, nativeWorld); //******************************************* //* Step six: Process fire spread * From a0e1df58808555ca7d24a2aa07ff77ef24290d7b Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Sun, 14 Jun 2020 18:02:34 +0200 Subject: [PATCH 173/304] Fixed TranslationTask checking world border in origin world instead of destination world when switching worlds --- .../movecraft/async/translation/TranslationTask.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java index 74372f827..3fc386b42 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java @@ -216,7 +216,7 @@ protected void execute() throws InterruptedException, ExecutionException { fail(String.format(I18nSupport.getInternationalisedString("Translation - Failed Craft is obstructed") + " @ %d,%d,%d,%s", newLocation.getX(), newLocation.getY(), newLocation.getZ(), newLocation.toBukkit(craft.getW()).getBlock().getType().toString())); return; } - if (!withinWorldBorder(craft.getW(), newLocation)) { + if (!withinWorldBorder(world, newLocation)) { fail(I18nSupport.getInternationalisedString("Translation - Failed Craft cannot pass world border") + String.format(" @ %d,%d,%d", newLocation.getX(), newLocation.getY(), newLocation.getZ())); return; } From 2fa8cf4672b76348bffa9d434b324004c9aabcf6 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Mon, 15 Jun 2020 21:31:59 +0200 Subject: [PATCH 174/304] Fixes --- modules/Movecraft/dependency-reduced-pom.xml | 2 +- .../async/translation/TranslationTask.java | 2 +- .../update/CraftTranslateCommand.java | 18 +++++++++++------- .../mapUpdater/update/EntityUpdateCommand.java | 14 +++++++++----- .../movecraft/craft/CraftType.java | 5 ++++- .../compat/v1_13_R2/IWorldHandler.java | 2 +- .../compat/v1_14_R1/IWorldHandler.java | 2 +- .../compat/v1_15_R1/IWorldHandler.java | 2 +- .../compat/v1_8_R3/IWorldHandler.java | 2 +- .../compat/v1_9_R2/IWorldHandler.java | 2 +- pom.xml | 3 ++- 11 files changed, 33 insertions(+), 21 deletions(-) diff --git a/modules/Movecraft/dependency-reduced-pom.xml b/modules/Movecraft/dependency-reduced-pom.xml index 6b6cf2997..dacdd996a 100644 --- a/modules/Movecraft/dependency-reduced-pom.xml +++ b/modules/Movecraft/dependency-reduced-pom.xml @@ -4,7 +4,7 @@ net.countercraft movecraft Movecraft - 7.0.0_for_1.8.8-1.15.2_beta_24 + 7.0.0_for_1.8.8-1.15.2_beta_25 http://github.com/apdevteam/Movecraft src/main/java diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java index cd44f0bbc..2efad0ce8 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java @@ -508,7 +508,7 @@ public void run() { Bukkit.getServer().getPluginManager().callEvent(new CraftCollisionEvent(craft, collisionBox, world)); } - updates.add(new CraftTranslateCommand(craft, new MovecraftLocation(dx, dy, dz), world)); + updates.add(new CraftTranslateCommand(craft, new MovecraftLocation(dx, dy, dz), world, sound, volume)); //prevents torpedo and rocket pilots if (craft.getType().getMoveEntities() && !(craft.getSinking() && craft.getType().getOnlyMovePlayers())) { diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftTranslateCommand.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftTranslateCommand.java index 960ee8fe2..621dd6fb5 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftTranslateCommand.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftTranslateCommand.java @@ -10,15 +10,13 @@ import net.countercraft.movecraft.events.SignTranslateEvent; import net.countercraft.movecraft.mapUpdater.MapUpdateManager; import net.countercraft.movecraft.utils.*; -import org.bukkit.Bukkit; -import org.bukkit.Location; -import org.bukkit.Material; -import org.bukkit.World; +import org.bukkit.*; import org.bukkit.block.Block; import org.bukkit.block.Sign; import org.bukkit.entity.Entity; import org.bukkit.entity.EntityType; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.util.*; import java.util.logging.Logger; @@ -28,17 +26,23 @@ public class CraftTranslateCommand extends UpdateCommand { @NotNull private final Craft craft; @NotNull private final MovecraftLocation displacement; @NotNull private final World world; + @Nullable private final Sound sound; + private final float volume; public CraftTranslateCommand(@NotNull Craft craft, @NotNull MovecraftLocation displacement){ this.craft = craft; this.displacement = displacement; this.world = craft.getW(); + sound = null; + volume = 0f; } - public CraftTranslateCommand(@NotNull Craft craft, @NotNull MovecraftLocation displacement, @NotNull World world){ + public CraftTranslateCommand(@NotNull Craft craft, @NotNull MovecraftLocation displacement, @NotNull World world, @Nullable Sound sound, float volume){ this.craft = craft; this.displacement = displacement; this.world = world; + this.sound = sound; + this.volume = volume; } @@ -105,7 +109,7 @@ public void doUpdate() { if (playerVehicle != null && craft.getType().getOnlyMovePlayers()) { playerVehicle.eject(); } - toMove.add(new EntityUpdateCommand(entity, displacement.getX(), displacement.getY(), displacement.getZ(), 0, 0)); + toMove.add(new EntityUpdateCommand(entity, displacement.getX(), displacement.getY(), displacement.getZ(), 0, 0, world, sound, volume)); } else if (!craft.getType().getOnlyMovePlayers() || entity.getType() == EntityType.PRIMED_TNT) { boolean isPlayerVehicle = false; for (Entity pass : entity.getPassengers()) { @@ -118,7 +122,7 @@ public void doUpdate() { if (vehicle != null && vehicle.getPassengers().contains(entity) || entity == playerVehicle || isPlayerVehicle) { continue; } - toMove.add(new EntityUpdateCommand(entity, displacement.getX(), displacement.getY(), displacement.getZ(), 0, 0)); + toMove.add(new EntityUpdateCommand(entity, displacement.getX(), displacement.getY(), displacement.getZ(), 0, 0, world)); } } } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/EntityUpdateCommand.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/EntityUpdateCommand.java index fec0ef205..2d3898914 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/EntityUpdateCommand.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/EntityUpdateCommand.java @@ -84,8 +84,15 @@ public final Entity getEntity() { @Override public void doUpdate() { final Location entityLoc = entity.getVehicle() != null ? entity.getVehicle().getLocation() : entity.getLocation(); - if (!(entity instanceof Player)) { - TeleportUtils.teleportEntity(entity, new Location(entity.getWorld(), entityLoc.getX() + x, entityLoc.getY() + y, entityLoc.getZ() + z,yaw + entityLoc.getYaw(),pitch + entityLoc.getPitch())); + final Location destLoc = new Location(world, entityLoc.getX() + x, entityLoc.getY() + y, entityLoc.getZ() + z,yaw + entityLoc.getYaw(),pitch + entityLoc.getPitch()); + if (!entity.getWorld().equals(world)) { + entity.teleport(destLoc); + if (sound != null) { + ((Player) entity).playSound(entityLoc, sound, volume, 1.0f); + } + return; + } else if (!(entity instanceof Player)) { + TeleportUtils.teleportEntity(entity, destLoc); return; } Location playerLoc = entity.getLocation(); @@ -93,9 +100,6 @@ public void doUpdate() { //Movecraft.getInstance().getWorldHandler().addPlayerLocation((Player) entity,x,y,z,yaw,pitch); Location location = new Location(world, playerLoc.getX() + x, playerLoc.getY() + y, playerLoc.getZ() + z); TeleportUtils.teleport((Player) entity, location, yaw); - if (sound != null) { - ((Player) entity).playSound(location, sound, volume, 1.0f); - } } @Override diff --git a/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java b/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java index b75906b56..69e397b5e 100644 --- a/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java +++ b/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java @@ -297,7 +297,10 @@ public CraftType(File f) { } if(!blockedByWater){ passthroughBlocks.add(Material.WATER); - passthroughBlocks.add(Material.STATIONARY_WATER); + if (Settings.IsLegacy) + passthroughBlocks.add(Material.STATIONARY_WATER); + else + passthroughBlocks.add(Material.getMaterial("BUBBLE_COLUMN")); } forbiddenHoverOverBlocks = new HashSet<>(); if (data.containsKey("forbiddenHoverOverBlocks")){ diff --git a/modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/IWorldHandler.java b/modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/IWorldHandler.java index c2596da91..332e2fc58 100644 --- a/modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/IWorldHandler.java +++ b/modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/IWorldHandler.java @@ -197,7 +197,7 @@ public void translateCraft(@NotNull Craft craft, @NotNull MovecraftLocation disp //* Step five: Destroy the leftovers * //******************************************* Collection deletePositions = oldNativeWorld == nativeWorld ? CollectionUtils.filter(positions,newPositions) : positions; - setAir(deletePositions, nativeWorld); + setAir(deletePositions, oldNativeWorld); //******************************************* //* Step six: Process fire spread * //******************************************* diff --git a/modules/v1_14_R1/src/main/java/net/countercraft/movecraft/compat/v1_14_R1/IWorldHandler.java b/modules/v1_14_R1/src/main/java/net/countercraft/movecraft/compat/v1_14_R1/IWorldHandler.java index c52a0342a..02ff06a4b 100644 --- a/modules/v1_14_R1/src/main/java/net/countercraft/movecraft/compat/v1_14_R1/IWorldHandler.java +++ b/modules/v1_14_R1/src/main/java/net/countercraft/movecraft/compat/v1_14_R1/IWorldHandler.java @@ -196,7 +196,7 @@ public void translateCraft(@NotNull Craft craft, @NotNull MovecraftLocation disp //* Step five: Destroy the leftovers * //******************************************* Collection deletePositions = oldNativeWorld == nativeWorld ? CollectionUtils.filter(positions, newPositions) : positions; - setAir(deletePositions, nativeWorld); + setAir(deletePositions, oldNativeWorld); //******************************************* //* Step six: Process fire spread * //******************************************* diff --git a/modules/v1_15_R1/src/main/java/net/countercraft/movecraft/compat/v1_15_R1/IWorldHandler.java b/modules/v1_15_R1/src/main/java/net/countercraft/movecraft/compat/v1_15_R1/IWorldHandler.java index 3d4477f7b..a85d97e31 100644 --- a/modules/v1_15_R1/src/main/java/net/countercraft/movecraft/compat/v1_15_R1/IWorldHandler.java +++ b/modules/v1_15_R1/src/main/java/net/countercraft/movecraft/compat/v1_15_R1/IWorldHandler.java @@ -196,7 +196,7 @@ public void translateCraft(@NotNull Craft craft, @NotNull MovecraftLocation disp //* Step five: Destroy the leftovers * //******************************************* Collection deletePositions = oldNativeWorld == nativeWorld ? CollectionUtils.filter(positions,newPositions) : positions; - setAir(deletePositions, nativeWorld); + setAir(deletePositions, oldNativeWorld); //******************************************* //* Step six: Process fire spread * //******************************************* diff --git a/modules/v1_8_R3/src/main/java/net/countercraft/movecraft/compat/v1_8_R3/IWorldHandler.java b/modules/v1_8_R3/src/main/java/net/countercraft/movecraft/compat/v1_8_R3/IWorldHandler.java index d802d47bb..f4d6e019b 100644 --- a/modules/v1_8_R3/src/main/java/net/countercraft/movecraft/compat/v1_8_R3/IWorldHandler.java +++ b/modules/v1_8_R3/src/main/java/net/countercraft/movecraft/compat/v1_8_R3/IWorldHandler.java @@ -195,7 +195,7 @@ public void translateCraft(@NotNull Craft craft, @NotNull MovecraftLocation disp //* Step five: Destroy the leftovers * //******************************************* Collection deletePositions = oldNativeWorld == nativeWorld ? CollectionUtils.filter(positions,newPositions) : positions; - setAir(deletePositions, nativeWorld); + setAir(deletePositions, oldNativeWorld); //******************************************* //* Step six: Process fire spread * //******************************************* diff --git a/modules/v1_9_R2/src/main/java/net/countercraft/movecraft/compat/v1_9_R2/IWorldHandler.java b/modules/v1_9_R2/src/main/java/net/countercraft/movecraft/compat/v1_9_R2/IWorldHandler.java index 929aedb01..492ba2a2a 100644 --- a/modules/v1_9_R2/src/main/java/net/countercraft/movecraft/compat/v1_9_R2/IWorldHandler.java +++ b/modules/v1_9_R2/src/main/java/net/countercraft/movecraft/compat/v1_9_R2/IWorldHandler.java @@ -187,7 +187,7 @@ public void translateCraft(@NotNull Craft craft, @NotNull MovecraftLocation disp //* Step five: Destroy the leftovers * //******************************************* Collection deletePositions = oldNativeWorld == nativeWorld ? CollectionUtils.filter(positions,newPositions) : positions; - setAir(deletePositions, nativeWorld); + setAir(deletePositions, oldNativeWorld); //******************************************* //* Step six: Process fire spread * //******************************************* diff --git a/pom.xml b/pom.xml index e62dc4bb7..edc6f10ee 100644 --- a/pom.xml +++ b/pom.xml @@ -28,10 +28,11 @@ modules/v1_13_R2 modules/v1_14_R1 modules/v1_15_R1 + modules/v1_16_R1 modules/worldedit/WE6Utils modules/worldedit/WE7Utils modules/Movecraft - modules/v1_16_R1 + From 9ef97ea5fd3bce069e5310e2e7d2b6faabc5fdfa Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Wed, 17 Jun 2020 20:19:14 +0200 Subject: [PATCH 175/304] Some fixes --- .../async/translation/TranslationTask.java | 33 +++++++++++++------ .../movecraft/events/CraftCollisionEvent.java | 2 +- .../movecraft/utils/LegacyUtils.java | 1 + 3 files changed, 25 insertions(+), 11 deletions(-) diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java index 2efad0ce8..d45a8b1ad 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java @@ -24,6 +24,7 @@ import org.bukkit.block.Chest; import org.bukkit.block.Furnace; import org.bukkit.block.data.BlockData; +import org.bukkit.block.data.Orientable; import org.bukkit.entity.Player; import org.bukkit.inventory.Inventory; import org.bukkit.inventory.InventoryHolder; @@ -183,8 +184,8 @@ protected void execute() throws InterruptedException, ExecutionException { final int maxY = oldHitBox.getMaxY(); // proccess nether portals - if (Settings.CraftsUseNetherPortals && craft.getW().getEnvironment() != Environment.THE_END - && world.equals(craft.getW())) { + if (Settings.CraftsUseNetherPortals && craft.getWorld().getEnvironment() != Environment.THE_END + && world.equals(craft.getWorld())) { // ensure chunks are loaded for portal checking only if change in location is // large @@ -197,9 +198,9 @@ protected void execute() throws InterruptedException, ExecutionException { for (MovecraftLocation oldLocation : oldHitBox) { - Location location = oldLocation.translate(dx, dy, dz).toBukkit(craft.getW()); - Block block = craft.getW().getBlockAt(location); - if (block.getType() == Material.NETHER_PORTAL) { + Location location = oldLocation.translate(dx, dy, dz).toBukkit(craft.getWorld()); + Block block = craft.getWorld().getBlockAt(location); + if (block.getType() == (Settings.IsLegacy ? LegacyUtils.PORTAL : Material.NETHER_PORTAL)) { if (processNetherPortal(block)) { sound = Sound.BLOCK_PORTAL_TRAVEL; @@ -250,12 +251,12 @@ protected void execute() throws InterruptedException, ExecutionException { fail(I18nSupport.getInternationalisedString("Translation - Failed Craft hit minimum height limit")); return; } - if (craft.getType().getFuelBurnRate() > 0.0) { + if (craft.getType().getFuelBurnRate(world) > 0.0) { new BukkitRunnable() { @Override public void run() { // check for fuel, burn some from a furnace if needed. Blocks of coal are supported, in addition to coal and charcoal - double fuelBurnRate = craft.getType().getFuelBurnRate(); + double fuelBurnRate = craft.getType().getFuelBurnRate(world); // going down doesn't require fuel if (dy == -1 && dx == 0 && dz == 0) fuelBurnRate = 0.0; @@ -307,7 +308,7 @@ public void run() { } //Process gravity - if (world.equals(craft.getW()) && craft.getType().getUseGravity() && !craft.getSinking()){ + if (world.equals(craft.getWorld()) && craft.getType().getUseGravity() && !craft.getSinking()){ int incline = inclineCraft(oldHitBox); if (incline > 0){ boolean tooSteep = craft.getType().getGravityInclineDistance() > -1 && incline > craft.getType().getGravityInclineDistance(); @@ -651,8 +652,20 @@ private boolean processNetherPortal(@NotNull Block block) { int portalZ = 0; Location portalNegCorner = new Location(block.getWorld(), 0, 0, 0); Location portalPosCorner = new Location(block.getWorld(), 0, 0, 0); - if (block.getData() == 2) portalZ = 1; - else portalX = 1; + if (Settings.IsLegacy) { + if (block.getData() == 2) + portalZ = 1; + else + portalX = 1; + } else { + final Orientable orient = (Orientable) block.getBlockData(); + if (orient.getAxis() == Axis.X) { + portalX = 1; + } else { + portalZ = 1; + } + } + Material testMaterial = null; int testX = block.getX(); diff --git a/modules/api/src/main/java/net/countercraft/movecraft/events/CraftCollisionEvent.java b/modules/api/src/main/java/net/countercraft/movecraft/events/CraftCollisionEvent.java index 361c046be..d045f0f8f 100644 --- a/modules/api/src/main/java/net/countercraft/movecraft/events/CraftCollisionEvent.java +++ b/modules/api/src/main/java/net/countercraft/movecraft/events/CraftCollisionEvent.java @@ -14,7 +14,7 @@ public class CraftCollisionEvent extends CraftEvent{ private boolean isCancelled = false; public CraftCollisionEvent(@NotNull Craft craft, @NotNull BitmapHitBox hitBox, @NotNull World world) { - super(craft); + super(craft, true); this.hitBox = hitBox; this.world = world; } diff --git a/modules/api/src/main/java/net/countercraft/movecraft/utils/LegacyUtils.java b/modules/api/src/main/java/net/countercraft/movecraft/utils/LegacyUtils.java index 932d4dbe6..73cc4f5b3 100644 --- a/modules/api/src/main/java/net/countercraft/movecraft/utils/LegacyUtils.java +++ b/modules/api/src/main/java/net/countercraft/movecraft/utils/LegacyUtils.java @@ -41,6 +41,7 @@ public class LegacyUtils { public static final Material PISTON_BASE = Settings.IsLegacy ? Material.PISTON_BASE : null; public static final Material PISTON_EXTENSION = Settings.IsLegacy ? Material.PISTON_EXTENSION : null; public static final Material PISTON_STICKY_BASE = Settings.IsLegacy ? Material.PISTON_STICKY_BASE : null; + public static final Material PORTAL = Settings.IsLegacy ? Material.PORTAL : null; public static final Material RED_ROSE = Settings.IsLegacy ? Material.RED_ROSE : null; public static final Material REDSTONE_COMPARATOR = Settings.IsLegacy ? Material.REDSTONE_COMPARATOR : null; public static final Material REDSTONE_COMPARATOR_OFF = Settings.IsLegacy ? Material.REDSTONE_COMPARATOR_OFF : null; From 9f1c8a904a5733baead59d701a53404cc378d9a5 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Wed, 17 Jun 2020 20:22:38 +0200 Subject: [PATCH 176/304] updated .gitignore --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.gitignore b/.gitignore index c5f9c7445..a72dbb256 100644 --- a/.gitignore +++ b/.gitignore @@ -189,3 +189,6 @@ $RECYCLE.BIN/ # Windows shortcuts *.lnk + +modules/Movecraft/dependency-reduced-pom.xml +modules/api/dependency-reduced-pom.xml \ No newline at end of file From 82aab7f90f0176a9b19cf5928e32ae771affe9cc Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Sun, 21 Jun 2020 13:04:31 +0200 Subject: [PATCH 177/304] Fixed crafts affected by gravity not dropping on motion --- .../async/translation/TranslationTask.java | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java index 3fc386b42..f3246f12b 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java @@ -1,5 +1,6 @@ package net.countercraft.movecraft.async.translation; +import net.countercraft.movecraft.Movecraft; import net.countercraft.movecraft.MovecraftChunk; import net.countercraft.movecraft.MovecraftLocation; import net.countercraft.movecraft.async.AsyncTask; @@ -30,6 +31,7 @@ import java.util.*; import java.util.concurrent.ExecutionException; import java.util.concurrent.ThreadLocalRandom; +import java.util.logging.Logger; import static net.countercraft.movecraft.utils.MathUtils.withinWorldBorder; @@ -174,6 +176,9 @@ protected void execute() throws InterruptedException, ExecutionException { } else if (!isOnGround(oldHitBox)){ dy = dropDistance(oldHitBox); } + if (Settings.Debug) { + Movecraft.getInstance().getLogger().info("dy: " + dy); + } } //Fail the movement if the craft is too high and if the craft is not explosive if (dy>0 && maxY + dy > craft.getType().getMaxHeightLimit(world) && craft.getType().getCollisionExplosion() <= 0f) { @@ -568,7 +573,6 @@ private boolean processNetherPortal(@NotNull Block block) { dz -= oldHitBox.getZLength() + 1; } } - return true; } @@ -724,11 +728,12 @@ private int dropDistance (BitmapHitBox hitBox) { final MovecraftLocation translated = ml.translate(dx, dy, dz); //This has to be subtracted by one, or non-passthrough blocks will be within the y drop path //obstructing the craft - Material testType = translated.translate(0, dropDistance , 0).toBukkit(craft.getW()).getBlock().getType(); + MovecraftLocation dropped = translated.translate(0, dropDistance - 1 , 0); + Material testType = dropped.toBukkit(craft.getW()).getBlock().getType(); hitGround = testType != Material.AIR && !craft.getType().getPassthroughBlocks().contains(testType) && !(craft.getType().getHarvestBlocks().contains(testType) && - craft.getType().getHarvesterBladeBlocks().contains(ml.translate(0, 1, 0).toBukkit(craft.getW()).getBlock().getType())) || + craft.getType().getHarvesterBladeBlocks().contains(ml.toBukkit(craft.getW()).getBlock().getType())) || craft.getType().getMinHeightLimit(craft.getW()) == translated.translate(0, dropDistance + 1 , 0).getY(); if (hitGround) { @@ -791,6 +796,11 @@ private boolean isOnGround(BitmapHitBox hitBox){ translatedBottomLocsInAir = false; break; } + if (Settings.Debug) { + final Logger log = Movecraft.getInstance().getLogger(); + log.info("Translated bottom locs in air: " + translatedBottomLocsInAir); + log.info("Bottom locs on ground: " + bottomLocsOnGround); + } if (dy > 0){ return bottomLocsOnGround && translatedBottomLocsInAir; } From b623f29e2df636984342eb9cf9024de4d6ab69fa Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Sat, 27 Jun 2020 00:42:24 +0200 Subject: [PATCH 178/304] Fixed Movecraft breaking with canHoverOverWater set to false, Made lighting update as a craft moves, fix #52 --- modules/Movecraft/dependency-reduced-pom.xml | 8 +- modules/Movecraft/pom.xml | 14 +- .../movecraft/craft/CraftType.java | 7 +- .../compat/v1_10_R1/IWorldHandler.java | 1 + .../compat/v1_11_R1/IWorldHandler.java | 1 + .../compat/v1_12_R1/IWorldHandler.java | 1 + .../compat/v1_13_R2/IWorldHandler.java | 1 + .../compat/v1_14_R1/IWorldHandler.java | 1 + .../compat/v1_15_R1/IWorldHandler.java | 1 + modules/v1_16_R1/pom.xml | 5 + .../compat/v1_16_R1/IWorldHandler.java | 441 ++++++++++++++++++ .../compat/v1_16_R1/NextTickProvider.java | 68 +++ .../compat/v1_8_R3/IWorldHandler.java | 1 + .../compat/v1_9_R2/IWorldHandler.java | 1 + 14 files changed, 548 insertions(+), 3 deletions(-) create mode 100644 modules/v1_16_R1/src/main/java/net/countercraft/movecraft/compat/v1_16_R1/IWorldHandler.java create mode 100644 modules/v1_16_R1/src/main/java/net/countercraft/movecraft/compat/v1_16_R1/NextTickProvider.java diff --git a/modules/Movecraft/dependency-reduced-pom.xml b/modules/Movecraft/dependency-reduced-pom.xml index dacdd996a..26fce8532 100644 --- a/modules/Movecraft/dependency-reduced-pom.xml +++ b/modules/Movecraft/dependency-reduced-pom.xml @@ -4,7 +4,7 @@ net.countercraft movecraft Movecraft - 7.0.0_for_1.8.8-1.15.2_beta_25 + 7.0.0_for_1.8.8-1.16.1_beta_25 http://github.com/apdevteam/Movecraft src/main/java @@ -134,6 +134,12 @@ ** + + net.countercraft:movecraft-v1_16_R1 + + ** + + diff --git a/modules/Movecraft/pom.xml b/modules/Movecraft/pom.xml index 0649729e7..9b211ceb9 100644 --- a/modules/Movecraft/pom.xml +++ b/modules/Movecraft/pom.xml @@ -10,7 +10,7 @@ UTF-8 - 7.0.0_for_1.8.8-1.15.2_beta_25 + 7.0.0_for_1.8.8-1.16.1_beta_25 spigot-repo @@ -35,6 +35,12 @@ + + net.countercraft + movecraft-v1_16_R1 + v1_16_R1 + jar + net.countercraft movecraft-v1_15_R1 @@ -336,6 +342,12 @@ ** + + net.countercraft:movecraft-v1_16_R1 + + ** + + diff --git a/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java b/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java index 69e397b5e..491662a87 100644 --- a/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java +++ b/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java @@ -315,7 +315,12 @@ public CraftType(File f) { } if (!canHoverOverWater){ forbiddenHoverOverBlocks.add(Material.WATER); - forbiddenHoverOverBlocks.add(Material.STATIONARY_WATER); + if (Settings.IsLegacy) { + forbiddenHoverOverBlocks.add(Material.STATIONARY_WATER); + } else { + forbiddenHoverOverBlocks.add(Material.getMaterial("BUBBLE_COLUMN")); + } + } allowVerticalTakeoffAndLanding = (boolean) data.getOrDefault("allowVerticalTakeoffAndLanding", true); dynamicLagSpeedFactor = doubleFromObject(data.getOrDefault("dynamicLagSpeedFactor", 0d)); diff --git a/modules/v1_10_R1/src/main/java/net/countercraft/movecraft/compat/v1_10_R1/IWorldHandler.java b/modules/v1_10_R1/src/main/java/net/countercraft/movecraft/compat/v1_10_R1/IWorldHandler.java index 361771bdc..27026c00c 100644 --- a/modules/v1_10_R1/src/main/java/net/countercraft/movecraft/compat/v1_10_R1/IWorldHandler.java +++ b/modules/v1_10_R1/src/main/java/net/countercraft/movecraft/compat/v1_10_R1/IWorldHandler.java @@ -289,6 +289,7 @@ private void setBlockFast(@NotNull World world, @NotNull BlockPosition position, } chunkSection.setType(position.getX()&15, position.getY()&15, position.getZ()&15, data); world.notify(position, data, data, 3); + world.c(EnumSkyBlock.BLOCK, position); chunk.e(); // mark dirty } diff --git a/modules/v1_11_R1/src/main/java/net/countercraft/movecraft/compat/v1_11_R1/IWorldHandler.java b/modules/v1_11_R1/src/main/java/net/countercraft/movecraft/compat/v1_11_R1/IWorldHandler.java index 86223594d..8efdbedb7 100644 --- a/modules/v1_11_R1/src/main/java/net/countercraft/movecraft/compat/v1_11_R1/IWorldHandler.java +++ b/modules/v1_11_R1/src/main/java/net/countercraft/movecraft/compat/v1_11_R1/IWorldHandler.java @@ -267,6 +267,7 @@ private void setBlockFast(@NotNull World world, @NotNull BlockPosition position, chunkSection.setType(position.getX()&15, position.getY()&15, position.getZ()&15, data); world.notify(position, data, data, 3); + world.c(EnumSkyBlock.BLOCK, position); chunk.e(); // mark dirty } diff --git a/modules/v1_12_R1/src/main/java/net/countercraft/movecraft/compat/v1_12_R1/IWorldHandler.java b/modules/v1_12_R1/src/main/java/net/countercraft/movecraft/compat/v1_12_R1/IWorldHandler.java index b852cfb9d..279a35601 100644 --- a/modules/v1_12_R1/src/main/java/net/countercraft/movecraft/compat/v1_12_R1/IWorldHandler.java +++ b/modules/v1_12_R1/src/main/java/net/countercraft/movecraft/compat/v1_12_R1/IWorldHandler.java @@ -272,6 +272,7 @@ private void setBlockFast(@NotNull World world, @NotNull BlockPosition position, chunkSection.setType(position.getX()&15, position.getY()&15, position.getZ()&15, data); world.notify(position, data, data, 3); + world.c(EnumSkyBlock.BLOCK, position); chunk.markDirty(); } diff --git a/modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/IWorldHandler.java b/modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/IWorldHandler.java index 332e2fc58..790e852cd 100644 --- a/modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/IWorldHandler.java +++ b/modules/v1_13_R2/src/main/java/net/countercraft/movecraft/compat/v1_13_R2/IWorldHandler.java @@ -328,6 +328,7 @@ private void setBlockFast(@NotNull World world, @NotNull BlockPosition position, } chunkSection.setType(position.getX()&15, position.getY()&15, position.getZ()&15, data); world.notify(position, data, data, 3); + world.c(EnumSkyBlock.BLOCK, position); chunk.markDirty(); } diff --git a/modules/v1_14_R1/src/main/java/net/countercraft/movecraft/compat/v1_14_R1/IWorldHandler.java b/modules/v1_14_R1/src/main/java/net/countercraft/movecraft/compat/v1_14_R1/IWorldHandler.java index 02ff06a4b..699f1a250 100644 --- a/modules/v1_14_R1/src/main/java/net/countercraft/movecraft/compat/v1_14_R1/IWorldHandler.java +++ b/modules/v1_14_R1/src/main/java/net/countercraft/movecraft/compat/v1_14_R1/IWorldHandler.java @@ -326,6 +326,7 @@ private void setBlockFast(@NotNull World world, @NotNull BlockPosition position, } chunkSection.setType(position.getX()&15, position.getY()&15, position.getZ()&15, data); world.notify(position, data, data, 3); + world.getChunkProvider().getLightEngine().a(position); chunk.markDirty(); } diff --git a/modules/v1_15_R1/src/main/java/net/countercraft/movecraft/compat/v1_15_R1/IWorldHandler.java b/modules/v1_15_R1/src/main/java/net/countercraft/movecraft/compat/v1_15_R1/IWorldHandler.java index a85d97e31..4c9a7319c 100644 --- a/modules/v1_15_R1/src/main/java/net/countercraft/movecraft/compat/v1_15_R1/IWorldHandler.java +++ b/modules/v1_15_R1/src/main/java/net/countercraft/movecraft/compat/v1_15_R1/IWorldHandler.java @@ -326,6 +326,7 @@ private void setBlockFast(@NotNull World world, @NotNull BlockPosition position, } chunkSection.setType(position.getX() & 15, position.getY() & 15, position.getZ() & 15, data); world.notify(position, data, data, 3); + world.getChunkProvider().getLightEngine().a(position); chunk.markDirty(); } diff --git a/modules/v1_16_R1/pom.xml b/modules/v1_16_R1/pom.xml index c8350c2e0..64f125fe8 100644 --- a/modules/v1_16_R1/pom.xml +++ b/modules/v1_16_R1/pom.xml @@ -15,6 +15,11 @@ v1_16_R1 jar + + org.bukkit + craftbukkit + 1.16.1-R0.1-SNAPSHOT + net.countercraft movecraft-api diff --git a/modules/v1_16_R1/src/main/java/net/countercraft/movecraft/compat/v1_16_R1/IWorldHandler.java b/modules/v1_16_R1/src/main/java/net/countercraft/movecraft/compat/v1_16_R1/IWorldHandler.java new file mode 100644 index 000000000..f3b4a9969 --- /dev/null +++ b/modules/v1_16_R1/src/main/java/net/countercraft/movecraft/compat/v1_16_R1/IWorldHandler.java @@ -0,0 +1,441 @@ +package net.countercraft.movecraft.compat.v1_16_R1; + +import net.countercraft.movecraft.MovecraftLocation; +import net.countercraft.movecraft.Rotation; +import net.countercraft.movecraft.WorldHandler; +import net.countercraft.movecraft.config.Settings; +import net.countercraft.movecraft.craft.Craft; +import net.countercraft.movecraft.utils.CollectionUtils; +import net.countercraft.movecraft.utils.MathUtils; +import net.minecraft.server.v1_16_R1.*; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.block.data.BlockData; +import org.bukkit.craftbukkit.v1_16_R1.CraftWorld; +import org.bukkit.craftbukkit.v1_16_R1.block.data.CraftBlockData; +import org.bukkit.craftbukkit.v1_16_R1.util.CraftMagicNumbers; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.*; + +public class IWorldHandler extends WorldHandler { + private static final EnumBlockRotation ROTATION[]; + static { + ROTATION = new EnumBlockRotation[3]; + ROTATION[Rotation.NONE.ordinal()] = EnumBlockRotation.NONE; + ROTATION[Rotation.CLOCKWISE.ordinal()] = EnumBlockRotation.CLOCKWISE_90; + ROTATION[Rotation.ANTICLOCKWISE.ordinal()] = EnumBlockRotation.COUNTERCLOCKWISE_90; + + } + private final NextTickProvider tickProvider = new NextTickProvider(); + private final HashMap> bMap = new HashMap<>(); + private MethodHandle internalTeleportMH; + + public IWorldHandler() { + MethodHandles.Lookup lookup = MethodHandles.lookup(); + Method teleport = null; + try { + teleport = PlayerConnection.class.getDeclaredMethod("internalTeleport", double.class, double.class, double.class, float.class, float.class, Set.class); + teleport.setAccessible(true); + internalTeleportMH = lookup.unreflect(teleport); + + } catch (NoSuchMethodException | IllegalAccessException e) { + e.printStackTrace(); + } + } + + @Override + public void rotateCraft(@NotNull Craft craft, @NotNull MovecraftLocation originPoint, @NotNull Rotation rotation) { + //******************************************* + //* Step one: Convert to Positions * + //******************************************* + HashMap rotatedPositions = new HashMap<>(); + Rotation counterRotation = rotation == Rotation.CLOCKWISE ? Rotation.ANTICLOCKWISE : Rotation.CLOCKWISE; + for(MovecraftLocation newLocation : craft.getHitBox()){ + rotatedPositions.put(locationToPosition(MathUtils.rotateVec(counterRotation, newLocation.subtract(originPoint)).add(originPoint)),locationToPosition(newLocation)); + } + //******************************************* + //* Step two: Get the tiles * + //******************************************* + WorldServer nativeWorld = ((CraftWorld) craft.getWorld()).getHandle(); + List tiles = new ArrayList<>(); + //get the tiles + for(BlockPosition position : rotatedPositions.keySet()){ + //TileEntity tile = nativeWorld.removeTileEntity(position); + TileEntity tile = removeTileEntity(nativeWorld,position); + if(tile == null) + continue; + tile.a(ROTATION[rotation.ordinal()]); + //get the nextTick to move with the tile + tiles.add(new TileHolder(tile, tickProvider.getNextTick(nativeWorld,position), position)); + } + + //******************************************* + //* Step three: Translate all the blocks * + //******************************************* + // blockedByWater=false means an ocean-going vessel + //TODO: Simplify + //TODO: go by chunks + //TODO: Don't move unnecessary blocks + //get the blocks and rotate them + HashMap blockData = new HashMap<>(); + for(BlockPosition position : rotatedPositions.keySet()){ + + blockData.put(position,nativeWorld.getType(position).a(ROTATION[rotation.ordinal()])); + } + HashMap redstoneComponents = new HashMap<>(); + //create the new block + for(Map.Entry entry : blockData.entrySet()) { + final BlockPosition newPosition = rotatedPositions.get(entry.getKey()); + final IBlockData iBlockData = entry.getValue(); + if (nativeWorld.getTileEntity(newPosition) != null) { + removeTileEntity(nativeWorld, newPosition); + } + if (isRedstoneComponent(iBlockData)) + redstoneComponents.put(newPosition, iBlockData); + + setBlockFast(nativeWorld, newPosition, iBlockData); + } + + + //******************************************* + //* Step four: replace all the tiles * + //******************************************* + //TODO: go by chunks + for(TileHolder tileHolder : tiles){ + moveTileEntity(nativeWorld, rotatedPositions.get(tileHolder.getTilePosition()),tileHolder.getTile()); + if(tileHolder.getNextTick()==null) + continue; + final long currentTime = nativeWorld.worldData.getTime(); + nativeWorld.getBlockTickList().a(rotatedPositions.get(tileHolder.getNextTick().a), tileHolder.getNextTick().b(), (int) (tileHolder.getNextTick().b - currentTime), tileHolder.getNextTick().c); + } + + //******************************************* + //* Step five: Destroy the leftovers * + //******************************************* + //TODO: add support for pass-through + Collection deletePositions = CollectionUtils.filter(rotatedPositions.keySet(),rotatedPositions.values()); + for(BlockPosition position : deletePositions){ + setBlockFast(nativeWorld, position, Blocks.AIR.getBlockData()); + } + + //******************************************* + //* Step six: Process fire spread * + //******************************************* + for (BlockPosition position : rotatedPositions.values()) { + IBlockData type = nativeWorld.getType(position); + if (!(type.getBlock() instanceof BlockFire)) { + continue; + } + BlockFire fire = (BlockFire) type.getBlock(); + fire.tick(type, nativeWorld, position, nativeWorld.random); + } + + for (Map.Entry entry : redstoneComponents.entrySet()) { + final BlockPosition position = entry.getKey(); + final IBlockData data = entry.getValue(); + Chunk chunk = nativeWorld.getChunkAtWorldCoords(position); + ChunkSection chunkSection = chunk.getSections()[position.getY()>>4]; + if (chunkSection == null) { + // Put a GLASS block to initialize the section. It will be replaced next with the real block. + chunk.setType(position, Blocks.GLASS.getBlockData(), true); + chunkSection = chunk.getSections()[position.getY() >> 4]; + + } + chunkSection.setType(position.getX()&15, position.getY()&15, position.getZ()&15, data); + nativeWorld.notifyAndUpdatePhysics(position, chunk, data, data, data, 3); + } + } + + @Override + public void translateCraft(@NotNull Craft craft, @NotNull MovecraftLocation displacement, @NotNull org.bukkit.World world) { + //TODO: Add supourt for rotations + //A craftTranslateCommand should only occur if the craft is moving to a valid position + //******************************************* + //* Step one: Convert to Positions * + //******************************************* + BlockPosition translateVector = locationToPosition(displacement); + List positions = new ArrayList<>(); + for(MovecraftLocation movecraftLocation : craft.getHitBox()) { + positions.add(locationToPosition((movecraftLocation)).b(translateVector)); + + } + WorldServer oldNativeWorld = ((CraftWorld) craft.getWorld()).getHandle(); + WorldServer nativeWorld = ((CraftWorld) world).getHandle(); + //******************************************* + //* Step two: Get the tiles * + //******************************************* + List tiles = getTiles(positions, oldNativeWorld); + //******************************************* + //* Step three: Translate all the blocks * + //******************************************* + // blockedByWater=false means an ocean-going vessel + //TODO: Simplify + //TODO: go by chunks + //TODO: Don't move unnecessary blocks + //get the blocks and translate the positions + List blockData = new ArrayList<>(); + List newPositions = new ArrayList<>(); + for(BlockPosition position : positions){ + blockData.add(oldNativeWorld.getType(position)); + newPositions.add(position.a(translateVector)); + } + //create the new block + setBlocks(newPositions, blockData, nativeWorld); + //******************************************* + //* Step four: replace all the tiles * + //******************************************* + //TODO: go by chunks + processTiles(tiles, nativeWorld, translateVector); + //******************************************* + //* Step five: Destroy the leftovers * + //******************************************* + Collection deletePositions = oldNativeWorld == nativeWorld ? CollectionUtils.filter(positions,newPositions) : positions; + setAir(deletePositions, oldNativeWorld); + //******************************************* + //* Step six: Process fire spread * + //******************************************* + processFireSpread(newPositions, nativeWorld); + //******************************************* + //* Step six: Process redstone * + //******************************************* + processRedstone(newPositions, nativeWorld); + } + + + private void setBlocks(List newPositions, List blockData, WorldServer nativeWorld){ + Map redstoneComponents = new HashMap<>(); + for(int i = 0; i getTiles(Iterable positions, WorldServer nativeWorld){ + List tiles = new ArrayList<>(); + //get the tiles + for(BlockPosition position : positions){ + if(nativeWorld.getType(position) == Blocks.AIR.getBlockData()) + continue; + //TileEntity tile = nativeWorld.removeTileEntity(position); + TileEntity tile = removeTileEntity(nativeWorld,position); + if(tile == null) + continue; + //get the nextTick to move with the tile + + //nativeWorld.capturedTileEntities.remove(position); + //nativeWorld.getChunkAtWorldCoords(position).getTileEntities().remove(position); + tiles.add(new TileHolder(tile, tickProvider.getNextTick(nativeWorld, position), position)); + + } + return tiles; + } + + private void processTiles(Iterable tiles, WorldServer world, BlockPosition translateVector){ + for(TileHolder tileHolder : tiles){ + moveTileEntity(world, tileHolder.getTilePosition().a(translateVector),tileHolder.getTile()); + if(tileHolder.getNextTick()==null) + continue; + final long currentTime = world.worldData.getTime(); + world.getBlockTickList().a(tileHolder.getNextTick().a.a(translateVector), tileHolder.getNextTick().b(), (int) (tileHolder.getNextTick().b - currentTime), tileHolder.getNextTick().c); + } + } + + private void processFireSpread(Iterable positions, WorldServer world){ + for (BlockPosition position : positions) { + IBlockData type = world.getType(position); + if (!(type.getBlock() instanceof BlockFire)) { + continue; + } + BlockFire fire = (BlockFire) type.getBlock(); + fire.tick(type, world, position, world.random); + } + } + + private void processRedstone(List redstone, WorldServer world) { + Map redstoneComponents = new HashMap<>(); + for (int i = 0 ; i < redstone.size(); i++) { + BlockPosition pos = redstone.get(i); + IBlockData data = world.getType(pos); + if (isRedstoneComponent(data)) + redstoneComponents.put(pos, data); + } + for (Map.Entry entry : redstoneComponents.entrySet()) { + final BlockPosition position = entry.getKey(); + final IBlockData data = entry.getValue(); + Chunk chunk = world.getChunkAtWorldCoords(position); + ChunkSection chunkSection = chunk.getSections()[position.getY()>>4]; + if (chunkSection == null) { + // Put a GLASS block to initialize the section. It will be replaced next with the real block. + chunk.setType(position, Blocks.GLASS.getBlockData(), true); + chunkSection = chunk.getSections()[position.getY() >> 4]; + + } + chunkSection.setType(position.getX()&15, position.getY()&15, position.getZ()&15, data); + world.notifyAndUpdatePhysics(position, chunk, data, data, data, 3); + } + } + + private void setAir(Iterable positions, WorldServer world){ + for(BlockPosition position : positions){ + setBlockFast(world, position, Blocks.AIR.getBlockData()); + } + } + + @Nullable + private TileEntity removeTileEntity(@NotNull WorldServer world, @NotNull BlockPosition position){ + TileEntity tile = world.getTileEntity(position); + if(tile == null) + return null; + //cleanup + world.capturedTileEntities.remove(position); + world.getChunkAtWorldCoords(position).getTileEntities().remove(position); + if(!Settings.IsPaper) + world.tileEntityList.remove(tile); + world.tileEntityListTick.remove(tile); + if(!bMap.containsKey(world)){ + try { + Field bField = World.class.getDeclaredField("tileEntityListPending"); + bField.setAccessible(true); + bMap.put(world, (List) bField.get(world));//TODO bug fix + } catch (IllegalAccessException | IllegalArgumentException | NoSuchFieldException | SecurityException e1) { + e1.printStackTrace(); + } + } + bMap.get(world).remove(tile); + return tile; + } + + @NotNull + private BlockPosition locationToPosition(@NotNull MovecraftLocation loc) { + return new BlockPosition(loc.getX(), loc.getY(), loc.getZ()); + } + + private void setBlockFast(@NotNull WorldServer world, @NotNull BlockPosition position,@NotNull IBlockData data) { + Chunk chunk = world.getChunkAtWorldCoords(position); + ChunkSection chunkSection = chunk.getSections()[position.getY()>>4]; + if (chunkSection == null) { + // Put a GLASS block to initialize the section. It will be replaced next with the real block. + chunk.setType(position, Blocks.GLASS.getBlockData(), true); + chunkSection = chunk.getSections()[position.getY() >> 4]; + + } + chunkSection.setType(position.getX() & 15, position.getY() & 15, position.getZ() & 15, data); + world.notify(position, data, data, 3); + world.getChunkProvider().getLightEngine().a(position); + chunk.markDirty(); + } + + @Override + public void setBlockFast(@NotNull Location location, @NotNull Material material, Object data){ + setBlockFast(location, Rotation.NONE, material, data); + } + + @Override + public void setBlockFast(@NotNull Location location, @NotNull Rotation rotation, @NotNull Material material, Object data) { + IBlockData blockData; + if (!(data instanceof BlockData)) { + blockData = CraftMagicNumbers.getBlock(material).getBlockData(); + } else { + blockData = ((CraftBlockData) data).getState(); + } + + blockData = blockData.a(ROTATION[rotation.ordinal()]); + WorldServer world = ((CraftWorld)(location.getWorld())).getHandle(); + BlockPosition blockPosition = locationToPosition(bukkit2MovecraftLoc(location)); + if (world.getTileEntity(blockPosition) != null) { + removeTileEntity(world, blockPosition); + } + setBlockFast(world,blockPosition,blockData); + } + + @Override + public void disableShadow(@NotNull Material type) { + Method method; + //try { + Block tempBlock = CraftMagicNumbers.getBlock(type); + //method = Block.class.getDeclaredMethod("d", int.class); + //method.setAccessible(true); + //method.invoke(tempBlock, 0); + //} catch (NoSuchMethodException | InvocationTargetException | IllegalArgumentException | IllegalAccessException | SecurityException e1) { + // TODO Auto-generated catch block + // e1.printStackTrace(); + //} + } + + private static MovecraftLocation bukkit2MovecraftLoc(Location l) { + return new MovecraftLocation(l.getBlockX(), l.getBlockY(), l.getBlockZ()); + } + + private void recalculateLighting(WorldServer world, Collection positions) { + final LightEngineThreaded engine = world.getChunkProvider().getLightEngine(); + for (BlockPosition pos : positions) { + engine.a(pos); + } + } + + private void moveTileEntity(@NotNull WorldServer nativeWorld, @NotNull BlockPosition newPosition, @NotNull TileEntity tile){ + Chunk chunk = nativeWorld.getChunkAtWorldCoords(newPosition); + tile.invalidateBlockCache(); + if(nativeWorld.captureBlockStates) { + tile.setLocation(nativeWorld, newPosition); + nativeWorld.capturedTileEntities.put(newPosition, tile); + return; + } + tile.setPosition(newPosition); + chunk.tileEntities.put(newPosition, tile); + } + + private class TileHolder{ + @NotNull private final TileEntity tile; + @Nullable + private final NextTickListEntry nextTick; + @NotNull private final BlockPosition tilePosition; + + public TileHolder(@NotNull TileEntity tile, @Nullable NextTickListEntry nextTick, @NotNull BlockPosition tilePosition){ + this.tile = tile; + this.nextTick = nextTick; + this.tilePosition = tilePosition; + } + + + @NotNull + public TileEntity getTile() { + return tile; + } + + @Nullable + public NextTickListEntry getNextTick() { + return nextTick; + } + + @NotNull + public BlockPosition getTilePosition() { + return tilePosition; + } + } + + private boolean isRedstoneComponent(IBlockData blockData) { + final Block block = blockData.getBlock(); + return block instanceof BlockRedstoneWire || + block instanceof BlockDiodeAbstract || + block instanceof BlockButtonAbstract || + block instanceof BlockLever; + + } + + private boolean isPowered (IBlockData data) { + if (data.getBlock() instanceof BlockRedstoneWire) { + return data.get(BlockRedstoneWire.POWER) > 0; + } else if (data.getBlock() instanceof BlockDiodeAbstract) { + return data.get(BlockDiodeAbstract.c); + } else if (data.getBlock() instanceof BlockButtonAbstract || data.getBlock() instanceof BlockLever) { + return data.get(BlockButtonAbstract.POWERED); + } + return false; + } +} diff --git a/modules/v1_16_R1/src/main/java/net/countercraft/movecraft/compat/v1_16_R1/NextTickProvider.java b/modules/v1_16_R1/src/main/java/net/countercraft/movecraft/compat/v1_16_R1/NextTickProvider.java new file mode 100644 index 000000000..b59445433 --- /dev/null +++ b/modules/v1_16_R1/src/main/java/net/countercraft/movecraft/compat/v1_16_R1/NextTickProvider.java @@ -0,0 +1,68 @@ +package net.countercraft.movecraft.compat.v1_16_R1; + +import net.minecraft.server.v1_16_R1.*; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.lang.reflect.Field; +import java.util.*; + +public class NextTickProvider { + private Map,Collection>> tickMap = new HashMap<>(); + + private boolean isRegistered(@NotNull WorldServer world){ + return tickMap.containsKey(world); + } + + @SuppressWarnings("unchecked") + private void registerWorld(@NotNull WorldServer world){ + final Collection W = new ArrayList<>(); + final Set nextTickList = new HashSet<>(); + TickListServer blockTickListServer = world.getBlockTickList(); + try { + Field gField = TickListServer.class.getDeclaredField("g"); + gField.setAccessible(true); + W.addAll((Collection) gField.get(blockTickListServer)); + Field ntlField = TickListServer.class.getDeclaredField("nextTickList"); + ntlField.setAccessible(true); + nextTickList.addAll((Set) ntlField.get(blockTickListServer)); + } catch (IllegalAccessException | IllegalArgumentException | NoSuchFieldException | SecurityException e1) { + e1.printStackTrace(); + } + tickMap.put(world, new AbstractMap.SimpleImmutableEntry<>(nextTickList,W)); + } + + @Nullable + public NextTickListEntry getNextTick(@NotNull WorldServer world,@NotNull BlockPosition position) { + if (!isRegistered(world)) + registerWorld(world); + AbstractMap.SimpleImmutableEntry, Collection> listPair = tickMap.get(world); + if(listPair.getKey().contains(fakeEntry(position))) { + for (Iterator iterator = listPair.getKey().iterator(); iterator.hasNext(); ) { + NextTickListEntry listEntry = iterator.next(); + if (position.equals(listEntry.a)) { + iterator.remove(); + return listEntry; + } + } + } + for(Iterator iterator = listPair.getValue().iterator(); iterator.hasNext();) { + NextTickListEntry listEntry = iterator.next(); + if (position.equals(listEntry.a)) { + iterator.remove(); + return listEntry; + } + } + return null; + + } + @NotNull + public Object fakeEntry(@NotNull BlockPosition position){ + return new Object(){ + @Override + public int hashCode() { + return position.hashCode(); + } + }; + } +} diff --git a/modules/v1_8_R3/src/main/java/net/countercraft/movecraft/compat/v1_8_R3/IWorldHandler.java b/modules/v1_8_R3/src/main/java/net/countercraft/movecraft/compat/v1_8_R3/IWorldHandler.java index f4d6e019b..9c62e955c 100644 --- a/modules/v1_8_R3/src/main/java/net/countercraft/movecraft/compat/v1_8_R3/IWorldHandler.java +++ b/modules/v1_8_R3/src/main/java/net/countercraft/movecraft/compat/v1_8_R3/IWorldHandler.java @@ -295,6 +295,7 @@ private void setBlockFast(@NotNull World world, @NotNull BlockPosition position, chunkSection.setType(position.getX()&15, position.getY()&15, position.getZ()&15, data); world.notify(position); + world.c(EnumSkyBlock.BLOCK, position); chunk.e(); } diff --git a/modules/v1_9_R2/src/main/java/net/countercraft/movecraft/compat/v1_9_R2/IWorldHandler.java b/modules/v1_9_R2/src/main/java/net/countercraft/movecraft/compat/v1_9_R2/IWorldHandler.java index 492ba2a2a..0c49ba248 100644 --- a/modules/v1_9_R2/src/main/java/net/countercraft/movecraft/compat/v1_9_R2/IWorldHandler.java +++ b/modules/v1_9_R2/src/main/java/net/countercraft/movecraft/compat/v1_9_R2/IWorldHandler.java @@ -287,6 +287,7 @@ private void setBlockFast(@NotNull World world, @NotNull BlockPosition position, chunkSection.setType(position.getX()&15, position.getY()&15, position.getZ()&15, data); world.notify(position, data, data, 3); + world.c(EnumSkyBlock.BLOCK, position); chunk.e(); } From 852949fc8d0fca205f2fa613584eaf26c1a24468 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Sat, 27 Jun 2020 00:53:32 +0200 Subject: [PATCH 179/304] Added "CheckForUpdates" to config.yml and removed unused update commands --- modules/Movecraft/dependency-reduced-pom.xml | 2 +- modules/Movecraft/pom.xml | 2 +- .../net/countercraft/movecraft/Movecraft.java | 1 + .../update/ChunkLoadUpdateCommand.java | 51 ------------------- .../update/WaterlogUpdateCommand.java | 31 ----------- .../movecraft/utils/UpdateManager.java | 3 ++ .../Movecraft/src/main/resources/config.yml | 1 + .../src/main/resources/config_legacy.yml | 2 + .../movecraft/config/Settings.java | 2 + 9 files changed, 11 insertions(+), 84 deletions(-) delete mode 100644 modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/ChunkLoadUpdateCommand.java delete mode 100644 modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/WaterlogUpdateCommand.java diff --git a/modules/Movecraft/dependency-reduced-pom.xml b/modules/Movecraft/dependency-reduced-pom.xml index 26fce8532..e4d4bdae5 100644 --- a/modules/Movecraft/dependency-reduced-pom.xml +++ b/modules/Movecraft/dependency-reduced-pom.xml @@ -4,7 +4,7 @@ net.countercraft movecraft Movecraft - 7.0.0_for_1.8.8-1.16.1_beta_25 + 7.0.0_for_1.8.8-1.16.1_beta_26 http://github.com/apdevteam/Movecraft src/main/java diff --git a/modules/Movecraft/pom.xml b/modules/Movecraft/pom.xml index 9b211ceb9..c2ab1d341 100644 --- a/modules/Movecraft/pom.xml +++ b/modules/Movecraft/pom.xml @@ -10,7 +10,7 @@ UTF-8 - 7.0.0_for_1.8.8-1.16.1_beta_25 + 7.0.0_for_1.8.8-1.16.1_beta_26 spigot-repo diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java index 2762f4a51..ef7dec4a7 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java @@ -227,6 +227,7 @@ public void onEnable() { Settings.SetHomeToCrewSign = getConfig().getBoolean("SetHomeToCrewSign", true); Settings.MaxRemoteSigns = getConfig().getInt("MaxRemoteSigns", -1); Settings.CraftsUseNetherPortals = getConfig().getBoolean("CraftsUseNetherPortals", false); + Settings.CheckForUpdates = getConfig().getBoolean("CheckForUpdates", true); Settings.RequireCreatePerm = getConfig().getBoolean("RequireCreatePerm", false); Settings.RequireNamePerm = getConfig().getBoolean("RequireNamePerm", false); Settings.TNTContactExplosives = getConfig().getBoolean("TNTContactExplosives", true); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/ChunkLoadUpdateCommand.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/ChunkLoadUpdateCommand.java deleted file mode 100644 index fcca390ca..000000000 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/ChunkLoadUpdateCommand.java +++ /dev/null @@ -1,51 +0,0 @@ -package net.countercraft.movecraft.mapUpdater.update; - -import org.bukkit.Chunk; - -import java.util.Objects; - -public class ChunkLoadUpdateCommand extends UpdateCommand { - - private final Chunk chunk; - private final boolean forceLoaded; - private final boolean generate; - - public ChunkLoadUpdateCommand(Chunk chunk, boolean forceLoaded, boolean generate) { - this.chunk = chunk; - this.forceLoaded = forceLoaded; - this.generate = generate; - } - - @Override - public void doUpdate() { - chunk.setForceLoaded(forceLoaded); - chunk.load(generate); - } - - public boolean isForceLoaded() { - return forceLoaded; - } - - public boolean isGenerate() { - return generate; - } - - public Chunk getChunk() { - return chunk; - } - - @Override - public boolean equals(Object o) { - if (!(o instanceof ChunkLoadUpdateCommand)) - return false; - ChunkLoadUpdateCommand that = (ChunkLoadUpdateCommand) o; - return forceLoaded == that.forceLoaded && - generate == that.generate && - chunk.equals(that.chunk); - } - - @Override - public int hashCode() { - return Objects.hash(chunk, forceLoaded, generate); - } -} diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/WaterlogUpdateCommand.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/WaterlogUpdateCommand.java deleted file mode 100644 index ebacb0bcb..000000000 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/WaterlogUpdateCommand.java +++ /dev/null @@ -1,31 +0,0 @@ -package net.countercraft.movecraft.mapUpdater.update; - -import org.bukkit.Location; -import org.bukkit.block.data.Waterlogged; -import org.bukkit.util.Vector; - -public class WaterlogUpdateCommand extends UpdateCommand{ - private final Location location; - private final boolean waterlogged; - - public WaterlogUpdateCommand(Location location, boolean waterlogged){ - this.location = location; - - this.waterlogged = waterlogged; - } - - @Override - public void doUpdate() { - final Waterlogged wLog = (Waterlogged) location.getBlock().getBlockData(); - wLog.setWaterlogged(waterlogged); - location.getBlock().setBlockData(wLog); - } - - - private final Vector[] SHIFTS = {new Vector(0,1,0), - new Vector(0, -1, 0), - new Vector(1, 0, 0), - new Vector(-1, 0, 0), - new Vector(0, 0, 1), - new Vector(0, 0, -1)}; -} diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/UpdateManager.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/UpdateManager.java index 3a5b384a1..0c7cab6a4 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/UpdateManager.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/UpdateManager.java @@ -2,6 +2,7 @@ import com.google.gson.Gson; import net.countercraft.movecraft.Movecraft; +import net.countercraft.movecraft.config.Settings; import net.countercraft.movecraft.localisation.I18nSupport; import org.bukkit.Bukkit; import org.bukkit.entity.Player; @@ -41,6 +42,8 @@ public static UpdateManager getInstance() { @Override public void run() { + if (!Settings.CheckForUpdates) + return; final Logger log = Movecraft.getInstance().getLogger(); log.info(I18nSupport.getInternationalisedString("Update - Checking for updates")); new BukkitRunnable() { diff --git a/modules/Movecraft/src/main/resources/config.yml b/modules/Movecraft/src/main/resources/config.yml index 13a450c5c..3934e6e08 100644 --- a/modules/Movecraft/src/main/resources/config.yml +++ b/modules/Movecraft/src/main/resources/config.yml @@ -27,6 +27,7 @@ AllowCrewSigns: true MaxRemoteSigns: -1 # Maximum number of remote signs that can be triggered at once. Setting to -1 allows unlimited. SetHomeToCrewSign: false CraftsUseNetherPortals: false +CheckForUpdates: true AssaultEnable: false # system to damage a region, incurring money damages. If enough damage is inflicted, ownership is lost. Ownership can be restored, and the region repaired, by paying damages AssaultDamagesCapPercent: 1.0 # percentage of the total wealth of all members of the region which is the maximum damages that can be inflicted AssaultCooldownHours: 24 # time before a region owner can have one of their regions assaulted again diff --git a/modules/Movecraft/src/main/resources/config_legacy.yml b/modules/Movecraft/src/main/resources/config_legacy.yml index 992fa8f03..2210a7f37 100644 --- a/modules/Movecraft/src/main/resources/config_legacy.yml +++ b/modules/Movecraft/src/main/resources/config_legacy.yml @@ -23,6 +23,8 @@ RepairMoneyPerBlock: 10 RepairMaxPercent: 60.0 AllowCrewSigns: true SetHomeToCrewSign: false +CraftsUseNetherPortals: false +CheckForUpdates: true AssaultEnable: true # system to damage a region, incurring money damages. If enough damage is inflicted, ownership is lost. Ownership can be restored, and the region repaired, by paying damages AssaultDamagesCapPercent: 1.0 # percentage of the total wealth of all members of the region which is the maximum damages that can be inflicted AssaultCooldownHours: 24 # time before a region owner can have one of their regions assaulted again diff --git a/modules/api/src/main/java/net/countercraft/movecraft/config/Settings.java b/modules/api/src/main/java/net/countercraft/movecraft/config/Settings.java index 52dcf9fb0..8bd849682 100644 --- a/modules/api/src/main/java/net/countercraft/movecraft/config/Settings.java +++ b/modules/api/src/main/java/net/countercraft/movecraft/config/Settings.java @@ -23,6 +23,8 @@ import java.util.*; public class Settings { + + public static boolean CheckForUpdates = true; public static boolean RestrictSiBsToRegions = false; public static boolean IGNORE_RESET = false; public static boolean Debug = false; From db7a40141e3e861b8edc29b1a47f24d29d4c5d67 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Sat, 27 Jun 2020 13:11:30 +0200 Subject: [PATCH 180/304] Removed unused StatusSignMarkers --- modules/Movecraft/src/main/resources/config.yml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/modules/Movecraft/src/main/resources/config.yml b/modules/Movecraft/src/main/resources/config.yml index 3934e6e08..715bc1024 100644 --- a/modules/Movecraft/src/main/resources/config.yml +++ b/modules/Movecraft/src/main/resources/config.yml @@ -173,7 +173,3 @@ ForbiddenRemoteSigns: # These strings will be ignored when searching for signs t - "Denied" - "[private]" RequireNamePerm: true # Require movecraft.name.place to place Name: signs and movecraft.name.use to use Name: signs -StatusSignMarkers: - all_wood: Wd - all_wool: Wl - iron_block: I \ No newline at end of file From 912318f7ad4549c2bc84c3569f70411189daddaa Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Sun, 28 Jun 2020 19:36:42 +0200 Subject: [PATCH 181/304] Removed unused StatusSignMarkers --- .gitignore | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.gitignore b/.gitignore index c5f9c7445..3e777f62a 100644 --- a/.gitignore +++ b/.gitignore @@ -189,3 +189,7 @@ $RECYCLE.BIN/ # Windows shortcuts *.lnk + +# dependency reduced POMs +modules/Movecraft/dependency-reduced-pom.xml +modules/api/dependency-reduced-pom.xml \ No newline at end of file From 94aa54b94bcf662c1b75c3233b0e7e544e89f7df Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Tue, 30 Jun 2020 21:25:23 +0200 Subject: [PATCH 182/304] Improvement in fuel consumption processing and fixed inventories not opening when switching worlds --- .../async/rotation/RotationTask.java | 113 ++++----- .../async/translation/TranslationTask.java | 215 +++++++++--------- .../compat/v1_15_R1/IWorldHandler.java | 2 +- .../compat/v1_16_R1/IWorldHandler.java | 2 +- 4 files changed, 171 insertions(+), 161 deletions(-) diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/rotation/RotationTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/rotation/RotationTask.java index 9807fb6a4..1f30109fd 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/rotation/RotationTask.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/rotation/RotationTask.java @@ -40,10 +40,11 @@ import org.bukkit.entity.Player; import org.bukkit.inventory.InventoryHolder; import org.bukkit.inventory.ItemStack; -import org.bukkit.scheduler.BukkitRunnable; import java.util.HashSet; import java.util.Set; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutionException; import static net.countercraft.movecraft.utils.MathUtils.withinWorldBorder; @@ -97,58 +98,8 @@ protected void execute() { failed = true; failMessage = I18nSupport.getInternationalisedString("Translation - Failed Craft Is Disabled"); } - if (craft.getType().getFuelBurnRate() > 0.0) { - - new BukkitRunnable() { - @Override - public void run() { - // check for fuel, burn some from a furnace if needed. Blocks of coal are supported, in addition to coal and charcoal - double fuelBurnRate = craft.getType().getFuelBurnRate(); - // going down doesn't require fuel - if (fuelBurnRate == 0.0 || craft.getSinking()) { - return; - } - if (craft.getBurningFuel() >= fuelBurnRate) { - craft.setBurningFuel(craft.getBurningFuel() - fuelBurnRate); - return; - } - Block fuelHolder = null; - for (MovecraftLocation bTest : oldHitBox) { - Block b = craft.getWorld().getBlockAt(bTest.getX(), bTest.getY(), bTest.getZ()); - //Get all fuel holders - if (b.getType() == Material.FURNACE) { - InventoryHolder holder = (InventoryHolder) b.getState(); - for (Material fuel : Settings.FuelTypes.keySet()) { - if (holder.getInventory().contains(fuel)) { - fuelHolder = b; - break; - } - } - } - if (fuelHolder != null) break; - - } - if (fuelHolder == null) { - failMessage = I18nSupport.getInternationalisedString("Translation - Failed Craft out of fuel"); - failed = true; - return; - } - Furnace furnace = (Furnace) fuelHolder.getState(); - for (Material fuel : Settings.FuelTypes.keySet()){ - if (furnace.getInventory().contains(fuel)){ - ItemStack item = furnace.getInventory().getItem(furnace.getInventory().first(fuel)); - int amount = item.getAmount(); - if (amount == 1) { - furnace.getInventory().remove(item); - } else { - item.setAmount(amount - 1); - } - craft.setBurningFuel(craft.getBurningFuel() + Settings.FuelTypes.get(item.getType())); - } - } - } - }.runTask(Movecraft.getInstance()); - + if (!checkFuel()) { + return; } // if a subcraft, find the parent craft. If not a subcraft, it is it's own parent Set craftsInWorld = CraftManager.getInstance().getCraftsInWorld(getCraft().getWorld()); @@ -385,6 +336,62 @@ private boolean checkChests(Material mBlock, MovecraftLocation newLoc) { return !testMaterial.equals(mBlock) || oldHitBox.contains(aroundNewLoc); } + private boolean checkFuel() { + // check for fuel, burn some from a furnace if needed. Blocks of coal are supported, in addition to coal and charcoal + double fuelBurnRate = craft.getType().getFuelBurnRate(craft.getWorld()); + if (fuelBurnRate <= 0.0 || craft.getSinking()) { + return true; + } + // going down doesn't require fuel + if (craft.getBurningFuel() >= fuelBurnRate) { + craft.setBurningFuel(craft.getBurningFuel() - fuelBurnRate); + return true; + } + try { + return Bukkit.getScheduler().callSyncMethod(Movecraft.getInstance(), (Callable) () -> { + + Block fuelHolder = null; + for (MovecraftLocation bTest : oldHitBox) { + Block b = bTest.toBukkit(craft.getWorld()).getBlock(); + //Get all fuel holders + if (b.getType() == Material.FURNACE) { + InventoryHolder holder = (InventoryHolder) b.getState(); + for (Material fuel : Settings.FuelTypes.keySet()) { + if (holder.getInventory().contains(fuel)) { + fuelHolder = b; + break; + } + } + } + if (fuelHolder != null) break; + + } + if (fuelHolder == null) { + failMessage = I18nSupport.getInternationalisedString("Translation - Failed Craft out of fuel"); + failed = true; + return false; + } + Furnace furnace = (Furnace) fuelHolder.getState(); + for (Material fuel : Settings.FuelTypes.keySet()){ + if (furnace.getInventory().contains(fuel)){ + ItemStack item = furnace.getInventory().getItem(furnace.getInventory().first(fuel)); + int amount = item.getAmount(); + if (amount == 1) { + furnace.getInventory().remove(item); + } else { + item.setAmount(amount - 1); + } + craft.setBurningFuel(craft.getBurningFuel() + Settings.FuelTypes.get(item.getType())); + } + } + return true; + }).get(); + } catch (InterruptedException | ExecutionException e) { + e.printStackTrace(); + return false; + } + } + public BitmapHitBox getNewHitBox() { diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java index d45a8b1ad..edabac323 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java @@ -15,11 +15,10 @@ import net.countercraft.movecraft.events.ItemHarvestEvent; import net.countercraft.movecraft.localisation.I18nSupport; import net.countercraft.movecraft.mapUpdater.update.*; - import net.countercraft.movecraft.utils.*; import org.bukkit.*; -import org.bukkit.block.Barrel; import org.bukkit.World.Environment; +import org.bukkit.block.Barrel; import org.bukkit.block.Block; import org.bukkit.block.Chest; import org.bukkit.block.Furnace; @@ -30,7 +29,6 @@ import org.bukkit.inventory.InventoryHolder; import org.bukkit.inventory.ItemStack; import org.bukkit.potion.PotionEffect; -import org.bukkit.scheduler.BukkitRunnable; import org.jetbrains.annotations.NotNull; import java.util.*; @@ -183,6 +181,10 @@ protected void execute() throws InterruptedException, ExecutionException { final int minY = oldHitBox.getMinY(); final int maxY = oldHitBox.getMaxY(); + if (!checkFuel()) { + return; + } + // proccess nether portals if (Settings.CraftsUseNetherPortals && craft.getWorld().getEnvironment() != Environment.THE_END && world.equals(craft.getWorld())) { @@ -251,62 +253,10 @@ protected void execute() throws InterruptedException, ExecutionException { fail(I18nSupport.getInternationalisedString("Translation - Failed Craft hit minimum height limit")); return; } - if (craft.getType().getFuelBurnRate(world) > 0.0) { - new BukkitRunnable() { - @Override - public void run() { - // check for fuel, burn some from a furnace if needed. Blocks of coal are supported, in addition to coal and charcoal - double fuelBurnRate = craft.getType().getFuelBurnRate(world); - // going down doesn't require fuel - if (dy == -1 && dx == 0 && dz == 0) - fuelBurnRate = 0.0; - if (dy > 0) - fuelBurnRate *= 2; - if (fuelBurnRate == 0.0 || craft.getSinking()) { - return; - } - if (craft.getBurningFuel() >= fuelBurnRate) { - craft.setBurningFuel(craft.getBurningFuel() - fuelBurnRate); - return; - } - Block fuelHolder = null; - for (MovecraftLocation bTest : oldHitBox) { - Block b = craft.getWorld().getBlockAt(bTest.getX(), bTest.getY(), bTest.getZ()); - //Get all fuel holders - if (b.getType() == Material.FURNACE) { - InventoryHolder holder = (InventoryHolder) b.getState(); - for (Material fuel : Settings.FuelTypes.keySet()) { - if (holder.getInventory().contains(fuel)) { - fuelHolder = b; - break; - } - } - } - if (fuelHolder != null) break; - } - if (fuelHolder == null) { - fail(I18nSupport.getInternationalisedString("Translation - Failed Craft out of fuel")); - return; - } - Furnace furnace = (Furnace) fuelHolder.getState(); - for (Material fuel : Settings.FuelTypes.keySet()){ - if (furnace.getInventory().contains(fuel)){ - ItemStack item = furnace.getInventory().getItem(furnace.getInventory().first(fuel)); - int amount = item.getAmount(); - if (amount == 1) { - furnace.getInventory().remove(item); - } else { - item.setAmount(amount - 1); - } - craft.setBurningFuel(craft.getBurningFuel() + Settings.FuelTypes.get(item.getType())); - } - } - } - }.runTask(Movecraft.getInstance()); - } + //Process gravity if (world.equals(craft.getWorld()) && craft.getType().getUseGravity() && !craft.getSinking()){ int incline = inclineCraft(oldHitBox); @@ -584,66 +534,64 @@ private void captureYield(List harvestedBlocks) { if (harvestedBlocks.isEmpty()) { return; } - new BukkitRunnable() { - @Override - public void run() { - ArrayList chests = new ArrayList<>(); - //find chests - for (MovecraftLocation loc : oldHitBox) { - Block block = craft.getWorld().getBlockAt(loc.getX(), loc.getY(), loc.getZ()); - if (block.getType() == Material.CHEST || block.getType() == Material.TRAPPED_CHEST) - chests.add(((InventoryHolder) (block.getState())).getInventory()); - } + Bukkit.getScheduler().callSyncMethod(Movecraft.getInstance(), () -> { + ArrayList chests = new ArrayList<>(); + //find chests + for (MovecraftLocation loc : oldHitBox) { + Block block = craft.getWorld().getBlockAt(loc.getX(), loc.getY(), loc.getZ()); + if (block.getType() == Material.CHEST || block.getType() == Material.TRAPPED_CHEST) + chests.add(((InventoryHolder) (block.getState())).getInventory()); + } - for (MovecraftLocation harvestedBlock : harvestedBlocks) { + for (MovecraftLocation harvestedBlock : harvestedBlocks) { - Block block = craft.getWorld().getBlockAt(harvestedBlock.getX(), harvestedBlock.getY(), harvestedBlock.getZ()); - List drops = new ArrayList<>(block.getDrops()); + Block block = craft.getWorld().getBlockAt(harvestedBlock.getX(), harvestedBlock.getY(), harvestedBlock.getZ()); + List drops = new ArrayList<>(block.getDrops()); - if (Settings.IsLegacy) { - //generate seed drops - if (block.getType() == LegacyUtils.CROPS) { - Random rand = new Random(); - int amount = rand.nextInt(4); - if (amount > 0) { - ItemStack seeds = new ItemStack(LegacyUtils.SEEDS, amount); - drops.add(seeds); - } - } - } else { - if (block.getType() == Material.WHEAT) { - Random rand = new Random(); - int amount = rand.nextInt(4); - if (amount > 0) { - ItemStack seeds = new ItemStack(Material.WHEAT_SEEDS, amount); - drops.add(seeds); - } + if (Settings.IsLegacy) { + //generate seed drops + if (block.getType() == LegacyUtils.CROPS) { + Random rand = new Random(); + int amount = rand.nextInt(4); + if (amount > 0) { + ItemStack seeds = new ItemStack(LegacyUtils.SEEDS, amount); + drops.add(seeds); } } - //get contents of inventories before deposting - - if (block.getState() instanceof InventoryHolder) { - if (block.getState() instanceof Chest) { - drops.addAll(Arrays.asList(((Chest) block.getState()).getBlockInventory().getContents())); - } else if (block.getState() instanceof Barrel) { - drops.addAll(Arrays.asList(((Barrel) block.getState()).getInventory().getContents())); - } else { - drops.addAll(Arrays.asList((((InventoryHolder) block.getState()).getInventory().getContents()))); + } else { + if (block.getType() == Material.WHEAT) { + Random rand = new Random(); + int amount = rand.nextInt(4); + if (amount > 0) { + ItemStack seeds = new ItemStack(Material.WHEAT_SEEDS, amount); + drops.add(seeds); } } - //call event - final ItemHarvestEvent harvestEvent = new ItemHarvestEvent(craft, drops, harvestedBlock.toBukkit(craft.getWorld())); - Bukkit.getServer().getPluginManager().callEvent(harvestEvent); - for (ItemStack drop : drops) { - ItemStack retStack = putInToChests(drop, chests); - if (retStack != null) - //drop items on position - updates.add(new ItemDropUpdateCommand(new Location(craft.getWorld(), harvestedBlock.getX(), harvestedBlock.getY(), harvestedBlock.getZ()), retStack)); + } + //get contents of inventories before deposting + + if (block.getState() instanceof InventoryHolder) { + if (block.getState() instanceof Chest) { + drops.addAll(Arrays.asList(((Chest) block.getState()).getBlockInventory().getContents())); + } else if (block.getState() instanceof Barrel) { + drops.addAll(Arrays.asList(((Barrel) block.getState()).getInventory().getContents())); + } else { + drops.addAll(Arrays.asList((((InventoryHolder) block.getState()).getInventory().getContents()))); } } - } + //call event + final ItemHarvestEvent harvestEvent = new ItemHarvestEvent(craft, drops, harvestedBlock.toBukkit(craft.getWorld())); + Bukkit.getServer().getPluginManager().callEvent(harvestEvent); + for (ItemStack drop : drops) { + ItemStack retStack = putInToChests(drop, chests); + if (retStack != null) + //drop items on position + updates.add(new ItemDropUpdateCommand(new Location(craft.getWorld(), harvestedBlock.getX(), harvestedBlock.getY(), harvestedBlock.getZ()), retStack)); + } - }.runTask(Movecraft.getInstance()); + } + return true; + }); } private boolean processNetherPortal(@NotNull Block block) { @@ -937,6 +885,61 @@ private boolean isOnGround(BitmapHitBox hitBox){ return !translatedBottomLocsInAir; } + private boolean checkFuel() { + double fuelBurnRate = craft.getType().getFuelBurnRate(world); + if (fuelBurnRate <= 0.0 || (dy == -1 && dx == 0 && dz == 0) || craft.getSinking()) + return true; + // check for fuel, burn some from a furnace if needed. Blocks of coal are supported, in addition to coal and charcoal + + // going down doesn't require fuel + if (dy > 0) + fuelBurnRate *= 2; + if (craft.getBurningFuel() >= fuelBurnRate) { + craft.setBurningFuel(craft.getBurningFuel() - fuelBurnRate); + return true; + } + try { + return Bukkit.getScheduler().callSyncMethod(Movecraft.getInstance(), () -> { + Block fuelHolder = null; + for (MovecraftLocation bTest : oldHitBox) { + Block b = craft.getWorld().getBlockAt(bTest.getX(), bTest.getY(), bTest.getZ()); + //Get all fuel holders + if (b.getType() == Material.FURNACE) { + InventoryHolder holder = (InventoryHolder) b.getState(); + for (Material fuel : Settings.FuelTypes.keySet()) { + if (holder.getInventory().contains(fuel)) { + fuelHolder = b; + break; + } + } + } + if (fuelHolder != null) break; + + } + if (fuelHolder == null) { + fail(I18nSupport.getInternationalisedString("Translation - Failed Craft out of fuel")); + return false; + } + Furnace furnace = (Furnace) fuelHolder.getState(); + for (Material fuel : Settings.FuelTypes.keySet()){ + if (furnace.getInventory().contains(fuel)){ + ItemStack item = furnace.getInventory().getItem(furnace.getInventory().first(fuel)); + int amount = item.getAmount(); + if (amount == 1) { + furnace.getInventory().remove(item); + } else { + item.setAmount(amount - 1); + } + craft.setBurningFuel(craft.getBurningFuel() + Settings.FuelTypes.get(item.getType())); + } + } + return true; + }).get(); + } catch (InterruptedException | ExecutionException e) { + e.printStackTrace(); + return false; + } + } public boolean failed(){ return failed; } diff --git a/modules/v1_15_R1/src/main/java/net/countercraft/movecraft/compat/v1_15_R1/IWorldHandler.java b/modules/v1_15_R1/src/main/java/net/countercraft/movecraft/compat/v1_15_R1/IWorldHandler.java index 4c9a7319c..2f234520f 100644 --- a/modules/v1_15_R1/src/main/java/net/countercraft/movecraft/compat/v1_15_R1/IWorldHandler.java +++ b/modules/v1_15_R1/src/main/java/net/countercraft/movecraft/compat/v1_15_R1/IWorldHandler.java @@ -379,7 +379,7 @@ private void moveTileEntity(@NotNull World nativeWorld, @NotNull BlockPosition n nativeWorld.capturedTileEntities.put(newPosition, tile); return; } - tile.setPosition(newPosition); + tile.setLocation(nativeWorld, newPosition); chunk.tileEntities.put(newPosition, tile); } diff --git a/modules/v1_16_R1/src/main/java/net/countercraft/movecraft/compat/v1_16_R1/IWorldHandler.java b/modules/v1_16_R1/src/main/java/net/countercraft/movecraft/compat/v1_16_R1/IWorldHandler.java index f3b4a9969..d717c78a2 100644 --- a/modules/v1_16_R1/src/main/java/net/countercraft/movecraft/compat/v1_16_R1/IWorldHandler.java +++ b/modules/v1_16_R1/src/main/java/net/countercraft/movecraft/compat/v1_16_R1/IWorldHandler.java @@ -386,7 +386,7 @@ private void moveTileEntity(@NotNull WorldServer nativeWorld, @NotNull BlockPosi nativeWorld.capturedTileEntities.put(newPosition, tile); return; } - tile.setPosition(newPosition); + tile.setLocation(nativeWorld, newPosition); chunk.tileEntities.put(newPosition, tile); } From 0ba3313308b5f1345cb14300a7a272971626cc48 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Thu, 2 Jul 2020 21:00:38 +0200 Subject: [PATCH 183/304] Fixed torps not exploding --- .../movecraft/async/translation/TranslationTask.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java index 09db94c74..955c13dda 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java @@ -449,7 +449,7 @@ protected void execute() throws InterruptedException, ExecutionException { if(!collisionBox.isEmpty() && craft.getType().getCruiseOnPilot()){ CraftManager.getInstance().removeCraft(craft); for(MovecraftLocation location : oldHitBox){ - Pair phaseBlock = craft.getPhaseBlocks().getOrDefault(location.toBukkit(craft.getW()), new Pair<>(Material.AIR, (byte) 0)); + Pair phaseBlock = craft.getPhaseBlocks().getOrDefault(location.toBukkit(craft.getW()), new Pair<>(Material.AIR, Settings.IsLegacy ? (byte) 0 : Bukkit.createBlockData(Material.AIR))); if (Settings.IsLegacy) { updates.add(new BlockCreateCommand(craft.getWorld(), location, phaseBlock.getLeft(), (byte) phaseBlock.getRight())); continue; From 9f00b35018632a47b7b5d612e661391d86bcfec9 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Sat, 11 Jul 2020 01:36:40 +0200 Subject: [PATCH 184/304] fix #56 --- .../java/net/countercraft/movecraft/utils/WaterlogUtils.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/WaterlogUtils.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/WaterlogUtils.java index 1f10402fc..fb2b818e1 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/WaterlogUtils.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/WaterlogUtils.java @@ -19,7 +19,7 @@ private WaterlogUtils(){ public static void waterlogBlocksOnCraft(Craft craft, HitBox interior) { for (MovecraftLocation ml : craft.getHitBox()) { - final Material phaseBlock = craft.getPhaseBlocks().getOrDefault(ml, DEFAULT_PHASE_BLOCK).getLeft(); + final Material phaseBlock = craft.getPhaseBlocks().getOrDefault(ml.toBukkit(craft.getWorld()), DEFAULT_PHASE_BLOCK).getLeft(); boolean waterlog = phaseBlock == Material.WATER; Block b = ml.toBukkit(craft.getWorld()).getBlock(); if (!(b.getBlockData() instanceof Waterlogged)) { From 6260cfa8d8489f7a39d0b36d4468043f4a1bd209 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Sat, 11 Jul 2020 11:40:28 +0200 Subject: [PATCH 185/304] fix #97 and fix #56 --- .../java/net/countercraft/movecraft/async/AsyncManager.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java index a98a0ee4b..900419375 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java @@ -946,7 +946,11 @@ private void processFadingBlocks() { final World world = wreckWorlds.get(hitBox); ArrayList commands = new ArrayList<>(); for (MovecraftLocation location : hitBox){ - Pair phaseBlock = phaseBlocks.getOrDefault(location.toBukkit(world), new Pair<>(Material.AIR, (byte) 0)); + Pair phaseBlock = phaseBlocks.getOrDefault(location.toBukkit(world), new Pair<>(Material.AIR, Settings.IsLegacy ? (byte) 0 : Bukkit.createBlockData(Material.AIR))); + if (Settings.IsLegacy) { + commands.add(new BlockCreateCommand(world, location, phaseBlock.getLeft(),(byte) phaseBlock.getRight())); + continue; + } commands.add(new BlockCreateCommand(world, location, phaseBlock.getLeft(),(BlockData) phaseBlock.getRight())); } From 911c63e187620c3f2d440cdc331691d71471300e Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Sat, 11 Jul 2020 13:06:22 +0200 Subject: [PATCH 186/304] bump version --- modules/Movecraft/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/Movecraft/pom.xml b/modules/Movecraft/pom.xml index c2ab1d341..571e309f5 100644 --- a/modules/Movecraft/pom.xml +++ b/modules/Movecraft/pom.xml @@ -10,7 +10,7 @@ UTF-8 - 7.0.0_for_1.8.8-1.16.1_beta_26 + 7.0.0_for_1.8.8-1.16.1_beta_27 spigot-repo From 22cc6dc339f66e824bf2dfeee2de4f2f4d913b7d Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Sat, 11 Jul 2020 13:20:20 +0200 Subject: [PATCH 187/304] Added check for plugin ticket --- modules/Movecraft/dependency-reduced-pom.xml | 2 +- .../java/net/countercraft/movecraft/craft/ChunkManager.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/Movecraft/dependency-reduced-pom.xml b/modules/Movecraft/dependency-reduced-pom.xml index e4d4bdae5..3bfd8f62f 100644 --- a/modules/Movecraft/dependency-reduced-pom.xml +++ b/modules/Movecraft/dependency-reduced-pom.xml @@ -4,7 +4,7 @@ net.countercraft movecraft Movecraft - 7.0.0_for_1.8.8-1.16.1_beta_26 + 7.0.0_for_1.8.8-1.16.1_beta_27 http://github.com/apdevteam/Movecraft src/main/java diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/ChunkManager.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/ChunkManager.java index baac75aa5..c1dcdf3b2 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/ChunkManager.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/ChunkManager.java @@ -62,7 +62,7 @@ public void run() { private static void removeChunksToLoad(List list) { for (MovecraftChunk chunk : list) { chunks.remove(chunk); - if (!Settings.IsLegacy) + if (!Settings.IsLegacy && chunk.toBukkit().getPluginChunkTickets().contains(Movecraft.getInstance())) chunk.toBukkit().removePluginChunkTicket(Movecraft.getInstance()); } } From ab89ec628813a60a979ae63c8b88df79bd728d36 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Sat, 11 Jul 2020 20:17:15 +0200 Subject: [PATCH 188/304] Removed unused config option causing problems on startup --- .../net/countercraft/movecraft/Movecraft.java | 37 ------------------- 1 file changed, 37 deletions(-) diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java index f676e149a..f4d049ef3 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java @@ -174,43 +174,6 @@ public void onEnable() { } this.getLogger().info(I18nSupport.getInternationalisedString("Startup - Loading Support") + " " + version); - Map tempStatusSignMarkers = getConfig().getConfigurationSection("StatusSignMarkers").getValues(false); - for (String s : tempStatusSignMarkers.keySet()){ - List materialList = new ArrayList<>(); - if (s.contains(",")){ - String[] split = s.split(","); - for (String str : split){ - materialList.add(Material.getMaterial(str.toUpperCase())); - } - } else if (s.toUpperCase().startsWith("ALL_")){ - String str = s.toUpperCase().replace("ALL_", ""); - for (Material type : Material.values()){ - if (type.name().endsWith(str)){ - materialList.add(type); - } - } - } else if (s.contains("0") || s.contains("1") || s.contains("2") || s.contains("3") || s.contains("4") || s.contains("5") || s.contains("6") || s.contains("7") || s.contains("8") || s.contains("9")) { - Material type; - try { - type = LegacyUtils.getMaterial(Integer.parseInt(s)); - } catch (Throwable t){ - throw new IllegalArgumentException("Startup - Numerical IDs not supported", t); - } - if (type != null){ - materialList.add(type); - } - } else { - materialList.add(Material.getMaterial(s.toUpperCase())); - } - Object obj = tempStatusSignMarkers.get(s); - if (!(obj instanceof String)){ - throw new IllegalArgumentException(String.format(I18nSupport.getInternationalisedString("Startup - Status sign marker must be string"), obj)); - } - Collections.sort(materialList); - String marker = (String) obj; - Settings.StatusSignMarkers.put(materialList, marker); - } - Settings.SinkCheckTicks = getConfig().getDouble("SinkCheckTicks", 100.0); Settings.TracerRateTicks = getConfig().getDouble("TracerRateTicks", 5.0); Settings.TracerMinDistanceSqrd = getConfig().getLong("TracerMinDistance", 60); From 5b7416d729561cbeca7c9531888dc9f76452dc42 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Sat, 11 Jul 2020 20:17:45 +0200 Subject: [PATCH 189/304] bump version --- modules/Movecraft/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/Movecraft/pom.xml b/modules/Movecraft/pom.xml index 571e309f5..d7850c911 100644 --- a/modules/Movecraft/pom.xml +++ b/modules/Movecraft/pom.xml @@ -10,7 +10,7 @@ UTF-8 - 7.0.0_for_1.8.8-1.16.1_beta_27 + 7.0.0_for_1.8.8-1.16.1_beta_28 spigot-repo From 8fb920527fccb0022397ba052046f12e3356379b Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Sat, 11 Jul 2020 23:43:41 +0200 Subject: [PATCH 190/304] Fixed a problem with newer Towny versions --- modules/Movecraft/dependency-reduced-pom.xml | 2 +- .../movecraft/utils/TownyUtils.java | 26 +++++++++++++++++-- 2 files changed, 25 insertions(+), 3 deletions(-) diff --git a/modules/Movecraft/dependency-reduced-pom.xml b/modules/Movecraft/dependency-reduced-pom.xml index 3bfd8f62f..3c0eca9a6 100644 --- a/modules/Movecraft/dependency-reduced-pom.xml +++ b/modules/Movecraft/dependency-reduced-pom.xml @@ -4,7 +4,7 @@ net.countercraft movecraft Movecraft - 7.0.0_for_1.8.8-1.16.1_beta_27 + 7.0.0_for_1.8.8-1.16.1_beta_28 http://github.com/apdevteam/Movecraft src/main/java diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/TownyUtils.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/TownyUtils.java index 567741fc8..43e542498 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/TownyUtils.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/TownyUtils.java @@ -23,6 +23,8 @@ import org.bukkit.configuration.file.FileConfiguration; import org.bukkit.entity.Player; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -39,6 +41,16 @@ public class TownyUtils { public static final String TOWN_UNDER = "underTownSpawn"; public static final String TOWN_HEIGHT_LIMITS = "TownyWorldHeightLimits"; + private static Method GET_CACHE_PERMISSION_NON_LEGACY; + + static { + try { + GET_CACHE_PERMISSION_NON_LEGACY = PlayerCacheUtil.class.getDeclaredMethod("getCachePermission", Player.class, Location.class, Material.class, TownyPermission.ActionType.class); + } catch (NoSuchMethodException e) { + GET_CACHE_PERMISSION_NON_LEGACY = null; + } + } + public static TownyWorld getTownyWorld(World w) { TownyWorld tw; try { @@ -110,10 +122,20 @@ public static boolean validateCraftMoveEvent(Player player, Location loc, TownyW if (player != null && !validateResident(player)) { return true; //probably NPC or CBWrapper Dummy player } - int id = Material.STONE_BUTTON.getId(); + Material type = Material.STONE_BUTTON; byte data = 0; - boolean bSwitch = PlayerCacheUtil.getCachePermission(player, loc, id, data, TownyPermission.ActionType.SWITCH); + boolean bSwitch; + if (GET_CACHE_PERMISSION_NON_LEGACY != null) { + try { + bSwitch = (boolean) GET_CACHE_PERMISSION_NON_LEGACY.invoke(player, loc, type, TownyPermission.ActionType.SWITCH); + } catch (IllegalAccessException | InvocationTargetException e) { + bSwitch = true; + } + } else { + bSwitch = PlayerCacheUtil.getCachePermission(player, loc, type.getId(), data, TownyPermission.ActionType.SWITCH); + } + // Allow move if we are permitted to switch if (bSwitch) From be96e20fb070127ba00454e8432d030ca48a6482 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Sun, 12 Jul 2020 00:31:25 +0200 Subject: [PATCH 191/304] using counter for StatusSign --- .../movecraft/sign/StatusSign.java | 25 +++++-------------- 1 file changed, 6 insertions(+), 19 deletions(-) diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/StatusSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/StatusSign.java index 6034b344b..fe6ed7024 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/StatusSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/StatusSign.java @@ -6,6 +6,7 @@ import net.countercraft.movecraft.events.CraftDetectEvent; import net.countercraft.movecraft.events.SignTranslateEvent; import net.countercraft.movecraft.utils.BlockLimitManager; +import net.countercraft.movecraft.utils.Counter; import net.countercraft.movecraft.utils.SignUtils; import org.bukkit.ChatColor; import org.bukkit.Location; @@ -19,8 +20,6 @@ import org.bukkit.inventory.ItemStack; import java.util.ArrayList; -import java.util.HashMap; -import java.util.Map; public final class StatusSign implements Listener{ @@ -53,7 +52,7 @@ public final void onSignTranslate(SignTranslateEvent event) { int signLine = 1; int signColumn = 0; final BlockLimitManager flyBlocks = craft.getType().getFlyBlocks(); - Map foundFlyBlocks = new HashMap<>(); + Counter foundFlyBlocks = new Counter<>(); for (MovecraftLocation ml : craft.getHitBox()){ Location loc = ml.toBukkit(craft.getWorld()); Material testType = loc.getBlock().getType(); @@ -63,21 +62,9 @@ public final void onSignTranslate(SignTranslateEvent event) { } if (flyBlocks.contains(testType)){ - if (foundFlyBlocks.containsKey(flyBlocks.get(testType))){ - int count = foundFlyBlocks.get(flyBlocks.get(testType)); - count++; - foundFlyBlocks.put(flyBlocks.get(testType), count); - } else { - foundFlyBlocks.put(flyBlocks.get(testType), 1); - } + foundFlyBlocks.add(flyBlocks.get(testType)); } else if (flyBlocks.contains(testType, data)){ - if (foundFlyBlocks.containsKey(flyBlocks.get(testType, data))){ - int count = foundFlyBlocks.get(flyBlocks.get(testType, data)); - count++; - foundFlyBlocks.put(flyBlocks.get(testType, data), count); - } else { - foundFlyBlocks.put(flyBlocks.get(testType, data), 1); - } + foundFlyBlocks.get(flyBlocks.get(testType, data)); } if (testType == Material.FURNACE) { @@ -90,7 +77,7 @@ public final void onSignTranslate(SignTranslateEvent event) { } } } - for (BlockLimitManager.Entry entry : foundFlyBlocks.keySet()) { + for (BlockLimitManager.Entry entry : flyBlocks.getEntries()) { int amount = foundFlyBlocks.get(entry); double minimum = entry.getLowerLimit(); if (minimum == 0) @@ -127,7 +114,7 @@ public final void onSignTranslate(SignTranslateEvent event) { signLine++; } String fuelText=""; - int fuelRange=(int) ((fuel*(1+(craft.getType().getCruiseSkipBlocks(craft.getW())+1)))/craft.getType().getFuelBurnRate(craft.getW())); + int fuelRange=(int) ((fuel*(1+(craft.getType().getCruiseSkipBlocks(craft.getWorld())+1)))/craft.getType().getFuelBurnRate(craft.getW())); if(fuelRange>1000) { fuelText+=ChatColor.GREEN; } else if(fuelRange>100) { From 04276145bff4d2d8c24902dde3feeab3207bea96 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Sun, 12 Jul 2020 01:30:04 +0200 Subject: [PATCH 192/304] Replaced notifyAndUpdatePhysics in NMS World Handler for 1.16 due to method being absent from PaperMC --- .../countercraft/movecraft/compat/v1_16_R1/IWorldHandler.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/modules/v1_16_R1/src/main/java/net/countercraft/movecraft/compat/v1_16_R1/IWorldHandler.java b/modules/v1_16_R1/src/main/java/net/countercraft/movecraft/compat/v1_16_R1/IWorldHandler.java index d717c78a2..15699ac17 100644 --- a/modules/v1_16_R1/src/main/java/net/countercraft/movecraft/compat/v1_16_R1/IWorldHandler.java +++ b/modules/v1_16_R1/src/main/java/net/countercraft/movecraft/compat/v1_16_R1/IWorldHandler.java @@ -276,7 +276,8 @@ private void processRedstone(List redstone, WorldServer world) { } chunkSection.setType(position.getX()&15, position.getY()&15, position.getZ()&15, data); - world.notifyAndUpdatePhysics(position, chunk, data, data, data, 3); + //world.notifyAndUpdatePhysics(position, chunk, data, data, data, 3); + world.update(position, data.getBlock()); } } From ea91b716681f3e442eff012f0c1d2568520cce3a Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Mon, 13 Jul 2020 02:07:04 +0200 Subject: [PATCH 193/304] Some fixes related to redstone processing and chunk loading --- modules/Movecraft/pom.xml | 2 +- .../countercraft/movecraft/craft/ChunkManager.java | 11 +++++++---- .../movecraft/compat/v1_16_R1/IWorldHandler.java | 2 +- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/modules/Movecraft/pom.xml b/modules/Movecraft/pom.xml index d7850c911..911de6bc7 100644 --- a/modules/Movecraft/pom.xml +++ b/modules/Movecraft/pom.xml @@ -10,7 +10,7 @@ UTF-8 - 7.0.0_for_1.8.8-1.16.1_beta_28 + 7.0.0_for_1.8.8-1.16.1_beta_29 spigot-repo diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/ChunkManager.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/ChunkManager.java index c1dcdf3b2..246c10f62 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/ChunkManager.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/ChunkManager.java @@ -39,10 +39,9 @@ public static void addChunksToLoad(List list) { for (MovecraftChunk chunk : list) { if (!chunks.contains(chunk)) { chunks.add(chunk); - if (!Settings.IsLegacy) - chunk.toBukkit().addPluginChunkTicket(Movecraft.getInstance()); if (!chunk.isLoaded()) { chunk.toBukkit().load(true); + chunk.toBukkit().setForceLoaded(true); } } @@ -62,9 +61,13 @@ public void run() { private static void removeChunksToLoad(List list) { for (MovecraftChunk chunk : list) { chunks.remove(chunk); - if (!Settings.IsLegacy && chunk.toBukkit().getPluginChunkTickets().contains(Movecraft.getInstance())) - chunk.toBukkit().removePluginChunkTicket(Movecraft.getInstance()); } + Bukkit.getScheduler().callSyncMethod(Movecraft.getInstance(), () -> { + for (MovecraftChunk chunk : list) { + chunk.toBukkit().setForceLoaded(false); + } + return true; + }); } @EventHandler diff --git a/modules/v1_16_R1/src/main/java/net/countercraft/movecraft/compat/v1_16_R1/IWorldHandler.java b/modules/v1_16_R1/src/main/java/net/countercraft/movecraft/compat/v1_16_R1/IWorldHandler.java index 15699ac17..150aaea18 100644 --- a/modules/v1_16_R1/src/main/java/net/countercraft/movecraft/compat/v1_16_R1/IWorldHandler.java +++ b/modules/v1_16_R1/src/main/java/net/countercraft/movecraft/compat/v1_16_R1/IWorldHandler.java @@ -148,7 +148,7 @@ public void rotateCraft(@NotNull Craft craft, @NotNull MovecraftLocation originP } chunkSection.setType(position.getX()&15, position.getY()&15, position.getZ()&15, data); - nativeWorld.notifyAndUpdatePhysics(position, chunk, data, data, data, 3); + nativeWorld.update(position, data.getBlock()); } } From 09bf6d904bd77299958bb17b4a0fba1955b9202f Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Mon, 13 Jul 2020 02:18:40 +0200 Subject: [PATCH 194/304] updated .gitignore --- .gitignore | 3 +-- modules/Movecraft/dependency-reduced-pom.xml | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/.gitignore b/.gitignore index a72dbb256..64a97dae8 100644 --- a/.gitignore +++ b/.gitignore @@ -190,5 +190,4 @@ $RECYCLE.BIN/ # Windows shortcuts *.lnk -modules/Movecraft/dependency-reduced-pom.xml -modules/api/dependency-reduced-pom.xml \ No newline at end of file +*dependency-reduced-pom.xml \ No newline at end of file diff --git a/modules/Movecraft/dependency-reduced-pom.xml b/modules/Movecraft/dependency-reduced-pom.xml index 3c0eca9a6..4683f3f5c 100644 --- a/modules/Movecraft/dependency-reduced-pom.xml +++ b/modules/Movecraft/dependency-reduced-pom.xml @@ -4,7 +4,7 @@ net.countercraft movecraft Movecraft - 7.0.0_for_1.8.8-1.16.1_beta_28 + 7.0.0_for_1.8.8-1.16.1_beta_29 http://github.com/apdevteam/Movecraft src/main/java From ec31d1c4595f8f793ec517000f01e3a9ed54180a Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Sun, 26 Jul 2020 13:43:29 +0200 Subject: [PATCH 195/304] Removed redundant debug message --- .../movecraft/mapUpdater/update/WorldEdit7UpdateCommand.java | 5 ----- 1 file changed, 5 deletions(-) diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/WorldEdit7UpdateCommand.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/WorldEdit7UpdateCommand.java index f5871d9c0..5539992f1 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/WorldEdit7UpdateCommand.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/WorldEdit7UpdateCommand.java @@ -7,9 +7,7 @@ import com.sk89q.worldedit.bukkit.BukkitAdapter; import com.sk89q.worldedit.world.block.BaseBlock; import net.countercraft.movecraft.MovecraftLocation; -import net.countercraft.movecraft.config.Settings; import net.countercraft.movecraft.utils.Pair; -import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.Material; import org.bukkit.World; @@ -40,9 +38,6 @@ public void doUpdate() { assert baseBlock != null; BlockData bData = BukkitAdapter.adapt(baseBlock); block.setBlockData(bData, false); - if (Settings.Debug){ - Bukkit.broadcastMessage(String.format("Material: %s, Location: %s",type.name().toLowerCase().replace("_", " "),location.toString())); - } Material weType = BukkitAdapter.adapt(baseBlock.getBlockType()); if (type == Material.DISPENSER){ Tag t = baseBlock.getNbtData().getValue().get("Items"); From bec85920a29944435fc734ba2f12718c8926c153 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Wed, 29 Jul 2020 00:19:45 +0200 Subject: [PATCH 196/304] Merge https://github.com/APDevTeam/Movecraft # Conflicts: # .gitignore # modules/Movecraft/src/main/java/net/countercraft/movecraft/async/rotation/RotationTask.java # modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java # modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/StatusSign.java # modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java --- .../net/countercraft/movecraft/Movecraft.java | 19 ----------- .../countercraft/movecraft/craft/ICraft.java | 7 +--- .../update/FuelBurnUpdateCommand.java | 33 ------------------- .../movecraft/config/Settings.java | 1 - 4 files changed, 1 insertion(+), 59 deletions(-) delete mode 100644 modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/FuelBurnUpdateCommand.java diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java index dc8214f9d..8f78a19d9 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java @@ -196,25 +196,6 @@ public void onEnable() { Settings.TNTContactExplosives = getConfig().getBoolean("TNTContactExplosives", true); Settings.FadeWrecksAfter = getConfig().getInt("FadeWrecksAfter", 0); Settings.RequireSneakingForDirectControl = getConfig().getBoolean("RequireSneakingForDirectControl", false); - if (getConfig().contains("FuelTypes")){ - Map fuelTypes = getConfig().getConfigurationSection("FuelTypes").getValues(false); - int numFuelTypes = 0; - for (String fuelTypeId : fuelTypes.keySet()){ - Settings.FuelTypes.put(Material.getMaterial(fuelTypeId), (Double) fuelTypes.get(fuelTypeId)); - numFuelTypes++; - } - logger.info(numFuelTypes + " fuel types registered"); - } else { - Settings.FuelTypes.put(Material.COAL_BLOCK, 79.0); - Settings.FuelTypes.put(Material.COAL, 7.0); - if (!Settings.IsLegacy) - Settings.FuelTypes.put(Material.CHARCOAL, 7.0); - String loggerMsg = "No fuel types specified in config. Registering default fuel types "; - for (Material fuel : Settings.FuelTypes.keySet()) { - loggerMsg += fuel.name().toLowerCase() + " with burning time " + Settings.FuelTypes.get(fuel) + ", "; - } - logger.info(loggerMsg); - } Settings.FadeTickCooldown = getConfig().getInt("FadeTickCooldown", 20); Settings.FadePercentageOfWreckPerCycle = getConfig().getDouble("FadePercentageOfWreckPerCycle", 10.0); if (getConfig().contains("ExtraFadeTimePerBlock")) { diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/ICraft.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/ICraft.java index bc27da1aa..889a97029 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/ICraft.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/ICraft.java @@ -38,13 +38,8 @@ public void detect(@Nullable Player player, @NotNull Player notificationPlayer, @Override public void translate(@NotNull World world, int dx, int dy, int dz) { // check to see if the craft is trying to move in a direction not permitted by the type -<<<<<<< HEAD - if (!world.equals(this.world) && !this.getType().getCanSwitchWorld() && !this.getSinking()) { + if (!world.equals(this.world) && !(this.getType().getCanSwitchWorld() || type.getDisableTeleportToWorlds().contains(world.getName())) && !this.getSinking()) { world = this.world; -======= - if (!world.equals(w) && !(this.getType().getCanSwitchWorld() || type.getDisableTeleportToWorlds().contains(world.getName())) && !this.getSinking()) { - world = w; ->>>>>>> 48212d491a1d8680ccbe838c7bc74cd35a2a2614 } if (!this.getType().allowHorizontalMovement() && !this.getSinking()) { dx = 0; diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/FuelBurnUpdateCommand.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/FuelBurnUpdateCommand.java deleted file mode 100644 index e0813ff7c..000000000 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/FuelBurnUpdateCommand.java +++ /dev/null @@ -1,33 +0,0 @@ -package net.countercraft.movecraft.mapUpdater.update; - -import net.countercraft.movecraft.config.Settings; -import net.countercraft.movecraft.craft.Craft; -import org.bukkit.Material; -import org.bukkit.block.Block; -import org.bukkit.block.Furnace; -import org.bukkit.inventory.ItemStack; - -public class FuelBurnUpdateCommand extends UpdateCommand { - private final Block block; - private final Craft craft; - public FuelBurnUpdateCommand(Craft craft, Block furnace){ - this.block = furnace; - this.craft = craft; - } - @Override - public void doUpdate() { - Furnace furnace = (Furnace) block.getState(); - for (Material fuel : Settings.FuelTypes.keySet()){ - if (furnace.getInventory().contains(fuel)){ - ItemStack item = furnace.getInventory().getItem(furnace.getInventory().first(fuel)); - int amount = item.getAmount(); - if (amount == 1) { - furnace.getInventory().remove(item); - } else { - item.setAmount(amount - 1); - } - craft.setBurningFuel(craft.getBurningFuel() + Settings.FuelTypes.get(item.getType())); - } - } - } -} diff --git a/modules/api/src/main/java/net/countercraft/movecraft/config/Settings.java b/modules/api/src/main/java/net/countercraft/movecraft/config/Settings.java index 77a8e043e..3ec18a969 100644 --- a/modules/api/src/main/java/net/countercraft/movecraft/config/Settings.java +++ b/modules/api/src/main/java/net/countercraft/movecraft/config/Settings.java @@ -98,7 +98,6 @@ public class Settings { public static HashSet AssaultDestroyableBlocks = new HashSet<>(); public static int AssaultDamagesPerBlock; public static HashSet DisableShadowBlocks = new HashSet<>(); - public static Map FuelTypes = new HashMap<>(); public static boolean SiegeEnable; public static String SiegeTimeZone; From 424f62719e4eca88e0b08814a904c9e76605745b Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Wed, 29 Jul 2020 02:45:03 +0200 Subject: [PATCH 197/304] Improved fuel burning, and bump version --- modules/Movecraft/dependency-reduced-pom.xml | 2 +- modules/Movecraft/pom.xml | 2 +- .../movecraft/async/AsyncTask.java | 72 +++++++++---------- .../movecraft/events/FuelBurnEvent.java | 2 +- 4 files changed, 38 insertions(+), 40 deletions(-) diff --git a/modules/Movecraft/dependency-reduced-pom.xml b/modules/Movecraft/dependency-reduced-pom.xml index 4683f3f5c..4a94dd2b0 100644 --- a/modules/Movecraft/dependency-reduced-pom.xml +++ b/modules/Movecraft/dependency-reduced-pom.xml @@ -4,7 +4,7 @@ net.countercraft movecraft Movecraft - 7.0.0_for_1.8.8-1.16.1_beta_29 + 7.0.0_for_1.8.8-1.16.1_beta_30 http://github.com/apdevteam/Movecraft src/main/java diff --git a/modules/Movecraft/pom.xml b/modules/Movecraft/pom.xml index 911de6bc7..ac7d58f8e 100644 --- a/modules/Movecraft/pom.xml +++ b/modules/Movecraft/pom.xml @@ -10,7 +10,7 @@ UTF-8 - 7.0.0_for_1.8.8-1.16.1_beta_29 + 7.0.0_for_1.8.8-1.16.1_beta_30 spigot-repo diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncTask.java index dfe69f19d..c0c320ae6 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncTask.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncTask.java @@ -25,6 +25,7 @@ import org.bukkit.Bukkit; import org.bukkit.Material; import org.bukkit.block.Block; +import org.bukkit.inventory.Inventory; import org.bukkit.inventory.InventoryHolder; import org.bukkit.inventory.ItemStack; import org.bukkit.scheduler.BukkitRunnable; @@ -61,71 +62,68 @@ protected boolean checkFuel() throws ExecutionException, InterruptedException { if (fuelBurnRate == 0.0 || craft.getSinking()) { return true; } - if (craft.getBurningFuel() >= fuelBurnRate) { - double burningFuel = craft.getBurningFuel(); - //call event - final FuelBurnEvent event = new FuelBurnEvent(craft, burningFuel, fuelBurnRate); - Bukkit.getPluginManager().callEvent(event); - if (event.getBurningFuel() != burningFuel) - burningFuel = event.getBurningFuel(); - if (event.getFuelBurnRate() != fuelBurnRate) - fuelBurnRate = event.getFuelBurnRate(); - craft.setBurningFuel(burningFuel - fuelBurnRate); - return true; - } - Block fuelHolder = null; - for (MovecraftLocation bTest : craft.getHitBox()) { - Block b = craft.getW().getBlockAt(bTest.getX(), bTest.getY(), bTest.getZ()); - if (b.getType() == Material.FURNACE) { + if (craft.getBurningFuel() >= fuelBurnRate) { + double burningFuel = craft.getBurningFuel(); + //call event + final FuelBurnEvent event = new FuelBurnEvent(craft, burningFuel, fuelBurnRate); + Bukkit.getPluginManager().callEvent(event); + if (event.getBurningFuel() != burningFuel) + burningFuel = event.getBurningFuel(); + if (event.getFuelBurnRate() != fuelBurnRate) + fuelBurnRate = event.getFuelBurnRate(); + craft.setBurningFuel(burningFuel - fuelBurnRate); + return true; + } + InventoryHolder fuelHolder = null; + for (MovecraftLocation bTest : craft.getHitBox()) { + Block b = craft.getWorld().getBlockAt(bTest.getX(), bTest.getY(), bTest.getZ()); + if (b.getType() != Material.FURNACE) { + continue; + } fuelHolder = Bukkit.getScheduler().callSyncMethod(Movecraft.getInstance(), () -> { InventoryHolder inventoryHolder = (InventoryHolder) b.getState(); for (ItemStack stack : inventoryHolder.getInventory()) { if (stack == null || !craft.getType().getFuelTypes().containsKey(stack.getType())) continue; - return b; + return inventoryHolder; } return null; }).get(); } - } - if (fuelHolder == null) { - return false; - } - final Block finalFuelHolder = fuelHolder; - final double finalFuelBurnRate = fuelBurnRate; - Bukkit.getScheduler().callSyncMethod(Movecraft.getInstance(), () -> { - double processingFuelBurnRate = finalFuelBurnRate; - InventoryHolder inventoryHolder = (InventoryHolder) finalFuelHolder.getState(); - for (ItemStack iStack : inventoryHolder.getInventory()) { + if (fuelHolder == null) { + return false; + } + final Inventory inv = fuelHolder.getInventory(); + for (ItemStack iStack : inv) { if (iStack == null) continue; if (!craft.getType().getFuelTypes().containsKey(iStack.getType())) continue; double burningFuel = craft.getType().getFuelTypes().get(iStack.getType()); //call event - final FuelBurnEvent event = new FuelBurnEvent(craft, burningFuel, processingFuelBurnRate); + final FuelBurnEvent event = new FuelBurnEvent(craft, burningFuel, fuelBurnRate); Bukkit.getPluginManager().callEvent(event); if (event.getBurningFuel() != burningFuel) burningFuel = event.getBurningFuel(); - if (event.getFuelBurnRate() != processingFuelBurnRate) - processingFuelBurnRate = event.getFuelBurnRate(); + if (event.getFuelBurnRate() != fuelBurnRate) + fuelBurnRate = event.getFuelBurnRate(); if (burningFuel == 0.0) { continue; } int amount = iStack.getAmount(); int minAmount = 1; - if (burningFuel < processingFuelBurnRate) { - minAmount = (int) processingFuelBurnRate; + if (burningFuel < fuelBurnRate) { + minAmount = (int) fuelBurnRate; } if (iStack.getType() == Material.LAVA_BUCKET || iStack.getType() == Material.WATER_BUCKET || iStack.getType() == Material.MILK_BUCKET) { //If water, lava or milk buckets are accepted as fuel, replace with an empty bucket iStack.setType(Material.BUCKET); } else if (amount == minAmount) { - inventoryHolder.getInventory().remove(iStack); + inv.remove(iStack); } else if (amount < minAmount) { - inventoryHolder.getInventory().remove(iStack); - final ItemStack secStack = inventoryHolder.getInventory().getItem(inventoryHolder.getInventory().first(iStack.getType())); + inv.remove(iStack); + final ItemStack secStack = inv.getItem(inv.first(iStack.getType())); secStack.setAmount(secStack.getAmount() - (minAmount - amount)); } else { iStack.setAmount(amount - minAmount); @@ -134,8 +132,8 @@ protected boolean checkFuel() throws ExecutionException, InterruptedException { break; } return true; - }); - return true; + + } } diff --git a/modules/api/src/main/java/net/countercraft/movecraft/events/FuelBurnEvent.java b/modules/api/src/main/java/net/countercraft/movecraft/events/FuelBurnEvent.java index 77e253a6c..7c2d18a67 100644 --- a/modules/api/src/main/java/net/countercraft/movecraft/events/FuelBurnEvent.java +++ b/modules/api/src/main/java/net/countercraft/movecraft/events/FuelBurnEvent.java @@ -8,7 +8,7 @@ public class FuelBurnEvent extends CraftEvent{ private static final HandlerList HANDLERS = new HandlerList(); private double burningFuel, fuelBurnRate; public FuelBurnEvent(@NotNull Craft craft, double burningFuel, double fuelBurnRate) { - super(craft); + super(craft, true); this.burningFuel = burningFuel; this.fuelBurnRate = fuelBurnRate; } From a8047e6e40ab3830c9dc94e7217963d2d6c80a97 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Wed, 29 Jul 2020 11:43:17 +0200 Subject: [PATCH 198/304] Updated legacy config_legacy.yml --- modules/Movecraft/src/main/resources/config_legacy.yml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/modules/Movecraft/src/main/resources/config_legacy.yml b/modules/Movecraft/src/main/resources/config_legacy.yml index 2210a7f37..af42238cf 100644 --- a/modules/Movecraft/src/main/resources/config_legacy.yml +++ b/modules/Movecraft/src/main/resources/config_legacy.yml @@ -17,6 +17,14 @@ RequireNamePerm: false TNTContactExplosives: true DisableCrates: true FadeWrecksAfter: 600 +FadeTickCooldown: 20 #Number of ticks between each fading cycle +FadePercentageOfWreckPerCycle: 10.0 #Percentage of wreck to be faded in each fading cycle +ExtraFadeTimePerBlock: #List of blocks that will take longer time to fade + CHEST: 600 + TRAPPED_CHEST: 600 + DISPENSER: 600 + DROPPER: 600 + FURNACE: 600 BlockQueueChunkSize: 200000 RepairTicksPerBlock: 10 RepairMoneyPerBlock: 10 From f021d08f6a7dd345ca07f13b2b2b6c617baba19c Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Fri, 14 Aug 2020 20:44:20 +0200 Subject: [PATCH 199/304] Added 1.16.2 compatibility --- modules/v1_16_R2/pom.xml | 31 ++ .../compat/v1_16_R2/IWorldHandler.java | 442 ++++++++++++++++++ .../compat/v1_16_R2/NextTickProvider.java | 68 +++ pom.xml | 2 +- 4 files changed, 542 insertions(+), 1 deletion(-) create mode 100644 modules/v1_16_R2/pom.xml create mode 100644 modules/v1_16_R2/src/main/java/net/countercraft/movecraft/compat/v1_16_R2/IWorldHandler.java create mode 100644 modules/v1_16_R2/src/main/java/net/countercraft/movecraft/compat/v1_16_R2/NextTickProvider.java diff --git a/modules/v1_16_R2/pom.xml b/modules/v1_16_R2/pom.xml new file mode 100644 index 000000000..f40287282 --- /dev/null +++ b/modules/v1_16_R2/pom.xml @@ -0,0 +1,31 @@ + + + + movecraft-parent + net.countercraft + parent + ../../pom.xml + + 4.0.0 + + movecraft-v1_16_R2 + Movecraft-v1_16_R2 + v1_16_R2 + jar + + + org.bukkit + craftbukkit + 1.16.2-R0.1-SNAPSHOT + + + net.countercraft + movecraft-api + API + jar + + + + \ No newline at end of file diff --git a/modules/v1_16_R2/src/main/java/net/countercraft/movecraft/compat/v1_16_R2/IWorldHandler.java b/modules/v1_16_R2/src/main/java/net/countercraft/movecraft/compat/v1_16_R2/IWorldHandler.java new file mode 100644 index 000000000..74746dc9f --- /dev/null +++ b/modules/v1_16_R2/src/main/java/net/countercraft/movecraft/compat/v1_16_R2/IWorldHandler.java @@ -0,0 +1,442 @@ +package net.countercraft.movecraft.compat.v1_16_R2; + +import net.countercraft.movecraft.MovecraftLocation; +import net.countercraft.movecraft.Rotation; +import net.countercraft.movecraft.WorldHandler; +import net.countercraft.movecraft.config.Settings; +import net.countercraft.movecraft.craft.Craft; +import net.countercraft.movecraft.utils.CollectionUtils; +import net.countercraft.movecraft.utils.MathUtils; +import net.minecraft.server.v1_16_R2.*; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.block.data.BlockData; +import org.bukkit.craftbukkit.v1_16_R2.CraftWorld; +import org.bukkit.craftbukkit.v1_16_R2.block.data.CraftBlockData; +import org.bukkit.craftbukkit.v1_16_R2.util.CraftMagicNumbers; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.*; + +public class IWorldHandler extends WorldHandler { + private static final EnumBlockRotation ROTATION[]; + static { + ROTATION = new EnumBlockRotation[3]; + ROTATION[Rotation.NONE.ordinal()] = EnumBlockRotation.NONE; + ROTATION[Rotation.CLOCKWISE.ordinal()] = EnumBlockRotation.CLOCKWISE_90; + ROTATION[Rotation.ANTICLOCKWISE.ordinal()] = EnumBlockRotation.COUNTERCLOCKWISE_90; + + } + private final NextTickProvider tickProvider = new NextTickProvider(); + private final HashMap> bMap = new HashMap<>(); + private MethodHandle internalTeleportMH; + + public IWorldHandler() { + MethodHandles.Lookup lookup = MethodHandles.lookup(); + Method teleport = null; + try { + teleport = PlayerConnection.class.getDeclaredMethod("internalTeleport", double.class, double.class, double.class, float.class, float.class, Set.class); + teleport.setAccessible(true); + internalTeleportMH = lookup.unreflect(teleport); + + } catch (NoSuchMethodException | IllegalAccessException e) { + e.printStackTrace(); + } + } + + @Override + public void rotateCraft(@NotNull Craft craft, @NotNull MovecraftLocation originPoint, @NotNull Rotation rotation) { + //******************************************* + //* Step one: Convert to Positions * + //******************************************* + HashMap rotatedPositions = new HashMap<>(); + Rotation counterRotation = rotation == Rotation.CLOCKWISE ? Rotation.ANTICLOCKWISE : Rotation.CLOCKWISE; + for(MovecraftLocation newLocation : craft.getHitBox()){ + rotatedPositions.put(locationToPosition(MathUtils.rotateVec(counterRotation, newLocation.subtract(originPoint)).add(originPoint)),locationToPosition(newLocation)); + } + //******************************************* + //* Step two: Get the tiles * + //******************************************* + WorldServer nativeWorld = ((CraftWorld) craft.getWorld()).getHandle(); + List tiles = new ArrayList<>(); + //get the tiles + for(BlockPosition position : rotatedPositions.keySet()){ + //TileEntity tile = nativeWorld.removeTileEntity(position); + TileEntity tile = removeTileEntity(nativeWorld,position); + if(tile == null) + continue; + tile.a(ROTATION[rotation.ordinal()]); + //get the nextTick to move with the tile + tiles.add(new TileHolder(tile, tickProvider.getNextTick(nativeWorld, position), position)); + } + + //******************************************* + //* Step three: Translate all the blocks * + //******************************************* + // blockedByWater=false means an ocean-going vessel + //TODO: Simplify + //TODO: go by chunks + //TODO: Don't move unnecessary blocks + //get the blocks and rotate them + HashMap blockData = new HashMap<>(); + for(BlockPosition position : rotatedPositions.keySet()){ + + blockData.put(position,nativeWorld.getType(position).a(ROTATION[rotation.ordinal()])); + } + HashMap redstoneComponents = new HashMap<>(); + //create the new block + for(Map.Entry entry : blockData.entrySet()) { + final BlockPosition newPosition = rotatedPositions.get(entry.getKey()); + final IBlockData iBlockData = entry.getValue(); + if (nativeWorld.getTileEntity(newPosition) != null) { + removeTileEntity(nativeWorld, newPosition); + } + if (isRedstoneComponent(iBlockData)) + redstoneComponents.put(newPosition, iBlockData); + + setBlockFast(nativeWorld, newPosition, iBlockData); + } + + + //******************************************* + //* Step four: replace all the tiles * + //******************************************* + //TODO: go by chunks + for(TileHolder tileHolder : tiles){ + moveTileEntity(nativeWorld, rotatedPositions.get(tileHolder.getTilePosition()),tileHolder.getTile()); + if(tileHolder.getNextTick()==null) + continue; + final long currentTime = nativeWorld.worldData.getTime(); + nativeWorld.getBlockTickList().a(rotatedPositions.get(tileHolder.getNextTick().a), tileHolder.getNextTick().b(), (int) (tileHolder.getNextTick().b - currentTime), tileHolder.getNextTick().c); + } + + //******************************************* + //* Step five: Destroy the leftovers * + //******************************************* + //TODO: add support for pass-through + Collection deletePositions = CollectionUtils.filter(rotatedPositions.keySet(),rotatedPositions.values()); + for(BlockPosition position : deletePositions){ + setBlockFast(nativeWorld, position, Blocks.AIR.getBlockData()); + } + + //******************************************* + //* Step six: Process fire spread * + //******************************************* + for (BlockPosition position : rotatedPositions.values()) { + IBlockData type = nativeWorld.getType(position); + if (!(type.getBlock() instanceof BlockFire)) { + continue; + } + BlockFire fire = (BlockFire) type.getBlock(); + fire.tick(type, nativeWorld, position, nativeWorld.random); + } + + for (Map.Entry entry : redstoneComponents.entrySet()) { + final BlockPosition position = entry.getKey(); + final IBlockData data = entry.getValue(); + Chunk chunk = nativeWorld.getChunkAtWorldCoords(position); + ChunkSection chunkSection = chunk.getSections()[position.getY()>>4]; + if (chunkSection == null) { + // Put a GLASS block to initialize the section. It will be replaced next with the real block. + chunk.setType(position, Blocks.GLASS.getBlockData(), true); + chunkSection = chunk.getSections()[position.getY() >> 4]; + + } + chunkSection.setType(position.getX()&15, position.getY()&15, position.getZ()&15, data); + nativeWorld.update(position, data.getBlock()); + } + } + + @Override + public void translateCraft(@NotNull Craft craft, @NotNull MovecraftLocation displacement, @NotNull org.bukkit.World world) { + //TODO: Add supourt for rotations + //A craftTranslateCommand should only occur if the craft is moving to a valid position + //******************************************* + //* Step one: Convert to Positions * + //******************************************* + BlockPosition translateVector = locationToPosition(displacement); + List positions = new ArrayList<>(); + for(MovecraftLocation movecraftLocation : craft.getHitBox()) { + positions.add(locationToPosition((movecraftLocation)).b(translateVector)); + + } + WorldServer oldNativeWorld = ((CraftWorld) craft.getWorld()).getHandle(); + WorldServer nativeWorld = ((CraftWorld) world).getHandle(); + //******************************************* + //* Step two: Get the tiles * + //******************************************* + List tiles = getTiles(positions, oldNativeWorld); + //******************************************* + //* Step three: Translate all the blocks * + //******************************************* + // blockedByWater=false means an ocean-going vessel + //TODO: Simplify + //TODO: go by chunks + //TODO: Don't move unnecessary blocks + //get the blocks and translate the positions + List blockData = new ArrayList<>(); + List newPositions = new ArrayList<>(); + for(BlockPosition position : positions){ + blockData.add(oldNativeWorld.getType(position)); + newPositions.add(position.a(translateVector)); + } + //create the new block + setBlocks(newPositions, blockData, nativeWorld); + //******************************************* + //* Step four: replace all the tiles * + //******************************************* + //TODO: go by chunks + processTiles(tiles, nativeWorld, translateVector); + //******************************************* + //* Step five: Destroy the leftovers * + //******************************************* + Collection deletePositions = oldNativeWorld == nativeWorld ? CollectionUtils.filter(positions,newPositions) : positions; + setAir(deletePositions, oldNativeWorld); + //******************************************* + //* Step six: Process fire spread * + //******************************************* + processFireSpread(newPositions, nativeWorld); + //******************************************* + //* Step six: Process redstone * + //******************************************* + processRedstone(newPositions, nativeWorld); + } + + + private void setBlocks(List newPositions, List blockData, WorldServer nativeWorld){ + Map redstoneComponents = new HashMap<>(); + for(int i = 0; i getTiles(Iterable positions, WorldServer nativeWorld){ + List tiles = new ArrayList<>(); + //get the tiles + for(BlockPosition position : positions){ + if(nativeWorld.getType(position) == Blocks.AIR.getBlockData()) + continue; + //TileEntity tile = nativeWorld.removeTileEntity(position); + TileEntity tile = removeTileEntity(nativeWorld,position); + if(tile == null) + continue; + //get the nextTick to move with the tile + + //nativeWorld.capturedTileEntities.remove(position); + //nativeWorld.getChunkAtWorldCoords(position).getTileEntities().remove(position); + tiles.add(new TileHolder(tile, tickProvider.getNextTick(nativeWorld, position), position)); + + } + return tiles; + } + + private void processTiles(Iterable tiles, WorldServer world, BlockPosition translateVector){ + for(TileHolder tileHolder : tiles){ + moveTileEntity(world, tileHolder.getTilePosition().a(translateVector),tileHolder.getTile()); + if(tileHolder.getNextTick()==null) + continue; + final long currentTime = world.worldData.getTime(); + world.getBlockTickList().a(tileHolder.getNextTick().a.a(translateVector), tileHolder.getNextTick().b(), (int) (tileHolder.getNextTick().b - currentTime), tileHolder.getNextTick().c); + } + } + + private void processFireSpread(Iterable positions, WorldServer world){ + for (BlockPosition position : positions) { + IBlockData type = world.getType(position); + if (!(type.getBlock() instanceof BlockFire)) { + continue; + } + BlockFire fire = (BlockFire) type.getBlock(); + fire.tick(type, world, position, world.random); + } + } + + private void processRedstone(List redstone, WorldServer world) { + Map redstoneComponents = new HashMap<>(); + for (int i = 0 ; i < redstone.size(); i++) { + BlockPosition pos = redstone.get(i); + IBlockData data = world.getType(pos); + if (isRedstoneComponent(data)) + redstoneComponents.put(pos, data); + } + for (Map.Entry entry : redstoneComponents.entrySet()) { + final BlockPosition position = entry.getKey(); + final IBlockData data = entry.getValue(); + Chunk chunk = world.getChunkAtWorldCoords(position); + ChunkSection chunkSection = chunk.getSections()[position.getY()>>4]; + if (chunkSection == null) { + // Put a GLASS block to initialize the section. It will be replaced next with the real block. + chunk.setType(position, Blocks.GLASS.getBlockData(), true); + chunkSection = chunk.getSections()[position.getY() >> 4]; + + } + chunkSection.setType(position.getX()&15, position.getY()&15, position.getZ()&15, data); + //world.notifyAndUpdatePhysics(position, chunk, data, data, data, 3); + world.update(position, data.getBlock()); + } + } + + private void setAir(Iterable positions, WorldServer world){ + for(BlockPosition position : positions){ + setBlockFast(world, position, Blocks.AIR.getBlockData()); + } + } + + @Nullable + private TileEntity removeTileEntity(@NotNull WorldServer world, @NotNull BlockPosition position){ + TileEntity tile = world.getTileEntity(position); + if(tile == null) + return null; + //cleanup + world.capturedTileEntities.remove(position); + world.getChunkAtWorldCoords(position).getTileEntities().remove(position); + if(!Settings.IsPaper) + world.tileEntityList.remove(tile); + world.tileEntityListTick.remove(tile); + if(!bMap.containsKey(world)){ + try { + Field bField = World.class.getDeclaredField("tileEntityListPending"); + bField.setAccessible(true); + bMap.put(world, (List) bField.get(world));//TODO bug fix + } catch (IllegalAccessException | IllegalArgumentException | NoSuchFieldException | SecurityException e1) { + e1.printStackTrace(); + } + } + bMap.get(world).remove(tile); + return tile; + } + + @NotNull + private BlockPosition locationToPosition(@NotNull MovecraftLocation loc) { + return new BlockPosition(loc.getX(), loc.getY(), loc.getZ()); + } + + private void setBlockFast(@NotNull WorldServer world, @NotNull BlockPosition position,@NotNull IBlockData data) { + Chunk chunk = world.getChunkAtWorldCoords(position); + ChunkSection chunkSection = chunk.getSections()[position.getY()>>4]; + if (chunkSection == null) { + // Put a GLASS block to initialize the section. It will be replaced next with the real block. + chunk.setType(position, Blocks.GLASS.getBlockData(), true); + chunkSection = chunk.getSections()[position.getY() >> 4]; + + } + chunkSection.setType(position.getX() & 15, position.getY() & 15, position.getZ() & 15, data); + world.notify(position, data, data, 3); + world.getChunkProvider().getLightEngine().a(position); + chunk.markDirty(); + } + + @Override + public void setBlockFast(@NotNull Location location, @NotNull Material material, Object data){ + setBlockFast(location, Rotation.NONE, material, data); + } + + @Override + public void setBlockFast(@NotNull Location location, @NotNull Rotation rotation, @NotNull Material material, Object data) { + IBlockData blockData; + if (!(data instanceof BlockData)) { + blockData = CraftMagicNumbers.getBlock(material).getBlockData(); + } else { + blockData = ((CraftBlockData) data).getState(); + } + + blockData = blockData.a(ROTATION[rotation.ordinal()]); + WorldServer world = ((CraftWorld)(location.getWorld())).getHandle(); + BlockPosition blockPosition = locationToPosition(bukkit2MovecraftLoc(location)); + if (world.getTileEntity(blockPosition) != null) { + removeTileEntity(world, blockPosition); + } + setBlockFast(world,blockPosition,blockData); + } + + @Override + public void disableShadow(@NotNull Material type) { + Method method; + //try { + Block tempBlock = CraftMagicNumbers.getBlock(type); + //method = Block.class.getDeclaredMethod("d", int.class); + //method.setAccessible(true); + //method.invoke(tempBlock, 0); + //} catch (NoSuchMethodException | InvocationTargetException | IllegalArgumentException | IllegalAccessException | SecurityException e1) { + // TODO Auto-generated catch block + // e1.printStackTrace(); + //} + } + + private static MovecraftLocation bukkit2MovecraftLoc(Location l) { + return new MovecraftLocation(l.getBlockX(), l.getBlockY(), l.getBlockZ()); + } + + private void recalculateLighting(WorldServer world, Collection positions) { + final LightEngineThreaded engine = world.getChunkProvider().getLightEngine(); + for (BlockPosition pos : positions) { + engine.a(pos); + } + } + + private void moveTileEntity(@NotNull WorldServer nativeWorld, @NotNull BlockPosition newPosition, @NotNull TileEntity tile){ + Chunk chunk = nativeWorld.getChunkAtWorldCoords(newPosition); + tile.invalidateBlockCache(); + if(nativeWorld.captureBlockStates) { + tile.setLocation(nativeWorld, newPosition); + nativeWorld.capturedTileEntities.put(newPosition, tile); + return; + } + tile.setLocation(nativeWorld, newPosition); + chunk.tileEntities.put(newPosition, tile); + } + + private class TileHolder{ + @NotNull private final TileEntity tile; + @Nullable + private final NextTickListEntry nextTick; + @NotNull private final BlockPosition tilePosition; + + public TileHolder(@NotNull TileEntity tile, @Nullable NextTickListEntry nextTick, @NotNull BlockPosition tilePosition){ + this.tile = tile; + this.nextTick = nextTick; + this.tilePosition = tilePosition; + } + + + @NotNull + public TileEntity getTile() { + return tile; + } + + @Nullable + public NextTickListEntry getNextTick() { + return nextTick; + } + + @NotNull + public BlockPosition getTilePosition() { + return tilePosition; + } + } + + private boolean isRedstoneComponent(IBlockData blockData) { + final Block block = blockData.getBlock(); + return block instanceof BlockRedstoneWire || + block instanceof BlockDiodeAbstract || + block instanceof BlockButtonAbstract || + block instanceof BlockLever; + + } + + private boolean isPowered (IBlockData data) { + if (data.getBlock() instanceof BlockRedstoneWire) { + return data.get(BlockRedstoneWire.POWER) > 0; + } else if (data.getBlock() instanceof BlockDiodeAbstract) { + return data.get(BlockDiodeAbstract.c); + } else if (data.getBlock() instanceof BlockButtonAbstract || data.getBlock() instanceof BlockLever) { + return data.get(BlockButtonAbstract.POWERED); + } + return false; + } +} diff --git a/modules/v1_16_R2/src/main/java/net/countercraft/movecraft/compat/v1_16_R2/NextTickProvider.java b/modules/v1_16_R2/src/main/java/net/countercraft/movecraft/compat/v1_16_R2/NextTickProvider.java new file mode 100644 index 000000000..8d4927744 --- /dev/null +++ b/modules/v1_16_R2/src/main/java/net/countercraft/movecraft/compat/v1_16_R2/NextTickProvider.java @@ -0,0 +1,68 @@ +package net.countercraft.movecraft.compat.v1_16_R2; + +import net.minecraft.server.v1_16_R2.*; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.lang.reflect.Field; +import java.util.*; + +public class NextTickProvider { + private Map,Collection>> tickMap = new HashMap<>(); + + private boolean isRegistered(@NotNull WorldServer world){ + return tickMap.containsKey(world); + } + + @SuppressWarnings("unchecked") + private void registerWorld(@NotNull WorldServer world){ + final Collection W = new ArrayList<>(); + final Set nextTickList = new HashSet<>(); + TickListServer blockTickListServer = world.getBlockTickList(); + try { + Field gField = TickListServer.class.getDeclaredField("g"); + gField.setAccessible(true); + W.addAll((Collection) gField.get(blockTickListServer)); + Field ntlField = TickListServer.class.getDeclaredField("nextTickList"); + ntlField.setAccessible(true); + nextTickList.addAll((Set) ntlField.get(blockTickListServer)); + } catch (IllegalAccessException | IllegalArgumentException | NoSuchFieldException | SecurityException e1) { + e1.printStackTrace(); + } + tickMap.put(world, new AbstractMap.SimpleImmutableEntry<>(nextTickList,W)); + } + + @Nullable + public NextTickListEntry getNextTick(@NotNull WorldServer world, @NotNull BlockPosition position) { + if (!isRegistered(world)) + registerWorld(world); + AbstractMap.SimpleImmutableEntry, Collection> listPair = tickMap.get(world); + if(listPair.getKey().contains(fakeEntry(position))) { + for (Iterator iterator = listPair.getKey().iterator(); iterator.hasNext(); ) { + NextTickListEntry listEntry = iterator.next(); + if (position.equals(listEntry.a)) { + iterator.remove(); + return listEntry; + } + } + } + for(Iterator iterator = listPair.getValue().iterator(); iterator.hasNext();) { + NextTickListEntry listEntry = iterator.next(); + if (position.equals(listEntry.a)) { + iterator.remove(); + return listEntry; + } + } + return null; + + } + @NotNull + public Object fakeEntry(@NotNull BlockPosition position){ + return new Object(){ + @Override + public int hashCode() { + return position.hashCode(); + } + }; + } +} diff --git a/pom.xml b/pom.xml index edc6f10ee..fe3e4b912 100644 --- a/pom.xml +++ b/pom.xml @@ -32,7 +32,7 @@ modules/worldedit/WE6Utils modules/worldedit/WE7Utils modules/Movecraft - + modules/v1_16_R2 From 05bcace4b6f29f31998a188dda4a7484c8305324 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Sat, 15 Aug 2020 01:56:53 +0200 Subject: [PATCH 200/304] Fixed lowercase support for passthroughBlocks, harvestBlocks and harvesterBladeBlocks --- modules/Movecraft/dependency-reduced-pom.xml | 8 +++++- modules/Movecraft/pom.xml | 14 +++++++++- .../movecraft/async/AsyncTask.java | 20 ++++++------- .../movecraft/craft/CraftType.java | 12 ++++---- modules/v1_16_R2/pom.xml | 28 ++++++++++++++++++- pom.xml | 2 +- 6 files changed, 64 insertions(+), 20 deletions(-) diff --git a/modules/Movecraft/dependency-reduced-pom.xml b/modules/Movecraft/dependency-reduced-pom.xml index 4a94dd2b0..00bac7766 100644 --- a/modules/Movecraft/dependency-reduced-pom.xml +++ b/modules/Movecraft/dependency-reduced-pom.xml @@ -4,7 +4,7 @@ net.countercraft movecraft Movecraft - 7.0.0_for_1.8.8-1.16.1_beta_30 + 7.0.0_for_1.8.8-1.16.1_beta_31 http://github.com/apdevteam/Movecraft src/main/java @@ -140,6 +140,12 @@ ** + + net.countercraft:movecraft-v1_16_R2 + + ** + + diff --git a/modules/Movecraft/pom.xml b/modules/Movecraft/pom.xml index ac7d58f8e..69254d178 100644 --- a/modules/Movecraft/pom.xml +++ b/modules/Movecraft/pom.xml @@ -10,7 +10,7 @@ UTF-8 - 7.0.0_for_1.8.8-1.16.1_beta_30 + 7.0.0_for_1.8.8-1.16.1_beta_31 spigot-repo @@ -35,6 +35,12 @@ + + net.countercraft + movecraft-v1_16_R2 + v1_16_R2 + jar + net.countercraft movecraft-v1_16_R1 @@ -348,6 +354,12 @@ ** + + net.countercraft:movecraft-v1_16_R2 + + ** + + diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncTask.java index c0c320ae6..b1ea68466 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncTask.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncTask.java @@ -74,23 +74,23 @@ protected boolean checkFuel() throws ExecutionException, InterruptedException { craft.setBurningFuel(burningFuel - fuelBurnRate); return true; } - InventoryHolder fuelHolder = null; - for (MovecraftLocation bTest : craft.getHitBox()) { - Block b = craft.getWorld().getBlockAt(bTest.getX(), bTest.getY(), bTest.getZ()); - if (b.getType() != Material.FURNACE) { - continue; - } - fuelHolder = Bukkit.getScheduler().callSyncMethod(Movecraft.getInstance(), () -> { + InventoryHolder fuelHolder = Bukkit.getScheduler().callSyncMethod(Movecraft.getInstance(), () -> { + for (MovecraftLocation bTest : craft.getHitBox()) { + Block b = craft.getWorld().getBlockAt(bTest.getX(), bTest.getY(), bTest.getZ()); + if (b.getType() != Material.FURNACE) { + continue; + } InventoryHolder inventoryHolder = (InventoryHolder) b.getState(); for (ItemStack stack : inventoryHolder.getInventory()) { if (stack == null || !craft.getType().getFuelTypes().containsKey(stack.getType())) continue; return inventoryHolder; } - return null; - }).get(); + } + return null; + }).get(); + - } if (fuelHolder == null) { return false; } diff --git a/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java b/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java index 78f55e4eb..d9919e1e6 100644 --- a/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java +++ b/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java @@ -259,7 +259,7 @@ public CraftType(File f) { ArrayList objList = (ArrayList) data.get("harvestBlocks"); for (Object i : objList) { if (i instanceof String) { - Material mat = Material.getMaterial((String) i); + Material mat = Material.getMaterial(((String) i).toUpperCase()); harvestBlocks.add(mat); } else { Material mat = Material.getMaterial((Integer) i); @@ -272,7 +272,7 @@ public CraftType(File f) { ArrayList objList = (ArrayList) data.get("harvesterBladeBlocks"); for (Object i : objList) { if (i instanceof String) { - Material mat = Material.getMaterial((String) i); + Material mat = Material.getMaterial(((String) i).toUpperCase()); harvesterBladeBlocks.add(mat); } else { Integer typeID = (Integer) i; @@ -286,7 +286,7 @@ public CraftType(File f) { ArrayList objList = (ArrayList) data.get("passthroughBlocks"); for (Object i : objList) { if (i instanceof String) { - Material mat = Material.getMaterial((String) i); + Material mat = Material.getMaterial(((String) i).toUpperCase()); passthroughBlocks.add(mat); } else { Material mat = Material.getMaterial((Integer) i); @@ -332,7 +332,7 @@ public CraftType(File f) { if (d instanceof Integer) { type = Material.getMaterial((int) d); } else { - type = Material.getMaterial((String) d); + type = Material.getMaterial(((String) d).toUpperCase()); } dynamicFlyBlocks.add(type); } @@ -341,7 +341,7 @@ public CraftType(File f) { if (d instanceof Integer) { dynamicFlyBlocks.add(Material.getMaterial((int) d)); } else if (d instanceof String){ - dynamicFlyBlocks.add(Material.getMaterial((String) d)); + dynamicFlyBlocks.add(Material.getMaterial(((String) d).toUpperCase())); } else if (d instanceof List) { List l = (List) d; for (Object i : l) { @@ -349,7 +349,7 @@ public CraftType(File f) { if (i instanceof Integer) { type = Material.getMaterial((int) d); } else { - type = Material.getMaterial((String) d); + type = Material.getMaterial(((String) d).toUpperCase()); } dynamicFlyBlocks.add(type); } diff --git a/modules/v1_16_R2/pom.xml b/modules/v1_16_R2/pom.xml index f40287282..112f37ee7 100644 --- a/modules/v1_16_R2/pom.xml +++ b/modules/v1_16_R2/pom.xml @@ -27,5 +27,31 @@ jar - + + src/main/java + + + org.apache.maven.plugins + maven-compiler-plugin + 3.7.0 + + + net/countercraft/movecraft/compat/v1_16_R2/** + + 1.8 + 1.8 + + + + org.apache.maven.plugins + maven-jar-plugin + 2.4 + + + net/countercraft/movecraft/compat/v1_16_R2/** + + + + + \ No newline at end of file diff --git a/pom.xml b/pom.xml index fe3e4b912..2686971ec 100644 --- a/pom.xml +++ b/pom.xml @@ -29,10 +29,10 @@ modules/v1_14_R1 modules/v1_15_R1 modules/v1_16_R1 + modules/v1_16_R2 modules/worldedit/WE6Utils modules/worldedit/WE7Utils modules/Movecraft - modules/v1_16_R2 From 315b766d6e3edf8ebe395067afecd2b6aa72b700 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Thu, 27 Aug 2020 22:53:22 +0200 Subject: [PATCH 201/304] fixes #63 --- .../main/java/net/countercraft/movecraft/sign/CrewSign.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CrewSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CrewSign.java index 974a093df..35325ec1b 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CrewSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CrewSign.java @@ -54,7 +54,7 @@ public final void onSignTranslate(SignTranslateEvent event) { for(MovecraftLocation location : event.getLocations()){ Location bedLoc = location.toBukkit(craft.getWorld()).subtract(0,1,0); Material bedType = craft.getWorld().getBlockAt(bedLoc).getType(); - if (Settings.IsLegacy ? bedType.equals(LegacyUtils.BED_BLOCK) : Arrays.binarySearch(beds, bedType) >= 0) { + if (Settings.IsLegacy ? bedType.equals(LegacyUtils.BED_BLOCK) : bedType.name().endsWith("_BED")) { valid = bedLoc; break; } @@ -115,7 +115,7 @@ public final void onPlayerRespawn(PlayerRespawnEvent event) { player.sendMessage(I18nSupport.getInternationalisedString("CrewSign - Respawn")); Location respawnLoc = craft.getCrewSigns().get(player.getUniqueId()); Material test = respawnLoc.getBlock().getType(); - final boolean hasBed = Settings.IsLegacy ? test == LegacyUtils.BED_BLOCK : test.name().endsWith("BED"); + final boolean hasBed = Settings.IsLegacy ? test == LegacyUtils.BED_BLOCK : test.name().endsWith("_BED"); if (Settings.Debug){ Bukkit.broadcastMessage("Has bed: " + hasBed + ". Found type at " + respawnLoc.toVector() + ": " + test.name()); } From 86b34ca86798e4c40988e32a7ff7075a4ef5d02b Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Thu, 27 Aug 2020 23:04:20 +0200 Subject: [PATCH 202/304] fixes #70 --- .../net/countercraft/movecraft/async/AsyncManager.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java index 24e79319d..b7c184369 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java @@ -19,8 +19,10 @@ import at.pavlov.cannons.cannon.Cannon; import com.google.common.collect.Lists; +import net.countercraft.movecraft.Movecraft; +import net.countercraft.movecraft.MovecraftBlock; +import net.countercraft.movecraft.MovecraftLocation; import net.countercraft.movecraft.Rotation; -import net.countercraft.movecraft.*; import net.countercraft.movecraft.async.detection.DetectionTask; import net.countercraft.movecraft.async.rotation.RotationTask; import net.countercraft.movecraft.async.translation.TranslationTask; @@ -35,7 +37,6 @@ import net.countercraft.movecraft.mapUpdater.update.UpdateCommand; import net.countercraft.movecraft.utils.*; import org.bukkit.*; -import org.bukkit.block.Block; import org.bukkit.block.BlockFace; import org.bukkit.block.data.BlockData; import org.bukkit.entity.Player; @@ -744,7 +745,7 @@ private void processFadingBlocks() { } fadedBlocks++; processedFadeLocs.get(world).add(location); - Pair phaseBlock = phaseBlocks.getOrDefault(bLoc, new Pair<>(Material.AIR, (byte) 0)); + Pair phaseBlock = phaseBlocks.getOrDefault(bLoc, new Pair<>(Material.AIR, Settings.IsLegacy ? (byte) 0 : Bukkit.createBlockData(Material.AIR))); if (Settings.IsLegacy) { commands.add(new BlockCreateCommand(world, location, phaseBlock.getLeft(), (byte) phaseBlock.getRight())); } else { From b33c8bba6d1c5ac7549b45eb0159dbdde16e7a8a Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Thu, 27 Aug 2020 23:08:49 +0200 Subject: [PATCH 203/304] bump version --- modules/Movecraft/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/Movecraft/pom.xml b/modules/Movecraft/pom.xml index 3dbdaa8d5..d782ae747 100644 --- a/modules/Movecraft/pom.xml +++ b/modules/Movecraft/pom.xml @@ -10,7 +10,7 @@ UTF-8 - 7.0.0_for_1.8.8-1.16.1_beta_31 + 7.0.0_for_1.8.8-1.16.1_beta_32 spigot-repo From 41768646a22506fdd944ebd2b9992d2223a75696 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Thu, 27 Aug 2020 23:09:36 +0200 Subject: [PATCH 204/304] bump version --- modules/Movecraft/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/Movecraft/pom.xml b/modules/Movecraft/pom.xml index d782ae747..50a59148a 100644 --- a/modules/Movecraft/pom.xml +++ b/modules/Movecraft/pom.xml @@ -10,7 +10,7 @@ UTF-8 - 7.0.0_for_1.8.8-1.16.1_beta_32 + 7.0.0_for_1.8.8-1.16.2_beta_32 spigot-repo From 0aa61a3bff9fa4b3e8a9d64e54ff1ac82d07cbf5 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Sat, 29 Aug 2020 13:54:53 +0200 Subject: [PATCH 205/304] bump version --- modules/Movecraft/dependency-reduced-pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/Movecraft/dependency-reduced-pom.xml b/modules/Movecraft/dependency-reduced-pom.xml index 00bac7766..550128f4a 100644 --- a/modules/Movecraft/dependency-reduced-pom.xml +++ b/modules/Movecraft/dependency-reduced-pom.xml @@ -4,7 +4,7 @@ net.countercraft movecraft Movecraft - 7.0.0_for_1.8.8-1.16.1_beta_31 + 7.0.0_for_1.8.8-1.16.2_beta_32 http://github.com/apdevteam/Movecraft src/main/java From 62909fdb722294aaad3593fc38839c8901f75c11 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Sun, 6 Sep 2020 01:14:51 +0200 Subject: [PATCH 206/304] Removed nested BukkitRunnable in DetectionTask --- .../async/detection/DetectionTask.java | 100 +++++++++--------- 1 file changed, 48 insertions(+), 52 deletions(-) diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/detection/DetectionTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/detection/DetectionTask.java index 967262d04..58f1bf664 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/detection/DetectionTask.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/detection/DetectionTask.java @@ -28,14 +28,14 @@ import net.countercraft.movecraft.localisation.I18nSupport; import net.countercraft.movecraft.utils.*; import org.bukkit.*; -import org.bukkit.block.BlockState; +import org.bukkit.block.Block; import org.bukkit.block.Sign; import org.bukkit.entity.Player; -import org.bukkit.scheduler.BukkitRunnable; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.util.*; +import java.util.concurrent.ExecutionException; public class DetectionTask extends AsyncTask { @NotNull private final MovecraftLocation startLocation; @@ -79,7 +79,7 @@ public DetectionTask(Craft c, @NotNull MovecraftLocation startLocation, @Nullabl } @Override - public void execute() { + public void execute() throws ExecutionException, InterruptedException { long startTime = System.currentTimeMillis(); BlockLimitManager flyBlocks = getCraft().getType().getFlyBlocks(); dFlyBlocks = flyBlocks; @@ -120,17 +120,19 @@ public void execute() { } } - private void detectBlock(int x, int y, int z) { + private void detectBlock(int x, int y, int z) throws ExecutionException, InterruptedException { MovecraftLocation workingLocation = new MovecraftLocation(x, y, z); if (notVisited(workingLocation, visited)) { - Material testType = null; - int testData = 0; + Material testType; + int testData; + Block testBlock; try { - testData = world.getBlockAt(x, y, z).getData(); - testType = world.getBlockAt(x, y, z).getType(); + testBlock = world.getBlockAt(x, y, z); + testData = testBlock.getData(); + testType = testBlock.getType(); } catch (Exception e) { fail(String.format(I18nSupport.getInternationalisedString("Detection - Craft too large"), maxSize)); return; @@ -140,52 +142,46 @@ private void detectBlock(int x, int y, int z) { waterContact = true; } if (testType.name().endsWith("SIGN") || testType == LegacyUtils.SIGN_POST) { - new BukkitRunnable() { - @Override - public void run() { - BlockState state = world.getBlockAt(x, y, z).getState(); - if (state instanceof Sign) { - Sign s = (Sign) state; - if (s.getLine(0).equalsIgnoreCase("Pilot:") && player != null) { - String playerName = player.getName(); - boolean foundPilot = false; - if (s.getLine(1).equalsIgnoreCase(playerName) || s.getLine(2).equalsIgnoreCase(playerName) - || s.getLine(3).equalsIgnoreCase(playerName)) { - foundPilot = true; - } - if (!foundPilot && (!player.hasPermission("movecraft.bypasslock"))) { - fail(I18nSupport.getInternationalisedString( - "Detection - Not Registered Pilot")); - } - - } - String previous = ""; - for (String line : s.getLines()) { - if (line.length() == 0) { - continue; - } - line = ChatColor.stripColor(line); - if (isForbiddenSignString(line)) { - fail(I18nSupport.getInternationalisedString("Detection - Forbidden sign string found")); - return; - } - if (previous.equals(line)) { - continue; - } - for (List limitedStrings : craft.getType().getMaxSignsWithString().keySet()) { - if (!limitedStrings.contains(line.toLowerCase())) { - continue; - } - int count = signWithStringCount.getOrDefault(limitedStrings, 0); - count++; - signWithStringCount.put(limitedStrings, count); - previous = line; - } - + Sign sign = Bukkit.getScheduler().callSyncMethod(Movecraft.getInstance(), () -> (Sign) testBlock.getState()).get(); + if (sign.getLine(0).equalsIgnoreCase("Pilot:") && player != null) { + String playerName = player.getName(); + boolean foundPilot = false; + final String[] lines = sign.getLines(); + for (int i = 1 ; i < lines.length ; i++) { + if (!ChatColor.stripColor(lines[i]).equalsIgnoreCase(playerName)) + continue; + foundPilot = true; + break; + } + if (!foundPilot && (!player.hasPermission("movecraft.bypasslock"))) { + fail(I18nSupport.getInternationalisedString( + "Detection - Not Registered Pilot")); + } + String previous = ""; + for (String line : lines) { + if (line.length() == 0) { + continue; + } + line = ChatColor.stripColor(line); + if (isForbiddenSignString(line)) { + fail(I18nSupport.getInternationalisedString("Detection - Forbidden sign string found")); + return; + } + if (previous.equals(line)) { + continue; + } + for (List limitedStrings : craft.getType().getMaxSignsWithString().keySet()) { + if (!limitedStrings.contains(line.toLowerCase())) { + continue; } + int count = signWithStringCount.getOrDefault(limitedStrings, 0); + count++; + signWithStringCount.put(limitedStrings, count); + previous = line; } + } - }.runTask(Movecraft.getInstance()); + } } if (isForbiddenBlock(testType, testData)) { fail(I18nSupport.getInternationalisedString("Detection - Forbidden block found")); @@ -273,7 +269,7 @@ private void addToBlockCount(Set id) { blockTypeCount.put(id, count + 1); } - private void detectSurrounding(MovecraftLocation l) { + private void detectSurrounding(MovecraftLocation l) throws ExecutionException, InterruptedException { int x = l.getX(); int y = l.getY(); int z = l.getZ(); From 4d29177b4b64ad3486f8b9d88b64271429f317a1 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Tue, 8 Sep 2020 22:12:09 +0200 Subject: [PATCH 207/304] Fixes #48 --- .../movecraft/async/AsyncManager.java | 2 +- .../movecraft/utils/WaterlogUtils.java | 27 ++++++------------- 2 files changed, 9 insertions(+), 20 deletions(-) diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java index c6e22a4ce..28996cb65 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java @@ -284,7 +284,7 @@ private void processDetection(DetectionTask task){ for (MovecraftLocation location : entireHitbox) { if (location.getY() <= waterLine) { - c.getPhaseBlocks().put(location.toBukkit(c.getW()), new Pair<>(Material.WATER, (byte) 0)); + c.getPhaseBlocks().put(location.toBukkit(c.getW()), new Pair<>(Material.WATER, Settings.IsLegacy ? (byte) 0 : Bukkit.createBlockData(Material.WATER))); } } } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/WaterlogUtils.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/WaterlogUtils.java index fb2b818e1..b003ea439 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/WaterlogUtils.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/WaterlogUtils.java @@ -2,25 +2,30 @@ import net.countercraft.movecraft.MovecraftLocation; import net.countercraft.movecraft.craft.Craft; +import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.block.Block; import org.bukkit.block.data.Bisected; +import org.bukkit.block.data.BlockData; +import org.bukkit.block.data.Levelled; import org.bukkit.block.data.Waterlogged; import org.bukkit.block.data.type.Slab; import org.bukkit.block.data.type.Stairs; import org.bukkit.block.data.type.TrapDoor; public class WaterlogUtils { - private static Pair DEFAULT_PHASE_BLOCK = new Pair<>(Material.AIR, 0); + private static Pair DEFAULT_PHASE_BLOCK = new Pair<>(Material.AIR, Bukkit.createBlockData(Material.AIR)); private WaterlogUtils(){ } public static void waterlogBlocksOnCraft(Craft craft, HitBox interior) { for (MovecraftLocation ml : craft.getHitBox()) { - final Material phaseBlock = craft.getPhaseBlocks().getOrDefault(ml.toBukkit(craft.getWorld()), DEFAULT_PHASE_BLOCK).getLeft(); - boolean waterlog = phaseBlock == Material.WATER; + final Pair block = craft.getPhaseBlocks().getOrDefault(ml.toBukkit(craft.getWorld()), DEFAULT_PHASE_BLOCK); + final Material phaseBlock = block.getLeft(); + final BlockData phaseBlockData = (BlockData) block.getRight(); + boolean waterlog = phaseBlock == Material.WATER && phaseBlockData instanceof Levelled && ((Levelled) phaseBlockData).getLevel() == 0; Block b = ml.toBukkit(craft.getWorld()).getBlock(); if (!(b.getBlockData() instanceof Waterlogged)) { continue; @@ -78,22 +83,6 @@ private static boolean isWaterlogged(Location location){ return wlog.isWaterlogged(); } - private static boolean adjacentToWater(Location location){ - for (MovecraftLocation shift : SHIFTS){ - final Block test = location.add(shift.toBukkit(location.getWorld())).getBlock(); - if (test.getType() == Material.WATER){ - return true; - } else if (test.getBlockData() instanceof Waterlogged){ - final Waterlogged wlog = (Waterlogged) test.getBlockData(); - if (!wlog.isWaterlogged()) { - continue; - } - return true; - } - } - return false; - } - private static final MovecraftLocation[] SHIFTS = {new MovecraftLocation(0,1,0), new MovecraftLocation(0, -1, 0), new MovecraftLocation(1, 0, 0), From 7c69c2d15d8f1b67deafcb2b33745b10098546b4 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Tue, 8 Sep 2020 22:14:48 +0200 Subject: [PATCH 208/304] Fixes #76 --- .../movecraft/events/CraftCollisionExplosionEvent.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/api/src/main/java/net/countercraft/movecraft/events/CraftCollisionExplosionEvent.java b/modules/api/src/main/java/net/countercraft/movecraft/events/CraftCollisionExplosionEvent.java index e1c0abcc2..9c781f10e 100644 --- a/modules/api/src/main/java/net/countercraft/movecraft/events/CraftCollisionExplosionEvent.java +++ b/modules/api/src/main/java/net/countercraft/movecraft/events/CraftCollisionExplosionEvent.java @@ -15,7 +15,7 @@ public class CraftCollisionExplosionEvent extends CraftEvent implements Cancella private boolean cancelled; public CraftCollisionExplosionEvent(@NotNull Craft craft, @NotNull Location location, @NotNull World world) { - super(craft); + super(craft, true); this.world = world; this.location = location; cancelled = false; From 28fd189b0a769c05a3614d57e9a53c8afc171bee Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Thu, 10 Sep 2020 18:31:30 +0200 Subject: [PATCH 209/304] Fixed missing method on 1.12.2 --- .../movecraft/craft/ChunkManager.java | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/ChunkManager.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/ChunkManager.java index 246c10f62..0d7a0e918 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/ChunkManager.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/ChunkManager.java @@ -37,14 +37,18 @@ public class ChunkManager implements Listener { public static void addChunksToLoad(List list) { for (MovecraftChunk chunk : list) { - if (!chunks.contains(chunk)) { - chunks.add(chunk); - if (!chunk.isLoaded()) { - chunk.toBukkit().load(true); - chunk.toBukkit().setForceLoaded(true); - } + if (chunks.contains(chunk)) { + continue; } - + chunks.add(chunk); + if (chunk.isLoaded()) { + continue; + } + chunk.toBukkit().load(true); + if (Settings.IsLegacy) { + continue; + } + chunk.toBukkit().setForceLoaded(true); } // remove chunks after 10 seconds From ce9dc5033a2685567fea7d54ee979a585eb6db13 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Thu, 10 Sep 2020 18:40:26 +0200 Subject: [PATCH 210/304] Fixed WorldGuard flag registration issue encountered when plugin is reloaded with a plugin management plugin (such as PlugMan) --- .../src/main/java/net/countercraft/movecraft/Movecraft.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java index e337fb863..795a893db 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java @@ -522,7 +522,8 @@ public void onLoad() { Plugin wGPlugin = getServer().getPluginManager().getPlugin("WorldGuard"); if (wGPlugin instanceof WorldGuardPlugin) { worldGuardPlugin = (WorldGuardPlugin) wGPlugin; - WorldGuardCompatManager.registerFlags(); + if (startup) + WorldGuardCompatManager.registerFlags(); } } From 82afc4cc7fbd2a43f289d0f45957939970d3bc2e Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Fri, 11 Sep 2020 22:41:03 +0200 Subject: [PATCH 211/304] Fixed WorldGuard flag registration issue encountered when plugin is reloaded with a plugin management plugin (such as PlugMan) --- .../worldguard/WorldGuardCompatManager.java | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/worldguard/WorldGuardCompatManager.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/worldguard/WorldGuardCompatManager.java index f195cd689..7f7319bda 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/worldguard/WorldGuardCompatManager.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/worldguard/WorldGuardCompatManager.java @@ -46,10 +46,14 @@ public static void registerFlags() { flags = WorldGuard.getInstance().getFlagRegistry(); } Movecraft.getInstance().getLogger().info("Registered custom flags"); - flags.register(FLAG_MOVE); - flags.register(FLAG_PILOT); - flags.register(FLAG_ROTATE); - flags.register(FLAG_SINK); + if (flags.get("movecraft-move") != null) + flags.register(FLAG_MOVE); + if (flags.get("movecraft-pilot") != null) + flags.register(FLAG_PILOT); + if (flags.get("movecraft-rotate") != null) + flags.register(FLAG_ROTATE); + if (flags.get("movecraft-sink") != null) + flags.register(FLAG_SINK); } @EventHandler From 959e969e37929984bad45c59db62143412ce550c Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Fri, 11 Sep 2020 22:41:48 +0200 Subject: [PATCH 212/304] bump version --- modules/Movecraft/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/Movecraft/pom.xml b/modules/Movecraft/pom.xml index 50a59148a..6e909f1cb 100644 --- a/modules/Movecraft/pom.xml +++ b/modules/Movecraft/pom.xml @@ -10,7 +10,7 @@ UTF-8 - 7.0.0_for_1.8.8-1.16.2_beta_32 + 7.0.0_for_1.8.8-1.16.2_beta_33 spigot-repo From 981a90682874cc08c2cb2e16b78dc23079034d00 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Sat, 19 Sep 2020 18:25:43 +0200 Subject: [PATCH 213/304] small fixes --- .../movecraft/async/translation/TranslationTask.java | 6 +++--- .../java/net/countercraft/movecraft/craft/ChunkManager.java | 2 ++ .../movecraft/mapUpdater/update/CraftTranslateCommand.java | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java index be41a4285..259ffb69b 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java @@ -214,7 +214,7 @@ protected void execute() throws InterruptedException, ExecutionException { // !world.equals(craft.getW()) || Math.abs(dx) + oldHitBox.getXLength() >= // (Bukkit.getServer().getViewDistance() - 1) * 16 || Math.abs(dz) + // oldHitBox.getZLength() >= (Bukkit.getServer().getViewDistance() - 1) * 16 - List chunksToLoad = ChunkManager.getChunks(oldHitBox, craft.getW()); + List chunksToLoad = ChunkManager.getChunks(oldHitBox, craft.getWorld()); chunksToLoad.addAll(ChunkManager.getChunks(oldHitBox, world, dx, dy, dz)); MovecraftChunk.addSurroundingChunks(chunksToLoad, 1); ChunkManager.checkChunks(chunksToLoad); @@ -224,9 +224,9 @@ protected void execute() throws InterruptedException, ExecutionException { // Only modify dy when not switching worlds //Check if the craft is too high - if(world.equals(craft.getW()) && craft.getType().getMaxHeightLimit(craft.getW()) < craft.getHitBox().getMinY()){ + if(world.equals(craft.getWorld()) && craft.getType().getMaxHeightLimit(craft.getWorld()) < craft.getHitBox().getMinY()){ dy = Math.min(dy,-1); - }else if(world.equals(craft.getW()) && craft.getType().getMaxHeightAboveGround(craft.getW()) > 0){ + }else if(world.equals(craft.getWorld()) && craft.getType().getMaxHeightAboveGround(craft.getW()) > 0){ final MovecraftLocation middle = oldHitBox.getMidPoint(); int testY = minY; while (testY > 0){ diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/ChunkManager.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/ChunkManager.java index 0d7a0e918..ef1330b0d 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/ChunkManager.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/ChunkManager.java @@ -66,6 +66,8 @@ private static void removeChunksToLoad(List list) { for (MovecraftChunk chunk : list) { chunks.remove(chunk); } + if (Settings.IsLegacy) + return; Bukkit.getScheduler().callSyncMethod(Movecraft.getInstance(), () -> { for (MovecraftChunk chunk : list) { chunk.toBukkit().setForceLoaded(false); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftTranslateCommand.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftTranslateCommand.java index a912fb1ff..60fc8aa01 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftTranslateCommand.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftTranslateCommand.java @@ -132,7 +132,7 @@ public void doUpdate() { if(passthroughBlocks.isEmpty()){ //translate the craft Movecraft.getInstance().getWorldHandler().translateCraft(craft,displacement,world); - craft.setW(world); + craft.setWorld(world); //trigger sign events this.sendSignEvents(); } else { From fe516ae94ae5b754ff5a3b622ea909597a89e4a0 Mon Sep 17 00:00:00 2001 From: TylerS1066 Date: Sat, 19 Sep 2020 14:13:05 -0500 Subject: [PATCH 214/304] Update maven.yml --- .github/workflows/maven.yml | 57 ++++++++++++++++++++++++++++++++++++- 1 file changed, 56 insertions(+), 1 deletion(-) diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml index 91106d3f4..3fab22e7e 100644 --- a/.github/workflows/maven.yml +++ b/.github/workflows/maven.yml @@ -4,7 +4,6 @@ on: [push] jobs: build: - runs-on: ubuntu-latest steps: @@ -13,5 +12,61 @@ jobs: uses: actions/setup-java@v1 with: java-version: 1.8 + - name: Cache Maven packages + id: cache + uses: actions/cache@v2 + with: + path: ~/.m2 + key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }} + restore-keys: ${{ runner.os }}-m2 + +# Run Spigot BuildTools for NMS if required + - name: Setup BuildTools + if: steps.cache.outputs.cache-hit != 'true' + run: mkdir BuildTools + - name: Download BuildTools + if: steps.cache.outputs.cache-hit != 'true' + run: wget -O BuildTools/BuildTools.jar https://hub.spigotmc.org/jenkins/job/BuildTools/lastSuccessfulBuild/artifact/target/BuildTools.jar + - name: 1.8.8 + if: steps.cache.outputs.cache-hit != 'true' + run: cd BuildTools && java -jar BuildTools.jar --rev 1.8.8 + - name: 1.9.4 + if: steps.cache.outputs.cache-hit != 'true' + run: cd BuildTools && java -jar BuildTools.jar --rev 1.9.4 + - name: 1.10.2 + if: steps.cache.outputs.cache-hit != 'true' + run: cd BuildTools && java -jar BuildTools.jar --rev 1.10.2 + - name: 1.11.2 + if: steps.cache.outputs.cache-hit != 'true' + run: cd BuildTools && java -jar BuildTools.jar --rev 1.11.2 + - name: 1.12.1 + if: steps.cache.outputs.cache-hit != 'true' + run: cd BuildTools && java -jar BuildTools.jar --rev 1.12.1 + - name: 1.13.2 + if: steps.cache.outputs.cache-hit != 'true' + run: cd BuildTools && java -jar BuildTools.jar --rev 1.13.2 + - name: 1.14.4 + if: steps.cache.outputs.cache-hit != 'true' + run: cd BuildTools && java -jar BuildTools.jar --rev 1.14.4 + - name: 1.15.2 + if: steps.cache.outputs.cache-hit != 'true' + run: cd BuildTools && java -jar BuildTools.jar --rev 1.15.2 + - name: 1.16.1 + if: steps.cache.outputs.cache-hit != 'true' + run: cd BuildTools && java -jar BuildTools.jar --rev 1.16.1 + - name: 1.15.2 + if: steps.cache.outputs.cache-hit != 'true' + run: cd BuildTools && java -jar BuildTools.jar --rev 1.16.3 + - name: Build with Maven run: mvn -B package --file pom.xml + + - name: Stage jar + run: mkdir staging && cp target/Movecraft.jar staging + - name: Rename jar + run: mv staging/Movecraft.jar staging/Movecraft_$GITHUB_SHA.jar + - name: Upload jar + uses: actions/upload-artifact@v2 + with: + name: Movecraft_Dev-Build + path: staging/Movecraft_*.jar From ac9333a7ec6666394462fb58f77582ad51366a3f Mon Sep 17 00:00:00 2001 From: TylerS1066 Date: Sat, 19 Sep 2020 14:43:11 -0500 Subject: [PATCH 215/304] Update maven.yml --- .github/workflows/maven.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml index 3fab22e7e..a91a1ef95 100644 --- a/.github/workflows/maven.yml +++ b/.github/workflows/maven.yml @@ -54,7 +54,7 @@ jobs: - name: 1.16.1 if: steps.cache.outputs.cache-hit != 'true' run: cd BuildTools && java -jar BuildTools.jar --rev 1.16.1 - - name: 1.15.2 + - name: 1.16.3 if: steps.cache.outputs.cache-hit != 'true' run: cd BuildTools && java -jar BuildTools.jar --rev 1.16.3 From 98ed39670bd2aa548ecd84a2a47215659bba7cba Mon Sep 17 00:00:00 2001 From: TylerS1066 Date: Sat, 19 Sep 2020 15:11:41 -0500 Subject: [PATCH 216/304] Fix v1_8_R3 pom --- modules/v1_8_R3/pom.xml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/modules/v1_8_R3/pom.xml b/modules/v1_8_R3/pom.xml index e4747c36b..7a0959e0c 100644 --- a/modules/v1_8_R3/pom.xml +++ b/modules/v1_8_R3/pom.xml @@ -6,6 +6,7 @@ movecraft-parent net.countercraft parent + ../../ 4.0.0 @@ -54,4 +55,4 @@ - \ No newline at end of file + From 53d58753bd2d99cb218e44c51559ceb56511f15c Mon Sep 17 00:00:00 2001 From: TylerS1066 Date: Sat, 19 Sep 2020 15:42:24 -0500 Subject: [PATCH 217/304] Fix v1_15_R1 pom --- modules/v1_15_R1/pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/v1_15_R1/pom.xml b/modules/v1_15_R1/pom.xml index 9dac4f9ce..5dea0d7e5 100644 --- a/modules/v1_15_R1/pom.xml +++ b/modules/v1_15_R1/pom.xml @@ -6,7 +6,7 @@ movecraft-parent net.countercraft parent - ../../pom.xml + ../../relativePath> 4.0.0 @@ -60,4 +60,4 @@ - \ No newline at end of file + From 6da63b5b5684085767d6acba803ac730517daa73 Mon Sep 17 00:00:00 2001 From: TylerS1066 Date: Sat, 19 Sep 2020 15:42:40 -0500 Subject: [PATCH 218/304] Fix v1_16_R1 pom --- modules/v1_16_R1/pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/v1_16_R1/pom.xml b/modules/v1_16_R1/pom.xml index 64f125fe8..faa816ef0 100644 --- a/modules/v1_16_R1/pom.xml +++ b/modules/v1_16_R1/pom.xml @@ -6,7 +6,7 @@ movecraft-parent net.countercraft parent - ../../pom.xml + ../.. 4.0.0 @@ -55,4 +55,4 @@ - \ No newline at end of file + From b976a2a4e7d818cea00b97763b7f84352518b336 Mon Sep 17 00:00:00 2001 From: TylerS1066 Date: Sat, 19 Sep 2020 15:42:58 -0500 Subject: [PATCH 219/304] Fix v1_16_R2 pom --- modules/v1_16_R2/pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/v1_16_R2/pom.xml b/modules/v1_16_R2/pom.xml index 112f37ee7..c3f334d88 100644 --- a/modules/v1_16_R2/pom.xml +++ b/modules/v1_16_R2/pom.xml @@ -6,7 +6,7 @@ movecraft-parent net.countercraft parent - ../../pom.xml + ../.. 4.0.0 @@ -54,4 +54,4 @@ - \ No newline at end of file + From 376523ba4c249369809de0f4a95d1c6f14b2ce40 Mon Sep 17 00:00:00 2001 From: TylerS1066 Date: Sat, 19 Sep 2020 15:44:18 -0500 Subject: [PATCH 220/304] Update README.md --- README.md | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 30aee0d4e..44474708f 100644 --- a/README.md +++ b/README.md @@ -17,9 +17,16 @@ Older builds (1.10 and below) are located on the [Spigot forums](https://www.spi Movecraft uses multiple versions of the Spigot server software for legacy support. As such, you need to run [BuildTools](https://www.spigotmc.org/wiki/buildtools/) for several versions before building the plugin. It doesn't matter where you do this, but inside the Movecraft directory is probably a bad place. ``` +java -jar BuildTools.jar --rev 1.8.8 +java -jar BuildTools.jar --rev 1.9.4 java -jar BuildTools.jar --rev 1.10.2 java -jar BuildTools.jar --rev 1.11.2 java -jar BuildTools.jar --rev 1.12.1 +java -jar BuildTools.jar --rev 1.13.2 +java -jar BuildTools.jar --rev 1.14.4 +java -jar BuildTools.jar --rev 1.15.2 +java -jar BuildTools.jar --rev 1.16.1 +java -jar BuildTools.jar --rev 1.16.3 ``` Then, run the following to build Movecraft through `maven`. @@ -29,8 +36,8 @@ mvn clean install Jars are located in `/target`. ## Support -[Github Issues](https://github.com/apdevteam/movecraft/issues) +[Github Issues](https://github.com/eirikh1996/Movecraft/issues) -[Discord](http://bit.ly/JoinAP-Dev) +[Discord](https://discord.gg/ukYYG2T) The plugin is released here under the GNU General Public License V3. From d358c7d6d38550d4d753fb57ff1b3c75efea2d5d Mon Sep 17 00:00:00 2001 From: TylerS1066 Date: Sat, 19 Sep 2020 15:45:54 -0500 Subject: [PATCH 221/304] Fixed poms --- modules/v1_15_R1/pom.xml | 2 +- modules/v1_16_R1/pom.xml | 2 +- modules/v1_16_R2/pom.xml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/modules/v1_15_R1/pom.xml b/modules/v1_15_R1/pom.xml index 5dea0d7e5..53a3c9d47 100644 --- a/modules/v1_15_R1/pom.xml +++ b/modules/v1_15_R1/pom.xml @@ -6,7 +6,7 @@ movecraft-parent net.countercraft parent - ../../relativePath> + ../../ 4.0.0 diff --git a/modules/v1_16_R1/pom.xml b/modules/v1_16_R1/pom.xml index faa816ef0..9ad776677 100644 --- a/modules/v1_16_R1/pom.xml +++ b/modules/v1_16_R1/pom.xml @@ -6,7 +6,7 @@ movecraft-parent net.countercraft parent - ../.. + ../../ 4.0.0 diff --git a/modules/v1_16_R2/pom.xml b/modules/v1_16_R2/pom.xml index c3f334d88..a9fa12d94 100644 --- a/modules/v1_16_R2/pom.xml +++ b/modules/v1_16_R2/pom.xml @@ -6,7 +6,7 @@ movecraft-parent net.countercraft parent - ../.. + ../../ 4.0.0 From deecf5665ec0c724cddc6e9798d2229097d260fc Mon Sep 17 00:00:00 2001 From: TylerS1066 Date: Sat, 19 Sep 2020 16:49:09 -0500 Subject: [PATCH 222/304] Update maven.yml --- .github/workflows/maven.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml index a91a1ef95..fb598d581 100644 --- a/.github/workflows/maven.yml +++ b/.github/workflows/maven.yml @@ -48,9 +48,9 @@ jobs: - name: 1.14.4 if: steps.cache.outputs.cache-hit != 'true' run: cd BuildTools && java -jar BuildTools.jar --rev 1.14.4 - - name: 1.15.2 + - name: 1.15.0 if: steps.cache.outputs.cache-hit != 'true' - run: cd BuildTools && java -jar BuildTools.jar --rev 1.15.2 + run: cd BuildTools && java -jar BuildTools.jar --rev 1.15 - name: 1.16.1 if: steps.cache.outputs.cache-hit != 'true' run: cd BuildTools && java -jar BuildTools.jar --rev 1.16.1 From 80ef00e25e2f12582c5e8b5696f48bf9e3b9a915 Mon Sep 17 00:00:00 2001 From: TylerS1066 Date: Sat, 19 Sep 2020 18:18:30 -0500 Subject: [PATCH 223/304] Update maven.yml --- .github/workflows/maven.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml index fb598d581..1f7e3209b 100644 --- a/.github/workflows/maven.yml +++ b/.github/workflows/maven.yml @@ -47,16 +47,16 @@ jobs: run: cd BuildTools && java -jar BuildTools.jar --rev 1.13.2 - name: 1.14.4 if: steps.cache.outputs.cache-hit != 'true' - run: cd BuildTools && java -jar BuildTools.jar --rev 1.14.4 + run: cd BuildTools && java -jar BuildTools.jar --rev 1.14.4 --compile craftbukkit - name: 1.15.0 if: steps.cache.outputs.cache-hit != 'true' - run: cd BuildTools && java -jar BuildTools.jar --rev 1.15 + run: cd BuildTools && java -jar BuildTools.jar --rev 1.15 --compile craftbukkit - name: 1.16.1 if: steps.cache.outputs.cache-hit != 'true' - run: cd BuildTools && java -jar BuildTools.jar --rev 1.16.1 + run: cd BuildTools && java -jar BuildTools.jar --rev 1.16.1 --compile craftbukkit - name: 1.16.3 if: steps.cache.outputs.cache-hit != 'true' - run: cd BuildTools && java -jar BuildTools.jar --rev 1.16.3 + run: cd BuildTools && java -jar BuildTools.jar --rev 1.16.3 --compile craftbukkit - name: Build with Maven run: mvn -B package --file pom.xml From b38bbae22914d4517041147753c5cf69b139ce67 Mon Sep 17 00:00:00 2001 From: TylerS1066 Date: Sat, 19 Sep 2020 18:55:40 -0500 Subject: [PATCH 224/304] Update maven.yml --- .github/workflows/maven.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml index 1f7e3209b..498bfda48 100644 --- a/.github/workflows/maven.yml +++ b/.github/workflows/maven.yml @@ -56,7 +56,7 @@ jobs: run: cd BuildTools && java -jar BuildTools.jar --rev 1.16.1 --compile craftbukkit - name: 1.16.3 if: steps.cache.outputs.cache-hit != 'true' - run: cd BuildTools && java -jar BuildTools.jar --rev 1.16.3 --compile craftbukkit + run: cd BuildTools && java -jar BuildTools.jar --rev 1.16.2 --compile craftbukkit - name: Build with Maven run: mvn -B package --file pom.xml From fed5fb2cbb03b83281b221fb529d7ff8da8bee53 Mon Sep 17 00:00:00 2001 From: TylerS1066 Date: Sat, 19 Sep 2020 19:24:05 -0500 Subject: [PATCH 225/304] Update README.md --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 44474708f..052259e6c 100644 --- a/README.md +++ b/README.md @@ -23,10 +23,10 @@ java -jar BuildTools.jar --rev 1.10.2 java -jar BuildTools.jar --rev 1.11.2 java -jar BuildTools.jar --rev 1.12.1 java -jar BuildTools.jar --rev 1.13.2 -java -jar BuildTools.jar --rev 1.14.4 -java -jar BuildTools.jar --rev 1.15.2 -java -jar BuildTools.jar --rev 1.16.1 -java -jar BuildTools.jar --rev 1.16.3 +java -jar BuildTools.jar --rev 1.14.4 --compile craftbukkit +java -jar BuildTools.jar --rev 1.15 --compile craftbukkit +java -jar BuildTools.jar --rev 1.16.1 --compile craftbukkit +java -jar BuildTools.jar --rev 1.16.2 --compile craftbukkit ``` Then, run the following to build Movecraft through `maven`. From 9c0f3f41eb8b0f00673995b8315f94e79def9d3a Mon Sep 17 00:00:00 2001 From: TylerS1066 Date: Sat, 19 Sep 2020 19:24:58 -0500 Subject: [PATCH 226/304] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 052259e6c..2b705a34b 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,6 @@ Movecraft ====== +![Java CI](https://github.com/eirik1996/Movecraft/workflows/Java%20CI/badge.svg?branch=master) [![codebeat badge](https://codebeat.co/badges/77751ae4-80f7-460a-a225-0e3ae8cbbab1)](https://codebeat.co/projects/github-com-apdevteam-movecraft-master) [![Build Status](https://travis-ci.org/APDevTeam/Movecraft.svg?branch=master)](https://travis-ci.org/APDevTeam/Movecraft) From 3ce730be017e696117c567254abd7779a4877448 Mon Sep 17 00:00:00 2001 From: TylerS1066 Date: Tue, 22 Sep 2020 09:59:31 -0500 Subject: [PATCH 227/304] Update maven.yml --- .github/workflows/maven.yml | 66 ++++++++++++++++++++++++++++--------- 1 file changed, 51 insertions(+), 15 deletions(-) diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml index 498bfda48..dde2e916e 100644 --- a/.github/workflows/maven.yml +++ b/.github/workflows/maven.yml @@ -17,45 +17,81 @@ jobs: uses: actions/cache@v2 with: path: ~/.m2 - key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }} + key: ${{ runner.os }}-m2 restore-keys: ${{ runner.os }}-m2 # Run Spigot BuildTools for NMS if required - name: Setup BuildTools if: steps.cache.outputs.cache-hit != 'true' - run: mkdir BuildTools - - name: Download BuildTools - if: steps.cache.outputs.cache-hit != 'true' - run: wget -O BuildTools/BuildTools.jar https://hub.spigotmc.org/jenkins/job/BuildTools/lastSuccessfulBuild/artifact/target/BuildTools.jar + run: mkdir BuildTools && wget -O BuildTools/BuildTools.jar https://hub.spigotmc.org/jenkins/job/BuildTools/lastSuccessfulBuild/artifact/target/BuildTools.jar + +# EXAMPLE - Copy/paste as required to add version support to CI +# - name: Test [version] +# id: [version name] +# run: test -f ~/.m2/repository/org/bukkit/craftbukkit/[NMS version]/craftbukkit-[NMS version].jar && echo "::set-output name=sucess::true" +# - name: [version] +# if: steps.frostburn.outputs.sucess != 'true' +# run: cd BuildTools && java -jar BuildTools.jar --rev [version] + + - name: Test 1.8.8 + id: bountiful + run: test -f ~/.m2/repository/org/bukkit/craftbukkit/1.8.8-R0.1-SNAPSHOT/craftbukkit-1.8.8-R0.1-SNAPSHOT.jar && echo "::set-output name=sucess::true" - name: 1.8.8 - if: steps.cache.outputs.cache-hit != 'true' + if: steps.bountiful.outputs.sucess != 'true' run: cd BuildTools && java -jar BuildTools.jar --rev 1.8.8 + - name: Test 1.9.4 + id: combat + run: test -f ~/.m2/repository/org/bukkit/craftbukkit/1.9.4-R0.1-SNAPSHOT/craftbukkit-1.9.4-R0.1-SNAPSHOT.jar && echo "::set-output name=sucess::true" - name: 1.9.4 - if: steps.cache.outputs.cache-hit != 'true' + if: steps.combat.outputs.sucess != 'true' run: cd BuildTools && java -jar BuildTools.jar --rev 1.9.4 + - name: Test 1.10.2 + id: frostburn + run: test -f ~/.m2/repository/org/bukkit/craftbukkit/1.10.2-R0.1-SNAPSHOT/craftbukkit-1.10.2-R0.1-SNAPSHOT.jar && echo "::set-output name=sucess::true" - name: 1.10.2 - if: steps.cache.outputs.cache-hit != 'true' + if: steps.frostburn.outputs.sucess != 'true' run: cd BuildTools && java -jar BuildTools.jar --rev 1.10.2 + - name: Test 1.11.2 + id: exploration + run: test -f ~/.m2/repository/org/bukkit/craftbukkit/1.11.2-R0.1-SNAPSHOT/craftbukkit-1.11.2-R0.1-SNAPSHOT.jar && echo "::set-output name=sucess::true" - name: 1.11.2 - if: steps.cache.outputs.cache-hit != 'true' + if: steps.exploration.outputs.sucess != 'true' run: cd BuildTools && java -jar BuildTools.jar --rev 1.11.2 + - name: Test 1.12.1 + id: color + run: test -f ~/.m2/repository/org/bukkit/craftbukkit/1.12.1-R0.1-SNAPSHOT/craftbukkit-1.12.1-R0.1-SNAPSHOT.jar && echo "::set-output name=sucess::true" - name: 1.12.1 - if: steps.cache.outputs.cache-hit != 'true' + if: steps.color.outputs.sucess != 'true' run: cd BuildTools && java -jar BuildTools.jar --rev 1.12.1 + - name: Test 1.13.2 + id: aquatic + run: test -f ~/.m2/repository/org/bukkit/craftbukkit/1.13.2-R0.1-SNAPSHOT/craftbukkit-1.13.2-R0.1-SNAPSHOT.jar && echo "::set-output name=sucess::true" - name: 1.13.2 - if: steps.cache.outputs.cache-hit != 'true' + if: steps.aquatic.outputs.sucess != 'true' run: cd BuildTools && java -jar BuildTools.jar --rev 1.13.2 + - name: Test 1.14.4 + id: pillage + run: test -f ~/.m2/repository/org/bukkit/craftbukkit/1.14.4-R0.1-SNAPSHOT/craftbukkit-1.14.4-R0.1-SNAPSHOT.jar && echo "::set-output name=sucess::true" - name: 1.14.4 - if: steps.cache.outputs.cache-hit != 'true' + if: steps.pillage.outputs.sucess != 'true' run: cd BuildTools && java -jar BuildTools.jar --rev 1.14.4 --compile craftbukkit + - name: Test 1.15.0 + id: bees + run: test -f ~/.m2/repository/org/bukkit/craftbukkit/1.15-R0.1-SNAPSHOT/craftbukkit-1.15-R0.1-SNAPSHOT.jar && echo "::set-output name=sucess::true" - name: 1.15.0 - if: steps.cache.outputs.cache-hit != 'true' + if: steps.bees.outputs.sucess != 'true'' run: cd BuildTools && java -jar BuildTools.jar --rev 1.15 --compile craftbukkit + - name: Test 1.16.1 + id: nether + run: test -f ~/.m2/repository/org/bukkit/craftbukkit/1.16.1-R0.1-SNAPSHOT/craftbukkit-1.16.1-R0.1-SNAPSHOT.jar && echo "::set-output name=sucess::true" - name: 1.16.1 - if: steps.cache.outputs.cache-hit != 'true' + if: steps.nether.outputs.sucess != 'true'' run: cd BuildTools && java -jar BuildTools.jar --rev 1.16.1 --compile craftbukkit + - name: Test 1.16.3 + id: nether2 + run: test -f ~/.m2/repository/org/bukkit/craftbukkit/1.16.3-R0.1-SNAPSHOT/craftbukkit-1.16.3-R0.1-SNAPSHOT.jar && echo "::set-output name=sucess::true" - name: 1.16.3 - if: steps.cache.outputs.cache-hit != 'true' + if: steps.nether2.outputs.sucess != 'true'' run: cd BuildTools && java -jar BuildTools.jar --rev 1.16.2 --compile craftbukkit - name: Build with Maven From 4f27270319ddacfcc103ae1669f2f150e232ff12 Mon Sep 17 00:00:00 2001 From: TylerS1066 Date: Tue, 22 Sep 2020 10:00:15 -0500 Subject: [PATCH 228/304] Update maven.yml --- .github/workflows/maven.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml index dde2e916e..f1ec7d825 100644 --- a/.github/workflows/maven.yml +++ b/.github/workflows/maven.yml @@ -79,7 +79,7 @@ jobs: id: bees run: test -f ~/.m2/repository/org/bukkit/craftbukkit/1.15-R0.1-SNAPSHOT/craftbukkit-1.15-R0.1-SNAPSHOT.jar && echo "::set-output name=sucess::true" - name: 1.15.0 - if: steps.bees.outputs.sucess != 'true'' + if: steps.bees.outputs.sucess != 'true' run: cd BuildTools && java -jar BuildTools.jar --rev 1.15 --compile craftbukkit - name: Test 1.16.1 id: nether From 1c553a017e23b11d9234934789e8865f8ac18f26 Mon Sep 17 00:00:00 2001 From: TylerS1066 Date: Tue, 22 Sep 2020 10:00:35 -0500 Subject: [PATCH 229/304] Update maven.yml --- .github/workflows/maven.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml index f1ec7d825..ceb455dcd 100644 --- a/.github/workflows/maven.yml +++ b/.github/workflows/maven.yml @@ -85,13 +85,13 @@ jobs: id: nether run: test -f ~/.m2/repository/org/bukkit/craftbukkit/1.16.1-R0.1-SNAPSHOT/craftbukkit-1.16.1-R0.1-SNAPSHOT.jar && echo "::set-output name=sucess::true" - name: 1.16.1 - if: steps.nether.outputs.sucess != 'true'' + if: steps.nether.outputs.sucess != 'true' run: cd BuildTools && java -jar BuildTools.jar --rev 1.16.1 --compile craftbukkit - name: Test 1.16.3 id: nether2 run: test -f ~/.m2/repository/org/bukkit/craftbukkit/1.16.3-R0.1-SNAPSHOT/craftbukkit-1.16.3-R0.1-SNAPSHOT.jar && echo "::set-output name=sucess::true" - name: 1.16.3 - if: steps.nether2.outputs.sucess != 'true'' + if: steps.nether2.outputs.sucess != 'true' run: cd BuildTools && java -jar BuildTools.jar --rev 1.16.2 --compile craftbukkit - name: Build with Maven From 2078bb1ff59a10316106508135dd12801dc4218c Mon Sep 17 00:00:00 2001 From: TylerS1066 Date: Tue, 22 Sep 2020 10:01:53 -0500 Subject: [PATCH 230/304] Update maven.yml --- .github/workflows/maven.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml index ceb455dcd..30d144fed 100644 --- a/.github/workflows/maven.yml +++ b/.github/workflows/maven.yml @@ -32,6 +32,7 @@ jobs: # - name: [version] # if: steps.frostburn.outputs.sucess != 'true' # run: cd BuildTools && java -jar BuildTools.jar --rev [version] + - run: ls ~/.m2/repository/org/bukkit/craftbukkit/ - name: Test 1.8.8 id: bountiful From 2d9b35ca25b9694864bd63ca7cb0d525767f9303 Mon Sep 17 00:00:00 2001 From: TylerS1066 Date: Tue, 22 Sep 2020 10:07:19 -0500 Subject: [PATCH 231/304] Revert changes to get successful buildtools --- .github/workflows/maven.yml | 67 +++++++++---------------------------- 1 file changed, 15 insertions(+), 52 deletions(-) diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml index 30d144fed..498bfda48 100644 --- a/.github/workflows/maven.yml +++ b/.github/workflows/maven.yml @@ -17,82 +17,45 @@ jobs: uses: actions/cache@v2 with: path: ~/.m2 - key: ${{ runner.os }}-m2 + key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }} restore-keys: ${{ runner.os }}-m2 # Run Spigot BuildTools for NMS if required - name: Setup BuildTools if: steps.cache.outputs.cache-hit != 'true' - run: mkdir BuildTools && wget -O BuildTools/BuildTools.jar https://hub.spigotmc.org/jenkins/job/BuildTools/lastSuccessfulBuild/artifact/target/BuildTools.jar - -# EXAMPLE - Copy/paste as required to add version support to CI -# - name: Test [version] -# id: [version name] -# run: test -f ~/.m2/repository/org/bukkit/craftbukkit/[NMS version]/craftbukkit-[NMS version].jar && echo "::set-output name=sucess::true" -# - name: [version] -# if: steps.frostburn.outputs.sucess != 'true' -# run: cd BuildTools && java -jar BuildTools.jar --rev [version] - - run: ls ~/.m2/repository/org/bukkit/craftbukkit/ - - - name: Test 1.8.8 - id: bountiful - run: test -f ~/.m2/repository/org/bukkit/craftbukkit/1.8.8-R0.1-SNAPSHOT/craftbukkit-1.8.8-R0.1-SNAPSHOT.jar && echo "::set-output name=sucess::true" + run: mkdir BuildTools + - name: Download BuildTools + if: steps.cache.outputs.cache-hit != 'true' + run: wget -O BuildTools/BuildTools.jar https://hub.spigotmc.org/jenkins/job/BuildTools/lastSuccessfulBuild/artifact/target/BuildTools.jar - name: 1.8.8 - if: steps.bountiful.outputs.sucess != 'true' + if: steps.cache.outputs.cache-hit != 'true' run: cd BuildTools && java -jar BuildTools.jar --rev 1.8.8 - - name: Test 1.9.4 - id: combat - run: test -f ~/.m2/repository/org/bukkit/craftbukkit/1.9.4-R0.1-SNAPSHOT/craftbukkit-1.9.4-R0.1-SNAPSHOT.jar && echo "::set-output name=sucess::true" - name: 1.9.4 - if: steps.combat.outputs.sucess != 'true' + if: steps.cache.outputs.cache-hit != 'true' run: cd BuildTools && java -jar BuildTools.jar --rev 1.9.4 - - name: Test 1.10.2 - id: frostburn - run: test -f ~/.m2/repository/org/bukkit/craftbukkit/1.10.2-R0.1-SNAPSHOT/craftbukkit-1.10.2-R0.1-SNAPSHOT.jar && echo "::set-output name=sucess::true" - name: 1.10.2 - if: steps.frostburn.outputs.sucess != 'true' + if: steps.cache.outputs.cache-hit != 'true' run: cd BuildTools && java -jar BuildTools.jar --rev 1.10.2 - - name: Test 1.11.2 - id: exploration - run: test -f ~/.m2/repository/org/bukkit/craftbukkit/1.11.2-R0.1-SNAPSHOT/craftbukkit-1.11.2-R0.1-SNAPSHOT.jar && echo "::set-output name=sucess::true" - name: 1.11.2 - if: steps.exploration.outputs.sucess != 'true' + if: steps.cache.outputs.cache-hit != 'true' run: cd BuildTools && java -jar BuildTools.jar --rev 1.11.2 - - name: Test 1.12.1 - id: color - run: test -f ~/.m2/repository/org/bukkit/craftbukkit/1.12.1-R0.1-SNAPSHOT/craftbukkit-1.12.1-R0.1-SNAPSHOT.jar && echo "::set-output name=sucess::true" - name: 1.12.1 - if: steps.color.outputs.sucess != 'true' + if: steps.cache.outputs.cache-hit != 'true' run: cd BuildTools && java -jar BuildTools.jar --rev 1.12.1 - - name: Test 1.13.2 - id: aquatic - run: test -f ~/.m2/repository/org/bukkit/craftbukkit/1.13.2-R0.1-SNAPSHOT/craftbukkit-1.13.2-R0.1-SNAPSHOT.jar && echo "::set-output name=sucess::true" - name: 1.13.2 - if: steps.aquatic.outputs.sucess != 'true' + if: steps.cache.outputs.cache-hit != 'true' run: cd BuildTools && java -jar BuildTools.jar --rev 1.13.2 - - name: Test 1.14.4 - id: pillage - run: test -f ~/.m2/repository/org/bukkit/craftbukkit/1.14.4-R0.1-SNAPSHOT/craftbukkit-1.14.4-R0.1-SNAPSHOT.jar && echo "::set-output name=sucess::true" - name: 1.14.4 - if: steps.pillage.outputs.sucess != 'true' + if: steps.cache.outputs.cache-hit != 'true' run: cd BuildTools && java -jar BuildTools.jar --rev 1.14.4 --compile craftbukkit - - name: Test 1.15.0 - id: bees - run: test -f ~/.m2/repository/org/bukkit/craftbukkit/1.15-R0.1-SNAPSHOT/craftbukkit-1.15-R0.1-SNAPSHOT.jar && echo "::set-output name=sucess::true" - name: 1.15.0 - if: steps.bees.outputs.sucess != 'true' + if: steps.cache.outputs.cache-hit != 'true' run: cd BuildTools && java -jar BuildTools.jar --rev 1.15 --compile craftbukkit - - name: Test 1.16.1 - id: nether - run: test -f ~/.m2/repository/org/bukkit/craftbukkit/1.16.1-R0.1-SNAPSHOT/craftbukkit-1.16.1-R0.1-SNAPSHOT.jar && echo "::set-output name=sucess::true" - name: 1.16.1 - if: steps.nether.outputs.sucess != 'true' + if: steps.cache.outputs.cache-hit != 'true' run: cd BuildTools && java -jar BuildTools.jar --rev 1.16.1 --compile craftbukkit - - name: Test 1.16.3 - id: nether2 - run: test -f ~/.m2/repository/org/bukkit/craftbukkit/1.16.3-R0.1-SNAPSHOT/craftbukkit-1.16.3-R0.1-SNAPSHOT.jar && echo "::set-output name=sucess::true" - name: 1.16.3 - if: steps.nether2.outputs.sucess != 'true' + if: steps.cache.outputs.cache-hit != 'true' run: cd BuildTools && java -jar BuildTools.jar --rev 1.16.2 --compile craftbukkit - name: Build with Maven From 3458277692d77d86ea70a70353ce984992c1e58b Mon Sep 17 00:00:00 2001 From: TylerS1066 Date: Tue, 22 Sep 2020 10:08:57 -0500 Subject: [PATCH 232/304] Update maven.yml --- .github/workflows/maven.yml | 67 ++++++++++++++++++++++++++++--------- 1 file changed, 52 insertions(+), 15 deletions(-) diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml index 498bfda48..30d144fed 100644 --- a/.github/workflows/maven.yml +++ b/.github/workflows/maven.yml @@ -17,45 +17,82 @@ jobs: uses: actions/cache@v2 with: path: ~/.m2 - key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }} + key: ${{ runner.os }}-m2 restore-keys: ${{ runner.os }}-m2 # Run Spigot BuildTools for NMS if required - name: Setup BuildTools if: steps.cache.outputs.cache-hit != 'true' - run: mkdir BuildTools - - name: Download BuildTools - if: steps.cache.outputs.cache-hit != 'true' - run: wget -O BuildTools/BuildTools.jar https://hub.spigotmc.org/jenkins/job/BuildTools/lastSuccessfulBuild/artifact/target/BuildTools.jar + run: mkdir BuildTools && wget -O BuildTools/BuildTools.jar https://hub.spigotmc.org/jenkins/job/BuildTools/lastSuccessfulBuild/artifact/target/BuildTools.jar + +# EXAMPLE - Copy/paste as required to add version support to CI +# - name: Test [version] +# id: [version name] +# run: test -f ~/.m2/repository/org/bukkit/craftbukkit/[NMS version]/craftbukkit-[NMS version].jar && echo "::set-output name=sucess::true" +# - name: [version] +# if: steps.frostburn.outputs.sucess != 'true' +# run: cd BuildTools && java -jar BuildTools.jar --rev [version] + - run: ls ~/.m2/repository/org/bukkit/craftbukkit/ + + - name: Test 1.8.8 + id: bountiful + run: test -f ~/.m2/repository/org/bukkit/craftbukkit/1.8.8-R0.1-SNAPSHOT/craftbukkit-1.8.8-R0.1-SNAPSHOT.jar && echo "::set-output name=sucess::true" - name: 1.8.8 - if: steps.cache.outputs.cache-hit != 'true' + if: steps.bountiful.outputs.sucess != 'true' run: cd BuildTools && java -jar BuildTools.jar --rev 1.8.8 + - name: Test 1.9.4 + id: combat + run: test -f ~/.m2/repository/org/bukkit/craftbukkit/1.9.4-R0.1-SNAPSHOT/craftbukkit-1.9.4-R0.1-SNAPSHOT.jar && echo "::set-output name=sucess::true" - name: 1.9.4 - if: steps.cache.outputs.cache-hit != 'true' + if: steps.combat.outputs.sucess != 'true' run: cd BuildTools && java -jar BuildTools.jar --rev 1.9.4 + - name: Test 1.10.2 + id: frostburn + run: test -f ~/.m2/repository/org/bukkit/craftbukkit/1.10.2-R0.1-SNAPSHOT/craftbukkit-1.10.2-R0.1-SNAPSHOT.jar && echo "::set-output name=sucess::true" - name: 1.10.2 - if: steps.cache.outputs.cache-hit != 'true' + if: steps.frostburn.outputs.sucess != 'true' run: cd BuildTools && java -jar BuildTools.jar --rev 1.10.2 + - name: Test 1.11.2 + id: exploration + run: test -f ~/.m2/repository/org/bukkit/craftbukkit/1.11.2-R0.1-SNAPSHOT/craftbukkit-1.11.2-R0.1-SNAPSHOT.jar && echo "::set-output name=sucess::true" - name: 1.11.2 - if: steps.cache.outputs.cache-hit != 'true' + if: steps.exploration.outputs.sucess != 'true' run: cd BuildTools && java -jar BuildTools.jar --rev 1.11.2 + - name: Test 1.12.1 + id: color + run: test -f ~/.m2/repository/org/bukkit/craftbukkit/1.12.1-R0.1-SNAPSHOT/craftbukkit-1.12.1-R0.1-SNAPSHOT.jar && echo "::set-output name=sucess::true" - name: 1.12.1 - if: steps.cache.outputs.cache-hit != 'true' + if: steps.color.outputs.sucess != 'true' run: cd BuildTools && java -jar BuildTools.jar --rev 1.12.1 + - name: Test 1.13.2 + id: aquatic + run: test -f ~/.m2/repository/org/bukkit/craftbukkit/1.13.2-R0.1-SNAPSHOT/craftbukkit-1.13.2-R0.1-SNAPSHOT.jar && echo "::set-output name=sucess::true" - name: 1.13.2 - if: steps.cache.outputs.cache-hit != 'true' + if: steps.aquatic.outputs.sucess != 'true' run: cd BuildTools && java -jar BuildTools.jar --rev 1.13.2 + - name: Test 1.14.4 + id: pillage + run: test -f ~/.m2/repository/org/bukkit/craftbukkit/1.14.4-R0.1-SNAPSHOT/craftbukkit-1.14.4-R0.1-SNAPSHOT.jar && echo "::set-output name=sucess::true" - name: 1.14.4 - if: steps.cache.outputs.cache-hit != 'true' + if: steps.pillage.outputs.sucess != 'true' run: cd BuildTools && java -jar BuildTools.jar --rev 1.14.4 --compile craftbukkit + - name: Test 1.15.0 + id: bees + run: test -f ~/.m2/repository/org/bukkit/craftbukkit/1.15-R0.1-SNAPSHOT/craftbukkit-1.15-R0.1-SNAPSHOT.jar && echo "::set-output name=sucess::true" - name: 1.15.0 - if: steps.cache.outputs.cache-hit != 'true' + if: steps.bees.outputs.sucess != 'true' run: cd BuildTools && java -jar BuildTools.jar --rev 1.15 --compile craftbukkit + - name: Test 1.16.1 + id: nether + run: test -f ~/.m2/repository/org/bukkit/craftbukkit/1.16.1-R0.1-SNAPSHOT/craftbukkit-1.16.1-R0.1-SNAPSHOT.jar && echo "::set-output name=sucess::true" - name: 1.16.1 - if: steps.cache.outputs.cache-hit != 'true' + if: steps.nether.outputs.sucess != 'true' run: cd BuildTools && java -jar BuildTools.jar --rev 1.16.1 --compile craftbukkit + - name: Test 1.16.3 + id: nether2 + run: test -f ~/.m2/repository/org/bukkit/craftbukkit/1.16.3-R0.1-SNAPSHOT/craftbukkit-1.16.3-R0.1-SNAPSHOT.jar && echo "::set-output name=sucess::true" - name: 1.16.3 - if: steps.cache.outputs.cache-hit != 'true' + if: steps.nether2.outputs.sucess != 'true' run: cd BuildTools && java -jar BuildTools.jar --rev 1.16.2 --compile craftbukkit - name: Build with Maven From 3f7de8b32104b4725aa70ea8aa28187655c27def Mon Sep 17 00:00:00 2001 From: TylerS1066 Date: Tue, 22 Sep 2020 10:10:27 -0500 Subject: [PATCH 233/304] Update maven.yml --- .github/workflows/maven.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml index 30d144fed..d9b04efa1 100644 --- a/.github/workflows/maven.yml +++ b/.github/workflows/maven.yml @@ -32,7 +32,7 @@ jobs: # - name: [version] # if: steps.frostburn.outputs.sucess != 'true' # run: cd BuildTools && java -jar BuildTools.jar --rev [version] - - run: ls ~/.m2/repository/org/bukkit/craftbukkit/ + - run: test -d ~/.m2/repository/org/bukkit/craftbukkit/ && ls ~/.m2/repository/org/bukkit/craftbukkit/ - name: Test 1.8.8 id: bountiful From bd60481a624b6f8b6c16c8fa398f9a98a94edf3d Mon Sep 17 00:00:00 2001 From: TylerS1066 Date: Tue, 22 Sep 2020 10:11:04 -0500 Subject: [PATCH 234/304] Update maven.yml --- .github/workflows/maven.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml index d9b04efa1..63fd684f7 100644 --- a/.github/workflows/maven.yml +++ b/.github/workflows/maven.yml @@ -32,7 +32,7 @@ jobs: # - name: [version] # if: steps.frostburn.outputs.sucess != 'true' # run: cd BuildTools && java -jar BuildTools.jar --rev [version] - - run: test -d ~/.m2/repository/org/bukkit/craftbukkit/ && ls ~/.m2/repository/org/bukkit/craftbukkit/ +# - run: test -d ~/.m2/repository/org/bukkit/craftbukkit/ && ls ~/.m2/repository/org/bukkit/craftbukkit/ - name: Test 1.8.8 id: bountiful From 6e020edec739b2d87bae8e7e20b0c5b12fb4e342 Mon Sep 17 00:00:00 2001 From: TylerS1066 Date: Tue, 22 Sep 2020 10:13:56 -0500 Subject: [PATCH 235/304] Update maven.yml --- .github/workflows/maven.yml | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml index 63fd684f7..4864a8ec6 100644 --- a/.github/workflows/maven.yml +++ b/.github/workflows/maven.yml @@ -28,7 +28,7 @@ jobs: # EXAMPLE - Copy/paste as required to add version support to CI # - name: Test [version] # id: [version name] -# run: test -f ~/.m2/repository/org/bukkit/craftbukkit/[NMS version]/craftbukkit-[NMS version].jar && echo "::set-output name=sucess::true" +# run: test -f ~/.m2/repository/org/bukkit/craftbukkit/[NMS version]/craftbukkit-[NMS version].jar || echo "Failed to find [version]" && echo "::set-output name=sucess::true" # - name: [version] # if: steps.frostburn.outputs.sucess != 'true' # run: cd BuildTools && java -jar BuildTools.jar --rev [version] @@ -36,64 +36,64 @@ jobs: - name: Test 1.8.8 id: bountiful - run: test -f ~/.m2/repository/org/bukkit/craftbukkit/1.8.8-R0.1-SNAPSHOT/craftbukkit-1.8.8-R0.1-SNAPSHOT.jar && echo "::set-output name=sucess::true" + run: test -f ~/.m2/repository/org/bukkit/craftbukkit/1.8.8-R0.1-SNAPSHOT/craftbukkit-1.8.8-R0.1-SNAPSHOT.jar || echo "Failed to find 1.8.8" && echo "::set-output name=sucess::true" - name: 1.8.8 if: steps.bountiful.outputs.sucess != 'true' run: cd BuildTools && java -jar BuildTools.jar --rev 1.8.8 - name: Test 1.9.4 id: combat - run: test -f ~/.m2/repository/org/bukkit/craftbukkit/1.9.4-R0.1-SNAPSHOT/craftbukkit-1.9.4-R0.1-SNAPSHOT.jar && echo "::set-output name=sucess::true" + run: test -f ~/.m2/repository/org/bukkit/craftbukkit/1.9.4-R0.1-SNAPSHOT/craftbukkit-1.9.4-R0.1-SNAPSHOT.jar || echo "Failed to find 1.9.4" && echo "::set-output name=sucess::true" - name: 1.9.4 if: steps.combat.outputs.sucess != 'true' run: cd BuildTools && java -jar BuildTools.jar --rev 1.9.4 - name: Test 1.10.2 id: frostburn - run: test -f ~/.m2/repository/org/bukkit/craftbukkit/1.10.2-R0.1-SNAPSHOT/craftbukkit-1.10.2-R0.1-SNAPSHOT.jar && echo "::set-output name=sucess::true" + run: test -f ~/.m2/repository/org/bukkit/craftbukkit/1.10.2-R0.1-SNAPSHOT/craftbukkit-1.10.2-R0.1-SNAPSHOT.jar || echo "Failed to find 1.10.2" && echo "::set-output name=sucess::true" - name: 1.10.2 if: steps.frostburn.outputs.sucess != 'true' run: cd BuildTools && java -jar BuildTools.jar --rev 1.10.2 - name: Test 1.11.2 id: exploration - run: test -f ~/.m2/repository/org/bukkit/craftbukkit/1.11.2-R0.1-SNAPSHOT/craftbukkit-1.11.2-R0.1-SNAPSHOT.jar && echo "::set-output name=sucess::true" + run: test -f ~/.m2/repository/org/bukkit/craftbukkit/1.11.2-R0.1-SNAPSHOT/craftbukkit-1.11.2-R0.1-SNAPSHOT.jar || echo "Failed to find 1.11.2" && echo "::set-output name=sucess::true" - name: 1.11.2 if: steps.exploration.outputs.sucess != 'true' run: cd BuildTools && java -jar BuildTools.jar --rev 1.11.2 - name: Test 1.12.1 id: color - run: test -f ~/.m2/repository/org/bukkit/craftbukkit/1.12.1-R0.1-SNAPSHOT/craftbukkit-1.12.1-R0.1-SNAPSHOT.jar && echo "::set-output name=sucess::true" + run: test -f ~/.m2/repository/org/bukkit/craftbukkit/1.12.1-R0.1-SNAPSHOT/craftbukkit-1.12.1-R0.1-SNAPSHOT.jar || echo "Failed to find 1.12.1" && echo "::set-output name=sucess::true" - name: 1.12.1 if: steps.color.outputs.sucess != 'true' run: cd BuildTools && java -jar BuildTools.jar --rev 1.12.1 - name: Test 1.13.2 id: aquatic - run: test -f ~/.m2/repository/org/bukkit/craftbukkit/1.13.2-R0.1-SNAPSHOT/craftbukkit-1.13.2-R0.1-SNAPSHOT.jar && echo "::set-output name=sucess::true" + run: test -f ~/.m2/repository/org/bukkit/craftbukkit/1.13.2-R0.1-SNAPSHOT/craftbukkit-1.13.2-R0.1-SNAPSHOT.jar || echo "Failed to find 1.13.2" && echo "::set-output name=sucess::true" - name: 1.13.2 if: steps.aquatic.outputs.sucess != 'true' run: cd BuildTools && java -jar BuildTools.jar --rev 1.13.2 - name: Test 1.14.4 id: pillage - run: test -f ~/.m2/repository/org/bukkit/craftbukkit/1.14.4-R0.1-SNAPSHOT/craftbukkit-1.14.4-R0.1-SNAPSHOT.jar && echo "::set-output name=sucess::true" + run: test -f ~/.m2/repository/org/bukkit/craftbukkit/1.14.4-R0.1-SNAPSHOT/craftbukkit-1.14.4-R0.1-SNAPSHOT.jar || echo "Failed to find 1.14.4" && echo "::set-output name=sucess::true" - name: 1.14.4 if: steps.pillage.outputs.sucess != 'true' run: cd BuildTools && java -jar BuildTools.jar --rev 1.14.4 --compile craftbukkit - name: Test 1.15.0 id: bees - run: test -f ~/.m2/repository/org/bukkit/craftbukkit/1.15-R0.1-SNAPSHOT/craftbukkit-1.15-R0.1-SNAPSHOT.jar && echo "::set-output name=sucess::true" + run: test -f ~/.m2/repository/org/bukkit/craftbukkit/1.15-R0.1-SNAPSHOT/craftbukkit-1.15-R0.1-SNAPSHOT.jar || echo "Failed to find 1.15.0" && echo "::set-output name=sucess::true" - name: 1.15.0 if: steps.bees.outputs.sucess != 'true' run: cd BuildTools && java -jar BuildTools.jar --rev 1.15 --compile craftbukkit - name: Test 1.16.1 id: nether - run: test -f ~/.m2/repository/org/bukkit/craftbukkit/1.16.1-R0.1-SNAPSHOT/craftbukkit-1.16.1-R0.1-SNAPSHOT.jar && echo "::set-output name=sucess::true" + run: test -f ~/.m2/repository/org/bukkit/craftbukkit/1.16.1-R0.1-SNAPSHOT/craftbukkit-1.16.1-R0.1-SNAPSHOT.jar || echo "Failed to find 1.16.1" && echo "::set-output name=sucess::true" - name: 1.16.1 if: steps.nether.outputs.sucess != 'true' run: cd BuildTools && java -jar BuildTools.jar --rev 1.16.1 --compile craftbukkit - name: Test 1.16.3 id: nether2 - run: test -f ~/.m2/repository/org/bukkit/craftbukkit/1.16.3-R0.1-SNAPSHOT/craftbukkit-1.16.3-R0.1-SNAPSHOT.jar && echo "::set-output name=sucess::true" + run: test -f ~/.m2/repository/org/bukkit/craftbukkit/1.16.3-R0.1-SNAPSHOT/craftbukkit-1.16.3-R0.1-SNAPSHOT.jar || echo "Failed to find 1.16.3" && echo "::set-output name=sucess::true" - name: 1.16.3 if: steps.nether2.outputs.sucess != 'true' - run: cd BuildTools && java -jar BuildTools.jar --rev 1.16.2 --compile craftbukkit + run: cd BuildTools && java -jar BuildTools.jar --rev 1.16.3 --compile craftbukkit - name: Build with Maven run: mvn -B package --file pom.xml From 4e937d6201438c5d433c56186c77dedf995fb4f1 Mon Sep 17 00:00:00 2001 From: TylerS1066 Date: Tue, 22 Sep 2020 10:15:37 -0500 Subject: [PATCH 236/304] Update maven.yml --- .github/workflows/maven.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml index 4864a8ec6..343526443 100644 --- a/.github/workflows/maven.yml +++ b/.github/workflows/maven.yml @@ -36,7 +36,7 @@ jobs: - name: Test 1.8.8 id: bountiful - run: test -f ~/.m2/repository/org/bukkit/craftbukkit/1.8.8-R0.1-SNAPSHOT/craftbukkit-1.8.8-R0.1-SNAPSHOT.jar || echo "Failed to find 1.8.8" && echo "::set-output name=sucess::true" + run: test -f ~/.m2/repository/org/bukkit/craftbukkit/1.8.8-R0.1-SNAPSHOT/craftbukkit-1.8.8-R0.1-SNAPSHOT.jar && echo "::set-output name=sucess::true" || echo "::set-output name=sucess::false" - name: 1.8.8 if: steps.bountiful.outputs.sucess != 'true' run: cd BuildTools && java -jar BuildTools.jar --rev 1.8.8 From b6d19d5eafca0d56354a61b8ec517e98ab2fbc8b Mon Sep 17 00:00:00 2001 From: TylerS1066 Date: Tue, 22 Sep 2020 10:20:41 -0500 Subject: [PATCH 237/304] Update maven.yml --- .github/workflows/maven.yml | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml index 343526443..52b86bf5e 100644 --- a/.github/workflows/maven.yml +++ b/.github/workflows/maven.yml @@ -28,7 +28,7 @@ jobs: # EXAMPLE - Copy/paste as required to add version support to CI # - name: Test [version] # id: [version name] -# run: test -f ~/.m2/repository/org/bukkit/craftbukkit/[NMS version]/craftbukkit-[NMS version].jar || echo "Failed to find [version]" && echo "::set-output name=sucess::true" +# run: test -f ~/.m2/repository/org/bukkit/craftbukkit/[NMS version]/craftbukkit-[NMS version].jar && echo "::set-output name=sucess::true" || echo "::set-output name=sucess::false" # - name: [version] # if: steps.frostburn.outputs.sucess != 'true' # run: cd BuildTools && java -jar BuildTools.jar --rev [version] @@ -42,55 +42,55 @@ jobs: run: cd BuildTools && java -jar BuildTools.jar --rev 1.8.8 - name: Test 1.9.4 id: combat - run: test -f ~/.m2/repository/org/bukkit/craftbukkit/1.9.4-R0.1-SNAPSHOT/craftbukkit-1.9.4-R0.1-SNAPSHOT.jar || echo "Failed to find 1.9.4" && echo "::set-output name=sucess::true" + run: test -f ~/.m2/repository/org/bukkit/craftbukkit/1.9.4-R0.1-SNAPSHOT/craftbukkit-1.9.4-R0.1-SNAPSHOT.jar && echo "::set-output name=sucess::true" || echo "::set-output name=sucess::false" - name: 1.9.4 if: steps.combat.outputs.sucess != 'true' run: cd BuildTools && java -jar BuildTools.jar --rev 1.9.4 - name: Test 1.10.2 id: frostburn - run: test -f ~/.m2/repository/org/bukkit/craftbukkit/1.10.2-R0.1-SNAPSHOT/craftbukkit-1.10.2-R0.1-SNAPSHOT.jar || echo "Failed to find 1.10.2" && echo "::set-output name=sucess::true" + run: test -f ~/.m2/repository/org/bukkit/craftbukkit/1.10.2-R0.1-SNAPSHOT/craftbukkit-1.10.2-R0.1-SNAPSHOT.jar && echo "::set-output name=sucess::true" || echo "::set-output name=sucess::false" - name: 1.10.2 if: steps.frostburn.outputs.sucess != 'true' run: cd BuildTools && java -jar BuildTools.jar --rev 1.10.2 - name: Test 1.11.2 id: exploration - run: test -f ~/.m2/repository/org/bukkit/craftbukkit/1.11.2-R0.1-SNAPSHOT/craftbukkit-1.11.2-R0.1-SNAPSHOT.jar || echo "Failed to find 1.11.2" && echo "::set-output name=sucess::true" + run: test -f ~/.m2/repository/org/bukkit/craftbukkit/1.11.2-R0.1-SNAPSHOT/craftbukkit-1.11.2-R0.1-SNAPSHOT.jar && echo "::set-output name=sucess::true" || echo "::set-output name=sucess::false" - name: 1.11.2 if: steps.exploration.outputs.sucess != 'true' run: cd BuildTools && java -jar BuildTools.jar --rev 1.11.2 - name: Test 1.12.1 id: color - run: test -f ~/.m2/repository/org/bukkit/craftbukkit/1.12.1-R0.1-SNAPSHOT/craftbukkit-1.12.1-R0.1-SNAPSHOT.jar || echo "Failed to find 1.12.1" && echo "::set-output name=sucess::true" + run: test -f ~/.m2/repository/org/bukkit/craftbukkit/1.12.1-R0.1-SNAPSHOT/craftbukkit-1.12.1-R0.1-SNAPSHOT.jar && echo "::set-output name=sucess::true" || echo "::set-output name=sucess::false" - name: 1.12.1 if: steps.color.outputs.sucess != 'true' run: cd BuildTools && java -jar BuildTools.jar --rev 1.12.1 - name: Test 1.13.2 id: aquatic - run: test -f ~/.m2/repository/org/bukkit/craftbukkit/1.13.2-R0.1-SNAPSHOT/craftbukkit-1.13.2-R0.1-SNAPSHOT.jar || echo "Failed to find 1.13.2" && echo "::set-output name=sucess::true" + run: test -f ~/.m2/repository/org/bukkit/craftbukkit/1.13.2-R0.1-SNAPSHOT/craftbukkit-1.13.2-R0.1-SNAPSHOT.jar && echo "::set-output name=sucess::true" || echo "::set-output name=sucess::false" - name: 1.13.2 if: steps.aquatic.outputs.sucess != 'true' run: cd BuildTools && java -jar BuildTools.jar --rev 1.13.2 - name: Test 1.14.4 id: pillage - run: test -f ~/.m2/repository/org/bukkit/craftbukkit/1.14.4-R0.1-SNAPSHOT/craftbukkit-1.14.4-R0.1-SNAPSHOT.jar || echo "Failed to find 1.14.4" && echo "::set-output name=sucess::true" + run: test -f ~/.m2/repository/org/bukkit/craftbukkit/1.14.4-R0.1-SNAPSHOT/craftbukkit-1.14.4-R0.1-SNAPSHOT.jar && echo "::set-output name=sucess::true" || echo "::set-output name=sucess::false" - name: 1.14.4 if: steps.pillage.outputs.sucess != 'true' run: cd BuildTools && java -jar BuildTools.jar --rev 1.14.4 --compile craftbukkit - name: Test 1.15.0 id: bees - run: test -f ~/.m2/repository/org/bukkit/craftbukkit/1.15-R0.1-SNAPSHOT/craftbukkit-1.15-R0.1-SNAPSHOT.jar || echo "Failed to find 1.15.0" && echo "::set-output name=sucess::true" + run: test -f ~/.m2/repository/org/bukkit/craftbukkit/1.15-R0.1-SNAPSHOT/craftbukkit-1.15-R0.1-SNAPSHOT.jar && echo "::set-output name=sucess::true" || echo "::set-output name=sucess::false" - name: 1.15.0 if: steps.bees.outputs.sucess != 'true' run: cd BuildTools && java -jar BuildTools.jar --rev 1.15 --compile craftbukkit - name: Test 1.16.1 id: nether - run: test -f ~/.m2/repository/org/bukkit/craftbukkit/1.16.1-R0.1-SNAPSHOT/craftbukkit-1.16.1-R0.1-SNAPSHOT.jar || echo "Failed to find 1.16.1" && echo "::set-output name=sucess::true" + run: test -f ~/.m2/repository/org/bukkit/craftbukkit/1.16.1-R0.1-SNAPSHOT/craftbukkit-1.16.1-R0.1-SNAPSHOT.jar && echo "::set-output name=sucess::true" || echo "::set-output name=sucess::false" - name: 1.16.1 if: steps.nether.outputs.sucess != 'true' run: cd BuildTools && java -jar BuildTools.jar --rev 1.16.1 --compile craftbukkit - name: Test 1.16.3 id: nether2 - run: test -f ~/.m2/repository/org/bukkit/craftbukkit/1.16.3-R0.1-SNAPSHOT/craftbukkit-1.16.3-R0.1-SNAPSHOT.jar || echo "Failed to find 1.16.3" && echo "::set-output name=sucess::true" + run: test -f ~/.m2/repository/org/bukkit/craftbukkit/1.16.3-R0.1-SNAPSHOT/craftbukkit-1.16.3-R0.1-SNAPSHOT.jar && echo "::set-output name=sucess::true" || echo "::set-output name=sucess::false" - name: 1.16.3 if: steps.nether2.outputs.sucess != 'true' run: cd BuildTools && java -jar BuildTools.jar --rev 1.16.3 --compile craftbukkit From 8e955fecb3e4827d11f68204f1eb5f620954c01a Mon Sep 17 00:00:00 2001 From: TylerS1066 Date: Tue, 22 Sep 2020 10:48:15 -0500 Subject: [PATCH 238/304] Update pom.xml --- modules/Movecraft/pom.xml | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/modules/Movecraft/pom.xml b/modules/Movecraft/pom.xml index a0834b804..27b7817e8 100644 --- a/modules/Movecraft/pom.xml +++ b/modules/Movecraft/pom.xml @@ -9,13 +9,10 @@ UTF-8 -<<<<<<< HEAD - - 7.0.0_for_1.8.8-1.16.2_beta_33 -======= - 7.0.0_beta_6 ->>>>>>> d85e113d2393a27b85a04cbe7b54210a7bab78e9 + + 7.0.0_for_1.8.8-1.16.2_beta_33 + spigot-repo From 3b7ada9720988737e1fadc91c1556edf12aecf3d Mon Sep 17 00:00:00 2001 From: TylerS1066 Date: Tue, 22 Sep 2020 11:25:02 -0500 Subject: [PATCH 239/304] Update maven.yml --- .github/workflows/maven.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml index 52b86bf5e..34f106908 100644 --- a/.github/workflows/maven.yml +++ b/.github/workflows/maven.yml @@ -90,10 +90,10 @@ jobs: run: cd BuildTools && java -jar BuildTools.jar --rev 1.16.1 --compile craftbukkit - name: Test 1.16.3 id: nether2 - run: test -f ~/.m2/repository/org/bukkit/craftbukkit/1.16.3-R0.1-SNAPSHOT/craftbukkit-1.16.3-R0.1-SNAPSHOT.jar && echo "::set-output name=sucess::true" || echo "::set-output name=sucess::false" + run: test -f ~/.m2/repository/org/bukkit/craftbukkit/1.16.2-R0.1-SNAPSHOT/craftbukkit-1.16.3-R0.1-SNAPSHOT.jar && echo "::set-output name=sucess::true" || echo "::set-output name=sucess::false" - name: 1.16.3 if: steps.nether2.outputs.sucess != 'true' - run: cd BuildTools && java -jar BuildTools.jar --rev 1.16.3 --compile craftbukkit + run: cd BuildTools && java -jar BuildTools.jar --rev 1.16.2 --compile craftbukkit - name: Build with Maven run: mvn -B package --file pom.xml From 639607059bd07c282488a153f9a93251be08e3ed Mon Sep 17 00:00:00 2001 From: TylerS1066 Date: Tue, 22 Sep 2020 12:03:07 -0500 Subject: [PATCH 240/304] Update maven.yml --- .github/workflows/maven.yml | 42 ++++++++++++++++++------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml index 34f106908..2aa22bd9b 100644 --- a/.github/workflows/maven.yml +++ b/.github/workflows/maven.yml @@ -34,64 +34,64 @@ jobs: # run: cd BuildTools && java -jar BuildTools.jar --rev [version] # - run: test -d ~/.m2/repository/org/bukkit/craftbukkit/ && ls ~/.m2/repository/org/bukkit/craftbukkit/ - - name: Test 1.8.8 + - name: Check 1.8.8 id: bountiful run: test -f ~/.m2/repository/org/bukkit/craftbukkit/1.8.8-R0.1-SNAPSHOT/craftbukkit-1.8.8-R0.1-SNAPSHOT.jar && echo "::set-output name=sucess::true" || echo "::set-output name=sucess::false" - - name: 1.8.8 + - name: Build 1.8.8 if: steps.bountiful.outputs.sucess != 'true' run: cd BuildTools && java -jar BuildTools.jar --rev 1.8.8 - - name: Test 1.9.4 + - name: Check 1.9.4 id: combat run: test -f ~/.m2/repository/org/bukkit/craftbukkit/1.9.4-R0.1-SNAPSHOT/craftbukkit-1.9.4-R0.1-SNAPSHOT.jar && echo "::set-output name=sucess::true" || echo "::set-output name=sucess::false" - - name: 1.9.4 + - name: Build 1.9.4 if: steps.combat.outputs.sucess != 'true' run: cd BuildTools && java -jar BuildTools.jar --rev 1.9.4 - - name: Test 1.10.2 + - name: Check 1.10.2 id: frostburn run: test -f ~/.m2/repository/org/bukkit/craftbukkit/1.10.2-R0.1-SNAPSHOT/craftbukkit-1.10.2-R0.1-SNAPSHOT.jar && echo "::set-output name=sucess::true" || echo "::set-output name=sucess::false" - - name: 1.10.2 + - name: Build 1.10.2 if: steps.frostburn.outputs.sucess != 'true' run: cd BuildTools && java -jar BuildTools.jar --rev 1.10.2 - - name: Test 1.11.2 + - name: Check 1.11.2 id: exploration run: test -f ~/.m2/repository/org/bukkit/craftbukkit/1.11.2-R0.1-SNAPSHOT/craftbukkit-1.11.2-R0.1-SNAPSHOT.jar && echo "::set-output name=sucess::true" || echo "::set-output name=sucess::false" - - name: 1.11.2 + - name: Build 1.11.2 if: steps.exploration.outputs.sucess != 'true' run: cd BuildTools && java -jar BuildTools.jar --rev 1.11.2 - - name: Test 1.12.1 + - name: Check 1.12.1 id: color run: test -f ~/.m2/repository/org/bukkit/craftbukkit/1.12.1-R0.1-SNAPSHOT/craftbukkit-1.12.1-R0.1-SNAPSHOT.jar && echo "::set-output name=sucess::true" || echo "::set-output name=sucess::false" - - name: 1.12.1 + - name: Build 1.12.1 if: steps.color.outputs.sucess != 'true' run: cd BuildTools && java -jar BuildTools.jar --rev 1.12.1 - - name: Test 1.13.2 + - name: Check 1.13.2 id: aquatic run: test -f ~/.m2/repository/org/bukkit/craftbukkit/1.13.2-R0.1-SNAPSHOT/craftbukkit-1.13.2-R0.1-SNAPSHOT.jar && echo "::set-output name=sucess::true" || echo "::set-output name=sucess::false" - - name: 1.13.2 + - name: Build 1.13.2 if: steps.aquatic.outputs.sucess != 'true' run: cd BuildTools && java -jar BuildTools.jar --rev 1.13.2 - - name: Test 1.14.4 + - name: Check 1.14.4 id: pillage run: test -f ~/.m2/repository/org/bukkit/craftbukkit/1.14.4-R0.1-SNAPSHOT/craftbukkit-1.14.4-R0.1-SNAPSHOT.jar && echo "::set-output name=sucess::true" || echo "::set-output name=sucess::false" - - name: 1.14.4 + - name: Build 1.14.4 if: steps.pillage.outputs.sucess != 'true' run: cd BuildTools && java -jar BuildTools.jar --rev 1.14.4 --compile craftbukkit - - name: Test 1.15.0 + - name: Check 1.15 id: bees run: test -f ~/.m2/repository/org/bukkit/craftbukkit/1.15-R0.1-SNAPSHOT/craftbukkit-1.15-R0.1-SNAPSHOT.jar && echo "::set-output name=sucess::true" || echo "::set-output name=sucess::false" - - name: 1.15.0 + - name: Build 1.15 if: steps.bees.outputs.sucess != 'true' run: cd BuildTools && java -jar BuildTools.jar --rev 1.15 --compile craftbukkit - - name: Test 1.16.1 + - name: Check 1.16.1 id: nether run: test -f ~/.m2/repository/org/bukkit/craftbukkit/1.16.1-R0.1-SNAPSHOT/craftbukkit-1.16.1-R0.1-SNAPSHOT.jar && echo "::set-output name=sucess::true" || echo "::set-output name=sucess::false" - - name: 1.16.1 + - name: Build 1.16.1 if: steps.nether.outputs.sucess != 'true' run: cd BuildTools && java -jar BuildTools.jar --rev 1.16.1 --compile craftbukkit - - name: Test 1.16.3 + - name: Check 1.16.2 id: nether2 - run: test -f ~/.m2/repository/org/bukkit/craftbukkit/1.16.2-R0.1-SNAPSHOT/craftbukkit-1.16.3-R0.1-SNAPSHOT.jar && echo "::set-output name=sucess::true" || echo "::set-output name=sucess::false" - - name: 1.16.3 + run: test -f ~/.m2/repository/org/bukkit/craftbukkit/1.16.2-R0.1-SNAPSHOT/craftbukkit-1.16.2-R0.1-SNAPSHOT.jar && echo "::set-output name=sucess::true" || echo "::set-output name=sucess::false" + - name: Build 1.16.2 if: steps.nether2.outputs.sucess != 'true' run: cd BuildTools && java -jar BuildTools.jar --rev 1.16.2 --compile craftbukkit From d7870d54e6e5866b502c24738db73205b36a0ccf Mon Sep 17 00:00:00 2001 From: TylerS1066 Date: Tue, 22 Sep 2020 12:14:09 -0500 Subject: [PATCH 241/304] Update maven.yml --- .github/workflows/maven.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml index 2aa22bd9b..54c577d9c 100644 --- a/.github/workflows/maven.yml +++ b/.github/workflows/maven.yml @@ -99,9 +99,7 @@ jobs: run: mvn -B package --file pom.xml - name: Stage jar - run: mkdir staging && cp target/Movecraft.jar staging - - name: Rename jar - run: mv staging/Movecraft.jar staging/Movecraft_$GITHUB_SHA.jar + run: mkdir staging && cp target/Movecraft.jar staging && mv staging/Movecraft.jar staging/Movecraft_$GITHUB_SHA.jar - name: Upload jar uses: actions/upload-artifact@v2 with: From 2c69553e187f3351d19952ac18cb2375517d4d37 Mon Sep 17 00:00:00 2001 From: TylerS1066 Date: Tue, 22 Sep 2020 12:26:14 -0500 Subject: [PATCH 242/304] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1ea776696..486b24908 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # Movecraft -[![Java CI]](https://github.com/eirik1996/Movecraft/workflows/Java%20CI/badge.svg?branch=master) +![Java CI](https://github.com/eirik1996/Movecraft/workflows/Java%20CI/badge.svg?branch=master) [![codebeat badge](https://codebeat.co/badges/77751ae4-80f7-460a-a225-0e3ae8cbbab1)](https://codebeat.co/projects/github-com-apdevteam-movecraft-master) [![Build Status](https://travis-ci.org/APDevTeam/Movecraft.svg?branch=master)](https://travis-ci.org/APDevTeam/Movecraft) From d90d7c7a8078c132c32581c29f554d43c3f13389 Mon Sep 17 00:00:00 2001 From: TylerS1066 Date: Tue, 22 Sep 2020 12:29:01 -0500 Subject: [PATCH 243/304] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 486b24908..23239b922 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ # Movecraft -![Java CI](https://github.com/eirik1996/Movecraft/workflows/Java%20CI/badge.svg?branch=master) +![Java CI](https://github.com/eirikh1996/Movecraft/workflows/Java%20CI/badge.svg?branch=master) [![codebeat badge](https://codebeat.co/badges/77751ae4-80f7-460a-a225-0e3ae8cbbab1)](https://codebeat.co/projects/github-com-apdevteam-movecraft-master) [![Build Status](https://travis-ci.org/APDevTeam/Movecraft.svg?branch=master)](https://travis-ci.org/APDevTeam/Movecraft) From 0b0d306ffa753463be37b26a061df5c2637d2c8d Mon Sep 17 00:00:00 2001 From: TylerS1066 Date: Tue, 22 Sep 2020 12:30:51 -0500 Subject: [PATCH 244/304] Update maven.yml --- .github/workflows/maven.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml index 54c577d9c..00131ef5d 100644 --- a/.github/workflows/maven.yml +++ b/.github/workflows/maven.yml @@ -22,7 +22,6 @@ jobs: # Run Spigot BuildTools for NMS if required - name: Setup BuildTools - if: steps.cache.outputs.cache-hit != 'true' run: mkdir BuildTools && wget -O BuildTools/BuildTools.jar https://hub.spigotmc.org/jenkins/job/BuildTools/lastSuccessfulBuild/artifact/target/BuildTools.jar # EXAMPLE - Copy/paste as required to add version support to CI From bb9b89b4098262d89e9b8a169b2ee236fcd757c5 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Tue, 6 Oct 2020 20:57:59 +0200 Subject: [PATCH 245/304] Fixed world-specific cruiseSkipBlocks --- .../movecraft/async/AsyncManager.java | 32 +++++++++---------- .../countercraft/movecraft/sign/CrewSign.java | 2 +- .../countercraft/movecraft/craft/Craft.java | 11 +++++++ 3 files changed, 28 insertions(+), 17 deletions(-) diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java index 3fa2ab729..f566d610c 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java @@ -422,7 +422,7 @@ private void processCruise() { continue; } long ticksElapsed = (System.currentTimeMillis() - pcraft.getLastCruiseUpdate()) / 50; - World w = pcraft.getW(); + World w = pcraft.getWorld(); // if the craft should go slower underwater, make // time pass more slowly there if (pcraft.getType().getHalfSpeedUnderwater() && pcraft.getHitBox().getMinY() < w.getSeaLevel()) @@ -477,59 +477,59 @@ private void processCruise() { // ascend if (pcraft.getCruiseDirection() == BlockFace.UP) { - dy = 1 + pcraft.getType().getVertCruiseSkipBlocks(); + dy = 1 + pcraft.getType().getVertCruiseSkipBlocks(w); } // descend if (pcraft.getCruiseDirection() == BlockFace.DOWN) { - dy = -1 - pcraft.getType().getVertCruiseSkipBlocks(); + dy = -1 - pcraft.getType().getVertCruiseSkipBlocks(w); if (pcraft.getHitBox().getMinY() <= w.getSeaLevel()) { dy = -1; } } else if (dive) { - dy = -((pcraft.getType().getCruiseSkipBlocks() + 1) >> 1); + dy = -((pcraft.getType().getCruiseSkipBlocks(w) + 1) >> 1); if (pcraft.getHitBox().getMinY() <= w.getSeaLevel()) { dy = -1; } } // ship faces west if (pcraft.getCruiseDirection() == BlockFace.WEST) { - dx = -1 - pcraft.getType().getCruiseSkipBlocks(); + dx = -1 - pcraft.getType().getCruiseSkipBlocks(w); if (bankRight) { - dz = (-1 - pcraft.getType().getCruiseSkipBlocks()) >> 1; + dz = (-1 - pcraft.getType().getCruiseSkipBlocks(w)) >> 1; } if (bankLeft) { - dz = (1 + pcraft.getType().getCruiseSkipBlocks()) >> 1; + dz = (1 + pcraft.getType().getCruiseSkipBlocks(w)) >> 1; } } // ship faces east if (pcraft.getCruiseDirection() == BlockFace.EAST) { - dx = 1 + pcraft.getType().getCruiseSkipBlocks(); + dx = 1 + pcraft.getType().getCruiseSkipBlocks(w); if (bankLeft) { - dz = (-1 - pcraft.getType().getCruiseSkipBlocks()) >> 1; + dz = (-1 - pcraft.getType().getCruiseSkipBlocks(w)) >> 1; } if (bankRight) { - dz = (1 + pcraft.getType().getCruiseSkipBlocks()) >> 1; + dz = (1 + pcraft.getType().getCruiseSkipBlocks(w)) >> 1; } } // ship faces north if (pcraft.getCruiseDirection() == BlockFace.NORTH) { - dz = -1 - pcraft.getType().getCruiseSkipBlocks(); + dz = -1 - pcraft.getType().getCruiseSkipBlocks(w); if (bankRight) { - dx = (1 + pcraft.getType().getCruiseSkipBlocks()) >> 1; + dx = (1 + pcraft.getType().getCruiseSkipBlocks(w)) >> 1; } if (bankLeft) { - dx = (-1 - pcraft.getType().getCruiseSkipBlocks()) >> 1; + dx = (-1 - pcraft.getType().getCruiseSkipBlocks(w)) >> 1; } } // ship faces south if (pcraft.getCruiseDirection() == BlockFace.SOUTH) { - dz = 1 + pcraft.getType().getCruiseSkipBlocks(); + dz = 1 + pcraft.getType().getCruiseSkipBlocks(w); if (bankLeft) { - dx = (1 + pcraft.getType().getCruiseSkipBlocks()) >> 1; + dx = (1 + pcraft.getType().getCruiseSkipBlocks(w)) >> 1; } if (bankRight) { - dx = (-1 - pcraft.getType().getCruiseSkipBlocks()) >> 1; + dx = (-1 - pcraft.getType().getCruiseSkipBlocks(w)) >> 1; } } if (pcraft.getType().getCruiseOnPilot()) { diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CrewSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CrewSign.java index fdeeaa04b..219f67751 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CrewSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CrewSign.java @@ -128,7 +128,7 @@ public final void onPlayerRespawn(PlayerRespawnEvent event) { boolean locationFound = false; for(int i = -1; i < 2; i++) { for(int j = -1; j < 2; j++) { - Location testLoc = new Location(craft.getW(), respawnLoc.getX()+i, respawnLoc.getY(), respawnLoc.getZ()+j); + Location testLoc = new Location(craft.getWorld(), respawnLoc.getX()+i, respawnLoc.getY(), respawnLoc.getZ()+j); if(testLoc.getBlock().getType().equals(Material.AIR)) { if(testLoc.getBlock().getRelative(BlockFace.UP).isEmpty() && !testLoc.getBlock().getRelative(BlockFace.DOWN).isEmpty()) { respawnLoc = testLoc; diff --git a/modules/api/src/main/java/net/countercraft/movecraft/craft/Craft.java b/modules/api/src/main/java/net/countercraft/movecraft/craft/Craft.java index 5a51aaa66..e59911b72 100644 --- a/modules/api/src/main/java/net/countercraft/movecraft/craft/Craft.java +++ b/modules/api/src/main/java/net/countercraft/movecraft/craft/Craft.java @@ -129,12 +129,23 @@ public CraftType getType() { return type; } + /** + * @deprecated use getWorld() instead + * + * @return the world the craft is in + */ @NotNull @Deprecated public World getW() { return world; } + /** + * + * Gets the world the craft is currently in + * + * @return the world the craft is in + */ @NotNull public World getWorld() { return world; From 0e4b049edfffea56c7c89aa7f088c9b7c30208d3 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Mon, 2 Nov 2020 09:47:11 +0100 Subject: [PATCH 246/304] Added gearshifts --- .../movecraft/listener/InteractListener.java | 52 ++++++++++--------- .../localisation/movecraftlang_en.properties | 2 + .../countercraft/movecraft/craft/Craft.java | 17 +++++- .../movecraft/craft/CraftType.java | 14 +++-- 4 files changed, 56 insertions(+), 29 deletions(-) diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/InteractListener.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/InteractListener.java index 7295659d6..ca453971a 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/InteractListener.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/InteractListener.java @@ -22,16 +22,21 @@ import net.countercraft.movecraft.config.Settings; import net.countercraft.movecraft.craft.CraftManager; import net.countercraft.movecraft.localisation.I18nSupport; +import org.bukkit.Bukkit; import org.bukkit.Material; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; import org.bukkit.event.block.Action; import org.bukkit.event.player.PlayerInteractEvent; +import org.bukkit.util.Vector; import java.util.HashMap; import java.util.Map; +import static java.lang.Math.abs; +import static java.lang.Math.rint; + public final class InteractListener implements Listener { private static final Map timeMap = new HashMap<>(); @@ -59,15 +64,9 @@ public void onPlayerInteractStick(PlayerInteractEvent event) { // if not in command of craft, don't process pilot tool clicks if (c == null) return; - -/* if( c.getCannonDirector()==event.getPlayer() ) // if the player is the cannon director, don't let them move the ship - return; - - if( c.getAADirector()==event.getPlayer() ) // if the player is the cannon director, don't let them move the ship - return; -*/ if (event.getAction() == Action.RIGHT_CLICK_AIR || event.getAction() == Action.RIGHT_CLICK_BLOCK) { - Craft craft = CraftManager.getInstance().getCraftByPlayer(event.getPlayer()); + final Player player = event.getPlayer(); + Craft craft = CraftManager.getInstance().getCraftByPlayer(player); if (event.getItem() == null || event.getItem().getTypeId() != Settings.PilotTool) { return; @@ -76,7 +75,21 @@ public void onPlayerInteractStick(PlayerInteractEvent event) { if (craft == null) { return; } - Long time = timeMap.get(event.getPlayer()); + int currentGear = craft.getCurrentGear(); + if (player.isSneaking()) { + final int gearShifts = craft.getType().getGearShifts(); + if (gearShifts == 1) { + player.sendMessage("Gearshift - Disabled for craft type"); + return; + } + currentGear++; + if (currentGear > gearShifts) + currentGear = 1; + player.sendMessage(I18nSupport.getInternationalisedString("Gearshift - Gear changed") + " " + currentGear + " / " + gearShifts); + craft.setCurrentGear(currentGear); + return; + } + Long time = timeMap.get(player); if (time != null) { long ticksElapsed = (System.currentTimeMillis() - time) / 50; @@ -85,7 +98,7 @@ public void onPlayerInteractStick(PlayerInteractEvent event) { if (craft.getType().getHalfSpeedUnderwater() && craft.getHitBox().getMinY() < craft.getW().getSeaLevel()) ticksElapsed = ticksElapsed >> 1; - if (Math.abs(ticksElapsed) < craft.getType().getTickCooldown(craft.getW())) { + if (abs(ticksElapsed) < craft.getType().getTickCooldown(craft.getW())) { return; } } @@ -114,21 +127,12 @@ public void onPlayerInteractStick(PlayerInteractEvent event) { // Player is onboard craft and right clicking float rotation = (float) Math.PI * event.getPlayer().getLocation().getYaw() / 180f; - float nx = -(float) Math.sin(rotation); - float nz = (float) Math.cos(rotation); - - int dx = (Math.abs(nx) >= 0.5 ? 1 : 0) * (int) Math.signum(nx); - int dz = (Math.abs(nz) > 0.5 ? 1 : 0) * (int) Math.signum(nz); - int dy; + final Vector direction = player.getLocation().getDirection(); + direction.multiply(currentGear); - float p = event.getPlayer().getLocation().getPitch(); - - dy = -(Math.abs(p) >= 25 ? 1 : 0) * (int) Math.signum(p); - - if (Math.abs(event.getPlayer().getLocation().getPitch()) >= 75) { - dx = 0; - dz = 0; - } + int dx = (int) rint(direction.getX()); + int dz = (int) rint(direction.getZ()); + int dy = (int) rint(direction.getY()); craft.translate(dx, dy, dz); timeMap.put(event.getPlayer(), System.currentTimeMillis()); diff --git a/modules/Movecraft/src/main/resources/localisation/movecraftlang_en.properties b/modules/Movecraft/src/main/resources/localisation/movecraftlang_en.properties index 6a55a2916..51730ff7c 100644 --- a/modules/Movecraft/src/main/resources/localisation/movecraftlang_en.properties +++ b/modules/Movecraft/src/main/resources/localisation/movecraftlang_en.properties @@ -81,6 +81,8 @@ Detection\ -\ Craft\ Type\ Cannot\ Be\ Named=Crafts of this type cannot be named Detection\ -\ ERROR\:\ Double\ chest\ found=Detection failed\! ERROR \: Double chest found Detection\ -\ Failed\ -\ Water\ contact\ required\ but\ not\ found=Detection failed\: Water contact required but not found Economy\ -\ Not\ Enough\ Money=You do not have enough money +Gearshift\ -\ Gear\ changed=Gear of craft changed. +Gearshift\ -\ Disabled\ for\ craft\ type=Gearshift is disabled for this craft type ManOverboard\ -\ No\ Craft\ Found=No valid craft to ManOverboard to. ManOverboard\ -\ Must\ Be\ Player=Only Players may use ManOverboard. ManOverboard\ -\ Distance\ Too\ Far=Distance to craft is too far. diff --git a/modules/api/src/main/java/net/countercraft/movecraft/craft/Craft.java b/modules/api/src/main/java/net/countercraft/movecraft/craft/Craft.java index 5786c6221..e6dc0c0d8 100644 --- a/modules/api/src/main/java/net/countercraft/movecraft/craft/Craft.java +++ b/modules/api/src/main/java/net/countercraft/movecraft/craft/Craft.java @@ -41,6 +41,7 @@ import java.util.UUID; import java.util.concurrent.atomic.AtomicBoolean; +import static java.lang.Math.max; public abstract class Craft { @@ -64,6 +65,7 @@ public abstract class Craft { private long origPilotTime; private long lastTeleportTime; private int lastDX, lastDY, lastDZ; + private int currentGear = 1; private double burningFuel; private boolean pilotLocked; private double pilotLockedX; @@ -358,7 +360,7 @@ public int getTickCooldown() { Material flyBlockMaterial = Material.getMaterial(type.getDynamicFlyBlock()); double count = materials.get(flyBlockMaterial); double woolRatio = count / hitBox.size(); - return Math.max((int)Math.round((20.0 * (type.getCruiseSkipBlocks(w) + 1)) / ((type.getDynamicFlyBlockSpeedFactor() * 1.5) * (woolRatio - .5) + (20.0 / type.getCruiseTickCooldown(w)) + 1)), 1); + return max((int)Math.round((20.0 * (type.getCruiseSkipBlocks(w) + 1)) / ((type.getDynamicFlyBlockSpeedFactor() * 1.5) * (woolRatio - .5) + (20.0 / type.getCruiseTickCooldown(w)) + 1)), 1); } if(type.getDynamicLagSpeedFactor() == 0.0 || type.getDynamicLagPowerFactor() == 0.0 || Math.abs(type.getDynamicLagPowerFactor()) > 1.0) @@ -378,7 +380,7 @@ public int getTickCooldown() { // Dynamic Lag Speed double speed = 20.0 * (type.getCruiseSkipBlocks(w) + 1.0) / (float)type.getCruiseTickCooldown(w); speed -= type.getDynamicLagSpeedFactor() * Math.pow(getMeanCruiseTime() * 1000.0, type.getDynamicLagPowerFactor()); - speed = Math.max(type.getDynamicLagMinSpeed(), speed); + speed = max(type.getDynamicLagMinSpeed(), speed); return (int)Math.round((20.0 * (type.getCruiseSkipBlocks(w) + 1.0)) / speed); //In theory, the chest penalty is not needed for a DynamicLag craft. } @@ -499,4 +501,15 @@ public long getLastTeleportTime() { public void setLastTeleportTime(long lastTeleportTime) { this.lastTeleportTime = lastTeleportTime; } + + public int getCurrentGear() { + return currentGear; + } + + public void setCurrentGear(int currentGear) { + if (currentGear > type.getGearShifts()) { + this.currentGear = type.getGearShifts(); + } + this.currentGear = max(currentGear, 1); + } } diff --git a/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java b/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java index 694c577b2..a0955bbeb 100644 --- a/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java +++ b/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java @@ -31,6 +31,8 @@ import java.io.InputStream; import java.util.*; +import static java.lang.Math.max; + final public class CraftType { private final boolean blockedByWater; private final boolean requireWaterContact; @@ -111,6 +113,7 @@ final public class CraftType { private final int teleportationCooldown; private final int gravityDropDistance; private final int gravityInclineDistance; + private final int gearShifts; private final Sound collisionSound; @SuppressWarnings("unchecked") @@ -178,10 +181,10 @@ public CraftType(File f) { smokeOnSink = integerFromObject(data.getOrDefault("smokeOnSink", 0)); explodeOnCrash = floatFromObject(data.getOrDefault("explodeOnCrash", 0F)); collisionExplosion = floatFromObject(data.getOrDefault("collisionExplosion", 0F)); - minHeightLimit = Math.max(0, integerFromObject(data.getOrDefault("minHeightLimit", 0))); + minHeightLimit = max(0, integerFromObject(data.getOrDefault("minHeightLimit", 0))); perWorldMinHeightLimit = new HashMap<>(); Map minHeightMap = stringToIntMapFromObject(data.getOrDefault("perWorldMinHeightLimit", new HashMap<>())); - minHeightMap.forEach((world, height) -> perWorldMinHeightLimit.put(world, Math.max(0, height))); + minHeightMap.forEach((world, height) -> perWorldMinHeightLimit.put(world, max(0, height))); double cruiseSpeed = doubleFromObject(data.getOrDefault("cruiseSpeed", 20.0 / tickCooldown)); cruiseTickCooldown = (int) Math.round((1.0 + cruiseSkipBlocks) * 20.0 / cruiseSpeed); @@ -242,7 +245,7 @@ public CraftType(File f) { moveEntities = (boolean) data.getOrDefault("moveEntities", true); onlyMovePlayers = (boolean) data.getOrDefault("onlyMovePlayers", true); useGravity = (boolean) data.getOrDefault("useGravity", false); - hoverLimit = Math.max(0, integerFromObject(data.getOrDefault("hoverLimit", 0))); + hoverLimit = max(0, integerFromObject(data.getOrDefault("hoverLimit", 0))); harvestBlocks = new ArrayList<>(); harvesterBladeBlocks = new ArrayList<>(); if (data.containsKey("harvestBlocks")) { @@ -343,6 +346,7 @@ public CraftType(File f) { List disabledWorlds = (List) data.getOrDefault("disableTeleportToWorlds", new ArrayList<>()); disableTeleportToWorlds.addAll(disabledWorlds); teleportationCooldown = integerFromObject(data.getOrDefault("teleportationCooldown", 0)); + gearShifts = max(integerFromObject(data.getOrDefault("gearShifts", 1)), 1); } private int integerFromObject(Object obj) { @@ -830,6 +834,10 @@ public int getTeleportationCooldown() { return teleportationCooldown; } + public int getGearShifts() { + return gearShifts; + } + private class TypeNotFoundException extends RuntimeException { public TypeNotFoundException(String s) { super(s); From 261881c6752162904e4580e9134bdb62cefafa53 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Mon, 2 Nov 2020 09:47:45 +0100 Subject: [PATCH 247/304] Added gearshifts --- .../countercraft/movecraft/listener/InteractListener.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/InteractListener.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/InteractListener.java index ca453971a..acb407787 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/InteractListener.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/InteractListener.java @@ -17,12 +17,11 @@ package net.countercraft.movecraft.listener; -import net.countercraft.movecraft.utils.MathUtils; -import net.countercraft.movecraft.craft.Craft; import net.countercraft.movecraft.config.Settings; +import net.countercraft.movecraft.craft.Craft; import net.countercraft.movecraft.craft.CraftManager; import net.countercraft.movecraft.localisation.I18nSupport; -import org.bukkit.Bukkit; +import net.countercraft.movecraft.utils.MathUtils; import org.bukkit.Material; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; From 5d351f538c8e5703bb9472452d4922d3bcd5b47c Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Mon, 2 Nov 2020 18:37:51 +0100 Subject: [PATCH 248/304] Some fixes to gearshifts and made gearshifts affect cruise as well --- .../countercraft/movecraft/async/AsyncManager.java | 4 ++++ .../movecraft/listener/InteractListener.java | 11 ++++++++--- 2 files changed, 12 insertions(+), 3 deletions(-) diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java index bb996e452..4518722f2 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java @@ -477,6 +477,10 @@ private void processCruise() { if (pcraft.getType().getCruiseOnPilot()) { dy = pcraft.getType().getCruiseOnPilotVertMove(); } + final int gearshift = pcraft.getCurrentGear(); + dx *= gearshift; + dy *= gearshift; + dz *= gearshift; pcraft.translate(dx, dy, dz); pcraft.setLastDX(dx); pcraft.setLastDZ(dz); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/InteractListener.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/InteractListener.java index acb407787..04e8c770e 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/InteractListener.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/InteractListener.java @@ -22,6 +22,7 @@ import net.countercraft.movecraft.craft.CraftManager; import net.countercraft.movecraft.localisation.I18nSupport; import net.countercraft.movecraft.utils.MathUtils; +import org.bukkit.Bukkit; import org.bukkit.Material; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; @@ -75,10 +76,10 @@ public void onPlayerInteractStick(PlayerInteractEvent event) { return; } int currentGear = craft.getCurrentGear(); - if (player.isSneaking()) { + if (player.isSneaking() && !craft.getPilotLocked()) { final int gearShifts = craft.getType().getGearShifts(); if (gearShifts == 1) { - player.sendMessage("Gearshift - Disabled for craft type"); + player.sendMessage(I18nSupport.getInternationalisedString("Gearshift - Disabled for craft type")); return; } currentGear++; @@ -124,14 +125,18 @@ public void onPlayerInteractStick(PlayerInteractEvent event) { return; } // Player is onboard craft and right clicking - float rotation = (float) Math.PI * event.getPlayer().getLocation().getYaw() / 180f; final Vector direction = player.getLocation().getDirection(); + float p = event.getPlayer().getLocation().getPitch(); + + direction.setY(-(Math.abs(p) >= 25 ? 1 : 0) * (int) Math.signum(p)); + direction.normalize(); direction.multiply(currentGear); int dx = (int) rint(direction.getX()); int dz = (int) rint(direction.getZ()); int dy = (int) rint(direction.getY()); + Bukkit.broadcastMessage(String.format("(%d, %d, %d)", dx, dy, dz)); craft.translate(dx, dy, dz); timeMap.put(event.getPlayer(), System.currentTimeMillis()); From 1d56273961f49ad6ee6c03c14339a38069b7fdb5 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Thu, 5 Nov 2020 21:38:55 +0100 Subject: [PATCH 249/304] Fixes and 1.16.4 compat --- modules/Movecraft/dependency-reduced-pom.xml | 8 +- modules/Movecraft/pom.xml | 14 +- .../movecraft/listener/InteractListener.java | 2 +- .../movecraft/sign/TeleportSign.java | 5 +- .../countercraft/movecraft/craft/Craft.java | 2 +- modules/v1_16_R3/pom.xml | 58 +++ .../compat/v1_16_R3/IWorldHandler.java | 442 ++++++++++++++++++ .../compat/v1_16_R3/NextTickProvider.java | 68 +++ pom.xml | 1 + 9 files changed, 593 insertions(+), 7 deletions(-) create mode 100644 modules/v1_16_R3/pom.xml create mode 100644 modules/v1_16_R3/src/main/java/net/countercraft/movecraft/compat/v1_16_R3/IWorldHandler.java create mode 100644 modules/v1_16_R3/src/main/java/net/countercraft/movecraft/compat/v1_16_R3/NextTickProvider.java diff --git a/modules/Movecraft/dependency-reduced-pom.xml b/modules/Movecraft/dependency-reduced-pom.xml index e9bcc7eb5..0f2cb062f 100644 --- a/modules/Movecraft/dependency-reduced-pom.xml +++ b/modules/Movecraft/dependency-reduced-pom.xml @@ -4,7 +4,7 @@ net.countercraft movecraft Movecraft - 7.0.0_for_1.8.8-1.16.2_beta_33 + 7.0.0_for_1.8.8-1.16.2_beta_34 http://github.com/apdevteam/Movecraft src/main/java @@ -146,6 +146,12 @@ ** + + net.countercraft:movecraft-v1_16_R3 + + ** + + diff --git a/modules/Movecraft/pom.xml b/modules/Movecraft/pom.xml index 27b7817e8..507671fb5 100644 --- a/modules/Movecraft/pom.xml +++ b/modules/Movecraft/pom.xml @@ -11,7 +11,7 @@ - 7.0.0_for_1.8.8-1.16.2_beta_33 + 7.0.0_for_1.8.8-1.16.2_beta_34 @@ -37,6 +37,12 @@ + + net.countercraft + movecraft-v1_16_R3 + v1_16_R3 + jar + net.countercraft movecraft-v1_16_R2 @@ -362,6 +368,12 @@ ** + + net.countercraft:movecraft-v1_16_R3 + + ** + + diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/InteractListener.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/InteractListener.java index 82b8f0124..7722883c5 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/InteractListener.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/InteractListener.java @@ -140,7 +140,7 @@ public void onPlayerInteractStick(PlayerInteractEvent event) { float p = event.getPlayer().getLocation().getPitch(); direction.setY(-(Math.abs(p) >= 25 ? 1 : 0) * (int) Math.signum(p)); - direction.normalize(); + //direction.normalize(); direction.multiply(currentGear); int dx = (int) rint(direction.getX()); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/TeleportSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/TeleportSign.java index 6785da190..57444fa81 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/TeleportSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/TeleportSign.java @@ -6,7 +6,6 @@ import net.countercraft.movecraft.utils.SignUtils; import org.bukkit.Bukkit; import org.bukkit.ChatColor; -import org.bukkit.Material; import org.bukkit.World; import org.bukkit.block.Block; import org.bukkit.block.Sign; @@ -61,9 +60,9 @@ public final void onSignClick(PlayerInteractEvent event) { if (c == null || !c.getType().getCanTeleport()) { return; } - long timeSinceLastTeleport = System.currentTimeMillis() - c.getLastTeleportTime(); + long timeSinceLastTeleport = (System.currentTimeMillis() - c.getLastTeleportTime()) / 1000; if (c.getType().getTeleportationCooldown() > 0 && timeSinceLastTeleport < c.getType().getTeleportationCooldown()) { - event.getPlayer().sendMessage(String.format(I18nSupport.getInternationalisedString("Teleportation - Cooldown active"), timeSinceLastTeleport)); + event.getPlayer().sendMessage(String.format(I18nSupport.getInternationalisedString("Teleportation - Cooldown active"), c.getType().getTeleportationCooldown() - timeSinceLastTeleport)); return; } int dx = tX - sign.getX(); diff --git a/modules/api/src/main/java/net/countercraft/movecraft/craft/Craft.java b/modules/api/src/main/java/net/countercraft/movecraft/craft/Craft.java index e98742113..2de6fa1f3 100644 --- a/modules/api/src/main/java/net/countercraft/movecraft/craft/Craft.java +++ b/modules/api/src/main/java/net/countercraft/movecraft/craft/Craft.java @@ -81,7 +81,7 @@ public abstract class Craft { @NotNull private final HashMap crewSigns = new HashMap<>(); @NotNull private String name = ""; private boolean translating; - private int currentGear; + private int currentGear = 1; public Craft(@NotNull CraftType type, @NotNull World world) { this.type = type; diff --git a/modules/v1_16_R3/pom.xml b/modules/v1_16_R3/pom.xml new file mode 100644 index 000000000..28e802f67 --- /dev/null +++ b/modules/v1_16_R3/pom.xml @@ -0,0 +1,58 @@ + + + + movecraft-parent + net.countercraft + parent + ../../pom.xml + + 4.0.0 + + movecraft-v1_16_R3 + Movecraft-v1_16_R3 + v1_16_R3 + jar + + + org.bukkit + craftbukkit + 1.16.4-R0.1-SNAPSHOT + + + net.countercraft + movecraft-api + API + jar + + + + src/main/java + + + org.apache.maven.plugins + maven-compiler-plugin + 3.7.0 + + + net/countercraft/movecraft/compat/v1_16_R3/** + + 1.8 + 1.8 + + + + org.apache.maven.plugins + maven-jar-plugin + 2.4 + + + net/countercraft/movecraft/compat/v1_16_R3/** + + + + + + + \ No newline at end of file diff --git a/modules/v1_16_R3/src/main/java/net/countercraft/movecraft/compat/v1_16_R3/IWorldHandler.java b/modules/v1_16_R3/src/main/java/net/countercraft/movecraft/compat/v1_16_R3/IWorldHandler.java new file mode 100644 index 000000000..6454e594c --- /dev/null +++ b/modules/v1_16_R3/src/main/java/net/countercraft/movecraft/compat/v1_16_R3/IWorldHandler.java @@ -0,0 +1,442 @@ +package net.countercraft.movecraft.compat.v1_16_R3; + +import net.countercraft.movecraft.MovecraftLocation; +import net.countercraft.movecraft.Rotation; +import net.countercraft.movecraft.WorldHandler; +import net.countercraft.movecraft.config.Settings; +import net.countercraft.movecraft.craft.Craft; +import net.countercraft.movecraft.utils.CollectionUtils; +import net.countercraft.movecraft.utils.MathUtils; +import net.minecraft.server.v1_16_R3.*; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.block.data.BlockData; +import org.bukkit.craftbukkit.v1_16_R3.CraftWorld; +import org.bukkit.craftbukkit.v1_16_R3.block.data.CraftBlockData; +import org.bukkit.craftbukkit.v1_16_R3.util.CraftMagicNumbers; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.*; + +public class IWorldHandler extends WorldHandler { + private static final EnumBlockRotation ROTATION[]; + static { + ROTATION = new EnumBlockRotation[3]; + ROTATION[Rotation.NONE.ordinal()] = EnumBlockRotation.NONE; + ROTATION[Rotation.CLOCKWISE.ordinal()] = EnumBlockRotation.CLOCKWISE_90; + ROTATION[Rotation.ANTICLOCKWISE.ordinal()] = EnumBlockRotation.COUNTERCLOCKWISE_90; + + } + private final NextTickProvider tickProvider = new NextTickProvider(); + private final HashMap> bMap = new HashMap<>(); + private MethodHandle internalTeleportMH; + + public IWorldHandler() { + MethodHandles.Lookup lookup = MethodHandles.lookup(); + Method teleport = null; + try { + teleport = PlayerConnection.class.getDeclaredMethod("internalTeleport", double.class, double.class, double.class, float.class, float.class, Set.class); + teleport.setAccessible(true); + internalTeleportMH = lookup.unreflect(teleport); + + } catch (NoSuchMethodException | IllegalAccessException e) { + e.printStackTrace(); + } + } + + @Override + public void rotateCraft(@NotNull Craft craft, @NotNull MovecraftLocation originPoint, @NotNull Rotation rotation) { + //******************************************* + //* Step one: Convert to Positions * + //******************************************* + HashMap rotatedPositions = new HashMap<>(); + Rotation counterRotation = rotation == Rotation.CLOCKWISE ? Rotation.ANTICLOCKWISE : Rotation.CLOCKWISE; + for(MovecraftLocation newLocation : craft.getHitBox()){ + rotatedPositions.put(locationToPosition(MathUtils.rotateVec(counterRotation, newLocation.subtract(originPoint)).add(originPoint)),locationToPosition(newLocation)); + } + //******************************************* + //* Step two: Get the tiles * + //******************************************* + WorldServer nativeWorld = ((CraftWorld) craft.getWorld()).getHandle(); + List tiles = new ArrayList<>(); + //get the tiles + for(BlockPosition position : rotatedPositions.keySet()){ + //TileEntity tile = nativeWorld.removeTileEntity(position); + TileEntity tile = removeTileEntity(nativeWorld,position); + if(tile == null) + continue; + tile.a(ROTATION[rotation.ordinal()]); + //get the nextTick to move with the tile + tiles.add(new TileHolder(tile, tickProvider.getNextTick(nativeWorld, position), position)); + } + + //******************************************* + //* Step three: Translate all the blocks * + //******************************************* + // blockedByWater=false means an ocean-going vessel + //TODO: Simplify + //TODO: go by chunks + //TODO: Don't move unnecessary blocks + //get the blocks and rotate them + HashMap blockData = new HashMap<>(); + for(BlockPosition position : rotatedPositions.keySet()){ + + blockData.put(position,nativeWorld.getType(position).a(ROTATION[rotation.ordinal()])); + } + HashMap redstoneComponents = new HashMap<>(); + //create the new block + for(Map.Entry entry : blockData.entrySet()) { + final BlockPosition newPosition = rotatedPositions.get(entry.getKey()); + final IBlockData iBlockData = entry.getValue(); + if (nativeWorld.getTileEntity(newPosition) != null) { + removeTileEntity(nativeWorld, newPosition); + } + if (isRedstoneComponent(iBlockData)) + redstoneComponents.put(newPosition, iBlockData); + + setBlockFast(nativeWorld, newPosition, iBlockData); + } + + + //******************************************* + //* Step four: replace all the tiles * + //******************************************* + //TODO: go by chunks + for(TileHolder tileHolder : tiles){ + moveTileEntity(nativeWorld, rotatedPositions.get(tileHolder.getTilePosition()),tileHolder.getTile()); + if(tileHolder.getNextTick()==null) + continue; + final long currentTime = nativeWorld.worldData.getTime(); + nativeWorld.getBlockTickList().a(rotatedPositions.get(tileHolder.getNextTick().a), tileHolder.getNextTick().b(), (int) (tileHolder.getNextTick().b - currentTime), tileHolder.getNextTick().c); + } + + //******************************************* + //* Step five: Destroy the leftovers * + //******************************************* + //TODO: add support for pass-through + Collection deletePositions = CollectionUtils.filter(rotatedPositions.keySet(),rotatedPositions.values()); + for(BlockPosition position : deletePositions){ + setBlockFast(nativeWorld, position, Blocks.AIR.getBlockData()); + } + + //******************************************* + //* Step six: Process fire spread * + //******************************************* + for (BlockPosition position : rotatedPositions.values()) { + IBlockData type = nativeWorld.getType(position); + if (!(type.getBlock() instanceof BlockFire)) { + continue; + } + BlockFire fire = (BlockFire) type.getBlock(); + fire.tick(type, nativeWorld, position, nativeWorld.random); + } + + for (Map.Entry entry : redstoneComponents.entrySet()) { + final BlockPosition position = entry.getKey(); + final IBlockData data = entry.getValue(); + Chunk chunk = nativeWorld.getChunkAtWorldCoords(position); + ChunkSection chunkSection = chunk.getSections()[position.getY()>>4]; + if (chunkSection == null) { + // Put a GLASS block to initialize the section. It will be replaced next with the real block. + chunk.setType(position, Blocks.GLASS.getBlockData(), true); + chunkSection = chunk.getSections()[position.getY() >> 4]; + + } + chunkSection.setType(position.getX()&15, position.getY()&15, position.getZ()&15, data); + nativeWorld.update(position, data.getBlock()); + } + } + + @Override + public void translateCraft(@NotNull Craft craft, @NotNull MovecraftLocation displacement, @NotNull org.bukkit.World world) { + //TODO: Add supourt for rotations + //A craftTranslateCommand should only occur if the craft is moving to a valid position + //******************************************* + //* Step one: Convert to Positions * + //******************************************* + BlockPosition translateVector = locationToPosition(displacement); + List positions = new ArrayList<>(); + for(MovecraftLocation movecraftLocation : craft.getHitBox()) { + positions.add(locationToPosition((movecraftLocation)).b(translateVector)); + + } + WorldServer oldNativeWorld = ((CraftWorld) craft.getWorld()).getHandle(); + WorldServer nativeWorld = ((CraftWorld) world).getHandle(); + //******************************************* + //* Step two: Get the tiles * + //******************************************* + List tiles = getTiles(positions, oldNativeWorld); + //******************************************* + //* Step three: Translate all the blocks * + //******************************************* + // blockedByWater=false means an ocean-going vessel + //TODO: Simplify + //TODO: go by chunks + //TODO: Don't move unnecessary blocks + //get the blocks and translate the positions + List blockData = new ArrayList<>(); + List newPositions = new ArrayList<>(); + for(BlockPosition position : positions){ + blockData.add(oldNativeWorld.getType(position)); + newPositions.add(position.a(translateVector)); + } + //create the new block + setBlocks(newPositions, blockData, nativeWorld); + //******************************************* + //* Step four: replace all the tiles * + //******************************************* + //TODO: go by chunks + processTiles(tiles, nativeWorld, translateVector); + //******************************************* + //* Step five: Destroy the leftovers * + //******************************************* + Collection deletePositions = oldNativeWorld == nativeWorld ? CollectionUtils.filter(positions,newPositions) : positions; + setAir(deletePositions, oldNativeWorld); + //******************************************* + //* Step six: Process fire spread * + //******************************************* + processFireSpread(newPositions, nativeWorld); + //******************************************* + //* Step six: Process redstone * + //******************************************* + processRedstone(newPositions, nativeWorld); + } + + + private void setBlocks(List newPositions, List blockData, WorldServer nativeWorld){ + Map redstoneComponents = new HashMap<>(); + for(int i = 0; i getTiles(Iterable positions, WorldServer nativeWorld){ + List tiles = new ArrayList<>(); + //get the tiles + for(BlockPosition position : positions){ + if(nativeWorld.getType(position) == Blocks.AIR.getBlockData()) + continue; + //TileEntity tile = nativeWorld.removeTileEntity(position); + TileEntity tile = removeTileEntity(nativeWorld,position); + if(tile == null) + continue; + //get the nextTick to move with the tile + + //nativeWorld.capturedTileEntities.remove(position); + //nativeWorld.getChunkAtWorldCoords(position).getTileEntities().remove(position); + tiles.add(new TileHolder(tile, tickProvider.getNextTick(nativeWorld, position), position)); + + } + return tiles; + } + + private void processTiles(Iterable tiles, WorldServer world, BlockPosition translateVector){ + for(TileHolder tileHolder : tiles){ + moveTileEntity(world, tileHolder.getTilePosition().a(translateVector),tileHolder.getTile()); + if(tileHolder.getNextTick()==null) + continue; + final long currentTime = world.worldData.getTime(); + world.getBlockTickList().a(tileHolder.getNextTick().a.a(translateVector), tileHolder.getNextTick().b(), (int) (tileHolder.getNextTick().b - currentTime), tileHolder.getNextTick().c); + } + } + + private void processFireSpread(Iterable positions, WorldServer world){ + for (BlockPosition position : positions) { + IBlockData type = world.getType(position); + if (!(type.getBlock() instanceof BlockFire)) { + continue; + } + BlockFire fire = (BlockFire) type.getBlock(); + fire.tick(type, world, position, world.random); + } + } + + private void processRedstone(List redstone, WorldServer world) { + Map redstoneComponents = new HashMap<>(); + for (int i = 0 ; i < redstone.size(); i++) { + BlockPosition pos = redstone.get(i); + IBlockData data = world.getType(pos); + if (isRedstoneComponent(data)) + redstoneComponents.put(pos, data); + } + for (Map.Entry entry : redstoneComponents.entrySet()) { + final BlockPosition position = entry.getKey(); + final IBlockData data = entry.getValue(); + Chunk chunk = world.getChunkAtWorldCoords(position); + ChunkSection chunkSection = chunk.getSections()[position.getY()>>4]; + if (chunkSection == null) { + // Put a GLASS block to initialize the section. It will be replaced next with the real block. + chunk.setType(position, Blocks.GLASS.getBlockData(), true); + chunkSection = chunk.getSections()[position.getY() >> 4]; + + } + chunkSection.setType(position.getX()&15, position.getY()&15, position.getZ()&15, data); + //world.notifyAndUpdatePhysics(position, chunk, data, data, data, 3); + world.update(position, data.getBlock()); + } + } + + private void setAir(Iterable positions, WorldServer world){ + for(BlockPosition position : positions){ + setBlockFast(world, position, Blocks.AIR.getBlockData()); + } + } + + @Nullable + private TileEntity removeTileEntity(@NotNull WorldServer world, @NotNull BlockPosition position){ + TileEntity tile = world.getTileEntity(position); + if(tile == null) + return null; + //cleanup + world.capturedTileEntities.remove(position); + world.getChunkAtWorldCoords(position).getTileEntities().remove(position); + if(!Settings.IsPaper) + world.tileEntityList.remove(tile); + world.tileEntityListTick.remove(tile); + if(!bMap.containsKey(world)){ + try { + Field bField = World.class.getDeclaredField("tileEntityListPending"); + bField.setAccessible(true); + bMap.put(world, (List) bField.get(world));//TODO bug fix + } catch (IllegalAccessException | IllegalArgumentException | NoSuchFieldException | SecurityException e1) { + e1.printStackTrace(); + } + } + bMap.get(world).remove(tile); + return tile; + } + + @NotNull + private BlockPosition locationToPosition(@NotNull MovecraftLocation loc) { + return new BlockPosition(loc.getX(), loc.getY(), loc.getZ()); + } + + private void setBlockFast(@NotNull WorldServer world, @NotNull BlockPosition position,@NotNull IBlockData data) { + Chunk chunk = world.getChunkAtWorldCoords(position); + ChunkSection chunkSection = chunk.getSections()[position.getY()>>4]; + if (chunkSection == null) { + // Put a GLASS block to initialize the section. It will be replaced next with the real block. + chunk.setType(position, Blocks.GLASS.getBlockData(), true); + chunkSection = chunk.getSections()[position.getY() >> 4]; + + } + chunkSection.setType(position.getX() & 15, position.getY() & 15, position.getZ() & 15, data); + world.notify(position, data, data, 3); + world.getChunkProvider().getLightEngine().a(position); + chunk.markDirty(); + } + + @Override + public void setBlockFast(@NotNull Location location, @NotNull Material material, Object data){ + setBlockFast(location, Rotation.NONE, material, data); + } + + @Override + public void setBlockFast(@NotNull Location location, @NotNull Rotation rotation, @NotNull Material material, Object data) { + IBlockData blockData; + if (!(data instanceof BlockData)) { + blockData = CraftMagicNumbers.getBlock(material).getBlockData(); + } else { + blockData = ((CraftBlockData) data).getState(); + } + + blockData = blockData.a(ROTATION[rotation.ordinal()]); + WorldServer world = ((CraftWorld)(location.getWorld())).getHandle(); + BlockPosition blockPosition = locationToPosition(bukkit2MovecraftLoc(location)); + if (world.getTileEntity(blockPosition) != null) { + removeTileEntity(world, blockPosition); + } + setBlockFast(world,blockPosition,blockData); + } + + @Override + public void disableShadow(@NotNull Material type) { + Method method; + //try { + Block tempBlock = CraftMagicNumbers.getBlock(type); + //method = Block.class.getDeclaredMethod("d", int.class); + //method.setAccessible(true); + //method.invoke(tempBlock, 0); + //} catch (NoSuchMethodException | InvocationTargetException | IllegalArgumentException | IllegalAccessException | SecurityException e1) { + // TODO Auto-generated catch block + // e1.printStackTrace(); + //} + } + + private static MovecraftLocation bukkit2MovecraftLoc(Location l) { + return new MovecraftLocation(l.getBlockX(), l.getBlockY(), l.getBlockZ()); + } + + private void recalculateLighting(WorldServer world, Collection positions) { + final LightEngineThreaded engine = world.getChunkProvider().getLightEngine(); + for (BlockPosition pos : positions) { + engine.a(pos); + } + } + + private void moveTileEntity(@NotNull WorldServer nativeWorld, @NotNull BlockPosition newPosition, @NotNull TileEntity tile){ + Chunk chunk = nativeWorld.getChunkAtWorldCoords(newPosition); + tile.invalidateBlockCache(); + if(nativeWorld.captureBlockStates) { + tile.setLocation(nativeWorld, newPosition); + nativeWorld.capturedTileEntities.put(newPosition, tile); + return; + } + tile.setLocation(nativeWorld, newPosition); + chunk.tileEntities.put(newPosition, tile); + } + + private class TileHolder{ + @NotNull private final TileEntity tile; + @Nullable + private final NextTickListEntry nextTick; + @NotNull private final BlockPosition tilePosition; + + public TileHolder(@NotNull TileEntity tile, @Nullable NextTickListEntry nextTick, @NotNull BlockPosition tilePosition){ + this.tile = tile; + this.nextTick = nextTick; + this.tilePosition = tilePosition; + } + + + @NotNull + public TileEntity getTile() { + return tile; + } + + @Nullable + public NextTickListEntry getNextTick() { + return nextTick; + } + + @NotNull + public BlockPosition getTilePosition() { + return tilePosition; + } + } + + private boolean isRedstoneComponent(IBlockData blockData) { + final Block block = blockData.getBlock(); + return block instanceof BlockRedstoneWire || + block instanceof BlockDiodeAbstract || + block instanceof BlockButtonAbstract || + block instanceof BlockLever; + + } + + private boolean isPowered (IBlockData data) { + if (data.getBlock() instanceof BlockRedstoneWire) { + return data.get(BlockRedstoneWire.POWER) > 0; + } else if (data.getBlock() instanceof BlockDiodeAbstract) { + return data.get(BlockDiodeAbstract.c); + } else if (data.getBlock() instanceof BlockButtonAbstract || data.getBlock() instanceof BlockLever) { + return data.get(BlockButtonAbstract.POWERED); + } + return false; + } +} diff --git a/modules/v1_16_R3/src/main/java/net/countercraft/movecraft/compat/v1_16_R3/NextTickProvider.java b/modules/v1_16_R3/src/main/java/net/countercraft/movecraft/compat/v1_16_R3/NextTickProvider.java new file mode 100644 index 000000000..ecc74142f --- /dev/null +++ b/modules/v1_16_R3/src/main/java/net/countercraft/movecraft/compat/v1_16_R3/NextTickProvider.java @@ -0,0 +1,68 @@ +package net.countercraft.movecraft.compat.v1_16_R3; + +import net.minecraft.server.v1_16_R3.*; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.lang.reflect.Field; +import java.util.*; + +public class NextTickProvider { + private Map,Collection>> tickMap = new HashMap<>(); + + private boolean isRegistered(@NotNull WorldServer world){ + return tickMap.containsKey(world); + } + + @SuppressWarnings("unchecked") + private void registerWorld(@NotNull WorldServer world){ + final Collection W = new ArrayList<>(); + final Set nextTickList = new HashSet<>(); + TickListServer blockTickListServer = world.getBlockTickList(); + try { + Field gField = TickListServer.class.getDeclaredField("g"); + gField.setAccessible(true); + W.addAll((Collection) gField.get(blockTickListServer)); + Field ntlField = TickListServer.class.getDeclaredField("nextTickList"); + ntlField.setAccessible(true); + nextTickList.addAll((Set) ntlField.get(blockTickListServer)); + } catch (IllegalAccessException | IllegalArgumentException | NoSuchFieldException | SecurityException e1) { + e1.printStackTrace(); + } + tickMap.put(world, new AbstractMap.SimpleImmutableEntry<>(nextTickList,W)); + } + + @Nullable + public NextTickListEntry getNextTick(@NotNull WorldServer world, @NotNull BlockPosition position) { + if (!isRegistered(world)) + registerWorld(world); + AbstractMap.SimpleImmutableEntry, Collection> listPair = tickMap.get(world); + if(listPair.getKey().contains(fakeEntry(position))) { + for (Iterator iterator = listPair.getKey().iterator(); iterator.hasNext(); ) { + NextTickListEntry listEntry = iterator.next(); + if (position.equals(listEntry.a)) { + iterator.remove(); + return listEntry; + } + } + } + for(Iterator iterator = listPair.getValue().iterator(); iterator.hasNext();) { + NextTickListEntry listEntry = iterator.next(); + if (position.equals(listEntry.a)) { + iterator.remove(); + return listEntry; + } + } + return null; + + } + @NotNull + public Object fakeEntry(@NotNull BlockPosition position){ + return new Object(){ + @Override + public int hashCode() { + return position.hashCode(); + } + }; + } +} diff --git a/pom.xml b/pom.xml index 2686971ec..bddb33114 100644 --- a/pom.xml +++ b/pom.xml @@ -30,6 +30,7 @@ modules/v1_15_R1 modules/v1_16_R1 modules/v1_16_R2 + modules/v1_16_R3 modules/worldedit/WE6Utils modules/worldedit/WE7Utils modules/Movecraft From 1abdd21bd8cdbd53e0f7a49ba3a6bed060196cd8 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Fri, 6 Nov 2020 00:12:01 +0100 Subject: [PATCH 250/304] Fixed turrets not rotating --- .../movecraft/listener/InteractListener.java | 5 +-- .../movecraft/sign/SubcraftRotateSign.java | 45 +++++++++++++++---- 2 files changed, 38 insertions(+), 12 deletions(-) diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/InteractListener.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/InteractListener.java index 7722883c5..a9cfb3214 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/InteractListener.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/InteractListener.java @@ -23,7 +23,6 @@ import net.countercraft.movecraft.localisation.I18nSupport; import net.countercraft.movecraft.utils.LegacyUtils; import net.countercraft.movecraft.utils.MathUtils; -import org.bukkit.Bukkit; import org.bukkit.Material; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; @@ -32,6 +31,7 @@ import org.bukkit.event.player.PlayerInteractEvent; import org.bukkit.material.Button; import org.bukkit.util.Vector; + import java.util.Arrays; import java.util.HashMap; import java.util.Map; @@ -140,13 +140,12 @@ public void onPlayerInteractStick(PlayerInteractEvent event) { float p = event.getPlayer().getLocation().getPitch(); direction.setY(-(Math.abs(p) >= 25 ? 1 : 0) * (int) Math.signum(p)); - //direction.normalize(); + direction.normalize(); direction.multiply(currentGear); int dx = (int) rint(direction.getX()); int dz = (int) rint(direction.getZ()); int dy = (int) rint(direction.getY()); - Bukkit.broadcastMessage(String.format("(%d, %d, %d)", dx, dy, dz)); craft.translate(dx, dy, dz); timeMap.put(event.getPlayer(), System.currentTimeMillis()); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/SubcraftRotateSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/SubcraftRotateSign.java index d7d719b86..e58b9bf90 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/SubcraftRotateSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/SubcraftRotateSign.java @@ -7,8 +7,10 @@ import net.countercraft.movecraft.craft.CraftManager; import net.countercraft.movecraft.craft.CraftType; import net.countercraft.movecraft.craft.ICraft; +import net.countercraft.movecraft.events.CraftDetectEvent; import net.countercraft.movecraft.events.CraftPilotEvent; import net.countercraft.movecraft.events.CraftReleaseEvent; +import net.countercraft.movecraft.events.CraftRotateEvent; import net.countercraft.movecraft.localisation.I18nSupport; import net.countercraft.movecraft.utils.MathUtils; import net.countercraft.movecraft.utils.SignUtils; @@ -24,11 +26,16 @@ import org.bukkit.scheduler.BukkitRunnable; import java.util.HashSet; +import java.util.Map; import java.util.Set; +import java.util.WeakHashMap; public final class SubcraftRotateSign implements Listener { private static final String HEADER = "Subcraft Rotate"; private final Set rotatingCrafts = new HashSet<>(); + private final Map rotationMap = new WeakHashMap<>(); + private final Map startPointMap = new WeakHashMap<>(); + @EventHandler public final void onSignClick(PlayerInteractEvent event) { Rotation rotation; @@ -87,28 +94,48 @@ public void run() { }.runTaskLater(Movecraft.getInstance(), (10)); } final Craft subCraft = new ICraft(type, loc.getWorld()); + rotationMap.put(subCraft, rotation); subCraft.detect(null, event.getPlayer(), startPoint); rotatingCrafts.add(startPoint); + startPointMap.put(subCraft, startPoint); Bukkit.getServer().getPluginManager().callEvent(new CraftPilotEvent(subCraft, CraftPilotEvent.Reason.SUB_CRAFT)); + event.setCancelled(true); + } + + @EventHandler + public void onCraftRelease(CraftReleaseEvent event){ + rotatingCrafts.removeAll(event.getCraft().getHitBox().asSet()); + } + + @EventHandler + public void onCraftDetect(CraftDetectEvent event) { + if (!rotationMap.containsKey(event.getCraft())) + return; + final Craft subCraft = event.getCraft(); + final Rotation rotation = rotationMap.get(subCraft); + final MovecraftLocation startPoint = startPointMap.get(subCraft); new BukkitRunnable() { @Override public void run() { + Bukkit.broadcastMessage(String.valueOf(subCraft.isNotProcessing())); subCraft.rotate(rotation, startPoint, true); } - }.runTaskLater(Movecraft.getInstance(), 4); + }.runTaskLater(Movecraft.getInstance(), 1); + } + + @EventHandler + public void onCraftRotate(CraftRotateEvent event) { + if (!rotationMap.containsKey(event.getCraft())) + return; + final Craft subCraft = event.getCraft(); + rotationMap.remove(subCraft); + final MovecraftLocation startPoint = startPointMap.remove(subCraft); new BukkitRunnable() { @Override public void run() { rotatingCrafts.remove(startPoint); CraftManager.getInstance().removeCraft(subCraft, CraftReleaseEvent.Reason.SUB_CRAFT); } - }.runTaskLater(Movecraft.getInstance(), 7); - event.setCancelled(true); + }.runTaskLater(Movecraft.getInstance(), 1); } - - @EventHandler - public void onCraftRelease(CraftReleaseEvent event){ - rotatingCrafts.removeAll(event.getCraft().getHitBox().asSet()); - } - } From 502f6d40feb1d5b1fef601603710a0ec26ec9d8b Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Fri, 6 Nov 2020 00:41:11 +0100 Subject: [PATCH 251/304] Removed debug message --- .../java/net/countercraft/movecraft/sign/SubcraftRotateSign.java | 1 - 1 file changed, 1 deletion(-) diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/SubcraftRotateSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/SubcraftRotateSign.java index e58b9bf90..68a194f98 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/SubcraftRotateSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/SubcraftRotateSign.java @@ -117,7 +117,6 @@ public void onCraftDetect(CraftDetectEvent event) { new BukkitRunnable() { @Override public void run() { - Bukkit.broadcastMessage(String.valueOf(subCraft.isNotProcessing())); subCraft.rotate(rotation, startPoint, true); } }.runTaskLater(Movecraft.getInstance(), 1); From aab151d349dc3b3cf123d7ded2797d434c4e9a1e Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Fri, 6 Nov 2020 01:22:12 +0100 Subject: [PATCH 252/304] Fixed subcraft rotate not turning after failed detection --- modules/Movecraft/pom.xml | 2 +- .../movecraft/sign/SubcraftRotateSign.java | 17 +++++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/modules/Movecraft/pom.xml b/modules/Movecraft/pom.xml index 507671fb5..438b60fa6 100644 --- a/modules/Movecraft/pom.xml +++ b/modules/Movecraft/pom.xml @@ -11,7 +11,7 @@ - 7.0.0_for_1.8.8-1.16.2_beta_34 + 7.0.0_for_1.8.8-1.16.2_beta_35 diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/SubcraftRotateSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/SubcraftRotateSign.java index 68a194f98..a3668524f 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/SubcraftRotateSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/SubcraftRotateSign.java @@ -100,6 +100,23 @@ public void run() { startPointMap.put(subCraft, startPoint); Bukkit.getServer().getPluginManager().callEvent(new CraftPilotEvent(subCraft, CraftPilotEvent.Reason.SUB_CRAFT)); event.setCancelled(true); + new BukkitRunnable() { + /** + * When an object implementing interface Runnable is used + * to create a thread, starting the thread causes the object's + * run method to be called in that separately executing + * thread. + *

+ * The general contract of the method run is that it may + * take any action whatsoever. + * + * @see Thread#run() + */ + @Override + public void run() { + rotatingCrafts.remove(startPoint); + } + }.runTaskLaterAsynchronously(Movecraft.getInstance(), 5); } @EventHandler From 8d1b3c1d7322154b85a2bc698bd5145a01e06a8b Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Fri, 6 Nov 2020 17:33:24 +0100 Subject: [PATCH 253/304] fix --- modules/Movecraft/dependency-reduced-pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/Movecraft/dependency-reduced-pom.xml b/modules/Movecraft/dependency-reduced-pom.xml index 0f2cb062f..421806590 100644 --- a/modules/Movecraft/dependency-reduced-pom.xml +++ b/modules/Movecraft/dependency-reduced-pom.xml @@ -4,7 +4,7 @@ net.countercraft movecraft Movecraft - 7.0.0_for_1.8.8-1.16.2_beta_34 + 7.0.0_for_1.8.8-1.16.2_beta_35 http://github.com/apdevteam/Movecraft src/main/java From da9ba4909e8d96aa82d1210ac3cc1a6a31aedd02 Mon Sep 17 00:00:00 2001 From: TylerS1066 Date: Tue, 17 Nov 2020 09:48:46 -0600 Subject: [PATCH 254/304] Attempt to fix java CI --- .github/workflows/maven.yml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml index 8b12c2c54..759c76196 100644 --- a/.github/workflows/maven.yml +++ b/.github/workflows/maven.yml @@ -25,7 +25,6 @@ jobs: - name: Setup BuildTools run: mkdir BuildTools && wget -O BuildTools/BuildTools.jar https://hub.spigotmc.org/jenkins/job/BuildTools/lastSuccessfulBuild/artifact/target/BuildTools.jar -<<<<<<< HEAD # EXAMPLE - Copy/paste as required to add version support to CI # - name: Test [version] # id: [version name] @@ -95,6 +94,12 @@ jobs: - name: Build 1.16.2 if: steps.nether2.outputs.sucess != 'true' run: cd BuildTools && java -jar BuildTools.jar --rev 1.16.2 --compile craftbukkit + - name: Check 1.16.4 + id: nether3 + run: test -f ~/.m2/repository/org/bukkit/craftbukkit/1.16.4-R0.1-SNAPSHOT/craftbukkit-1.16.4-R0.1-SNAPSHOT.jar && echo "::set-output name=sucess::true" || echo "::set-output name=sucess::false" + - name: Build 1.16.4 + if: steps.nether3.outputs.sucess != 'true' + run: cd BuildTools && java -jar BuildTools.jar --rev 1.16.4 --compile craftbukkit # EXAMPLE - Copy/paste as required to add version support to CI # - name: Test [version] From 5c5e7185118fa00f5c1f50ff24aede54d05c5071 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Sun, 6 Dec 2020 03:56:00 +0100 Subject: [PATCH 255/304] Fixes --- .../countercraft/movecraft/async/AsyncManager.java | 1 + .../countercraft/movecraft/craft/ChunkManager.java | 2 +- .../countercraft/movecraft/craft/CraftManager.java | 4 +++- .../movecraft/worldguard/WorldGuardCompatManager.java | 8 ++++---- modules/api/dependency-reduced-pom.xml | 6 ++++++ .../java/net/countercraft/movecraft/WorldHandler.java | 4 ++++ .../movecraft/events/CraftReleaseEvent.java | 5 +++++ .../movecraft/compat/v1_15_R1/IWorldHandler.java | 7 +++++++ pom.xml | 11 ++++++++--- 9 files changed, 39 insertions(+), 9 deletions(-) diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java index 4677f1389..a82bd5085 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java @@ -925,6 +925,7 @@ private void clear(Craft c) { private void clearAll() { for (Craft c : clearanceSet) { + c.setTranslating(false); c.setProcessing(false); } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/ChunkManager.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/ChunkManager.java index ef1330b0d..d0d4a6151 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/ChunkManager.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/ChunkManager.java @@ -59,7 +59,7 @@ public void run() { ChunkManager.removeChunksToLoad(list); } - }.runTaskLaterAsynchronously(Movecraft.getInstance(), 200L); + }.runTaskLater(Movecraft.getInstance(), 200L); } private static void removeChunksToLoad(List list) { diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/CraftManager.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/CraftManager.java index 688a8c190..ae7d0b164 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/CraftManager.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/CraftManager.java @@ -47,9 +47,11 @@ public class CraftManager implements Iterable{ @NotNull private final ConcurrentMap releaseEvents = new ConcurrentHashMap<>(); @NotNull private Set craftTypes; @NotNull private final WeakHashMap overboards = new WeakHashMap<>(); + private static Thread serverThread; public static void initialize(){ ourInstance = new CraftManager(); + serverThread = Thread.currentThread(); } private CraftManager() { @@ -166,7 +168,7 @@ public void addCraft(@NotNull Craft c, @Nullable Player p) { } public void removeCraft(@NotNull Craft c, @NotNull CraftReleaseEvent.Reason reason) { - CraftReleaseEvent e = new CraftReleaseEvent(c, reason); + CraftReleaseEvent e = new CraftReleaseEvent(c, reason, serverThread != Thread.currentThread()); Bukkit.getServer().getPluginManager().callEvent(e); if (e.isCancelled()) return; diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/worldguard/WorldGuardCompatManager.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/worldguard/WorldGuardCompatManager.java index 7f7319bda..a79802682 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/worldguard/WorldGuardCompatManager.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/worldguard/WorldGuardCompatManager.java @@ -46,13 +46,13 @@ public static void registerFlags() { flags = WorldGuard.getInstance().getFlagRegistry(); } Movecraft.getInstance().getLogger().info("Registered custom flags"); - if (flags.get("movecraft-move") != null) + if (flags.get("movecraft-move") == null) flags.register(FLAG_MOVE); - if (flags.get("movecraft-pilot") != null) + if (flags.get("movecraft-pilot") == null) flags.register(FLAG_PILOT); - if (flags.get("movecraft-rotate") != null) + if (flags.get("movecraft-rotate") == null) flags.register(FLAG_ROTATE); - if (flags.get("movecraft-sink") != null) + if (flags.get("movecraft-sink") == null) flags.register(FLAG_SINK); } diff --git a/modules/api/dependency-reduced-pom.xml b/modules/api/dependency-reduced-pom.xml index 5ac148d35..ba21c924d 100644 --- a/modules/api/dependency-reduced-pom.xml +++ b/modules/api/dependency-reduced-pom.xml @@ -159,6 +159,12 @@ + + com.destroystokyo.paper + paper-api + 1.16.4-R0.1-SNAPSHOT + provided + 1.2.0 diff --git a/modules/api/src/main/java/net/countercraft/movecraft/WorldHandler.java b/modules/api/src/main/java/net/countercraft/movecraft/WorldHandler.java index 9d49ced9a..eb57b977b 100644 --- a/modules/api/src/main/java/net/countercraft/movecraft/WorldHandler.java +++ b/modules/api/src/main/java/net/countercraft/movecraft/WorldHandler.java @@ -22,4 +22,8 @@ public void addPlayerLocation(Player player, double x, double y, double z, float player.teleport(tpLoc); player.sendBlockChange(tpLoc.subtract(0,1,0), standingOn.getType(), standingOn.getData()); } + + public void loadChunk(MovecraftChunk chunk) { + chunk.getWorld().loadChunk(chunk.getX(), chunk.getZ()); + } } diff --git a/modules/api/src/main/java/net/countercraft/movecraft/events/CraftReleaseEvent.java b/modules/api/src/main/java/net/countercraft/movecraft/events/CraftReleaseEvent.java index 768d8fb7c..ca471e882 100644 --- a/modules/api/src/main/java/net/countercraft/movecraft/events/CraftReleaseEvent.java +++ b/modules/api/src/main/java/net/countercraft/movecraft/events/CraftReleaseEvent.java @@ -20,6 +20,11 @@ public CraftReleaseEvent(@NotNull Craft craft, @NotNull Reason reason) { this.reason = reason; } + public CraftReleaseEvent(@NotNull Craft craft, @NotNull Reason reason, boolean isAsync) { + super(craft, isAsync); + this.reason = reason; + } + @NotNull public Reason getReason() { return reason; diff --git a/modules/v1_15_R1/src/main/java/net/countercraft/movecraft/compat/v1_15_R1/IWorldHandler.java b/modules/v1_15_R1/src/main/java/net/countercraft/movecraft/compat/v1_15_R1/IWorldHandler.java index 2f234520f..6d380677b 100644 --- a/modules/v1_15_R1/src/main/java/net/countercraft/movecraft/compat/v1_15_R1/IWorldHandler.java +++ b/modules/v1_15_R1/src/main/java/net/countercraft/movecraft/compat/v1_15_R1/IWorldHandler.java @@ -1,5 +1,6 @@ package net.countercraft.movecraft.compat.v1_15_R1; +import net.countercraft.movecraft.MovecraftChunk; import net.countercraft.movecraft.MovecraftLocation; import net.countercraft.movecraft.Rotation; import net.countercraft.movecraft.WorldHandler; @@ -49,6 +50,12 @@ public IWorldHandler() { } } + @Override + public void loadChunk(MovecraftChunk chunk) { + final WorldServer world = ((CraftWorld) chunk.getWorld()).getHandle(); + world.getChunkProvider().getChunkAt(chunk.getX(), chunk.getZ(), ChunkStatus.FULL, true); + } + @Override public void rotateCraft(@NotNull Craft craft, @NotNull MovecraftLocation originPoint, @NotNull Rotation rotation) { //******************************************* diff --git a/pom.xml b/pom.xml index bddb33114..ebc1673f1 100644 --- a/pom.xml +++ b/pom.xml @@ -7,9 +7,10 @@ parent - org.spigotmc - spigot-api - 1.15-R0.1-SNAPSHOT + com.destroystokyo.paper + paper-api + 1.16.4-R0.1-SNAPSHOT + provided Movecraft Parent Pom @@ -43,6 +44,10 @@ spigot-repo https://hub.spigotmc.org/nexus/content/groups/public/ + + papermc + https://papermc.io/repo/repository/maven-public/ + From 5fa7df23de707e016cebd9cf28dd1fcffeb1eced Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Sun, 6 Dec 2020 03:57:35 +0100 Subject: [PATCH 256/304] bump version --- modules/Movecraft/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/Movecraft/pom.xml b/modules/Movecraft/pom.xml index 438b60fa6..991a88e12 100644 --- a/modules/Movecraft/pom.xml +++ b/modules/Movecraft/pom.xml @@ -11,7 +11,7 @@ - 7.0.0_for_1.8.8-1.16.2_beta_35 + 7.0.0_for_1.8.8-1.16.2_beta_36 From 969bb712f23193861e5391502fcf5c199296155a Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Tue, 29 Dec 2020 13:45:00 +0100 Subject: [PATCH 257/304] Added direct control command --- modules/Movecraft/dependency-reduced-pom.xml | 2 +- .../commands/DirectControlCommand.java | 38 +++++++++++++++++++ .../movecraft/sign/StatusSign.java | 2 +- .../localisation/movecraftlang_en.properties | 1 + 4 files changed, 41 insertions(+), 2 deletions(-) create mode 100644 modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/DirectControlCommand.java diff --git a/modules/Movecraft/dependency-reduced-pom.xml b/modules/Movecraft/dependency-reduced-pom.xml index 421806590..8df2a7e04 100644 --- a/modules/Movecraft/dependency-reduced-pom.xml +++ b/modules/Movecraft/dependency-reduced-pom.xml @@ -4,7 +4,7 @@ net.countercraft movecraft Movecraft - 7.0.0_for_1.8.8-1.16.2_beta_35 + 7.0.0_for_1.8.8-1.16.2_beta_36 http://github.com/apdevteam/Movecraft src/main/java diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/DirectControlCommand.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/DirectControlCommand.java new file mode 100644 index 000000000..e0cd8899e --- /dev/null +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/DirectControlCommand.java @@ -0,0 +1,38 @@ +package net.countercraft.movecraft.commands; + +import net.countercraft.movecraft.craft.Craft; +import net.countercraft.movecraft.craft.CraftManager; +import net.countercraft.movecraft.localisation.I18nSupport; +import org.bukkit.command.Command; +import org.bukkit.command.CommandExecutor; +import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; + +import static net.countercraft.movecraft.utils.ChatUtils.MOVECRAFT_COMMAND_PREFIX; + +public class DirectControlCommand implements CommandExecutor { + @Override + public boolean onCommand(@NotNull CommandSender commandSender, @NotNull Command command, @NotNull String s, @NotNull String[] strings) { + if (!command.getName().equalsIgnoreCase("directcontrol")) + return false; + if (!(commandSender instanceof Player)) { + commandSender.sendMessage(MOVECRAFT_COMMAND_PREFIX + I18nSupport.getInternationalisedString("Direct Control - Must be player")); + return true; + } + final Player player = (Player) commandSender; + final Craft craft = CraftManager.getInstance().getCraftByPlayer(player); + if (craft == null) { + commandSender.sendMessage(MOVECRAFT_COMMAND_PREFIX + I18nSupport.getInternationalisedString("You must be piloting a craft")); + return true; + } + if (!craft.getType().getCanDirectControl()) { + player.sendMessage(MOVECRAFT_COMMAND_PREFIX + I18nSupport.getInternationalisedString("Insufficient permissions")); + return true; + } + commandSender.sendMessage(MOVECRAFT_COMMAND_PREFIX + I18nSupport.getInternationalisedString("Direct Control - " + (craft.getPilotLocked() ? "Leaving" : "Entering"))); + craft.setPilotLocked(!craft.getPilotLocked()); + return true; + + } +} diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/StatusSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/StatusSign.java index fcfdeb899..2e0d8089f 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/StatusSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/StatusSign.java @@ -116,7 +116,7 @@ public final void onSignTranslate(SignTranslateEvent event) { signLine++; } String fuelText=""; - int fuelRange=(int) ((fuel*(1+(craft.getType().getCruiseSkipBlocks(craft.getWorld())+1)))/craft.getType().getFuelBurnRate(craft.getW())); + int fuelRange=(int) (( fuel * ( 1 + (craft.getType().getCruiseSkipBlocks(craft.getWorld())+1))) / craft.getType().getFuelBurnRate(craft.getW())); if(fuelRange>1000) { fuelText+=ChatColor.GREEN; } else if(fuelRange>100) { diff --git a/modules/Movecraft/src/main/resources/localisation/movecraftlang_en.properties b/modules/Movecraft/src/main/resources/localisation/movecraftlang_en.properties index eacd1f416..574f95d11 100644 --- a/modules/Movecraft/src/main/resources/localisation/movecraftlang_en.properties +++ b/modules/Movecraft/src/main/resources/localisation/movecraftlang_en.properties @@ -223,6 +223,7 @@ Invalid\ Coordinates=Invalid Coordinates Movecraft=Movecraft Error=ERROR Direct\ Control\ -\ Entering=Entering Direct Control Mode +Direct\ Control\ -\ Must\ be\ player=Only players may toggle direct control Direct\ Control\ -\ Leaving=Leaving Direct Control Mode Crew\ Sign\ -\ Can\ only\ create\ for\ yourself=You can only create a Crew\: sign for yourself Repair\ functionality\ is\ disabled\ or\ WorldEdit\ was\ not\ detected=Repair functionality is disabled or WorldEdit was not detected From 16eeda1667f1bd5cc525e9e3f854a552b73b27e4 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Fri, 15 Jan 2021 12:45:23 +0100 Subject: [PATCH 258/304] Removed checking number of cannons on craft --- .../async/detection/DetectionTask.java | 39 ----- .../movecraft/sign/RegionDamagedSign.java | 154 ------------------ modules/api/dependency-reduced-pom.xml | 4 +- 3 files changed, 2 insertions(+), 195 deletions(-) delete mode 100644 modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RegionDamagedSign.java diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/detection/DetectionTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/detection/DetectionTask.java index 58f1bf664..42147b4db 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/detection/DetectionTask.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/detection/DetectionTask.java @@ -18,7 +18,6 @@ package net.countercraft.movecraft.async.detection; -import at.pavlov.cannons.cannon.Cannon; import net.countercraft.movecraft.Movecraft; import net.countercraft.movecraft.MovecraftBlock; import net.countercraft.movecraft.MovecraftLocation; @@ -113,7 +112,6 @@ public void execute() throws ExecutionException, InterruptedException { return; } checkMaxSignLimits(); - checkMaxCannons(); long endTime = System.currentTimeMillis(); if (Settings.Debug){ Bukkit.broadcastMessage("Detection took (ms): " + (endTime - startTime)); @@ -421,43 +419,6 @@ private void checkMaxSignLimits() { } } - private void checkMaxCannons() { - if (Movecraft.getInstance().getCannonsPlugin() == null) { - return; - } - for (Cannon can : CannonsUtils.getCannonsInHitBox(hitBox, world)) { - - for (List limitedCannonNames : craft.getType().getMaxCannons().keySet()) { - if (!limitedCannonNames.contains(can.getCannonDesign().getDesignName().toLowerCase())) { - continue; - } - int count = cannonsCount.getOrDefault(limitedCannonNames, 0); - count++; - cannonsCount.put(limitedCannonNames, count); - } - } - if (cannonsCount.isEmpty()) { - return; - } - for (List limitedCannonNames : craft.getType().getMaxCannons().keySet()) { - final double limit = craft.getType().getMaxCannons().get(limitedCannonNames); - int count = cannonsCount.get(limitedCannonNames); - if (limit >= 10000.0) { - int max = (int) (limit - 10000.0); - if (count <= max) { - continue; - } - fail(I18nSupport.getInternationalisedString("Detection - Too many cannons") + " " + String.join(", ", limitedCannonNames) + ": " + count + " > " + max); - } else { - int maxCount = (int) (hitBox.size() * (limit / 100.0)); - if (count <= maxCount) { - continue; - } - fail(I18nSupport.getInternationalisedString("Detection - Too many cannons") + " " + String.join(", ", limitedCannonNames) + ": " + count + " > " + maxCount ); - } - } - } - private void fail(String message) { failed = true; failMessage = message; diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RegionDamagedSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RegionDamagedSign.java deleted file mode 100644 index 9b4549b18..000000000 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/RegionDamagedSign.java +++ /dev/null @@ -1,154 +0,0 @@ -package net.countercraft.movecraft.sign; - -import com.sk89q.worldedit.Vector; -import com.sk89q.worldedit.bukkit.BukkitAdapter; -import com.sk89q.worldedit.extent.clipboard.Clipboard; -import com.sk89q.worldedit.math.BlockVector3; -import com.sk89q.worldedit.world.block.BaseBlock; -import com.sk89q.worldguard.WorldGuard; -import com.sk89q.worldguard.protection.managers.RegionManager; -import com.sk89q.worldguard.protection.regions.ProtectedRegion; -import net.countercraft.movecraft.Movecraft; -import net.countercraft.movecraft.MovecraftLocation; -import net.countercraft.movecraft.config.Settings; -import net.countercraft.movecraft.localisation.I18nSupport; -import net.countercraft.movecraft.mapUpdater.MapUpdateManager; -import net.countercraft.movecraft.mapUpdater.update.WorldEdit7UpdateCommand; -import net.countercraft.movecraft.mapUpdater.update.WorldEditUpdateCommand; -import net.countercraft.movecraft.utils.LegacyUtils; -import net.countercraft.movecraft.utils.LegacyWEUtils; -import org.bukkit.Bukkit; -import org.bukkit.ChatColor; -import org.bukkit.Material; -import org.bukkit.World; -import org.bukkit.block.Block; -import org.bukkit.block.Sign; -import org.bukkit.event.EventHandler; -import org.bukkit.event.Listener; -import org.bukkit.event.block.Action; -import org.bukkit.event.player.PlayerInteractEvent; - -import java.util.UUID; - -public class RegionDamagedSign implements Listener { - private final String HEADER = ChatColor.RED + "REGION DAMAGED!"; - - @EventHandler - public void onSignRightClick(PlayerInteractEvent event){ - if (!event.getAction().equals(Action.RIGHT_CLICK_BLOCK)){ - return; - } - if (event.getClickedBlock().getType() != (Settings.is1_14 ? Material.OAK_WALL_SIGN : LegacyUtils.WALL_SIGN)){ - return; - } - Sign sign = (Sign) event.getClickedBlock().getState(); - if (!sign.getLine(0).equals(HEADER)){ - return; - } - String regionName = sign.getLine(1).substring(sign.getLine(1).indexOf(":") + 1); - long damages = Long.parseLong(sign.getLine(2).substring(sign.getLine(2).indexOf(":") + 1)); - String[] owners = sign.getLine(3).substring(sign.getLine(3).indexOf(":") + 1).split(","); - if (!Movecraft.getInstance().getEconomy().has(event.getPlayer(), damages)) { - event.getPlayer().sendMessage(I18nSupport.getInternationalisedString("Economy - Not Enough Money")); - return; - } - - if (!repairRegion(event.getClickedBlock().getWorld(), regionName)) { - Bukkit.getServer().broadcastMessage(String.format(I18nSupport.getInternationalisedString("Assault - Repair Failed"), regionName)); - return; - } - event.getPlayer().sendMessage(I18nSupport.getInternationalisedString("Assault - Repairing Region")); - Movecraft.getInstance().getEconomy().withdrawPlayer(event.getPlayer(), damages); - World world = event.getClickedBlock().getWorld(); - ProtectedRegion aRegion; - if (Settings.IsLegacy) { - RegionManager rm = LegacyUtils.getRegionManager(Movecraft.getInstance().getWorldGuardPlugin(), world); - aRegion = rm.getRegion(regionName); - } else { - aRegion = WorldGuard.getInstance().getPlatform().getRegionContainer().get(BukkitAdapter.adapt(world)).getRegion(regionName); - } - for (String ownerName : owners) { - if (ownerName.length() > 16) { - aRegion.getOwners().addPlayer(UUID.fromString(ownerName)); - } else { - - if (Bukkit.getPlayer(ownerName) != null) {//Cannot add names directly as bug will allow free assaults - aRegion.getOwners().addPlayer(Bukkit.getPlayer(ownerName).getUniqueId()); - } else { - aRegion.getOwners().addPlayer(Bukkit.getOfflinePlayer(ownerName).getUniqueId()); - } - } - } - //Clear the beacon - int minX = sign.getX() - 2; - int minY = sign.getY() - 3; - int minZ = sign.getZ() - 1; - int maxX = sign.getX() + 2; - int maxY = sign.getY(); - int maxZ = sign.getZ() + 3; - for (int x = minX ; x <= maxX ; x++){ - for (int y = minY ; y <= maxY ; y++){ - for (int z = minZ; z <= maxZ ; z++){ - Block b = sign.getWorld().getBlockAt(x,y,z); - if (b.getType() == Material.BEDROCK || b.getType() == Material.BEACON || b.getType() == Material.IRON_BLOCK ){ - b.setType(Material.AIR); - } - } - } - } - } - - public boolean repairRegion(World w, String regionName) { - if (w == null || regionName == null) - return false; - Clipboard clipboard = Movecraft.getInstance().getMovecraftRepair().loadRegionRepairStateClipboard(regionName, w); - if (clipboard == null){ - return false; - } - int minx = clipboard.getMinimumPoint().getBlockX(); - int miny = clipboard.getMinimumPoint().getBlockY(); - int minz = clipboard.getMinimumPoint().getBlockZ(); - int maxx = clipboard.getMaximumPoint().getBlockX(); - int maxy = clipboard.getMaximumPoint().getBlockY(); - int maxz = clipboard.getMaximumPoint().getBlockZ(); - for (int x = minx; x < maxx; x++) { - for (int y = miny; y < maxy; y++) { - for (int z = minz; z < maxz; z++) { - if (Settings.IsLegacy) { - Vector ccloc = new Vector(x, y, z); - com.sk89q.worldedit.blocks.BaseBlock bb = LegacyWEUtils.getBlock(clipboard,ccloc); - if (!bb.isAir()) { // most blocks will be air, quickly move on to the next. This loop will run 16 million times, needs to be fast - if (Settings.AssaultDestroyableBlocks.contains(bb.getId())) { - if (!w.getChunkAt(x >> 4, z >> 4).isLoaded()) - w.loadChunk(x >> 4, z >> 4); - if (w.getBlockAt(x, y, z).isEmpty() || w.getBlockAt(x, y, z).isLiquid()) { - MovecraftLocation moveloc = new MovecraftLocation(x, y, z); - WorldEditUpdateCommand updateCommand = new WorldEditUpdateCommand(bb, w, moveloc, LegacyUtils.getMaterial(bb.getType()), (byte) bb.getData()); - MapUpdateManager.getInstance().scheduleUpdate(updateCommand); - } - } - } - continue; - } - BlockVector3 ccloc = BlockVector3.at(x, y, z); - BaseBlock bb = clipboard.getFullBlock(ccloc); - Material type = BukkitAdapter.adapt(bb.getBlockType()); - if (type.name().endsWith("AIR")){ - continue; - } - if (Settings.AssaultDestroyableBlocks.contains(type)) { - if (!w.getChunkAt(x >> 4, z >> 4).isLoaded()) - w.loadChunk(x >> 4, z >> 4); - if (w.getBlockAt(x, y, z).isEmpty() || w.getBlockAt(x, y, z).isLiquid()) { - MovecraftLocation moveloc = new MovecraftLocation(x, y, z); - WorldEdit7UpdateCommand updateCommand = new WorldEdit7UpdateCommand(bb, w, moveloc, type); - MapUpdateManager.getInstance().scheduleUpdate(updateCommand); - } - } - - } - } - } - return true; - } -} diff --git a/modules/api/dependency-reduced-pom.xml b/modules/api/dependency-reduced-pom.xml index ba21c924d..8beba05e5 100644 --- a/modules/api/dependency-reduced-pom.xml +++ b/modules/api/dependency-reduced-pom.xml @@ -138,7 +138,7 @@ junit junit - 4.12 + 4.13.1 test @@ -171,6 +171,6 @@ ${junit.jupiter.version} 5.2.0 UTF-8 - 4.12 + 4.13.1 From 129e57df913f030c7222f2cfbacfe1ee65ad70c5 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Fri, 15 Jan 2021 12:46:34 +0100 Subject: [PATCH 259/304] Removed region repair as assault is removed --- .../movecraft/repair/RepairUtils.java | 22 ------------------- 1 file changed, 22 deletions(-) diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/repair/RepairUtils.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/repair/RepairUtils.java index 5cf733fcf..9077e6471 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/repair/RepairUtils.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/repair/RepairUtils.java @@ -4,12 +4,6 @@ import com.sk89q.worldedit.blocks.BaseBlock; import com.sk89q.worldedit.extent.clipboard.BlockArrayClipboard; import com.sk89q.worldedit.extent.clipboard.Clipboard; -import net.countercraft.movecraft.MovecraftLocation; -import net.countercraft.movecraft.config.Settings; -import net.countercraft.movecraft.mapUpdater.MapUpdateManager; -import net.countercraft.movecraft.mapUpdater.update.WorldEditUpdateCommand; -import net.countercraft.movecraft.utils.LegacyUtils; -import org.bukkit.World; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; @@ -25,22 +19,6 @@ public class RepairUtils { } - public static void legacyRepairRegion(Clipboard clipboard, World world, int x, int y, int z){ - Vector pos = new Vector(x,y,z); - BaseBlock bb = getBlock(clipboard, pos); - if (bb.isAir()){ - return; - } - if (Settings.AssaultDestroyableBlocks.contains(LegacyUtils.getMaterial(bb.getId()))){ - if (!world.getChunkAt(x >> 4, z >> 4).isLoaded()) - world.loadChunk(x >> 4, z >> 4); - if (world.getBlockAt(x, y, z).isEmpty() || world.getBlockAt(x, y, z).isLiquid()) { - MovecraftLocation moveloc = new MovecraftLocation(x, y, z); - WorldEditUpdateCommand updateCommand = new WorldEditUpdateCommand(bb, world, moveloc, LegacyUtils.getMaterial(bb.getType()), (byte) bb.getData()); - MapUpdateManager.getInstance().scheduleUpdate(updateCommand); - } - } - } public static BaseBlock getBlock(Clipboard clipboard, Vector pos){ BlockArrayClipboard bac = (BlockArrayClipboard) clipboard; try { From 6eb4654a1edac189ac53879e3bbc9ad795fbc3b9 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Fri, 15 Jan 2021 12:50:26 +0100 Subject: [PATCH 260/304] Fixes and bump version --- modules/Movecraft/pom.xml | 2 +- .../movecraft/async/AsyncManager.java | 3 -- .../movecraft/utils/CannonsUtils.java | 30 ------------------- 3 files changed, 1 insertion(+), 34 deletions(-) delete mode 100644 modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/CannonsUtils.java diff --git a/modules/Movecraft/pom.xml b/modules/Movecraft/pom.xml index 74857c2cb..5afb48fc6 100644 --- a/modules/Movecraft/pom.xml +++ b/modules/Movecraft/pom.xml @@ -10,7 +10,7 @@ UTF-8 - 7.0.0_for_1.8.8-1.16.2_beta_36 + 7.0.0_for_1.8.8-1.16.2_beta_37 diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java index a391cb894..be12575b2 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java @@ -17,12 +17,10 @@ package net.countercraft.movecraft.async; -import at.pavlov.cannons.cannon.Cannon; import com.google.common.collect.Lists; import net.countercraft.movecraft.Movecraft; import net.countercraft.movecraft.MovecraftBlock; import net.countercraft.movecraft.MovecraftLocation; -import net.countercraft.movecraft.Rotation; import net.countercraft.movecraft.async.detection.DetectionTask; import net.countercraft.movecraft.async.rotation.RotationTask; import net.countercraft.movecraft.async.translation.TranslationTask; @@ -43,7 +41,6 @@ import org.bukkit.entity.SmallFireball; import org.bukkit.entity.TNTPrimed; import org.bukkit.scheduler.BukkitRunnable; -import org.bukkit.util.Vector; import org.jetbrains.annotations.NotNull; import java.util.*; diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/CannonsUtils.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/CannonsUtils.java deleted file mode 100644 index a51396a0e..000000000 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/CannonsUtils.java +++ /dev/null @@ -1,30 +0,0 @@ -package net.countercraft.movecraft.utils; - -import at.pavlov.cannons.API.CannonsAPI; -import at.pavlov.cannons.cannon.Cannon; -import net.countercraft.movecraft.craft.Craft; -import org.bukkit.Location; -import org.bukkit.World; - -import java.util.HashSet; -import java.util.Set; - -public class CannonsUtils { - public static Set getCannonsInHitBox(HitBox hitBox, World world) { - Set foundCannons = new HashSet<>(); - for (Cannon can : CannonsAPI.getCannonsInBox(hitBox.getMidPoint().toBukkit(world), hitBox.getXLength(), hitBox.getYLength(), hitBox.getZLength())) { - for (Location barrelLoc : can.getCannonDesign().getBarrelBlocks(can)) { - if (!hitBox.contains(MathUtils.bukkit2MovecraftLoc(barrelLoc))) { - continue; - } - foundCannons.add(can); - break; - } - } - return foundCannons; - } - - public static Set getCannonsOnCraft(Craft c) { - return getCannonsInHitBox(c.getHitBox(), c.getWorld()); - } -} From c7ed5e07d1b1e242649ff743de241f676507685b Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Wed, 24 Feb 2021 00:25:44 +0100 Subject: [PATCH 261/304] Merge https://github.com/APDevTeam/Movecraft # Conflicts: # modules/Movecraft/pom.xml # modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java # modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/InteractListener.java # modules/Movecraft/src/main/resources/localisation/movecraftlang_en.properties # modules/api/src/main/java/net/countercraft/movecraft/craft/Craft.java # modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java --- .../net/countercraft/movecraft/listener/InteractListener.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/InteractListener.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/InteractListener.java index 37142e9be..dc93fad8f 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/InteractListener.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/InteractListener.java @@ -102,8 +102,8 @@ public void onPlayerInteractStick(PlayerInteractEvent event) { craft.setCurrentGear(currentGear); return; } - Long time = timeMap.get(player); - int tickCooldown = craft.getType().getTickCooldown(craft.getW()); + Long time = timeMap.getOrDefault(player, 0L); + int tickCooldown = craft.getType().getTickCooldown(craft.getWorld()); if (type.getGearShiftsAffectDirectMovement() && type.getGearShiftsAffectTickCooldown()) { tickCooldown *= currentGear; } From 44328983744dd771331eb78b5bf0bdff677b6d44 Mon Sep 17 00:00:00 2001 From: Ineusia Date: Mon, 1 Mar 2021 16:05:53 -0600 Subject: [PATCH 262/304] Listener priority (#376) * The BlockBreakEvent listener here does not rely on the state of BlockBreakEvent, therefore cancel it early so that no calculations can be done on an event that Movecraft will always prevent. - Increases plugin compatibility * There is no case, ever, where this event would be cancelled when we get to this line. Even at MONITOR, this line would never execute if the event is cancelled. --- .../net/countercraft/movecraft/listener/BlockListener.java | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/BlockListener.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/BlockListener.java index afe00e8ad..e09aad3fb 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/BlockListener.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/BlockListener.java @@ -69,11 +69,8 @@ public void onBlockPlace(final BlockPlaceEvent e) { } } - @EventHandler(priority = EventPriority.HIGHEST) + @EventHandler(priority = EventPriority.LOWEST) public void onBlockBreak(final BlockBreakEvent e) { - if (e.isCancelled()) { - return; - } if (e.getBlock().getType() == Material.WALL_SIGN) { Sign s = (Sign) e.getBlock().getState(); if (s.getLine(0).equalsIgnoreCase(ChatColor.RED + I18nSupport.getInternationalisedString("Region Damaged"))) { From 78759a69cf87ab6b6d3194616503d011a76e87bf Mon Sep 17 00:00:00 2001 From: TylerS1066 Date: Fri, 5 Mar 2021 12:51:58 -0600 Subject: [PATCH 263/304] 1.12.2 (#382) Update v1_12_R1 to 1.12.2 instead of 1.12.1 --- .github/workflows/maven.yml | 8 ++++---- README.md | 2 +- modules/v1_12_R1/pom.xml | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml index 7cf7a532d..a82b9a27e 100644 --- a/.github/workflows/maven.yml +++ b/.github/workflows/maven.yml @@ -43,12 +43,12 @@ jobs: - name: Build 1.11.2 if: steps.exploration.outputs.sucess != 'true' run: cd BuildTools && java -jar BuildTools.jar --rev 1.11.2 - - name: Check 1.12.1 + - name: Check 1.12.2 id: color - run: test -f ~/.m2/repository/org/bukkit/craftbukkit/1.12.1-R0.1-SNAPSHOT/craftbukkit-1.12.1-R0.1-SNAPSHOT.jar && echo "::set-output name=sucess::true" || echo "::set-output name=sucess::false" - - name: Build 1.12.1 + run: test -f ~/.m2/repository/org/bukkit/craftbukkit/1.12.2-R0.1-SNAPSHOT/craftbukkit-1.12.2-R0.1-SNAPSHOT.jar && echo "::set-output name=sucess::true" || echo "::set-output name=sucess::false" + - name: Build 1.12.2 if: steps.color.outputs.sucess != 'true' - run: cd BuildTools && java -jar BuildTools.jar --rev 1.12.1 + run: cd BuildTools && java -jar BuildTools.jar --rev 1.12.2 # EXAMPLE - Copy/paste as required to add version support to CI # - name: Test [version] diff --git a/README.md b/README.md index a9510b97d..74e463ba7 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ Movecraft uses multiple versions of the Spigot server software for legacy suppor ``` java -jar BuildTools.jar --rev 1.10.2 java -jar BuildTools.jar --rev 1.11.2 -java -jar BuildTools.jar --rev 1.12.1 +java -jar BuildTools.jar --rev 1.12.2 ``` Then, run the following to build Movecraft through `maven`. diff --git a/modules/v1_12_R1/pom.xml b/modules/v1_12_R1/pom.xml index 91f19842e..80c38f146 100644 --- a/modules/v1_12_R1/pom.xml +++ b/modules/v1_12_R1/pom.xml @@ -33,7 +33,7 @@ org.bukkit craftbukkit - 1.12.1-R0.1-SNAPSHOT + 1.12.2-R0.1-SNAPSHOT provided From ce8b8c9145eaa807225fa6b4d37987bd0554ac09 Mon Sep 17 00:00:00 2001 From: drfiveminusmint <52045376+drfiveminusmint@users.noreply.github.com> Date: Fri, 5 Mar 2021 14:03:35 -0500 Subject: [PATCH 264/304] Sinking patch (#380) * Torpedo Patch changes * Remove orphaned import * Variable name case * Add CraftStatus enum * Change craft status from boolean pair to enum * Rename to CraftStatus.of * Add files via upload * Missed a return type annotation --- .../movecraft/async/AsyncManager.java | 191 ++++++++++-------- .../async/translation/TranslationTask.java | 6 +- .../movecraft/utils/CraftStatus.java | 30 +++ 3 files changed, 146 insertions(+), 81 deletions(-) create mode 100644 modules/api/src/main/java/net/countercraft/movecraft/utils/CraftStatus.java diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java index 6fd8858e9..73d7d08db 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java @@ -33,13 +33,32 @@ import net.countercraft.movecraft.mapUpdater.MapUpdateManager; import net.countercraft.movecraft.mapUpdater.update.BlockCreateCommand; import net.countercraft.movecraft.mapUpdater.update.UpdateCommand; -import net.countercraft.movecraft.utils.*; -import org.bukkit.*; +import net.countercraft.movecraft.utils.BitmapHitBox; +import net.countercraft.movecraft.utils.CollectionUtils; +import net.countercraft.movecraft.utils.CraftStatus; +import net.countercraft.movecraft.utils.HitBox; +import net.countercraft.movecraft.utils.Pair; +import net.countercraft.movecraft.utils.SolidHitBox; +import org.bukkit.Bukkit; +import org.bukkit.ChatColor; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.Sound; +import org.bukkit.World; import org.bukkit.entity.Player; import org.bukkit.scheduler.BukkitRunnable; import org.jetbrains.annotations.NotNull; -import java.util.*; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Queue; +import java.util.Set; +import java.util.WeakHashMap; import java.util.concurrent.BlockingQueue; import java.util.concurrent.LinkedBlockingQueue; import java.util.logging.Level; @@ -453,64 +472,13 @@ private void detectSinking(){ if (ticksElapsed <= Settings.SinkCheckTicks) { continue; } - final World w = pcraft.getW(); - int totalNonNegligibleBlocks = 0; - int totalNonNegligibleWaterBlocks = 0; - HashMap, Integer> foundFlyBlocks = new HashMap<>(); - HashMap, Integer> foundMoveBlocks = new HashMap<>(); - // go through each block in the blocklist, and - // if its in the FlyBlocks, total up the number - // of them - for (MovecraftLocation l : pcraft.getHitBox()) { - int blockID = w.getBlockAt(l.getX(), l.getY(), l.getZ()).getTypeId(); - int dataID = (int) w.getBlockAt(l.getX(), l.getY(), l.getZ()).getData(); - int shiftedID = (blockID << 4) + dataID + 10000; - for (List flyBlockDef : pcraft.getType().getFlyBlocks().keySet()) { - if (flyBlockDef.contains(blockID) || flyBlockDef.contains(shiftedID)) { - foundFlyBlocks.merge(flyBlockDef, 1, (a, b) -> a + b); - } - } - for (List moveBlockDef : pcraft.getType().getMoveBlocks().keySet()) { - if (moveBlockDef.contains(blockID) || moveBlockDef.contains(shiftedID)) { - foundMoveBlocks.merge(moveBlockDef, 1, (a, b) -> a + b); - } - } - - if (blockID != 0 && blockID != 51) { - totalNonNegligibleBlocks++; - } - if (blockID != 0 && blockID != 51 && blockID != 8 && blockID != 9) { - totalNonNegligibleWaterBlocks++; - } - } - - // now see if any of the resulting percentagesit - // are below the threshold specified in - // SinkPercent - boolean isSinking = false; - for (List i : pcraft.getType().getFlyBlocks().keySet()) { - int numfound = 0; - if (foundFlyBlocks.get(i) != null) { - numfound = foundFlyBlocks.get(i); - } - double percent = ((double) numfound / (double) totalNonNegligibleBlocks) * 100.0; - double flyPercent = pcraft.getType().getFlyBlocks().get(i).get(0); - double sinkPercent = flyPercent * pcraft.getType().getSinkPercent() / 100.0; - if (percent < sinkPercent) { - isSinking = true; - } + CraftStatus status = checkCraftStatus(pcraft); - } - for (List i : pcraft.getType().getMoveBlocks().keySet()) { - int numfound = 0; - if (foundMoveBlocks.get(i) != null) { - numfound = foundMoveBlocks.get(i); - } - double percent = ((double) numfound / (double) totalNonNegligibleBlocks) * 100.0; - double movePercent = pcraft.getType().getMoveBlocks().get(i).get(0); - double disablePercent = movePercent * pcraft.getType().getSinkPercent() / 100.0; - if (percent < disablePercent && !pcraft.getDisabled() && pcraft.isNotProcessing()) { + //If the craft is disabled, play a sound and disable it. + //Only do this if the craft isn't already disabled. + if(status.isDisabled() && pcraft.isNotProcessing()) { + if (!pcraft.getDisabled()) { pcraft.setDisabled(true); if (pcraft.getNotificationPlayer() != null) { Location loc = pcraft.getNotificationPlayer().getLocation(); @@ -519,29 +487,10 @@ private void detectSinking(){ } } - // And check the overallsinkpercent - if (pcraft.getType().getOverallSinkPercent() != 0.0) { - double percent; - if (pcraft.getType().blockedByWater()) { - percent = (double) totalNonNegligibleBlocks - / (double) pcraft.getOrigBlockCount(); - } else { - percent = (double) totalNonNegligibleWaterBlocks - / (double) pcraft.getOrigBlockCount(); - } - if (percent * 100.0 < pcraft.getType().getOverallSinkPercent()) { - isSinking = true; - } - } - - if (totalNonNegligibleBlocks == 0) { - isSinking = true; - } - // if the craft is sinking, let the player // know and release the craft. Otherwise // update the time for the next check - if (isSinking && pcraft.isNotProcessing()) { + if (status.isSinking() && pcraft.isNotProcessing()) { Player notifyP = pcraft.getNotificationPlayer(); if (notifyP != null) { notifyP.sendMessage(I18nSupport.getInternationalisedString("Player - Craft is sinking")); @@ -720,6 +669,90 @@ else if (diffz < 0) { } } + //Returns a given craft's status as a CraftStatus enum. + @NotNull + public CraftStatus checkCraftStatus(@NotNull Craft craft) { + boolean isSinking = false; + boolean isDisabled = false; + int totalNonNegligibleBlocks = 0; + int totalNonNegligibleWaterBlocks = 0; + HashMap, Integer> foundFlyBlocks = new HashMap<>(); + HashMap, Integer> foundMoveBlocks = new HashMap<>(); + // go through each block in the HitBox, and + // if it's in the FlyBlocks, total up the number + // of them + for (MovecraftLocation l : craft.getHitBox()) { + int blockID = craft.getW().getBlockAt(l.getX(), l.getY(), l.getZ()).getTypeId(); + int dataID = (int) craft.getW().getBlockAt(l.getX(), l.getY(), l.getZ()).getData(); + int shiftedID = (blockID << 4) + dataID + 10000; + for (List flyBlockDef : craft.getType().getFlyBlocks().keySet()) { + if (flyBlockDef.contains(blockID) || flyBlockDef.contains(shiftedID)) { + foundFlyBlocks.merge(flyBlockDef, 1, (a, b) -> a + b); + } + } + for (List moveBlockDef : craft.getType().getMoveBlocks().keySet()) { + if (moveBlockDef.contains(blockID) || moveBlockDef.contains(shiftedID)) { + foundMoveBlocks.merge(moveBlockDef, 1, (a, b) -> a + b); + } + } + + if (blockID != 0 && blockID != 51) { + totalNonNegligibleBlocks++; + } + if (blockID != 0 && blockID != 51 && blockID != 8 && blockID != 9) { + totalNonNegligibleWaterBlocks++; + } + } + + // now see if any of the resulting percentages + // are below the threshold specified in + // SinkPercent + + for (List i : craft.getType().getFlyBlocks().keySet()) { + int numfound = 0; + if (foundFlyBlocks.get(i) != null) { + numfound = foundFlyBlocks.get(i); + } + double percent = ((double) numfound / (double) totalNonNegligibleBlocks) * 100.0; + double flyPercent = craft.getType().getFlyBlocks().get(i).get(0); + double sinkPercent = flyPercent * craft.getType().getSinkPercent() / 100.0; + if (percent < sinkPercent) { + isSinking = true; + } + } + for (List i : craft.getType().getMoveBlocks().keySet()) { + int numfound = 0; + if (foundMoveBlocks.get(i) != null) { + numfound = foundMoveBlocks.get(i); + } + double percent = ((double) numfound / (double) totalNonNegligibleBlocks) * 100.0; + double movePercent = craft.getType().getMoveBlocks().get(i).get(0); + double disablePercent = movePercent * craft.getType().getSinkPercent() / 100.0; + isDisabled = (percent < disablePercent && !craft.getDisabled() && craft.isNotProcessing()); + } + + // And check the OverallSinkPercent + if (craft.getType().getOverallSinkPercent() != 0.0) { + double percent; + if (craft.getType().blockedByWater()) { + percent = (double) totalNonNegligibleBlocks + / (double) craft.getOrigBlockCount(); + } else { + percent = (double) totalNonNegligibleWaterBlocks + / (double) craft.getOrigBlockCount(); + } + if (percent * 100.0 < craft.getType().getOverallSinkPercent()) { + isSinking = true; + } + } + + if (totalNonNegligibleBlocks == 0) { + isSinking = true; + } + + return CraftStatus.of(isSinking, isDisabled); + } + //Removed for refactor /*private void processScheduledBlockChanges() { for (World w : Bukkit.getWorlds()) { diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java index d692cfa99..012227465 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java @@ -328,8 +328,10 @@ protected void execute() throws InterruptedException, ExecutionException { if (!oldLocation.getBlock().getType().equals(Material.AIR)) { CraftCollisionExplosionEvent e = new CraftCollisionExplosionEvent(craft, newLocation, craft.getW()); Bukkit.getServer().getPluginManager().callEvent(e); - updates.add(new ExplosionUpdateCommand(newLocation, explosionForce)); - collisionExplosion = true; + if(!e.isCancelled()) { + updates.add(new ExplosionUpdateCommand(newLocation, explosionForce)); + collisionExplosion = true; + } } if (craft.getType().getFocusedExplosion()) { // don't handle any further collisions if it is set to focusedexplosion break; diff --git a/modules/api/src/main/java/net/countercraft/movecraft/utils/CraftStatus.java b/modules/api/src/main/java/net/countercraft/movecraft/utils/CraftStatus.java new file mode 100644 index 000000000..92642f1d8 --- /dev/null +++ b/modules/api/src/main/java/net/countercraft/movecraft/utils/CraftStatus.java @@ -0,0 +1,30 @@ +package net.countercraft.movecraft.utils; + + +public enum CraftStatus { + NORMAL, + SINKING, + DISABLED, + SINKING_DISABLED; + + public boolean isSinking() { + return (this == SINKING || this == SINKING_DISABLED); + } + + public boolean isDisabled() { + return (this == DISABLED || this == SINKING_DISABLED); + } + + public static CraftStatus of (boolean sinking, boolean disabled) { + if (!sinking && !disabled) { + return NORMAL; + } + if (!disabled) { + return SINKING; + } + if (!sinking) { + return DISABLED; + } + return SINKING_DISABLED; + } +} From 7167e57e22de0ed18b9d545988e672fb882be2a2 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Fri, 5 Mar 2021 23:03:36 +0100 Subject: [PATCH 265/304] fix --- .../countercraft/movecraft/craft/Craft.java | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/modules/api/src/main/java/net/countercraft/movecraft/craft/Craft.java b/modules/api/src/main/java/net/countercraft/movecraft/craft/Craft.java index 8ccac18f7..b6c30a94d 100644 --- a/modules/api/src/main/java/net/countercraft/movecraft/craft/Craft.java +++ b/modules/api/src/main/java/net/countercraft/movecraft/craft/Craft.java @@ -405,34 +405,34 @@ public int getWaterLine(){ int posZ; posZ = hitBox.getMinZ() - 1; for (posX = hitBox.getMinX() - 1; posX <= hitBox.getMaxX() + 1; posX++) { - int typeID = world.getBlockAt(posX, posY, posZ).getTypeId(); - if (typeID == 9) + Material type = world.getBlockAt(posX, posY, posZ).getType(); + if (type.name().endsWith("WATER")) numWater++; - if (typeID == 0) + if (type.name().endsWith("AIR")) numAir++; } posZ = hitBox.getMaxZ() + 1; for (posX = hitBox.getMinX() - 1; posX <= hitBox.getMaxX() + 1; posX++) { - int typeID = world.getBlockAt(posX, posY, posZ).getTypeId(); - if (typeID == 9) + Material type = world.getBlockAt(posX, posY, posZ).getType(); + if (type.name().endsWith("WATER")) numWater++; - if (typeID == 0) + if (type.name().endsWith("AIR")) numAir++; } posX = hitBox.getMinX() - 1; for (posZ = hitBox.getMinZ(); posZ <= hitBox.getMaxZ(); posZ++) { - int typeID = world.getBlockAt(posX, posY, posZ).getTypeId(); - if (typeID == 9) + Material type = world.getBlockAt(posX, posY, posZ).getType(); + if (type.name().endsWith("WATER")) numWater++; - if (typeID == 0) + if (type.name().endsWith("AIR")) numAir++; } posX = hitBox.getMaxX() + 1; for (posZ = hitBox.getMinZ(); posZ <= hitBox.getMaxZ(); posZ++) { - int typeID = world.getBlockAt(posX, posY, posZ).getTypeId(); - if (typeID == 9) + Material type = world.getBlockAt(posX, posY, posZ).getType(); + if (type.name().endsWith("WATER")) numWater++; - if (typeID == 0) + if (type.name().endsWith("AIR")) numAir++; } if (numWater > numAir) { From f0ae2337e36c473dba590d9813d7f441cf7bbe41 Mon Sep 17 00:00:00 2001 From: TylerS1066 Date: Sat, 6 Mar 2021 09:51:35 -0600 Subject: [PATCH 266/304] Bump version --- modules/Movecraft/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/Movecraft/pom.xml b/modules/Movecraft/pom.xml index fa1977446..0e98c4d43 100644 --- a/modules/Movecraft/pom.xml +++ b/modules/Movecraft/pom.xml @@ -9,7 +9,7 @@ UTF-8 - 7.0.0_beta_9-SNAPSHOT.2 + 7.0.0_beta_9-SNAPSHOT From 61d66eacaa5f62397b28db1b6c90854194774a08 Mon Sep 17 00:00:00 2001 From: TylerS1066 Date: Sat, 6 Mar 2021 10:05:15 -0600 Subject: [PATCH 267/304] Remove Towny --- .gitignore | 1 - libs/Towny.jar | Bin 715172 -> 0 bytes modules/Movecraft/dependency-reduced-pom.xml | 9 +- modules/Movecraft/pom.xml | 10 +- .../net/countercraft/movecraft/Movecraft.java | 23 -- .../async/rotation/RotationTask.java | 9 - .../async/translation/TranslationTask.java | 1 - .../movecraft/towny/TownyCompatManager.java | 143 ---------- .../movecraft/utils/TownyUtils.java | 262 ------------------ .../Movecraft/src/main/resources/config.yml | 8 - .../src/main/resources/config_legacy.yml | 8 - .../localisation/movecraftlang_cz.properties | 4 - .../localisation/movecraftlang_en.properties | 10 - .../localisation/movecraftlang_no.properties | 4 - .../Movecraft/src/main/resources/plugin.yml | 2 +- .../movecraft/config/Settings.java | 4 - .../utils/TownyWorldHeightLimits.java | 44 --- 17 files changed, 3 insertions(+), 539 deletions(-) delete mode 100644 libs/Towny.jar delete mode 100644 modules/Movecraft/src/main/java/net/countercraft/movecraft/towny/TownyCompatManager.java delete mode 100644 modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/TownyUtils.java delete mode 100644 modules/api/src/main/java/net/countercraft/movecraft/utils/TownyWorldHeightLimits.java diff --git a/.gitignore b/.gitignore index 8b79f57e4..1adb3d79e 100644 --- a/.gitignore +++ b/.gitignore @@ -8,7 +8,6 @@ *.jar *.war *.ear -!libs/Towny.jar !libs/WGCustomFlags.jar # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml diff --git a/libs/Towny.jar b/libs/Towny.jar deleted file mode 100644 index da94c58cdf2cadd3c39f3b4342da4be80b54f5dc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 715172 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

  • 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 |TTvF!@BqnJ3418jW8#ce)R{#t6Cp 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

    TPfKQ=J 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ºZDgB2vDB&ZlcT1y~$`Xmg47JR$w-%<72| zY-b#MqV|nc+DLJfT^U@9G=O5cR<6+mD?nf})dJ`n511|WYyr%cJo^Img>J&ix*~UD zsSt!(G5%{Yydqosb_$mtyE4W-x7dB@v}K_ zD|lCC>olWv96{B&6L3}dtN`2+cd7wgl|2&zw`8kbh|D;$Z~dc*m<~exUlM&YgXL9k zBLSSi_X@xn^_H>BT8?uSfT+YX2S8N*3RUNRFZAjlVQ5zjF z00ktojsTwhsf;SQvO#9ID**rTuZX}$1i*ljrdK3OL;eMKcr34D9!}8azwAx|dNf$w>V`0coIo-D2QR z*2{k2LGI(&(o?SX5fn@Wcpl&H*f&6bx1BJc{@{e{Rk_B4Gyq=nLIx;ZQ#oB5q^`;K zZ=;`=7z#o{QCs#2eS?ezR|qN;%9c^KRr)I`Tp}kkto(PBzHk>%?+B45R4E3VOl=vi zBhFr~%EGQt6et!`QKCu%NiV-Vp<0tPsD=w^M{Ox9%)9%#P5sPiwho*NYD7pqwFJ2W z-3FFN{jpuk{$j&+D9xn>+oQXd6Ndy7qMNGBr3BN#HUf^tg&kmDl^p3H{Qz9?!T#v@ zioyY~3WbJ&l|NK+MTHq4L#VNBK_uu%rG}Z6;W^e2&N0tnn&yI#1xAGuDv6T))V;Vh z3O|>yVMkO_>HzFBs#GMrRX1fKw5G8WoXcWBd6s3H6!)$w|G1J zF04%S0jYZ7=~Fl?e|i%e$cLv7SocC{&cZ8#d3EQZF)N6l^$E2NB{nf zOZg9x80QFLI;}XskGv5LRg6x0(J;7RarV-F&=#3%ko{C2HHbzFwc0q*HbD!Qn(Y#|y%nk)Cv)t;u- z|3WcYFKgt*E>X$xKDWEDMMj&*7Pd@*ae%vWkhb~2M`=8ctmvVTu+3br&NnXyGIXggU_+*61w^qtZQVbi$E_D%BMnoedJvh7#OS zMy00L3Nkb|!^aK0%=0XSOu1suh z<6`nc-Bg`yxKt97*6MCzcLD>-38qrTn!%VXM!Qu5(b>+rEF74NK`Cr`D(0i8$O7cX zMO&Fpvf!oc!n_x7=|3ieAxPQ*+TaDu?e(a6u)rsz!+c9Qu##U;4Lz{Pcn|=h>=*q`{%eg3>sf79F@IV z$wXCEy3d<#h(x`fE3;K(DO|7`VwgC!ru+cYMkBG*l5vHvwpePscn2hiR?4?NQKQtu z03y!iE9ouq4 z9x9|Z6ZU~nUmF7+oxT8-ZX~`9Upy&Uv*?kQo~L>(3cZT80;&cPB=w8bI;;#rl)ZGh zxmG~!1Q_E7g4MH0)nxltO$QiQZn|mR;QsSRY~m0KnzoZT2=-pd-G3Ejmb15*=TSF> zEDp{Cv+F0E_t9}C@0W>zh3k4E^h66Ty5kgiryQ+x8&|HJ4 zIgr$TMDm!6%ezrzhfA@xFe$0XK-Bzpo#bzA$~S4W2xVk> zSkjcJu5k4-cX-e}2a$oY{y7d=_Oq(U?>xOLE#?k;F>!G#CL#63O#%N(MS7>lu2EEI zO;wcVHtSaCe?A*&MSaPJo*Jmv?Ql|zD(%yE=}n-)DiF9-CYQDrm7OXh{mS&er42nY z(maN^5|s#h7zUw;(l6SD2ED< zy9&t0WsxSSOGmbt^{IKfoiGo!nASu0Eh1_<_;3-u*ZY&N9?Ix&W$E)2Wsvo75;=9- zo~a}B{5thmzq=w~nCcFI$+%x3#X2YiOFIE)0|Ge;?7Q>IxplG;piN>v?bcQ(50%RuOmR>re&K2=q%3so=bD9 zDw_|qujEz8(p*^VeQBHxi=l1J-XasVqsDUlb!wJ1Q+Ib2^K>KEWS$znzAp$p_>x>QXNYwBp7P1&&Bpkig3Ibj0lOlDV*qWT!Ll$qJ%x3p48ROB z(L(K$mO_U*z9Zd!T}`$+CJW(heAyb3wVy_2^IaP|i)9MAyk<*dQ7@&>=~Ylu{p#(272JFtST!6+>QJ4nkt95%qI39v_SL~TTb?^VWy2zB+;(9YG{ z!1N+SRP+xtBiV>_f&79#fu*&?U3E*Ul(r};(r)!DZCxm2NjvPGozNtBsyb}5<-fJ9 z^ExI}G^%Xsb;zzZ%4=Je+^oB0Uo43>%WGSg5KblT=`3t!_$f9o(+R6Vpo$4;D$2I; za{FIP^j%}Sliaw$7n@}>R?_v<-5sR-NZdyH#OTdSHTb2rNAuLV4L|rpZtq2oG)ud< z8cP*7%_|X3-3vMfRXjkQb3FVV{C^HKH`GAC%P)T|@t^7!bj+&YaXX*>OZN_BVz)Kc zIu(9MEF~;M$i!V7Z(X8%h%Du(k_1$k%o(9i6QOwgS;(T@F<@gPzzMc&3d5w?lS1l) z{^MP+W?eZNNdO!u7NTWNR!LtgBb4l&Q&Fs-qJKzTizf^&%~$88dx%|&qT?`I`gt=b z881VWBj`q2+<(mYozvj;erK;djz(&fO%xc0AdcQt!2iEW68g7j21+j;T1@V5EEN=Ds`5$^p z1(b-2Q$(cvh6-Bt>iRALQ$O49*qsSC#>X$}O(e4u*Vc8NkPl2+2WslEGN9nI3exdd$ zr9G+!%-A>Eyk6W64y;^j-h1pRVEbX9)V9u12wq zc(6(MAPoQVGl^TMl=fTV>X2{bP2~8V>lBNFRvtS$Xw*|~v}VQRjbaj)yw%omLoDzR zQtGcN__EYX_t5kTsb*_(wW#t*$<4gq>taimKKuaVbe;H}Z(eIlE&;B)Wmqn_snaSB z%7aRh5*d`QslZTH>aW(Tb?WgD!STFlME^jQR*|gq@iQs?HRk7@{sSk?bn+Y*{U7?4 zgj=UnTH?A%mA7Tdbe=+7y6^De@|Dq=V=P=r+C?VHxXtjwI0h9GL^C?!V#CJN8${to z&vb+6(~+#30My%}!t~B;JQP_{O?S1zTwNIVFETTZf6S-t&>Q?D3u>$wI;}*q85?W% zp7HSvu$ypoyU}Z8Mn{5$UH13%Eg4OH(d^?zgM9S-0E>z^=|ELAsN$Cc^l>KW2dxfn z4P6QQ^!R^Kc2+@=G(nu-g+&&3cXxMpc5!ELcXxMp9~>5UcU^RF`_RGN-C69oyO+DC zi;JkPsIKU!e&~#-tjz5H@5+k>b^>)g~cg z4^EI-n&`st!6I-j3P;T7H%b*hemln(jM~*71y;UF7Xv{Q5y>`ZWfHmU*W~UUK|ntDRs{Opd-vFNKnJa4?AX?s)jmkrBR+ z_fMTRS>{R+^33xzsN=U{7}u+NF9o-!L5TU_+H|vf_V_2bPwYdp(r;i`(CVwyQ5@Ns{VTXzr(p}yG> z>&RM^N!zjLo!RF)#!z@X@l=ZC7d1P&%9D4LN4_|1CsBm>h6Rl$pNdqN?JF^ z_bB##JPg^3pB)UIiz&B=n*XFaqXcbhxaBGq#0nH5Zoxq2#0 z3yckJQ!E&ky^@LUa&OOhxamywkU4 z_%K<{4tJxXy}OW(2Z%9hCDms!*)-I3yonoD?DU`YC>2!&2dNSf&C(O$V@-@1#$2qn zI;ecUFL>dvcWnX++LzOgdL<&&3LX@yLQ)-G0%ce*Q zxhyTiOpS9j<y%Mz|x^!A`ThoJLnJk?%a2bQ#jj|*vL`Q<aNnm}{<` zJ0#8*>XOZp1)o&!d`DY~O|t!DGhdO(CsNM$NIpL~(^F5B3Un;`e5JaLA6+J%9}WB8 zWTN+fQO#Gys6D4b%aSs^POj{+3$?{EM~3wl@7B>gX9aph>oc!W#NhSqa^LAVI>^Im z6u>bSIh_}|Ow0;-%TT?`dYq5D=86|>GD$AmdwB=B{IDU;I`!gUTuHt)Ybz~nr+9As!F|H5V|$mNS1Iq)1sE9CNNf!dnM&3LW(^KWv^ zd}o}d{8?mho9D!WHka?2Xhr@vXa9P2c+o%JYfo3}U`!WW+p(k9A#-!wd0>hI}JWoAuuzk#0TwL-V zG~X)8Qwkyvj(H!APsbj|X?llKu2!z$-t%?dNkfkiDo4!mP?26f%EbCp?xN8j@~4!O z`@9~AEGSJwDwsVFO7=-I1Fn#O*C zqx^9b3D3ZWDP%|gh2>$+z|lYBs4+8mP* zVHtyfxU6}=R-;TS;UlAq4M*ru`CR>|I>GxUEhDkJ zqktE3DBJ6gcGLz>bz+eN%pJowTIOtP`q!{Var8jNbjCr^&{Qqu=oHu67w=tiBG6KR zzt*ml!7;ru-wji!&`)udX{mw}?oT6ICW@)f#iobc^rsV&$<)`&@nprhkqIvQI`?U} z+N|gmPlq2h{?aJNr)z<%Xlz1OyLS}7=U}B5;ea$NED4#1nlySb(vn39xE4vQ2SFH2 ztZE!sK#o722IQAZ#Lm%F_5C5Yts8+sGLr_CLtW#oo-~k&iXQ73iJxuLMQn=GL!09< zgo!zXl9jej4Z3fy9Vs9p_F;5E{v03!QL-8@9sK%JG+Fl*Zq_NNIA+p7L}p}WmiVo& zuZ&KoH~oi%98LNa)9&gwUv%+EYSyhYnf_(FQ$$YcU18^*QPwt7qrrG*3{el-ziST) zzFSegzl=ZS%gD(Wx^PV%VqiNDfBv_VyBXQKY;iS}fm~(*zGX-AO$c$Qrb=j{CirsI z3uKX?6N(cU!NH#|=vybX+pvGp`ZjQA#OQGUq0%*)oW+i&{~)KAkrgCBu;uN>sK^JR zc18Jnx6-uho*f-32cAm<*@}rHVq%F*PFkG8?)a$4WgfeHgrsoY8L3t_kjTlq4=dWA z8^*KMSHtB(lje?QtMJdl7{|}8HQ!q%aqxA}0C(pTqbCxET?sbSl21-YL4Ih#6TxAe zi_?R<0k^n1Mv}N?4{wgTgV?&|r zFb0@}K}k!aF%q`>!6NG4?dwP`=hj2gMw;!D&owbot9D4&pNH)xr=r(Qc`35x3}S{# z0Y8SW;gxlhcCYE&`N>RZmP^A;G!KW*T^6nY&hpBfs%E`fafDdc&-n!Yf&0+jWDUb=J93;W9*I*MLXZS*YDrG_A6$j&3z4cM``5? z`0tmsKn&jeWz!Xm-SkrNgB6(DsdqCmsp_Iyyq1fsvL{=@8oTIAb=PAROu@~{oyLTD zvO%m;4`Mx1;*F!Ls@AukS+(ci|GP^@W;P0ChNY3J2_tjtTXP}$L_KzT*#L@tX%TCZ zN)Qz*MiguHSm7+ax9?nnS;U*S`-gU`dTukH8VlN}P$pw6Jv1!S65!<_s!DiHpvAd4 z=S6Z`w>+9^-a>WJJ|fgTBGS-6*-Rl*6il(w-^1_WV~pYKL#_Lq6F!L@$qbK@uC7ej z8nh{3Hosux;8e0zH2JYn(}|N}CW+N+UvHc2H&uyQeC_GopHGWy`$Qd)sn+WB8OaS8YGvPyX#C^Wy7+M8`9 zX}!TsJ=Ou9Ot-!}8qW_4y$&-bJElX*%M_jqDm^_NyOrDx#-iXIuQ;V(F;`+)y}7gK zVNZu46Bls0d9t%kpoJ$G`IMLUuX$EJ0vl64wmsghB4ij94IHsUK6NW z!hJ3bMBdEy$hZ5R!Wmkj{0QlZH&{Y}nCGxnpA5{vq(xpYJK}QtxYN9y*1$c{FIsJ0 zB=~)5!GS7$l-0p|Dp+8wKYCf-zoNDKI7fNEQ+?3d(xk>}tz~8<5td7tM|_|guh7UW zjoUmRW?>=spJtKj#e`z&%T89(^l-UmdbHbomTnA}N-fizUtO$la+1W&ZJ+u{eJ>l*`#4sB1H(v+;CD?j_Nit>hcVy5(%g z7+nrScC>y%Dqm?XWS2+{nErv@43ZXprevesE1F#yR(FPg`*qMT9_6kz`I2cjzXtS4 zgL3^9pDjnc)qlde{Nt~05)W5^kG7Q)(nr35%e;T&Sh$xPzob|A;!6PM+R?*t48!}oI6#$&-H;4(8q?cR znz0yN9-TolG{!8~Ci#Kg3@Rfh)s)2gcn*dbas=6_fbA7JiB z*bi=##1+!%n5OS5TQL8vt}$=d7gFql&EV1#fMW(|aQLz}uI}erYN48;xvBfj2>2?a z@U0~nS88BhhSm#;wv}nlkzJ6K>O``VZFWVA=G=lQUA!GziTMy0hYqJbacc(NvL}}6 zUUdENLOW>5nlRgScHCd=IeV&=vOqjjXgGq!?>`gwxK^vI`-IAP!FC&Kjtc_2F^-D( zdQ(17D1q51#|hDVBCiDfNMb`y0RcZ1Q3v}#B8@v@)Lw!{qf%Q@hwdZa4prfN6IoA# zfCaCGR3fMG~Eb zSxUiOLdE%}D-JwJ9+KN*)eDwI%k+vg)#bW*5nY}2oxuvJ{N|q6z)*jCR|R4wpaw=4 z_MR)C&>^`e7?U!MiNgoHVbT-=NfFXe`d=Qe>n^&d&^JKeNr=2*_cxau#o@nJzI>&W zez6sMnF<0EQ5O6+1k^&qQHpN69ejuPNu}{eCvU7gQl!iSERh|#B!MQr&WBjrnQJ1G z>kzlfhMDKeN||GzqV4&Dia{R2e{MK+;<6Dx`Q(Zfe)EADnk)!8MxKoXZ+#IWM9{)b zL}RUZvGGQq!)`A8X4W$-{>=S)^hlkzql6(uHTs>3i6g{kfRwB%JawGUqi&UD6a z9_VN-)g>%8T7WL%v(#Zx9j>m7aL1u)^Uz)thbieNtaOsbHa(xq(KsO*RcJv;&-axR zbRDaXsFk?#K9>4X7jY?Z<2_m)LL_lAHOs);gydZtk;0bJWSN$On%rdfj5=r=tnW^h zCv|3*P@3MHpf7@eZfz72?o}Pm%gf&3Kry*@{^7LnH$V4L_1`mW`}?5d+0G9LU1Ug( zeb&q|Nb-UM0_eeYSOju_E&KDSkrE-oCX)DV)0vSaWAn_`k3qe9@_Kv)e+u`S5CMwm z@&}ZBfleX?iAt&j(L$kEmSoFRZ=9HwxU&vKg{-Jp;a(`YzR%VH31X5p;aFWDLbegS zt9f0cBKT-DOziIZVYK3#s%SsQ^`NUQCp?5BT`S|j(%l~-xSgLg{dz4Z`oWUd(5V9v zN=OFcly9&xTGZvn8>B=3L=f?R$bw-3AmE_0J65$J_8{bZcMq(uYvw(TRG?vPM$ z47kh@*VysrD+H4nj3J|@Bc@{DnI~KI5v?Qr)i;mZpzHQcV(~r^0u1H@Gm?7lv3O@W zzwcH6jUXSwr?4&`7WFagy~_eMOynJ*8qh9BXA7e36d*C$pRT;w6V13a)Jkl4)@CH&JZ}2@qvJ>w0B6uQJj%)4 z&%N^MbN)_l8<@Y%`z(phK`4!zu)uUcpVW;1rz%BEY*k{39!#*?sPJ&3PSW)y!@ZMg zd>_V8i&nFZJIat8N;e&D7sAW#V{YaUq}n=AL0~=_2OuA)8vD^~D1)45^>iERDC=K} zHIT{|lV7vkL@6ARAM>v1BbI$SeRn!N!lyH*7s#V`yu06pZ$w>qDN}OcBdDBr@Cz7% z=Ea2e*-RjQ|70dS60gXvR1DKPARvLM8g}1?IZG#+)QuTT&^q`=Ft68W>@$XTv3M#< z-`1z!NRX+UjGo@jGQ#|Cqzpu!A&I|jUuKX6^eDk8&aAlc+dy!Oamlu11staSvx9B4 zguIUnRwioF30ted@|NbTiv_PUKGelqv>?u}^ZkAv?wF6Fd*~`@slM8&Xl|!XtJM8g z7@%vNBcH2E9^qJlURHtboV|C;6Sk;R0KGhVDHr-X=JYaIq&9w#cLPnmjl%l+yoQE3 zX;C%{AwL(d4HGzLs?8-eP!ruZ7(S1Ya-f`1U2>5hj%EQBK|uL0yTUwc$51K9yf_Qb zRzX*LeSX$iuvt#EqEvv9(VidGy+njHRaU)fX^?fNQr*q*pEpa&OgU7VZ|OYKa7|rE zQ|ka2LL-~!qmv`G;)vz=N>;V2PqD*guKYnSK}uwXK?A0WdugC;r-fgUIfOAPd8RB@ z%rg&A8Ad&5$IRopCXUelMgyIbXhH~~qM;y$Q5+glWFjc(*Mb0@ABmnTp_y7@$I6LY z8ii?G(+(QD5{cr(m8IFF6~gFh@P{dNx3s~L#KjL@qNu01ZZJm~N$xkMO&rn|u>r!_ zY2mp_Aa0}(LKXp_Q|pP8Ky1o37X2sH*z4oo;)MKIdFFmQ`R6>(*!+38)xtI-jQ|Va zAauPha0a?*%$7oD2vpB$OVAY*XQ9~m+fq`_=&A|gk(uE&cWN6edu**9>`Re7VNw5$ z+4$}mj)6ahaX-C5#h;x1sHHktc(n2vNn^^uRQ9>e7HVrk2CBYEf}jgP(I_iH*QMKR zWFukGs^Ds-8GUJ6Gisq3Gj>j(+@}HGOgEIda_MX9@v~JY;-a?Sec7n1tbPN@y2&`|U4Og%Tq2bR z4>b4Mg=)%wRjsm2-x>ZXbY3-pgtk&I{iCW2x#|H-FgV*=etGsL{;N-I-}mFL-#51d z>E;Dr<8dASRPngwE5!iyim%ZBCbZx7*J#HeRmS*r8$kTG;rnWcFqcI5Vjt@uo?~)^ zHAOjU+C>-zL0K3lgxd$%+u2d6y|u_H#){3UZWr%9Cf(!8dJ2c}kj{efKvBy?S#|(RD#;FWs z9o+bvS|egrQ^NXBw#KPtwnp4XFy1bRK?B(jtTAeqP@oGA2R-eTJLLy1p8sB%%o7{y zBK$Dq2jI7&ADlPY;;aoT7|%3VoqKUb^z=cTONM^J>GXf}Yc!^V)z8(Z4DOQls0N>W zA^$=?`C{=$ZAHCNI#w&cF{O&3NfQiR9XJI8+g!?II=q=<9j-lOWuT419SWjPdhD zw{tfb`f$NBWc(Q-4@g|`Iz(+*gLeuL3s_ySLVZ0%o%!kW!{Tu8mOiC!ME#yCVFYT= zr?bji+>@Ac%aZv*qdjUcw7SNT{YFK>T;rBeXO3R7wu@1i-YZ05dGO-hOyibNU&^d( zTutrHgKX~rrv-85exW-|AM5LsuFXQ*tHZAfUjS#l&2$ep9qy9oM$^0EGFn!|2JuM5 zwEkK?DI6%_>aEk1KpJroo^;OcD*Mz&do09kYEW?Yj@Y?jKrZVSaruaRZ2lQawKQXy z`v!qszcst~!95;m;AHYy3pPipY%EzFTaA_F{i!}v)Q!Z-2eo?5IEsVjB)k2PA(jRK z&$+e@3}PMS(or7Djj^@wGD|;J3&S$hl;W}EHKe+X$P@a=NN}*}t1ehhau)jF5rhmGTy6y$Qub^Q&7BvMvEpz#% z8?0R~_G4R6tg5Qs@8&?1oeuLtd1QC-?2+Im@dw7tf5VD?lb9~x#7-Q!BS=1_ z7py!IhnsHUq{$0ca|ls$h){D#P`ip$`=UMxLsx9#R`?^R^w6vH;H&iTs|Z5+WibH8 zeER6}ep=k+ITFnX8IPCorW%Aj=E%Ol$LHL-B;Gpxy1QVd`5aYN^1s`m`8@8YF~Cl_ z)rkk*j*uR_k{%>TkLL%b5`VSG)EUWfWT|mvvH#V7jm5{2rN*NDu|TW2oJ5Q2BT;jMvZG5 zRtAeW5`3~g&$`&EI64%RZ|=>)GDnllvkhbEQyJNk9m0`ax~Jamp1tkl2{%FO5ADul zqlILbgo5tKNWH7AFwl|{Y@-!u!;87>%vXCb)(&KMWK;yTIH;nnWh^2E&q9c1Va zD+bNKR5&8#!yny=wZ~%jQ-!|q82nJ&8MhyK#?>vz#StEv5a6eDuDR=Oxje6au-eql zzpQz1uNzUw9l+hzO;*+t3=y;sLg+MnNC{iXU!SE%nr> zDozsWwPEhl51n~-dGpG)Lnv$vb8nx~Te3Je+c?pRl-IHn1Fk)TVKr7I`(1W6Yu_uq z=!Mq~8GD;8+;8u6oV455nU{j|t36Dy8T`g*-=)<~CUkZ%>HIh=?>WovAIksZZXL)r zt?E{XagbK;-eb8FE|S@Dli7-)^V_0*C(+HyeJfxpK4-!aF(cMP_VYGZIo;!X9-~PjS-Eq{g9ItR(y*V^Cu^B`mFn>eon^HargXE&wH#~LG z!;e2J;}#gC^&;cY*H7NVo5rjuTBs;KlCRSz_byQ^@owEMcc5+x^79Bw zT)?PsA>il}+(4|@R5A5}MOZ*zRP@8XTEJ;ea&>6X4A-T+GHMSBIbT=1<6TL0i|2Qd}L z;pS{x&>zyb-yyv2CGMK>?@xa*>OBX4euC{b)@}TZU601YH~XdFtzqq3?IqyWMCa`* zz@QgZujm!5`+-8ggWN>vi{2F}JYavA4W9Rf_la6=@_5mBBn*g!+zQ9=f{RPO=w?2x zQuc+JIhy$cSR12%Y4XM08dj7Ja%BSQ4H+D!-=;qwyb=HE(MSG46!kcYUL=_Jxo zllyD=rfBe3s{FB$g_FKkBnTUP5t80_sLTmOB^sm?!H(^#RkMz>N;KDLVb6V(~&mp)LtF`;>NZ4Rn^GU zUn95h6*^y&v&ilOo94&VPI!>g2jt?aOmbZuK_7hXa*S%8=@hip zHW`R2fHqh`)=R^ao4U+=L%M!#{bFoQR-M&lf_gws zB}HtLfYt&N8~lm9%tITy*2lKi)_Q&3D6k@zIA2K#rTJ^UdYKa%pD8M=$S<{Eb44 zFzhZc#4|X=GdaZ5C9ZvuufR>^>@d_bI>u85=Oz_)Nc9vDAhu36#3;6|eKFG05;!Zo z69D-S5-GUXF@pzx?LYPr2N)j4 zBV%c|@-Ikdg?q?`5%C@-FU!tD{Q^B^CQJ)LovGICvq>$2= zTD$+MknJK%O0$XoT#y?Ip%(C$1#clbK0RL(?k*0OfvXW`A-xV`XMmIyd&njmEBL9uxF60&C(EDzAX% z{_T$Oj~VokXG_+MnGx40oB`~pf;Tid1E%mB`XR@UM4YecJg+xp*66>CpxX^&f=}I? zp#bc?7k}38v_i@hQNIh*G8p)xX$!kD=%6F5jLS2aKvB3ESy495(LCytXk|vaksTx; z_#uJ@6j^Ht5eDqLAzpw>5e*u$pMf7ENz#- zD~Lz47Pac2Wmmu}rd>pcf+*|&f_ zvvKNqlUyeWz~&x*-^GI3H6I?fqf@X|y4giaW4Kgf9MY>SDOVqfepM58YCC1VR1O*H zv2I`ag+;R3OTO*YJTdw&Dk84d4SKnK33q*4+rqKQCbyq&bZ#j#P}ZoubsB+c4v+r8 zq39+#h@eAq&BgCehmdCcUI*Y6>63cZuP8}V_N5EZ^{dR?@DwiB8(;OrF-$1;@kTmV zo7e$~|6;D4Sieyk{WpvLSFSG6;m)!7sSktD2t~X1D#*Y!!k_2T$1v)IN^^=_cl7b+bKDLiEt{f$y@wps37QW8VBe(g-b5leHNQU;m&Wufi28$Qas9G zfgtPd2&&&_{d%Asl}RM#%`_6*4dv^l$bB*v&3AL+q|w>CXzg060t&iF+?LU=!@No{ zK!Mtb?!IA}TBnBO%|dvfeQ0S1+MobK!^tzNNQ|kjvi zN4ydZy&JCv^x)9VRoUL5v8I@JV$NiZc{iHIK_{+saynA3D~d=L=ptBkUNWoqK*~d`y})vND&PC^zZ|* z3z!2}Lg@_Io3Rtbu+`u;Bm@cQzXEtSJgL#th83P@8qsCjYz>69Xo`dH#xMeOc|p`e z3LI4VVMh(;m^TpTSXX@s6B^}=(1r*|@f?aeVwR@8jfa|w! zzj+KZSoa1~hoRSeVu<@(=7v#+x!0sE>I$s43)6}^!4;JccE5r5(R%}JV*YJ<`a*_^ z-%!7bpPTp$8`$QrOmsYFzYh8Pr7l3P_M_AM_uF@5@I8;zsm9{h`Y|qAn`iit`qyoy z#V>@#2+1umfwK!SBP%A1rT(x1z78dTEH<3%?Vt5< zSHd7h8hvyzK|nBFtlx1ZODl8rfM?DVo?v`H!d~HEKcWumsdx!9i5s!2_-~hQX)%n- zos#s`#7I^3{*f4JAsfhf$XsO|ac?U;6{1%0b zOH_n16nIura!EYA>)hHDyVGrwg{zr|F&I(Q+^E>*Sb{Ha!NoL!etwOA->vx;6(Pu( zIC~x9)66>{2FVIC5`lpb&SOf6J*qQ zaIN!}sy31 zidXOHt73{$@0qRA$I!|RT&!NGqPJ1eyj)c0sHnO>#p150x;+)+B0h<(=F_-PU+_d| z{m*Za*h5J{9O~Zm({pZ1rbT6syDyO=pmH(2UB*Q#q4@`2n5@LtZ+jN9rzd&AQsTVbJ4;Zz$9SJ&{Wi5E1xmD z_RAd@lQ;f*;a5*V65ksBLk{3q?wNYsQhMFPxd7XYyXakB`8@c=?Hr^=^A9#K#9;@J*~B|(0;m2N=8S-v zqHwSqC94VcTvmq9*9NUf(Y#Gs16jy>)=t2#<}}*t9_gf%V-tdSg&_q_0&O_ z<968lSIU1cLdOj9$E16I%3>ov{tGtF{1Icu4xr2))MCS38pmkYZw;Jc!z4;)G%B-& zVjf+(rUUjc^7j#eQG1hfx2e4l-pKd|>l*3z8u8gpp=DDut2@s7RZOwYD4Mi1!P#aL zCR)Vch=;V12BSveiIjJ+CvTv9Ds}xBTf|gaN3{}?dCb0&22(`63~x>@sdT-IDNz?7 z-aLIw**1<~&_3A&YDD=8*pQIK2`dySVt(#fiqDu{j*9(bX~H=HT%KIo2?g?0r||~*?z|x zpBK?z(b_}qG5BY{Td|Kn-5CzR^jpSTv|e@nX^(NvH!m;B0Ik}+y0MlwL@& zY0EbbU-(f)edg6sdZ8vmp?q3UoK2y_7LVRYJ;df*4jbQu2+X-H(gt_;y(H=dxyL)6EU{1 z@kZV4?*>hK?AHU;Lea~_pSQUC3l>S5`6(CsOkmMo5}#4*B%M#v*NOB4oR{bvW&=qk zf5Mk%d9PMq@w^x_?6J1Q{H-LLgSA__m)dobE%E7(Z(gtDFZFLqLS(|C$6ctW7NbY` zCNqL7x3UZ`a4uV;#QSZHqW)#86Ibe*FGb_YpDH2yb=Ku?l8EV_8q`J`rZ3r9q@PMn z`&ZWSZ?cT3KI$FoWx!EL>yGt04LYSG`fz@UayOYu{xp>t8c2`$D4&r!Atk3%a)z~{ zT_~_bl^x$##o6jhNCKD+!sk{POAhrv$7_sW)-K0^|Fc&4^q7| zsfrIjWRX=W>C_&hib*Q!)LO0FUaDoB#N&5!cvStoQ#zVq(_SIK@v9r^zle|7jp!o4 zrX;HMuph>(4og~ z?^P^(Dzdv5G?*X4v(W_q;C^CHlPe>9|0|Rvhhg^z`xEyliG(6{p8Y9?2dBh>h?xPW zz{0*jye08-U`CRLUC?u)d!dSGe@1Y0O>p$dJCXRF#KD;~hF)M4kxAg_9;kA}XHgdA zEY#e#GxnQhHk`UlR2V-`05`s6XY7L|ijxTk3cHs0x27f*-a# zEb;bPxiU<9wZTx3()^Ie9Cx%^ZG2rx^Vd0r2ft;#VD1B>Faa!A))RN`ep_CH*1OvC`8f!E zj2IPRb&wZu8TKqJn)F2EBQrU86~K&#D;)&QFUE0vVX1~s{K;RrSa6NdCiuniXyr#3 z!`pKL6cS=&)=G!T$qjHynb*cBL;B5P`5>dB;HnRwGr!#%{U`K9+t$7DLUkEqY9c^L zB@auCyVy{5&u;yC#_j!Us#P^wU!|$aWnpJJ^&VS<_8jlkh`MX(kyT~IO`-oEpSvGi zSO3^XWJkt~r`DD2QP}fy-tlcQt*gd#r3v@RGAx+(+`Nuyv9`*hhq=n6ZRKIwMY~dA zVnJ}n#9KG{@N24*#Qtuz_-WxIW9?qL?F72*)kB!#IrQ_LUY^{mMVuNbiur`+0zYr-)(?-&F}=epeE6XhQy}!}}4kXb7kZ zA3(ImSr5{FvFAi1(kL=)8V})fBeT^sF)YJ_sjIrV2J-#fRDQXR%7XP-Fnt!44>DL( zdltv+GqC1Ew}zHgW7o3bjB!(Q0a$S2zc;FCF>|IrsDB4m!GTdY6A)EJxfG@>UaY@o z7hpANRfbL}m)Q2wnZ&3=@$0BJELyYj8>lzARfg+T0ULD|o!z^%L6>UuV5*kr#R~Qn z)l-I6@!Tr?`O}cU>ugI|mm@E-8K=8xh<7S3-3u@JrwYt1^C1EmdMCb#&r}pEOW$j!Am6@y zQiGdp8{bvXR~wG*#RGn4Z#3Zic$HiGi6Hlw)QWyC{xDJS;NMA0(a}KcCH42V?q`7H zb2^p*@{1>AG=AW>v7#>_lDJ@~xz#ov8PN&o=6*zEloi8fN9#ZdrMU2K#n=%F5bFuB zvviLq$c*f&D;EA5t4r!;? zm5yZ=&7*_OzI80``8t;?!`e-S-k7l(_ggBi1O_AaWQ zMbybp3r*DIr@e^Ff{X2!FbwOp@E31?Sw39}*OGKak7R^Zjm&TTv{XLp)oww--p`Fl z8Z(LbgUf|8$I?fWucZSY^-G3WvW|*W=XGR@gofo^vspD^9B$mMnooT&Y|YwsFYEz=4|VT zWcW4Zb$~T8{P=V1;=vvRV2sHR_8dyJEkui`#VvRX`N>}5X^_byqz8N{3uF^cp7gtbhNB%K7 z-eX<8GIW(-5d;6oyH%&{NM$q#C`0B{^2Qx^yTvswZT#B{M*2N(@k1~$-0WACKNzW1 zSlZ}y;#0UmkaP{J1Q~=@LVLcoqv(p$j5-s8Eil*dvr)-a2-0q$X;$kZ*!F<{k7s5O z;Q>Oe0((dI0Zq5|BWU;5%u}fcLa|bF$Ls;mw_HEsY5~7qvuA8~LC3PMd#ba_0}$|_ z$R*P=QCj%~DDci#uRxyVdCBN072086D0@?Tz(p<>e1mx4{gn0Vf2v>(Q`v%*^`lQ- z@YwZy=qXnhj`Uef*hPJ4@>F;y(^vW%jlJlw%lXjdDf@on&p*l>NcX||iGpE(kiG)? zhTKOeHd{v+xwoM`H&=uC8$kcyKpa3+7$S_D5UqFW!6>1Bj3%ee!C}g#w#f!o9q!G>Q(wLVVui( z$|b{W`s0gds-P`!wyE@aKnFX^_Gf8gZ0}UI*4zmW_BxuA2SczBgb{1QzHk8 z*d)NUhiShh!wR;R$beS>fG1(_{JV6YIhBKbqn>XWSag1>0flc2-jSSe}Th3}Rj zGL23BBx~C&LntisiS;W=j`2o)e1k9^I8*}0L;XnPM4PNx{XS9<-3}B3_T)c>xU+mp zB`sEB&&2-j-1%o9@5o-Y8TB?BM1{U6wRyZavf>~rq4*o4nw$h!PSRFLFZ(79!V6pK zUz4+ETuvZ1fXtyUKe%+@dS0Xb8&IbZQU)gbwD#HL2O)?wd}%y8U@hQT=m){z4D}s` zaWnhSrZU4N?CI&@YTRjP7JTe!EaN5OX=qk_;%O|CB{&ONmTZ)1rUBc+6sAGfKHG3klLUAGYX!= zJ;c#7OqxT~z`=D)O8U8sD_F2J8qQaQEnssW)E3)YKXMH77l*pn6&8KjK5d9~jB#D7&1FsyRr zAvEQK$u%W(i*)6&vAJk{w?xRB}+7ko7|My;ExO#3mQ9pHArKpJ<KKyf4%5>^`zV4vt+s#G2= z&J^E|*#nu(i@BNOGK2{vb!@Ya%nJ%Z9X<3OJzVXME+fgsLZ7M?j%p4h#br6}M!X-!HEE zx}Yx>U6?(H>o~|*V9gUv45aFqeZ#SCaURGBV!zI8NTI};Y1B2r#y1m)@cu`9uD56Q zn0`YCv*)I`Zr;Q#DLV&;%R0n_Uh}|gP6o-xupaM6`rk2$7W^_sA`F0OTr?^mU~qBc z6GFWC`@iTA1ZS$%&SgcGxK`3x2RZ3pwI$*H=@IESisGJ&Ey(;Ep&?viG5Ec`NCPAX z+?zp82mk@n+%!Jf#0#l&Z9iC8#9k@t#_b2}<;QcoWxx-?fLL(TAnN@ar}<30^sI}+ zWZp@{)k#RHV0LC<%JKRA`Ne%PzTl&hs|62NVH4WOu~Ely;b5(AvOYc%b|L29%xukE%@mAWtsLwn|L4sARshUZ z(UZj&#Sl!fZ5*QlX_#1>#Fq9BVd&Bfr^^^r?hYnnOI|ynMYx@sx7tzxKj?+EL$Thz zzblt`P_5y_swD>bSRCg0Om_^vecat4_3_(cB#l(UV9Ph@xHMe$i_S|<4C99n;A)m7 z{R&5zB2f_g%gra8zKV@4X7y>Pi?FX0V0ewO%%-6ygn|IyZ{gqn9$7Ujybz^EN-9$@ z3xhuJ@OY@2I$idhI(i6MA>qMs9JL?$L?%o8;yvoE^sajuS|A+8GSW)~jTECD-XmOYEZ7&J;u)Kwz(?8AJ zXa74K|2s{|WGiBj2TnqA?@Br-zz(zk+@UE7G{#k5n7CFlwtTx<#MuEWLY#Y1BlofosG_|GmT6uv}wq7puTIRV%d_H?J8=;PS8H zPWOnv5xJ(VwE9RT3*zU({2?O!w^aXr-Y*Sp==0P5ACl4Zz}6e=|Jy)#D^ET9zYN6g z%RqSke+)#;!Q=llk2IAj8FEpS557#(S+fl~#!a4K z+zsO`y&VM6`%z<%>8?!wDu@fWmzI6$9n$<<)a*0c@lOR@cn>_JW_NOiE5#H@a-QUu zOdYKg9psDTr6`XJG(->L2T7TaAi;{)?5nc~0g9R847(Q@og#Jn^em!w65%ozEYpn3 ziOMW^~2qU4ON;|FQj#Fs68t{+Le;urB&B#Y& zv3f}zg4^fmigd9mzHJ-ZJeyRa$tWd9gkl$6vDhG4(E5nFI}fc0WEtc%OeMc7->!r! zL6Or{m1tLcNg@kLwaw?5dkMO0xf{YcPWwzI{&~UJec{Wepzd0^%eZG~7w!W>dHdd; z#cYs&#o~F|{X+-%&@Mjkp z({3|wvzc#CA0Kl*Wp7*Hb6W4kimIlkvjnqbU|H|S4T(X>Gc8Z{7>{H-HXlRr8)%e! zzNf7mHE6k*hr@0M9{?`vY$3N{gEI$pr8%O_nQD~{-7y_1NWFq@_$zT%x0BrWuBf+B zQf$H>`)o#A?yApMxAFVs?p<~sGFG7jnl4$v`;9kT1~cT^iQbw!wqr{)9%(KzzilNS zj+6x*vfVc+H+M8W$8pQHY(-IBC%Wh4Hp1O%zi68_!o` z`^wl5BY+L29u_QpLO1Y^TI~aP8NkK+`vNgrh&ZFRBD;4od@Tg;In`qR2=HCJ+$*qS zSN0Jv(Gw4-SpI__$hH6eIyCCq)-(tZTA0s&Tgzna43$i5>|6lW|3qw((wgm@z!%;O z4wv0@)Kv$oxoH-ic)|sxLG6kzl^{M${7pOFcA#EDGV zrESp&-xwChfp6PRF7x~N{6;W%H-Ik9|8q*y><#NR-cEN)ZmV(Y>}}FCT)bLf=9dGpekp(+6?x z;iZvWhw4o>(#Gq`G=o~DgT*AatSMReNgjP{W!)`hdn*ANOLvxTTTe|Hr_9N^x>d8| zi;23P)=Oj{*>rI-ykiM;sON zRYoMklsoz}^s1m?1U)fAULcP*L4o~ZH-_ryTt z5FUgl-b{;p;W_sB9cx=|d*->Fo$`67lJ4G#KewaC7Cq_OIDHcVBERr)C;SMV?j9OM z7V;|{|{j-e?vwo}|w`9NJvGJif z8^)j+XXEkfz^4m(iK|?X=gG!KPRI@PO;l8YD{<^&)TnRgjzLz4lZ%(pj#~%nsFzK& ztlUb8JrmVQw13dY);CY(tyDQ44J-FiA%zBVWq%RP3apm85ra_PGgMder>e`uJx?i{ zj~r4Q+&gDBuV1j%D$LsRt9Bq*e1Fem{{hxtl4bJ$V+#Vbp`pQIRY+16RXX#Fiq4l(NNPxI z)zKMy^)hW=!eQtgeZ^d$X7PU~2ujtZw?He8-|3&cnCx)3GhO8O^?n8Ug{5VJxm?;a zP`qptwjbv=jE4Hd!eFfj1>$xj0#P_S8WY<#9wDpuY47U@F5kBO!P&kXJEjRe)*a3B z7v|;a9Fa*+`bamfJ7T_<0Hli;IVO$+pM$$2fmEe46G5TU2c6RDNHQJgk^0WE22-oU zoE<&#kj%UT2*%6k0uXu6O~S&Awu~n|w_inm92L^M+%OcE5vQX2Jgvp9JW^yjD)(aR z$h&<(B6)t68}K`Xo`chN6I=Ni4JL=*dkGh_GletK9Reg1p_f(rkH(?1qWjnHg;g^b zk(sDoe{$SEuL(Fg?vJ87M|Xyq2F>Qwt%T!wAJRd=0aPzVrB&vB>Ro5^G|7KV^_(tfC8q>syK%_2b+z-wG3Y$+GHk zYfqgt5U!Lf0nrD_8nGtR9N-(iyaA@oQ@J^E(5E7V$R`>k;SkWeDSH#R#Uq2&<-lyl z3BF3NT*ety5Kg%YTqC7c?_HLjFEw(dpvDNhXx5uW-9u(!Lve*J8d39tH~7verQaiG z#zow7%4BoP{;zPU?zC5S0)u@OFxa#IO}I>4|6AFYq%^N4&tBNPeR9Km*w^)qCD9@tUHi1rmrCLMaz2Z>y@tK) z$ikPAUyWod4zIC!G8!9aB6zC~`6NjX{tQNw%`EA+r1+$M%PAhit=&Pca?jwdib5-c zJjps7r3@_k+|>QAVVC_1ACR-CwSvAsixHEBg)127X9c=GL0~8wSD-qNFyAb)F1yaD zl4!HEYRV)y&vBVjKoCttnPn8;u#9C-(8XsB3oW+Fw{YIby`r~1tmTa8N41uZB-niE zXUb!TH{(5@TF_3Z#D6)1N`|>Git2WwJu?3{v zjY73T8(zb(&z|FkMu4VT2opAx}o=C%}%g$H9Xu=gTRW97dK4pXeaiE8g*x$h&KiMg2kBr~xEH8Q@}!`np- zh$VZi2iJT~Hvy|>HZEbnbH+!ujqFhK5vuHX4}G%9p$_0!;b9y{@ep)4@Yp~qaf3b= zvXCQ&l_62err;-h*L^wpekbxdp^xSue_K`ZQ=xutCNGgaqRXodSZ_*7?JdE7=|ZTs zyTmETd#NtabPj=)-QP4F1#5u2iG#2?z}Cz}!P?I0pQ3V>GO)N){KDJ3;qv;UDO?Mj z(jVNqxd*u~0BHv{?n(hJtZ-=9#*-FyO|MS3{Ea9_)JB5k8uFp^76kXX=1r(6 z8yo2DMkuUXaN#zRm$#zIF@@*$r5{!~4pXbjwyvpCzpOJ}xiM(W#*mhgvbFOEv2IvP z#`LqCu-Dg`ap*Q==0)aQPMZ!#F0Yhs5pm03y*kQsSRB&aT11{Luys%NSm!kI4Y|m0Ko@ z`?_f=ezOv?lA+r}H*B8*b`8@wRrE@d6rSVVNAdCFA_HmAG$ok{MGh=)7*S2YHUinm zW>F2=jm!>TfVYz7;|STphVVMM)n|LutM6Xvwjs+FXn$oQ;uXmqWMiM)Hs~AhdXMPT zRu+ME9ee?1@ZsO3qq-9h^f=Y#A zM`&7X5SpcIsy-3{nw1_>22=(E&ye+J4n~+J;$FwNtVYEvkIx*U!W2Qj;^QHVyGfoO za9=QL>*FjAe@<4^!FK;!OQJjUa_vtm^XK0;v_G&4TblqJ{)yNmrN7z{ymPkg=Pr~m z8ik244@L8VQBM@xg2dYZBN=N6H{v-HrDR*zahLFG{V)QenE`@dF-+@ex~nkI#q^Jp zzqt<7{nCf-t_B8L7v2m7ll}JK-*zGxhDp(g5IOc_hM@A zyl67xjPvu48BNF=83vjc0L^Ap2ydK|JAM9mJUtjb-tE`FT+Lmgr3Qa7>82y5kSp}F z{N_n)X}PjZdS+e=#!%j>*|N=4>(K*afFqY9WlC-P+!ZM;-{rBCr(ojo&t~{uNKQFW zd(4xGln-6ALw|h-4AMm1%G`@S!JxeB=^v5{>*_|O8v!if)-(L|$G7_mOH|_#EV1<8 zC;hoKbr$9#bSHqr%EEQ1OrLeOI;nccBKX*36gKN}WGiViJ?@XWX^^Bl zwU|JCAEnnIU!w2=Yj3OfJJ4pYjl%gaSqlTonkH9c79>#CY=Bw%Z#KG>Ol$!*|5Ky; zQhrVWmDlck(Y8v4+@Jpdmym(1I*idLE)}z2TbLPz=&P64sh(7xmFyDWtwx0OYx)!9 zlQ`C;CvAW=EJX9(=F+C;1?SwAk2Fjym33Zu1kry-8h{k?n~ne~INft3rWNI8#MNc?Yp54h z3UM}s{Xp%p$92#1NWY(i*9k#3qU^5xj2Za_9t^#6TY1K}Wct~2;0uygyZT&r?Djb# zDjS5z8#B4&@w%I^NtMgH+xYUJ&zarxa{=EEx>~eUhHeE#R7Mj!lk7rmE`+l8$aAy> zQ44D@^_q*9zTutXc*3EjzrTA`-R^l08IH}*O}MV*C0p4nt>5(N)GR7Ra$i$i53~!= znE^)a#bIg{#Ri9nvDs*r*=!A>^L!Ru0dDX7uw>B6%BmpJPP(#fBiI+xtWH!Cv{VVW zqomWMJ+k4=M`glkii_R;-io@79gr=uzF*W97-P5-$22gFPRkwqOj2rHDe1~7xF0R5 z#adVSg!6vyp=x>FqQ3l0trh#+0~YR_?5>)_yC=OCzRQX+8ZY0O$+@4!6x z;A);=t47~Sc>so`xM=qMUh--V%OJst&EX2hc`WB1W$-t1VwYc*jP*eNlSGuwJNUoi z#qZ$H_6IL-AYMFwFFXAMFC`O43uE9A<)0J?I7#`_1jvlYTDF$~%VPl-lHmW&qQbZX zLZo=D_V%-h}x;c!mU1c%}#I^rrGKo|4aX&WmQ;YH7JWk|HO zAkNE)%<_1DU&oYz#DQ<>a=XOq z6r)D^e459bf4c2aUF$xiRO6zI=3~C%+3llHdIOKyZBrtk0BTGO%^8Oj2pGUG&t-$a z(Cyw=jhRL_Ed#w)Xlbc1qH5c3URYDET#^JjU*nT5)OztPLT4i-Q}_!|t1Q$-@4wfz zJFRNsMYM?j2rZ&)N>-z*JwtAiGD90Hzl}YxL>;Sg+|!zx%57x(t6ZZN`4nHdOQbk2 zaa54l5!Z{_IxZ!pz^O|v{_Ndn!V;}Tw)KKwl!Fo)t6qBdYsf0oxpWSOx_GrV9k@Z_Z)<0oZ@b=Qe-T%jaUX zYC|h+61r=gQ@{ze5c)bpgdY>009(eGXnR-JRT;R_p$(z08#F1_dP4rvMDPKv7_sv=R?m{fc11H5jh?dZZy7V}?5=3c-SlQwsgo z@bGa1)2IyFASxjdJ6QNL5l=f^;XVPLsBe&&q2+8Uj2dZ|lCkfWG^l?c)W* z+`l{hnBFZ+eA&C32ppD!_c*2?y@9S)aQ9tTCI)&;5m0_Qjr+Cs~VvN`iDW0rQ4*dT^I+#nVZPWNPG8 zzgJF0m9_@tVh*;ioae+%peu5Pu_=!!MZ*RBHTEpCuFfIl#d5D=k`rcf6pICT&GzN^ zFX2L|gU@%963PhgVD;bMWBMapta5%kz>h3LhbBTOxwi6TZsm=1^Q@7u>-Ecd(P7ub7qFoYMa*SHo3gJYYbs`hZ;V{ypLPLlm%e z`9CR_^41@?-v7X*h9w8CnEC3*K&1&!A1omgIde7r^c@!Zy3EQ>?2k20Jn4r?0mDAx zRSZ++njS>j=MYbh!%fdg*U87M`uD%QQMMssdYVE|Tsc##uhQI2NeEvSz5;s@^A3#s z4ip~|%hCn)v1;?^Xhfcd?*L$UZY;P)Kt@l&ejvP6;2Io#E(Ug5fCA^X?h4`M7A>7G zzimc+g6F{g!^MOTpo(O`VAkh+ER^byL(YxjasTkr4OL!462q)w&A)dk7JwhqE=Ql6 zQjXUuS9>_n)iNf|%6V0Gv3Q?Y$LBvoJ;jZ2XPQ}--floa0o1GC)AD*uUglfYLiJN7 z-t-yc7sgmq=1lB5A!6Wd$6{=zpU1L})@%t$scZy`?)b0=>3mNk;^=f)OD6M}UEoj^ znQBAR{g~juni+;`y*7lfvOf+@G11?tG9jjO?F33{gnPjRL*+OH$?pe3y+H0D`*>E? zoK9oS_7-Xk^k*x}$3ZT35j066cIhtS=nVn>x^g5K8ZOYUp=ZRZBTSEF)k0l{*~Dgi zyncqZnF74oER{-NxpGZ{wCN%ZNo+M{3@bXBqwxx)NeKnF$dVJQ8cH&oZwMw@QSOqm zdg#V(spY8<6?4BPsC&4=DkZ-~)D70Wp*;UqM(y&$lb02dIk(qp@`3m-y8aZC-QAbW z3P8G?AU=H(`}=eWS=$*|DVsPsS=gF6{-drm{wIShO8k$B;ql`z=#IE5jcT|+y8y;% z(Ew&>V8jp()X>*qbXKh4ckQ7Q)EVaO%1e z0r1R*5fWgTty=z3PX6Pvk)vOz-{ra8r}^h^qx$3NjCS}brYw}X=6%N}CL%eT*^P`d z>JjEz=YgQw4Hvtd)%Am_W``uEDa0x%dbl#(wZ=iK;FKgy935W3a(1@T>*?GjVjFcH zCll{DwP<<0ey|foUo9(`TrRr*C}MvE*3l_!{7PeH?ZkC>C57wWy>|q`@{QLR3SyOu zX?6y-!-$neUpfT5Blf|MTwpI9D?H%>yFcTjlLam)4$cyU`cBjAxI#XbzD~S8m8C@N zrbMhx!U)}|(LQF!+oODDMPj4a4Yt%e|8lpmQ6ltWyj}s^nYlfbPEmkmF2fWGK?aElCTttd2EJV^JSA zAMN^_KDNt}pg6%gt3y5!#h6|c~He zC~OU|u=yuQfpw%EGVneO7%c2qvSmbR;_Tv3pkbewSHpGhP%&agS0c;xPq?u_xfR5E z8rFB}YZ73Y0QROh#NCfxE4zB-aJl}cH=4%p>-!Ed-RpzoZmrEQqfmo~(vA+tB6F7J zHl)z<3$TT89h$c-cHMIv6(XF*u_F~2=Ey|d=8)K7N5>8YID;jwsLxQ@&V*XBn@he!cln&S@{J_s z^^hl-N-janfe89>VWZ8IM`|%{%H&EeNJLf7TzL=fSr}_{4_>&WbtfP45Nw&a;hYf~ewKUhXUnnfkX9-wEjsmO5 zP5*iDvl)Ko<69F2WvV-16*=WM>Bm}U621y-jqOq|V{A0avDG-D@eo=~ow$X<--udI znw_@QrJ6|B%l}lnqB!RvTZeP6U==OC-+`=4;8e%bj50CEn8r!3=Q@?+T&R#*O`08c zi#OydyU{u2u46Ca*N@MZ2EcqRPe!=30?oaH9eSm7*y+ zQrH;KEd~C*p8aDU^FJEqKPJh4&HI2e86Bw+aPt#2#uE~e4nhS28hjy@vXg|}N~Pv5 zm1vX!{YC**=&yX=f#bf_wFVdkr5lF&c4o7K%(SQBshTYi>pb1SU@>T}^qqO+gRtNd z(!H7aE17=mfUe6x;hbTk;B>q}5-SEyo;&0SdG}O}HO=XVp`X&DQP0abv)sbNE(JYY z4sYLwNyvZgI_e;ML-A|P{QBM=wvg}~s4DusR|jgT1Qsw#l5IV8w6J#iL0sAu9h{kG z=t<aG+nx_sP~ZA1xA1ja20HM9=-@m)mTA{1V|Jp5D+sSXcHx{SpS~m#+WtOCmGd zOd&>g`Mm6LY_&2F1@g6AbXnq6sf;D&RBJjp6Uox}(VsKVeE;c}peB0%xoJ0}@Pgn@%Lq+f-EFY`{cpFeBF+l|NI&5LA;z`2Z} z13d-rvc8=1`lcX@;5GVsW(mNGsXVgT1Ft6NN`w?q>rx;;#)8T4*(0aN++-!YoON!W zT?b4*)B_S9<{&&Z1Dt2)4n-eNSdGW23oYFG*-Zlf><@O}5k z)TSaI?S4=5y3nEmv{HpPgrJjyEE2KMtFf8-=RQ)=`_J?x=RPGL>0;g)qOKx7;OE~h}nx<^?azEflE23sGZty4oU*?@Z{HVs)0VgYt5NS58}99t5$ z)(bjdp2NMPDPOO#P(9D#PL5-1r9Ly|g};g@lH^5Dy7LC??>VsMz?LicnFukjO9x3{ zlhcdUcMD+Em^v3?)5?#8R=YrJ;6ZYye21UanCcyK()KB`n|_#7e1db~T10}@lbYju z`X`V3lgm`go>#sBJuU>un#BLgnVXTxw?DT%9q9$F9ZUem?n)+R7LHCP4kpH;|M|Cn zTmmhMo1zC3L>=x{UNBMBroG?w*H$$|frb?EkB^N4TX=Qi)+~4}NXruapdk+n;1}4T zzw+e>Z?_waQ4TpJz4I4`@$Xk{?j!y`*G|h| zj~pf$Vjtlw&oth}prMo1{l5F@k#l%nEeTkeE0!2GHD2(W;4%uFi8jOz%R{?Rqx({U z%mM;lpM$@0Ch6^qk{BHA8nm}n53fE&$}4eQn|(KZV^M#Gfq9s=I2?;Jil%2aatAvP zN_Av|LcZ&hd(#BNTy4!0Ycmgi%VMh<)3@e?Y&c@Eb=iz3G6ROGehtnY2{Js|cb|SO zr7?vuROu7xI<-J(kBHwNF}=0V>Jr?NUTB6`BzG~N`a#7M3GEaT`!Q*;kx`5z5?3UQ zdd$^UcpY5J%;PI1@que?P)JwN_>CzF;teeZ;C@JtifEfxzXLBC-tQ+Wd?=U%8mo&& zVZzN>OpJ5?YuetmPI}4*p6USbRR8zU&3~SpBfY4RovodX`@fxKR{WGL3gefdZpk{y zblWu+8<@n8W|kz&FqECGqR%R*_LO^(^^N`+y6wQvrS{7NKvj2oz^*8GJ~M0ve$OSR z+kGBl-g^7`dipq}|7pFq3jJi+cIO0{SO<2;1B@NJMbi9m)FLf9ajcP*9uXhq2n%4c zmA)>$E6zl#;za1v;lcjfMJ6=SaS@5D-^iUxlxji**P~=&k1y|C0OydWhmg zIkCx?<0&{WjMXrzukWpa0dw;FFa(c35P9x}^Qv!lMDjSDMyFGhcM>>$x9P+nGpsa> znx+_^XOND>q|RF;UH`3b+BamEDvH+poOSZ%gl1jfM+PNbWNAO7%~|6x#DTk3iGPE4 z-MY>XdC#3BU+O~vxyV`V!0gr#Y!c1LRk@?d%~t!l#S@Ga`;V0K+45j*sSK+(IqwjyP)ia#_Td}hDybX5LdPoI&Jg*Y2{ z`UJrFhtU7wH!W)O&B^^g=KBB1#DDyn<9|wl34RIwm}Fwy{c5@H+Ci#leO11<11dEl zI?>6@X77~DFlXPJV3%u`{|gk~>l1-g<#FUp0Mrh^vhDr-wSua&`7uTPla&Tb++af( zoaqg!sblIGARE9DpGUG@3`atKh3MLhxr{FiV7?+D^;$r+RX0Vnr8Z)JxJL`vh7}bH zPHMw*>mbpQ54PF<8QR=dQWCvG#qmh*KFt-^v;%*xSK^8jeOZbPM*p!7DEb+@0vG+Y zUt#0gq~NsC*o{z&j5@kB9{k=8MreJ)3RGV4x{O80FAio+RO<#>+(0vs6E*qnILaVA;Scj7^!Q5OmMnXO8`0M(S7*tVs2K)C45 zEIbmehkg%~2?{T}6ejo`W$~=x;2i0=Rv%0GSd4`4wMO~Dk?OQn6=>5rC4 zKkIvt<95E$>7BqK4PIe?KQDJH z+zkdxjVdKwF;CDqUmg_H7Pi?yq)HP8k&#Lqwh56rO(BU>+%6k24CcroG zdZJdryv*htV758l@#uc*ZTIk)L%c?vmih;Lw-*T?%UO_HY^^hh=Bd3-ayjAZJQD{YoTuZu zY8ukKn!onTW;?x6uinDF_^_k#QHJr#X<`EU8WEG_c*Ni>V|U&~bc30?Avg7^%|u(z z4?yeqQfr+QkCwIMPo&sn{bRvuNu;^Yigr~pIg1M|Kv~lK+|F_{dY`E>M>b!EjjGl? zm^-^BRS94j(w=~T<)3y&eRA0}d^%y)v1=v68pyulOOn8AXQzB&e-%QGy3eBIoUcB= zJA(s8?K@jEOrYencIZ5a9)9@ztm$x(IV8HJZo|EBN)}g9-EC z>$H z=9nI{eQx<(mKlN1QBX))x`hixUF;K-0-EuosE)m6U0(^X(lD8#-uV0>e|;qq1Ym0- z!K4-ILd!q)2VVsurX-^x5xz1(pOv^5&Vt(SQa9*NHzH2^6R5%)$JcV{DE!jcnt{|W zq7Uqu502~(7R@nx>4@F)#@1_^(!|{k^g>9OxDSB!!Rr^hz-a(0Q*87MFjNye!N8Y- zqXsb9dn_j~svR*{C26D?X$0ueC=V6n3x$a8lZR_5>al--{wu`RROmS7KnZgNf-LfX zfLPAX>HiZ+CjMMV37Wc6uY3#h569UcB4c5kfe%j2CBrr*8u9rqiFb_Hq&)L@C90Fw zas}c=v1=p9R>xpJlh$fB`TJn~?)LOISPv1EMWXZ9+A@H2KbvqbM)sbXzFU`5*4h{| zgv(&8O>1;bOTo)Jj0n?%LYq%oQyp9x%CW?Paj5#^D_mGIH!|FFlamN}Eo9&6wV$Ze zk8=d*F=)Aa9hp+@W9H1JkZK#578BU1y{4-uK?Zzj6AIT89-JKu3bOFoC$V8w_P)d} zwb2FiYELLi7sMt+~i;D;D^ZiNSQc?JxMjAh@|Rnv$h{KI|}C z*Umv_UNAf>xQP!@GmdxaTnv~9u`?pM4|s!8!Z6fxY*og>MYEt+-C2 z2kf-EhLZ*`>UrS4+Exq3G->@xYsLR`S3S;>EDuTBQ5L zu74WF{|T6Hd@L7(z>|Cjp5*^N5BpE)aissFME@;_#7+IVZavg(gUpSY(qs`odsEUw z36Go{8y;IqmDePZ+v69!&VDfpT;?fu>I@q*$Nn8wg7*%@4b7J4li?y`VQBUhz|8Dz z!mew^=hfW@pa+B&s)&d0izjpZjM8sIH4ghWg;1 zIf|sLa*fglEb#YLf7ot~Wo{o6E^4yuTad~0F~^DT8ZyPP)xD^AM-GH&$k1Yq7vxdn zzD-)_0mtNG1MA@=!S~HUbxbHEY0^9V>QdTzY)nq{tyzy>de`ElR&|55?5qZ+kAJr( zSG*ciA4<0VMDv6UX=C`|Mzo<-;k)LwcSm$V@>M2}Ec`wA$RKL_=LfAE$pJo{Dws#k z5_1kqwVXUWgLO}U{13?$(CR#~$5SXuIwjKlNJZq7vT9tY zjNHboD*CNCLxa9~g~HSJ_rLwnlO7v1Wne#jn!^3`iRpj)p_@A!JJL(2ipTh1!#3s@h#8koy?P(*OodYi0S!E-;A59-XL8WJXH#^)fy|*4;qaQQu zvVHGo$Ujwn@u5%uX2geWpAekUIpU&c8`ocTbI(R^);zYN-RXw2c`=CR7J_j((B9$3 zzDdG)lvrXszZrl0>!s#^~fw4(`<@_u*Y}VPH_VtP27hkWv&X&|MS6r^imi{S zJohaa`U5Bq52WKa#jR_HBdu9Igmfrv z>ph~TT}Y4M~J0zgsx=l0f^&6ND_Glb0+*oaknDFD@HnoNFT7Fu0t7M|-&?v;mC&@NpFZmI|%Gp%;T}#oFghgqAnUvFT!!vVv82b|eNVw2NA_ZSH8i zgowHALz?AO^u9MJi2%A8<>@g&v>y^|2aPI~o4jE-7Mbo1I-&e&56!7^M6%o**=U#2 z!XOP%BcPJXzHGF;gGRSgO~l_S9igSr09mU#!Hz0M#yzGon|eZzyLK=V;uY5bzQkYy zK;H}lI;Su|EwXLBwo{eqoaX2*G;Wwue4mO>S*W+!*M%-Vt8JS7N( zt&y0CEAg}OTirM>^o1%R^1euF=n2WyPc4UgGiz*n&yS3RQI0p(6Dm&+DLZ{?HpH zxDto=oxL`D6CKvSW{3A(x<-6c?(cSb!}*xG*6+yQg?ca9Eya!AMuV?8;h@Wf&WoT~ zMO*1B2*cIggNYgz$tJsT-bUk-J!+%)5|o}Q$dolnJ1rWQS{7#Lk5uoZC^Tr;L}7w- zVi-*^C)%1?5$4{ON-vj?%XXV?lHa`+9{94TtyU z3bYAANHU4aW!)b6=wXi@J)thCp4JO;jCt9$9+cPWG4d_O)3KBhr0j+Wb)}Q34QiC>97ve1smbL`JSX$2A+6l4{hM51%60pZ#h_>!J2_fX z2f0-J(J|*_Kb+e(df%KBj9#}K<(nXl)aECUHR86NrEZAN(T9Rx;MNkmArR~va-4dj z)#(dV_b|U6*K=-pu?kiZjSRsYvGJ7MSInQ0xm9rF=OhQ{?f3 zu_%95;kK`{?LbsW;c#4(8g1!y*q5GlXZ6W9KU-DVl3R*2MB6MN3a|-yb$A!?TP?+h zPxFhZx4HeS$_NjB;>v6s{7P!KFK)!E*sKbCG-Q=Uuy@CaB_A5pDh_^x0C953J~`+f zm%XqPW6T$Q(z!Y-MlCwyX;J(q4IjqBSxBko3sjvYzVHL->$dx6&Yu<+0a9b&xYBX` z_8>eOp%@NH`PreqFu3kDiNscY85gA+mU>bMB7RbgwwyPh1TB>nR7??243X0jIo0NP zoEAhp)P?5p)Zs~LNI(5W8L|7*`6@F1mk0%@h@v>^SePOBZ(bbfS|)H&6W~s6u5eN0 zK{abf#r2VraX?gL9~8`5GX5vuh6^ERa#2uuLsQRlitvz_?z7C)BoQSU@1EAwkcDw! z-h!FjFEl&vJQtGfnj<7T=SRhOTK0;PGG2(PZ=I|9r1*&hK9P46LE>xx1 za$}2}^0d2ns#W}M$G&mOOQ_P)ZF;4ZGO??dNzoa@tt!RtlgIAwI=k^Eb^6`v@YN`k z!{0IZE8XvUjh;CvI=Z(k zdL;EXp#BgT)4*q?iEWfw10NqkKOoCi6O#OXN&KYOH?d9XsMIOiI?zzPFs%-!teV*q z&G>$A)C0faQ=Zt|7M6=1ZJZ(%0ltr)&13XVfsRPP z&+}lbBNzflV~TnTRhz9dCqXkCRBvI!SWmd^adgI{nzm9NzGKTeQ$?tF06?oAkXxz( zH6|cIPPV#7qATJ??aSSbH9t@mT22`k;Etoi65I#5O5xvL9&Ist_lR*S_dsR6=iKLn zlmwlf!rd>?qoe;+(dF{=R4?aKx<1~k%AN<)0fS$<3D+Bz>3}w4l*W6D*9~e`IDqKd2+goZA+_tBYe~9k-WFZ2 zzG(??ulc6Qkuk7e`whMNU~|EZ#FY#9BB{-3T>b2nM?7&WfYz%SuRcPFc{1ceo6 zIw?wj(otderUTq8@g-DTtGS%SVMM2jJ=l=-iotn^IsE5uU-D$cL=B!*Afd(K%+sZ;v_RHUc z;EzC!oivdRyad!{3DMQG++BlW>8*z!y#Y9pmtX{8ct+xc-1cW=7M9lJ7U%P}87$Rv z15wIL_G=Btanp~crsD0U&Yb)y1mlmJubZA*uhFiw;vY{p6`#=OsQJ!@xUn}U`sA;c zG~Ey{U$5Aov<42CeUJP zf6-{FEhIudmxD^}yjJk4%_qghWhtN@AUq)%$IS}*g%c{$uge-I(GXGl&03lmk9&O5 zZIDdee;;Rh6(gp{TQt@5b&-0s|<_Ar_{vRav&~$^f7k#3Rnbh{s?iUj+g*2^%7`NBF zts{wXr`UN>>#L!7VPiOXXDpD)Huua$3z0!>%a`KgfSq*nkuzDQG)dL%D}!(YM_-+< z1$2u0>~g8xqp%iDxP%R3iMgx}wt*`JPz@Qq`0n%270)X1T>N1+dMM`Fw@QlFne|n##RB23-`x zz;1zA!f6O%nWxQPgNH%NS$+$n;i-*BW@pMu{$YqE71a?4me3f?+9qW;$Uv=D6qrV>c^!-h%;53dXSPoi^ zZr_I#Gy_9u1T^(W!!NU6oL))0=}-9L*a5cr8LVxCx!T8UQMT+y2yM!?yxZLq3uZV@ z7#meHdI1-C-0(axc9>4|=QBrq0S_}iQ5PxPTn5u%hBZxju4eRWhSLFcAtA<>UFdpM z%i&rOyfmm2ZT_Q%0r*HP^@|U{4v$ZmO>zQks^Zin?e}IA^@vEZtkYTawxN4dSer;E z)aEd9?fMfB$LU=0s(yMpGa=J?cWhklMw?_|hD0Q|5MeT~G^Al1Lu_8t>D{|PF?npK z*rqxV-QT>tmFJWmS_Nis9?4y%(@V#k0of%P@GlUZ2Gc|yGr1{88QAbxPN~tDEHdY_2agHVh`msMlNz_z`zC5jEs4 zW7J5}5QH+H9{bI9!pHWO9Dochk1zAr3OWknGQ#a#dSClI10{1)6<} z&AaROlv2@iauU{Po5<9ZQb%hTjPfv!+=a!)#%4Ch%~A6;l`XycXtUF`Q|xA2^WE|V zobX0#>+Jxz!IsGj7TUn&hPSW2r7QT6OCo(pl=+qwT1$2|RlAO~<`TnoJB}GY`d?Br zuB&aTDy-s#mYM{a2oI^6n@q;sgKvL9MMSwbX$B1O4Z6qG@GPYz8#PmA<9lkX(a85Y zpwf{Jj?Lmdr4Al07o{aFag?w^cm{05f9=RxlMO>IkvX!|{1~56Pl=8qQTu4J$=e9D zIA*bJ=ugnrbVT6_qb0-G6Wy)-_SwM5Qkb#q{@i%GtSQ=cCQ#QsrUM-XeY-@m4oM7FUI1 z#&$ac)o9a?-L!)v0StYVD(N!wo_?(qPxR`YR87gu?DJH!Ra2~4Y@Au0mse;)l1Jw= z{__?YKW{`W{E}q|&*YG|op-fqNnp0vZjO2vWmX8H!% zBd6V_jE>B&C>4~F&N|FO9n&_>OZupaiy~DOD2sPl7(bpnAC(#bbOGMWD8jVIqCO;yi<=V z9eCwr}I^iY=)U;|vm+Jk+BZp{{ZKEd|Oy6?Z76<&_ybU_1rw^9KJSn2aY~Z<$tb z<(yG8XcHwB&iNNrYG@zcR|Am;z8QFlsU{WMPDVJM8!?G)}TVb=A(OY57L+r1% z(VEIFXVR#mYN zbj6hXrW>}q_G!U5DrV4jf^4#?d;?Rh!8VySUXfZ3*pBW;db_Th{yfT5{6kr-&`Pzs z?#O=|DsyOW>W`jlX&~sy2O*7vIhya?Hz&NHp30#e@P(-O49uf=@AxLc&m zN4{f@=dPg8!!Z<6LV2UZGZa$8vV=ikjw@f~LGcX6#>nlFM?bc|+3-Y)afI-X6Lz9Q zM>||h&E2GijO=~Q-2{b@`)k5N#N5ifEHK|xhLo`IRPABrN)9xPaEM6b=A>~7V0F7j zUi$=GKsDU2zI{`;L@vk+3XUeMPqzXWq&}HUjCqrfMTW_^X&wBFwB1dibN@Kj?i;hV z!^vZu`nWTRad6|2r6Ww&MOxUP?fYm9h`w0OZxBOnD(Y#i9b#{O8Lt}(c0mCr7rS(YsxdJwg$o8s69pAJxB-2B*r&F3SdJE=p;#+}3 zw`Z*zsxMD{J#Ju)PZ{by>Rb@wIX)oi3`9F5KwcCwN4&u)F?Yh$Oc+d8EVD^g=MEg(@@H-%G?~xfYGX8E zB6e|98ZS)da<|Q&mnF56O`Iw_yhmcSr+WPm2I4+r)ZVqn7|99re*NNs?v(GPt?v7( ziq?KAbyS)k_a2Iyz*M1&Ri!%_J&LAcr>@ctB~JMZnl-TNnx!>M`Nitvgt4Kl{08zR zbb>eRS{?amlH7CaY>vT=qU^XpRwvNw1+KQf%L1;prVkWYVH3N-_74nrTEBK390X>0 zbyphP%Elfo(1nd7qc4k1eN=xH9Kf(@6et4ow64z>h=`quojRT+vco`U=y^Y(W3SnJ z&<_Sw11$${+5)1&p z(_ZEG#ZUlqZyN}M)U++&grkaz-Ccv+v^o$4o~ga91g&0crT0Jok619<{Ky6$_6m|) za+Dc~{XoCYlQpzUn-k5V$#j#v9q?3xd`$2(v^1uucHEBc+t#X#&mz<2SY0dhgudh9 zb_njt@s|-dpantK?85tEu;jNAxJM~MS0fZ6)*pP{n1~Z%-Q2LHaX- z(#AbQ6KFaG!B*ve2TUgLbZWMPcqa7K@_55Z;|;Bnd-`Ra(G^K8_EC3u)hc|0F5~2_ z055Y+Sc_=CHu* z^V>#%E6+h&1~Z%)(7HK<9XUIy+tV(?vs92tHf<(o5xLbvr+&=ewfEozU7t=N+|IOdiggxI5gA8HF09qU+ua=D3n%Qf(4<358Tr)eF!UuuqXp z*)TRoc-c6b3FdR0SX@m|;_Idu-q9Cp_2d!X9R*Y(uO!gV3r3wbg|Ypg2~!GB&Rbl4 zid-J)o`e59Q_ake{Hz$FF$wdT_C8dYRQ<6g-I56fk83@EZyTCN-{EzIw_s8!@)e@r z3WbCx$(>Msgypq$KI3=r)6&)7Q6tzJmiVeU?z^QjTFs@prt z41t`2E+McaD}f}z9~P3-n^>_S!ZZ?MA+l-dKZ~kbsQ5PCbEyi zuY>FnzgUAFUs@2pB71^vuHEDWd|htv;l4}{uHn9v40ho6KswdJ;2mcBVxYi?2pI=y zP^9i~IrA1Q8nkL z4hLhU6D2GU#-P&kbIU9#{@xh504(6P9dD3>%k2+I9<%WF8MFnM7a11f5|*A(SSKA1 ziK8>mMlCE=Pe-lAjwx=O#g5CbF$p=9j!`9(CjT1y6E8`MKtmhH(ab;4_QB(J?(ND9wFqyO%Em3Ck1KMDNv!Hi6}-_=Cmx}obac~i-$wCFztb|mbA^Y#2VxAv&# z3PQ51)lEG8JHX(&(P)@k3|&NJ46>49hI#m)ns7WL z>vNoHJ8d$ObhVA-50NKqkXUi`FgIcw}7!yArYR1U6r{sxzS}+ClG2db4;hxLw>P&XuEECK3$w`So5&r zsX5cSc2-}74HxJDyswKtq6D-omntG?o@-T_3yQ$5xs^q2DI>1MdM(L(UX$GfxYqsy z33z?(>cUxPBhhW7(<#4vjacyxj)bZ(`z%XV7W7X{e5>f zVz4}H$(o{gSo%%0*lAv%1u+DcQ)*`*@5<`B;~P&DbBEYJU1%l8SEM8R6lWH=7wX)G_QlI-t1|sSg`5strNqcwQyzyH zO1{m^L{w!wxz;7~0MpH+1{JLsCzO^N`2}-5I}&2@%jrS|%9MlBzLM& zI>O|s{N{lcm$z!_41K-tW)pa&(#b-M^TE-p{w@ zFnHdgy^awvKi7LQD7BpBJqnhZsjP%-BAbEV8sR0Aw+7*{jOy_I)SR&=OOoS}(Vc@9osog_k>e{U?eRGI5tLT7^AXkBIPmWHl4BI@ zO1op0_SwGK3#Ye%M!iy+w*g6Zc>5jYD+_c4bxzzlm`PWHoJtAbbQ1QV=rNa?ZG48# z8d;9Y0KodSle%TJYSAt@g0^*ah!m%_aVrT|5~76?mqV(+xg&X+19eL2V9r&`_U{o~ zo08Rda)xF{27KGjrhT0R=rV$k2;lWro3!G}?#^=mUBMbGgVtAr_P!d|2n9rDjTLO<#Vuoyvet?ne* zX*e=b>!z=nRXI{YSKF0D&lv(}TdNIhwT=vRwaz519753H^%YnjEibm-3BAVYEBa2~ z$9U*$+aJlm@c>4eJB#x7$*Vt<^LCQiL6P4#*qO1PU-D95oaD2uph9q~%OS^OD0ga` zc)i-V*M}OA;Lrc!+l1&(&Pf7iv=<}-_k|H#JF@tDl8d#wTCrrYX7M@9GnS}r>b0I;7#MZ_5lrSVK;#T;wcQ2{KL9ryD*Dk!dXN%3il0WC92ZxfIWE{I?FUO=; zFXep(Z|&sKZpUGlmx;x|f)B@wdlss&W6Rhm6s04-@szNUrypKGj#JopdwNBr5UM!EmRqdk6)v_gRm@MHl+-!u27}e1uxn+Rmn2N`9NP-L zN{QJ26?q?o>Nib% zv`BdQ5#{9DmOGu2XBMtA`I5)j91W-9TulmcB(fLnbsCwoB5SGSuI+AYHMXa<6QxCX znd!p{iFM5iE1gl8*=wGgPYm{hsiNb8+x!7+!b)|f#dZQJIhL0(9BI7KSYBNxykkpE zOfg-8%~Pl1mAo#l&Qdie;~e0hb7S(131$hi9%I8N!C7;zRKkdw5ocEDr4Wu{Ji`mJ z7gGIvdjH(1(N}0HRIynmwT^;66um*w}nZD$>GMxSr0=xU$t$xaFFf0_(l%Bz;f1IXPKIwUplC zB)tuxoDKOU)^JMq5wjL_QNI%3%-)^>ybeeNoaaYrmrSAjGfK99#MDtb#n@372CXRutFCsBp! z9vz80IfZaO*A!|?e%1&MLnwRB`QlokeR@EzR{eXk3(r@!HORK-I5J*3niO$%xxtF2 z!HYW580vCxevJNopQ$&1_V@@d+4S|myk!ivk>>rX_suT9k8<|0P*+Kd8CCAJ@Rx1W zxQw=&=aY7TmuGWupA2vYS2>))z<(rDIk$YWqDAr!ZuPD<;w=!4n@paH9YaXls+7!K#3x0AVT3*7Zs0rHjUlpINiLQh|RshJl zJUUd$MZf^6=h&fbYe0OyEer#L3qQDP!Kz;jZeiU~S1l5 zPjRv-78GanJ_lA&A;v$4bXzL2*eg)wJ>krVf94}3+QDO*XW)*ZW4@@({X|(&6%MdX z_TUb9!fg(;)gUYnlwRqYWx}+418IE?bbXIO(%Fmq*Nz~R0OD^D-QMA->w!bJ*v62k z4C_spy1GlDY$+CBDNb(jY96~Kp}Uf(-jZs&zV{!n1x*`%;NRYL=HPYgdR#ElBA1R> zJ*LKKH8qWDq@*g|%gBBAKb*9jQL_>lVW*4p(p-~cgPHkF4opY1gr9&W;c*+Lc(s>! z>Jzlha@^|45~aHk3X{2a$w6%Q%gZ#Y31)4z?uMyM6PZUZLv{524F#8918SE8VP!fP z5+4pa7%GN;4IXqO6?WAF{9{lrhB%Nd$f zG=KN+n~(G{Ysv5SKkRg7x|Jqm+KNn7%RSz~-Jgls`pWDWlR@W)qjl-6F-RRDgiXn< z_ZZpdz?|bB%7ydW&U*QMFaY{_e&LC|e)T*XbC12h^jG%-*CcmTdRiOjTm6btFw(f4R%cqxj%m2G(G>udu%joyw#Q@T9IWmOPsvuAKPG@ zT3OW16l8sU(Kv>=yv0{Y&p5TPMOW_1FvJ~qD>rP6o>XTiy=I7X7c({9gT2zsY|CaH z(3&`JlXW--Piy+fMvh<(HD0#fxhXNh>}H~v#be7{sj!`yrV>u-s@?n09dxRX@G`M$ z^fqVB2qub#Bs+&A8-ljDBgqzn>iM;Udy<&9N^-PHbMFvWIgHkZfIh)mxs;YJS75sN zZx-*OXiP4l$W6LKNpbw9Rko+&7OlIo;_cooq^}`q?*STol~3@M=Tx(}qUxa*+j-C4 zY-$137j0x)el@WDJ-~UAZ?7cfcZ^CMA0_#w2S5#rM~hmQAALR&-wZ*!m=yQS1_gAQ zBqTyI5NvZ=4l(#Aki(^&lfIh?#eP+DvkHOXc8fS!U zZ7Tsav?|)ANLBlT-+->iKRHf@+|tXu(y{Fdj@(jin4#Qm*|9u|wU{?s8WUnJ4xZM- z%=i#nmh@5_B)od`iT1ioM&=-yX(%6vl*)_YHgGB_NL9C8`2c2~+Q?lhcpOptCWsJ7 zH1}QmfIuF5&^`$~j(Gil5O`wtQ4rBYt;--{$UIXZBM6z7{zj0~x4jN~il|rkm&5Lz zNAgL0Uait55cqh-hC87H2IPLBq0qo?!W<~Q!~?d!@PEo%y9#?iKs;PL41Oa)5g=~X zZt}lkpi@9^Vr!S8Tq@;2+8w&H0q*ztlRP^a9cgWsQ_###BN?Gg_rP|#v1y^5Z3$@| z9@EWZl+$M5bj{4rB57b73NIfpK7agL{`NsVVPfRAMWJ3O;^f|k!LebY+%cWR z|FS`{v0yPvuo!2WNjw-h7zoxlqk0&;ohH^{C!+GL(i;j|CYf~gl9k(zIpJ$mj?Tfs z>%p(WStD(7&%r>aPnFgmFm9&2{anR3^iJzbL4RRudg03IeOBdcxYn>n)LbJWNd?#% z7JH^%KD4aKe}m`5@o3W%I|Sm)=(-YSw6kr}tQcfm3h|Lu$Xu}cM2$r9A2=KkbX%k4PtXkb+zUHr;P)XP6X7tZ z?MpPE%B5x8HoCKR8(s~nO?|ozdqL_k`v#j$!QZ%8{q8o9>2p#A%Wk2%rL`i|tySF> zIp^_OSr1C7l)B|Thw8M}3BA@@IY70-)@`yKu=?SFVIhw)BgySkc88^1GPC-}u1ISv zSGj4n3?o-gy@Xf$9H|29EiGNsRQNy2sr0Cxqj<@v@RL+J@>Epp$fy!_%Z~O99OK`> z3WB{fzcO`8Pz3Fy#vE`82FIIi_j9!;nb;J%b9RfAibu24_d^GPj|w`0T{feF6ixA9 z?hq=|tfY~;#my3|*?d6mkSY`D4A0!dGKx)g4&F!FJaSID#w}u2omc?>6*AAEaR~BFfL+%G>=*>YZFV#I zR=0w(@4b7cCuiMFi(mNdQK{>K8^U7dy8&cPxQBS+8((gSU+xo7_U)%co!aCRlJhPH z0Hm%g@|!}CdHOQbrU?>sg18^s@`ayIZapcP>zN$${-Ch29)G$bbUP#!nI-d2EHEc9 z2R3}@n=Y|0r!`b6PIO}f92N$FoGbUA`|lL3LO3tI0wlmR7p8YYmC@&u-1m64_0PO@ zE!fPCQjYCL5LjW-^OHl|*&E!LyYDKu)HLhQcejphx4z&7DUt8py@>gdKCWwH)fpT( zr8S0LC?zS}D7TLT_i$kjK+HIOB%<{iM!&#whU{L^zR~%Dzj|?fMgYUtuhMU%=P&qy zzFmt#1D+*%V86ztSf32$Z+ler1_) zb^bl}y^(n9f%3~T02pDk;Ah|sxGm|3FTY!0)ZmaE$Gqu0mi+e+7@sLnSS{MGU+q5( zV*dZHlBV^4a_F`uj{lV$`k&w+>HnJhub_w~q`vaf5+A_CbbIm;h>)bW_BTapR**=t z-ygJOeYS*JP+=|!JOg7UWHT}v&6V(`@@v z>TrthzgM0KX+bo|@6g-NSKff^AC}{e#uaY1&+}Xj@|<8*zm b*OFbf-adUy;UYz zln|B~*HXj81XoAbg+Wbck>~2JgD&0-vax7L3b|u(X!Jb^;q;v&o1E)C3cZ|3&h)}2 z&(;L9TXD+FzQ+9I(;W_<7GKW6Q5%mOz^RKR(5Wz?!YMn&)S=s+P8=Xe=NSK}r^+=0 zFnm=fN`x-dptz$!0z!*u1dMGU(bFg4() z#}HsNr=kmsDr>{6(H`A&Sl#OVC@#I-qWd;Yx24uL)oj42HsIKUUXKD=Cyez3-1f$? zKzx?MD5~Bzp_BEt*m-+Wt8guSda6?<{gO+MWXE-MGNP+fN&N2}nT2au?KSe;hpz3O zVqD|WgpIXigH*cf3cIYjW?W215oFkC%1P&l6zxNGMxdKxs5#%^ajpHi^L-H$htdQ7 zt$m^qp4Syph-X)4%rkTj$b8r2K+65Qh?81aR&`>H+L&6bHf_G{)QWguRLXr*eJK3z zTNgn``SkPPdkB*&Sixt)wfU&i4})%r!A=cv+c;KR)M@;=*8(oz$gw5N3rqN*)MM3_ z5bkj9&ptTj`KxP&f+1QR&nHmBp}L#yS^s@93pGC<69Sa5D#P(H856;6Q!+7;)+yt3 zdEDP=O**)=riEiWNQ2_0F0D)Wn-?*lg?8{7@Ja%d4b$QTIDL3& zrtm`Ac1nKhb$OPb;C@uIcu-=KP<1X0=FLTY{G0~P)`AQS;d7`e{U_GZmJUw76>DX# zrh9fao%H4F=+U4XsgjC{4e8w?reQ}~;~l_ED_{@9?fG23NLnaJq-F(JgIDE(e(oZ( z_)+O6$x%z$P7n@*(NzIe`~^K*uVc(WR*;ZQXD zLEzyd91x;0gvsSKtb1Ltz7|*Z!0^o7aI1Q8p&S<$(886%eJn;KhGaUhtifsXH~ooO z(sb!jBRF2DRAv=NvS5^L2}cs@B2)3N+v>g?0j$*RM2Obi{F-6wicuD~IEhQ(O<;nO zvtJHb@TXoG(=F#88odyvDpy?I>Pb{hLq8WMKE?m`cKpvs&Cl`2Mv9Hs86;JlO&9U!^Xv80Ch;xU>#|!IH&HEESHK2s ziZeB?C(*^2PRP0!a$Ft{Go+`K)ieH;rxpuh8H-GkS}!VSRf0^yeRb zeR_KZ;P?j+EpR{dLpvyFIFEefjt5k?wLJh_bo6!0Xan_cezC~vvAcnPu?X}X<)42Y0sjv2wY*{esGR0!egQZKSd4|WM~SZ`S@*PZiLlRL ze(>}#U_}^Ea~j-22kIT_oqfdj_3Z1Ne_#jtPV_LpJbyq0evkSxz07>n_xbLr!F*Bg z*xc+CzIIr{{yS3%)H_&#vcK?u=*3;h1n%q~ zfajoSbd8A@jXYlF83hVCPLgdm^_!Tj>z^IAIDqx|=Tl^b3_~lF z@f+15EsQ;cO=3cDkg?I)fJr06&|HZ%Cr>8f%Go9)Z|bmP&k(YfZJ5YkzJqGKkRXSP z;5KEtd0e)^ra3RGXo{(E?Sthoy^9*@Dis$2OFFxY-Va&Eycw7?V8lx(qaZ8lx4AiB z)(*y|nr&uwddbn5c4hWXINr+ws!>pfnyK;Cxg-yDLi`^K^kB_3Lt}9I#4Ossksc9p zSR2MHhQ|9K{eLV{!2l+o<=JGbqL5}mtuiYB_Bz$9RYkCV6pKlJyS8iR2X9W3{6h|+ z0P;>T++QC7GEAeX@y0jbO2@QmnJPA!IoynR#iJMhCYbnvv?kPPrvZQmrS0@2NGYn) z^ntjK(fCy9lG2oSDW4;$RyOaOKfVJmf)4h-QCCKb4GKxQOizdMf9Z8!PB?IGZ5zfi z@QV64%*>AWqFjg_0+x0*>wm`mNA{g(Nm+PI2rLwTc!86yNh%Xdo=O}zk(z>%7FtVe zhKNeR`J{+i<${dH=+;s@=kTs+E*%J5jum(1Gr6%)u+YkHMqh|)DKTj23I1AkqFlfV zW$DMsWy<7t1sdZAH*rk-9f`7(AC5-^dzwn3u;XE9ARSCZF#x55&4%#F{N3l7M!PCK- zN-b1AG0uEpfUzVs7f#ze>(lTQ*-jGz8L;+pS7$MCleU77DBH@~{WuX>Fa`38#98V)b$%>*yAs*0LoYtvt;;FjLC{G$_(V1r;^(1rH3b8W_uPD>K}3SDn;8!ASm@hg|cgvqUdc)Qx|yw zjPDVxHM!_y^o_35FBVa8?F^f>3m7gZ^>Hebn%h6|Dh0wcyCo3$62Sv6ZkPz)odien zJ(MVZCPNt`Ymh5k9uvG96pXD^Lxypw#%d(4!KthWxVP9lk$pz0Zq-A;1xur5)uYOs z#uzyFyp1gj@U*KYN9%jA?8REetU{w~;NXVtX0OHNXOcWC%hgo^8cd7`w9w!K@4e+T zWc-o@%+djG%Y^Jn#8l+KAEOu;R5|`i75o^DFRH(^T+`n27$GwEs1t!&LX0|prR)NR zbgR66ZFKAjKFvVfE4Gh`4vXIsVUg$8=|E`-G;MaHO-Gh29!3~&k~=$(*YIBb`G&N( z`!!yuWr545XLSW(Bqq)aUTnd=p~2Y3u>J6$Kfm85ojkZF&N_VOIQ*1?C!5?xgK1&A{Ex<2L9_5 zV_|*=^4-%+VfUBI;2VS^^AbBI662BC?$f6BYY@B2WPZOkV0DHdJB|> zP}D>Ww186l^dzYDyYEUEnLoQNpA|PA^X&%2le(^INA~e7Y@&#`@(aI`4+25HbLWmQ zdqEdimrLOud>s2Xhl5YwKq0P(T!GeHH2Eu}Hy>wd5Kp5YU%<9;L^_`&e!~|Kj5m%p zrZ1mB&LI2EB8+2TwwvIWP~oGZCc8TnPS+ua=B(5-7EASdf4-P_=*nYUM+}dfTa1DS zKBg4TTC}bF_+-B>mfG0^r>DgSW4b*)?MNm}F<-h{7!>M2|KucJ`r!wb32TXoDLWfC zO}Oq4)=3HL-P{uYHTr3;v8Z~CZif6SSCxk46Jd#0lsTOiD0*R%kLw&^iBGg4-DHkv z#35bh?5T}*4ZtI4cEAz-H-|f7I_(0ANANyVeNP)7bmlbAx^|LQQtG^*6VH*lOnCpp zHa#c`%{f7V;!`jV^h{DIJZcuEQ7X5yh{Zoy0lX^LT2o@doRzlNQBxLGSrWT6-m)~> z(t>;aS%Fta4ED#n-XA-~(98A))9n>UmoH`k(It$&aBWWh8TavkZkfkETKGMS=c*Vx zq9l%40~F$(=y;;^VA0w4$ANkOl6eu9*mOaHOSq*kcHv~lncEu;iN08G9@m*%UtVIT zWM)q1FbEXl)V4iT+nK&tj{NU%M`Fo>LDtoQl5&v}d{%x0Zio?-Hy&u3{wEki*G^EU z*ooA}$pnVGU$-IgF($*EU}U_17$wr+B>EuA%98@5bhF~SFUgs$W2AS9hb2guG6dz}3eqNTcMU7Mq zAl>@zd3b3D=1CXwEcig3$%bFqS0L0Ez6pY_td4Jg3 zWc+Bc$I4D-e@h3`iRJ#vfhS zk{2!#7m8V3Y0+T|j+E+!11|3c;2PPT`BO+Tk5EbGgku=nwTSB9@2ykqr7IAzkmRYuq|0uFz4$<$w9 z#`;nVb!BT0Zi;@{3;4N!KZH92`Sm6c7MR44Pb|{rkgjdC>U4+dzG1_#iFSeUHB^K< zA$@n=p=9$3u}74p7ZzODUQQ>W5_d;W6DiQIKKc`Y!p48HQoRn6f0{u*2z7mg`I}8V zQK`pzB&)C~7DXY^&=*no1eahI==-H$m1w3L*fn?JBU zWqaI|DaD&(>FdI>1>R|tKbT8j++RlNPiR2|XyNEwSL-G{I%o>BV~C8ZM02`|2qd zPRQ}7>KD}tb%CAjQufoa3o!bcUY#&D^83d2g4PXU^P{xF1cOauAgnVrPy3ROHMw zy-2q3G>YH0TzfJci+XgpHm(a!=i4YET)o~9WMUZ~w`n6i#pz}K;z)1H%9LVv0QyV>EHre6Wee4M`=ifCbPBJ1pn)E8@x%~O zloSvVqGm6gf~^i=1+uRJx;tuyX^`@YC8{MG=iBXWccd(qYJ|}JHr2}@|<88o&HUB%|`AddgXI{(`2QBni z(X5XViVCAbVx;td0j%%=@=@^xK_;1$8-C6Wv;BcE+!uTJZuKZCs%09cw(%q*03(q&A)hEF!pe-6M7hZ-*}kDbsL zfiBQx4N2h2tTbJTyS4ylXSSpp2<;w~<}kWEx0;gQ`Ke-eEZz~gM=*Au1$WnQ#tEoh z9=kg=z@8a!D@%8X%ail@iF#M$j0yZs-Ma}nSnK;|LzZB>|8duFpucw79jXS)IK4tX z9ej+8(pqx}-174;B{^INIg_O9oMW!-odi`JZ~=>gu=NKQ1CQ~^zuXO3YUbAYN4W^^99LGZReUsuS-_oJ+wES=hso_ zKJ|;X_rsTMJKmq2H5s)%2NCwmk%MvDc4b+mr_2`z%g_f@`5G?i$J>UanV&At)Qj6@ zIMok)?OYoUvoXx7`$55dnE?;F?V_zZ)JfkEsUEU5{7_BO1;NgE`UXWM2$BT*I)_KD z>Af9w4|wB;1TuSYi@sU%LXp!4Qb2VSRflxz!=8xSPY34CzYy9YiM+rBHrC}kA0zcgqH}OZ#cb>F;EfVvYu;q zKzS>P)BrRLhFm16*3e}Y5E-1~ZE@P1-Jpls!Yz2Qpo;3$lFQ#+&oJ$a2s z!*KTEmf4@lx9y2Az1d2fd7eeOwZ3<^JbF($RugDp&b4z;ggA4X0Eb%> z_Vr*~!VFm2*cfNc;t*%<=^aQe@?DPnH_P6yjU1OUIPv27b1q{xrEGSW&vPu zDGhF&ixLlHRcF$SPbJqvY^%?sW3NMpV_QhILk8F8WcEBZ_oF>)<@y_=3{9<8P(w1f zw2A6z`yF|=m?*3}Y?cBrM2RRjC_AIZ|F#|t{jeiyhG@k*a)Qt3$yzP=jZUh5K2<(% z#)mx2-0(m`LeJprF@F(Fc5NBO-x<}uJuus)5btvd!i{B~Eeg7G6FoIB%rlgb?xpaf ze@J@h)dcsICTrQ(0^!=+W2=CcLM`|EKQr~j)?#iQFe~SN%%Q&pLzCm-Q%bM$_1EBX z5?mN$vf&lAnCG3QsyV>*Q0h-WTq=Gzh&ywv54&|C&$CtfDg#*cP<$)3(d1Cwvo|Q% zSlxqU1Bbo|5sPy-sNKo$UIn{auw0HHo->faCa;M3Fpmc zn9S*(qb((eqOC`D3INyb!@P3pVDpt#yj85r7X@yRWA67v`^f3@5Xq!E zNLn%H3_iVmgn?Ez-64>BXF@a)yv;87CyyTJ0O{Lx{7>rM0Vw@BH)WX5L#y!l7w^&u zb?wQG-S5r^#!r@Jq3nNKzY)2lPbR)HVun$*!9Lc0tzmrX47g|(q*}-Gq?=#5Kd6B| zA#Mt}aWuxvPEe)y^M6Vw?0K`$k9_5?;mclOs>q4uAuqn_cdpUh!FgICOomYZ(~ zRa}1oBiHH8eqrGPZ9+?obkD{CfNqe2&x}j=`|&j4o=ETn_%m22feb5<7U1^R|G`t% z2pIB6FC%Ua+H}S!Z1!R3=npeSL6Vp!7jjP-ZH|!XD21o?!5e?Z(a|eLIgC3c7;X|= z$4TuK(*LGiLM~3ub~gV_wba(skkv50 zVM$Xe?gl+~ELv~}X<BhI0bpVXuXOwKOmE{e7`6(jkbs;^qIj8 z>5SZyJfW)GV$qgsaUOxa7`(4GGkZUVJ2h=HXv;PwEvx<6tb%f(n@_^~ee_kvq_@*?YI%+NXK^8MgO`Tzoyb{dYH8mz(p?sa5Y?KjG#3m1 znfE)vP|L&%@5I#X?LHP}Bd2dtJi?t@#QhSJ%Sz`j!6GfoFpaq^48NJh>nSJiGWQY) zxHI4tSG^c>Ix3JxAhEt`$a?4`u?S)3B^Um2of(-$xZDL?rk1tJuv2R6uhEG0FT^K& zYEFyA!zhU+^AZp;WtJ3G@|m`RQwg3Ldcg$-5$ST~n`Yq31?Kkh8e@x}tuULo6ZM;h5=%y14q81FnrAA03 zo1WgsaYt2cASpQIn@4oe9&XV|n5S3^00Ba^3on?jOipkR8q#vhIF-MJ+fH&&8uDx< zJ@7`w-%SqkJ|C#Ee`^khzeP-_+&A(f%6tC?QW+}QMNo7Eooa>W#mp&t!OK^(lyq_Q!LVAk*;4kb(Lw#oSG`zIit~#Hbm)K;EBy=#E(2TejyWHh|u9cAv z-4rjqtlN_T7wfR~iBkOXTk9;XNsQ;6uAt3-&&PLGEJO9#`Zd?8doY^bJYehpU9W6}DN7{Zz7BQCUQ8#1PmL!a9?V>$V;XYno?^IcQM?BkMiGY|51NE@rBxxt z$foOq$l=jhziux#8R;yw7nN>aQmsYtv;ExCBEO;A!URRxX;LfOH#m|b{YT!=ooTNz zi?Ly=#}uvtJ;H6XdaOrQvLg4-dJa8wt6YLS=MtjXl1A4PytLX9x-{n-aFexBUoq+c zJbQt7RdZeEiFH$?V$ymkcbNKOce(^mE5ANtQUM4W>sI&K9Z98ptrW%RIt zZLS8I0r|G1Xuh%uA*V|e$ezNH8qZ&~Oy@S{NSXUdaiCegf|1%ZnJ~v*=hs&~$R*C? z6LBafBxYXy@axVQf$au4!>kGOjO4aQHytFJ#~N;q zn!6N${^qw3fwAF;a+Tx_rRE5N$qtPg@XEu<%cipo-y`F4z~1W2iP^)8J|KU1dF|+z zHkB8X`N<3vgtxCNh<-6V5sp9NQO)^(ZZZZ!yLZb?K%81&@XwzSnrimJH+rV>t?YVg z@=aFu{Fw$Hjj0tAl@=xcKC|TVFm_I|8Bsv0D9z8vG2-&(>XV7lyL|aydeQwy*jLcY zW`lpguE#$IQ^EhA4h<1oXA5Wd|5MmW82=BGMwarqEV2N~S23-%78<2n9s$t_6?z;P z{V474eIzVT#zp~TADNZ}*HhP&3)_g!(Cb}0M#4c1yxvfz?6rKNIDK(f0Qb%*r&%|r zQ}d3m7cbBa=!C>(pFOZnYX*Up@Vo-pb9^hjOglcws0YPqY2z?TB(>WhLow=eRd40d zOZKscO4VlNO4T1^S$!~wbVR{ZeK`hUS0)%M^q>|BfeMEbOHLJ=hNv2zzH`x+iDdIu z+PdisKGbmfjOHWtJ}4n)FT)JN<}20ForETwI6JoSe(KwLne6ULD@V@^&*a0B>9Chx zhQzHS+UkwQgzUc&G7ZfJkR66@+2^#3&gdYv%M!+^Lf-n~Xj{c*;jmK6;whWnfL!nP z$|Hz=#O=mPaVnURMxC4ofUvw1HB>Q*bVX`kWjLO;QrU)_3eSL3NMD2qMQQ>ky|VK} zraMik`XKN?{VCf6uPu9!+7ayD`6b$!zjEP5iJ{jgK2(ziI72CB=xFC#z>w#|xOWy8>AabhbAU)|4Ul~GJ!*zTD^3r`cw zHuyR-`LP|S!?g^Q6)50wX;EJI`?zk3%~8-r<$aie)kvN9jk3`^)L?Y!cp#F=M21%$_ zABh2yD1(DU7(>!@fAZI$&(4|R3R`Prm=_o;Nwv9FRjXRn(sET~^HMv#9|G_@>)n(r z(YRh8c&s(k^}OlS{jWCfD&ykqbdEgS+)*(iBm1zN#q%$E$18{K{?UO)86Kd`gR^F~ zBH5NNKuyEjkW1DqHbc#+X^7SHKqZaUwi?)UdU24r*%@=bsXgP%{<~GMM$XkKPS^tH zNX({BQ`U-9TI%cVE5()Q~4l??ZE?rgg+>)G13 zkG;hbZRdDD<(<&oAu2kzRfV<#cw0m_{#xL(b-OoZ9Wbq44pcL949#e{$wIS}Eivqt ze(%wub&buq2ENa~`uYkK`4-&!%ua2%cj)pa4a46Puh(m6UDUP?O;xSCQ1h3ECUf~gYy2c#6w$@%KmsFoAD zoh}uu&uL!Xf$?^p9HqRNba{%hda7`{%Qk%!;OVZQ+qJ&Rs$9q}9m;+s;?3@8eVDQL zOkJygphte66-R3W_uU>pvdh1^b$xdC;g=5loNjj>zwm9p$o&e1eJex#%BsGrj6Oz& za!Mm|+FyG<(lYpu>9s$Kx?jilYqp%h{0@%nUb(Z@pV7W^GOCZZxGs55KR~Zls{CXe zHbp=eUdgwALk3KAqlR=7r8bciNi*5mOGB9wQzn$FQEwTZR*}+4&u==1w$4=*b_@YP zA7+13N$X)KGAWnmXuaK6J7fMZ8WpffqYShs4Sd`Mxib!vuFs8waT#Nf(G2N06!7tg zlNLMS)WVN(9_s@{)su`Q2-9#Tg{NL1_3U8Nl-~ylZ6hdI3hNkE&CDbzY2ud7*xf8H zc?C9Qd)iU>xg4~+bldxK)b{l-_DIDp5b_TkKL?vJMo(YL1~QH?lA?oIcFOoj`}o>< z7=2pW)s8o`!^yv;fS2>SjClOz>x$)(fvb5GtijxR);)#}?n)IO#VlFHe+p&?i2X~{ zNtwZi^7>dhu~+E5?#wT{cCEmp#wn|CEnlpZjSUmHe|)S=}TZ%tFXDU;(nRr=LZbX zQ0&pO-zshR*<3o=ikWbLv7y7Q?m5ZQE-+2o*MmTNuS(?_yo+^c?pT4Tj80)H36sCs zkm_#PhD#F(VtI){_QJQZ_bjn<$>6taG1z+S5( zBi0X5s)GfHRK${CF@(pW0_XkPie>PhNF`3JP0Uu#NxBEY0q2BAWx{dh5a16MmK3uX zEDohUjT@^7(e8=d6buC=k~8Vs!UZC1D`K2kSS}zVG`&VRqfw+DfT)pw0WXn%dp(S1 zwbpjmeq+^xxIjND*_e#u1!p#rpTs%2_Kl~{ zOiRT(^Vc+KrW1RPzg9zO#iash7feD(nQhWY#aA7ZwkMm56pkoZxD)gB1$_R_SyLvI z0VbE&hIU7?OeXv>dq)8tOgn&rqF=wJ0AP+$q(#k1|HhZlkG_cN8MGtia<9$G5=FEs z^%#hofCJ-j(vgjNWx!g!w(4rVVlmUy+s>+0e;O+IIjG=`uU~Ziuw0E`!r3txEE1AT z)9iJ{^J1{_9x{!F$was!+zw4S1toQMM|nAp%%ZNMqKmV`Q2DqKS_5EL-||^Z176W^0$g;A@~^Y6!gHm# z%|GC?WX-WXGhU&Of}W$)YuaQY%@GZ$gVu~%WV#Nh%?Y2>b_h9mqh5;Lgu3BspxB%-qpxm0}gwFcJ zmSZI8^QvRbrrE^joj+~Q+z9+Qn{@NWUEDTLWvI9_(UfPCFg&fNxr&xdGw_dw!I)7q z51qXFT_LUfm|WEoaxrCbA8vSgxK^>{SzIG@eU|2uR-($@k$J@X z-|kt|V=N)%U%M4Iw$Vhzx|iaUb*HB+-T7F7ASvkWLTo)6Y_4D9p^Mgb9J|eH;#=ce^V_}vI3epMg91MKz0McKTz zh#h~M4}ShK8T~R7(Bf0!`BLL+ICRqLR=D@21U7q<>TTRb8=h&sZYO*<7_-+$l6qOc z3T`);)O?sv$U7qGE8>^y0Aaz^UP1R%mVSO?>CxUqU^LK&E2uV;L#*uy=w}%ch6~P| z39q%eCX@=3&~L~|&F|&NNrgO*Fra>X$db=~#00yCQrJu`kntTH$0jpNMm|k9qKUqL z#UHpzaYI7~nfJIgr4B!|L&#%T9#~l-d{1wHdZ6bGGr)Jo|F)a+uE|; zPYw9OpPX&<%pD+XhzZ=--G4MlkfbJNxYy|SG)Gv=@X~2ko^1IBFSI}3hhOcM=DASE zTUg3(U#@CqT+ZZ2u?oGassGW|EyWk`oeqmAZR-;NwS4{h<2-oXU97y~!Q1}2Agv>#62T8m)FQs43`F$S5@&xDa8l2_&7TPGR z_2)-;B^MGkYm>;S_&&j=!G<29GS1d3{)Q7)*+WQ^#O!CqszSM~M32g_#B{DJ*02w9 z-Lj_;a9gQA!otZCU+rH&F5IO*aGKO%@bvdH4cJs~)c{`3RlCWND<0iA)S}B*oa6*& zIKnKQ-;~O-z7ZE0Q3{x9sHfVXK)n!hd5PSZK<&77gXx>l5n(&~mgrhvDc+L8R-ZkT z71p`_6zIlV`0}+APsPu42|nq6O8b$o#5gquA>(Vu(Zl6-8S;QU+OQ?6bI|dL&z2gtYzQViH1#9fu4v| zqoty)q!Rnt?U&P*Dt0WgwHz1N%qh2lQ=%frlMxSuph0ubpQ+gvRS9|bEuDYR^5`1D zUpoq4mYD$Yt$B^;!T&&3;_uYDh0WIg!lFUqkQij^0VdgN10UBmOlvf&gx7LrubyYded6M^;Xhwmr?BaI zC??JF3e!ea-dw!S^SY$vKV~VqrfhatP<#^kM|i>{^IH(fAYEKJi@8@KG3-D#L2C21 zA3_n3eAL?J^lZ3pmO0R}H>cyLXK>?1A5d~=sjxnMqfZvl&DCW=tCo&PO-m|7WLZX) zlk<1LGc-XfXQ z8XJwM&dETZV+NbPZMQ$0<&VkK-_<$f+F`(D8P1SNjpu%osi$R0IdO9d<|S}=qq@d> zEE#hm8XY+^nZ_8E5Xlz|BaEmXF?DT4{)I!k-WI;i>X%vY)tv~^3nr#rzkaa$6>?UW zUx6JcIBFrP0)AJ)-zggzKT!STWYi-mlh)8$=v<9#Dm`b%vWBx>QCPge-Ui)1p%>xK zJSOn~PHDB_hnL+^dEU&Dkey2&eoFbVqvz)+Ao6?n?fHQwW@gV85Aq*eIdVmS$9;vE zVAG2H1{&id;djK9l0cX&c7N)z3F}yBf!?+Ip_rp9QWNDzKR4lC;`0T5*$AAhgHL2p zQbaC_mbNWEv^hwpEUFAvWd9S>JwDL2Bvef{KIxS{PXJhvvNg6Kj)F^w!ZKonn5*MZ zRnRLhgyD)|vY>=50J^(@$mXj!b9k78dqhX9P46A5?BM5DnTgTmI$-}#T6+LxMN9|F;o1RC0gXnwyxt3IG$r_ zUrjYYThs};_j=$f${m7v^XL0#gglja!~Vq89Wpi)(}W}b1U)dDWqg=PjR*hZ_$IFm zLagx+FN!}?ccRxpxHP8!9fNhj{|9B%G3xB^9@9R|u*uoo-L3q>tn4Cui9yC_^ui6< zn@HcB)bH{sIK_-d{JP-bgQTutxFL%}G^~JyJ}q+yxq@Z|{!GW_IP4PPt3pc4M^&yQ zO3UZ^f3%6jn3P5FoYDO-_BD&rRk1q_)+|_uRhgn^TjIQ?WKY!o`V05gLwz#b!h4-; zQVEk0v|@u|R^Hof6)g*$1vjv1_QgWA*yLvahn6|)hZ|O>H?>WPxZyS*sxDDG&UQD* zb~jXa54dV~jM%~>OR{gYDtqo0t+@wrmLU5=n=|%jf^F!asl;aZ_LZ35bHRw0`R^_9 z*agrB7}bM`2LhfZScz3R{5jzVJogYd2&q0%&1V0$pfcPK#S5T?ps2)B9DU@ihQdh+SboZ<5{xQF?nzeNpKBjO5RU# zEO42h+Flj_Q9ZSv+GU_}vj@6Z7IW`s9wkud)bmvkjLnSB(l;rd1GLzX!h)2-7Y3=nx_oKWLQ;dN-EZxf|`Kj z4Gw?E{e6F%|!E$#M;ZYI^kXy*#X7r2)M!j@rWNiF(Ym# zPRMlC*T8}$jBHN7-Acd@b+vBxgK>aIT1k4if2iOg;*}W--NwvRmhkuNXXY<|5`#%2 znM~ObK#LR9cCo;U76)ptWbkmtYCkiyC!HDkgOh_Mi6wVe+g!#16D}>T2lib}295q@ zV7dj=Z@%7rKD60LFG|ppwcm+t2SAnxQIb<^V((u;9dKWpvG3x!%3|dV z4m(enHqB!3{UsJ+$UZe{5w)B^tV8I8Hi9A}B8fGrGO)4@mRbVbr1Lg&WF~RwsV$L# zc=3pgld#S#ixCJf)H1>8RYZi=Jh>2# zq(s?TO6fZ@f9k;vy(4=60NUeYLAOMQdYIi3P#ykM9!z6NX(&w!RZIOi1wGxfv2dwmWVjzeblIeb0eVc z1b@}=&6C1!6)k@GOa}(o=HZagkkiH#`Q0Fx$3!aPgqczJc5d&z+x>H5Hp( z6oe;P?y^qq@1^6t3Ivh&2Yr*i{wBLFa*TxMvWF*~sdFFXYeW&}`tuMWNS7flMxYjP z`;+snoA;0k)lmhiaR_U?cc(xhFb6;}y?gS_@PmC}adu zqAHQifNmZw^l1x)+EdCNGYM4UAXMbPc7{o{f+$xdpxq(e-6@tIqb`n8pE~jdR0CBO z2g!*pUd*Z43DmM>=pEy9_ZLoF__DT-nSb;#pCa=`@&O}%7D1m#cZYQ!NE_Wy{~X16 z@i-*{Emr=umo&=E!HOo)^Scs`?eM{lC&Fp>BM;(OE}JKH`%qYhU??7*HBR|OmWX|q zofM>J4(%B0?^DP>3NBy6%Yw}IV$AD=piBM|+`*`}94ExfDX4j83D03^qge^|<|sO@ zfff16&TdHA-h69Q)Bi1QjSs8na^{%NmJO}WK3w6=0M zn0;1dEXXHG$OM|i{)>V}bb0O`+_-v*Lod>$hZ8*BgrI&ygP;N;QbWK_eZUJob9enm`Lobsc+cTu4(VV zEyfZb+Mgjpu04oTw00QEQ4d$~3(N~_r!O7*uT}|}u@I$^OHz@9*ymY-M@_{Cx~)x@ zg8?29VWnxpcFShcJE8=53jELqC!|(O=&B77O3CNb&)&a>4yIN3;YwR%>6K}q9(mp2 za6g?a^5ba_?eY!YFw%(qd-2<>8GKHVmhj}d>0kK*Hx2?`O7qAm_V$k{f^$lKc0!-u zm|#uU5N!59mGpoMe}}8yU^|2KNG^S-PPz|R6hqFBQ5MihQ;x>Z!Da$?Dr0fK>B6+xK4Q~tir5Q`dcqdQWFJuE&{^ja zH7I8ktr}+{=V+)kPj%*HQrH&g8#^YDT(e5b4(`af9vR#Jb(UZ4dmDSN7ecT7#L_CluS!C=Z}jdtJ^<-x3BvK?}jB+KBBU38kV5r;w6) zpD?%_DYBhr}kDFYrwIAg4ez30YU zc5!LmJvc*COc^@~LSO1f68Mw}Kbh1*BGkr%7nhP4ASAIqCM{WxDiF6(i~NwY&O5^H%=MlOrLP z+`{vqy8JNYpecZ)2Wx(fD7oF+wbVphjdLrE@n1YIX1PkKO9>&OpmKA1S&R>HxLhL6 zjv+|7S9Z!Xc(bd`dwW+vDjL$IREz8q`67`zO_Y-)y}Iy0J!;x9N;RMwN2x+fOg8^#*90<@7~^GrT}KPDq_mlPiR{Qz)q}D3s;J*N5C0)8dlxrBj`ohx{_{&XiF> zDmIyys5o3ymzfrJc1nZt1CQuiG0zDfBOf-r3%5UoN&FeJmu5O*PBA4shf#F{Ur17$ zlnEi722?=l-NzP!0FW zoucB8DnTnYM|-7TndeW8To!WUIChGz6*KznR4%4|PBGiBGx@Nof_6UHu(?1Tu(@cb z(QPd<;?<>}PJ@V(Mi*;kocu7`*sVru_o9Zy%RoQvzrhnWvfYsa+c?Fe@UvsyLMK%5 zK;$d>hG%fL__wsTD$(#P)JU*Jfh)35Mv(4Q>lGz2>pL|YI6dw?Jy!B-^9LUfw*Mey z(WEQ#Zi^}&13I^A3xhe5X8N&CC7qjBYsW%euQ*q3ibw-Z@5XJE>05}IZ1N@!>Dr~P ziYtIW+a>V|H^8VSgdb{ogt!ZXvy)Xl1@TH!fRb;@*?IWDmP{ggEQC`4=?@U8>I?~k zbQ`vKn%aErhVaAu408tbTWyg9FlRXQz{V1P@hnR=fTHXt#=nlhpUtnP$nO~v9~csP zw{s7uNBk%(orAN7E3ja7%)awJTd}lnSYb*;1pG+qcOVT#NhMlR9d$^q3qLsRCD>26 z!Gi+_qWJxFvEp5u#CJd?hI=T3V)0lW^fM?2Sek||NyVh78&VS=b$FthM=oKxptTH) zXKw`n)F1`MU5@%m;oAxC{EI^H2g`E==_>ew!$E9o+oqORJp+;(wCPe>S?A&zr*&Vk zBlBl$tF+kLoY)ZQkiM12K<5xn?l7(ZaL_+~zw&i|=WqYW-v&wF22bD4v-UtIJoF(r z0VO!OZdB(JdU;6&Oq4W=@fEn-fdwB*a|w5sGyts*o9+Ay?E(s~{R_7qIxoVLr9$)6 z9ia+`k|LR8+0j=-?Dz7W42C)5^DWe99xgzz#vkRi6*6f>I7{-51p}*%C(rN#!Aq36 zk`xhx?uZ0WR*gCMH7PE^K!3ua;D5G@1mr3NVJcAZ1>P&Hnv(MhChhG{yclS3b4$NP zlI~1Rzxn+)moSXIwla$RZVqNEK{@Y{1*ua0#cZdG4`+b`Cd9xwMNzeVPDHQ$(hfX(+ z7%Ci^K093SEvq+gRLPAqVRwLC$StjR2f|Jtvw=7I4)nqMOF;NH)2*=1SA4kH07bu3 zFoiRtuk}88Fh!qVsN_Wn*N05_r?y!S#DT|$JVwu84a(CwgKyyX(q4lFJ;lWkgKmG0%M<$0dj;JGZB)+zKGb_jzpm=4fzM~kv@YbH3UW>GZ973!Eri41 zEFnSyj}N%)7`zc8T*%;|k`NRPgd_(|uwihaM8FV_2w9LZ5$5bAy`;amgrtO&Fq0%B zS*URYku2;Oiw^l(eOwZ?ITvO;vNOk@M@oCK8+lUm-rkRoOR6{!Yp!Yfocq{kPo=9W4j>@)YyJpCSn3J>UCvY zCT@bJPN@`AMd`vjD#}x4*kAV z4o94cH9<{LS}N7VEuecDCACbO!a{-AoD`Y(k)#q<8nVS+W!vd6@Vwo_-OSmD2KQk2 zO@t_|uB$0A7G>DLrzp!jw&Q9eIf7IP?mE7JpyrVw%!aMX!dAP-6jzvbIbNbTe`4|e z;MUyBe@qXU#5gfa z({P+BU@1*zwX7Lex7JK2Z|zTauB8l3+p2OE@LH`zfgPs;G(ICzM&nXJp=g6QD@MTs zGgKiCeEEnyAF(Aa}$ z9W!$NM$DPe!6?ZxR)791>&do*%$A(X5(_!aJoLaXz`b6U!K4-2eB5=Ku_(NIJK;jE zNmPwv?c%VYWdBuat3P?(+5p}YgBeg6-&Cw^J;r5Wz@t&G%NAEmifxienL)coq$Rsn zd~Ih~tKk@~O~rA|FWvjMzM!pQ?g zArY!=x##OWpM(n-G%lg+pb3{QA%&D=%2J;fh4E-8JXrt~k{U_1kaoCifJ*H`tra57}scWlxKO?&ozi+cHe=C_$U{0k#8`Dc zJ2%1%Ow_n*1|`HYs`1O_EQpdODx5j59-}JD9ND(xQ-Dr!+drT?mSZ+|y3)34XNj3N zk?y+qW%};ZO@}^?q5A6x@c@|!Gy2Pzp^c^>6kADGamBIaWpl5=gy)H@7-|M%qOnUv zrK|cvwI@d7BQ3`k>!w4{J3&((KXG_=WOFrN(N*LY1ferWGAM0mQVJs zF7kee)N7m@!oEd`;cZdQmXd@l#K$6uimcTkWIh^v#L00&vBJMxG4~mcy~<_BG!9Nqo{*iSM#`+}=`rHe+Va z?gA_QoijzYR#HW+r4Oi~f!gkG(;54H9PBZ+p+{#nD5V#t>cR!H{3QYKKmN zH)ZvsiZ+ug#p~3yl1)Pds<>dd*W1Z{x!(He7MaD^p=bSUPP@^x5yR&Kx zMkFxwyAwYxBLzK1lR{}dMDUt|9%MN6$Bgb;N##cq|Gs^OYD9Tv zniIu|Ubn6X=NQ;BHWy{YHhBvYIiDA!5)A}}hvJ=Mh~27Hw<3zz3)@zHa+w<4QmE*x zo$RG5oW^ z9Q$qJFDL3C_WFrAa(}PAw@>M%^weK_eEeW6=kpTGh*Rm7&o{N6_dr?v;rtLO;g31Blp7KW zLg!e{8~N};VLOqGN*!x=SZvN^HH$kasi+h9r0R|@wphSpcj z<(c%L@T7YC*p(#HPgzXG1kl?i=P&n7zLFTW&z_ee$7@X26YMar4O45DsMh7yN`;~e zP;Q&zq;;G!JC5rsUUSK5Ar4ZtD{|%{8`r-&7f`yKs$>V3w%W%kETzSrnZ!KJ2ZV+^uDqbQ%+d4gaQM@2VAc3 zG?+k!Xm1w8UI*5doxQAMkuq68Hfkh*5!c-~bw=Jzq%HKaC;Kc1-le)Z^(t{7uB>0D z2FLsRKJV0zUamIJnO^z6^!Si@5g47Ax)BQn38^`ksoXT#xt7+a^(v&K;@+Z#u@}t; zTXU=%P0p;-Q?FTd1h`W#!>gW^*K^{wc=AC9C>LU=ztnD8l=($KMvp(FE`aW+JF30A z@Cey0_)Il-kqmFIrn|H_k$F3FW`yug3jR=?$#zOQ*4oi6Kc_FS6j8slBhSO+(}yP@ z`awvPIsF9^S>TCk&Io^jfsXn?6!QsBErC+3hIW4O9j*W$)p!H?b$O&&q;Gyjc;3po zeQ`vb-HqRaD`=xvdg27TyegVW=}4SGNi=6ZkWqAnyMReiZ0g~8gOGNWQp5AbB(&Rm zybvZ)i7N6hdHta(wqgAhk{%s0IUFD(PdWI#8lXoIvSUd86~gfqEXOD*S>=aL7WcdF zu{D6Hs8b`=d3O@ZLyC1f#tq>K6dsK%C3Y{%9o?<6k6=3*n{o%7CoIFBxyymsttXT@ zvC}&pXFCGHq!qu#K{Z$R@EyzSdgzjenc`<>tTN17!Y*8A&U!~8#7eIxYDrq_gvhlb z@_W=u8K5@2L)N=DIQ=D;xozb2neZ#HHLQt(hb=!Gp1U=aa2V)4K2}rk%VU5&J~;M< z9sUjdE!I(Wd~Ia(Xr!POJx5?ib#tWUz08;Vr7&Rs82Ng5JkVWjNpN%bWqK(&W<-Va zfS~x1N$SYw=kSkla0Oj-<3pM2p*P2@Oa^~suR2B0pjznhKrW|%NN~mi^ySX+^0T|n zPYw$N@}0oM5D3mxsr>Q;Y0$7zx8Lt$`iw-4YN=}n;K!$LN2gc|C?%=&A{0}UD8=dh z*0~%TH&xhKHWxF{rVo?#QdsI5Tg&rB@V8 z`+o-UO@6#WnC|`=eonDRgVTpJDu}1Fz&5IdmCpy&JK7H1{8TYL6^;Sl8RSSEhxnxV z_o7G>)Ok`GAzRVWDTltCI&-vBP4Q}I-^^G7>dL2}C1i_UIoEq`TbUOs%6e}PqU(wk zRcOxfZ^wbCWcY_S%(6QcY2)ewr;Dz_lvK-)B*uPJe_AuX=k11}nbI6kQp6D~6%Vz9zM zM$0W55UURg+){6sv{?u>3|8r|GwEY$sA4|b1<^B-lUgEGq(S$Tja{b*hhc`*q;9c@y~EIb z$(tj*>dt5Hva8vBes9X(BT3DSbi*>S#hxbF9Sn9sI^D~Bq0${$bU~?l@P5JV8&<_b zA7Q33lrtdwLfNoAle*_CH+kH4Cw+H^?RZb!8K!sO^0{O4QbjX-U5H7a(7`VOor8TV zz81wlR^%?Y{<i0_yD`_|0^<2z3LrXHu4+7Y2jp_#!uJ+ZiQx);|4 zu?ia$=OyW^GHa~LXRg6!cJ*rRRf1PPtAVz>R6Hbrs50}WsPxtFXL>w_GS__BA1&ce zhgf>BAJMp@GJ^*A5x#MCY{o6fz&2?I{IH5&aF*44kx#Ocv}CwF8H5C5h3JY%1PusZ z=nrMgfR0VCx$!xB$R9{8si_E)o}KIsXC}iFb3t=Xt-4o;C41XJ+PpLM_GfT~Q)CNM zuaR+WFxQ#w>R^d(?QmyLvCijZ`52lS7^uI}C_uXF;+TqE$RZYUO2JRR{qnuMeSj&O zSTR&i*$HKMMi1M(&721)Y_S{%93BWYi))Fp3p>p zCrozzq7XHSJq*UcL&Y;5Q^1XX%8gp{2ub=TorkA^DK&2>OV3YcC z-d{NmwdDm~_FWnBDr+I)ty{yjziev}=f>F8Dbn_V+94T-j+>Jrj?{r~pY@Zo8%q#JtX!53GOnA?uzXmW zc&42>&U>6J=9xK8Y{v&^hEvo@)?1T`M!2K%!#*6~nfAR8FF%VYFK-XVLYCQyNyvwN z&S!*^;P+Y2&;K44Qt1Osxc@oz+Cl&KPCW%{0}qq`nG*hwQ%^}p{-0BicL89lg;o}( zj)+(||92EB+(*H%o>FUJ)kdFA4GdHDlOUKj|+6DcchHMmL2!3xY(>5hU`b&K3 z#irNvWR{oh(Khe*6A-4Ct(iG>q>E)`nC{xtvZ?*tmj2AU~hFls1OOsLo8GUPRJ zGW^5O+zdN-FJAI-XnM!|Kie4GRxAiGb%9jEmLsmXGvT^SgOOJ6FyZw(c>|~E2jOqE zJ7@tz8+4bGi{2R>?>zP-J)2SCEilkcM!x;5DPB5NS1ln=e})ikM<77>-TN4pB3ic! zJcr#%9YbU$@WGo)Ihe$!@8rAYvM0oeN;wTkco40}qm+a9)~fNjbXQR3;&=WiC@3h` zg}9(5DyZ-bheVLC8mE3cAyTnmJ}IZuS~Fa%`s!iZx6uEkyN*=oa3`frNH)JRLCkx~ z7{Akk(O0Ozi?5#;PzZuqv$_>~S6@XOxc^?sB`;e3Y_*@`x;$Pcm2c%vYM&Tt3S8eY zJpCkpEM7CmYo_Vyo~V7Pu^)oxiW%9u6_^b&E(aLksiwDE%(h;fF14#v^$?k>o{MSN zX|9o`Pr*!4O&l33kqAL4wF>&CuX64O`H!2`Hq@lWhWW(leIO%+4|9{~##$tt46>?( zk=0m4lrj}x#}jmEZ1(+fRPUpD1^FbO8BNJGO7X_gn3tAPQSF!QKX;}U_XTemMXOdg zg~C)b2Q1?#+M#TQyjJ8*IyqwzyQI+ubQt5$jmN2K)?1%(|F<;lWOeC-$bS5o*8bo7 z>;7As{~2IUd3*fJ`F_0NJSO{RumcrRA0P^}CWH*qkwF**7irK(>di$ZA4337NMm6B z=}_~oTDps-Fc?jtNL@-8*4i{ww7jl)xj!#z<<_*MNnN_b`P{WeK>hi7+ccH&e)Vs5 z?KI7M-WA(@_oy`UqZh_y6*6ZJVEls8b3UkLUxD1RR|VHe3uZUMeF&5zZ{BwWb>kq! zyms8*YF!9_hR~~%SSN3P<+gwD5;W;KAAadBfQS3{G`BI^ai7q8Jv{Ul)5AyAo|l|CJH=V`qznSWN= zq+-@ZpX8Sw&N;xQtcCF-j9pQ>kv&S1^qL6o8Pwx6VEEEB{UF2K8Fu@1xMl1O??)ZG z137w~_43MghjW)7?xUsGhwl30E*SYcQjhDF0uLF{mo%{(?O(e{pg$#{3?Y$;!e7B~%G&gV z%vphuM4TiV1~~vk5yzNu_E@3s{CYY}j?y;@mOz;tmV^Zy)*wAmgbmB8q_BA@PY9=Z zYv4SXVNjyjJOz0)8c6}znEB>et`ZEEQQSms9eCFGEQ?s0BOn;asdaER~FAH%b5#E#{2#y z^NHV=LLJM~$1YDWZ9nVX*V>yK+{u`9T?j(u-0!122)~R65Uaa5){$H7ckV^gOp=MT z2$!L9m`$7iOsMn(M44bHk8?|yz)_`?p~`7ewLd^)T^3616(p4Z@@h&1%sF~gN)$Vl zhPb4vj-R(x&TsCkZE?*=?&RN_TuH-e0&}5*_*!@@Mg3jwO3^7jf1O*#3kEW@kYR!z zCXZ;IYLQood9aKPko)*ruyR}Qg5jXZ6eBcom>pyC}f*ql>zz6NHg&wvmHwi)nP`lN-*5vP3pq4}!t5op9CSNX`}elB^Z(evlE zL6p#)v>1`DAN_~A^yMug?FeFnvUkCqd9rLA!jBbDZRg9$Z5d6QFztb$;6k1z&;zU< z0IxvZtLf+055ksWScA!MmJ`yHR-eacz+yV6uAhI3puNk_&czS}t_fc#eGMEnBs8k=#_ zU6TJ2aYszt8ZZ3UdQ*0L+%iJ(GDJ`cE>cH1M$lAjAYtdDrbqD;lv5Gxj8nsVf4HC< z)?x$$1x@^4K)Xw}f`d}SN#A64ArdHV@?>MT+&=6r+snsK`8*68qk~~Bb+>Ka>N~ZnoLYJo84l} z?wIW9TY#RS)t@ubDYDwa-sFt7)f1NUkTyC{gfr|^s8qXB!>)*fI82L)>*U(Ct8bEM zf&Tmws9}|oUt}JP4f$XrvRyOxjQI73EHyhW2UXFW!JOQzmr+db(&B;T9kh$_jlo=* zg?CNoBMReKt2LzPw9X@aX`vs@xeGj&j<0K`LA^$rS`|f2W#mS$_g1C30sSLXuz=(N zUcAQ9>!87_sRd}z!z$3;bQOfi!7lcc)kMZb+Q7@a%f_U|LbUla_?&Be|x&_=@k4+S~>Yzfo`@q8J+Zwm1)%77mxRYkc z-!R#X3^hz+?9r6Tg*t1D4J@&y*r!K_4XfEagq$s-Xn8p1+TA{i2)$z^iD)FImeuQn zhQ>w%wrqIPa6fk>=MaaGe)spPuV}Xx4~>+6dAd12&bd8db~mszjZEVig%NhAl+@n{ z`+jC@qJRsGUgpuwt{P>fr<$%>hYr0jjw1A9@-9|y?PYalMmo8Qt9$_jvO*U`*+TZR zQ1X;S@ntxqp3`phUgmS(Wj+1zSj<}_Z5|N%gV5K{rk9X)h64QgZ)lrIrv=V+baN`k zyVegZ_v<}q&|S%RWxQlOgPyP+coXr8uAR#59Z}09W9Rq+pE4decnxL~$(k0PVY&1b zfAbp83wn+h3OCLamVjN zDQ2L0Z051H(Iv*rMv`@r1a;9g=rNv-2whh^Ak*o{c*^SfQVrBB%*ecPb{Wjl%XlVk zGo7T|eNiX+%Jwk+>-)PbK$Ub9y?dI_dkA2>HbNSOB@_u}Ue_7A#oz#$- z7VH%EK=$sO)_{KwCTb^k$62bkiFl1mNt7_h4a$vyEJ+sSUzYxPin6Qx`b&iY}aGKVfe%dULVG|PgFAYnHL)vPOuvj9poa=1S8lrJ0m!M;Mkl;GfV! z(`?IsJcF*7`Q{Gc?1}G}J1M(itORQYL~B>G%26x4XNF`{@CRs%e6U-qtTmz{2Xntl z;AW&%iXvf}$CRUnW!V#ONfGQ6{MW+8qT@XZMs4rkxm~XL!`X)M?AhEWF5QBwZ2hS? zt|NB~=C<;6&v(e5(Li!GVQvxqoS3*wKU5yABg!S!!7NJ4XN+~!%;vF5D3evwn$VdVkMVaQ50Yx8{@Jb6ugtk8WBWotbZ5I)G&c)w%W`Rk?wQu1@(qr;Kp;bl)bxy%ST?A+cp$aZ?6ZvR>7acHVi8s$`?GA?-rdpt(sJ zx3P><(xIeTeZNW@hqK^@77FdsTJ9S8IU4-pQ^;kXuydke!q8Mfa;ibXQJJsK+lg$J z_cfV{+KEZ5+G!#L?UGx5UCNW?u2qqKvA-nmO1NTD1}6QK_s4;ex_PT%uFVz|@|<{P zkaNBS-T8Xl6szG24$CsG99O{$=7~p%r=rKMY*e~g?#gUYIj&J<;sByPlT4+v92Oib z@(IMCz$%98^d9(PbGnPlN`peDIa50TH8)NO@Wy7WmTguU$50E5V_aUYTqw&W`*Yq) zd#ZfSG&tTj5Gp)ymg}u~#3>$QTZNYzWF(@UVkO^)L-MLPH~jckJLb6_St!i|u~bz1 z;N@*7Oh<_h=>a#}RXbqn$vGF&J{aW3sD0u+o8Xsu`zd^_+*V?K8$962KxyQ-qJlh7 z&a-2Ah6I@1XeHTZEd}A}{bZ7(A798Z5Fd>cC6LdSTs{Y$^46s-E@i-%8FAJe8B)rS zy!gQ#5%K&X`So67=gj6(#M@vhNVExUipa$QH+HTeiwc?Tnn8$9!>D5}7nvM?M9N8# z=T$$NpoR0ip26cM6{lKhQTcqI=kqXpmdS=LE3DcEBttWuoRTDbI$99Vyh{0U$XgT! zQ(4=L8ZMiNL_A`cU0o!e+^K-9)l%eT=RioAGn-a$U7p7zb8%raukS|lfOFit(AYDK zgbcSRl;F)x=tHDBt1g&RXLjMrYnCOmtxvC6OnU^|a<$|yCJRs{nJ>|pzSfO6q-*9d z=IX?FVWh@gthDE>;4%@THHKG{*wlgQVX1}L)M5HuC8v@jA6^RiRVB4)gj75a(*n~g z=~+;3?&)T_y4;+{W^R(2LMgt{;mdr<(x%8~QCvqyCWGaW>>@NyTLWyMk6a3z3d(>b zv=WL^$+0m*9)VH~)8EGE*-0zKQHTVsGfu!^K2IJfKBi7Fk&3!hfk`(d)So#iyDNp3^qCnebFTg3%kq=nxi9NWa}^gkk6@b8ewj5aV(X9#A%a3R!2xzE2>a(RnrlN$w3hAge(h0g z*tKX;`Di6Hn%qy4jV&Zq&KV3X)V($r4#wP6xS;0cGT?M6xvpnJvs&slj}CeIA=y56q1*T+}ozl3|9>&);piHMM7 z6sgM94fh}s)jKOZLf}oAX~!bwawv(G;I0@BkPe-zm#AUV4d#^FlITmzpogJ53|G)O z8ts7moa?h_W>=zA(ZC&dDeIK3ta>_81qT%u6A_uX+|kGIG!eE!Eoj1Aed~$tXs*>l z)^M@C6>`;JD=!ZY#BMnD`AW3UTIjP*#2Q`hM9@-zfkf8A#%A3}SJ6vIVO6#d@;_khAw8>@9=jtTaK7iE{nXvTBi`eNR zs4t1=mds1*2hN?b`Os*D`jV0149;2^|4h0#b6)ET zyPU`QYXqDkJ<^^Xe7$fA4LFI^RzsOW{1QU7OhY#sQw=@SEgusUSHosZeHmO_BL)Qr~9kfxGH}S$yBI~dPhw< z*}LX@%kTTt1~Ht8&`#!EIFBZti*HM}_+{qWu*AX(x@_U_UmuxTs^9^|_s-3m2;`#s zCB}P`&deKK;K3af)7m$prGG#}KgqS&PLhqw7t(9!=+YQ}l_ciEM*HNMw|#-cifzCb zE&tDEdhVq*=lwy~Tmf~%ZTD+1UD-NJB&Fv=Uk<|!KaWeqCHA7>Z^r~xz#64bm{iPM z`-4n{rh=kQ+Yn=}2%uk5HYXI$iT&ovH&2P3iFD`4`mv%LJt-cxC7F1L75BBg@=6sz zecCw1;tnxhYHl!C?4(@5ZS26r{^xn((eUUIIRjEB-$jhevjU&qjFN`F=^o-pPeq=o zg|CWATFU%ecs_>1+Nuqh4g^deK^G>Q9&Tftf%0HwfYQ)Qffre;V{&!$*Ai3LCq6E+(7r z92V0%7Uet}v}04yP}FKPHM8`_-#q1Vy`AMo;mZ#mu&}Q}9UkgG9pt6=nk!r5tWRj}hw<&{+WIIb=_QKh;IdcASO%N(Qo>;5{ygTMq zm9E#9t$hT9V6G}NmfKns?tSY}yCUvVqp^stx(rwH3dh8W^3eYf62~P0Si|aixBg4d^nieX*r|r6!}L z9H;(8LHoVB}m2u&KDi!i{BU6y5u`FZ!)4R8%P+z4fzUz#y zq4ZZzb0VL!zOAdRYNQ}?%Z*!QB=S=-Dq^vtSig`fzOiF|3%~c@aXV1RyA{j~WtRXB z>Y@3+iXusG?yiNKhata>CW_`yqYtr#k&NEZe$9as>3mz4* z6a#Ralm{#flA4L0tGImH;^OukvW@Yfscj0osg)GM=dGVy@2j-~wk#kc|7s!D4NmR= z7)Kd;VqS&%j)(n|5Cf$rnd;A^A;#9(YCDXPVY$}tenVMocp|JtAn+vRlh`blxXVMX z19GA6Cyl!weQIyWT)=_eH#(UfOORc?;6nT8T)n#uLi}$! zf2IcjebawQ{2#9|yH>u>U~g<>k zGKk(<0R$@gz%L?f8tiiww+a)miO(xGkU>WTJoV2X@Z>z~_eQsF%z=>g?Re9GqS)P2 zpo{*Mky;#+zt9JKb=Uf=!_Hv&pv`Fo00_%#7Ww^tt^RY^T@-ybGz0|)2qQMzfv!cYO_-7s(jrnZPYuvW>tOKxBk(dTQlmNvX)&4o&yWvJ{5)h3#-uUu z^^A2GwMH>egBC${XDL2*z!G)k@Zx%3eraRdX&=fhv(vXto6yfT1lUt8$;pF8 zIe@1643_##CO!&nAaxsX$zZYPv3DDyN(KX0VK>Hp00r{dvw>cZjC>nvo3q$*u#?Sc(fz)?vS;5kTUF`I#q39Pcs^kAJWDr zIeXbylNkw+aUkTb;P#Qknl(0mQ@_# zz&uQ_U!e&v(oG0KPCd8|50$Ts?BY3bE1srNvSpBB4RwS9$DR}m`6sIxPm(Lo+6$WF zsJc$2tbwh)04T+^Z>@8$3%1O-u-Y<261T<|H>G(1(IVN53@7x6h0;a@EK5lxDPA?H zg|T`>vj=D9%KxFl60!Y3Yjd2+weM|V8L*Ob_fIz^k;8)^W=l#82Njdnt>zXJwf{Mh zy$aY8$xa7S%H)N>uJ9$k{i8RoYOA1t_l{E?C)*u7^OCq5=V&quV_)F%B_4pCt)izQ zSXInc=s9`+MT<~xxcu}KHS!zFH4Zy&)cmeD8I z>^HbCU~ZkJ&y2${6*ipSfi-bf7=-$e!zH%#fJ;>rTixAGpllb8(k-m&=%@w|TslFrj1ohb78}1`R_Nkz%)wrrtJ7p3#?%SC_n0FkeFVeokj9h) zsjU&@F@NAcAGEY`y+LhPX3!kdUF`_0kyRz6IKeR&f(@$P|tKg<2f%RoICJBGq_p-r*KNKaYVdU=}h5KIX~8pgLWBASFD65m}_; z%ig9Y{IJ4+HY?eEWGKb+XyF!clk~x?U{-k{L@ffRaFn%RLW1~ION3>MFqo`*>4Xtc z2^s1?rBY?>>b$_ z#|c0p>@cW}rdi`&TjA}}I=I$-O!`bSVOn+Qwxc9f}FJe?psE{hM3Io~IWHNS@H8>sXlXtj0`L zj`UBsL5-lPkBwi*t6oD3IWXGB`i23vC@&GE43mmpJi{<}(k}M8{)-!?D^^7;lhVd{$$|8o-S*6)gT73{gT8FS zAnKxFChB6b6LX%Zu6-x!f-w?39WTQ(U$(u^)(5p###*nSGbHLlfwg>8RioCRpffD$ z!h*FNW39aM`(swr1qf?-+FE(Xpm2Rkv^j>v3Cwzc%cJ|sTAC{lqLikdD)GyrWuG9gTH;U<&gEfh$DxdD)k9WxQ zfeN)LOI076J;?VTy1v%An43C?Z`|6Umpji-BBM7d+@ZKzmQQrPKDoA&9WqQ3)!>-K z_HfLjN`t~7uR+lWuKzGX(Kmx3az5ii>iU>_XLMw{zm3#|*i7+1N%ZEzXd@n`ts@?& zDeEH|vnAsp2(Cj|C(Q*?E6syXpH4tOm-~o1zwJa`0gD z|3JSySOi|+Yg2N@%v~h~Tw$yB3tXA32Q}EyK%Huw_%el8KU#|+;w z12&oy&J;+nXEr#{%8Y1F3<*vQ5N5(9o`c98gvnB=Lp7++nkNF>DFj zI3Hz|Pk(}n3MI0ZI5|(aQqpNbM^_(Xv1YU(eDxao8`-n4G4%v17*t5U z@p-FV&JCJQz3cn#e?*QYy%KWJdh6YpH{B|?n@I9I_W`_`2V!6I z&NH>2druQ&;SdyKT&$1OlP!Cr+YQZpV6rOJH5NU@zLEzsmU>h*D|=Igbi(&!CQ`L| z3dTY2bvd=1V0F5}go~s?EWKO8FkB6L9$f6~*LO?LJC=IcQyohRFk9bSQ%xh)nQb0? zXb;_b^R6M58(_klBX&$C>EndfJ}GCiG?jwJoLxit7yZ zIl`^a#~F*8zq&5fwU4(0Du?i5%9KUw2N6BYg`D6-Gd2p>mO~%;rpLv!5rDRD*?KIZ z4&1U1aHURwTmK>oeI$R37iZt+o)K)kE>}i_l^X>2V1YK*$Uc(ym^s=`AA@gL6f2>B z6l2vm56+#a$3LV%KKcdNr32p+cCQuIdAVB}&yC{?^U25J8jYuL&BN4A*e{7@ zQDc#?NqiG8q}{H=R$PT9;K4dW2q3(UzDhd{*p0$-Ki^&d;p2X;1<{N9`hDYvA$5;Ypi@*aro?8(MD-?R*RUCt50+t8;WMcSVp9i?G^<5?}S zx~KWvnXUrmUhMqr;=c{|XIYGQ?%!2cy)e@DGS2jJ_lWdrJ=bB3)bnryMB?tpw}XK$ z64590fHhk1Wy!`3I(i~zoB?d|gKYV0@@bu>{UN{b!C40cb@vd zX5(36btHA)vj20Kl&ol5p5nB#5BCFKaY{cu%&?AtEs{++K3Wa5o}HU|HtFB$^SBkY zjfjptvrmm~bySo$0Gr-Q$ZOa7Fj%7Dn84rah-Y#iuH248JG*pYt*x+_S8YWA^?^Z3 zC_EhAv6pU*p5;7m18#oPf!^gDN%>(pdB>)M>2hAG>;EfTBB3W}84z1V;%Xd|4nD;# zV5r?Xw6~WvHAX-2^AOj z+c^6HmiCAcohR3nb)rR1_-$I`GelHPrCw5`wR8L^#Bc~tQwdD3kx2M^RBJ97Re(Kv z2M4;Bm+QKTTH&hsOR&YIDXlsV)n%C}7g3F#)(-ftOYKE>w*PaG^}e zT+V!3*`L6~5dUW$b^N_9(0)=C-ZsMi@2?@YVQK`c)mIQZ?&jL$sv$ehlTBEf7fS>U z1&sEE==G~h5rs}7svWRA`?}sjYk1hIqwgcRh3dJB{nYKlcj+Z1PpjMlzVa_z@Zkc} z7B9pE-I4{KnqDATu^_&eE6@vO|G}_?&MMJn*qn~BXJZ@K(w>2%VsUfgFsoYHoF2Av znIW&fXiF~BT5(EA2ga~=2Suv`E$l$BYhVh^^vJECY;7g?6*>SgfcUJY}u@-F>wT31Apv-;?GF zI1TiosR?N>CoR}P&DhV?0z+z`jfm7B3mjsH{w(FEP2&TS>XOaE?hb_d=DsBMmaBlg z4WnmwM=3pcc2CJ)84UFINHJQ;0iH_ac`JQ3>LBWoUfTB$z<=Lx+b}VF-2emt0Q+6O z6#5@BwN*{bEsU&9{)?miU)z_(iW|0z{O~-PY3vNNE|WAAAuYQLhaf<;AjHVUior>e z#E{}X>+F@rnK5kl#Uy$|O!x%B@_hbrf>R|Tw|z%|7H+09GwIp$Q{G?CZ_s^4%-Ea4 z&4GxPC=IO8T_#40BQ{tY&|bbb%BJ&0gC{+*Bj5D7vL?q->`7|_b~Gw}3~10Hg{(qv z5=F+;jb_lpo<@E8EKlKCmHE*kY`HKZ3nxM%bQk%tZJ4*hnBI5l@OJ2|gTD)xK*I+P zbIaY_8Q9|aqSeIn@4)zH1|Dh`?Q2t#?=%=6R)^C~I3C_CfP1W3v8ihYT%E$N_PxF(t%!NEZ)! z=mAb2$0>`dvbgQk{1k)Mx8Gn0DA~85R0O>->loat4`&Sh`VkkjDRTG@}-lkIju{*IC2p>tc`Qhj)vfRbFj&dHlA8`1X|x_txl1t9OeMLxdc}4vf<#t%Ji+OcKQcwfm+yw0&PDQNKP+6q5m!Mr} zRd_ow!Wr(JtREm)o77?-bcm`GCMXH&adh+FvBNm*3x)~`0ATT}oh0!84?F)UKcKdu zrmTYgV}s6a&rX?FmUmn%0h*RJCx}EsTM*44IprUcoSnV~D>jqGlpGJ z9u!7pT_d*3X+k|zr^zEBHLn*jw|XqgDN?pL$g^Q?v@bWY0l%QKp!7gqG{I%+9X)OW zLp0Ez$Fk_rTXzoFeFzN7eL)LBQABNT*l}?K;Xu;8x?lweP9XHZbq4m8T52|#8_>lV zJedp7pniG-(qW7hImfD!GEQ8`v$3(3vSSRRF%k08-W%Y(I!w%^+4;QoL`ayS=-ykV ziA>aIi_kr6nXyh(B_l40$}i~f?qp8`#+y$G z`ESRcrs~KpOGD+PZ1$=wwR zOFW@WDW;mp0D~PMeP15H`99ryTiwdQniKRi+cb=Y7u*`sP(ci13QSfcue37C{8!!- zHoR4_<&dm>%5|_8B*w_x5K;T``hyDb!{~z(A*(9%v8Bk;yWzp5DBMA2B;2LD9$kHN z>~4w~k}Ua}vgGG!DH;0--nseZ0Pg%!j{W!09r5SBPFY&q96+|@0M{%`7`8G-Bwb~@ zBwf^dC?K`_Wx*@RU9oJ)T@kIs*h;so+X?pC{U5LV17VP|yF?&(2gD|N{lwvMN`~uX zki5fY&^E30tL6a_o59Y@;vvuN%W@o9O7Kj#IIRX#I|J|?<4>dTUFjl&^4RbfK7&uK zY?{RxTSgisN3sPfm8+ZWnw!c`0S5UMgu~ggV${M2Kj-{|+@1V!A91RZ-F%!i91#eb zjlO|zJZU>YZ#?SOghB==ICMiFIr%o9dz+>(i{!-m54qHs;Z&U*vXw*)}C4ftrAtD`sQJk%d zCQPH4C^NDUjXY-7sTut^f|GZS2WQY6&dpnw|n zBm@I11`42 zzG}0{DJa&lc%ZorescEG5m^~qeyl_#W5C%JS=#pJI=d*{raecS_iMl7sv9Y>Q*a&` z-W1sxh6nqmd_8T@ishT!O{{ znv4o9!DYYc*f~7$`VDDdhJ+&=56<;4faaM?U2@IOMxGJZ$Xx8noIq+2Eq3Wr7C*Y4 zAzY6j@X0B}9g^WI$cIA$E^6<>)Xph`L&P?sAAW4F_~Z_{L(-D$qh3KU*tjl)Mz=Vt zkgX$a{1NJX11{epk{MHR%7QaXdg^%TNBF&}rCqS12Z$E2wLw+nx3`qlK7#shW&aOVT$^mNcJ#tbwy)?IcZ+ZIugxh_bK?zX`_MC++q{*%#b@4>}ZF zbjUBi3CrVe!ty^2I%*~c&gTD{F7ls2N72gaKgc4Dozs)%i)G8NmR4Fagl+P-N-FV& zF?HtkB!N4m<8|q#Oh~3?TJN>U$o+8N0DgbnU-AP~iwOs}v%QWtnO+!ndi>rX^`SCZ z+||nmhAlCyOg3qZvh$gv66GmFWAw{PzoW&J3iNV;kt}>FkaG;Qo$&WM=C|k5)Bpf6v`9qB=iy&XB6Oaa4)&p4g9(cBlz>QD-T_MR?QSLduH3YIEvYA4aZFKo?(HgTqpGbSz&B- zcr}m@vefb0m4)N&f8);yf-^$K~GdDkm`FbS|~i~Yy7iGN6Hi*ok9rqU<)LX`DVdT3{M|CA*^ z#w4ipFB|W_qY6PKK!WgBDNF(q0D$j*n98WxIa(Y4R}%c6nEEg6T5Vv#kzjsvav5z& zOdwDa0+M`KW^L)Df21R z=Y1=_KSOpo6R)5Iw5vW{5pWb(97%`CkbJ7~9x`SHhx=QI-*zB74a0 z3T>7>U7c3$6=pYDVCNk>C8BH?nrJpU^h1oHB#uXhy6hL+c8Nu7Mpm1fhp~IJR0FDZ z8}=BAF>5k|Pr)SEY)y?OTqQZ>V~Wtf^B>R6g>btf3^t4oYbxUU_8Iz=u~peUV2bD9 zqwGgEZ! zaR%$rTUhk{6aQQl_+Z=F>MGL{re*Nlg>N17e7FkHRrUtT6z|3%Uwq?JIb+vXTs0Y6 zlqHr~hAP3dnlJk=*@Kw+2QI;f?G0T+vtQx7nB}3_404ci7;2d5J zqKZ+O#Y5{_UJ)~R@z}p#iZv0*1Rci?Hf)np0v1y0aB;{%U8boxGSpbU{cuaFw?%R# z`T$sntSHudUJ$b=U42p@64K)CBzs^WeEVb&wO=l>%w{<1bR z7QkC6_+li~T(b55%50iLVjMisYNiE7Ix%M_BD4}&_Gy_KW;De^# zL_i8f+xksH*`~OJS^ddfAliWowR(h_ll%hUEqLafHZ6~n-(huyeog^JfL5de8{qu| zw`+u{10{eyK*mqs5s+CVISZ8__NT(++(-Fk^%a4zw;*H>z1oZ;44x#G((Hx8j4kvI zgCTZ~UGj_OofoYw1{g+^L3LJo!^1Q*!thX=>ELNv_%oA98aisBDg^%%XMH>#*%fE) zFc{{TuOOFyoM^~bK#l!;jdRHU8J?}-Nd?^T$!2#4`zt^P z;+^?RrWrUvI>|4ujpY7!F+qpqBvD?%H`Si0$RXEv%~aedqv0N)_7=W20kWV+P79gn zlGq195YSDWO0Z1;a|_D)elg2lIstSLt-qx8E2t>=tk=OrU?4~Y0uIc=hIH&U_2>Vf zKt}wE6<(T~kXijwAjf}Q5bOV&`>`{$G%<3f6Ed;37PNCTHgWu~!aG~pMs86a+4q|D zpABmHD=2uRq6d?rd^&mfJ~o5{v=Ic;UXv+*ywbz>ip?rDl{VT+ToF&H0HSUfjE+k`Fr@S3 zK79+ZYpKbk?-Ui-%aX?KOUhbR=t2A}w9^)%vrEO&YHUxrfGiwlAu*ax?ZVQnO=PqJ z@p-qdyuEj=O3HQE-}Vd4B4^BXODrxr=e5477_J)#==YB`j#Jkq?x0VoM<_@r7<5z` zN?OUC2F^ia?1)+Oh#5}I>^b^QGyw1;%8r^re^N}SB{=#O=|4@3KT4yORPlVKM0dQF z^^!MIwc}q?adOrvvZ`^c(tkmYWpip2`ksncIDgeQ5RV9#i?|FL>okTlF*8u>JT5;Q0Gv1tpSe9-&J@6fX+HTJnvZiCyx&FUgn?hs)e zV7$!X#oU8hha@Jz7OGP{10I5B%PsNlKq{arUc`=!RHBzXt1Rmy4WDRLwe1i^MTGcN ze*lkq13EDCqJe1*;@Lw81~Q#r6st0`6Y}};2&TBte?b0s^!yL_S}7zg50q=W)?%^$guu_7c^zfqQsE!(#t>S)5v1!uiGh+K^*e5BHR5J#_g}r4 z;3iY7>x(-q2oxh{{9A&r6hBZASlPzP$P`W`jz2@sRW31L6uSIVXbA2~JxWRem43Ne zgURcEh&tMOvy;5w5oY8_IB@i1lVcfBQz7`GRYuyb=avMMxO1u`In_2pfOdE3^1^#MR2oc^c2c9E%=-&sdpI+st8ammwe`4`s z>=E?`_#IHu*5nO1zp%HDMEj(1@o(2L>410=Pv#*A#h% z9tC2kb5rXuLBX_9U7_B&@j3W;4xy;QkUdnZj~|$mFRj1EyW)s>7~xlDEvet1|Bl+W zs?6As-zq{B8~}j(f9`bu6Se;ZSS_bTQRHvd6q>d0RpR(10%Y;5Ayye}^Y&!|_O=q3 zGFi+JU?IET>3RS)LxXhK%6ASgKY0iR(4fgCcRyygg&YL0MzN#IIK_@i@^^{l{{ME(609 zjfH87VP~FZw7C>-wz(j$-&I~fkeA^~`#`T3m^C#9i>08~-RssE368qe%nfAXZGhMOZ-rl&r6g9Y z*@{g259UGEgEPXyWuO%jOi_cR()TDK8|e($jm808ehcOM4^x#5*ES~#x)U%P)t>=# z-P%S|5CRj7Ni3}^?^!Oe)WqUiAq0uY3_q41gdjYxR{ zh~Ys0T;RAFyE$8vn92sH95Ch*!|p((VeV!_~AE zq4ma;Od^}Yr4$0S(ZyoXe*E8kE%9z7X>jLB>Vqfe_ly+S_Gk0E-@m#=rGGGIG6YFh?a`yU=P8Ipetc}#qEy~S)uWk{P#}U6jE0p7@emoN?;w`>EJCytV zm3YKya5N$;eCCNYZAxtt!8kPy+Ao;~72z^wJsm4s!|x?B4SF4!25mHkFuy5#1Kz*O zM08u{jbsmf|x3lUyz=GygiX0T7iigDUE(= z|I!w|i)y#XTL4jVR zHMSK)-rxWSOc1B4q4@r~A{QMQ%!NHYVOULQR;U6@90Y&gsk6@Hh5eNG_Jq|faFZ>S zR-ID~e-+;ej5>43yR1{whU=AJX5Wmm8Y^2OE=xATBo?z+m3K!kJGV93Lda$sSI*2+ zE}38l+X)8{4u@dVV|LB&+PCu|D0KjePKy-|ZS14gHbmo2zKMz&traIviP@xsel&9E zWmjJdNcFM-#|$rub(B9ZYvaA(N$L=#d`>GQuez6j{>y+X7nT6ym|oO+(=KjCYGmKp zm$kI-TYP$MOu5N8!!i;TFMBtiDTfN(>_2?(PA*;>n9?G>p~o&_u2ILe2-*9-l7^~I zebX?w^uqHz<|;V&Y;D)qzZn}Eh6J+3YR*2!R=eRFI*&8y8o2gK6^#$QEeh1DvYHKo zpgvuv9ggLw>2frD(=%QlDLJY>Q_fjIDLm{$)|hKqqg?bn)DMAAz%8`2yrgFiEf6gX z0c8dGhOKPuJPHWaB02)wErFpv=QGJDj$0tJu3+ia%04R|4}s~f(r)xuS|&qV?FFgL zu&azUD2UO(-G-0A8?%I$K6faW>V5%`mp}7OdV7Nm{VYq`%n7QqC zL8LL=6(Un_8$#8fyCPSBD~?0!Yt6Z|6>FY50*u&gcVW6L>LOVz+@&8ESa7xlbjh}>9bFmwY`q5VW4d&o zpw?4zn~&}_D@FzM6Kx(&$2I->og-CsRWshT+DtK1xfpmUjh;Grv~4ZSB_R06Qnb=$ z=sh<&JAgIq7{b*@6Ar>&l1{G1uNgYyaSU0c5g9f9q(2fQK{B2Rk=l*a$m3m@-2aff z=96U)d^wcz1D~(LeD@>BmwG1wJzEmnr8@xH`Uvob4MvKcu)iPnK1yDm^eCD z;3+Woj}_hQpZDCsaoeZmx1jI@FCGUGT*5lN7{n`Rh5I29j8TKH;bDNPZ3J7mZ2baz zG_{7vYh92Nv>SW|=!h}m(8~?AeK!W>C^5Z~FSGKl#ZczqM`=g|RkvUPEkL|zTTXi|b z)C?|r4PpxM#sD#3E&sgx#Hzt(3^|?KbjBfHGxIjhwP6DZ--6!l&-`<_ca6+{>T*4v zcLojEBpuv9jg&3O%@`lykax3CBHvS4RdT6GiaT=(!Gq9C+_LhQm+NuI-k*J zshE^-;)06dnVJp8kjTkb_kZdaTC_9jhGt0feKv|1#RR8+%*<+hP~TQBi6Sv*(pHhH z6yM3y)OFs?O(%+IY4v{Y9xy_)m0rHdXOGbveX%R&Y507{YH;tX(Bk%yw}&mfgL%Ct zX0z??zQN2#pMOU#m%Hh^iSD$CG9A(b4{#j++JLYDFfM7_mg zm{NsN{(JXOkJ)-vZD4tEd%2zA_kUFX;lGh8M*lom@waq(fC2!Z`~MoL?0!rC{}rT? zRkhTR)R4brNz)+==E5N$1uDAr#plGkRpSZW2SqIes#md+jKPV7NM!`0xSQaAkQb6AP5CxE#s8I*%+^6funC$!g zY2arzYPe3Sk|;~g8bxzm0DYz?IGP;-}qQcFDG!QP7;f` zE{=q_6w4jUbOSNLmVXI_dIA!pMX4Rcr$#_^jX01MG@K8X*sJ_WnL2r`NMKwu!?R zRj)MPCaUP%M-`}Do>xe*Zhbp1J5t=aGk(myPffI`mZzmB=oboM0{}XWyLwBgya0C` zTdMlLrKqHs6uCkPPpB4K%DqKkTDg!Kb=QQfNVe#xJGVIu!Ry*t*OE2r7OTrm(Jp7L z7fz|PM_<$UZShghwQ?2o9kTM`Mr9l%KZ_T)>*k!Vpi1nXvqoaS(VCHJTqlqa$3bFm z!^A>rJRDo1lqw^KlZ0h(9&3#kCLQZnICybJO?Td^Z>z9{k0gRJFrHMa-aoU1)rtv^ zI3zO2JQ7(Iz;%-%Qg8R=MG!zkLVw*vqaTJxWTG?InHPkUAfef>`5WyM9MCkj`5OS$ z^yUB4CRM{})mM|Q$`e*%o{BWv=d?{@kJb$^zvxmta>WAfMSRLZz(T3@VS;O6fO4L* zSPS});e>IO`;eWt*F0*_DcG2oQ}Y$eRkjs&BW!Ps==?Z9=Sc`V75IlA#jhFPNxTxQ z4aaZ4B>_8Uiwk%U@?4rDScE7CFaE?A@QjrH$34WD4F~vFysi+4XI1Q0Y}|2)Pc*pp zkD?JK0ShUlc*Y9yw9Y!1d5l!XBWd82uvHn1Ms0L*DUqlHqeh%xn*i$QMUldy$2GEu z=yibnxf(DlW_$-TZW4XTO`bk*EKxaZT;;2?Mqsr+;R2_)Su7h!0o$K>m4AU|y)yWk zR`_Qv0Y&Rz1~Vf=iIcH{@mRdVa>G-dp66I2wm+8%xWo z0L(#%cg**Sj12C4*LjG^Dc@QU6Hc+ z@4u2p!QZ8~7Cov&oQbkNaq{*=Uu2JV2n(zWe*C?|MT3tX(YB@}Dqhe;uRwtf&lyEG zh13C5%5jzS_A#NaoL_tlGEUBo6gLT?+eGX!Ou~4j7~E1V05jt?AThU6(CF-Z01%G75-kTzNft|k0-+~^PbJL>I;`##u%oxWrrEv+M z4Ily#;RP8Xf<@*)BY_7>h~>eH%52<;;|%l}k;stnEiZbO{?XRRXm@B7pr9xV!mn61 zi&VF)|IQ_U1?!$aI=sKAm+!x3eeAZoq)EjuUxM0idOEYbt~I_-vcSTAzWN4*nKOSb zODo&t4-|aw?G0#U_U9L(6HKd^MSOpcBWqLB9ei;I@cmz$y<>1DQM>+|Ofa!Mu_v}Q zv2EM7ZQHhOYhpjK{lxYJC-2$+UFX#Pw9l#P>Z4?T2V} zRM%~Lb?=H6_THqLEywMUQ5`L|NMZ%PaMU_<<)Lm8vG42wbGoHWxqQ59d1mi#U->=@ z$4;bh^mfb2OX6Wm+!EsGQ_}$6-Vxn;X9tts-W|?$H@7K`r<1`*eHFS_fGyy%`n{3uIO2YAZI@l^Tu4 zk8f|GrL0zIbXu>RrTvvQBM3!QhQdNB=P0-KEG&7yxsf-pZOo|Z$+=PX#Fr}Vy?!Wl zoDUY1C!B<5Ny9FbVpdzmwy3sXC#W*xGigpgRZin=w1uIn2-Y@HwR&W&WtUs_Prio` zrWgqm8=#KTybC*@#RzklDlANuuT_d$Op9u97zn2aQp`kaudb495Q#1nnu-zAk-kWm zRtF>hsDd4ww>KmLls5+4QSI~}>Y!K!2#40eh)uu6E>D|w53J%ciu5*^k~9v4haGL< zKajVEI%porUq$FBRD;rAnil>^zayX0fi5*TM-jb$;wqXZztZchTC+~#;2gV`MEVwr|{-qpC8FY&nyNaw9s67GZQy zK{)~3e2>bZiM4g;T^M(dZ7AoGwY9_pUSt9__eVr~wJq5y14_e-cZ?kI~Y=x-KVk;Fvzeok-aD8e5q0m3i7-b zQ?K^F(d5a&-VXm_EJo&Bg*e*}6N}qUiR+$R>+PT#Htj7f-y&{H=ty}yOjZ{Jg3i8E zGB?y~(1o~ul%9pba=ynnD#&3I@1rb-XrEIRR1gVFFl2*n_{aR3H*FV{3DtsI%J;xj zx`gghmm#&qq0PzIn#ww{W=X> zBaYD5e22~%5SdV{JxCy#T+sQZF_QSWhQo`jDG#|!=P8Ug(T5yqy%Y`|g(`gU-@+-` zLP1K^eymnE9JVmliv8=kll;j;i+C$GofAt2B%4}h1JaIajwWA&Xr3`>FP81cz{G7g zYOJdU57(sC zuoZ3~f08wr$G8Zi;`sfd>|xGcT}NSerHdNX#595cToC2WYWFi=)SIuT0*-yZr9vj^+ICNPo@3FOT zqQSActXBISZ1=}$Sl0ag+z{{9)Ja1fmvgpp6x%UVmL0I;P=ZFmdfPt#`{Lw*^{rEO zMcgTeMQ5?*-t7c~eBqS5Q}f{Z?48#$&SERZ`D2Gi5}N=DYuKK{}q_)JFvbS5F}`^=a)Kk@_@h#DGcZcvs*c>TiBd( zJ9!uCMLi9f@#<&Z`Rhg^#_JG0cdFYd2lP7O&3T3y7rT+PTQK6{C1Y|A&|UN(;4J`9 zKVT`XMTk=6T$A0n5|B#H&KcxfV_rQ0ba0-}y#4>BALHxcbMGRvC9$ds=u!zeo(AFY z=id|g%9ov=Lgo<-JlBiX_BWzth z6E;s25@!F!V}B?IKd5=imbv|1o>p1*&<1yoSbWVayTQoowN zx6jDU{p8vb-&r{IJ0akTxHu)U_!RY9c^!480HiNJ$tPjQvD-k0wUTEN?_HWEffUTh z-6`RG2?O&Y?T~l}Sm-)bF<3;5B1-L>$0y4EatPE=cKo>Q*I2T29@*z2z(DoXT>OGt z-8VZ08-73Z)K{}NIBj4!#bdu5Lo;sU3;f)dk|zWIRpQU&hZUK_AK zagJHGYXj9F=p8Qw)O3ExOB`{MnKS~S;=8+X!tZeUYHxq74*G#$Q$N9EXmbxs=_wf~ zc;?<&<~Xg<8~#N3P%wTX?<=|8xbqeRdgIpu)F7aCmR@;%^?>})^rK=zX=<+P_BIiz z7RU0|dW1NMxawPkC=YSe1XjIt{PkFlM9tt%)Y)joRggp+hN40!4|gaHkM-#zx4eA52VT zy-jD4o+=z(MQ8JUOs#T*)?P2#&?)V1gHTdj;0Wi#N^`KBYV5P848)hzLi6gI%~$Ev zKe1Ay9lvu#Kb!vu*I+ddx(m@@B+Swg_K`0j!-$`Q!*cx7eQoV7vm*x?G| zu`J&C?vLWeO%`&6Q(7BQ(K$6)4diEL=1CLUD9rE-R8FY4&v0IOu4-Cg*~X&>O^~1X_?ABK0v97e~01Z_6(k zi1CikX!mbhu3*(+4`D}B)p6Sg9!}xZ_^81ojS~g`j#3xRSlh7+O16`%Pn$=%e0RZ6 z?S}0#W$>fM(p62r(~@*epIC=8E~WWM`|z8`k2&vWD8g3IdyWoFGuP~ko~3J6$zvZW z6Iu|!l0AuOEk38B*7I@;7!}bYOJ!cZNH;4{w+Kt8V2|lfGF7k*sV`J2vPyQLDNtBq z-PO#{<$-S z{5aexJMsN>X>2delF-c(8VXRi*ArH<;DK-`qMDj1Njl+HXI$rs>6O|cQS7-6qCSju z{^fp0nOocJkr@+o*SulAO0>WZ8H$(xE_Qga$HC#w{|W}t!%`UKNUIvStqTLiuMwFi zmk{cT(@s?ck`k0hn4$=wvOi0cd9`oSIy7nh7O-!^{-%2e9$7B-xLf_QCF{1zRHgWi zLJCIr#6>)&5Y&Wbv8Ab>Wco(5WnrglX-5}7-NVwD#bSr((e%Vot>t{&ae}t$>`I-P z`z|8*9R)yJXLU0**rZ&nv?}5eW{!r&rYT`1O;WxB;Z;$-PZ)DAf53M^+rJf+Pu5m_ zETjs{;DmE*$k!OeHE=?~0r22H=&nEQwu|w4nD)UGz>?sTU+EC;Hu?@KO-j z%DEL>c0s3_?Fw6FG+=Q{!sd6to17@r+qnpXqyybLV_#9d%Gtf@;*Q}E;B=+_e&rVY zX(jD>t4&u*V}_Rx-SbeP!r@3f#4kDbr{<1QrV>{5Y2k2WBELCa+h?|6XFN2>8AVA_ z4K67cROcCU4=1`dWT0kf({qZgzj%4*ft_+YNZ+89c95o;CjVo13(W0zi7r<@OV4J> z>F?xwBKVc^Yb2HE%dB!uf3wV@oFd6&+dOiQP>ga( zMtHQMXf9Rg#iaRo)m?TcFRF832JDwCSt{B1Gy-tzWB^_*2#@O8>M}EKI8+ z1I^*AbC{j0Jk8~+sCau-ViZ(aO~+JQz>2!`RdUj~5u1R6kuyOmIsD-&yzgIzDsjfm zl?zjV_Q62Y3H89e`q zT=16yAa`0XQ$0hTsz{2NbGn%@+sD8lKS7tp#_M0uWe=64qr$7I_NC#1m%rcN7PSYpBuZd3n|buLU+U>E#K@9&+u{iDa>$wRZ4oD zy!yEU%r9BZ({N}dOsj`q?@tle-HG7(%eTqrIIgOFmiblm*TA!=MdNQn04q7Ul-$g^ ziW#~I1e&W7G97tYh1MfH-cj8%&Sk9zwG7({yw8v)67l<;=IGdY9EP5RjF}NHRIkMt z%)kZ{7L-PB6t}zxX&sQkDBiNwd}NRpvOh!hCA&p2@!iS-eQhx_I37!EJBAaV;XiQj zKoh-%QCU3Ua~k~;#pM4+($yKA{*q6CfU>f79!I{Oknm{H6GbL(S_9r~TJWwhNJ#;o$eC0U5Kt1xHL?B6`AKp24 zVVy7N?{EW%rfg{zfB+g%e1+LmW zX|BYdToGn>w&_DomN2>SeHNq}wonA`AQM*#qPyQ_ zgcz54IRb91Gm5O@5G4DRi9?Zt;-|k*{U`k;efS`ZlU{qH6{3R5b7SsWRTxh+o65 zykdKD780lgv5tuSFt{|%Z*G-aG2 z?t*chL!j&g(8)jq*kz8%)f`8>tUmTwuTxNSQWR=SMRQg7QBNdJK!V8UX zBU*2@J$R3xPk~e7HY33T!!NzfojgA0N>p}yt5eFimgtTZF{q|gaXJ}aZPawGrVWfS zjaC5$S69c2`=@l8cR~K}hRrig%4e?r$w!u4JCOWs@unB8Aa8Zk__i*%PJ1qWr17#%U#V z&bm=|C2#*BzxC@Dq=}>`Z(kgn%lvO2<80mBZ*%$_$WnIpv?48BI2Iw-?XYqaBUKNA zjPo~hDT0tEh%(TTR<=^Dd7I=Ret)t{NZsfDMBB18@1HlXbd|?F2y8C_>-ZeTsgAv* zfP2nKhXw6{P)-f80z9o=nm+5929Lg}P{3*A^XhpOb4?aGWsF@LYppKv(_}9T zC;>>D4+w(76j9~jPdtP_t9w?Rw9*g#dwG{rXcKwm6!Z8~5pS#%v+bj*U)mI`c>0ik ze>0cYI|5Ww9D1)L*=fDK;Fe!WRtFA{4pC#_rCX!~B*-W@*%($N$jV6C&hsQE#F9ZH{>MHxhxi_o`r+Ce}yeQEIGQT`VUNVFNrNB%LNX9aKKtlStm)$Oe?Bq zYH23uW*}=|la}u#O(r}m3rzNh>T}EXLTBgJ-kFQP&68Q*IJai{^8dX;y!q=H(|;wZ z-PE-w>FwM4W<1~2C5gbfk$6X?n2=B=uZh6X5TD|DvjZ!F7e>2MdOYj}bEpg(laHW% zD>+qaG@R-TZQBNQlbPG7fAQSWYsT~uEO?v50cgAq4Pcb=@R&+7}F%joO$Tfg~PqU&lUq>1`Bf^ZoUr{|*aAMo)g2PdQbY(bHa}Af5jK zp~@7IQEnPf^)#P$T}1swh%cWbkHuihhHgX5U;g`~R}^{a?8k zLIy_WCjSj4m;5)FyxloXjEW4Zpg?6^UIlg(73yyk74-{Ai!c=NxVCF;qSMuaJ6`Y5 zjFoW&%NK-y!rhk9pMZr@;$Qat=2JHCVbjU${a^#xAA)Dn5T%W2OrJ_<+eYG=vYmRo zIoJ#3iaK3^VNxCt4aVKf1;4#QQ&;xb0YLT5dKS)S{kc_(XIbF3i*KpxB&S|rD%tq^ zJr@tW6=+$dDn7z<0UNq%8$;tec+qmQXTRn8_bq<~t#>>Np(c8f zH;Q{>vyJSl1q<~WyY$ShFXWQH79L3b-Uc z3^j$sI$Cjc;e-NVUcl_5H2-M^{{MaUt;MYw27zoj?rh$_Aw&X2_bzQm4q-U?N>?9H z3O$Mf|FHSl1eCDM;|9~v<(-+%m z%0vD~TK9rUit>vf-W_iqZT=8jCA@UTJhL2SK2AJ-o6?pz!eL53^&*>R$~f(tU1@YU z6sJe8$ZQwokW)A?7PHT>zgpDddZa4brra_T|9*x6Bi8~MqbC;8izcn$U1)F(LBd$KOtu0|GS1LrOo~LrXv1Lrg#THK3pJUMPU^ zIJBSRo+JRel$K$96D{2kLuFG1X{s!Z`P>4+relKQ%CJLmv&GW2rninT(^03aQ@Qo| z8L!cyNqr5#-#Y0f>oU3R^z=CWc4b>px?;Wy*3;N=fM)e(x#lYnbg|zGc#Oj~`_5#| z*c4rE&uDZMT^6T=GD#edd6Zr*-l4r6mW*VII08tS^0XL|ve}v}KpvT!rlxXg>cpA- zk|9o-)u;$gP(jjVwNR`KkP*%_W-}@Fa6R2G)yS{M4S7djrjl9S{k^~mliZ8EYFHeD zUbxz=;qZCDjIkBk} zf6eB0@vl|4b&GbZQbp=&S$dX{X3JJJ($!^7Z1;hh zN%FCJ{$$-X;)&cirBz$AM3VX2HzF*ZHuYm*xu79bYbVR+Qt_CwtzM-3-89Md_oiXwX=_n*w%dJ~SURU^GEAT$4zX43kikl#^JK z9FyRaq?2f#r{kQRf1J~zjv}R8axShon?0~INSA8AW;M~G3HStFEz>=g@VGNarv@2% z>}mm%@>(Z{o}h+#v%Yy?d_R58_`di9%fJ|Ol7Y86fIzV2C2Lu3F*#0R-nuy0O{5~0qM~`WA1E^is*PR^AT&JsBhK- zhj9U{GmZX)&PVLu7w?D4mp}IlGWQE~-oBZ4tlkZT@82}{h_Dy<*&A-3Jis5enPVLq zsmznT4PoY=^^sR0GyMO9!BG;5nOcVi0SWpA0>b+LeLDHC>Eo}um9w@A`sbB#;;FPP zz72rox6N;)^>I=gO-*x~_4r~$oGkLCW_Vh@_6%)ufVAmChJ=)W2(q&LO$d5qWTa-b zf;pK4LAQ6nE*QFeJpY@}#{t1d!DNdzU7ycY4mW$!Mke@*q07;C&Qo?*pB?|q_P?i+ zuWUcaepYv8f4LBQf-A&5z>72#4&N_9Fg~@&*#poFAEIDUT*TcdB5((uv7DbK?&6`S zOgy;5n%)woda3t%32P)w|0?11P!seJ4O#Kw3ov)$d+a7|Xt8A{Zq%WuZ!bY)L+as1 zO@Q1?(c@2U5RYC&Jh2qUu9~6Dpx$}{xyecgMAG_-sb*jtnEkIHbmoMm+X>Q{r#8?e zNsP>(JS7E&dS~j5ya|yAPsTA9;-TC=B)7s}y3D+2v&Q=s#i1cNVKGIb0CBcl^K}zr z$S16!X`DdbTlK`cVi|aLIsS&f>ylXG>PlivRwGl+_a$;Iai-Iz&s-^z>7tDtAzv(0 z*X+z|&X$WZ)l5z_xiJXsZO5Zc$8(?2r`yzJy=&XbT=RXjDU#1t>KoWH@T~B^B8Zsr zm_w(em3GE<^?5duOBhA76n(;`&0BweLGDTY8y4kWIOWYq4~3x1@1l>zxbfBmHlHafP+<& zT`Q*i&n=??vl6iVMd{UmOkyZ8>b%h4V~Xa$vFlriIflueh|ahyPQ&}h+`d50zLEIx zFYI3ojf^~Ymg{k*{Rb|wtuSwiZIC-r=Vh$P%i1s(;<{=3 zt*6h~*Zmy-vJ1%!8JXxRtW^X5lw)2dFx)BFTiqy35Y}p#aCg>LPllG%-UzY&HMZ zF_hnUBpj6oChwA?b+?8feF=Z5xpeN(>?6_J$G1zyxC$<=o*R97$o3DzS zIqFQq8^nd$gn6>eUTgz9OH|`vd0{~vk*(;Kxf?N)xX(6c6F+piy1cqL7~`U`BBcLt zH3kj3~uNd7m`BkDYH`$kfs`u zq-XZP(>qD{RCh0oP)@{MnI&3ufanYT_3FZp$TzO}jxYb2XcTw3CVVsc$!Z>8bu16M?VX~^>1eN`&|=yV>(&Z}&gcHLqC;KtMt#=n!Is3R<-~a+ z6y^)K>|g5hSbo%sca^VvCj*L}b%CE%g^EioO1Y*nLQRnW(564mY-%zAU>svYKgPui zV+EeEmFsf*_gTvpx#5Hw+%L?nc07z*mj4R`B*;jb?4m)2Z2Nmk&%)8 zi9~Y6Igktr;M)jhUtl1XkDCK6ftON~+rJy6#4cV7)!yv{tL6UBDapJKEB5MEc)mv= zG{VssfwIlLDA}XPIKt5xfs)ZK+0iapp>UJ$C)$&#YqrY`Z-+ujs~&lSVfC)-=H7&I z34%Zcn7k!eJD%U_FM((9b}IyspluM7T#)A}Q2&og_&E!(3 zBLvY`7Pvf?PPP#%Z@DWYC!quITAqNai_M;n_Ez^b4Q-Y4JOLd$AtRdx9y!B=?5;OX z@O%DT)xeNBM_tifP}Aq1j0A|tXW;j5L)~X_40}A4;jKuvd;kE0Q$=yLX_zCk-KeKX zhepD4MMgZmB69>0|3W=VCK-v*B*$R1H5m)P_ui|k!Sr3+CC?6~ir%rLY};yO>an7d zY{~SeW?wn$%DE_O!*eUTSd-esNk{i)$2gOoxga8;&Cy|7YG z94eXmFzLoIoMMK+(`{Iq4Y_#;xh~5!jIz|NSVVX9vx&jrI~cM)&jdkQ-gvZm#C;*x zMc1lN@bdk?<=#Zs)EW~Xl#VGEE7-|)@z+^&zACNGT|ZQ%JN)0H?+d#tU*j+f zXl%0OKcTkt$Jb3J7see_%!IQ9+KK#9Xe<2+hxwJ>^t2V7GFs9ty%$qGF|S%nS~s>t zGQ@rGLBAwkbaVnzh(6C2x~ED!7`;ns?)dn}Y&>k(Ci9)K9uLCNs6N<726l8F0%I5c zEHy>8%Q0NbJS!Pj<`IYZzWqdhr}%iN%Xl3R^FnWtYmA8RQV(9T9#!Cs+gtT_scEsM z&mD=WY59NmyZ-0j(>s)6WcHf~oaF=oVftTg78OmLER0QTo&Rg6Sn|yTqAh)VeUN8O znYuZ~3y6b|QL;+?00%_|bKD^ZCGz)IO}nV4v33P)#UNcC%`dmAmgF`|@@h8J)XYhO zRFpTjSXx=t^dN3nwv=hwENNDKU0+XMTwIu#WIb@-@E(X zc0CcSX%Y?zVq=Uq{AHqnzERZ0I6UeWOa;DlEX~@0+5%I!>R{$LY*W*K6V@$xD`QPU zp)HQ4IWy;AECI8ql)u3HMKf&f?q7X-3Hz^suwdTEVGzJ$5I09*Q&ayod*#rY#^~`L zo5oGL$##Jg82iAayF#s0f_S15r}fzkkm&<_52uD1?jOzJStbq4V?EzMo>l5v36r-x z_!|*6AMRn?jhIQhG;s3h9i2)0w?03)7(f25+>J`$XVTrilJ93TPuc4#7D~C?H>5!-J@3}e~Www-{Ten+jeCQ>ITod%-$>Q z!WvUt@8Le}(4#Hy8S(}HvyrB^@LmmUap?QX>fMEZ2MF{bzW)$BV?VrNKT?-WeV)t! zD=g<@EDho!Sa@Yf>Lo*GMonN*GC6O(`MY^w5&u{hawe*}$TE~E%9Ue3xY&Maqr?N5E z&~3d6QU`}Nnt!?~nEy!D3>=b7=$#Yg4AC)fM(ff@v4!g>fs<~Kw!5!%Z(os~c68|C zNeD18v>GEXo%@@VBabwe!TBQMWLCCDODtD4*%Q@db)&OTQ*MC6%1~n15E0&iT6*}0 zrMQV4^=fk)<4ToFpg#otyERSc*jku2V^s|wT%;yFH_KR$I=_~1VIh*0$MS2$Kl7q4uR!`(;vX9p#~?s1&iy5 zLDulV34+)cQ?fDGBQd6nNeCnH+w`(E>?}~^QWo596x9b8qKu5oxIh{PFV6>>U#fAw zgG(7JcPSybV~A5R={l}wOCwKP-Tk@UsBIA4B|#}=sg+xY=A_Nzhs0og_4MGd^V?kT zvA?`%QlnZbUsJy1P{J5=PzVSW?ZoluK`hoW{MzkCk~qv7+93jnrZrFYC|TPP2g(eo zQj@bUNC}iA&WoSfCR|Y`=a0VA)7W6Uw2cc&FVy?qWr^M2b0d44o`mwy|VT_BQF zm`){#sU$BPcknv8l*5E4+XJE%{zav<$*3D_CGs?wnr(;6l@GSLxtk;@ZamYF4pR!J z#2_CMEr-5XGUgw44<=|1AAfZ(vZ-uOrgtVcX1{=5x#x`7MQtTfv z&R$@d;-0R-c0To~5u^^;P}vCpQb%e9yICrfx6!Q&&P`vRf6L@X$QctA`vDx|p%`u_ zx?W;Zu!+AC~xqn(rIajkT!spm-+2KUot3@d`g=!e~J1UpyT+n;;AH?|~7-GPQx9Nhspbxo) z!w*%b#f}|g3BYR^3zvDi_ zBkXrIh6%rezM?CxTwI$u0$~n%!K8OY&w>23lk^#S?02RACvFeb17E}(Ruww1Q1ukAJK~V2_K|u( zc4uGI(BZH7SK6R2>NZyZ5Ux`O?H_KR&CS<~P0mihyUWXyjt{Mnh~YUOZ3uD!z7PT z^MMt7hB?)0Iwl{f#xOHeN$@g%Bb5efR4XCi5XNcBu|riyWFXlc0bcX_RF;_edh5N8 zVuGDHfH<)xSKIP4Jrc$ixFsq~Hy1O{5V$nhWFQa`{A#d1_<=`W%QWRll?~Cg2sf$( zpgQh15`X@_tun(~JZC{+58r+;Za=)t0>}`uV{&|xmtbO9^irKSXbb#|R^otHE-xUq z!$E5`teBQA8&arZ6cUJOE-C6jyRP-*s4^^D1&ckwv&r)b}%P5 zgjT~{$L!(MK*aab-lN6z7kH>=U@MAHxjJ#1acErz^Ls`qh3^W`F?J~@$sS?p z`-g?9$(UaCw$LCY&3WX&?It-(s=^tgj&*l7#`CLwB2ZJCm0Y*2XUr9trK?P!bJx&D zkrIeoOl=$W_u!7T#oy|u8*=avi;28LmEBe9g6gF6XXTN!RJYg6!52Bo6scAc_f+zc zvk~kyb%Xk5t4P-{RU4U+eKht*uPHp4@+{Sh`016*FGxZigL<60SYxK#RP~sAUop>t;~%dnV0O$POr_US|}bLdOr|O_xsUTrF|~9AGRzvJ>O6PWPL*2%J;l# z%sUZXM2!je+&1R7Yt3t0eU@*kq*xbt?4I`R8x47eec95j?8{oC$;4fTn`OWcJ}w~uy7zD$WIiVa>jn|`0m`WAY_MUV|z>>64EeI@gPtsZ%~XG z!nrQ19O0|9#g!dGl$SAj1;y#mLw+KQrY2M^6uncRRguSw8Qf`L2^|4Qumo(20V)EH z6`_FSg2+kbLF52Y%hD)w7@GpX?>|ZvVWsnA93Je1OX}70x}9O-)4gyB1(~IFb80rA zQvo26H#8QwUjCL&&ESh$8OqXT9r`I8^^(b&5Ez|Ezf_rL@{_{GuFBTyIP)bJkJn(L z4e-9L!F+PAoS^1u&|->+&IAQ9c4r1bp^&{$1Zzut5Qr|23U{;w#uViQpS)1_=}C*x z-PR!qjnibteBVMLqOJq1qi$;vgJ0YLZzF|#l|i7SPAx{e-w7pz<1guvjElKq|hmgmp zxU1Q#92Ifozw?uL1K2P@;8z6@=h5Vy-`+lU=ki^-Fqhk)>73YeMI}Mg z?7&Fa2C=%#gRVA?xwF24{-b##*WURl{@0m*`xV5bx5q86>F00m&Xb{?Aju&g=WqmS zna2u$Wnn~pU5Q@y6YZSX4g*Zq>WJk{xc$dL&Wk~X6(MLk#}e~G5A{ACy*6_tD9NRG`4u5- z9}e+ODU+pAc$}$Jr_fhoC+YCEozwY|5g+6zn@L z#80kSS)HZV3KA+FR!J|@*j-EA4W}S7JJ(QNXaXq2xro0-#JDPisVYQqDngD9+iRTK zYl_5FywT8K!~sF+esTCs$a$CH$jU;A%rKAjW+2FXwm-KhaPf)R$`e9{^M228Gmrj> ziNtpU9m6C_q@QQVF9$urElfZtOrUabT=o|Z+<8WO%?Kg>sw^Ax+f9Ek{O4GreO1)N zC)R04|Eg_jGq45>R61n>8ZJx#p~ES5w0_X$q6jpGeBs=j8q|;BtQNO{+tMZXBl42X zDN+Xf9FqX1HCw+l#63*tQaT@Y&7{=2Z(=k#Jv35r3H2D;zgBu9nqz49pk#?N)_r>p;~ zNPdHlCqT~cGC(~UhN*nxyWg*6I#ks=Orc)Y#6R|ADabz2viO?6eo<@JgmyJ~es3`ENvw!p z&HnHBUVi?KG=!LI#j&Z%ZNp5?1TeWJI9t>>{Nj@^57S()YjR8C?VR|c+&s~xKn5p4 zNtfK?yq~(0_P}-bAhzD4ezktV5Ln;20D|T{=8p*7`V0meeIsjfM^Qsiy#QkRvJk4@ zKJFatSbtJ@5=EVAU;$V^0qNedRQJgrg-Kg+yCsW?O2q}p!9P#4`7CW9w%J6la6=@x zi(1v!$XSmoAMIzJdan7}2%hEsT&{qRw>Q$q6)3$J!#MD=-l}JYn=!{JflKBwBhUUb z0Eo2zk_We}zw}gp(Mzc@fbN#Cadp61J;AdPc!&C~luj zHH6A_tv#|ax~y;OoSW|#s$xJ2M$I{9u*cDkdGR?sK!WH%W?K+;;Yk>|BUPT8cE&y1^itW}GlH=$ zcx|4?ZBQ?5iyfQ^YLZNic_B}Zc{1$!{Y!_L9ycX+M4r}Sme*u_oImwP>FQ&9c6{K@ zVG#i$(Uvw9qbc<+f4LUKvZ}Z)V+wy-92rEKQ}Ta%us!`Qi6oT`Esek&LQR`f)|LF# z|0w3csWVM|@|#agqI^3skmRHcxwjzrT^wz=8$@L$MkeBO(Vr=*y8+u(K< z$1TBVu<0uHjGdnvrSb#S!mD;#=zDDF_MN{&c&mHAIxN;XkHPy2K-dyS#<-{~qB{m$ zan+4vS{Qa-4@#@Y97N0K=VSNkSyy1G9#aGcc~Uqg(UdHDqcG?1iaJ(Sq!akA9_nAQ z9U$6JVJef!NI#ts54C!v;@5cVYq)T}*m3gHOXu*;> zRRB%;lv?Or7I2lDRrpM&rWy=O0Mz{xDQLTK@bOo+O_@Y=DtNUZmyH3jKSlmdT)($f z4eMw-ryK4!rX$2Z)fO=IrdqyofgkG7MIYcrA8?lAfO20h8G5D|-KTBnea+a*Ul)*P za9imeGS~p(uUgyIjq{V$cfbiEFdrzrNwB?9Z?>Z0+OkUTYY=!364Gg@{Hgkqvk?@M zJ(dMZLMA$l@^Qi^L5l}Zl`vQD(2!FL15fT~#5Q@2J4k9A7a>x8Lmg5e;^e}LkylR| zOP?gf%w8f*(c&oa_qvjfWpNaET1tu$&^^_pA_%Lf70O+eR9wjh*Q2DZ=tV-*Fz&bA z2vT!~lH(%><8CrH`AymP>+#~MI&1R(1yn8)Novi1FV8@5K6FFEZ86sFJlTD_{N@+( zmi%qqz#dgTLEvqWGao?->3up{=$ZuZ-9Aj~-zH~EUfc8jYdyYTnZ;`I4z7PET*pm<$)cs-*;fe=>#2$6D(n?7R{sNu9;EltLw^htm_RQ zQkRtM8wKZ3kJj;U(TUgl{Y2{pTe1g@;8)Hjz-^j?!R{zYb*sBCPWeUn{Ad-8oSkBWA@CRa9W=fW;Xx^i)0gxB3%H6-N%c+b|mv)yYp}ZPc z%Hn)K@*021lrc@qwP^m%DTXkwRy{849VqA>D1leMQFkK<#~7Hj<}02$9_M@a#4{Ncw6tg*AuGb!<=- zydZiLw*nMRc=AUUqJ5m2{JT4-W=ncs*DyAxWr$g$8(zbhlS_Hx_vh#lYKfgmneT`s zCI9*#4f6$<#9#B@WpROTo9_Ruo9Ta-$N%G_{9h&Vlz3j-K>?(Yog1@HVlwef&`g>_ z7vTirloIjwBCRRQCjGhuH{9VRMSFi-stLNWLh+P}%ZnVT^{YH(LXd8qKlcpWR;ZQkPm=xjYu$1~>xk2H= z-<=hK2Lv(1J`pCkF>T(wFDIw&I!+EmO`Ld&IGaJ5^p(4dd^Emz&5%SFqONDbyC6G{ zS=xy#=Eg+?4#>OPd9R5z?xgpd1jxQe>4{MbZNee*Pq@`MyeCCb>1R%foR4J&Z>Z~4 zn~t_Q%F@h5$u!%HjSjkVl{1tC{#XTTMr@z?9Tpv|)*WVnRAn*c_^nFM7S(Kz5A*eA zEt|6Y=XJcnliE=)#0VT57z;B_=nfVnKa8!v!woXIz})YB)n_+P|Dk>c+?K=J|G}uL z5Kop}Qi6b}nSy}O{V&Cs|GuxE5zCn5bXfVN`$?zFBCsfQ2` z490_?7)OFk%wS*!RdhRF?rhP-T-3Du27MsV1d-6&EURp4S}kpKI^SDb)|WN4&=o$N zuDb4zrw`#tX?N28U2VEucL1}!p8oOazTC}IfaoW-ufl&B5?EdA*zR5&D8Gb%gk{Q= zzbYH$b^KutmFrvuKJbW4V=j81jvO~ffqm{qJ?G}bTub*NePJ+d%aipyM zMVWnyL?88qW!>HrCvU(^ky+{>g|2lBKI--V;_RJ*HH)Gw-ON0;{$ty=ZQHhO+qP}n zW**zNZQiW9)fG|w)ZH(8$Bx)5bi{CxW$zfK)}XF+`=R*aZ7a zOST(k`VEusyD&c**b|BQWPajd(~EIOfOp2#o|YTaye-_!%Eca+yR~D_VtfC1qb)b% zib)@=+pJh8a|DP6r^tr0d;9DdAEzW&%qhqfFXhtky*)Bx3uEUXWWt?v9OVa+c_BOx zipdB6%0Zr@H%(WdTe7^olsHxX#v$NI`Q06aS#_Q~N3gq+$)_39<~WksCmPdc?*u-v z_jq5|^}+JZx#`j4TwAsqv&=Oxa_4k^C$D*@sGU{*=Fh;V$^MZ`#w)djO+IR?!VSy$ zmdun6E7p-~(H-ZTcF=6A`PvrEH#X{yXl?Js{!822%WL=0(%0gqsHT(orw{87k8fY} z;+G!@kJuDkcqp8_qn{6sQ1^alnR{A>Xc@cI6aq(zjYZ6S7Y-`#@p0_^fz3CXZ3H2(|Lk(v#)6imiIP#oT_z6EqiP zi>IqQrAD`ZN<@g*7_M2lQ5?p7@YhriAJHVR_GuM3i_HtOFog>FYqBGPmPZ}oJPx!d z#(H-rP@ADVZCt;cBw#W^FOhX04)jps#ih2Fxnr_^V`F_>Pl^Hf)H#w?t{yhGjiq>M z109+kZHG4qy@(kU2zw8ty1xXwjj~cdZfzUEV*MEABcrg89N`8Bw_AIR&(an~M8)%k zZfqpmE|sLW)!EpIYH(%w6eg5&%3mp?hvCpx;P`lmR<2Mzh1g;YJx)rWu10oo5uIvi z3jTumiqosdWyqNjD3!OXp|E~wCrIdRFlurN8y5CKJq3GSckwZXAjX5q3op+MudAW_y8bEQ zxt-*>LFQ*!+c39Gmqm{aV&l^}`J>5pu>!_R!F+4{1aD7**G}QDX=zfWB zHLhvzQ9}@lbT`1~JYUj=W@%EsD~`;yIgPNbU%)V8UC&@g&3u5=tsJ~ohJ5*zhX75n z+Rn;ec!x#R(%cfeRR@`IAcu^%+Qf~&w*P13bzekzkB;VfJX@iA4i~!3mkFoXI5s1U z_AnY)(8!}ZMcDn$Vs`CX@y|of$WH_cQY?3eIU+HkIe5C_ySG}K)~IxaL0f4)$?)@J z!)L|zG2vRyjwy0E)V_QZo}TX53YH==wCG&h$Dl;tSdz#LXCiQE;go|PS?np9!q=XK zZ71)(FmG|87ge;nuIQZzhifan2By`J@Oq0`EI>M=0>Cu;IN9%Cp;JPw-4hL)zba&^ zUY$)tT8@x)0QUl#R1I2v!35lrS78(G1S~>2A;({thT^5!w#R| zG%*9cK76i+J5�&*upi zZ7z+S9|yoZ9z~Z%Q~;Hb+jJS)NDlYOeLm$5lk|icKZs?Y`quOSya_}SEIBu|)Ih%j zkrk;R2zNBJg5Ggq?6(k>X!^)p7TPy*ST|H(K=*RD-;7a?N|Scf%|NOxVcffCa$Y6d z#p%BwQzX9ghocL%iOoP$PlLa$2XuPTPwdfyR%mD*G^0bbrbvN&oGTYgsz4-- z+ls;^Z{~=^NV-PREn`5RCjaJZgcCf)%480)S@w7#x(ovh#U929T3J`e&WKA`d0979 z3582>t=@SrARMfoPAX=US)xHo7RhEluNOfsd^ErG@kYmrnnW&F8?><}_+d3#-LbE*M7Wo|;Pi!g8@AOOB z?5at`R!=k$wUDc{m3kE+%B|^ zJW(7o%U=Nr#`j$7(~enCMzk%-43FSL$2oVd!n@wY@uxp#oI7Lg1y4Zex#EY(p<~f6 z%aP#9O*zv+!IvJ*yG_-J7&dY$A<5i6Oor?vh`7CDrzC(e5iWaejNI5 z>BeZj7tb|o($y7QyEfnkXeXMNrBuAhRJ(2lfzu(4nDICCD9XVC+cNu!u(<=K99ad& zlCM$yWjx?ru%+~mLBH>3q2h~!qXC$xHWpB=S*4A?Z^NfU8m#{L>4y9S>Z`zVOcd(( zV{u68!$$j-J@_`Lb2u_cpWw>R2zUF+&q#O2mZwH=r-(?S^uM!a7BIp+eG7JDoqG#( zYn^+K^DexKXZudeo_#{OkelTFcmkI?9zu~saPU&|p+;4&tnsYhBd+VM`>Kxc)h~gV zUfg-9dTK%v_Uq|e(#;BhDVIU@li>T-ALuoAi0NlK?G<68A9T#dQ4a`rrB9ojT7guW z(kX$u22b(pvdION?h)#NH^n-Mrhp;bl_B%~U+6p~0dweTmM7eE&)MG;Qj&WSTEEIPci zC&D^&byve9Inl?*yb!eLAb~qK^rJ=J=ptF#z$@Ky7w%bN+*F z7l%DREP=TGQa@Uwr<(BCRT=IGy=0_2N{C!31hf@H<^}=o4irq$O;LmiEM%_MkRCkm ze0IrSVAG~tQV36UtWN+mwPB%Mg>O=YeBo4|lL7O`upcY)QxwTeY6kh_%z)8+y3lDk zR=zMXR=o7s{yAt`CeGU((!DRoaOUC?RQ9aUL8N+&?y*9b~P z{;J1Bn(4eid>6^tsgiH-JEL!vL@=RYddF%=x#KqS3VNhwJ7k1;97q>$b*`bhjvDRO z8KuIp=ob2oSt}U-P5|Ky9K>rX*v-eR4Y4o>B=00tnmU}M7bdFKfXP|zj_E7wnamq(dVXk4`qd@egLV2NxuD};qdx^ zfp(CP8j=}aU;z-JexnfogFD3im-KTAjZ63z5x=L?GwE{;?2o@J(_DFEZ5R|Co;U>& z02sZXC=zNepuRV;4Z1!8D%e0peQsD-$j)9j8d#+3tAX^X6Q~D1klq`-psa~KpEo9M zfEkeg%7&Www!LHvO6)Cjgg$wl`ov5zh5|=dI5PpW*Gx4fk)%S%Nnda|&p430rxZww z*somCBq0dpt=WxTEmFXU=QAngcYiRd>|@kgq_0`GCDmS)rvxfLYpH5!yoU6%Jk~zH z?w!xVYY{ftQTp5sXq(pxCI5T)V}O3Wh4IKjX+@`WZi*}t(IU^0C)uEeK4rZ+}*AQVbiYbU(?fkaPM(aj5X=x!3TgUOhXYi5;VPGYewGRM@8k&o{7z@&L*#vI6d z8&r6Y0tRO+LaU9|q%%CV%BrX19l=4w?Vz-PsA|fYy7wvRSYAZ%{UFRnrqt}tjxbHf zzM48cGgoXjb>DfT#c%s8aXA@I4ySU}al%z3rRBi>{T9}HtVF86>G~H>nB+-AQt70@ zi<7gfdM_h|kM58Wb~soA^X@&IFrx#NA2k=)F+4V2u@)9ob8zlnS2U7W?gA!H1Mj(T zf8o;Qt%bk_v7oKI_wojnF*FzCH=u%~X^z5*GK|s-lRn2w8J*g;itkxOdR49SLa=kf zWPfU354@NMG1>7%I}8wl4g}6fE+$qCJcCF%DvI}ZA{X}xG7Ymz%e zOe1O*RZQhcGY}ST5ADh}8fU(3OsT6I;(`wLQ^wvY;kJu{br5A37|hw_5JOxEJQsc2 zP3)x3t;mx?f_e~fn$>rE`oN5U#~N0gGC6gKRvmr!QC-~bV~4*Q4VztEv76!72agjS zL^knijLlll$k zWl&_6x@aEt>g5gvF9ChQO?)@4sz+)IbI}BDo-GB#=N_{@zylddv=@UD7^k{HD>>EUCOJrE(j)V|Z6QaIUpY+5u4)4nQfWB>{lSaC}E?)+! zA+&4S3S6hfkGzJ?oxlg2xx#vPc4Z*+dBlvvu+5V9FoUz$v!Ao`Lfveegc#e-s;W*> zAz0Dm%dm1KR>pM}VSiaFZ7Y=hOr290HckDC1`(O%eOe~U#+!R)eVNt}C$f*1H`upmVeDX}4M!Ly3 zySxD=@pH+~&x|s>Iu;p~xwp>KOL96qN-9l3Cz58UQmAuro+jmIw4Si^cBNT~@7d#y zCQk5J)Oes);oq<-j^Pq#@aQ^N`dom2VFLXD|L86j^-snD>)9gcUlMcYG=RKy0GBjwtb5CbUJ^q4i@)1xR5I z_G|QHdv!4#qj`X@a~`5z%<*eFHYOWwR5lAZ{2|C8Gf)LWB5T6_;Hy7YmH1HPWPZbJ zhUC-gA&nOB8_0;g0-Nq6IGPZY$!XIJ^x4DXx3B1!q28!rRVdNPK$x+;SZy0>UW)#q zHga~+9FO8*b8c5UV!W_Nm|V!B`U4OG4g}eI`eXM}=OKSR&&rO5N5?6uuONQotZ!(Sz!O0sVtq}>5#XEG+0t2{* z_VdVp$*{M{2P{WJKr$I7t^u0e;x(wmPeaOG{f_xcBEh5=Vc0aO>>8li5bFWE=nrQ@ zr48mRuTqjjrE4g;XI3E^UQmc)`wU2^sMo>y!rXLUEuHdMx8WUg!38=*xq)|6&`%~I zSoVKe>2oj@_C=>{MPXKd2j;;_qn(>PZzG0N^nMo=c+wDZc3T(1EWY;Dj z2T<~hJuXNhjBeV5TU`H6lxYQSg<{>Y&S%~#YEGC^324@aSe8R9RCguouV4bc0GFaP zgu@AS$K-m56Y#U@6XFfN!R zj?~W8!8&=IunJFaG%thys?E^P{8|UiKU)|&CurFDD2I5f4&W}QVuLnZvtXMtw+!3< zq_>H+i^KKlITv*!>arOM+5t7S@r9VJuxSBp)F>P^Sq&DkYS1E-pj$5I)Nj<1YAY<}WdAmX6EW}&xH z4M{KzS0L2sSHvFPzV|QV`#AAIxy2+7@jy(GbS9-VQ8oQGwD5Y^eLx$+)?N@zzIyF! zR_PFR^sEqRW7c3GMCqz^d>j*!SH@=6<(dSh-d5cJ&gxy`FV4}$H*6#NJ9Qxr-OAa* z0~*0oXKp!PEEOBF!Q1^T!@3B;$z04RPsEMV*%NLUpj~yqI<7hk4Ff9;14|6jwK56h zO&&%fhi$5fDQy&f^#jvm-+9ug{uHQx;Xj=vR@jUNmX<4EIkzt##xoxg7t`Kt0b9$4o>A!+;LO8Eu!8EP!^mzBkO)H^hE;#(tWT?SlBWf5NQY z*WAM%w}KzSGS10{^=z}|lt^D}n9OSZPjt1*P<;0Y*NBF56uR+Y>b2zl$+w=qSxCEl zh%q4-ueL{5a|x1m-lQ~{ZlQNh88vAOu{TEQ&)PR^7EL6y{@mQlg5WSVSf7Z~Vxc*O(JsN2AVE>?q z8XEg5fhF2bNrzpkiRRrb(oEr)3YS+)IThr#v>gjQaTF+oTEd+pq0For8tRZ zboi-MYjU+U35RAFdlM?Q9zH`CIcf&|t#h)8-X%Iz9M@sm+*oNH``BeWo!?aJZkp+S z+URGHA(H{7-xikU2r`L5$83uIMk0faCBcD3T%WNxTB{(vjVQy2wX{&_bc%g-RbA?# zAyaxvm?Tg_9Y^>foSeED2yUTy|UAu#5eelxIr$Pz1<&T74(xxB#jpiACovj*8c znVC8prBpexKvW$pA(p;UL7twTX1{hEF=L(zG^G(@Q0FANf}Ias(-ss*i(tly3%^AF zX1=SRq30(5od;pg(@3*$l}}jZ$(2C zJdr*Z12cqyG4_CrdZ>`bExAdKxf31mgEe8gcpx1-Mlo>*kV1H^VHDTGRuawCm1P_FfW2kXO24roA)EMlq1(WQWA z`V-N>`#*aMX>lVK;r@;>l}oO01J}yxRc$NT^iZ;k;Hhk}HEnUSNCQWRoP2y+cJMeE zbIOte8wugS)9x}BWa++*LI^kbyRC3rfe(FX=UhR|C^$gftxmdz9IJq(;MOevlArcg zT_@DMCB!97g*H2mP}I3Tw$%_&p()a({Cq1~148B(nfFWn+l7EuFC6>jZ>cTcUxaId za?`MVTrTh_b)oq=*ul=1_N!wadPtst=}{jfPS~l-pmcU?foJsK8WZ*V4yk*C%D<7- z4g2U*Pfbmih%k!X_r(|z&RI&{OI2H2#X)+o4HU`^=W;)9h!1iMr>3-c!?Xm$yu*r~ z5DaUSXyBiSBlWudfM<+J6I(SIhnVm$EU4$Sj!wxYwyat{=S%H*GDZoE{=j=J&ND6i znxg(~0cB52r{~U|Bqp=M%GD(aI$e;$I(Fvqtn5%CT_yGdN>BdMEE)j=KCO*%G)I5= zg~POYxX}1C1mr>Bw5Un?+l=6}-=4VXkG~ntY{!ax^L~H93m*^~EsmPyeFyH}*-FLm z3JN+ylGM@CNB{gucU=br%PagM)65|7ToE&oVNPdPM(Kw6Cz)Efsu=8oIA?xlp6{-0 zv_uZCR6?PjWi#GCnhxZ)!&k7EXVvne%Sq=#X1WH=zCba7mC_>-=$U4*%}61#-Cr}E z$gE*y+~6KpiBbk>W}-004wjV5j2$Qrdop(Q^TDFo@q2qxl^p_BL{W9aX?x`x+Yi+L zh5JYFRSs=1R5QrF>Thp-iW7Xahe{0qfpoefs{-UPzqa7k!PsiN3{+@sQ@*VLv!;k4 zfGPu;ED}Z9LUI&8M!WRKfy}?MP>%=~rr0Yg9XeJ>niQDr+}^(`9^Q7Gs!JTm2avC8_QRB17^i} z@JV|&=LqevZwSZucc`t}it{_U!CSQFo(ZF|^Cpz4ctxka@BqzGih}%_4;k6Ni6U8Y zfe(?DvmLbE-ZkfURLDy!kh2nCvBCp<;oqNgz_%gt9cW~fl&rR7g^nT!Y*m~=qZ|k(2ldl|ntL*BnALq3wi`Q2YOhvq2XPBOdkHy#mf3o@IatEkjssh_Op9|TJ1LKQPu`ozFM^< z&jfS6akXX6gnE1Zz8tOpcq3pNOYNidBJY|`?f>UF-!-V(cjJ!T6=`^L7k!JrGlccY zl`@{0HqF}Tsk8k85pO>Yhu1|1WeGAVrNsR)w*5)mM2+2 zpSDDB{@`XT0c!HDyy;60yd=4fpEMW$c&}FSd1nXdATA4Ibs*MRCyHaAB1yfi)2zs8ZK` z2`glm73Bpy5;Ba@$;dp-yA@2dTEyFlXh54V z4DDNYkr(AmRKFAMSjT{Sl*$L%3vhTvj+?1%QoE18^T8*L3A<4{R|^RpV`iDAV`*^( ztmIV3G|w#G0Vno zFK}<&cAISml~vJIxTIHDxYEMN56K10-5M~_IoF}Eq=kr-(0{7f-EQC|@4({tfI%O+ z3gGubNxZu1{n-Ia{_K>Sx)CmX;8q)WDcm~?X#V^#bGr_W{`{?Yn^HFBuiuApg|Cis z&WL~HSXLrHnI$OwxVy^z`ogUVdm}Zn7dkz%=Q$RL9b#=tr?dWiI($zg1p2BE4IHC~Hydch1v>avNSA^e zdiMz|bs$>+M`G*K8hqRKO0CrH+n%2DN{kah7A%Ywp^^ z$LG{LuO{IVa*FR5XoGV0)=%#i$Ito+4>Kirn3Md4pIaI=V|RHSn^6hG5X=8pkri4y zPM%a3izx~*(8-KXJj1kG|9}?%j#iN42RUlDcEITyWAdnWP~jVt>9$qgWIM?Dlls$zkl=%-y{YTM;TId|bUubNl!oL9`#&Yxe(Zha6eg{x}hX*oDm!$pDe~w}p|7e#G zYnC-hw!$Zx&1?rUeftmRoE<-Rn9p2~LQm*D&^SXeA{-saCF#P6z6l4$m~JHVyCq%OZ}O29o5C3OphNPkVWF>?9&g00~PZ$5}| zZfP%7qOlR80ZD14A?B7y*;O(JR<1c1Qp6QoiHb2Hd(ksa8Hy)uz*X^*K79Yt^yaC0TEf^Rl$1dza+dS zyzyGT{@tq=G6TP!oc8fS;ZJte`@WdS+e{Jrh2gbE|9wPhSM*uS?Si83S;J~egGE=G zr`9p-vxW$H4( zpl%36itk=SS<}sdS@R0E@*!wwC2a6SSmQ)k>rBAAxDLLowThpT6>`a?Zm3O+ZNiL(sBZ%19wivXwa++FLY>jv{_sv-hvXKew0 z+HEgEyhKUz$hq-ff_-xq7l->y>mfh$&&8sk7Fc;1=m?tm9Qth+5x9#IiYLhh4YH4r zMg%)(GzZi;WWPY#uK&j~8$GvIDdSPOK{u01ws@f5$R05~hJ?j-cgJ?s7Wq0=?hQRx z81aR_Sg?lXp=%X}cQ{K@B%ZgBOySuFC--9l%KnaN{|y?luaQoO3(RmhmioJ41&piV z#j=AnB4RLZ(X1R{u7K?RUyHyW?T2Dulr8K^IX81Dh7*=n{{*!dWb4*}wQK*4m__95 z8F{9*?kq$#T91Qe!M-QsBZL0sshezm>-NH?j}CwMVMJZ!D@5h5#hC33)0MQLh6`(# zbBVbvCfg<?;jJeu_ibon+`XvbL#EWP zpVYcH>H7y(3MLWWU zmOH36`7Y?KedO21S7t9fAD|zUUgN}J%_{Y-sT#md-9}Kn{gm+EE<}c6zoI%kzyy3s z&G*zzUHwZ-*Rw;tZG-FVjl=6NA2Qx=q3%yzrC}oQ&NT# zeiO8Re0?$c(+vmE7FKa(`Yl&^L6RGmwTimlaOLTKX0|V(C7C#V1sWf05E~EVO-2nZ zT|$U6vU}Ilu))4c!H%6n>fQ3>z5e!%=63GUa^G(E&lldV1Z~QE0x{j;SDcIft!3l_ zf15cL{Ue!Vk5f@}rtijEVo%1Q9?X5qZ*com4)QLypz=NZtf*wVzfWsL7E_`Z)s0F` zS*N6|vPv@nxpn)+lY~q%JPs+m+Rd9m@*`dRS0*_e^M&8Hm73NnV9Lau{}>S#z!eHK zPrr-1XV>o}N-^o&re7`?3JNyu>ZaF72-U*Y(0?=5oP=gl-#d;th$0!@|BkQMG-RhU zj~H0$8ouYvDC(_zRCb{hb1pR|UpXCD7}IoErZnqVfwg2bc{Ykj(HG-|c7_H#9Mey? zBmZjxTQKfjziyd+Godym{q0!!qDf}j?#KjX80S5D29kHJlfN-NU<|1|Di+ptRA3tj&57Te7MBKw|P((aP zDFZ~8)+)$w*Hz@Rx+}?Ij!er6+E#g|GKcmYK>e11e!PIUd5P><`}^=dpW?NiYk$E0 z=LG7q5UOtBKe*@5Ke*@rDe~;Usfqs!?U}8pDT~Ap_%5N|Y5|mm1%yR3ILOXgvELEX**9D0k)cya@WtLF8xnNhq_s7c!6j-dw_=?Wx~yWg<&aU* ztxea3T}q)R(r1O}*p?{-X_}BG$`S6_HbeJ$Q=I75H;Ch)wp%y0hY(5(JAs8mIE5$w zQWSG7KDw3o`Jc}KieYq6IwHpw>o#;rOO|L7!3yoM3|@czcO`Rl6B%S*udq4pDT}+O zg+xWoH$~FCgEJa(3mawf6i0^~{p(%_@EA>I>#2KMgslo8lWI9R33OiLR4s)F1`zUK zWOe1-xiJ%(-U@}ga}OQ)1|~{Xs`({Pf)g^Hgk;I!MKbPK9uFES=AoG^%AwiV#vvf1 zZ9FN+*ISs&Q_+1Wf!sINPvrQqby1<5cNU43N^6jYxt8d7#5HJliFQzkmJDs3%IXHa~*-^=p>!*DuEZi*e!qWQG3M%&;1S z+kasGY*XA5|4y(-BjM#sNoJ5FGMP)7=abK}m|rA0)t4s$nq?AKj82VA($bq2LF|A) zl7~SeF>RFcEi}b7$~EKxTJWw$2*b#~kzGNAejIl)Q~x>zBqrQ=zHGPOWc}oP<)qqn z+pVPjrc&VMVcO-HxiiiC8HXQWHGWNj-eI}L#)aM_<-Jbb>tx{CJ-Fpo_wI$}?SnIZ zB1HGO9A-)PB>;vSKQHCs3JQhcB6uhS^)cC{r}eSfMZJHv$Mp%^%90}docjZ~! zgV_7(hLhdbN5^^ECtq{d2;m*O6^%cYW#Cc_@%da6Mfg?_ng1}psTH_yWyo>qMfH8z z$JO~%Z22ZO`bk-8)Zrp6<-QsAHF^L6`gx*wO;Ql%p<4J;W`Hh1)i)N6 z9Qx=%znOwH>1h$nfxav`Y7 zUqvZ8ghTr`qzM^HW5U*)9fff*K;mU6agIM2q#Niiep-l)!+lgh=EknszWiN54(Byx%EeJ~-qhJGbkpq9jK3!NO=LZoaw%NH26-)?? zi(Ab`XKcwg9|-dH>nU}zhC96aB#MU1vN8A1rk3T1l3Nm%ch4tzKu*cg42+q~gTY>o zLm`ZW2SVn|oD{hb3FTSDg>^Z&>MXt4@~uZG3{lb6^~ekZpHr64f_i6yORu8$?8ZgN zZOo0Gk{22>w;t8h(ww(G;h|FDj0vg8H1 z?J@Q5{{E`dm?Oy~VQ45S7JXz|9!m7qhcI+BoA<NvPN%v($yfX@F*to^rQB7d;AjPDx)r#+9LT&HwDRlaU=J=3Ai{Rd#P zRds%e?eH5i*>c|aqMim5M%3}ZwXkF{Tt%wp?@Q)GLNMzzNkBOpeDi>~wF?3ncI#F_ zpo1k_J2lPSO?c6AFrmDNsje3jyIytpDV2j^vEZ$=R!D6|*scOnCpCIwW>W}Fs{+w*OR zn47jFNLm$7t~iJAHi{R~&#e@xQ#ER4HSCNF za2MUJTuW6Wf+DAOKh2RHka7`Nv6A+n+9rmMRxS52x}@`YS}|%dqJ_+z6}9tJ$N(T3 zM$HKrEgU{wqSXv{2%8oaHqdp7St&%)P;32CABg+djqc96Wu{Ld)cMKXQ5gaVtIs6W z@vk-$!HEo{IxY1#el?ieYO_nW`pt~Z{~9)0J5h6j}l+!M1SFTFCsXOlo?jewZU{YWtL z$VWqkQ-cl_$=T7ugA3oGD0(cJ@U6v94>>X|KCYo)hWEuQIkOr{PWRoQYNlF!6+%IE zlf*x|W+Y18`NnOyJ=~2(+^5`!#}4pFt&Ya8B!h_KI3b}lJ9XpZvVF29Qmy7Cga+ps zUW_8gU6|KIEj834ov28!kdG?QTnir2Y87c;m8jOsn&`ny6K_lMBG21FZ@!A;|a zqAMAef#ZlAp;ZJmah%qo2mZwIuua)RP_X5Q*zu0j11*&eODz)miA)Zkfg7N3*n^@t zmPVe}_F+}^r=t<8&Z0nc){Fie*i@@1pCyxN7O5JP7+l|H*eALB*+#Ilf{oG};u3cw zHET_8#wI-Vx6m)P+^K%~xUEb~<4ga$c%R!r5<}W0wL_HNN1x8}|Mf>fGb7fAtGd-dz&W+e-ZLjDKB;Syk zJUyj4DAQCHvK@f`868Fe`)gyVQtqrPFjkB;GnbIb(nYv|oS{P9ujzDo`@TE)yh8s( zF)g5j-?rl?FA#}>Yj?-}e&nv+hOFLJOh%!L|7it#-)7Tt)d5L!Vx*;tU&HCxQFBoe zz+I#%IKJdGp`j2gwjvqh>?A|WPE%yLoSSq(M5{aGe5vx#X5%vAEWKc_EnIV5L$yGuzXO?<%z zWctx(avk8lYfSQLHV=u>k|10YV|)!T@dRr8hcTsAM5oY3W$vKNx#loI*$%$I9#tAR zScoBCAau3ui;memdGLzgK*|~|V3lw8!k`sVMtYy*_}Vzw_q0QTs$TWWC4f~SH6K#i z??{+wmusP3P;a4f)&p!`a2Q3qAQpz9WR4MY#+0QD)3kj`bg|bK1;N3l1Q)Oh{EgMTDI@x(VUv=nniC(i)BJl zeQ3{_k>`nha8H=gedDrC-CoaI4Cb8Ufz^4${?THFqwo*eO3gvXgA{uG<-<)htZ z1sO$d$0AgO?;%L7BR$nEL)GU0A?Q|1S~Ji7Q)t2t%+!nbt zo>~XtYDn2Lo^ycnzNd4%SuxPNB*j%J(+_nH{i#YV7m>T6vsCScgkR*rfIpPn ze{gU>TI4e*PlYqO#$I1Ru~!WKruc)@F^AZenLTl# zD3h+We5}h5Q~a@em%Fgx0ywF$?L}Q0t*hGEaRyAp?sgq8eZGCjk+1y9g&L_RSiR25 zRX$&WPAb<(tAJ%@>X&k+I4%Qist}=4X|$_>G+X=gTwY@}aVxH!VzC+(&K}Xk?nTCu zJ1Pa#y41F^#lZ8iRpeW22)lq_dE~Eyq9P7STUnp^yNXm8DsDXuG9nJxmw)XK$j;)f%KKh zmy5hdi2$;}ld4eb(c(`jP|9W$9$r5a>NmYz;|h3nkSNv2QH`59LM`G_jY|d?Edc_c zIRmgJDaG7t@GS2k9m4*aGtxTRXoOsy`^*XP#pp@b7}HJ;l)KpT#By!{D3@-|WA&|j z7y709x~WiY6j8Lgp;%L1bSS2l%r$kgM;>-0i`z%G_zz&E^f$GqyPblFX;C9x#SLke z;p;<6`x0X5```aao`g#DT-gNK@SETHx76Y_<*0YX z1RHNvH@&mb9NrIT?wvHGPHb<;oaV?Jl*@@nsL^w8 zM^rwq=)!+yW_@5~Pn#O8i_hK76yg+FW7E0bne4Br_5P;TiakJXfA+RS@o0?niN&;+ z#Bw5!=w?|KZufV!MhQ7H@Y)()-PN1K`%!Uk!5JA|*HkZQy*PhTdIeSa$ZWtfmHO5w z$6se{0)E*?#CCxE`cxBae)0XESz{yHIF`#lw~32?ZWC<(w^^gCtBtY4f2EEp+Kvk% z0PcotvXrACHeza`FPhy|>Ht17!Ff5-pqAYrX#LYBTT9Q;u+;?7l;1yqR~Tsvdm-je#yRITq~%U%~gxq8mo zZs{$L8ZM=Vov;w8vC*>|(Fb7+?IxTpy*2piYF>Hx&1cKywj~Cf4y79v5;r|%EN6dJ zH#5w5;B%@k$I|a{*AII*a^5>-vCiT-HsX66R0^}EP(%_-03ha9wCS8>1uNH-?d%ww zJ|f8KEeI0lsr0&PTv}sOg42mfGhSpI^`e6c`chHDx~mG`zxps3b0CGfzk2~?L04}D zExpw1^4L+;rOa#3gE?7uMibstp=>4U_gi}{+}KOiLZgQ;Tf*y^yW!l3z+p6`y+Qc|(e2FB4!`DX;JqfS?F!+>lT!D+6rQ1-K|gDCrINI zg#QczS;nw1&fEdKtEhG!np)xy!P97a{8hXnhh}W!yn+FtNLVsG0pA3_)OI~HBK?{2 z8Pfd2;mp(Z*?0y!p-3|FGXUPk^5v5O0e9T10Oyb9feP}) zDWsgy>Pn_%;|P5~h!mErPABUTI&W1wH`?XmCbB0W0OzNf9X*b0up>;!kjE?Dp-=9s zC6qG_Z89;aMhD140=&X&34|H`Xp*Jq5Pm_Yx6-AJPwFDHrT57OS{|Ecb){?$JJ0epWM+FH}v>04PFJDBQQ8#~e(I9pnpJJCA*(}=s%+8S6G8#>Yc zcimIT-R{3_jj|P_W&aThyfw!|!3$o+3s~VI!a<@)qwo=>Gn8oYUaZ&p1Ueuf^!{p+qa+CY;)1lrwLFL@g+;GbJ%=jzutOEH zwtiE$yp;{d0fY8Pn7}V9Fglem75@_DWijy-d61Z)KG6VI=lTa)!cXDvvoyf08Y!B^ z0H|20Ov;fGnYu9G%Gf2eiz8RazaK=z?aO4?4SqSc>hHt&|l(f(JQ9LYoRla|J?QMUL#X) zwi{#oN+dC^lM7F7BcLOiJ-INM>9yHA-DQ|~FP+t~=y)45lb%q(+J!Q}(?G-?Z>PKp z)|dEelVt430~2JOC~MavemC`$L)j(`i_3`9s6_qLwrICDj`N<`t7$KU6u86&+p(VihyP`#Z03=EL9J&xOCUb>uzs*)-px}98Yxy_z z94W5X|7csRjSt&3bgpHu*&b(RXRrMyOalh%s6M2d>bbFu&ZtIvC)x&0!*n@~*KzCM zTkb~0{{l|4q&=dV;KUoWnh-1?->ALEElbuK;j!%sL7}B+u$u=?%ULHtgULYI_GudVL~crDn32tK_mjiIDn z4Xg@WCmAZAXI{z$BDUJOk{3!deSfrfyom0q1xv=kCP#yh*yv@MlVqxmdmhgfM0DhO z|7{v&OCt31>1mvm}hsW(b!~3as_Y)`MZD^9@6Nl>+4o^%4*mv zKD_mjjud;{hS%?X>Xr@shr_cGa6+dh$=qUa7d$5#aoV;06<6bVboIdJ<-s`Y^EWOd zvB331HPCyJM`Cq+4-33MQm+AWu@f$c?cL#=eZ*-xrT0Y88jLr^p{kW=x9C=Zmy}dO zrJpTHer|!=i^2?|2WP(yH4?CqkJ~&U{017BUd}2Eh#Qh^W5(h=EyKf?+}Ps|2t<6b zbipurGMOXgu+Uy;me|l!sM@5mZ3Xz1n;^=FVi zeRsgWJ7_=eA1VJgTC@It(R%;DkcWaS*^t8kHqLy$&;zKA{)^Vl|KgwLF125*sp)mc-(|_%TT&F`27L*vMFDj95 zI}g(zslMG9_Qyf*2xrDok z&HQMuvN)Rf9q78=7~9Fxz3Tp-j4|6kP?MDhW<>NJ z3K9iXd>@R#ffyPDi`4zg7_WhT8RLn00RuN_SB#{bqp`sN{$2u;%xWE2a*KuOhpEnA z&c%NN&5~nMAB>yKRrZ3hu)2u804MlW(rPfL?a0wrzo|grHK5&w-Y{a+BBjr~yjy>? zrH~%KL{}aZZ`%oqvN3UBiw>cXZ$^+9dps5hR&(Q7bk^A&6IzH)JNm8?%8eHZwv}9{ zf*mi$#8~ufC`YrL9a+xU<<$P1%4{=DR^(UtbS$8XfkB&E)%!#!dR@tAv~h{Wey}T2 z`3>bn$LSQzt^1%nmIHwZyW9sIJRBB7`fy0$gZ*pP{($i>H5$ck%gr9rZFL)!*xZ^z zh{yP|M3OY3ODIzsr=x~~gM3Aqdbe73U}WQOX^oyx7V8s#fkuP_F+TSN+Hvg2@a7k2 z@v}mI2W|ZeG{4$FGWPlZ2^#B<&+Y#k)!6?5n)F|w{b|2L7DUZ?X~il?ZT-oJ|2NQ# zAAud|r9oh%|0ifIvfK+_9#qck_3`5tDmVCpCb>3g*cF=_w#-VseGg9fV-Ww&%+^Ea zX-e(1qh7D2Qq&rW^OAuiy__5qx|w?DzAYR!v_Zi8JoMNj0@ZO5}PSA_>R>)O+pnCsd-~ju&%yG|2Fc<1v{iq|Nlfaj(?)|Pu;VB za16v)hiYW#&nS{FnQ#Vn*iDN=kw|9|F+Ou=y#F^zJgr6-oUk=@HR;2=b8#{0oH;Xw|q<2%bTWnzuRdC6#QvxWgnI`KGk zU~L$YJ7E*^Wgzjc9s#@Me;LR;oPQWd{4WDJT68oT#&@(W0t&*1lxI6LY{WiK{Cj`K z#UdsU<<}3cO^*2DGFsEvc2Y>FJ zTVsh#2qZX@o^Nny!4aVDjF_LMCJwy}vYX+cN6h<;0?Tl5l6FOO&!q!s{sY zbu`P<(b3deq*L2{+mI4*K*mZ}s)yz^NKv?T;X=5j5>CAES|U(5Fy~|z7D5vak+jw$ zE0i^?S|4y%C7m*Ai+<=9`tM34_$9Xk7%(IbiK7-$aGl`2Jae!iozA!s4i(@_RlL+MH zLylWYgAMVq9y$}1qg}#+q;J-GXoX8;x0W5*e<>fE{9z!P7lm( zeNI^X^TN5prqY-70E`wl6%hJXo)Hj+JTL_8&ba#7EM=5q(0N0FZl04hY3KKP;QQL`NaWSe5Fxs8Zz;?T59|nbE&a`FF?$kU!bVAijM=NB;jmrSD&21^)$@x;p?z z9PKlz`bSMmSUs&Ao?&hnRJ=?98K2{-Y~`wBzDRSxiuiI~p_RLlU1xk`H0~xln3j1S z?oqdP?(CptWnn%k?vZ(0-sba08O0VRP3oe>Dv$9mfXA)YTcx=_~xZ@(`v6)`n`6ICE@@gL(-L z7KTz2byFDB41C1@q>tdB+ovYNPntcq@1feYLI%Haf!gUc@&a@s?F_cO+}K=|U)v}2 zOqlJU+<1dCjE2b!k3MR8@Yx+=VTba5$58{4j+KPZV%2P23*_I2;O!3t&V;V7|Ar%hte{Wpbv=WDau(cNX||RD-X&{ zOCuDG^58Q`4|sh?I=~Gumm_ajYuo1;@DOj;V5p+-CYu9a${aflGK{VzOZL4i^OrM* z9*&GVuO7Ja-gNX?tq8&NwPdXZbFoCy8ZjEH<7lfr0DP6YWG+_`#ki_d=n(kV&~w|^ z^Jicgm8NDhITpMoisJSKO6+W#0&G-fN(KJb`626=fYmVSGv)dnl=esx*<|g2JnH`(e z#GnJKCO2v06rLtxrI~q?p&qI$S3&_JF2ShhT(^(XnpJi>l;l1Feg8?QYhuEqEc3j$ zL9uAfn8E}ulRZ9Of4$KLj&%>Hi^THDnHql~%+_DMZB!kTI1tA@8)4E7)i&;gBsbm+ zM*;RBIw*NbgT+$@_L&CrCEQK<%CzWBFmT+nGxy2tU556VhR;FI4&8DsWR+j* zps-L}`kim7owu1H6PTix!s;S+y3-7{4R==Eo=An!Sq-Cjf+orEiq5e1~?7Q33na+PdW` zW)&5gL~-@?SVkuF1kLi2LF<}Z9~bIMRaOR~>bc&sP3>fMTzO3%A?cv3_XTRpZPKMC zk9v<%kIF$6Qh`=H2Bp5Vp1z2ndyLjFRm}~>zxtBEX9Fr?Wld*hofKzqCWHp7)HvJq zT4;RU?6fai>>ZPMuE&p+DAI-Y)}u61m+pm!*ZePoB>#{(qu+~SyRFok$)Z1P3taCS zyb{!Px1_mI{5&m{9?{{tnukikcPcxcmrTJwLB-!TwUNqNE^b+OM!9ZySe0Arw9vv) zJx}P9?Oa&sM1o^*2=AVpvxHInlYqXf8TbtCb<&q}fgT0)mLYOyVXX68u77`X*lI6E zM`#!N{lo@r38$WAJbHDW@K<$Sobcq=NY>uRxaKJn$hhPPMB=IL2=h>uH+rG=+Q1c& zX^^J`=g3(2+0P=rSGPsG1M%Gh%+WQuJ?1O)8r}o0teQ<$pA|57E+n)nD~Uu3{yhG> z@7QYT_KoA9Jr(|YEYqzS&#{dmzE;{I2O!jJF>4taxPC?Vza7v|tg{w{EHec=eZeM; zrI#{ z&}2(D3dqWW@p|&;^kWe1L~7xDT`LHb;?}eS!(kD<^+>WxIv)p!LCK<7FD9OQ^A%~X zsSGnquj&X!6!T16t7lj7ltki4tt$1Y$y&gHCZ14jj01F`@}T?Ek&!@)WZiwR*pq9! z{7Z{BNy5kBqdOY{pP;!|ikLAW!4v6B)Ui6GSC#v8Wq-j#3kv>H{2Gj^2lYmMx|FD) z02@9IR8$lB2YJ6QIAm|76UJPLbqAQOBHb5ATZOjvXKXnX%xbmeKJdCKtwbfSNN7tA zB;$c4R5mntBNKe`clxPiWm&!cJW-Np5xN700p3-~1mZ|>7RfZBwd_J;i;hS^dNPW` zLCpNpj!4hXH;$OJmFTr^s?;^UVCS<^svDwkzYv=;B(*eG#S~%oY|HoGD5~Z2AwGMj zUfAK8;tg#iYVo;xeQ?{fqz8BW*%c?TP-=1PhP6X|JF5Eb>B%5l4{}yT%d?bxskcoR zxNm{;Lnuu=-K!tM6Kmlw?JX9I3{q@eEFz@Y+noc1|9gdW*w>6+6k20$h%fJNfb^eb z{gmwu+-zk`TurS1?*50=*R*j~&_3aiC%=RHgUR_{>R+_NLmDj&0|Jm?2yvV03z>k` z9kg8#19(hR6`Q`AfMwTZFRrw|;*Qpw`q=DYZ?h?X_`NSzoJ_$9YZ+F3O1on` zuQQL_l09eIQhYz3x1ND;NBA@Lf{q7p9lzYO&XWNo7lL{!^GrbB05C#v40uFHXXwnU zg1}seT4JjD@r)=z^*$Iu@(m{eUkp9Nr6_(k#hx*#w}Xse!*S^>@%wv zK(*h3%r}d_n{W>n#z(oo1@MQ>se2&vT8d*L@mdlPb#l#o0x|hJFVLX)U7|n6{STCr z&v@nvX=G?CSuSf*E9Q)hSmG&wBpcbDD7gvU-+f7A7MjyVkQ&@<{Qlm9Qlq{)U0TrU zI6RpaO!*=2aH+ynMtd>R0H}k#*BDv3%vgx9wb|G_o{yaAR)H!#6vo^EJxzfo8U4Hb zkT43$oCZr`cqEKDY?NMTyh4dCELO0KD!Y@xMCO8%gOwV}Y)_J%rZz<@oi<6zyVkN4 z`a`7}%v|ycG>k`GsdlmO%}8}=gypQll#T)=+9**)y4sklKt>eOKpZN9Y>1&Ul4$R2 zQHZqCLcV2UQ~pooE^h>=J-Cf-9`prST3y}LIcQ3kVf}0Ci^0sFCmz>uW!HO^zm3$? zSc{kZr^R%nbrZf(q#|uCN*4g@Rv6L0e&cqjc_OBKmQ9E#n&2vG)0}fE)}q1~-NNwv z?4fHip|@K5eVXZ62^!e!Ji3Om9a*%OsybRV$J$VslI$-j{9_)P&0Kk#;>20GH!n+n z?XHqqe`dLL5jipbs{C^AN0Wf)V4Df?)NQfByq_bW=Kbj z8kNbKO4)da*-6bnEGKJ828*4MDxc^8eLJo$60I3E#UY+{%XHmBw~A?g!6mj7acoMf zx5w$>y8akzxpN>L;>^4}xK5?w8DZHo=5e}y`>k@Nt2l*z2Giq7_nKe7sH2i4QduP$ zCkFlpujT-g#T&Qhn`N|W|F$$2k#LhNoptF@yG!>kf%xr%$8=(X?cS%yJo6&tG3B`? zCCVGo!*7rrIxRyhZKJL$C?w~6z_<-G!pddtxZbhLqe<@eo;zb^UB%Q2up_QoEYixw z-KA*ZIuVD*T%pQEz{4IbZPUxwfEFn>BL!120ysYp#3o*#zU`_EjjToGJFev&wk32y znD3k^2cWl^4SH76cq!3?6EvR?QaV#yEhgtUd_7O%JrOcaEI4t? z(X>Tlb1q~Qdyf(K4FGxUFV|q{nmy9h<+UukL$X$b6My^aj3`lU-VeMc@Cx~PKO3gq zU@h-D{7!kka-lz3%2tDa@U$Ga`+1)m4nnO*bA`D&nQ^{)iZZbyLE{f^|$aXB$?!{5V#^IBTFZ@7|i%i@i>-RusjQGHFGjf5oozRTl{ zSD5D84IPNavKe#&?mgF$JWQ6cB6O$dwU|Ue#FMcOWT%f7<+j&lfK#UWf*Doc5#1&? z`zT5*+zE^zlHLLG@n%~<$xsW+ID7OX81>XrN6aa=!UC&1Lv@ii5awZSRURN-3j+cG z7QaRHZ!SVHH)bKZV7UoL*{f5>ZC}xKP{QSulSYYW`!g~&A^ElV&VAmnE4vq3t6C8L zfk4yG3-1rNxh%xCUt@Ul2H*nZY0Btr*>nOSKdW<9e$2qv12?jqpI5?Qd|C{l*dfl^ z+kaV?rLl$3rl!<)fuKujlZ5|-tc_Sf@C^sC%dTJicu4iaqr!4s@+mFd*sYZes~ZW9 z76mx&SK2{-_n{bjYc%$$p5G_7YgPUMB-Tw;?mgFf8UU}VV%2*p`Obq)8?Oq=xfc6W zpLMn`U4WFO*?BzM>0+`ZZjES=jePJ}mFLeBnbF=`&?({jjDU;cr?B4p+X^0F;SV_v z8qcrma(#I)Pj!Ki%QEfLX3e**^U7@2WuOd~+B*M|j}WRC1+b76jhWTTuiYxI?}rY) zVB*UfAZ+KQ8iKQ*d(hFU_Fhq}<_&TZz#rB^o}LSyB1ApyNi1#l0+I<$W{E672ox6m zm@4zgCL(QMd!|i@9hV+)bt%(plFsvG-pJrjd#daHD`jNZn+rSvmAo^5{w;|0<5OC( z=_~z?_7xG~`w!Ca?xIF^wstn|@_)pZV+O_NLE!7#NwcCmq*9G%*v#ml zBQ|Ip8@KU_&ri*Ki9!L7LmyvNA;;0go$3?LsYN6+!l-6SBj-s-9$LBQq}5PVO#OYl zM(@Z&`V+CTDfzdOgH;h};1Y3htDJ@n@#N=02(h?bZgsI0$CA*-7CM*h^XAL6a1wL} z!M|oRhezxvPQPA;#aCWT{(t{M{t7?1E1NjFnm7s?8QHn~W94v_imctjSGB@ zY8qY-djs>^MNUum=Qn$V7FHU4Sz$OU7o9;;xD*G`Ayu>$Ov{)87G!xWsw&r*JWEqM zj)8c*qD?GPkZiXPL7BMXEHIzV`+JG234PVhh~S6n3~vc}o@|19FLua!MJmjPE|#M< zthWI|@=0m#QRIUz0&*UNk3fW|zSC0*d|=`PKSuuW8*9M0BpxS z1@zz}wGF<97;oaIh1nYs{2~MKAs2849*Ze$mlEQVJg-et0E;g?_|$}$d#|2|qYiaK zZpYmPmkLd}#)<<74i%fr<{)iw*C!ie@Z0^7A%MZ|9`+JTrN1jmXn-bC*n`-;QoDGA z-DagB`+3Y|Qys#4X8l_8?c>LSvmW=4VD1JwLncC5pYt3DdNUHxv7qr4NqM772A&Mc zbV`@vP=t+#wx#bm(5UWBg@as|u=OO;G}hihcWJm_*i}tL0QeH~rIBy-(y_p{yVjE1 zlw)TYD&2Xnzvy4j2%KGH>?G{k3i(MY5}Vc@)-i^E);B*)E6dEQLBCT?$J)e`Z*a@{ z#ur;R)V<*R>!G3wa$~solCY9r0W6;X^`ZK^jIC0CQ^y%W`-4uaMM#ej;D8#57auDT zsvk5sMCdvXjO?csx`?PV5AmZ=bW}pCJ-*f=qgZyn(B{>7z4hxZkrTGLDhD#iS8_>j zGxJNH_rr5O+lN^zIiy$4!Y3`Ot=*}|v&Yly>XhKK?Uwu-!d@`J7Q-1sL?HoXstcsi z^b8?wusc5!2fZnbk8vDILni?``q0I_km;MEfa0W-PaxGs@}RvSEXIe%Fb4c?#7lgz zS>WM>AwUgQ4=JO&e2RZ zRgTgwZ`PRE*TVLj!1iL)Qem}mm08T0!zmF;cB}P-Ve91hWPP5x`7-UFEJl1vbAO4OU!boV++$xGPx>-_m2Fzt$h?VpNJu&nTTBB+~I98*DIY z`uFnn(p;Z>a}tck;~8u-msnMUE1mK!WQ)@z&vqlK-IG27|i7i3)q4f*OS6m_q^Y+ZRe4_PEF-H=(e8SjS-laxrZgKE>hH$vD1yn|`23_9e z%s+KUG62%Tnj>iMf`SXvG`~^@mAMQ7D&jqu+rz40Beqjr(N=&|2)7=Y_^d2dR*i9E zWiqSZy5emEs1kTGCUN|3liX{UsRarnE}aDjF%pn$J4x&MU0qT9HA+8|MFVCnCmovHkqY&GzbqC9t*O#6({?)wAN_KP!(XeCk{ur$s zLUnn!X?ZU%A~akB7KUEd9%RXwn2{p@o{ncOp`~O1RG{6jx`8qoCWnuG)4Iw^i&}~3 zkUtRL9ejgq5zt!ZEfh^@HK}<`kEV_!H%2icjf-gXHc@U}S589QI~wBn0B;hw%*0}R zNoYvFnSy}6lysZunAk$`QK@QtmW(!2J*iV>iXHWvx>pHs!x43&X+$%jR29FylfX^0f&4_fw3t)8 z<*kfhCnR>Wbm$Ns(dJy$UONJ$rX5ZdVXJoU(jMc_VbMPti8G+fF{|gS=onKx1!rqR z5-un%)!c%Bx$@A!gbobhtxmz>EWHEH9`DK{(jLFEQn z7K&+XPP5N_fIs!^ku+-49xKHPM_HdZ$Lnt}cp*`kSB?d0DULAlLdGX7OGuCuimIcQ zb1uu}JxxJx4gj9z43*`?-Y#~hw`D~;urEjHL#42l>V(RZL@XPCGgu*nuHV_|OOEe5&J;< z`?6VCo|l@Js}aAiI+alQS8u_#YX&n-@Q^6Z_y$xlkZwbb8TJmrv=V~fIE?c+lKHE) zwMeRIRKaHG_QWh-D&Er`16<>{!3;YpFVGsFLJK>|G7p|JODfgW$J~i%5Q(MH9YvZb zT8dKe=3`t}CjPocq)T*xH`4Zr=Q+EOo*%07kIvxFa@LLx%lGGgS@TKS+-iSt!Mkq@ zTfzPDAK;GaY#fs4@_gstQ@cPL`#vj;aCNF40K~d=4F?!X<3fZ7Xtwz|3cxw8q2B18 zKC2nKCAX+t@y_>>0(S%77TWezy!(2m-Jya04vxP0)tR=an^OJPRbt!KDKf28JU{K7 zx;sft`H*+K!?AzcXk8FjV@e)+0ygF^r#P7;Wb4Vj-4*_n!NKK?GE%%^ukJKLb%hT7 zUb&ymy7^`XjiRQ~Y5sHMB{`P8Yv#G*`q*9s;o0ks}%3`aN@ z9I4rm8fgEtlVf+b%8m>!VTZ!6IXpG_UWT)7S(Q0A*_ckb22QQn)L53zm6IhMqq znh+`XV>!Fy!X%q!G&*M}I8Pr25Eoq&KcgI*Sk$RY1!aFZC^`uGQYDpO@RNpCeX`zC zb1Gc{tCZ>kv{Qjf9+2U*PyF-8`)&|wX3CDb3#wTEkL|U_nG@g8CJ)nddMHc_)lvBl45DB{C)ng z0hg-AxVxTMWaUg^jATae1d3VHRWzx^9)o2V24jFwtp#yy%eAMxNGuVN&e&T_dN7fi z)t`&PCvq!Hs#84HENe~Dk_E%uD$=Yrv@?>j&hj04?3J?1^)M1yNA%@OhDOQjAROgd zT4|leR>fslYFhMGl$P-LMEzCvS?aA4`FUN9qdaJ5ohYD#)rh9d#Se2pai>2#+v`!~ z`SpHC&_V&6ll*MhMe^V=(WGa%pVKujG4;)QIYR}+e@HH2Y=@2fo|48%X8x2OG@Zpo zEFV;Q8P`jvEBKX`OMfQ&8rre9zg?Uau`!ptcue9+cmp}hC0Qccjv)b0MUII2OsO+s zPn~T9*j`O_GruIaioDN7U;@9P%Q^&yc4H7#62M%D9wOKy#=Vg!8_*89Cf`&tJwu$? z-Qg0Qfhy$ka2r#^V=8-~?8)zm1~NIu1R7EvX<}#dcI5$&TPBpiBwHXpJmWHT070M_ zMWFoJNIq|WjJSsvLM>2N1)0!TJ5bB6<5qYd$<;p$r!0HzL}H zf3HQlI~?5iGG<|DK*D;w0KbaAspk;3r*`y@Td5M+5=5vnAYzgQqJUJG6b$DQc^IMm zNlC;gjhdP(L?@iMh!Bdt!n&M~?Ns_IaZi|~J4XzS!CtU$-)dpLedGO4 zzM13=oxZ-i4GgVK{%RBWyVWa7vT#yX#T@xe2|jL=+}Q9gF|iX2D-B(R4m?(x-#!dJ zbcNEE5Y_^=2)7B}r@P{&x(a{e);l#3!^OkW<@N#Q_si)`iJrNC(4Xji0oFhM?C5F8 zNpQ0B{X9vj_;xkqrh2m%X2}y)^3L&VWMOGF#*8Cd6|=f{{G@frJ&5AoJqYO-2D)Gp z1I_wa8k+HV0@~r28XEpyH3;;cH7H;~!lVek1v-+X6_jegrwjRWEEgtW71^A>BeA+CS zDcP*?lX1e7p){@0nVcy(wEL?z=HEade_C1N!U7k-wRFq?tIbT3)CNIY=3X2JVn%B7 z0s+;boNuK}$B`kINBt5UmL)YU){8+9m9>}nxx)i$UheuU^;Llh&dex##?~|j-&1P` zEU44!vi2yNDm2y1CW|a}wdSQniPbVy>e{D4n<|e-IB4ey%M8=(<6Q>@e$4L^YtB*U zN+)wIn|ExtWJfUXNf?WMtu{}Hs>Us~7_GD6a-z=nG~2u($r^C1J0B!ZhORIVNlV0$ zQ{w06*LKj-`I!@JO`X|D)XrnlR!@<3{+bWGo|3HNwjgz;zG(KeHa$xb#h8rQR5^Hu zxt=o2@X7sJ=wd%9bz9FiJ0lSTj?d)6%+xyahxAzQ5c^Z=SQmHKSDfcjOdXlSi( zW4qs0OWDQJ)`2f&M{jrNYvREYTQ+Sd)}O#^*nKN6BmEPbY0N>IZa71H7_MN4@1YbU zkRuc!Q%DD)P8_&U(E+%U(WoI4jKhr6jD3t_amO5k4ygx_BZ|>RxLDB#xSG+F(YPZ} z(L5t8@R+4tw~26-(`YAB&JwcTAJjfT;%w3oZAM3STq=`vG_adz?OPmYz1x=$lH2mW zH6G8+_ZHs<(xIjTzFJxmiz_&bIjcGIILp$Oc?#V%?n93ir;O6E zrVi3Irzoc~kD;bIk69Kjb~{ALcZJcQIlw?l#+H$O>oq|fkXN<`hZBs#qEb>9RmZQ- z9vGlhbnN@a!6S!%(2#0Wv?BD}O%U$*;?6MU9* z5SZw4qZdtSQt(JoQkR|PXW8FU_w=XO-l*&NwMSCLS>{LxkhE$QiWN3170L}hL@Y+I zP{fJFkvWz9XwZnTU8Pz!rE9XrIA^FBK116t7%?4X;AeHd_v@!r0JX z4!1$wFkTL`K|g1ft@Ej)HSJnetLvBquj?3UPKz=mtn-{CtGhIOPMET^15>N(jnZ zNxBHokS~3#jZ-)=VD5XEl`nm+O`6@^vlS``LChN)a209@d4r_IcSY3Vy&!3HUllcf zW)L{Nxnam#7{C`w31P_F7(g_Lf}nQ68jktwVn3OaE>jR*=?SpCGxcaEXo4(=?j|Mc z+If8V!@A4JvQNsgN0k1{bH|@xHoU@ofWUktXYroidEd?%i_aMcPQ&OSe`GaS*9g%n z3aOHrtZqAX82oFL#jv|I6P=WEHq+=Sv^8X|-;b}>=iGKl$f6Banc;Y$v)pqjq{yf9{Z9-#A zANLuYF*Hmt{7U*oU`QB>tjL{Y$_P!Fsu)YE-DO|IwV^-8dBg5peA6Z(w{L^!t7SxO zBJ5$5|5nbW$CctjqDJaQ4b+Al7H?;P{W4VN@j-%t1YQdES4#6aK(28*HZyC(NCDa> z3q52an!K6&G99wK^LRcXuHMecEe0Zb(3gO0P&_#7j*$O2c%mz~?ou1CL(@4>n?0Zx zL6-qm6RAbJkYhT}&S+G_hrCvFE)KU%nh1jwhmwJJ<576TN=0Px;hf4;WzsTrL>Z1f z*8&g>1{cAAIs8d4FyQoiJ)UJkLtmq)8_V09neNqe@NajWs|{oj%*ObWu-x4{22?`f zW_1^GIU|iWV9tS8RgyblQG{Qa9+^{I$?%{1 z2(=A*X?7A`N$Pjps3s@OiR_FrNVunhN&4jw3!qDwK7K-vj;#?ukp|EUhi2ybYGXA9 zDB6b!qe@*WI*%x}aakpmjCaJXvaZEARW8I0I7g@Wq8@rfcq)Hb2YI9_pvvjiP!GrW z!kAGC!xh+Mef@Zj+3tM*ZKhRM==1K#*QrDX|MpGfe|ahejhw#@=Rb8zmC6tK1$|T> z-KV)~YG4pQAS$9Ww#4xiy@57HF&(C%SwGEAhONqm+NQ$u@0;gQJz`?OVg-BaU#HW~ z0+sBxe~t8H%zfsb@1%hD?a#qI`?m%SsJ<9(WK#xeeU;wMKuGk~wuvcTsOMV&ksgu8 zkjxBJ#z6oKSFDEzPjv4wXNgzS7ni9z%-Zo9@*cE(LSni^g{RCBY3iOVC%;q+tag zMY~hI`@bJYw3XB>FX4)kvoi%fW{$_Yuen$6MypxfwSUFXePi#Gf0Mwe2ojI zG2j;Lm0$x-P!nV9W^GQY1QVdj#FiE_i)E#{F%d$eUHXkMLx*O*HhEC9%KKcZ@R+fk zM`S&v6M0KErMrsiF#=LRYz{556^0={_r*;LARc2*{4;3%4xWl{Q5CEc}&UaP4wAH%UBtFa}MBc6r*gU|Oe&(tYT!iy*Zh zdd!KXWV^h_W%M~KBQ`P}rMvkPxp>34;PZ1i|7yOUsg{$!FQZ=Y>A*suq5xw?pHtJUpla415V!KX7`~yAppjw& zX1&BAD84mv1r5zce^7gONoL-WF|t5fM_>*D}f2W1IgIg5j*6`6+qG9FJ%hnX9bretKR&quEs#+E6vR%eX zZVcB}=EroMdMFp0s;oE~o{m1M=)4DB%beq4LIRORQR@eN{hsf{`mozN}pm%};S@*;Adw zK(}L>3(ng2fUdrg_mmJshanmr5fZP59YH_{ zGYYmJa>Z-#);jkiYhr#QSjIe_?rGWWp3-|V`0*fQdFzTOJn6>j7Gqnb$nLb@JaF(J zPIwsXZuIS_PfhL)mtb#zR0LBI)(8|L5dOi;u6INc17!j z(;2Ly4hS->1~Nxr7owdGw^dG&GiVRo7W|FHF+9@{oA4FL(A4n(GcLdv7lW~{>%jGA zo3Pabwzixpg;QiAXD|S?Y-{+$iAO0yT!>45?__6o@Fn3BK5vl#4o{d*goXl@kfJ>x zpBxvpD~>=VC_VHSX;a;xN*M`VZDB&t>3B?oRPe<>s27yepg5uQY)R;E#9 z7!^*2W~G{0VVD(uuTrV*&>fx|Zi+@rrKP$__GXJwbmOwx8NDIRPl zgKQ(H#&tXl1SSk`MQD3L{~u;KxY>OTDbBGKGfTgIWR{_qC zOF!(IC^^-{eC;wkpY%W_+k#-$vdr>C!JfG|kM}VRqhnAV;VM$`!m-cOJq?t&HrtY| zft1#E=y-|0W&lzzOKFK5?eKgohmS@Mvm9E9IYX_WutqK(5*(cQVy%*XQm>^SE3hoE z71%VI2DyE9uZQ0~m_P6oFfDMExyo*lHn#;8cyRE^4Nrk-eK5vNelRAT3PZk~dFpTL zLDtT|6jm=Nz2zHd-K86BpOU?2fNCF!nY0nf+}BW!1IdCWHq*g?{l@VsS}_`nV&`c; zmDxn~+T2|MOS;c%xOdq-`cb_^K?!h=ie5TgV`huP2Mmp)0g^H>CBB!kJ(teBJ%rV( zAp+KSC_764%m!;G?Ty)2ukao{Kv?kB>@h9a%|TgES?ZnMyhdW!Zh8Yje?5wIH;Oz z6ihY>#%sB!3)Z_@(tg|Kovf%(^Tn1wOuSV^kM6+1%wWrVA78}Rr{jmq&!EAIa;QcV z73@e7c$hM#7|?k;`X8e^t^}9bQF!_>=IA=nk{;n)nygNTUR71$jwZ|x%Y(<$AEO?V ztjQuOD%uK{+1Nt2&QT+eev7Wp+t=E3jq2KI8-0W)QBOkV&N_^kXlbd6*9DFIsBxwv z8^KUA+SV}j@(E~QSr?);A}N$if<0UIhw9u{yJyNC*&ykFI8Y=Q*lW)~!C*sn ziZw7KOHyM5C7fo7z{1c^pk&%4Hb-|GOD|z5z`=?}U<-Rq+P6UL_pz9K!@(K! zoH@_diBD)&^(NZl zN`Hj$u@$ihWB|=Dk*W{PKj~-xq}cuUL`_yCHEeG@{JP$ zlmSe+F|Lr7&~L!6m?68;2I>L?=ZNo=7m%k1xI${s8z8TMkldnL(%hUw#Cqjb#90_z zAvx$MAa8%+QQ17ATnw(jPE=FyhXlO-SX5{bk2v93WlZE*@^nyD$YNh6nNP0>SBP;; z{RK?tgJH%5Lqt0A zHCz6qty$dd3VvOsg9Q)!C>#mw6(*ges<(8G=zO{ApMqfo1!A{`ZSfIWCM0SU2d9d+ zPJTyyjXA&3#D)A*_4XYw;z3||txo+B4{iwbzswkW#$s|us>T_c&(H9`J_*rLO?0nqF96YXh?`Vd7^ z6nzMNwM(-@+_{0Y=f=9Y0^W&qCV8eyBBfuB(0M(8-O|0kM*;a#x@kaQ!>uUV-T>;R zA|^UpGe1$YUvr$piP+`Nb!=mjnyQ68Bwc>-j&AxPy(zRG^ML|yrP3Jiwc#imk9C0z zbtS)Kc%Z0!B%*G5gxy5j19(Ahqn!a?lXjyW0ZV=WaqiA;Kfnk_=bx`TSEuIJ|4x9W zuV?PgHIUov!<%E+LG9g}WB5VtzP%}&(3aUfJSN2JG58ujM7y{FZs+gYVQe*(oA%bN z@Y3{KO9`$kjI_PF8GU@`W-)j(f4Jhh9%-JIoK}_D8-Ra|v$ZDtvgdZ=nKJf@8+)X; zHtY^eQl71r5fmvCR?!Sdt&c)zr$$nDCCuB5D!fDHN?fU1JL*SILD2r8JohU-DnduL zbro%pw7SB+?A+4Y$z_je<)d};5jCNvhio@|FK1q9}&!QcA~U z`oxwp4j3Qk`pP?Xx;FDxA?MW>q=tz7&fgIQXMf5%hZiWC zJ%-s`%tB38Ya(qrBn@u`}e*z|OYl)w1v$;0}r zGzC$5>{I@mVTnh8mEeuX(ua5p@(0j4aOKN|NB)d4Z5>yB`Aqyi^9GT*Q0hWNF0_Gd zdTtJteR}V&<@S!6z>BZ7V;>T!E7JZYHG!Gk$nRf2cBK7VY63UAk?W)5dWp^w6=Hss z1WbSEN%njnO!plbU2@gB1#YIzQl8)^w%PjJ)s^cBtGE>JXN}YkYa%Z4qoXUP@njjFCIMmvU*%RR#}J)KeP%yOK%;Vou;0}Ctl!cbp7$7R zc5n~`{`U11cE@anDKF>X$EW-DhTd+}r|8pG%1gILTCrCUnOD-$4eMqwy94>Q5c~FU zK<5H~u-j_T&e55H()NHjAZP1kK-a>%ki079X38NdYq@hAzi%OaWF?(`*sfri1{JGx z4+qGdYRAXyAXD_Kl&8*TuJqsYlYrw?VxV!jaq^<%S*Nr5JkevhvmjR%zghAibE5yniL98814L~ByjKJQj4b6rH-4P}3QU`)KN-5aLHy_h za>Nkw6|IT+;yL1yX1>_uoCvLv*6?+*m7!?z|3le1#b^?BYq)LOw)<<_wr$(fwr$(C zZEM<`wrx%0O#YmkKj-Qsm7T0qs;+kSs-dX&$k% zopXk66G7FezWf;N2IrV3kuzeOJ42XT6!{GIs4Cu&GWpOs_(r)#%N`+aULb|)m)D|% zI;*cq{Lry+gbwVKC1HCKULetO=Q2S$q`yETf9gO=fPB20A<^PFiqWWsYT>c3x=N9Q^z zgVDL(6k@vP$nmE)IERMy0Zn{IR`(i{+?v;@+kuyQ5TW$}1Y^#$j}LvD_egA3$0Y1& z^uJdoN^D;tw_6^lGwO;?Ltcl;{~4RT-rn91r5%Z9bD~`OMD^>4b~A(={$LjPP9eNK z8TZ!oczsxx_xr@|?}*R-`|hNXwoXs5w=>UoAoN|D>N!Em{Z`GVRiqO064Cqlw?Tq; zC^-Isgm3J@Z<{pl_ek>RXNm?dz2BfN{{?dY@<_cV{IC1$V}i!`@%)96<{HuNw|%a7 zkG$u5W_5732b*}0KukZ(Vvhw<{fCI%2EWfVqtCe3H#5cxyF85^Mt;L>!iPhNZJ!xcpP||Oj&~Lg z|NRpc`!vT#Y>s@FM{o}R;}eJN&)n>v{j#iV#?E(04g;r01^e&O+5XP=tZavl_q6OE z$L9QO(CyFk>|j$Slpd7QJ85dY?GCogLMeFSVz%{FJSgIrdV9F`l=hDx`fthR`cXpq z-QR7VE=1}CunzF8=^Tzcu*56}@eo;`g_>x@^&hOe7zUm?bVzgtN743C@9bb-yyg7A z@g7DuN&G@qDoG&ps>sXQ_Pj!cjqfUSECi7JLBA-yB zAdF*#1&``^SVT?_O--7~en8D$n1P?E9Gc0-`a4_K474 zcRC^yS&+=1vXEQ7yiN{YrXOM)K%hV^Bshe$?{DuP0(d?19Pb*>Z*VMEi9A{%sbnK%~Rx3p_RuyUJ8Y}q#w&D`L_l*&+pc^(+~?0}lNctLK$F;iPkLuIC^Z(<5U*&xC? zA?lt7o?QU_eMk_H&SK>qgtmnW!{tcVaN?=9q#yNR3t(dXL-ycDQ!@t}PAUf_@fvlv z@`71nMvK%W`=csjK!k=~_QWSv2@+36vW}z7L;EL0$Be0w34d>gCSlYWVX)RVMk$~& zn$m(Rl$y1mpV4zOpf363m(~FPiFwu&iK^S+t_7#49#PgrMih$gV|xj^7t@tZ)$6!% zi}Xk{-O=CzglC}R`;g#ogK26poeAVB+j?;p3`UnYo^(Gms?F6+oVbxsxoPbUjU}{G zU5(}TP*jMr0BbQC)XKXOnmMv4mso%OW%J z4(<>w#J7SU$;XInqvIcJ5MO)}c{q;aHu~{hctw@sHo-a!33eN=1Dc>LM%jTve+E_z`wR z6hK=^`B8RB3uBdFaO#TXvErOOZ0hY%pEr?ph6d2YXq{5Gd_ij*;l5u*T zTq9mS9N;z%Bh`^KA$R-0TwwZ75yiYkIZQb-8dnjjTE1mAn*X?Dn74Ku@I&f95$6%A z1K2uH=>q?fCsg`RJ_!%l!c+X4g2SVP3H*0KezM$LM;9@(nig~ZS1+ZteP@Cvdzk05 z6aTx+E<}*kU>%DhzHpfwR8JoTLblB?aVq*t>!)(3*~l)+&Ov*jqDS=XmMF!ZLlGHY zLu0Q3o7dkacqM<+=+-Yo(cTQ{QVRkAQWLSkhyga-Vn6VUNia+@dX$PgoMO{DPT5r= ze@odM7nz;ok<`xn_i9A{Lix728Q_3F$OQ0sxhd(Z{aFnHQCO(RX>R9-_{*b!Q@s z=g%3e+L#BadgLg-U`30!T9$`;GB(~*(Me8Cg1=2q)5_W8glbJ}(26(=n}FK=>TAms zYV#{A06H~Q+_S=gWNPy$n)|GfGB{86LTjlPSpd@EaP;0c(P9cjRV9Te4L@<21x2HDx{-So^D|`#L7%R7WqKNP$IW+;)^Uv@I3xt8h?J zXpSIUOuPb0y_aDM{JzkiGXO5G>jojmnKO_DnP$OsARv5kXS9%Bw+qt|39oosXd;{P zPZaw}w0&F}BP=#o8n+6?rfD6;qbrvtf)Exz<2D9a!oH?ZO32bO#uFwTi+nz%m2(Bd zVR!x4Mp#lijw_c`8s%A_Z&KxCv6~O<+NE<7-O{~_Zq=M9jJFN7 zsDS+1F&Y>8zx=9fAxBVr=;ukt_U0`ozjW-%6})0x78h+AN-?Q!{Gp-AWFq!hg89q{{ZnTy=Z)g$6%(sIG1zLgz z2IC{5fLaQ+Diz@5& zqQ{b$d2HIaTJ6dW9IrghR4@fgkmMSFsh=3rGp!jKHIl|-+AFerFv*EY@kZ?e&m z88z0x)y5)0Z1`DbW%sOL|MAi;-sF{ks*PgIjTJ$zzXFD>sw%s9b?ldpxJ*+Ybdz+H z#2ES1c=<>HGaw-g->H1^PPZ;B`29zWtZGC|0seO;X?mDU-KUec3Dm1C;3k3UQJ5!g zsX-O_uZNz0MN^W19**7JJo|bC(=nUK{T2KS(lI9q&mN4o3npb;dkplerl&PG5f4PV zdUW**O~QMW(>3-9@Oe7j*%;T@9<=rJDeKpc5Z!#x4HoZpJcAk9n}N5f>euese%02y zJVJcyj|({8%GvKwRFArMcw+7@-GhEAjtlJPyM3l)&v(3o^&bd6pvy#M{R4ME;(r$I zfxb1ygF##ah0lahB8Ns}bxhAllE-^mO2GEy^>)boOD413JYjDZj%vGlfw@-t*sRj6%^Mmyab}Qy^YnQ60$GAAdKJ;^OfYaFu+rt zSt>+g-QBB3>_RqY}nKt?tYt8Z%T5?JTlS|G{6r?4yI9FcX_ z(U&M!X~{%kkfuDz8paCXJhN3F3gjXps-aaxvcHy~>fHj9Q9xa{tdng9#@Z!9-Op0C zumu`28E$WC8td9tyoi~sR&~InSJ1?p$oEWL@ROA6ZjirCSJST1Rp=P>UWJ&^PR6Fc zxVB|$!n)j7)v@8UgDCHU;$$g`kmKojfwT!D%4e7vfU&+DTYp)MykW_Ik?jCCB5nXA zA$@DWJgMU*mm#W=i;>OCsG3$w-zd~(mwh9X4tPVRYbYLiv6q#dq!7B8T3Itj1}kqp zv3V)S$@;REaII&ijds)tJ((Ykgg(42dbRycwz!`mBng2U7+yVciNx-AeA^N~flHgI zSyiqR2tHz2Wk99~XI>pFZPdR59AG)&+x{Xsn5w_X(eDIk;sF?H)$C&$e`fAl+fYDS z(U+ogftxFcy2L3+)j!5I4CP#4cklONnsyYVjn?xiG1}}o&#X-bJDf+uNvPe?ERV-t zX0jXat;-Ca2DH9-)kdE_a!gV^-D|QSwtQy4^PJC9+_NHLWg(1T{O9*Jj9?LWwN($4+UEIw6e0+pWbwRWSuW#c$F&h3|^zae7 z_Bqrn+L<9Gf#Vr`*2Weenc=<4^qH<)kdRVLV2QJQklTFPtt`eJE}lE$f`Y{wW;Hj!5bV>hVznEg zYIxWu5gn>>Bd#6DHky%&Im(e%bVclio7TLnhfjNsm%pRI9WO>vCW)rZLsZECMh?AH zmZO)`3$*br@Qhk zRm>^6mR+q6vu$2HTR4?nCh6LCC=2_L#e6Fyd<=LnvYu# z5C*p7&zZyg1o&nURLu6#Vm?oe;ZSVx8-KMZrOoTsbewo@NS{(p#Xo1i6B_y5wrh3e zm6-AY+wYT*__Uj!c7IBQrtmsvSa0tu>5MG@DeV;A^Fogetlhx_nFgiDV^*9VkU|N* zF+PLifnny0YtBm|L?cpMSxC(@j5p)<^kj?qGCEjR8Zeqyx^ur2@2&)7#C}!c3o4`s zkkJ7(N4)}J2!I&R5+oo7((bs8cVpkzsplM?2h1ep2fMd}@F#3G?iIdJ85iPx3@A z3qw9_L4wBm$^U|U+C}h^nhWSQKYivX0<@Cs7&9F*C#*QZr zoF+`r8u6+MQO^VeG{IbqnCSva5pXa!Ss6x%Ia8=+%KacZdfxMhIc1;05yFw5%)u7y zp`OiAs!Dc;xYfD0N4=6JZsf3j|Lo4ajuh zeGI}(gmU9J6tq7p0?`_g)F`82B!_$m`Qt?vN34PX;l+YST?l7i2t%&mL_Fif6?$@F zjAt761wy$sYNAM82Q0Lj;VU*&pCDs3Q&?OPV7-QrI5WW!=dwlM!F^i1Uq(bE6G6(C zag+}zYSu^agzY?&{$Yuj2IhzxhYqo!ip38_Mb9*`1B_EZVQScDR)k!V*zN`7=9Jh>Ib2j?89Xtm|K19h)(cz5~G_ zK`ITrJ7?8FKi(`qKE=RfCm8y1)lt|i((w$~Wx^w1tcv}{5kqKZORqeusNQo5@A-_Y zS-I(*5wI7C>?^kcG)R|vccU8=k`ra)J%I6zvvwNogr}}}nNMkOCo#K=8M}*1>Nm3s zOBWLdDZGoA(}_9Nzb?qk*Nmxs)hOQi;&QKJOmMePbhn9(%oMkgHl!@2AHVZmabn zpk%SGMv8e9*!hLCN6{15wvG5ArV^+i<7D0ME;P&o=(3IEQy45)`k_$@z4T1i)T5c( z5O6+Ji=<-;Mgz-aGtSNS3g2|H4}xCL{E5H6DeUk%HG*46Ag#zFOYDpnk<#~+Rig8m zT0MSki-x-n42kkFG(5e9Y#IZm#I}g5L+IQZfs{|%@h@yW=K2$8{G?m_#jyuYTk7(a zW`2hB?<1K6J*A|Wuc>ruEwYUUL?WsiDTHc0OIEG2I&m0CTM2MEW{;n|z*jRL?2iIu z`wywslX%nLT#T$Jm%-|Kp+6Q}lqi?&+f&wGKCq?r4Y&`!IeA!PRnT+_rQ%XtxD+bK zAwUb?aBE?tkR7Hx;L<89ntJ?VFOfBcNNNwu5elf51nuUet+@@=zHr>9)~aXMavhB~ z=VxzlOlZuw@f+GuSKY!HPD|uDJGY?AU57sKnG&AoDcv6winlkQDjBURT$kB#q2n9-^Mv;+O{_A(~r7m63Q{@iv+_bXH zg3jQqX3HNxtm0Vp;fuj;h@KY}`=k?Aet7&l4!I}9UoNyGSQd_orM_(D!*;Pbn;OwS zr|F`c>c=nZ;np|BT|mb3)g{HDKLYy>cdBJq5PxUPmNNpB3Y0M7iwV+2DmF|-nFj$f zxeJllcG!uAdKnH+3=J(IA1m7C{JJt_pY;IDwrHCw0<|&qAs@=uiNe}QGx220P&-LpBjFRVcAh{446}EIQeW>*&UtF0&(VFL#Y?+3r*KSd+Xi2 zh)1}VEF7k_W$u~RrX0Y)f$h@GGD$*tJLb7JDE*MGcBFGELcm2gU1~-n(WZ@k2(^VJ zkx=q6y0jrCnouA?XwL+#J*Nitb%G52S95o zjf0=nks1yKisC^Je#wO2p4%nAGz+wnh&#RJpaPo}lMp5o;9Nc5^=>jNko%O$d9`8*9;h&@MJ;)FHm|z3-gV>R76BJQv%3&>7*oR$WsfeWM_q0N%{Usog|~2I8ISH zQCr5PhP`!o_SYfzGZ~8vmcP1Z8^spam^ltg9?0VvgSU7$g>w_d=+pVaySOo z1&`;RNc%_V`9-1fyL&6pBtq_QrbimIS5hZyNpd=Q{fuv%gWgNK#UcCSmY67pO|QQ3 z#9bL0;FHVuorr5T98bMyOT8$Wz`XJ+#pRxtM~J#vY^L zaF5an8JFsHh{^{G<{p_Rw^)?0UqoMA7$c@-sgoo-hUAkW&*7th4(Ttk3_4klhBL6f zB~_zOj%w5eI5MF5ca}1(2KEkcyJMacEnAClyVK7v(p@GL#p6SV=y~^CYd@#(DJQ=k z%$p-Lp7ZKApLVt%%GJ;A<LJx{KWcW^G-nL{H z(Q}(<9WTlv`TRK`a+x&mw7TyMsN+~S*ltdt-K@K{3B1O{o+`wiDZkxEAF$XyooHBj z=RCIG?Q!F`s&r@o(vK`?dE<7xrT1NC=tqgp0#cC^Doo({Vc2i5>mmIiHjacnVe`s8 zo^eTyr_}piz&dwgJ#Yp?I`{1!nBNEnqv`iDK4KkrY=wuH#u$CXs|UAYNIwNJM<8e6 zp-0Sp;k%T!>a(Qx0GvbRozUx-^>o%T@_yW164FEFbWNL^8?%V_lZAiA-aQV>-;G$ENZIn8d`O?{Y75$}#)(Qjn9BpD7v0f>(mGFd0 zCD+g$VZau?Uim8$a?hjNVJxMZx=c5C4Tqgxc#0gz$9BV2%5LLuN!K}xXFm6|3sj$G z+C`yqVq*R*gp#JkNAA4hQl5q(ujcNKw9-t>+^?)NL#4yQ7G2FlZg%3eL78_{dY_FW zPLq&^mj{90Am{cxq})AVKF9|bPbMq1ezNxtcF?dUb`D0ts&Bl;+(+o&-fE|J1~E!_YHhIJb#ek6YoX&M@c!#_YJX%;TxRs zP~(o~JDDcNz4GoyymAd*6=h9D+yft>bmW{fqf(VDS@?tGIGs;*-1OkNM37)zjBm&N zd7!#VL-6rM=?t(VA0S^vYdwJ+A4GWv@xdNU^c{E+gKI_IJc(paBIYtESX3P1rK{j8 zyYnS6HSZt8vBb-;wmYVif+NosoCN%;9%R!~%|;uGGr=o40ATHr8{Sfr^5;oaS2arw z;BZo0A(~dzfw-fedBfl(hKK!IyX-i_vGqTOVv$j#zA6A~3U>VpNiuGQ_BLPvw3$<3_2miBd{>mg+`5qzcD z)yx4?uXA-ZwHHCJ5NB;UHNRvrHUCLi17-P$p_Jl;oi~nXrpIX|=~sRiu~EL4{=I&a z6w@*(!J71S$1f0xLIkR&wq_F_-qD4Lb->^2xL|jlU$b!}PQh5BeO#Dh(Y#b>!A6x> zAe51XdzkMHQgFeu#v$5uT%u>nSY;$ZxN)JC;wc49zJ0y>y{q!W+K%C!*|+2Q6xUVv z5v|qic-z*)+3qU{1Dxc)n;sklN8HzMC?fv^zhS{%8rRau=)csrGTk#>W5jy3Wj=J)T&*mj*QIEU{=|{hMuB%a=^O3Aq zCyd74TF=k)1Y)`L7$E0#DuE$VQXwVNqRUIX5)xK%$N{NV zQJ$@>(t_NM@zB<^vqpiZX|4m&PrEWcvQv~@_;2OS>m{1wWx%`0z| z8QW4xV6`k^Di{M{*G=l0xzT&l95e=rYe5L<7|CE}r~Y><{S+8eA=@N)lV655Rnsa$%N{kw*U^t6!6*H_}9;E=>>$ zorGGP5xU?=&$$=Xfe|lQ2e!Xg`91O{f%Jx0z?1QPJQpqKHazmc0xj&e7^rD_HCPz3 zyp+BC-6r?r2Ul#6?>sE)+~F^X*G>nLa&h2#w)h@z-l$kD5>KI z-8@=vShx;ZJ;LHx`gtMg&g+;|%lBONGE_)18S)l6H zi|A15bD|P|r-*!~M|s>LJ8_qsxlPL0C1vhc5Pt{8J{~tsAxu*86BU1-{DCa?VT)Cg zE?1HcS1L;oo)>>d$37OAr1}vPe|G>()lX9O6Blp)dyXFa*nffw@iQOm*k;`{Y@*YA z{TZw4?r({!xL4p$zTbVoWh1kKfT%FL{N zywlHKyj1t1bB>9|X0ZQWbr5ysj|un1u58)2Ws%>5k<`VkYsZfCm>b@HmWyV`&d_sN zi8`R_|{gz_*`z??9r}RXKF@H2YA+$fe z2gvAd;tickoewt9DH&Sr*7w-UOFIhjZkW|_S3$fx_IF+~1pRHp3;6ZFnO`KkRFX)t z-SGhdTdcx}vdKGGdX^?dwuNYx(=7$|q#Hu;@{9?c1xgPu^j-elJTCg1vlx%4V$&D#^ zfHc|f{y!O-Ny@2OlbYsaB{Uors-@lt2z&l2lqmV+;Am?;zja|39S6rfoESD$jJYS2 zsL{*jlbPvBWv7=6l?!RneZCDuOTvD{0H3X3{(3lXG$iFAjQ54hcRyKhy9#$4Wq}U5 znX=%!sR-Y@N&D?6pOX3e-D2X_Z~h8l{_KOhX*hkqLnz@tXIvkC@=f1%Dc>-kwZ3;) z?VqPjNjti{+i9A*I#zh(1}MqM)qW%)d~LEqrZ%6aRP&_BJj%M0-hN-Z?a_L|MY=2W z9|#1!TP*UIT@uis--gPr$wTUo^OrT^s1|h3{%KQnzNBoDdokx`FaAlL*}P%JU4TZA zeo}}u2Fj=YC3Jslisr3cjKt;SkO$_GpxvS^yi=i+tK$@l(zh&2F`XTcQ5V^zYONa3on;Ei)b3#gm{H6yT| zu*op4z*;Rt-Mq%x<*?mgd+FRl|7N(28nArf#;0Tz_B_MKZtA4G`fW+|p#G*u359o# zUHwb4&Z&hF%a{i}Y*}W@jh9l_JOb0a4GV>QqbPi%>M$}^zn%IM!lA1Lpqk3=-rjLb z^=-jS!4HsCeSHJw(7Us0yr{aB4$a6vTUT05L+IP7SJ}YPYABRS^&fj|$DTw($m`JR#JWGfsy4UkS*7SN z!KvdMZ-&cN&osOddUZ;1^I>z#(Q#Cji4d1CMO+>=kH{lYg4Os#@_c8$N3CPJjrJ2K zR`?4a$cZM4LVl={W?e0zDbW|@Cld7{b4V$vC%(y`=X=B?KzIG7FlsL1BSypQU8=K&dA~8`#Z`6(Y#sr_K zi}`~1@13df&4D2OkK`kj1p;FIfA7ry6{^wx&(FsKujZb~lcdnVAV%;=hE0N+V2SuB zDL{b@v{7b~1V%)e*ya?1H9BJ8jc&9I1*_K8nxPo<*g`2{;Arlp2aDD#s|+`P1fm{t zU3POh9Co&$BWG{ZyLVlFUg=)*Tz2t(UM4|-n35dahwC>mV*i{$%(a;g9$tl~d`2W? zQ*~x0=}>j1CT&r@Gyk)*?aWQ$q3TRd>ZaNdpZpd3=Q@mmV$z$cGd(H4gSm5l)^F;j z`~p<<13T4Ez7(?Z2`TlL;<*vcSCDkP;<*ydb;%+F%~z6if6<~n4WD@Fc;%A~&2^zN zZEBIKSCF)KWlKB~uT<%ms#lb>g338iDuVJkQYwPVd8X|Pop)Rk>BbcmkND&xj`tvZ z@`e+KtvRFet_hv>O=K?>W*29qZ|;TsOuBN?$gZe{olS@@BsWzoqDZoE!aBroU1? z!;^lBkI=|}N{?8{caetsN*CKzxkboj*D0spjV?u0@qxtZW?Fr}uOAdGp;Jo*Fx`+%OfzM6fS+H}>lD-iociXT2ZvRWIbE z2&F%)d-8GH4)dIpk>Sr2N`X`0N=h=4gjii2PnHqqa=2We0<1+6^0$LO$yk$>Kzc$h zGgSsYT^^P7#icsO!j<`BPE-{Ex`(8!{K|*LSU{k?o3|Xosj)kb>rgBc5n!u-ndh^6 zH@oL_7Vz%b)Ms8oNe{72>F?OydJ|6)1`UIXy@#&41XaX-Z>^h#;Pl9ecNmL3X0i22 zf+yNkLe*&6EsN1$7@K{Pk)>Y49!B+1+(wC$jinuQ^*LT2XhYZ=ynPB*%psxUvHOZN zFeANye-=@6RYVF=toneFuiCCUo5iM8LDvlAo>lkklLsoA^lDx2!)m+_wK$qhAa!eD zJ+OmAO9ZZ{ZJpUM3#&_5jO^EQ2+QgF+fgA6))HwMcqpx(IuwLzV?8CUY>o+*j9tF6 zW66aHD4Vh3Ad@MUT-DyUfeAMfTZ25tx`{(+T$W$y9oW>w$5O%3P%uE@i1(7uh}ZWQ z8vh#D4L~_Vl@)@%_iz&U%KmaABQEx{8gNkMcmpLi(Kactmy6{v4)NI$H#KugLK#Wd zLV_mNCBC{50#~TI9G1#JecR74BSC6@KrN875kG_LT3^k>fMUhb7hw3qW@MR)92Wx8 z(a8Wk3%mN4#H~6fxSCXasfY<$pwJV6hC^6#hq{X4ylW3R=*s+X7S6##Eo2!6vR19N zecp=(G*I#D?H6vAAPLx>_ANZ}uMoC-o{id0z(2bsr8g4#G&N}#q?b&t!P8eUiv1nF z$t!BD8KPc*q5=i?R=AI?y>=jmIRVgnGpO6n*r@(8ZO!!9(*zA63Bk?{d^;4aM8dfr zF_}g%vX*6@`Fmc{(W9-hvI(RDGiDy0b0Dh%G=Xt0hG>r|u}~+t9D?LvQfZ6Sg5KtL zD7K>kGfg!-ca`-7E_BG4%_km&2;ViOI1;OaZ!dI{2#ZqQ%{lHx3=wpGoYtgW;V(D_ zD?)meW@+wgO1yKkyd`)nN21z_aF~~Jh4rq>Zj@2#p%>Bwb3h@T`H-p%p^g@an zX6+f7adt<|@Qy%XY_SxcnN;~-*afl_uA&8#5J?!8W6`BV3!FMZ%%Hg+xwVwPSgm|m zgUfz^O~=zkA&CaBXhCCRPk_VpR;auBrU5qz3uu}a8EL7w^^&nz8{c}_tf6_tYvnC` z^9{01#_~YD0T4$?$bbua6)`bCR6Y<$BGohof^vx8NosSeagRY0t}{RwGHM9eVV>$J zUDlyt=F5j=cNYXn+u1|dlW@4m`#NRbX^Y$&n(;h2IIDE8i*#p=z~-sq8F^(ZM(W)r zYS(-iW8O)+@+8JC^5;WLGM>yAP7-Np>@x3QOXmq)#<3J?+5WlFYWsZZ*tET~vB*w( z`#av_n=A4*;x3vEef?gVLG5Wlsxw^Ik&CMIB%hswQQn%=-NG@*%Eg1C5{wVHx4o*Ou5ls4kOuTU(x*N z#kNP$%S|nixRZF&5gdxW=2dO^OjLhZRC261o2Vjnm3fs@MCq(12H3-7Dce^h2pqLl z48f%*8*m`n8a;e)p!Ghwz9FW+(7!rd3Fof_D~NxUWb!+QZcvjYT1^Dt(w;Z}q!3`rRi{X`rq+S|_ zlR%+aepDuI8V~bNtyt4-Ns6!tF|JCLW6ZP0=12d{rLos{=D<>I`)RTzhUsI1F6WdN z{@4s!*JAkHyd>C8f|ae1f@loW_1_@Y#Hlh+w%<^B78QjEu!M`0LN>0HM$6Xo%CADXE zk~@_r=8lZ!fEUohe)}B{K7T=JhP61PhuT`uE^jH@3p#T|0L8{B;w}JfMCzMN# zJMP%E%Nkr-B5~vBL5+)^!1|&#e$iQp!$jOax#hW>dGKhX)_vlqu|3ea4n|aB1T7sX zxqq=eH}20WCxRt4`^G@I5m9!;`!HrZO?4CJRvW}~->IRM7iA|)YtrY2?i%OjL_Tc+ zb|fK97O8jCbxiVyM!6CmEOjGm=XZdfqWfp=-GI$8oi{V?9+>(9lhcvf$J?cEMoRjw zAgFnhURJ--x%vYQn@>pY{xFB-w^r`{xK(ZWYW;bRa~~FAbN)8%Lyj{aSZa4vo!Vv~ z^2>GWr`$tY`iJoB;6XvC+^9|=FLx3Ssya&!lyaRnM7M8Jnm?i=t0;Ndl`VO#XLlOf zuNZ#SV-8Di@os&oyLFE|Z@F+|KJ6l^r|$PWZf(es&2n_Gj4^S1*nkSl*O1Pl8AFfp zG%A8XC7p+8{NS9C4AH}_IdeM;H^mvrg`QlQEi!UTIwq2%rLb8Crc3M5a(Ea%YLEhJ z%4%!zu3X>7TWY_i$2;AA%VZPd+Mt+Ys-?d{Y$H2ay9H2Yf0gf0;|ran&8U!Kd~+%> zcU4eC&X0(}rR;lScs|@T5n~4uDVb0CrT7mXzpj z2Y!uZ$0YDy{{A%=!d1LH+c{65(Fm^1fE(hynr9|4n+{Du=m@BlM|kz5gqqfneHt8z2Kp2}Z* zuq-}vq$+1Qy`B1`&b7p^=jSxb8mm2!iLXf*%o31-mPo^2Ich-YRpP~#AWba)MS^Bm zXF-ssnqhK+S0mF^`9Da-ldOF8d(L|$PUn_k02kEQufkh`i%x@tmj zbf zL`hVOz9_S#LmZqWE6pmcn_`;Ur0%GaBo`?!MJeq}HCaj)pEQ?pL^{YI*)^#Y7+K zIuWjW210NKFH(pY6Vm6%@FFJ|S{(}900lAROcln)1Qn!+Fv|qT5Dv2rHEaYM6QJWX zrpE+x6YR1_j0N9q2zMm}^LL+DwcV+L8&wgXqKJyJFoNQ6Q)Q1O10sL#0=x`pPvOqu z{;+a>pOH#4W|&HKkRJ`TPSi~>@hb4?55}kLf=3@waW*I!w#sI{(bnl*D78(8Aj%{q z$zLFPFCNQt9wI(F%C@o%s<|emnRK*%v}Mm7G?E8&ANol9VY5Z(LMc~};H(EqX#XgKLbBfR&V5u-z6idTSVRhs)hCn0#uRt^F~ryR%i?!GmX<`dqFb9h-#IX z9!jkjwlXj6X;+NtpUN}lo{liE=j)20KR=;MC}L2LtTWyRRez8sVnh`6RQzIo&xo=% zBc$E7rOjgktOX%zhmL)JgR;G&I_1E?tS<8HC8qFnjWOj}s1WUTs+HL6CZ0M%V0YZ?RwJ6d$e5aqV zNHK+d(Nj*44^JroeYmx;v#oCeh{#vr*40trTc1>PnnhUV53`e%=G%|lN6TI<`|#|< zv&}^FCRuwa(vnZkWY6|Rs;P9;C86@Q-9zGh(?xmYmBl@oI`)2TN6vA%)6qHMgKX>& zr~ z>exc&Py3}bF-VqIyMbUS*Yu7;H}KiJJb-mTX(4m?sg&DGM7bBp{|O!YQORER*3r4n zow}2f{G%DTTp7H0N9%Z9Y6+I17xR<8Cnf)&ZO*P2^|M<{5!As8vok(o-5Fs{vEvGQ zN0Ci^pIQ_M!W%L6jPxQ9L;7nkLPF6e{-8sT)0r~rT*Kq^x-IUQ;f&YSf-m93usX$q zE+1Lo?o0X1$oz&i7F{?_(usvni*a(Y8yVDTTm(ns1*|4QIM*%MHTn;>FFWAR>Y}}84`4O@IT?J;@^AwYZjEFP9)o6@so(NLmzmXHXMK}(*&LG9$*~8V_I?}s7MLOqo(uZfMeyvPCFLE=uVEL%c1cd z*rReuC%we5pnlh!XNNXRg|1ClVvxP9Ohv3MLyq};un=%(6t`6+8 zjkEjXhan+e&6RY1G~rXyMHFf|CK=aLfF@U_!YY$e#H9f*>H^XU7D&efn{X&il!Y3h z0c~1?6EO{KN)BSh37deKDyS<@WRoH|*Q~E-J~`>h$@Le@(tE$@k7|s!Xjv4v(&(x% zJM7lkF?p3{o2$pzKFDEhc)}a32wGpgkCEYvtOP9BxP4Jk&6oYlH>UY7lXB;8SN={QPgrd%;mm?#TM7yb|F~>lMlcHnQm02zVhaFS z377@fvSHamQ020ORO&rtKTd?0ilC3w>nzJUt&~l17se^x-Ug*^>tx`O)i4iGk%7VZ zi%JP-qx9Ql=!FhInurg&ju;LgvW4nI)Wiig!2nz>B*D|QayHqQh)iB? zZE&;=wf>qeh!u&ZL%SGyhL#Ap}nNl_JR59B=$f*JQ^;xxZmqxUVp zS;wf{htTtx5OXHHPg5U6#S?34PsEPWhAz3eDzG|Hx?CtsVo)IDk4YujAy;C*sXLb? z@=ri+w(%69uVR*dN4RW#>-N1Va zWQ!UUiZCJ{>isHPoHB!0meojlYzLWa8!gF&1|0Ps#;QEzF&~Pt639Da)+#eQEcBwh$_l|_9-$h+Uv5-_ zJv5h8g^yI;+*WLa)oN6hd<=t0Cn+;>3T2TT)Hzw^Y$rTCfmLFJ1*n2M3E2i^OTT7> zMXu7Y7uLt$-NxSk{wAWcvl;V-)sx*gIJyRFT3~i<#doy7*T#{Y1}PuzF`s8}loS5* z9q4R;*Ww>Y79iDew+)`c zv(PWy7?eE1*ev(XS7Z^mSzd8ChmQXfnzO_h-}5|-ef~I5bFa&%OXjitBZE(u#Y1p} z({41wM&@y#)_x;03pb>H67EJO9sXXl2eAgDeZ1RgOkl57n7bDa{I*)L-yvM-9iDgV zI^@g;hxX88@aP?XZR|Sq;>FkT#~0LA#Eaa!Uw?tj+;v3&*&pV^Xz;Y)EZ;o6xSH+Q zeVqxkHFik#s9K?nUoaX_4iP<*cFmq0YIn)f8vC5D(Ec!;(B;KY<7k18aEGM@A`fse zD{ITxZ$dLvm`rjetJxsr{PB&kR6`w`R4X|aNEhNVRpCxyalZ4a#@qH7mCET9<>r2_ zxMgV8&O6G~maA=9sQGm_C}J>VEnxX4{rzfS(Lj zVJc~1Dzhk^ndeq1tl2NJ6aZ^-0dsbktrGnTX2pQ!QW$7=+sx~lTLN!t$AZMrXp0G9 zF9h@<1MWV4hF5AA2>mCuE1-5gxug=TzViKnOabjR+q=72HbqxF?a(Ao;nHFcs*A+W zgrr)h*zKZngZ!ei^WzC0%)0g>2etQ!G193eW26!1*Yrbk%pkret^+wn<%vl;Q_0O2 z@IPmBBh)aYg5L>zJShMBv$=mC7>hVKIGg^*Y)<_}14RS%6JH8b5*)eCkk(R12Mq*U z=nt_vQb{#>vzw5W-Q=$rL?|g)aG}oYx1LS7&h_D%GO+5ChbDo)*`HE;xf?%syI@5k z?2Hv=y0)HdA~h4)Z|j*?tUGeEn?^1 z7Gcfa-RPp_T1e>cjYs=^I~jg>g4Mp>V(VLkaIB?pXnD)zdo$Bimql=p5p5X$X<-;C6x6};2D#9laLcxPp~z_u;5XKWI3Dm5ld-Aq z)0n3(smpXvJ}^<+2@tf1ta$Szc9Y!QYvT;60h)(sL{6FhZ>xc|CPczicNPq$m_8?#VhwnKD9w`rR37i9`_J=?1< zW$iQd)771{)?7Kg>R_J#WmQib`*`_hNi3n`QHc?leU3#kPh64{*CX$^t89J&Wp-bj zmwTAiwPsV==p@ro(klo+#wd|PJX?5USvXXYzlXi~?FNu-mEcOupcaeWu9Q{5OIJNa zqOXtmd))@BzCK4>92pgfMdI@`B%wIS-f?lt-s*SfUwSEHa3SxpN1q+lpAlc<`6(@( zTKTEm4I13luZdYZZVx{5D|0>VQBCDRC*AIC+!LqAKDb3>5{v|0QRU6Nu8IfOatfv< z$8=ESS9`i4t2cpeqBn7I=uHg|HE~&WLix?6GThvAfiAje(YIs6d&byRv+}>{nD4{YBL5gU5k>f_|=l_mTf0(Tz(j+kOZEty_{Xo=)ZU zMc2+7TV!46YKAj<97A?&vY}zDr zY&*D7VLE%#NY1!*U4Zxz?v0qA@bDA7Zi%igy^-tB;2(DYV_H^f?ZhH6Fz+?%oWvscXdRdWSto;@~sgotW>%?r1T-#7Fjah_)>rL`@C8x z>XF)BNVZ2G{;h$AQ&3wEwe6EUlw(`z&X|2PHu{=X>g>V zbLdu285Yi3cFnQZ;5t*Te~_5zXK+Lh90+)91351n=+Gm2pb44&9uS@sASjDl&lIG} zyP@}Mg+TYe>KekWMe0G@wt`%g4UQ`(8lEUp7!Kx$bmL;w$7`Sp?Er-J<9L4ebGEte zQXc|uj21xCaCASgvck=;t?{x(4~Keo>H*+*0B|aa+(&PWkCTVcpT>&pJIZ>iNEMrF zsMgp= zEx@f-LZYHYrO>cXu~GJka|TjrKq=DsEtBIh)Dq;H#rVT#f0kZ)Jj)N97zqhPUTpXU zJ5cbfeWIkw7UlAh-cDFq?kwIc^z7!JaHz@`iP+7R)-Uio$aTKMccY&5ZV=6Tpg;hl>`g1w76r(V-MG+(RchO&^t2XZ@NtJt8bu^F{J-H$- zss+Z1O!1=R4LKK4>$r~}|L=<&spBPC$a&aj@U7ue|MtHY_+P1I9REjfhYN$Sn~jZ? z>%Tc*t2nqhoBW4sU$?rA296k}UzjdCElhHF6JKQJ6^jdUdI_yelHiJ zCqU%4%`twm%|!@SSgkh&F;+fHft%@PeYD5iH%!M~jf8->7H2A!r_bE#TIhu%s>N0I%qhXn2k%ItEbPDgj4oth=VsX8FF&WpOnVKu zQ6}0&C5z!9hIrJ8m(-r4OaB#97@cx+3{#X%)>jw!F%F1Xm$#%SoF;x zrEX!JW%Q9;QRh=AOWU2=a(`+=)SwO{L8<&kTh5zF-9Hq7}D4ytkUwd4axD6EL7m92!F2VGPVuB$#c60)haRuKtS`4szD*3 zRT=3Ggat9wNflB(BO6HN=hLA|3W158LQ7M!{61-l4zjCafz1x#(&3;M+g3L;3=fo} zTsy*~hOS^7H^yOg#zX&sy2Lo{crQSp6n2)TPXli?naYj=o7)V0xUx7JK$Lvwf#lVq z&mJ+o<^>NDEDC>PyOIUFwFh9igF?msK%13uNGw`_bgtqe|>JLh>Pr zD!u6vA)`8V@&4eBkCUI(cXMYOe=wkLqM1A#r$JFMlpd^JpF$(;z)k96Q+CCAqlI%IJ;{MD^TQ1ofyGN_!SZt z{-!vBeH!DTv?%ED10&Z^acblzc7%c$%7ZUHy*&TN6|_i8%hMy3@Ts} zaX<}wo75EB=-?EC$~>h_cl07cd5H&e0H;`zpurPma41>vZ7WLBIE3@IRVm88XbT5( zkW(!?e;z;NQ#21$Z9vE0@YVx5f0y&Mb$^^u!AMuoid8JeyZ7ELHY)o7WS)&-sFn(; zG&wyjlMQQU_~&$TFMGgTkBI$x%qDdGmOSIXPQO*v#)SQS`ny*$;Pt`5D7F%B7 zvC2{=DoL4HY~HWGzCLqH0Rrt1BKQ;PQW`q6*moD9qW1RlIK-dF0{`q?+?E9%Pv5_Z zQ#2qTjsHsTl5lo#bCff(H?lBu{#W-Rm5>v0b8&UB6LUASca^nraW%6ybN<(dqgf-` z0C)LYE4n`2$B0M@Wga`5%qkclWh@KDWCe*R+}J6KUk`2$p#@5yrlPZ3 zt!*dgyCkvMw5(m^MAq_GO{RKf0FCat zhS^r^Pt&dFH`A@zQ2f4NY#8c2xUn~+xSbwP?_a$+Dddzij8pc78Jg`pkd2=1v5ygW^-l2f7*yizVmTkq;+i zqHCX|p>p&!xbXOkBW!F18BT6}&2TL8qmeI9Gg!yC1oN>f88)1b!rg827aKD3kqYF6lmL8G z!o z;Qd9q z^GxKkO?l)y0m?34Vo}7iFcQ&%voV=townT}GpIMp=%s-f_`GcR<2C9d%7__6Q)#4N zp2%qD)MZrn#!nXA6wWlK1*piB&)ORSxQWEGPZ78IW@M-DmE>5pFs=%gUEn$}-pYrE zb~;0GVT~AB{XI5=;o=<~Pwuc_5E8<^dfPu>FQdni3YfwJ+vu(|g=fEAwZPN5;1J*x ze(C_HLj!BZ<3I-*+&oIO7P@XRzHC=pW)ojW_;0_o|7OnCog+dz zJPvbl@ByxczptTMR8#QaX+EWtsE+`d+0x#i3o&{F*|gFp-&Ls9P9_{o)JdJ=S|qHT z&5iJ(_H}N7^NTL=nZfsp9cIdQQK%xS=VuYRrgvEVZMk{~k3KKUP1jLy7*j>fs?ZXf zk<@G-cT+`E#ah8-Cer@Cz1!a6ib-az@K6RzNo~|8DrrrNK?;vZ_1zcmF?hwF} zpX$k1($n0xl}(ncFk=^;WC}^gro>yqvfgIABm1B-KFcKz8IU8R96_TP|JU%DR#Ohn z9~kHcX*+`a)twsx z(=YUvgr--kD@vI9n-SPlv%Rb!f9wwxP5Gu|A+O(D!BJFWfK)468*aE2XYdr*TEX#r z>frMYG_0kjx915f-8tl&gv1Tpl>UjNo7T6X6I88kph3(R%F3kkQNErPtj} zegxILlDY^0V_sQGUg3IyC_YbEh*Nxl7!=YE&T)RZ1qI7in zP(lb^4^Vr9f6F`+hhajNqfZB9Fbh`mBh#E%^vN=)5-0ZLy@8G$@%ps`EAxsUNhB#> zEXjiq2a3DVO-_rtsYtL8Y#5%LH3=xHYKiGn~`71VBcXRJ_DKIX`z4cL=@20 zp{=q#Vq~&`d z@IA2O4X~1Jz74%0Ir&F$@}t*X7K)x`NR5h159dqPaD&7Ss*7iP)rnj5VUyLtoA+x& zef26){5t=zKq{VatfqWtFixT*jf@&8uD%0!Q>Qsx!q0*8N0yyEq02(Qsu%7S?7o%n zaee^J`>*3Y6Z{iv^iK{%D}G}QO(Y;7q5nIq@gFp%=952)1o~GTnb)wlRcWTEkgA76 z90{qWp>YH-Ma!+x=nxc@jTJ3=t$WILO6=mK-o}xnf~13oBUxGqDI{ch-g~M5bvs96 zB5j~9CnNslRL`C7?$hz~SnucKB?3?jzyd9nvv99QY%NNOX{&l4AGdn2yG^10gBq1r z5#omlbYk=`ka%NVG3?PoMm5~g5NH@IG`2c5&anzlM0-?yJfA~VSz~EfiXle4VUhiN zBPQO$eI?$~Jts6KT%xvarc4%JU> z0(6tYS*OL}zf~zRSuOmO0?5-OumE5AC>GjF7CZi5lQB*nYnY9eB|WoJ*eel$Ok;gb z(}$lXXu;j7!;4{PYnSrm?I(Y;CGV;nzP~8h&!e&+JwNT+w64r$XGzc$zW3xH!hgWkn~LZ1pAA256pq!rU5B`szH#I1*7l#MQwmQEr2RdX>cxDXgv#I()Wx znUZnJ5{x|Y2Xg8Uc+W1v+bv2dgClzmMv4n`!g5x^eO8+mBadm)FbnO40t*hl%_4ub zOd0sHbtW_!CYUS|bhuDTydf z4{pu2voDi%M@71hx3b`aO!tk`!MG^Lj**cqLV$?#WSW=NRe-Tk?thf7iP_XtUBMR= z6@W3I;JD1`*OUX$x+(x{wq=FOH{3glH>F{%j!^)G)w)G?4LcE#txf2i`5XEj67ZTD zC`wO*L5SyHL`>51`y^XvR|hkmUATf<5Bu^n7?V_kCwR9)(Kz_=Ck@UOdn9lK2Poj@ z+YHvvsQwx^2ykUi;)4RW3}9a?Hv~SVd%f8FqZoz9N8qKzw35BW0GaINn-t8R5iR7~ z!>g5>SWWKmM%5ab3*ON& zUWkH-pC7#Xzb)E%=~`-NJnAXl47}KfD)hIu?sbtTSa{^Hu?q8AsOHfgxEJRkr~v#W zIXGBRj$$ch-0=;@cW_W-80{8=Nq9T)RyV-FIGVPP7bTR`mp;CJYNoGO8a1}tqFvKr`Zy-1Mj$n zug$n5!zv4oQ0DvCOH|cC_tZSiKke_(9g`?`hNofx@)&V@)oP90lK?zj-a{op4}R^o zBzw_eFR6UbX&PwMljisSY@&*aLPv!0&os-PEYKL+)J>|eN3cNZY~uan6P{u9b!PuY z{QVw<1`x>=M?QX0l<4TJpYvlAQK)ktQIq<0VW~eyMxkoB#)sb)rftMRh393P#vs|} zI8wwT{E-mFn-GIrx_8L_w-```y7Wm|adk~J@-$SqkI zO4^c86^A30B=~EH9f~bR;3b^s>fdX_OR^#H*@Li0-j(Q*zg|N;gKz+t zHA4O#Qd?jdp1SmrEXYfE+Ch0~r6A9BF@;Vio({$cKFq=DF=K*KCmi`g2#37@(w6IRi>8YQ%*f51BRU{kCmmwrzd3#Y77msiPw`n$r@BIz#uRHER|n zeGb3&!l4c!$-d}W4U>VkMbNyHcXla${DIa@23cYfBw~C)1=SR32#+X6T(?X%3LRgt z#!?pzD+&Avb61B9zFOeag*1w4A}$ma1Ns5>ehK!RObYDPIHnp4+9j%f0$Ofb2OS66 z#>c1#f=L4$g9apCr#=9kAg?+Az4%51%?sqDY7V8TakGp4eC=REhq|1K1-c)P(MO^g zB~kL^nXh%%Bkx`K7{z@iHRn>cgfG;%RHl*vX)pZj|Ig=Iy`V@0>w7&F_dDG3e;Hf< zKhv7>Znn1nnbgcl+O%I3L=5|CMxlVSf~G1%ho(Z!L|2m8LWQglloU%Tq_i&F;W=Be zy%1??3G70_a18v_wg>D%$eLpde-y`Hp#Jf4kk-;54M{dPLwF6xQ+V zLTUd&|F+Ucq|kkdKzGuYNZg`gLF7XN5@z9F7T@M7h6uR}GbMk>sn_t+k2Jh%SW%S; z)~1n?)QBCSGm#(?q5CvKJ?s;#`6bwdA9mUoKSJaxwED6B?+i2EWaG3xWvE3f`%DMs z1hbss+G{I@q7Lu!kTWe z&Cov(Dm){we_*zJx$I%Oo6o3{a4gTG=5ri;g-k@*0*q4p+KKloB^zLqE$Nb)VPfs` z8(z?C@8>Zr^Trn#C2ZileS|aA8cwVrbQKDnB7GD)y`oH98TOnfe8grsRcbHtnA3&i z4V8qj$DP3Eoxt4OYE*{QCJfueYo#3-RI*Eb--B1u3$3u^2H}huo3rNZjn9mo;%AXK z`g5XmMygR;ki#IK`9W^ zM0!C6m`~>Qb2S>J17<_34X8kS4<)`95j(OQ8Cw_Srn)WK?rNZQ(|0jVnsakp6Ym zl{wE)bZ~c^s}pH)>*Ye0K07N;7{^S_fNBoEK5J??OYcd0a^R31+@YxBX+sBB;{&-8 zuT;QjBQ{R=X3hGuyr`$`5X5sqqAn}*U}+^%Q^vlnY!n!KIG;Yfrq0Y;oaH_=w$@Qz z2DXHrv^x@#I(}N*=>n&1M>mzVqHmUQ$-*&EYPUuLAK8~{NSXt;?)^m=n=z`M270J} znrqTaF;1h}yl-hLh_fIJH60Vqec5C*LbYI_vt7HIv_D;aNoE0$ACO5=! zTtZ2URQKo@X0aWk+~f+bC|FI-iEX*TSm41g^G7n=_%~&%L1~^gTm6tW->9IaD-pWs zaQeu-86+P4D7$CUTa{ZX-ikdI z>hFnN@*$)D%NH+OimSmi|w|ysWK?Z1MF1`zFlkMQl6DrdemJsb{-`u1Obs z=@NrU(Z5EUPM1jNa*JA19#;I`Qr#|p*ZbMSTMnxoCs5>|ATaz_E8}Y3$LaIf%87DT z#K$%&%}mAX-$CQ)n+)k86JvNMj;|4$)6F(Ai42Nqg26NqNkh?(MEqy53u(BQ-(8!x z@%VhYsC?=Qcoy8cnyaa{s1$osJ>593auz17=xQ_ieP(11O+`O_6arPLl6k>48t-JD z*5pi;p+wNrgrPL+Moq4N#p0Cy(MWA-m5D3fZQwT)&PjF~m$IZU(QdzpX^fs^LB+RNyuRV;{s)>~rSR4Jp4OZJDSnQ+wvM4> zYu#e6?_B0+0KCqYd~9Ga(`UN{%rgxvhL4Vi%rB*t3yG!FJvHELKhgks{xb2{U zbD#Tjrw4zEIO5KEo&V0l6KQo5@lbPk8Nclr;p(WaUCT`RSAa_W>`g|MM13uSVq0a?vagkPP7tWT=GkJ8xr7=tr7(c7SpBeLaO1rgW){+v_##|~6-yQI60p9hErBzwjY zSJkA^$7>WW`x3@vkxCo$9twl)?F8U_WdnDI zHO{8cEvZdSzk+6Hn`gL&elKUROa87jP@k(!0Xc5;R^c7Sft>K*3wZ+AcK;c4 zHt%p;h0-LeD~_1@mX-Yg70(%a8dCxk<#gD^Gl1`o#533TBieR(Ht|B{Pm#g#45>!# z9$Qyb?*XpaN8*B?kXCPLlK}wkeZ*;5gpw@2vL2=Lw8wlaG|LIb$8`drv zwO>XbIDAHiUXbt6xdq;T@UktqLw#RiExff)WT(%M)iFLU7aD|%N09q-W5joB8r}+b3V_*AMO+iLGdXq{rIgPncK8V%IVLpbb{ArYsJ3 z9(XEYFr;7bP6^BiwNqTa;QBc?J91~p6VRUe5@1Z70jd6jWJbb7>AG#BY@kr7I>M?7VG)zQOmN27w!ce?o>PYZN*{NFbmXWFR2U|0BroFES}b^UVZT4eitZ zktu7M)UI_FEU}c#jw5SyM7YG(x;Rz}XDph$3AKq?ihR?Gy>oKPHZuTZ|A!A@P!ObX zz4gV9CPFzCMNy@S=jVQbvDa;$&Mdi3tHjcF7MGLk>+Jh&mznM)h0muQ2%yJ(0iz*D zIH|%N#sC?Nxx*YKeXRq} z>^((*cE*pFnrtt9_}#^upfC)u7T71=wH%MFKd!Se8BT9>qiigtboozao|p1CaVFd# z{Xf)4oI63`M_xx87bCM1a@jAFne4bD>))4>kI1+FWK8KAtH$MgXz{3J&z9U%(IjE2 zr_CIjfP7y438AX1*_}uaemP@W#Ah2>_?|9VjK)4N4YnM*7%AVh7J(QVaNCu}G==|k z^x1OF&Rut6IniF1rHE}SqviHHnckkxcx*c2RCPiwHYUw#9hI|&Sh5K$T^6N@&4{CM zoV;^_S&C~Ld0q-gP;n{;d+rG%V8oIXn{W-cb6Lp58&_~f#ncNt`Lkx_vL%PhhG!E5 zv%2oTk%T{CeyU)bYYd zc9+%wq!F!0T+En6+}!-LSbT98f#Y-ARJpCDI&3D zaN(xV&|m~l)&44S`_uv~@fFlPS?=fAT2^xzTq|$ZfWBbxp_E`_T&Dfb3?oOmzAw2= z8ATU|&_b3%XB9`FcYCR{%{5Ujf!&jvyeFScgcJ+th%5}FiITz*2_t1EV_*{e>#y{KzHgVeF(Gg??T({pT#+r=lXrjGSq zSdH4ue;zn)u;Ml{<*CGD`;{E5KF0z*g{Qf8MYgiOtB+ngDvfS>e#dK_!%lhP^^SJR z`r)N9)&iV`yoE;5y2=iGyTq&{+z|2nf2sHq{Q$hq?)tft0vL_=gN!YT1Pq7z0uD39HMLE}^d!$C4D!=U2ZCIfNASvY| z0p=LZoQ&SgD!mEAA;(HNhea+roV}D;PODS5odWTwuKN~aTALMbY5-Xf)K4eVs_Cdz z7iE4gJ~*>0(H^786C6#lOT=0!Prs7N=od9LL>kqUPO`DZT74S>3^Z+Z9VQ*N2rrgm z#qxS*4U}pQqjy#eHUX|K?+IL-D9?xUY1oIa+;BCYPk|a6-kd*cODha zAW_<07<>`}J@pOM+y9QL`=|E7`!x;`et`+8H96ZJEK1zmL!8DKghjOaMO4V#4C~PM z6Zm6%dV$suQnuk(Q&1u%x@ag~9>7;4^aN){@W*eoLNxWsY})(aeLTH56f9!;Z|BaAC!Sn=&y; z?zcnUy5@kHGMO|q^2XOm`h>Bxi?!v6-$pYlif(8n{jk$ODsKM$Ma^o}KqtL#?~As% zGipacU({oV59eHAguj{e`P&~j_Rcv$-`nSJBGI1xYtE22ZlAfh3k|;v`&GZtC+-MQ zwkU^uQTT3K_j?at3>I#`Nn6@()e`{i;eZw#txTfpR7N(JWQH$l+(ndI)ZHif@;E0x zu@>Ocb-#EXJ#-}&(2_^;ic~u8*PIw=qq>NC;ER1l_t~pZBsUaP;BAaB*E0GkUZ}28 z+gVX5)-c0};YCvgTuy?8qeB+Rlc=q#(>GHC14%0KSIvPC*TE`BLPg^vD)><`LADLB9m!wHO%311{ zt{ZOzO6c>I1{AoK3l6xpj%wteyUUa-4XUT3UDJRQt1GZ0>mmw$XSW>ZXoFr?A#Ro7 zxA3-8{C7p*o)%cYr@wo(DlfKJo_0`OEui{(K()rHf@Z3^XD&a@8?D2>zW#|iW-N=q z8o$XgVsIcJ<^K}u_#gVef0xOK*}K`fd@E=ET~1>lWa4V&VE->XQmtyEuwjVmM;!_h zgaL{>v%L+v{l~Qf$C9*)7%HepTKKUaZKdAYN=`>N^^b&{>~Vuxbly`@YECP2%G94p z%OscAu9G|d6RX|N_rHH30>Ee?`VRaM5f~{5iS~>TNzyIM`{U;c!3gSO!~~3|7+#Pp zKI;h%rUZ~~l0}FOs2m)wY^76TgJ>}($h;_8bLqa5XmG>saJ(jMudhvU;>@veg~0|D ztFvp?TC80t(QwRVwlp46t=Upit)u@w?&Kav#J%i16JAxS%QV_mG!0KTTAT^8;f`Cj z{wd#iJY!)FUFcAyvNe<8I?I+lRIsh~>A~dJtCGYyq8=PjWz*S8HHAOY_#i*wQG8&> zc{5{PemeG<@hNh~q_+;!wr)MIXf9cD(?;6Tn{?n>N*dNX5=3$vwv1{pu@Yy=Ip>I% zoVTU)R;y=i@lE^TplE~sX5+6+R)m$=I6&kF)h%2hy*$Gcs|quwy{MSoB9_A|g??j! z?cMtPH&lCsc5$~|J;G9veN$aTZ*fgDaj~T+Ui$b zjUmPsj>+I;Ifz(jzd#EPZY{_HpN}I~!3d#V^;ixQfld30CJHZ!uASlAKAYrk)>l7U z_IizsnadmN%rrCsIyBKExPEmymLO06ojgtw0Hq5SE+yPL-bk|s{Dk#`;>L$~2!O4X zhZC**>9%!x%wW`~hll$^;2vxT<)+Fozif|uea;Hoejc4xUO35&?if&jgJ^C}5f9*b zmuL^@jN!Rz=UTiWk$OxXm&gp!)7kA?B@Q~l{3HR@MLg7FJPrD_3TA`>`=ZN8>qBvP zHW&E&77uoU%>lxw{rJLAlOM#xvs4IIzkw;_%ql23n;Z@!GO28mDimvV);OkIQjJ$s zR2`-Fe_B-eH(6}T2rrz?cZsBZ^T#Ux4JD%D^{ptg`%g7ur?9Aq>PJuG$^Zub!wix* zsspYh=*}w1HZYLXOoyG2$d6F3x^Zsj8=KwKf+90v!{vP_jkrt-3u5%PZ60Rl=C+>j zc0c{AM964I2?0{L3JD1bi3!mn{auK&g_to(_w5my5yqmH-|uOdWp|aDjLp%v)k|#k zNF+h}jNdpUZ5j(@R(94-MfF?H8H+00pxYA3w!3U?2~TM)`(}8!dOrA-gkK?kMy|;V zzuBwx**si&IT0<}b`YpPRCS47LT|BiI z^8gYZraOgJZvss|nm6wnG*K+aR*OaYMJguMHl3YNfFdLHjF5CcajI#T>DoCJIv9#) zi6QnAk1?VY7>Oh^>^6B|!ET+NyyYnKIu58>7DOr1oM`PA4Cdh7v;jK)noldAJC0gU zo8(h~aGFGMI{F^)0*NpM1(?TS0^%U%h)`!xRe14mR9>L3_%0c7-k5Qlj5FbboYFh! zLe8_SNA@~b_WY@%w-fMdKZfPz~p3OPDr?#EdBOF0Z|_9uznNK9WG zgwYgjVTeadaItVwMDq>Y!p?8pcEJbS`nd?1f`rpAdG*7XmZx0TFwq0tKM&p=1&Bke z^{gUzWn&%ZcaSaxelbSVSfMtt$nwDrT>Pzt>$9p{GV>N z&G*g5^qZK_77ujlH4sgPO9l>V1-6d?i8djjA<<$bGE=9u#k1mx`5MS0CP6Bizv)-_ zq&)ZupAwDS+eYt|$9H{{ed4?6;`jdk4%bJU2#3f-&?my1$Vd&40@CxGkX04;2nd3q zHBk~57$n2`0h>3DX^NS|G{i`6k`8EyK?;L{q5<)C&dl6iS8c?Rl9MrC*pN5o%hgw* zT54)ZaDn|vq3<}|Kqe@qooYl8)p39s7Z9sjpc{pIKAdQDeMUAI`9~cdUY27&byxeE zI6O>`884hVXY6>`|L<6x?s7$PcD+rdgg=c`>FTnrGfl4i?=)%c?m6q@h1C&Xn{`?H z`|s7v9Bum-1pk1y0~(qb%52l+*eUj+g*A8H6csk$GYmHSasOfr8e8?O0>|oAbd)2F zuz=KLE37kVtJS*Jhizgn(jKehW+1-gjn()ENu}0D;!K-wGMZJ_1k0}6S%|^@qGjCu zi8KPeddk?}PJu;>k#12BdCo1k!_+gYVw;0}x=M)UiFUhsttpXV2;@$<;1umzx7=(1 z-FjmM`3%)(9r(77@GjSgs)2fW%Tx z|5IRkK&R;kFM9sFQ%Kjl*OHTi3C~cZ!f%1#G3fIew2*P?6RY$-()h(U!pYS1z<9p^ zRwgb-=&xIW2{Kux%ZQt7t1(sHOR5+7oVt?_jEEQZaS!MhP`GSRQF&}GrE@N;{o?gm zDHsZ&$Ru_74O96It~1Eo6F2aZ+96*xZhf!%C~-Oi1F@vkCyn{SqY`TE<}O{a&QyfN zN)?_!M<1qMrG-iHInnKh1Uw0rh+K6YgYT$yD~Ac5lftOyZ_4rk=-Zb_cOcb zF{L8jwl0Lze28nKvC+lUiqX4}-)hG1dCTWN{x`Llv)!z5RJYMLTxH#F zj|YnyKpJ&O0TEe3TLX4bC#1CCPT(HtT8T(d3;TNL^|U4-M#>|UgFl%^FiTBiSacJZ z`V~`{#vRp0PzTwdEPqU+>$+6bci5h$J=a~`_rr7=b8m! z#jvpSPm!{yV4^!#bW4G7%N$jR3_pmONML`*rD>C;LHFD%bb!&~;!z3kA&+*4Tvi}Y z-n$Cs6sR!P;Tn|yhmhdMd2=2E+QL!r<-IwF8Ci$Kg?J(%4Z#}`5y{x4#%c^v27bEY z_C1BA2ViOm7-W?`b7ep6W6bq;>lsD35X^f4C6Ku`k?9gv;)Vf;>2KYz;k80w`<%EjLc6BOrbzYbr zrxKvx%MKxxmv>p9aX~&VW^lz^om~&W;KWSqMSNmAd!vbvbHxgsA@7I{>W#!NB4l&g zpd6D6i4~5}{Qy10Vcik(e5)*HS(2Y4>^QTJ7-5td)-6gQWz#BS7bx(%R7Ua9pNDCi zxdoqTV49~VM#j{Rdk6hzm2#bjcBg!Uzr%0v_uo>b{~zeDIr;mIG(;W!LbzD5OOD5#4GJTv1m z^X27t@^JStdg1_Ne!~j_d`3ymNM$TJR7Cm8G#raNBAA>Q?=|d->2zf=An7PTV;o1M ztF)v{UweoJJ~?4?+4nbQM7`!XLoQ2*daVUOtJQIVO)sKV&4zQAYtIH-R>J|SQPbk? zA*b+|d42iAYt|9F^dfN~Wzym+#dq)#wR72V)L(#blJUJlRp~x-ze1U+>L^NPVr9X) zrft9r*~^TpwWg+8Rr=z{U~>OiTwYIuH7w1cV-{s&wHp0eO{U~)@Nq!dWz!H-QErp6 z1zT-UYq1i&I^wgvq!o6P%1vT-)l8=KqT!gURByJlQvq2ei*0*j4ln74DLM%J;jmZ{PlVyAc!7ku_P_r(vq6t1{2wtW_lJMcH^rp8cje zZpOLf(ZH=qI8!)h$;oQ4xXnvSKmEfF7Dn~qiHU^Bhx~gw6KV?_F%Wf}WV!1k97{l2 zC^ZE_AN~cyr1NX3`j3=El%ne<&bVT3vC*71oo5t$;oax7tF^;pqj9ik@$n{$C+*{b zA~6k_8`Osf*M9Ow0^E(5ZM493Y=1$;f_+3cFVQ7Ef=LHZ2UIYo*nt1@GRtg)eyL)H zU_?6@CxGDsrV|BPYr;X$Hm%fA!yl*dV9%`HFvg2dfL|ar5tmzR|D4`F>OK(9FCu+s6+dirybs!vDVy ztACST6$hn03x4%XvtsGP+`@Jtg1TAH#9xWR>=A*)Xq7av)bCG9XIRPEuHk{ffBwKP zRZ4;!>YidwmRkedG6ed%n}A~`!z`{Wzod+68r&xA0F3^W~tckP2vdQwTBr~FdWFP z!0p~uAAe%6+%Rr|uz~4cBN5%(?h`_{z;5Vo&eEy-)cMuQxc7BdpCgRw&Vafq6w@>8 z7U*cUYbZ_$KI{>&KS4Y8OU1l2oc8_Y2f@Z5rjrlo;vnNn9Slzs3bqZqgb9v@f-DXM z{<4i^_`xBPNQ6r^f{)tv;lB@X{3(xv>7*Y%80mlb!1w=lWo2v(jU4{HsL4>SXrlA| zllq2=u>I*bi(-df5c?qHC$s#CZ}91sW+4d=Fep+)~J z_#}myS(2{uXZO{gvn#&mv4`=b#Uc}Dhn2^(zJQNaq?TT=Dal=kk~ww9 za?g7VG@M$MQ!MYQ^7)n3ED{Dg_p*L^jN6}{O|mkbK(tbdopEXgRhc&+TEQBri7%bS zlcnEkwM)N>)7?xPc!;soU3$QGzu+0jUITJh@ z6FCsvUq%fec{M7xCU|rv3?R5ajw*xjsTYDw(@FO2Kxv`7lpuWig(A~*vV9m(TKKNH zpel^>mt+%I_iR0rEVuehau{dC^Ff{LU(CF>EsJ#rsZhY9-Y?0SI&a;Uyl)4&QPy~I!}eJtOeBsn$V)(&jVQrTzLu7qa1%^VTWxNtNdZgN3p*H;`QC_2I&wj5Sv<~UrTl3i(WAb zRv;hSu{1!t*XhY-KICT3L*Jq%%fh*r>5XSLDNh_h{6rt!gZQIUxi{${IDrH4^V?_w z#2@*}gh>z4i4=&RXruEGf7C1ICq0BGG$DSXj5a|0QLb#5TqfJs=v)=N(iXHqd1pad z!?a0L*Yhq*;dUV@ARd4}z> zgI0+b8ce;&_y2%ABX*HMtK*kN1gOXSM)qH?i8^7Dl_mlpO-$_t3BK{bj2a5E!=;1rzh29C zDo#qHTr+k~Pr}1IHm;vcSkmvKcXDSQKtKAf16i~MGfYjQGWVOC*A$3T3vt{5yW zu#chZD-*|b`zoD3GZz&nOd!wvjBNxnP+F0aJs~}H&b>@;F|Hvyp)xt;CNLlge0TK( zb&)-wlZ7EY)z5*Zh#1#so#L6C3KOc31b(}wg1RUk@W}>{p4#VsCUD93ao#IWclkhV zl=rSInM|{B>PLCvyfdw!3G#U$k7)FPx14Y$yBQS77)R&-QS=#a@Q}((-5Az z=Le?7u#dmjzpoYT;(|wG~Gc#b*1B}};Ghn>F zCPRX}=v;}CML}Lfu8heJkS_}7Zl?G&`>LRXOita26A%GtHw)xN%dxBJ)tI>ktrNWa z4dg}biaN?9*pAYQI|?hx=q-Ox=G? z<^Py#|C-wWG5P;B75`)6fec=EsNP;lId*l+FVEKgHHrUYw*PCA|1}lJp~D{%N<1Y0 zi4dLp&v(pBos4hxafnUpiQY{^za{@^ydZ`9>uH(r{hxlRUvaPKRo!U+0YqBE@=uS> zDagO5!LTrYUA1Oq{^B7my!|HtwbMUciUz*@?fF1X^EXa(IQ8ERQ`kRfrU2sq#8Kq> zCxFP*KSysALHADpBS*A<_L-gX7nc;`%0D|3+b4RD@LH+I``2WLn*+S>^qH~K{V!ab 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 X4&eY-g5SEtqQzox1|>`onet.countercraft movecraft Movecraft - 7.0.0_for_1.8.8-1.16.2_beta_37 + 7.0.0_for_1.8.8-1.16.2_beta_37_TOWNY http://github.com/apdevteam/Movecraft src/main/java @@ -233,13 +233,6 @@ RELEASE compile - - com.palmergames - Towny - LATEST - system - ${project.basedir}/../../libs/Towny.jar - com.mewin WGCustomFlags diff --git a/modules/Movecraft/pom.xml b/modules/Movecraft/pom.xml index 6ac1485b4..815858378 100644 --- a/modules/Movecraft/pom.xml +++ b/modules/Movecraft/pom.xml @@ -10,7 +10,7 @@ UTF-8 - 7.0.0_for_1.8.8-1.16.2_beta_37 + 7.0.0_for_1.8.8-1.16.2_beta_37_TOWNY @@ -144,14 +144,6 @@ 2.16.1 provided - - - com.palmergames - Towny - LATEST - system - ${project.basedir}/../../libs/Towny.jar - com.mewin WGCustomFlags diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java index 1b8432567..244e16d8b 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java @@ -19,7 +19,6 @@ import com.earth2me.essentials.Essentials; import com.mewin.WGCustomFlags.WGCustomFlagsPlugin; -import com.palmergames.bukkit.towny.Towny; import com.sk89q.worldguard.bukkit.WorldGuardPlugin; import net.countercraft.movecraft.async.AsyncManager; import net.countercraft.movecraft.commands.*; @@ -32,16 +31,13 @@ import net.countercraft.movecraft.localisation.I18nSupport; import net.countercraft.movecraft.mapUpdater.MapUpdateManager; import net.countercraft.movecraft.sign.*; -import net.countercraft.movecraft.towny.TownyCompatManager; import net.countercraft.movecraft.utils.LegacyUtils; -import net.countercraft.movecraft.utils.TownyUtils; import net.countercraft.movecraft.utils.UpdateManager; import net.countercraft.movecraft.worldguard.WorldGuardCompatManager; import org.bukkit.Material; import org.bukkit.configuration.file.FileConfiguration; import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.plugin.Plugin; -import org.bukkit.plugin.RegisteredServiceProvider; import org.bukkit.plugin.java.JavaPlugin; import java.io.*; @@ -56,7 +52,6 @@ public class Movecraft extends JavaPlugin { private static Movecraft instance; private static WorldGuardPlugin worldGuardPlugin; private static WGCustomFlagsPlugin wgCustomFlagsPlugin = null; - private static Towny townyPlugin = null; private static Essentials essentialsPlugin = null; private Logger logger; private boolean shuttingDown; @@ -230,20 +225,6 @@ public void onEnable() { getServer().getPluginManager().registerEvents(new WorldGuardCompatManager(), this); } - Plugin tempTownyPlugin = getServer().getPluginManager().getPlugin("Towny"); - if (tempTownyPlugin != null && tempTownyPlugin instanceof Towny) { - logger.log(Level.INFO, I18nSupport.getInternationalisedString("Startup - Towny Found")); - townyPlugin = (Towny) tempTownyPlugin; - TownyUtils.initTownyConfig(); - Settings.TownyBlockMoveOnSwitchPerm = getConfig().getBoolean("TownyBlockMoveOnSwitchPerm", false); - Settings.TownyBlockSinkOnNoPVP = getConfig().getBoolean("TownyBlockSinkOnNoPVP", false); - getServer().getPluginManager().registerEvents(new TownyCompatManager(), this); - logger.log(Level.INFO, "Settings: TownyBlockMoveOnSwitchPerm - {0}", Settings.TownyBlockMoveOnSwitchPerm); - logger.log(Level.INFO, "Settings: TownyBlockSinkOnNoPVP - {0}", Settings.TownyBlockSinkOnNoPVP); - - } else { - logger.log(Level.INFO, I18nSupport.getInternationalisedString("Startup - Towny Not Found")); - } //Essentials Plugin tempEssentialsPlugin = getServer().getPluginManager().getPlugin("Essentials"); if (tempEssentialsPlugin != null) { @@ -369,10 +350,6 @@ public WGCustomFlagsPlugin getWGCustomFlagsPlugin() { return wgCustomFlagsPlugin; } - public Towny getTownyPlugin() { - return townyPlugin; - } - public Essentials getEssentialsPlugin() { return essentialsPlugin; } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/rotation/RotationTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/rotation/RotationTask.java index a0abcc718..ee157029f 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/rotation/RotationTask.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/rotation/RotationTask.java @@ -17,8 +17,6 @@ package net.countercraft.movecraft.async.rotation; -import com.palmergames.bukkit.towny.object.TownBlock; -import com.palmergames.bukkit.towny.object.TownyWorld; import net.countercraft.movecraft.CruiseDirection; import net.countercraft.movecraft.MovecraftLocation; import net.countercraft.movecraft.Rotation; @@ -55,11 +53,6 @@ public class RotationTask extends AsyncTask { //private int[][][] hitbox; //private Integer minX, minZ; - private boolean townyEnabled; - private Set townBlockSet; - private TownyWorld townyWorld; - private TownyWorldHeightLimits townyWorldHeightLimits; - private final BitmapHitBox oldHitBox; private final BitmapHitBox newHitBox; private final BitmapHitBox oldFluidList; @@ -123,9 +116,7 @@ protected void execute() throws ExecutionException, InterruptedException { break; } - //TODO: ADD TOWNY //TODO: ADD FACTIONS - //isTownyBlock(plugLoc,craftPilot); if (!withinWorldBorder(craft.getWorld(), newLocation)) { failMessage = I18nSupport.getInternationalisedString("Rotation - Failed Craft cannot pass world border") + String.format(" @ %d,%d,%d", newLocation.getX(), newLocation.getY(), newLocation.getZ()); failed = true; diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java index 0c2251408..d7897750f 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java @@ -299,7 +299,6 @@ protected void execute() throws InterruptedException, ExecutionException { } - //TODO: Add and handle event for towny and factions final List harvestBlocks = craft.getType().getHarvestBlocks(); final List harvestedBlocks = new ArrayList<>(); final List harvesterBladeBlocks = craft.getType().getHarvesterBladeBlocks(); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/towny/TownyCompatManager.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/towny/TownyCompatManager.java deleted file mode 100644 index 1ff895989..000000000 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/towny/TownyCompatManager.java +++ /dev/null @@ -1,143 +0,0 @@ -package net.countercraft.movecraft.towny; - -import com.palmergames.bukkit.towny.object.Town; -import com.palmergames.bukkit.towny.object.TownBlock; -import com.palmergames.bukkit.towny.object.TownyWorld; -import net.countercraft.movecraft.MovecraftLocation; -import net.countercraft.movecraft.config.Settings; -import net.countercraft.movecraft.craft.Craft; -import net.countercraft.movecraft.events.*; -import net.countercraft.movecraft.localisation.I18nSupport; -import net.countercraft.movecraft.utils.HitBox; -import net.countercraft.movecraft.utils.TownyUtils; -import net.countercraft.movecraft.utils.TownyWorldHeightLimits; -import org.bukkit.Location; -import org.bukkit.entity.Player; -import org.bukkit.event.EventHandler; -import org.bukkit.event.Listener; - -import java.util.HashSet; -import java.util.Set; - -public class TownyCompatManager implements Listener { - - @EventHandler - public void onCraftTranslate(CraftTranslateEvent event){ - final Set townBlocks = new HashSet<>(); - final Craft craft = event.getCraft(); - final TownyWorld townyWorld = TownyUtils.getTownyWorld(craft.getWorld()); - if (!Settings.TownyBlockMoveOnSwitchPerm) - return; - for (MovecraftLocation ml : event.getNewHitBox()) { - - TownBlock townBlock = TownyUtils.getTownBlock(ml.toBukkit(event.getCraft().getWorld())); - if (townBlock == null || townBlocks.contains(townBlock)) { - continue; - } - if (TownyUtils.validateCraftMoveEvent(craft.getNotificationPlayer(), ml.toBukkit(craft.getWorld()), townyWorld)) { - townBlocks.add(townBlock); - continue; - } - Town town = TownyUtils.getTown(townBlock); - if (town == null) - continue; - final TownyWorldHeightLimits whLim = TownyUtils.getWorldLimits(event.getCraft().getWorld()); - final Location spawnLoc = TownyUtils.getTownSpawn(townBlock); - if (whLim.validate(ml.getY(), spawnLoc.getBlockY())) { - continue; - } - event.setFailMessage(String.format(I18nSupport.getInternationalisedString("Towny - Translation Failed") + " %s @ %d,%d,%d", town.getName(), ml.getX(), ml.getY(), ml.getZ())); - event.setCancelled(true); - break; - } - - } - - @EventHandler - public void onCraftRotate(CraftRotateEvent event) { - final Set townBlocks = new HashSet<>(); - final Craft craft = event.getCraft(); - final TownyWorld townyWorld = TownyUtils.getTownyWorld(craft.getWorld()); - if (!Settings.TownyBlockMoveOnSwitchPerm) - return; - for (MovecraftLocation ml : event.getNewHitBox()) { - - TownBlock townBlock = TownyUtils.getTownBlock(ml.toBukkit(event.getCraft().getWorld())); - if (townBlock == null || townBlocks.contains(townBlock)) { - continue; - } - if (TownyUtils.validateCraftMoveEvent(craft.getNotificationPlayer(), ml.toBukkit(craft.getWorld()), townyWorld)) { - townBlocks.add(townBlock); - continue; - } - Town town = TownyUtils.getTown(townBlock); - if (town == null) - continue; - final TownyWorldHeightLimits whLim = TownyUtils.getWorldLimits(event.getCraft().getWorld()); - final Location spawnLoc = TownyUtils.getTownSpawn(townBlock); - if (whLim.validate(ml.getY(), spawnLoc.getBlockY())) { - continue; - } - event.setFailMessage(String.format(I18nSupport.getInternationalisedString("Towny - Rotation Failed") + " %s @ %d,%d,%d", town.getName(), ml.getX(), ml.getY(), ml.getZ())); - event.setCancelled(true); - break; - } - } - - @EventHandler - public void onHitboxDetect(CraftDetectEvent event) { - final Set townBlocks = new HashSet<>(); - final Craft craft = event.getCraft(); - final TownyWorld townyWorld = TownyUtils.getTownyWorld(craft.getWorld()); - for (MovecraftLocation ml : event.getCraft().getHitBox()) { - - TownBlock townBlock = TownyUtils.getTownBlock(ml.toBukkit(event.getCraft().getWorld())); - if (townBlock == null || townBlocks.contains(townBlock)) { - continue; - } - if (TownyUtils.validateCraftMoveEvent(craft.getNotificationPlayer(), ml.toBukkit(craft.getWorld()), townyWorld)) { - townBlocks.add(townBlock); - continue; - } - Town town = TownyUtils.getTown(townBlock); - if (town == null) - continue; - final TownyWorldHeightLimits whLim = TownyUtils.getWorldLimits(event.getCraft().getWorld()); - final Location spawnLoc = TownyUtils.getTownSpawn(townBlock); - if (whLim.validate(ml.getY(), spawnLoc.getBlockY())) { - continue; - } - event.setFailMessage(String.format(I18nSupport.getInternationalisedString("Towny - Detection Failed") + " %s @ %d,%d,%d", town.getName(), ml.getX(), ml.getY(), ml.getZ())); - event.setCancelled(true); - break; - } - } - - @EventHandler - public void onCraftSink(CraftSinkEvent event) { - final Set townBlocks = new HashSet<>(); - final Craft craft = event.getCraft(); - if (!Settings.TownyBlockSinkOnNoPVP) - return; - final HitBox hitBox = craft.getHitBox(); - if (hitBox.isEmpty()) - return; - for (MovecraftLocation ml : hitBox) { - - TownBlock townBlock = TownyUtils.getTownBlock(ml.toBukkit(event.getCraft().getWorld())); - if (townBlock == null || townBlocks.contains(townBlock)) { - continue; - } - if (TownyUtils.validatePVP(townBlock)) { - townBlocks.add(townBlock); - continue; - } - final Player notifyP = craft.getNotificationPlayer(); - if (notifyP != null) { - notifyP.sendMessage(String.format(I18nSupport.getInternationalisedString("Towny - Sinking a craft is not allowed in this town plot") + " @ %d,%d,%d", ml.getX(), ml.getY(), ml.getZ())); - } - event.setCancelled(true); - break; - } - } -} diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/TownyUtils.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/TownyUtils.java deleted file mode 100644 index 43e542498..000000000 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/TownyUtils.java +++ /dev/null @@ -1,262 +0,0 @@ -package net.countercraft.movecraft.utils; - -import com.palmergames.bukkit.towny.exceptions.NotRegisteredException; -import com.palmergames.bukkit.towny.exceptions.TownyException; -import com.palmergames.bukkit.towny.object.Coord; -import com.palmergames.bukkit.towny.object.PlayerCache; -import com.palmergames.bukkit.towny.object.PlayerCache.TownBlockStatus; -import com.palmergames.bukkit.towny.object.Resident; -import com.palmergames.bukkit.towny.object.Town; -import com.palmergames.bukkit.towny.object.TownBlock; -import com.palmergames.bukkit.towny.object.TownyPermission; -import com.palmergames.bukkit.towny.object.TownyUniverse; -import com.palmergames.bukkit.towny.object.TownyWorld; -import com.palmergames.bukkit.towny.utils.PlayerCacheUtil; -import com.palmergames.bukkit.towny.war.flagwar.TownyWarConfig; -import net.countercraft.movecraft.Movecraft; -import net.countercraft.movecraft.config.Settings; -import net.countercraft.movecraft.localisation.I18nSupport; -import org.bukkit.Location; -import org.bukkit.Material; -import org.bukkit.World; -import org.bukkit.configuration.ConfigurationSection; -import org.bukkit.configuration.file.FileConfiguration; -import org.bukkit.entity.Player; - -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.logging.Level; - -/** - * @author mwkaicz - */ -public class TownyUtils { - public static final String TOWN_MIN = "worldMin"; - public static final String TOWN_MAX = "worldMax"; - public static final String TOWN_ABOVE = "aboveTownSpawn"; - public static final String TOWN_UNDER = "underTownSpawn"; - public static final String TOWN_HEIGHT_LIMITS = "TownyWorldHeightLimits"; - - private static Method GET_CACHE_PERMISSION_NON_LEGACY; - - static { - try { - GET_CACHE_PERMISSION_NON_LEGACY = PlayerCacheUtil.class.getDeclaredMethod("getCachePermission", Player.class, Location.class, Material.class, TownyPermission.ActionType.class); - } catch (NoSuchMethodException e) { - GET_CACHE_PERMISSION_NON_LEGACY = null; - } - } - - public static TownyWorld getTownyWorld(World w) { - TownyWorld tw; - try { - tw = TownyUniverse.getDataSource().getWorld(w.getName()); - if (!tw.isUsingTowny()) - return null; - } catch (NotRegisteredException e) { - return null; - } - return tw; - } - - public static TownBlock getTownBlock(Location loc) { - Coord coo = Coord.parseCoord(loc); - TownyWorld tw = getTownyWorld(loc.getWorld()); - TownBlock tb = null; - try { - if (tw != null) { - tb = tw.getTownBlock(coo); - } - } catch (NotRegisteredException ex) { - //Logger.getLogger(TownyUtils.class.getName()).log(Level.SEVERE, null, ex); - //free land - } - return tb; - } - - public static Town getTown(TownBlock townBlock) { - try { - Town town; - town = townBlock.getTown(); - return town; - } catch (TownyException e) { - //Logger.getLogger(TownyUtils.class.getName()).log(Level.SEVERE, null, ex); - //none - } - return null; - } - - public static Location getTownSpawn(TownBlock townBlock) { - if (townBlock == null) return null; - Town t = getTown(townBlock); - if (t != null) { - try { - return t.getSpawn(); - } catch (TownyException ex) { - Movecraft.getInstance().getLogger().log(Level.SEVERE, String.format(I18nSupport.getInternationalisedString("Towny - Spawn Not Found"),t.getName()), ex); - //town hasn't spawn - } - } - return null; - } - - - public static boolean validateResident(Player player) { - Resident resident; - try { - resident = TownyUniverse.getDataSource().getResident(player.getName()); - return true; - } catch (TownyException e) { - //System.out.print("Failed to fetch resident: " + player.getName()); - //return TownBlockStatus.NOT_REGISTERED; - } - return false; - } - - public static boolean validateCraftMoveEvent(Player player, Location loc, TownyWorld world) { - // Get switch permissions (updates if none exist) - if (player != null && !validateResident(player)) { - return true; //probably NPC or CBWrapper Dummy player - } - Material type = Material.STONE_BUTTON; - byte data = 0; - - boolean bSwitch; - if (GET_CACHE_PERMISSION_NON_LEGACY != null) { - try { - bSwitch = (boolean) GET_CACHE_PERMISSION_NON_LEGACY.invoke(player, loc, type, TownyPermission.ActionType.SWITCH); - } catch (IllegalAccessException | InvocationTargetException e) { - bSwitch = true; - } - } else { - bSwitch = PlayerCacheUtil.getCachePermission(player, loc, type.getId(), data, TownyPermission.ActionType.SWITCH); - } - - - // Allow move if we are permitted to switch - if (bSwitch) - return true; - - PlayerCache cache = Movecraft.getInstance().getTownyPlugin().getCache(player); - TownBlockStatus status = cache.getStatus(); - - return !cache.hasBlockErrMsg() && status == TownBlockStatus.WARZONE && TownyWarConfig.isAllowingSwitchesInWarZone(); - - } - - public static boolean validatePVP(TownBlock tb) { - Town t = getTown(tb); - if (t != null) { - return t.getPermissions().pvp || tb.getPermissions().pvp; - } else { - return tb.getPermissions().pvp; - } - } - - public static boolean validateExplosion(TownBlock tb) { - Town t = getTown(tb); - if (t != null) { - return t.getPermissions().explosion || tb.getPermissions().explosion; - } else { - return tb.getPermissions().explosion; - } - } - - public static void initTownyConfig() { - Settings.TownProtectionHeightLimits = getTownyConfigFromUniverse(); - loadTownyConfig(); - } - - private static Map getTownyConfigFromUniverse() { - Map worldsMap = new HashMap<>(); - List worlds = Movecraft.getInstance().getServer().getWorlds(); - for (World w : worlds) { - TownyWorld tw = getTownyWorld(w); - if (tw != null) { - if (tw.isUsingTowny()) { - worldsMap.put(w.getName(), new TownyWorldHeightLimits()); - } - } - } - return worldsMap; - } - - public static TownyWorldHeightLimits getWorldLimits(World w) { - boolean oNew = false; - String wName = w.getName(); - Map worldsMap = Settings.TownProtectionHeightLimits; - if (!worldsMap.containsKey(wName)) { - TownyWorld tw = getTownyWorld(w); - if (tw != null) { - if (tw.isUsingTowny()) { - worldsMap.put(wName, new TownyWorldHeightLimits()); - Settings.TownProtectionHeightLimits = worldsMap; - Movecraft.getInstance().getLogger().log(Level.INFO, I18nSupport.getInternationalisedString("Towny - Added Config Defaults"), w.getName()); - oNew = true; - } else { - return null; - } - } else { - return null; - } - } - if (oNew) { - saveWorldLimits(); - } - return worldsMap.get(wName); - } - - private static void saveWorldLimits() { - Map worldsMap = Settings.TownProtectionHeightLimits; - Map townyWorldsMap = new HashMap<>(); - Set worlds = worldsMap.keySet(); - - for (String world : worlds) { - World w = Movecraft.getInstance().getServer().getWorld(world); - if (w != null) { - TownyWorld tw = getTownyWorld(w); - if (tw != null) { - if (tw.isUsingTowny()) { - Map townyTWorldMap = new HashMap<>(); - TownyWorldHeightLimits twhl = worldsMap.get(world); - townyTWorldMap.put(TOWN_MIN, twhl.world_min); - townyTWorldMap.put(TOWN_MAX, twhl.world_max); - townyTWorldMap.put(TOWN_ABOVE, twhl.above_town); - townyTWorldMap.put(TOWN_UNDER, twhl.under_town); - townyWorldsMap.put(world, townyTWorldMap); - Movecraft.getInstance().getConfig().set(TOWN_HEIGHT_LIMITS + "." + world, townyTWorldMap); - } - } - } - } - Movecraft.getInstance().saveConfig(); - Movecraft.getInstance().getLogger().log(Level.INFO, I18nSupport.getInternationalisedString("Towny - Saved Settings")); - } - - private static void loadTownyConfig() { - FileConfiguration fc = Movecraft.getInstance().getConfig(); - ConfigurationSection csObj = fc.getConfigurationSection(TOWN_HEIGHT_LIMITS); - Map townyWorldHeightLimits = new HashMap<>(); - - if (csObj != null) { - Set worlds = csObj.getKeys(false); - for (String worldName : worlds) { - TownyWorldHeightLimits twhl = new TownyWorldHeightLimits(); - twhl.world_min = fc.getInt(TOWN_HEIGHT_LIMITS + "." + worldName + "." + TOWN_MIN, TownyWorldHeightLimits.DEFAULT_WORLD_MIN); - twhl.world_max = fc.getInt(TOWN_HEIGHT_LIMITS + "." + worldName + "." + TOWN_MAX, TownyWorldHeightLimits.DEFAULT_WORLD_MAX); - twhl.above_town = fc.getInt(TOWN_HEIGHT_LIMITS + "." + worldName + "." + TOWN_ABOVE, TownyWorldHeightLimits.DEFAULT_TOWN_ABOVE); - twhl.under_town = fc.getInt(TOWN_HEIGHT_LIMITS + "." + worldName + "." + TOWN_UNDER, TownyWorldHeightLimits.DEFAULT_TOWN_UNDER); - townyWorldHeightLimits.put(worldName, twhl); - Movecraft.getInstance().getLogger().log(Level.INFO, I18nSupport.getInternationalisedString("Towny - Loaded Settings"), worldName); - } - } - if (!townyWorldHeightLimits.equals(Settings.TownProtectionHeightLimits)) { - Settings.TownProtectionHeightLimits.putAll(townyWorldHeightLimits); - saveWorldLimits(); - } - } -} diff --git a/modules/Movecraft/src/main/resources/config.yml b/modules/Movecraft/src/main/resources/config.yml index 5ccb0e2ee..504387dfe 100644 --- a/modules/Movecraft/src/main/resources/config.yml +++ b/modules/Movecraft/src/main/resources/config.yml @@ -57,14 +57,6 @@ WGCustomFlagsUseSinkFlag: false DurabilityOverride: end_stone: 80 end_stone_bricks: 80 -TownyBlockMoveOnSwitchPerm: false -TownyBlockSinkOnNoPVP: false -TownyWorldHeightLimits: - world: - worldMin: -1 - worldMax: -1 - aboveTownSpawn: 96 - underTownSpawn: 255 ForbiddenRemoteSigns: # These strings will be ignored when searching for signs to trigger from a remote sign - "Mounted" - "Denied" diff --git a/modules/Movecraft/src/main/resources/config_legacy.yml b/modules/Movecraft/src/main/resources/config_legacy.yml index af42238cf..e405a049f 100644 --- a/modules/Movecraft/src/main/resources/config_legacy.yml +++ b/modules/Movecraft/src/main/resources/config_legacy.yml @@ -115,11 +115,3 @@ WGCustomFlagsUseSinkFlag: false DurabilityOverride: ENDER_STONE: 80 END_BRICKS: 80 -TownyBlockMoveOnSwitchPerm: false -TownyBlockSinkOnNoPVP: false -TownyWorldHeightLimits: - world: - worldMin: -1 - worldMax: -1 - aboveTownSpawn: 96 - underTownSpawn: 255 diff --git a/modules/Movecraft/src/main/resources/localisation/movecraftlang_cz.properties b/modules/Movecraft/src/main/resources/localisation/movecraftlang_cz.properties index b2feb4fae..705c34fcf 100644 --- a/modules/Movecraft/src/main/resources/localisation/movecraftlang_cz.properties +++ b/modules/Movecraft/src/main/resources/localisation/movecraftlang_cz.properties @@ -93,10 +93,6 @@ Repairs\ underway=Probihaji opravy Repairs\ complete\.\ You\ may\ now\ pilot\ the\ craft=Opravy dokonceny. Nyni muzes ridit stroj You\ do\ not\ have\ enough\ money=Nemas dostatek penez Need\ more\ of\ material=Je potreba vice materialu -Towny\ -\ Detection\ Failed=Detekce selhala - Nemas pravo ridit stroj na teto parcele ve meste -Towny\ -\ Translation\ Failed=Stroj se nemuze pohnout - Nemas pravo hybat se strojem na teto parcele ve meste -Towny\ -\ Rotation\ Failed=Stroj se nemuze otocit - Nemas pravo otocit stroj na teto parcele ve meste -Towny\ -\ Sinking\ a\ craft\ is\ not\ allowed\ in\ this\ town\ plot=Potopeni stroje neni povoleno na teto parcele mesta\! WGCustomFlags\ -\ Translation\ Failed=Stroj se nemuze pohnout - Nemas pravo hybat se strojem v tomto WorldGuard regionu WGCustomFlags\ -\ Rotation\ Failed=Stroj se nemuze otocit - Nemas pravo otocit stroj v tomto WorldGuard regionu WGCustomFlags\ -\ Detection\ Failed=Detekce selhala - Nemas pravo ridit stroj v tomto WorldGuard regionu diff --git a/modules/Movecraft/src/main/resources/localisation/movecraftlang_en.properties b/modules/Movecraft/src/main/resources/localisation/movecraftlang_en.properties index c0c76d6e7..b33b1fe47 100644 --- a/modules/Movecraft/src/main/resources/localisation/movecraftlang_en.properties +++ b/modules/Movecraft/src/main/resources/localisation/movecraftlang_en.properties @@ -132,8 +132,6 @@ Startup\ -\ WG\ Found=Found a compatible version of WorldGuard. Enabling WorldGu Startup\ -\ WG\ Not\ Found=Movecraft did not find a compatible version of WorldGuard. Disabling WorldGuard integration. Startup\ -\ WGCF\ Found=Found a compatible version of WGCustomFlags. Enabling WGCustomFlags integration. Startup\ -\ WGCF\ Not\ Found=Movecraft did not find a compatible version of WGCustomFlags. Disabling WGCustomFlags integration. -Startup\ -\ Towny\ Found=Found a compatible version of Towny. Enabling Towny integration. -Startup\ -\ Towny\ Not\ Found=Movecraft did not find a compatible version of Towny. Disabling Towny integration. Startup\ -\ Essentials\ Found=Found a compatible version of Essentials. Enabling Essentials integration. Startup\ -\ Essentials\ Not\ Found=Movecraft did not find a compatible version of Essentials. Disabling Essentials integration. Teleportation\ -\ Cooldown\ active=Teleportation cooldown is active. You need to wait %d seconds @@ -157,14 +155,6 @@ Direct\ Control\ -\ Leaving=Leaving Direct Control Mode Crew\ Sign\ -\ Can\ only\ create\ for\ yourself=You can only create a Crew\: sign for yourself You\ must\ be\ piloting\ a\ craft=You must be piloting a craft SIB\ MUST\ BE\ PLACED\ IN\ REGION=SIB MUST BE PLACED IN REGION -Towny\ -\ Detection\ Failed=Detection Failed - You are not permitted to pilot a craft on this plot in the town -Towny\ -\ Translation\ Failed=Translation Failed - You are not permitted to move a craft on this plot in the town -Towny\ -\ Rotation\ Failed=Rotation Failed - You are not permitted to rotate a craft on this plot in the town -Towny\ -\ Sinking\ a\ craft\ is\ not\ allowed\ in\ this\ town\ plot=Sinking a craft is not allowed in this town plot\! -Towny\ -\ Spawn\ Not\ Found=Town spawn of %s not found\! -Towny\ -\ Added\ Config\ Defaults=Added default Towny settings for world {0} to the config file. -Towny\ -\ Saved\ Settings=Saved settings for Towny worlds to the config file. -Towny\ -\ Loaded\ Settings=Loaded Towny settings for world {0} WGCustomFlags\ -\ Translation\ Failed=Translation Failed - You are not permitted to move a craft in this WorldGuard region WGCustomFlags\ -\ Rotation\ Failed=Rotation Failed - You are not permitterd to rotate a craft in this WorldGuard region WGCustomFlags\ -\ Detection\ Failed=Detection Failed - You are not permitted to pilot a craft in this WorldGuard region diff --git a/modules/Movecraft/src/main/resources/localisation/movecraftlang_no.properties b/modules/Movecraft/src/main/resources/localisation/movecraftlang_no.properties index 78ec54b07..7039fb6bc 100644 --- a/modules/Movecraft/src/main/resources/localisation/movecraftlang_no.properties +++ b/modules/Movecraft/src/main/resources/localisation/movecraftlang_no.properties @@ -75,10 +75,6 @@ Repairs\ underway=Reparasjon underveis Repairs\ complete\.\ You\ may\ now\ pilot\ the\ craft=Reparasjon fullført. du kan nå ta kommando over fartøyet You\ do\ not\ have\ enough\ money=Du har ikke nok penger Need\ more\ of\ material=Trenger mer materiale -Towny\ -\ Detection\ Failed=Gjenkjenning mislyktes - Du har ikke tillatelse til å ta kommando over et fartøy på denne tomt i byen -Towny\ -\ Translation\ Failed=Translasjon mislyktes - Du har ikke tillatelse til å flytte et fartøy på denne tomt i byen -Towny\ -\ Rotation\ Failed=Rotasjon mislyktes - Du har ikke tillatelse til å ta rotere et fartøy på denne tomt i byen -Towny\ -\ Sinking\ a\ craft\ is\ not\ allowed\ in\ this\ town\ plot=Det tillates ikke å senke et fartøy i denne bytomten\! WGCustomFlags\ -\ Translation\ Failed=Translasjon mislyktes - Du har ikke tillatelse til å flytte et fartøy i denne WorldGuard-regionen WGCustomFlags\ -\ Rotation\ Failed=Rotasjon mislyktes - Du har ikke tillatelse til å rotere et fartøy i denne WorldGuard-regionen WGCustomFlags\ -\ Detection\ Failed=Gjenkjenning mislyktes - Du har ikke tillatelse til å ta kommando over et fartøy i denne WorldGuard-regionen diff --git a/modules/Movecraft/src/main/resources/plugin.yml b/modules/Movecraft/src/main/resources/plugin.yml index cdb4aaf75..f6ec91b13 100644 --- a/modules/Movecraft/src/main/resources/plugin.yml +++ b/modules/Movecraft/src/main/resources/plugin.yml @@ -1,5 +1,5 @@ name: Movecraft -softdepend: [WorldGuard, WorldEdit, FastAsyncWorldEdit, Cannons, Vault ,Essentials, WGCustomFlags, Towny] +softdepend: [WorldGuard, WorldEdit, FastAsyncWorldEdit, Cannons, Vault ,Essentials, WGCustomFlags] version: ${project.version} api-version: 1.13 description: The original flight and movement plugin for minecraft. diff --git a/modules/api/src/main/java/net/countercraft/movecraft/config/Settings.java b/modules/api/src/main/java/net/countercraft/movecraft/config/Settings.java index 88edc3b06..cbcaf964c 100644 --- a/modules/api/src/main/java/net/countercraft/movecraft/config/Settings.java +++ b/modules/api/src/main/java/net/countercraft/movecraft/config/Settings.java @@ -17,7 +17,6 @@ package net.countercraft.movecraft.config; -import net.countercraft.movecraft.utils.TownyWorldHeightLimits; import org.bukkit.Material; import java.util.HashMap; @@ -60,10 +59,7 @@ public class Settings { public static boolean AllowCrewSigns = true; public static boolean SetHomeToCrewSign = true; public static int MaxRemoteSigns = -1; - public static boolean TownyBlockMoveOnSwitchPerm = false; - public static boolean TownyBlockSinkOnNoPVP = false; - public static Map TownProtectionHeightLimits; public static boolean CraftsUseNetherPortals = false; public static boolean IsPaper = false; public static boolean IsPre1_9 = false; diff --git a/modules/api/src/main/java/net/countercraft/movecraft/utils/TownyWorldHeightLimits.java b/modules/api/src/main/java/net/countercraft/movecraft/utils/TownyWorldHeightLimits.java deleted file mode 100644 index 311e5c18a..000000000 --- a/modules/api/src/main/java/net/countercraft/movecraft/utils/TownyWorldHeightLimits.java +++ /dev/null @@ -1,44 +0,0 @@ -package net.countercraft.movecraft.utils; - -/** - * @author mwkaicz - */ -public class TownyWorldHeightLimits { - public static final int DEFAULT_WORLD_MIN = -1; - public static final int DEFAULT_WORLD_MAX = -1; - public static final int DEFAULT_TOWN_ABOVE = 96; - public static final int DEFAULT_TOWN_UNDER = 255; - public int world_min = DEFAULT_WORLD_MIN; - public int world_max = DEFAULT_WORLD_MAX; - public int above_town = DEFAULT_TOWN_ABOVE; - public int under_town = DEFAULT_TOWN_UNDER; - - public boolean validate(int y, int spawnY) { - - if (world_min > -1 && world_max > -1) { - if (y > world_min && y < world_max) { - return false; - } - } else if (world_min > -1) { - if (y > world_min) { - return false; - } - } else if (world_max > -1) { - if (y < world_max) { - return false; - } - } - - if (above_town > -1 && under_town > -1) { - return y >= spawnY + above_town || y <= spawnY - under_town; - } else if (above_town > -1) { - return y < spawnY || y >= spawnY + above_town; - } else if (under_town > -1) { - return y > spawnY || y <= spawnY - under_town; - } - - return true; - - //return !((y > world_min && y < world_max) || (y < spawnY + above_town && y > spawnY - under_town ) ); - } -} From 22088714c598e028daf585fe8d13a80b426ccdae Mon Sep 17 00:00:00 2001 From: TylerS1066 Date: Sat, 6 Mar 2021 10:28:11 -0600 Subject: [PATCH 268/304] Removed final bits of cannons --- modules/Movecraft/dependency-reduced-pom.xml | 2 +- modules/Movecraft/pom.xml | 2 +- .../movecraft/async/detection/DetectionTask.java | 1 - .../resources/localisation/movecraftlang_en.properties | 1 - modules/Movecraft/src/main/resources/plugin.yml | 2 +- .../java/net/countercraft/movecraft/craft/CraftType.java | 7 ------- 6 files changed, 3 insertions(+), 12 deletions(-) diff --git a/modules/Movecraft/dependency-reduced-pom.xml b/modules/Movecraft/dependency-reduced-pom.xml index 1f2db46ee..789f6c6a4 100644 --- a/modules/Movecraft/dependency-reduced-pom.xml +++ b/modules/Movecraft/dependency-reduced-pom.xml @@ -4,7 +4,7 @@ net.countercraft movecraft Movecraft - 7.0.0_for_1.8.8-1.16.2_beta_37_TOWNY + 7.0.0_for_1.8.8-1.16.2_beta_37 http://github.com/apdevteam/Movecraft src/main/java diff --git a/modules/Movecraft/pom.xml b/modules/Movecraft/pom.xml index 815858378..42ab3c44d 100644 --- a/modules/Movecraft/pom.xml +++ b/modules/Movecraft/pom.xml @@ -10,7 +10,7 @@ UTF-8 - 7.0.0_for_1.8.8-1.16.2_beta_37_TOWNY + 7.0.0_for_1.8.8-1.16.2_beta_37 diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/detection/DetectionTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/detection/DetectionTask.java index 42147b4db..088ebcd63 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/detection/DetectionTask.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/detection/DetectionTask.java @@ -46,7 +46,6 @@ public class DetectionTask extends AsyncTask { @NotNull private final HashSet visited = new HashSet<>(); @NotNull private final HashMap, Integer> blockTypeCount = new HashMap<>(); @NotNull private final HashMap, Integer> signWithStringCount = new HashMap<>(); - @NotNull private final HashMap, Integer> cannonsCount = new HashMap<>(); @NotNull private final World world; @Nullable private final Player player; @NotNull private final Player notificationPlayer; diff --git a/modules/Movecraft/src/main/resources/localisation/movecraftlang_en.properties b/modules/Movecraft/src/main/resources/localisation/movecraftlang_en.properties index b33b1fe47..16aa70f1a 100644 --- a/modules/Movecraft/src/main/resources/localisation/movecraftlang_en.properties +++ b/modules/Movecraft/src/main/resources/localisation/movecraftlang_en.properties @@ -57,7 +57,6 @@ Detection\ -\ Craft\ Type\ Cannot\ Be\ Named=Crafts of this type cannot be named Detection\ -\ Failed\ -\ Water\ contact\ required\ but\ not\ found=Detection failed\: Water contact required but not found Detection\ -\ Forbidden\ sign\ string\ found=Detection Failed\! Forbidden strings found on signs on this craft Detection\ -\ Too\ many\ signs\ with\ string=Detection Failed\! Too many signs containing the following string(s): -Detection\ -\ Too\ many\ cannons=Detection Failed\! You have too many cannons of the following type on this craft: Economy\ -\ Not\ Enough\ Money=You do not have enough money Internal\ -\ Error\ -\ Processor\ thread\ encountered\ an\ error=Async task generated an exception Gearshift\ -\ Gear\ changed=Gear of craft changed. diff --git a/modules/Movecraft/src/main/resources/plugin.yml b/modules/Movecraft/src/main/resources/plugin.yml index f6ec91b13..b7a718149 100644 --- a/modules/Movecraft/src/main/resources/plugin.yml +++ b/modules/Movecraft/src/main/resources/plugin.yml @@ -1,5 +1,5 @@ name: Movecraft -softdepend: [WorldGuard, WorldEdit, FastAsyncWorldEdit, Cannons, Vault ,Essentials, WGCustomFlags] +softdepend: [WorldGuard, WorldEdit, FastAsyncWorldEdit, Vault ,Essentials, WGCustomFlags] version: ${project.version} api-version: 1.13 description: The original flight and movement plugin for minecraft. diff --git a/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java b/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java index eade643a1..76ccc2fed 100644 --- a/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java +++ b/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java @@ -123,7 +123,6 @@ final public class CraftType { @NotNull private final int effectRange; @NotNull private final Map potionEffectsToApply; @NotNull private final Map, Double> maxSignsWithString; - @NotNull private final Map, Double> maxCannons; private final boolean gearShiftsAffectTickCooldown; private final boolean gearShiftsAffectDirectMovement; private final boolean gearShiftsAffectCruiseSkipBlocks; @@ -358,7 +357,6 @@ public CraftType(File f) { effectRange = data.containsKey("effectRange") ? integerFromObject(data.get("effectRange")) : 0; potionEffectsToApply = data.containsKey("potionEffectsToApply") ? effectListFromObject(data.get("potionEffectsToApply")) : Collections.emptyMap(); maxSignsWithString = stringDoubleMapFromObject(data.getOrDefault("maxSignsWithString", new HashMap<>())); - maxCannons = stringDoubleMapFromObject(data.getOrDefault("maxCannons", new HashMap<>())); staticDetectionRange = doubleFromObject(data.getOrDefault("staticDetectionRange", 0.0)); underwaterStaticDetectionRange = doubleFromObject(data.getOrDefault("underwaterStaticDetectionRange", 0.0)); perWorldUnderwaterStaticDetectionRange = stringToDoubleMapFromObject(data.getOrDefault("perWorldUnderwaterStaticDetectionRange", new HashMap<>())); @@ -958,11 +956,6 @@ public Map, Double> getMaxSignsWithString() { return maxSignsWithString; } - @NotNull - public Map, Double> getMaxCannons() { - return maxCannons; - } - /** * @deprecated */ From 5d9b7eeb805d6a6cd81ce3b5ea3b1121a0981fcc Mon Sep 17 00:00:00 2001 From: TylerS1066 Date: Sat, 6 Mar 2021 11:53:43 -0600 Subject: [PATCH 269/304] Removed final bits of WorldEdit --- modules/Movecraft/dependency-reduced-pom.xml | 24 ----------- modules/Movecraft/pom.xml | 22 ---------- .../movecraft/utils/LegacyWEUtils.java | 30 -------------- .../movecraft/utils/WorldEditUtils.java | 41 ------------------- .../localisation/movecraftlang_cz.properties | 1 - .../localisation/movecraftlang_no.properties | 1 - .../Movecraft/src/main/resources/plugin.yml | 2 +- modules/api/dependency-reduced-pom.xml | 6 --- modules/api/pom.xml | 6 --- modules/v1_10_R1/pom.xml | 5 --- modules/v1_11_R1/pom.xml | 5 --- modules/v1_12_R1/pom.xml | 5 --- 12 files changed, 1 insertion(+), 147 deletions(-) delete mode 100644 modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/LegacyWEUtils.java delete mode 100644 modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/WorldEditUtils.java diff --git a/modules/Movecraft/dependency-reduced-pom.xml b/modules/Movecraft/dependency-reduced-pom.xml index 789f6c6a4..19fc9accd 100644 --- a/modules/Movecraft/dependency-reduced-pom.xml +++ b/modules/Movecraft/dependency-reduced-pom.xml @@ -74,18 +74,6 @@ true - - net.countercraft:movecraft-WE6Utils - - ** - - - - net.countercraft:movecraft-WE7Utils - - ** - - net.countercraft:movecraft-v1_8_R3 @@ -185,18 +173,6 @@ - - com.sk89q.worldedit - worldedit-bukkit - 7.1.0-SNAPSHOT - compile - - - com.sk89q.worldedit - worldedit-core - 7.1.0-SNAPSHOT - compile - com.sk89q.worldguard worldguard-core diff --git a/modules/Movecraft/pom.xml b/modules/Movecraft/pom.xml index 42ab3c44d..5343cc4d2 100644 --- a/modules/Movecraft/pom.xml +++ b/modules/Movecraft/pom.xml @@ -105,16 +105,6 @@ API jar - - com.sk89q.worldedit - worldedit-bukkit - 7.1.0-SNAPSHOT - - - com.sk89q.worldedit - worldedit-core - 7.1.0-SNAPSHOT - com.sk89q.worldguard worldguard-core @@ -243,18 +233,6 @@ true - - net.countercraft:movecraft-WE6Utils - - ** - - - - net.countercraft:movecraft-WE7Utils - - ** - - net.countercraft:movecraft-v1_8_R3 diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/LegacyWEUtils.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/LegacyWEUtils.java deleted file mode 100644 index 37d9b78f9..000000000 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/LegacyWEUtils.java +++ /dev/null @@ -1,30 +0,0 @@ -package net.countercraft.movecraft.utils; - -import com.sk89q.worldedit.blocks.BaseBlock; -import com.sk89q.worldedit.extent.clipboard.Clipboard; - -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; - -public class LegacyWEUtils { - private static Method GET_BLOCK; - static { - try { - GET_BLOCK = Clipboard.class.getDeclaredMethod("getBlock", com.sk89q.worldedit.Vector.class); - } catch (NoSuchMethodException e) { - GET_BLOCK = null; - e.printStackTrace(); - } - } - - public static BaseBlock getBlock(Clipboard clipboard, com.sk89q.worldedit.Vector pos){ - try { - return GET_BLOCK != null ? (BaseBlock) GET_BLOCK.invoke(clipboard, pos) : null; - } catch (IllegalAccessException | InvocationTargetException e) { - e.printStackTrace(); - return null; - } - } - - -} diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/WorldEditUtils.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/WorldEditUtils.java deleted file mode 100644 index d793cbdc1..000000000 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/WorldEditUtils.java +++ /dev/null @@ -1,41 +0,0 @@ -package net.countercraft.movecraft.utils; - -import com.sk89q.worldedit.Vector; -import com.sk89q.worldedit.math.BlockVector3; - -import java.util.HashSet; -import java.util.Set; - -public class WorldEditUtils { - public static Vector toWeVector(org.bukkit.util.Vector bukkitVector){ - return new Vector(bukkitVector.getBlockX(),bukkitVector.getBlockY(),bukkitVector.getBlockZ()); - } - - public static org.bukkit.util.Vector toBukkitVector(Vector vector){ - return new org.bukkit.util.Vector(vector.getBlockX(),vector.getBlockY(),vector.getBlockZ()); - } - - public static org.bukkit.util.Vector toBukkitVector(BlockVector3 vector){ - return new org.bukkit.util.Vector(vector.getBlockX(),vector.getBlockY(),vector.getBlockZ()); - } - - public static BlockVector3 toBlockVector(org.bukkit.util.Vector bukkitVector){ - return BlockVector3.at(bukkitVector.getBlockX(),bukkitVector.getBlockY(),bukkitVector.getBlockZ()); - } - - public static HashSet toWeVectorSet(Set bukkitVectorSet){ - HashSet ret = new HashSet<>(); - for (org.bukkit.util.Vector bukkitVector : bukkitVectorSet){ - ret.add(toWeVector(bukkitVector)); - } - return ret; - } - - public static HashSet toBlockVectorSet(Set bukkitVectorSet){ - HashSet ret = new HashSet<>(); - for (org.bukkit.util.Vector bukkitVector : bukkitVectorSet){ - ret.add(toBlockVector(bukkitVector)); - } - return ret; - } -} diff --git a/modules/Movecraft/src/main/resources/localisation/movecraftlang_cz.properties b/modules/Movecraft/src/main/resources/localisation/movecraftlang_cz.properties index 705c34fcf..a45b9d4dd 100644 --- a/modules/Movecraft/src/main/resources/localisation/movecraftlang_cz.properties +++ b/modules/Movecraft/src/main/resources/localisation/movecraftlang_cz.properties @@ -84,7 +84,6 @@ Craft\ is\ too\ big\ to\ check\ its\ borders\.\ Make\ sure\ this\ area\ is\ safe You\ have\ left\ your\ craft\.\ You\ may\ return\ to\ your\ craft\ by\ typing\ \/manoverboard\ any\ time\ before\ the\ timeout\ expires=Opustil jsi svuj stroj. Pokud jsi ze sveho stroje vypadl, muzes napsat /manoverboard pro navrat, drive nez vyprsi casovy limit. WARNING\!\ There\ are\ blocks\ near\ your\ craft\ that\ may\ merge\ with\ the\ \craft\ "=VAROVANI\! Pobliz tveho stroje jsou bloky, ktere se mohou sloucit se strojem. You\ can\ only\ create\ a\ Crew\:\ sign\ for\ yourself=You can only create a Crew\: Muzes vytvorit cedulku pouze pro sebe -Repair\ functionality\ is\ disabled\ or\ WorldEdit\ was\ not\ detected=Funce opravovani je zakazana nebo nebyl detekovan WorldEdit You\ must\ be\ piloting\ a\ craft=Musis ridit nejaky stroj Could\ not\ save\ file=Nemohu ulozit soubor State\ saved=Stav ulozen diff --git a/modules/Movecraft/src/main/resources/localisation/movecraftlang_no.properties b/modules/Movecraft/src/main/resources/localisation/movecraftlang_no.properties index 7039fb6bc..e0ee877d7 100644 --- a/modules/Movecraft/src/main/resources/localisation/movecraftlang_no.properties +++ b/modules/Movecraft/src/main/resources/localisation/movecraftlang_no.properties @@ -66,7 +66,6 @@ Craft\ is\ too\ big\ to\ check\ its\ borders\.\ Make\ sure\ this\ area\ is\ safe You\ have\ left\ your\ craft\.\ You\ may\ return\ to\ your\ craft\ by\ typing\ \/manoverboard\ any\ time\ before\ the\ timeout\ expires=You have left your craft. If you have fallen out of your craft, you man type /manoverboard before the timout expires and be returned to it. WARNING\!\ There\ are\ blocks\ near\ your\ craft\ that\ may\ merge\ with\ the\ \craft\ "=ADVARSEL\! Det er blokker i nærheten av fartøyet som kan bli del av fartøyet You\ can\ only\ create\ a\ Crew\:\ sign\ for\ yourself=Du kan kun lage Crew\:-skilt til deg selv -Repair\ functionality\ is\ disabled\ or\ WorldEdit\ was\ not\ detected=Reparasjonsfunksjon er deaktivert eller WorldEdit ble ikke gjenkjent You\ must\ be\ piloting\ a\ craft=Du må ha kommando over et fartøy Could\ not\ save\ file=Kan ikke lagre fil State\ saved=tilstand lagret diff --git a/modules/Movecraft/src/main/resources/plugin.yml b/modules/Movecraft/src/main/resources/plugin.yml index b7a718149..2c08fb7b9 100644 --- a/modules/Movecraft/src/main/resources/plugin.yml +++ b/modules/Movecraft/src/main/resources/plugin.yml @@ -1,5 +1,5 @@ name: Movecraft -softdepend: [WorldGuard, WorldEdit, FastAsyncWorldEdit, Vault ,Essentials, WGCustomFlags] +softdepend: [WorldGuard, FastAsyncWorldEdit, Vault ,Essentials, WGCustomFlags] version: ${project.version} api-version: 1.13 description: The original flight and movement plugin for minecraft. diff --git a/modules/api/dependency-reduced-pom.xml b/modules/api/dependency-reduced-pom.xml index 8beba05e5..a2f31f641 100644 --- a/modules/api/dependency-reduced-pom.xml +++ b/modules/api/dependency-reduced-pom.xml @@ -103,12 +103,6 @@ LATEST provided - - com.sk89q - worldedit - LATEST - provided - org.jetbrains annotations-java5 diff --git a/modules/api/pom.xml b/modules/api/pom.xml index 31e0628f2..1c86a50f1 100644 --- a/modules/api/pom.xml +++ b/modules/api/pom.xml @@ -45,12 +45,6 @@ LATEST provided - - com.sk89q - worldedit - LATEST - provided - org.jetbrains annotations-java5 diff --git a/modules/v1_10_R1/pom.xml b/modules/v1_10_R1/pom.xml index c0a5b39b4..5093f7826 100644 --- a/modules/v1_10_R1/pom.xml +++ b/modules/v1_10_R1/pom.xml @@ -24,11 +24,6 @@ - - com.sk89q - worldedit - LATEST - com.sk89q worldguard diff --git a/modules/v1_11_R1/pom.xml b/modules/v1_11_R1/pom.xml index 5d4f61665..7bba80fb0 100644 --- a/modules/v1_11_R1/pom.xml +++ b/modules/v1_11_R1/pom.xml @@ -24,11 +24,6 @@ - - com.sk89q - worldedit - LATEST - com.sk89q worldguard diff --git a/modules/v1_12_R1/pom.xml b/modules/v1_12_R1/pom.xml index 9202c74e2..4eac3a1ff 100644 --- a/modules/v1_12_R1/pom.xml +++ b/modules/v1_12_R1/pom.xml @@ -24,11 +24,6 @@ - - com.sk89q - worldedit - LATEST - net.countercraft movecraft-api From 652f26c6381f02e03f429fa64aeba479b4518541 Mon Sep 17 00:00:00 2001 From: TylerS1066 Date: Sat, 6 Mar 2021 12:46:56 -0600 Subject: [PATCH 270/304] Update versions --- .github/workflows/maven.yml | 30 +++++++++++++------------- README.md | 15 ++++--------- modules/Movecraft/pom.xml | 2 +- modules/api/dependency-reduced-pom.xml | 2 +- modules/v1_12_R1/pom.xml | 2 +- modules/v1_15_R1/pom.xml | 2 +- modules/v1_16_R2/pom.xml | 2 +- modules/v1_16_R3/pom.xml | 2 +- pom.xml | 2 +- 9 files changed, 26 insertions(+), 33 deletions(-) diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml index 3e4e80cdc..200fb45ca 100644 --- a/.github/workflows/maven.yml +++ b/.github/workflows/maven.yml @@ -66,10 +66,10 @@ jobs: run: cd BuildTools && java -jar BuildTools.jar --rev 1.11.2 - name: Check 1.12.1 id: color - run: test -f ~/.m2/repository/org/bukkit/craftbukkit/1.12.1-R0.1-SNAPSHOT/craftbukkit-1.12.1-R0.1-SNAPSHOT.jar && echo "::set-output name=sucess::true" || echo "::set-output name=sucess::false" - - name: Build 1.12.1 + run: test -f ~/.m2/repository/org/bukkit/craftbukkit/1.12.2-R0.1-SNAPSHOT/craftbukkit-1.12.2-R0.1-SNAPSHOT.jar && echo "::set-output name=sucess::true" || echo "::set-output name=sucess::false" + - name: Build 1.12.2 if: steps.color.outputs.sucess != 'true' - run: cd BuildTools && java -jar BuildTools.jar --rev 1.12.1 + run: cd BuildTools && java -jar BuildTools.jar --rev 1.12.2 - name: Check 1.13.2 id: aquatic run: test -f ~/.m2/repository/org/bukkit/craftbukkit/1.13.2-R0.1-SNAPSHOT/craftbukkit-1.13.2-R0.1-SNAPSHOT.jar && echo "::set-output name=sucess::true" || echo "::set-output name=sucess::false" @@ -82,10 +82,10 @@ jobs: - name: Build 1.14.4 if: steps.pillage.outputs.sucess != 'true' run: cd BuildTools && java -jar BuildTools.jar --rev 1.14.4 --compile craftbukkit - - name: Check 1.15 + - name: Check 1.15.2 id: bees - run: test -f ~/.m2/repository/org/bukkit/craftbukkit/1.15-R0.1-SNAPSHOT/craftbukkit-1.15-R0.1-SNAPSHOT.jar && echo "::set-output name=sucess::true" || echo "::set-output name=sucess::false" - - name: Build 1.15 + run: test -f ~/.m2/repository/org/bukkit/craftbukkit/1.15.2-R0.1-SNAPSHOT/craftbukkit-1.15.2-R0.1-SNAPSHOT.jar && echo "::set-output name=sucess::true" || echo "::set-output name=sucess::false" + - name: Build 1.15.2 if: steps.bees.outputs.sucess != 'true' run: cd BuildTools && java -jar BuildTools.jar --rev 1.15 --compile craftbukkit - name: Check 1.16.1 @@ -94,18 +94,18 @@ jobs: - name: Build 1.16.1 if: steps.nether.outputs.sucess != 'true' run: cd BuildTools && java -jar BuildTools.jar --rev 1.16.1 --compile craftbukkit - - name: Check 1.16.2 + - name: Check 1.16.3 id: nether2 - run: test -f ~/.m2/repository/org/bukkit/craftbukkit/1.16.2-R0.1-SNAPSHOT/craftbukkit-1.16.2-R0.1-SNAPSHOT.jar && echo "::set-output name=sucess::true" || echo "::set-output name=sucess::false" - - name: Build 1.16.2 + run: test -f ~/.m2/repository/org/bukkit/craftbukkit/1.16.3-R0.1-SNAPSHOT/craftbukkit-1.16.3-R0.1-SNAPSHOT.jar && echo "::set-output name=sucess::true" || echo "::set-output name=sucess::false" + - name: Build 1.16.3 if: steps.nether2.outputs.sucess != 'true' - run: cd BuildTools && java -jar BuildTools.jar --rev 1.16.2 --compile craftbukkit - - name: Check 1.16.4 + run: cd BuildTools && java -jar BuildTools.jar --rev 1.16.3 --compile craftbukkit + - name: Check 1.16.5 id: nether3 - run: test -f ~/.m2/repository/org/bukkit/craftbukkit/1.16.4-R0.1-SNAPSHOT/craftbukkit-1.16.4-R0.1-SNAPSHOT.jar && echo "::set-output name=sucess::true" || echo "::set-output name=sucess::false" - - name: Build 1.16.4 + run: test -f ~/.m2/repository/org/bukkit/craftbukkit/1.16.5-R0.1-SNAPSHOT/craftbukkit-1.16.5-R0.1-SNAPSHOT.jar && echo "::set-output name=sucess::true" || echo "::set-output name=sucess::false" + - name: Build 1.16.5 if: steps.nether3.outputs.sucess != 'true' - run: cd BuildTools && java -jar BuildTools.jar --rev 1.16.4 --compile craftbukkit + run: cd BuildTools && java -jar BuildTools.jar --rev 1.16.5 --compile craftbukkit # EXAMPLE - Copy/paste as required to add version support to CI # - name: Test [version] @@ -117,7 +117,7 @@ jobs: # - run: test -d ~/.m2/repository/org/bukkit/craftbukkit/ && ls ~/.m2/repository/org/bukkit/craftbukkit/ - name: Build with Maven - run: mvn -B package --file pom.xml + run: mvn -B package -T 1C --file pom.xml - name: Stage jar run: mkdir staging && cp target/Movecraft.jar staging && mv staging/Movecraft.jar staging/Movecraft_$GITHUB_SHA.jar diff --git a/README.md b/README.md index 832e97612..ebebe29a5 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,5 @@ -<<<<<<< HEAD # Movecraft ![Java CI](https://github.com/eirikh1996/Movecraft/workflows/Java%20CI/badge.svg?branch=master) -[![codebeat badge](https://codebeat.co/badges/77751ae4-80f7-460a-a225-0e3ae8cbbab1)](https://codebeat.co/projects/github-com-apdevteam-movecraft-master) -[![Build Status](https://travis-ci.org/APDevTeam/Movecraft.svg?branch=master)](https://travis-ci.org/APDevTeam/Movecraft) -======= -Movecraft -====== -![Java CI](https://github.com/APDevTeam/Movecraft/workflows/Java%20CI/badge.svg?branch=master) ->>>>>>> a538bb5fa41388a3e020df14e4186df46d6a6609 This is a maintained fork of Movecraft, which aims to add legacy version support as well as performance fixes. @@ -27,12 +19,13 @@ java -jar BuildTools.jar --rev 1.8.8 java -jar BuildTools.jar --rev 1.9.4 java -jar BuildTools.jar --rev 1.10.2 java -jar BuildTools.jar --rev 1.11.2 -java -jar BuildTools.jar --rev 1.12.1 +java -jar BuildTools.jar --rev 1.12.2 java -jar BuildTools.jar --rev 1.13.2 java -jar BuildTools.jar --rev 1.14.4 --compile craftbukkit -java -jar BuildTools.jar --rev 1.15 --compile craftbukkit +java -jar BuildTools.jar --rev 1.15.2 --compile craftbukkit java -jar BuildTools.jar --rev 1.16.1 --compile craftbukkit -java -jar BuildTools.jar --rev 1.16.2 --compile craftbukkit +java -jar BuildTools.jar --rev 1.16.3 --compile craftbukkit +java -jar BuildTools.jar --rev 1.16.5 --compile craftbukkit ``` Then, run the following to build Movecraft through `maven`. diff --git a/modules/Movecraft/pom.xml b/modules/Movecraft/pom.xml index 5343cc4d2..b460d67d1 100644 --- a/modules/Movecraft/pom.xml +++ b/modules/Movecraft/pom.xml @@ -10,7 +10,7 @@ UTF-8 - 7.0.0_for_1.8.8-1.16.2_beta_37 + 7.0.0_for_1.8.8-1.16.5_beta_37 diff --git a/modules/api/dependency-reduced-pom.xml b/modules/api/dependency-reduced-pom.xml index a2f31f641..7fe3aa7ec 100644 --- a/modules/api/dependency-reduced-pom.xml +++ b/modules/api/dependency-reduced-pom.xml @@ -156,7 +156,7 @@ com.destroystokyo.paper paper-api - 1.16.4-R0.1-SNAPSHOT + 1.16.5-R0.1-SNAPSHOT provided diff --git a/modules/v1_12_R1/pom.xml b/modules/v1_12_R1/pom.xml index 4eac3a1ff..ef65d344f 100644 --- a/modules/v1_12_R1/pom.xml +++ b/modules/v1_12_R1/pom.xml @@ -38,7 +38,7 @@ org.bukkit craftbukkit - 1.12.1-R0.1-SNAPSHOT + 1.12.2-R0.1-SNAPSHOT provided diff --git a/modules/v1_15_R1/pom.xml b/modules/v1_15_R1/pom.xml index 53a3c9d47..970041345 100644 --- a/modules/v1_15_R1/pom.xml +++ b/modules/v1_15_R1/pom.xml @@ -29,7 +29,7 @@ org.bukkit craftbukkit - 1.15-R0.1-SNAPSHOT + 1.15.2-R0.1-SNAPSHOT diff --git a/modules/v1_16_R2/pom.xml b/modules/v1_16_R2/pom.xml index a9fa12d94..14944f7c4 100644 --- a/modules/v1_16_R2/pom.xml +++ b/modules/v1_16_R2/pom.xml @@ -18,7 +18,7 @@ org.bukkit craftbukkit - 1.16.2-R0.1-SNAPSHOT + 1.16.3-R0.1-SNAPSHOT net.countercraft diff --git a/modules/v1_16_R3/pom.xml b/modules/v1_16_R3/pom.xml index 28e802f67..4a770c777 100644 --- a/modules/v1_16_R3/pom.xml +++ b/modules/v1_16_R3/pom.xml @@ -18,7 +18,7 @@ org.bukkit craftbukkit - 1.16.4-R0.1-SNAPSHOT + 1.16.5-R0.1-SNAPSHOT net.countercraft diff --git a/pom.xml b/pom.xml index bc0a7cee7..87e9d6e88 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ com.destroystokyo.paper paper-api - 1.16.4-R0.1-SNAPSHOT + 1.16.5-R0.1-SNAPSHOT provided From 611b16ee472a23941e21d1b433960148534e8af8 Mon Sep 17 00:00:00 2001 From: TylerS1066 Date: Sat, 6 Mar 2021 12:47:38 -0600 Subject: [PATCH 271/304] Missed one --- .github/workflows/maven.yml | 2 +- modules/Movecraft/dependency-reduced-pom.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml index 200fb45ca..1645d41cc 100644 --- a/.github/workflows/maven.yml +++ b/.github/workflows/maven.yml @@ -87,7 +87,7 @@ jobs: run: test -f ~/.m2/repository/org/bukkit/craftbukkit/1.15.2-R0.1-SNAPSHOT/craftbukkit-1.15.2-R0.1-SNAPSHOT.jar && echo "::set-output name=sucess::true" || echo "::set-output name=sucess::false" - name: Build 1.15.2 if: steps.bees.outputs.sucess != 'true' - run: cd BuildTools && java -jar BuildTools.jar --rev 1.15 --compile craftbukkit + run: cd BuildTools && java -jar BuildTools.jar --rev 1.15.2 --compile craftbukkit - name: Check 1.16.1 id: nether run: test -f ~/.m2/repository/org/bukkit/craftbukkit/1.16.1-R0.1-SNAPSHOT/craftbukkit-1.16.1-R0.1-SNAPSHOT.jar && echo "::set-output name=sucess::true" || echo "::set-output name=sucess::false" diff --git a/modules/Movecraft/dependency-reduced-pom.xml b/modules/Movecraft/dependency-reduced-pom.xml index 19fc9accd..def69ffdb 100644 --- a/modules/Movecraft/dependency-reduced-pom.xml +++ b/modules/Movecraft/dependency-reduced-pom.xml @@ -4,7 +4,7 @@ net.countercraft movecraft Movecraft - 7.0.0_for_1.8.8-1.16.2_beta_37 + 7.0.0_for_1.8.8-1.16.5_beta_37 http://github.com/apdevteam/Movecraft src/main/java From 916686862dbf2492c6ef8cbb5eefc29fedffcf30 Mon Sep 17 00:00:00 2001 From: TylerS1066 Date: Sat, 6 Mar 2021 13:24:41 -0600 Subject: [PATCH 272/304] Update maven.yml --- .github/workflows/maven.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml index 1645d41cc..84045a550 100644 --- a/.github/workflows/maven.yml +++ b/.github/workflows/maven.yml @@ -64,7 +64,7 @@ jobs: - name: Build 1.11.2 if: steps.exploration.outputs.sucess != 'true' run: cd BuildTools && java -jar BuildTools.jar --rev 1.11.2 - - name: Check 1.12.1 + - name: Check 1.12.2 id: color run: test -f ~/.m2/repository/org/bukkit/craftbukkit/1.12.2-R0.1-SNAPSHOT/craftbukkit-1.12.2-R0.1-SNAPSHOT.jar && echo "::set-output name=sucess::true" || echo "::set-output name=sucess::false" - name: Build 1.12.2 From 1cd0cc2d73706e47d69cc81f7c0f7a76258159cf Mon Sep 17 00:00:00 2001 From: Nicole <52045376+drfiveminusmint@users.noreply.github.com> Date: Sun, 7 Mar 2021 17:42:02 -0500 Subject: [PATCH 273/304] Gear changes (#385) * Gear changes Moves gear control to right-clicking the speed sign to improve ergonomics. * Fix typo * Change text to hotbar --- .../movecraft/listener/InteractListener.java | 13 ------ .../movecraft/sign/SpeedSign.java | 40 +++++++++++++++++++ 2 files changed, 40 insertions(+), 13 deletions(-) diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/InteractListener.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/InteractListener.java index babe1b65e..38e82e2c9 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/InteractListener.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/InteractListener.java @@ -74,19 +74,6 @@ public void onPlayerInteractStick(PlayerInteractEvent event) { } final CraftType type = craft.getType(); int currentGear = craft.getCurrentGear(); - if (player.isSneaking() && !craft.getPilotLocked()) { - final int gearShifts = type.getGearShifts(); - if (gearShifts == 1) { - player.sendMessage(I18nSupport.getInternationalisedString("Gearshift - Disabled for craft type")); - return; - } - currentGear++; - if (currentGear > gearShifts) - currentGear = 1; - player.sendMessage(I18nSupport.getInternationalisedString("Gearshift - Gear changed") + " " + currentGear + " / " + gearShifts); - craft.setCurrentGear(currentGear); - return; - } Long time = timeMap.get(player); int tickCooldown = craft.getType().getTickCooldown(craft.getW()); if (type.getGearShiftsAffectDirectMovement() && type.getGearShiftsAffectTickCooldown()) { diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/SpeedSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/SpeedSign.java index 668025b55..f0535a134 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/SpeedSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/SpeedSign.java @@ -2,15 +2,23 @@ import net.countercraft.movecraft.MovecraftLocation; import net.countercraft.movecraft.craft.Craft; +import net.countercraft.movecraft.craft.CraftManager; import net.countercraft.movecraft.events.CraftDetectEvent; import net.countercraft.movecraft.events.SignTranslateEvent; +import net.countercraft.movecraft.localisation.I18nSupport; +import net.md_5.bungee.api.ChatMessageType; +import net.md_5.bungee.api.chat.TextComponent; import org.bukkit.ChatColor; import org.bukkit.Material; import org.bukkit.World; import org.bukkit.block.Block; import org.bukkit.block.Sign; +import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; +import org.bukkit.event.block.Action; +import org.bukkit.event.player.PlayerInteractEvent; + public final class SpeedSign implements Listener{ @EventHandler @@ -40,4 +48,36 @@ public final void onSignTranslate(SignTranslateEvent event) { event.setLine(2,String.format("%.2f",craft.getMeanCruiseTime() * 1000) + "ms"); event.setLine(3,craft.getTickCooldown() + "T"); } + + @EventHandler + public void onSideClick(PlayerInteractEvent event) { + if (event.getAction() != Action.RIGHT_CLICK_BLOCK) { + return; + } + Block block = event.getClickedBlock(); + if (block.getType() != Material.SIGN_POST && block.getType() != Material.WALL_SIGN) { + return; + } + Sign sign = (Sign) event.getClickedBlock().getState(); + if (!ChatColor.stripColor(sign.getLine(0)).equalsIgnoreCase("Speed:")) { + return; + } + Player player = event.getPlayer(); + Craft craft = CraftManager.getInstance().getCraftByPlayer(player); + if (craft == null) { + return; + } + final int gearShifts = craft.getType().getGearShifts(); + int currentGear = craft.getCurrentGear(); + if (gearShifts == 1) { + player.spigot().sendMessage(ChatMessageType.ACTION_BAR, new TextComponent(I18nSupport.getInternationalisedString("Gearshift - Disabled for craft type"))); + return; + } + currentGear++; + if (currentGear > gearShifts) + currentGear = 1; + player.spigot().sendMessage(ChatMessageType.ACTION_BAR, new TextComponent(I18nSupport.getInternationalisedString("Gearshift - Gear changed") + " " + currentGear + " / " + gearShifts)); + craft.setCurrentGear(currentGear); + return; + } } From 5c9f44708abbac97878dc0baaff973db082b93ee Mon Sep 17 00:00:00 2001 From: TylerS1066 Date: Sun, 7 Mar 2021 17:04:34 -0600 Subject: [PATCH 274/304] Bump version for release --- modules/Movecraft/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/Movecraft/pom.xml b/modules/Movecraft/pom.xml index 0e98c4d43..04e2a6171 100644 --- a/modules/Movecraft/pom.xml +++ b/modules/Movecraft/pom.xml @@ -9,7 +9,7 @@ UTF-8 - 7.0.0_beta_9-SNAPSHOT + 7.0.0_beta_9 From 4884c2f32e3e3a03ee9cac90f9424cf59556d0b7 Mon Sep 17 00:00:00 2001 From: TylerS1066 Date: Sun, 7 Mar 2021 19:04:23 -0600 Subject: [PATCH 275/304] Remove Essentials & Crew Signs (#378) * Initial removal of crew signs * Added ManOverboardEvent * Removed unused dependencies * Fix overboard * Added annotations --- modules/Movecraft/pom.xml | 10 -- .../net/countercraft/movecraft/Movecraft.java | 24 --- .../commands/ManOverboardCommand.java | 9 +- .../countercraft/movecraft/sign/CrewSign.java | 152 ------------------ .../Movecraft/src/main/resources/config.yml | 2 - .../localisation/movecraftlang_cz.properties | 1 - .../localisation/movecraftlang_en.properties | 8 - .../Movecraft/src/main/resources/plugin.yml | 2 +- .../movecraft/config/Settings.java | 2 - .../countercraft/movecraft/craft/Craft.java | 6 - .../movecraft/events/ManOverboardEvent.java | 35 ++++ 11 files changed, 43 insertions(+), 208 deletions(-) delete mode 100644 modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CrewSign.java create mode 100644 modules/api/src/main/java/net/countercraft/movecraft/events/ManOverboardEvent.java diff --git a/modules/Movecraft/pom.xml b/modules/Movecraft/pom.xml index 04e2a6171..376db3744 100644 --- a/modules/Movecraft/pom.xml +++ b/modules/Movecraft/pom.xml @@ -24,10 +24,6 @@ jitpack.io https://jitpack.io - - ess-repo - https://ci.ender.zone/plugin/repository/everything/ - @@ -66,12 +62,6 @@ snakeyaml 1.10 - - net.ess3 - EssentialsX - 2.16.1 - provided - com.palmergames diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java index bb489038c..7ecbaeafb 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java @@ -17,7 +17,6 @@ package net.countercraft.movecraft; -import com.earth2me.essentials.Essentials; import com.mewin.WGCustomFlags.WGCustomFlagsPlugin; import com.palmergames.bukkit.towny.Towny; import com.sk89q.worldguard.bukkit.WorldGuardPlugin; @@ -56,7 +55,6 @@ public class Movecraft extends JavaPlugin { private static WorldGuardPlugin worldGuardPlugin; private static WGCustomFlagsPlugin wgCustomFlagsPlugin = null; private static Towny townyPlugin = null; - private static Essentials essentialsPlugin = null; /*public HashMap blockFadeTimeMap = new HashMap<>(); public HashMap blockFadeTypeMap = new HashMap<>(); public HashMap blockFadeWaterMap = new HashMap<>(); @@ -138,8 +136,6 @@ public void onEnable() { Settings.SilhouetteViewDistance = getConfig().getInt("SilhouetteViewDistance", 200); Settings.SilhouetteBlockCount = getConfig().getInt("SilhouetteBlockCount", 20); Settings.ProtectPilotedCrafts = getConfig().getBoolean("ProtectPilotedCrafts", false); - Settings.AllowCrewSigns = getConfig().getBoolean("AllowCrewSigns", true); - Settings.SetHomeToCrewSign = getConfig().getBoolean("SetHomeToCrewSign", true); Settings.MaxRemoteSigns = getConfig().getInt("MaxRemoteSigns", -1); Settings.CraftsUseNetherPortals = getConfig().getBoolean("CraftsUseNetherPortals", false); Settings.RequireCreatePerm = getConfig().getBoolean("RequireCreatePerm", false); @@ -227,21 +223,6 @@ public void onEnable() { } else { logger.log(Level.INFO, I18nSupport.getInternationalisedString("Startup - Towny Not Found")); } - - Plugin tempEssentialsPlugin = getServer().getPluginManager().getPlugin("Essentials"); - if (tempEssentialsPlugin != null) { - if (tempEssentialsPlugin.getDescription().getName().equalsIgnoreCase("essentials")) { - if (tempEssentialsPlugin.getClass().getName().equals("com.earth2me.essentials.Essentials")) { - if (tempEssentialsPlugin instanceof Essentials) { - essentialsPlugin = (Essentials) tempEssentialsPlugin; - logger.log(Level.INFO, I18nSupport.getInternationalisedString("Startup - Essentials Found")); - } - } - } - } - if (essentialsPlugin == null) { - logger.log(Level.INFO, I18nSupport.getInternationalisedString("Startup - Essentials Not Found")); - } if (shuttingDown && Settings.IGNORE_RESET) { logger.log( @@ -280,7 +261,6 @@ public void onEnable() { getServer().getPluginManager().registerEvents(new AscendSign(), this); getServer().getPluginManager().registerEvents(new ContactsSign(), this); getServer().getPluginManager().registerEvents(new CraftSign(), this); - getServer().getPluginManager().registerEvents(new CrewSign(), this); getServer().getPluginManager().registerEvents(new CruiseSign(), this); getServer().getPluginManager().registerEvents(new DescendSign(), this); getServer().getPluginManager().registerEvents(new HelmSign(), this); @@ -322,10 +302,6 @@ public Towny getTownyPlugin() { return townyPlugin; } - public Essentials getEssentialsPlugin() { - return essentialsPlugin; - } - public WorldHandler getWorldHandler(){ return worldHandler; } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/ManOverboardCommand.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/ManOverboardCommand.java index 1d9e2220d..abe2d96fd 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/ManOverboardCommand.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/ManOverboardCommand.java @@ -3,8 +3,10 @@ import net.countercraft.movecraft.config.Settings; import net.countercraft.movecraft.craft.Craft; import net.countercraft.movecraft.craft.CraftManager; +import net.countercraft.movecraft.events.ManOverboardEvent; import net.countercraft.movecraft.localisation.I18nSupport; import net.countercraft.movecraft.utils.MathUtils; +import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.command.Command; import org.bukkit.command.CommandExecutor; @@ -33,7 +35,7 @@ public boolean onCommand(CommandSender commandSender, Command command, String s, return true; } - Location telPoint = craft.getCrewSigns().containsKey(player.getUniqueId()) ? craft.getCrewSigns().get(player.getUniqueId()) : getCraftTeleportPoint(craft); + Location telPoint = getCraftTeleportPoint(craft); if (craft.getW() != player.getWorld()) { player.sendMessage(MOVECRAFT_COMMAND_PREFIX + I18nSupport.getInternationalisedString("ManOverboard - Other World")); return true; @@ -55,9 +57,12 @@ public boolean onCommand(CommandSender commandSender, Command command, String s, return true; } + ManOverboardEvent event = new ManOverboardEvent(craft, telPoint); + Bukkit.getServer().getPluginManager().callEvent(event); + player.setVelocity(new Vector(0, 0, 0)); player.setFallDistance(0); - player.teleport(telPoint); + player.teleport(event.getLocation()); return true; } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CrewSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CrewSign.java deleted file mode 100644 index b3ca27b03..000000000 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CrewSign.java +++ /dev/null @@ -1,152 +0,0 @@ -package net.countercraft.movecraft.sign; - -import com.earth2me.essentials.User; -import net.countercraft.movecraft.Movecraft; -import net.countercraft.movecraft.MovecraftLocation; -import net.countercraft.movecraft.config.Settings; -import net.countercraft.movecraft.craft.Craft; -import net.countercraft.movecraft.craft.CraftManager; -import net.countercraft.movecraft.events.CraftDetectEvent; -import net.countercraft.movecraft.events.SignTranslateEvent; -import net.countercraft.movecraft.localisation.I18nSupport; -import net.countercraft.movecraft.utils.MathUtils; -import org.bukkit.*; -import org.bukkit.block.Block; -import org.bukkit.block.BlockFace; -import org.bukkit.block.Sign; -import org.bukkit.entity.Player; -import org.bukkit.event.EventHandler; -import org.bukkit.event.EventPriority; -import org.bukkit.event.Listener; -import org.bukkit.event.block.Action; -import org.bukkit.event.block.SignChangeEvent; -import org.bukkit.event.player.PlayerInteractEvent; -import org.bukkit.event.player.PlayerRespawnEvent; - -public class CrewSign implements Listener { - - @EventHandler - public final void onSignChange(SignChangeEvent event) { - if (!event.getLine(0).equalsIgnoreCase("Crew:")) { - return; - } - Player player = event.getPlayer(); - event.setLine(1, player.getName()); - } - - @EventHandler - public final void onSignTranslate(SignTranslateEvent event) { - Craft craft = event.getCraft(); - if (!Settings.AllowCrewSigns || !ChatColor.stripColor(event.getLine(0)).equalsIgnoreCase("Crew:")) { - return; - } - String crewName = ChatColor.stripColor(event.getLine(1)); - Player crewPlayer = Movecraft.getInstance().getServer().getPlayer(crewName); - if (crewPlayer == null) { - return; - } - Location valid = null; - for(MovecraftLocation location : event.getLocations()){ - Location bedLoc = location.toBukkit(craft.getW()).subtract(0,1,0); - if (craft.getW().getBlockAt(bedLoc).getType().equals(Material.BED_BLOCK)) { - valid = bedLoc; - break; - } - } - if(valid == null){ - return; - } - craft.getCrewSigns().put(crewPlayer.getUniqueId(), valid); - } - - @EventHandler - public final void onSignRightClick(PlayerInteractEvent event) { - if (!Settings.AllowCrewSigns || !event.getAction().equals(Action.RIGHT_CLICK_BLOCK)) { - return; - } - - Player player = event.getPlayer(); - if (!player.isSneaking() || !(event.getClickedBlock().getState() instanceof Sign)) { - return; - } - Sign sign = (Sign) event.getClickedBlock().getState(); - if (!sign.getLine(0).equalsIgnoreCase("Crew:")) { - return; - } - if (!sign.getBlock().getRelative(0,-1,0).getType().equals(Material.BED_BLOCK)) { - player.sendMessage(I18nSupport.getInternationalisedString("CrewSign - Need Bed Below")); - return; - } - if (!sign.getLine(1).equalsIgnoreCase(player.getName())) { - player.sendMessage(I18nSupport.getInternationalisedString("CrewSign - Sign Not Owned")); - return; - } - if(CraftManager.getInstance().getCraftByPlayer(player)!=null){ - player.sendMessage(I18nSupport.getInternationalisedString("CrewSign - Craft Currently Piloted")); - return; - } - Location location = sign.getLocation(); - player.sendMessage(I18nSupport.getInternationalisedString("CrewSign - Spawn Set")); - player.setBedSpawnLocation(location, true); - if (!Settings.SetHomeToCrewSign || Movecraft.getInstance().getEssentialsPlugin() == null) { - return; - } - User u = Movecraft.getInstance().getEssentialsPlugin().getUser(player); - u.setHome("home", location); - } - - @EventHandler(priority = EventPriority.HIGHEST) - public final void onPlayerRespawn(PlayerRespawnEvent event) { - Player player = event.getPlayer(); - Craft craft = CraftManager.getInstance().getCraftByPlayer(player); - if (craft == null) { - return; - } - if(craft.getSinking() || craft.getDisabled() || !craft.getCrewSigns().containsKey(player.getUniqueId())) { - return; - } - player.sendMessage(I18nSupport.getInternationalisedString("CrewSign - Respawn")); - Location respawnLoc = craft.getCrewSigns().get(player.getUniqueId()); - if (!respawnLoc.getBlock().getType().equals(Material.BED_BLOCK)){ - return; - } - //Attempt to find an empty location to spawn the player - boolean locationFound = false; - for(int i = -1; i < 2; i++) { - for(int j = -1; j < 2; j++) { - Location testLoc = new Location(craft.getW(), respawnLoc.getX()+i, respawnLoc.getY(), respawnLoc.getZ()+j); - if(testLoc.getBlock().getType().equals(Material.AIR)) { - if(testLoc.getBlock().getRelative(BlockFace.UP).isEmpty() && !testLoc.getBlock().getRelative(BlockFace.DOWN).isEmpty()) { - respawnLoc = testLoc; - locationFound = true; - break; - } - } - } - if (locationFound) { - respawnLoc = respawnLoc.add(0.5, 0, 0.5); - break; - } - } - event.setRespawnLocation(respawnLoc); - } - - @EventHandler - public void onCraftDetect(CraftDetectEvent event){ - World world = event.getCraft().getW(); - for(MovecraftLocation location: event.getCraft().getHitBox()){ - Block block = location.toBukkit(world).getBlock(); - if (block.getType() != Material.WALL_SIGN && block.getType() != Material.SIGN_POST) { - continue; - } - Sign sign = (Sign) block.getState(); - if (ChatColor.stripColor(sign.getLine(0)).equalsIgnoreCase("Crew:") && sign.getLocation().subtract(0,1,0).getBlock().getType().equals(Material.BED_BLOCK)) { - Player p = Bukkit.getPlayer(sign.getLine(1)); - if(p == null || !p.isOnline()) - return; - - event.getCraft().getCrewSigns().put(p.getUniqueId(), block.getLocation().subtract(0,1,0)); - } - } - } -} diff --git a/modules/Movecraft/src/main/resources/config.yml b/modules/Movecraft/src/main/resources/config.yml index f3e256cc9..835facd61 100644 --- a/modules/Movecraft/src/main/resources/config.yml +++ b/modules/Movecraft/src/main/resources/config.yml @@ -26,9 +26,7 @@ ExtraFadeTimePerBlock: #List of blocks that will take longer time to fade DROPPER: 600 FURNACE: 600 BlockQueueChunkSize: 200000 -AllowCrewSigns: true MaxRemoteSigns: -1 # Maximum number of remote signs that can be triggered at once. Setting to -1 allows unlimited. -SetHomeToCrewSign: false CraftsUseNetherPortals: false DisableShadowBlocks: # These blocks will not cast shadows. This improves the speed of moving ships of these blocks immensely. - 26 diff --git a/modules/Movecraft/src/main/resources/localisation/movecraftlang_cz.properties b/modules/Movecraft/src/main/resources/localisation/movecraftlang_cz.properties index b2feb4fae..db1f06589 100644 --- a/modules/Movecraft/src/main/resources/localisation/movecraftlang_cz.properties +++ b/modules/Movecraft/src/main/resources/localisation/movecraftlang_cz.properties @@ -83,7 +83,6 @@ Leaving\ Direct\ Control\ Mode=Mod primeho rizeni vypnut Craft\ is\ too\ big\ to\ check\ its\ borders\.\ Make\ sure\ this\ area\ is\ safe\ to\ release\ your\ craft\ in\.=Stroj je prilis velky pro detekci svych okraju. Ujistete se, ze je oblast bezpecna pro vypnuti stroje. You\ have\ left\ your\ craft\.\ You\ may\ return\ to\ your\ craft\ by\ typing\ \/manoverboard\ any\ time\ before\ the\ timeout\ expires=Opustil jsi svuj stroj. Pokud jsi ze sveho stroje vypadl, muzes napsat /manoverboard pro navrat, drive nez vyprsi casovy limit. WARNING\!\ There\ are\ blocks\ near\ your\ craft\ that\ may\ merge\ with\ the\ \craft\ "=VAROVANI\! Pobliz tveho stroje jsou bloky, ktere se mohou sloucit se strojem. -You\ can\ only\ create\ a\ Crew\:\ sign\ for\ yourself=You can only create a Crew\: Muzes vytvorit cedulku pouze pro sebe Repair\ functionality\ is\ disabled\ or\ WorldEdit\ was\ not\ detected=Funce opravovani je zakazana nebo nebyl detekovan WorldEdit You\ must\ be\ piloting\ a\ craft=Musis ridit nejaky stroj Could\ not\ save\ file=Nemohu ulozit soubor diff --git a/modules/Movecraft/src/main/resources/localisation/movecraftlang_en.properties b/modules/Movecraft/src/main/resources/localisation/movecraftlang_en.properties index 08c323b57..b2e6d7843 100644 --- a/modules/Movecraft/src/main/resources/localisation/movecraftlang_en.properties +++ b/modules/Movecraft/src/main/resources/localisation/movecraftlang_en.properties @@ -34,11 +34,6 @@ Contact/Subcraft\ Rotate\ -\ South=south Contact/Subcraft\ Rotate\ -\ North=north Craft\ Report=Craft Report Craft\ Report\ -\ None\ Found=No crafts found. -CrewSign\ -\ Need\ Bed\ Below=You need to have a bed below your crew sign -CrewSign\ -\ Sign\ Not\ Owned=You don't own this crew sign -CrewSign\ -\ Craft\ Currently\ Piloted=You can't set your priority crew sign to a piloted craft -CrewSign\ -\ Spawn\ Set=Priority crew bed set\! -CrewSign\ -\ Respawn=Respawning at crew bed\! Cruise\ -\ Must\ Be\ Player=Only Players may cruise. Cruise\ -\ Craft\ Type\ Cannot\ Cruise=This craft type cannot cruise. Detection\ -\ Parent\ Craft\ is\ busy=Parent Craft is busy @@ -129,8 +124,6 @@ Startup\ -\ WGCF\ Found=Found a compatible version of WGCustomFlags. Enabling WG Startup\ -\ WGCF\ Not\ Found=Movecraft did not find a compatible version of WGCustomFlags. Disabling WGCustomFlags integration. Startup\ -\ Towny\ Found=Found a compatible version of Towny. Enabling Towny integration. Startup\ -\ Towny\ Not\ Found=Movecraft did not find a compatible version of Towny. Disabling Towny integration. -Startup\ -\ Essentials\ Found=Found a compatible version of Essentials. Enabling Essentials integration. -Startup\ -\ Essentials\ Not\ Found=Movecraft did not find a compatible version of Essentials. Disabling Essentials integration. Teleportation\ -\ Cooldown\ active=Teleportation cooldown is active. You need to wait %d seconds Translation\ -\ Failed\ Craft\ cannot\ pass\ world\ border=Translation Failed: You cannot move the craft past the world border Translation\ -\ Failed\ Craft\ hit\ height\ limit=Craft has hit the height limit @@ -151,7 +144,6 @@ Movecraft=Movecraft Error=ERROR Direct\ Control\ -\ Entering=Entering Direct Control Mode Direct\ Control\ -\ Leaving=Leaving Direct Control Mode -Crew\ Sign\ -\ Can\ only\ create\ for\ yourself=You can only create a Crew\: sign for yourself You\ must\ be\ piloting\ a\ craft=You must be piloting a craft SIB\ MUST\ BE\ PLACED\ IN\ REGION=SIB MUST BE PLACED IN REGION Towny\ -\ Detection\ Failed=Detection Failed - You are not permitted to pilot a craft on this plot in the town diff --git a/modules/Movecraft/src/main/resources/plugin.yml b/modules/Movecraft/src/main/resources/plugin.yml index be34f514e..29d6b9a1b 100644 --- a/modules/Movecraft/src/main/resources/plugin.yml +++ b/modules/Movecraft/src/main/resources/plugin.yml @@ -1,5 +1,5 @@ name: Movecraft -softdepend: [WorldGuard, WorldEdit, Cannons, Vault, Essentials, WGCustomFlags, Towny] +softdepend: [WorldGuard, WGCustomFlags, Towny] version: ${project.version} #version: ${env.BUILD_NUMBER} description: The original flight and movement plugin for minecraft. diff --git a/modules/api/src/main/java/net/countercraft/movecraft/config/Settings.java b/modules/api/src/main/java/net/countercraft/movecraft/config/Settings.java index e0ff8ea23..080b23b2b 100644 --- a/modules/api/src/main/java/net/countercraft/movecraft/config/Settings.java +++ b/modules/api/src/main/java/net/countercraft/movecraft/config/Settings.java @@ -53,8 +53,6 @@ public class Settings { public static int ManOverboardTimeout = 60; public static double ManOverboardDistSquared = 1000000; public static int CollisionPrimer = 1000; - public static boolean AllowCrewSigns = true; - public static boolean SetHomeToCrewSign = true; public static int MaxRemoteSigns = -1; public static boolean WGCustomFlagsUsePilotFlag = false; public static boolean WGCustomFlagsUseMoveFlag = false; diff --git a/modules/api/src/main/java/net/countercraft/movecraft/craft/Craft.java b/modules/api/src/main/java/net/countercraft/movecraft/craft/Craft.java index 9d7142756..bdb8605c3 100644 --- a/modules/api/src/main/java/net/countercraft/movecraft/craft/Craft.java +++ b/modules/api/src/main/java/net/countercraft/movecraft/craft/Craft.java @@ -72,7 +72,6 @@ public abstract class Craft { private float meanCruiseTime; private int numMoves; @NotNull private final Map> phaseBlocks = new HashMap<>(); - @NotNull private final HashMap crewSigns = new HashMap<>(); @NotNull private String name = ""; public Craft(@NotNull CraftType type, @NotNull World world) { @@ -438,11 +437,6 @@ public Map> getPhaseBlocks(){ return phaseBlocks; } - @NotNull - public Map getCrewSigns(){ - return crewSigns; - } - @NotNull public String getName() { return name; diff --git a/modules/api/src/main/java/net/countercraft/movecraft/events/ManOverboardEvent.java b/modules/api/src/main/java/net/countercraft/movecraft/events/ManOverboardEvent.java new file mode 100644 index 000000000..3f30bd824 --- /dev/null +++ b/modules/api/src/main/java/net/countercraft/movecraft/events/ManOverboardEvent.java @@ -0,0 +1,35 @@ +package net.countercraft.movecraft.events; + +import net.countercraft.movecraft.craft.Craft; +import org.bukkit.Location; +import org.bukkit.event.HandlerList; +import org.jetbrains.annotations.NotNull; + +public class ManOverboardEvent extends CraftEvent { + @NotNull private static final HandlerList HANDLERS = new HandlerList(); + @NotNull private Location location; + + public ManOverboardEvent(@NotNull Craft c, @NotNull Location location) { + super(c); + this.location = location; + } + + @Override @NotNull + public HandlerList getHandlers() { + return HANDLERS; + } + + @SuppressWarnings("unused") + public static HandlerList getHandlerList() { + return HANDLERS; + } + + public void setLocation(@NotNull Location location) { + this.location = location; + } + + @NotNull + public Location getLocation() { + return location; + } +} From 37efee185980734d8b4849f4090937f34dfb25d3 Mon Sep 17 00:00:00 2001 From: TylerS1066 Date: Sun, 7 Mar 2021 20:11:09 -0600 Subject: [PATCH 276/304] Movecraft-Towny (#381) * Remove the towny * Cleaned up * Fix pom --- .gitignore | 1 - libs/Towny.jar | Bin 715172 -> 0 bytes modules/Movecraft/pom.xml | 8 - .../net/countercraft/movecraft/Movecraft.java | 23 -- .../async/rotation/RotationTask.java | 63 ----- .../movecraft/towny/TownyCompatManager.java | 143 ----------- .../movecraft/utils/TownyUtils.java | 240 ------------------ .../Movecraft/src/main/resources/config.yml | 8 - .../localisation/movecraftlang_cz.properties | 4 - .../localisation/movecraftlang_en.properties | 10 - .../Movecraft/src/main/resources/plugin.yml | 2 +- .../movecraft/config/Settings.java | 4 - .../utils/TownyWorldHeightLimits.java | 44 ---- 13 files changed, 1 insertion(+), 549 deletions(-) delete mode 100644 libs/Towny.jar delete mode 100644 modules/Movecraft/src/main/java/net/countercraft/movecraft/towny/TownyCompatManager.java delete mode 100644 modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/TownyUtils.java delete mode 100644 modules/api/src/main/java/net/countercraft/movecraft/utils/TownyWorldHeightLimits.java diff --git a/.gitignore b/.gitignore index cbe8db9eb..ae916f3f0 100644 --- a/.gitignore +++ b/.gitignore @@ -8,7 +8,6 @@ *.jar *.war *.ear -!libs/Towny.jar !libs/WGCustomFlags.jar # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml diff --git a/libs/Towny.jar b/libs/Towny.jar deleted file mode 100644 index da94c58cdf2cadd3c39f3b4342da4be80b54f5dc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 715172 zcmbrk1#nzTk_Fl=W@cuF7Be$5Q;Wf3W@gD^OP0mV%of{XW?9T^F<4;9-*4XR#_ar^ z_x8u{h#MVoZ=Q3rGP5eP@|LOsBoqPw00#iX82HEn{^bV`fC4B$c|ITR8ZG&&tVWdoxDfdRYLYiMS73T`7;h9 z)lD5c`!){YCJsX(_?gS6!@J|ZbpiZCmw(avx6%NBxswCye`)*wmO%TbgtMu=gQcsr zse`54zexYP8F2p>X)}*^?`+-w1@wnO{#6Nz{|qv-cQSwH;$i7w`4@PS|BN?xa#-D--^O@BcKRjfcg*;{QE%X#Y+Nds{bmOGiuBePFe~3&om<0riVx0%P;LVvjm|!MCKZS5VHc@=6mUx6fyupd((NVsCDeih>vrTJ$)J^!_hoId&SE<7|?Xd_I znzh}HY%U{4hGbEtFh_FA0Bob9D}+9Eia(9I-@nXArH-zM{Z6~ij#o*XDE(HANzNgB z#l6Jp-p1-#O}$t+h$QxwS;Qc_g z%oheSju1_2n$vBi5+LlezL&w+aGt3OGByCF7Y> z(6K2Ru5(dl9nBoRx1Y^D55m(+(~J~oH!ziaVYjv@n;Q|TIDG^DSC#Z(Eg#WC2{yn19{-|dDjHwS=?=;r5(S&gA5yv6oA)EJYS2@{~V^dOEZIxsp z$(a{?Od+V{L`H6EI&{+wh4Sz6?r`tkJ;N!EDZa3AJn=mNZGVg*gl?Z~U+a2ZZf-Pn z%E-)B@dUjhZ)5t`nPDws`xg|#F3;ojWy~?i{b+7>lzk_y&vS61gWz~?sx1ZMhTvGW zU-;bzTW>x2$i(^z8K>BfEzC(x+c|^$$-ED83Z%aY;zky_iYUp5*w}7qy!weD@tNYZ zbqAIO8e0HHsjWNRbou^e5!vy%1YiC;X6q4QtDH}&<-F}F^H)39Hb>5mGMzAKiAUc> z*9qxwA;OH4QFF!X3+a2@?c@2RJZ@ZyNfq;7aNdw4oJ`Fk$k~n-%EQF$GPV#uXJ(ge)l%=tAL36#pWi^I~ ziLdM~O8G%jVm!KP_|p4VZ3Q;1vr?dptT@cxSZaz0@=+2kzd(%2S3hr)uK|WLR{$Sm z)P~{$iW*BSuIw+ir+ht#FNPe3@#Fi;$gEBRfjwg#IT;Wbk<@{QEkC(`SU$-hWptXx z@9fpmC2?tUX7}qsR}u7l{S^7`QM2D1S>-B?{G~PtZ)&I(dhMu|u-V^O0F}7dJKC9!e^X*>su1$cxLV#TEV*w=@ z62VECS?#Spc+??;%AIV?&#!PgGT~KLed=j%fGyh{(r@L8z%uOP=L3he!_Q~ml(+Q; z2ImU;^|e)TTi?hG*OI#3zi!JQvE{Zza4B!I<%&g2PL8N&7tfx2>O-&qKxHBf*TxNKHq@SLv z;+G52Cuj!XkJsnRvsTJirfdNgHi)MZ0t%Adz~MrSjN?4AZ6=l|93ei=WvaXKZ|~87 zcyGj~3U`;}P3iNVv%gT!^SU|4YzipSM>Us{s~2m zzLJJ1-eZHJ6*E5PqOR-|Q9Dhb)7xMFz2o|GrNFin`wH_r_lW<_J#7E?l|skK_1!-g z3bk>^c~z|Jv&UJe)bQ2rDdtljK)^HQhC=@%0niF_O~Z?8v3tN^baZPg)T{C74S>t@FwcYLDA+=w-t2k7`8 zYDCIVOHpcq9>e1+OtR~g!kx7F(C(Bl&B8O!vS+Em!q*syV?Dt>BDzqckRj(&dQZVU zfnJiKQL~Z=3z7Ze!bVfW?80|L1)8}%xCvdn+W~>)v~^*aA+H6blN&t7ycyRES>vfe zlf$O_)0->@>YoExM(w55mP^_B#-vxiyT?Vc9S;WAD&(*z70+KtNwaeJQiIWj)aPd@ zKh@m`>JRn!6FJwPR&4Y){FrKL2!SNT&TcZ@>w3>1@xEZn8F&WK{R>Y#e=1;O#z1ky zde8iXmSGr<`PtO+xrv7Jp-A3bVQ?|~9pADWjh`7}sF@=Mx6O~tDdyeQTgWdbB{SJp zu_;Zd;$8&42w!dS=oQOMOY3_ogmK~PQbk5|$~G-st5eos_>5>WjBZwnHgLMVQ#^*L zKZjKE)~I41Eou(NC{*rFe6HkeDPWj#NU+3;+O$0s#C)E%)!~=Z~PWbp2;oX}=f{Y7qp|hAZO1#A?zxU^mndU{HCl z87b6+&U{K&SOYV9+tQBW!HCmLDSjSYt6l!wxnbngiF3KUYh<9Xx_WdyYx0`9V7>e! z8=jovj$UM6pzYE>ig&(n3#Rv_%QmEi)KL?w!m>^m%ca>WLJ-RNqxR01Z&n3ZNU zK60yYW8(aGuYOA7Ke~McGqL zfS$*vIx(JvghUAB{Wx3Vh{E%Twg2qgiDXp>`gI#XlfsK#GA zguTCSPHLF#c9TS)B>&76vZxhK!LgGwEnm-Tl>uu4sm)8*XMC*!Ox7sg{%*YcHa~QG z!!xqHhOqJGP}YUUlHXjK!8%s*yg6CGhBsX|gC}gWcra-<?lLL<6_|&cA`YSI=%5wb9I&%fKno?eNV1Am{_ZtlueX=3A=qj3thJuHjtZI7=nPifiTbBllC;)p z>fuX!%2iO$bx;_coeMrS#ZkG?>XnaAX(cH?!eP4(RXf*LtP1kk`!rn#+$g45$b0nAkiu!PbJ`a2iLY&0vs_e{;Zqe{)EHe{;}}e-n2Xva4)Yf|ztCEy1VZQFoa3 zQFGY((Qp{|QC$Yraqb$sXUT=Y+TA~_34xm_BIAyzr#i6TRju=R!)ntV38u4KVi-bR zJlmY``m38q_Aov+uDgF++elUMmQkx$z32EEA%1V^@YGa;g}9(kuUm8NL}2S+OEXhx zAJ4YP0OJ#c_VJ(=Je9T4bT&G2@v+uwoaOKjbf(0l%pt`~3bnvaB@yU`v4cScLVc8G ze|l4q6vH9Z5(beDg>f;vby@+#FDCIXkiAGs-V_|?=Jh%<7%`GZcFbW$5o7Si zpG~pvVsk&l{TP4x=x}7%>k~hTqv-O^&4O#3LLGP=yo1l~8aV%HeK0HFDL!bXr!qvc z_xri&IB|o}*^ZvA#TTAcr_PI;&mVyIduuuuLK}=?ffa#R>?2!(9GxzMSyh5q#$604 z?F%m7nqHY7E*IBtJ38)!>_68gbGb18ni=SmMUxh77JS=4i2gC|Qe@-k+NG5MoP|6X z(WaGYmEe0AV^b6maE3ilu2o;J+wr!%BTBPbhJcvWh3A?D!}rhMEajxtl$Y3xp%JP^ zadXbC`PzRmT0g(KEJA$^&W>rv;=@da!4ooYTiH^sg(Q-gokT1*y2&5i@OG8~3@EB*_S+8|x&jxH_g`nPn^ePO!qKP1&2S3!=ZW;g_2(g+bbe0!`n4|@Dq%gd z-qj;{g$3cIFTOFXxy+VBk+6dh=~V{R@!pj%wKIVh{lW{Q53k_ti*_g$wIUB@^O|0t za4BD(Itu%a8jf?erNEa^rA7-5#Wiw4sZiJWPfZKHvCe{t8yL-Wh@7&hoi3>6DknCr)0buo;>4Z)x@4w(D!QmBxzr@u8$5Q~n(9&ZDQTdYsp&a7Ud+ znQ>!$`Y?cpxpLO@fNQVj!m9Gv@{2gj4AI79s#N06cZro;!Qe@HDgSZ$ogV=!ZcoD*vC*{-2>fVXxjAMZ7W7?(T*zoGS60@ z4}3D>F;cMK>Do8#*|=xlQ`c^4CLT7bzF>L%8i`Mt7LRjERw*^x9SIRZ0MxPSVMe{g zJ#q~BWbY;Mr%atMyj_pkaI&J6Erycu4Rl-iwe0iCGawswA_H_PdLaZ!h zxPE{K0Mao50RI16W&N`yEb+U)`n$ntX(92C7O{t`=^uTyKl5UZj-RvUBL1(O&cx1@ zbwOQSFgz?e4JveFY?94%^s8_5 z%bOpoiBEXX(|SthuM=D6Pe@O0|`|Z|gIPLcH}M z%bIG1-pPL{>hkF-oAWI^?HhFf!P0eC!UjZ-t{u2f{;&~Zey#1}+N86vHSL$>Pb-te zR=y>oQf(V~oNiC?)XpasFk0V`%}{d;2cx|w##N2Xx0oO47w~P=ZCUVsy9aw(-E)X>fpETR zi#Z(T2AS5_g$()?O~;N)>yGa`@^6GT6J&3ehw>&FXln#&4@a$*I83eF97fxv5Z?s2 z*Z8Ug9ENO$%>@*@7tq;9QyJ(}2lTH@t=QvMINH)P8d3xo>@mz|h-5+Evga*6+*z!% zq)%J4cWtKCY7I&=?tR~o(+W^ozh0-@d++wqz1lp(ElCzX96zxw;j^KM$VwhNOXa3~ zl|uYnN#kH+-b<2JC`5tWn9jkum=Bx0|u8v=2V7eii*-n)h1#Sc!GIQWqvan}&E4s%$9aC;DtxTYN;TG4P5FJFeN zH^!TVXfLa{xJPIG z(|zNQo>(n0>?(@FCODrK&W z%#Kllyu`^zBor&RC4fu*)|gSAT*(Q1j`2+i(p(BF&*4q{b0bEsJ-;c()a`gCQ=E}M zIgMK>b6LA%m-?9%$Gn5XxWOnMrfb}QE#nF+dN?2Lgs(YPdx}oS*&2bqB{EgErvrs( zMrRfQ_KN=&-NZz-(>q2&(E~g~fzmOB6MV)TRl30YG+`Bd1->vAoc(HX_j`v1vkv%O zY8-UBEDnwi`#R=ZHEv^?2|B)xp(zVne<}P1Rz0t;at116Aze}$`ULO5#+UL((>*Qw zzcP^6pQUCD1Ic9A2#&6*>La$^6Z}HAixI}H++cr;{%q(s+KGogr_kOB&yox1A2LUK zPn%yO0<)~vPMDSO#Z9%MmJGR1i9e1roM56KX<6)q; z`RTet7N{R^b+hi(R!UM?L-cY&^wioIcU`2qYNLBNPZ6J#r5Oy- zgJwvpzg5*BKZU+o&W@>Cf<4g-OeYYvaM*^sRgj_>axA-|Kd&B>T=UknmtcQI&n09F z9dg8@rf)pi>M|-v*7_VOjec8n5!&95UEwNK8MY{I$7&VD5VknC{Y3~ASvjEELKpv2 zNcTVv>OR1RVUUtp36Y7c!21LH;Q*Eg>PcbnFMb5S1`QU9#adaVdYW?Bsy#n8k^S^v z#SdR7rr;+Sb`2{RuW}RR?diJ-12Z!r^vA|jTqTW!a|K45z#fvU;Jstw_@`e%um&L! zNWNaCsnG;t)1cDPo}@2vn_qUz(b+eL8`Us}+G~@ZNY`WyK5%X)cq4oiU=Wrobe|Ed zB)LN=QkTQpP8O4Gm?H0`^Y<<8DE8T8fy!>d(w)=8d$MktuRi*LlP?osC)hIQt!-D< zJikiHn`_53s91eiZrC?}AlMs@f$O$TksVDpY=^B<*VjVS&3H6P&nlwo6;1P zozo7SE`Xg*?L<9$TwI8gXoq&%*8YiMGEBdoAYw-O27~!)``P4pxYsmJ?;FLTX_am$ zumMZXgm+YdiCqanhPT+^ zfnjfT#9dnlZciHzZ)t<*oK*_Js>MA%=1@}yYR`8x#xuL#YHOhx%~98lt)$DgbvwbH z5OsEC&Z+|MDJRCr&sBJklF?j%B&^`(uNzl2wz)Y=_C?Hy}&A-89) zBz3iAB6m~{(Kp~MyJlu0| zT@#11wo@j9vj0@CzZP?!HVGkIj=urJ+B{vZBN5H{1NJw z^$}}+-|QNH0`2{;ev12_cy3(hNQbJ=g({#IZsG>?O`Eiq@e+5kQcB@31CLWU5Qo*& z?ujE_@i&;>XgJ(_02X7K-q5bsk`sLB?ff!1a*@%Ek6)xS8$+mUZE&A z>8M!Tfg;O`m0vtJzef>**VOazwn0mDhmrn;*E}S$JdtDVk)l$%%vIm13FG9$6`!lD znY2ceuMFq?7;e+8dY62U&lSqM7Z%7M)TV319-J-fAKk+pFTuplv9C9bNR2NSgLQ1- zTif(M(=~noX)nCIp?h_5KF2f}e5Fr+Jt!}3a&b3TVX?g6qb0;pp$3w2$eg%tz#(|hSO-+(ilmy zB)2&24i&P>_{1|MdQwDDEzJISbKo^Tw>;dV(G{y#CC*L+92P6d{uw)FSeB;w9P~e{ zNse}1*e~_~KokrR!1{lvCjU5RpzLH}>Go#{SseiDPdIo}uROXjNe_WV43D-NB2j5p zmINpmYu)|$ExqA;I9g~D^9oKfHRY&_V$c;r-7P}hk4@6wm)~XgkIlEbAdQFE*qpwX zp9;-h0!>X0o}N}-o|mb=e2)Ai3T7Tg_Nr%G_okvs!Pn{_W0;}w zes5^JI;cG@a2G-Ra`3f2$QX9$tlt|D&l7wt4cden%Ifz<#B+k)a{zY{$9n}|D}y$n zhdTScQSmOJ_X5COr17Z1*J2=HsG+F-M>srE=sk0=KT*6&@UlH z>`xNU8hkAU>VX={=zm1OGlAZF2lmggyF#8}h2F~o`^RneAU|7z{i8^F5uXph{)r^L zsL$BopMZGMxwS;mUW|Csuxm_Epgg(=SUN6iZ&)tK;OlSWi zF}ffmC2`kwDAAJ~V?l(9dWet;2j!J|2ah1pAPDJi;u7 zyyN`%uD=T~;Q_9Nb%T_0f(pQ!Py#!awm}^)2X{n}2#Apan-C{z?pl%WkUp;UuZub1 zh6*DbD*LWOKjVGG4e?>?HiCE#1bKz|(03cbJOe?jWy6f3y*Lw${avw}Dfy&OO@tF9 zzGu*{{2-0HcGx=!@Iy#P#^$qFFNvakX22ac;Mo+^FeGu84)Y2FYB*k=S%W*)12u#f z-EqS_zXzL%q0Fqc7o{LE~WUzHI1QD^L}9sjoVWPexZpj5U-G^^nci z0Pso!asu9JgPe+@*Th614vFu)X^&;Uvw%op4mYq|P>*GwcfcvZAX0e#!y7u#WeHCj z`o|sfJ}P+A!tlN>QdAl_I816NoIPQXocKpN@_I=X;BCd7r^vBxd)e&Xyx6d~Fr*>| zCQWP%A1Dv`(CzrVBcBxd)(0${w`mOE*WQi*_e5_RBR#W$Odt*wPR=d!S%aTkK_+5O zbx_2NKNvtJN=|h^;_K{_?Ei@%6o~C^e^M7B z2QeZEbZ7mz1(gbw6a#TQ3l4;xxSU)2Av$dQDEv_*zl}8XO&1gdb(nZ^PMa@+GLaX` zrr<;uRv#6poY)I^g$KW3Oqk5B)rkdBMDzlQ1RZwZ@$sL!c=KOsK`LEWlgU0cuO zAsw0=U)SZEN2PGGs}TrcPxOX8p@M$Nq5pz-4Fvr{J`6fO@68uMCWFcch6B@qOt55P zP;}9`C{&SGiBRbIWWF$c2)^;5Z;HXG0A(272nw@&5kxSxC{bT&w1!v^cOOIWBA`rd z;3QuJb{omp5c1g#I0eOvxNRToMt5O2lLxyE$cA+m7KI(Gfqs1g-~y_P+V1mv0bs~J z>0l+S2K+l*2r7Uq6)?6K7wA5_r#)kWRF4c6=spL$QUh=yl4K#U^{=N@lA2XnBZp|UT7kk?ikRlkIa^wK;0t&`&UckJb1AYJmiMG)J ziBR5HQd@}60ss=^D?9)Of3Wyb4j>WM8=?;rcme5+(U%I$74ItxePaoJ0m?1_Vn2C7 zl6jHq2*pw4B0u{9l1!7-l2~QO0P>kXAi9!BOrV}$0LF@mtiab-0F@m;Y7!Puk0|#C z5EY^;mc#`4ISNp(P)}O_+A!GgzQMGiyWXK5eN$Z53HtRbKzFuneoa917aTx4xELuv z?THS6bJBhHAUq=i6TA`_yeSO#JPZVdq0X<#i2i~C#1M$8-O2&N141{2;h)O@!cvKO zFt76fDks3fq%}YoR`do&b<-bbJMQk0dWP*`{Ld#xz#f=Cp8&VB{=9_??1B9A7X0?h zKW-tXJfim{0s|qgG=lShKZ&++p?*>yn*hnsA?eI|5JW$t$C@GCoK;>mKAQFW;ZA$GQX<+`(TCI|0SdfJ)&l$VXOTee#)J zRGbqLoKq1Iz&m{1@&37f_C9uc0?QdxwbL2O*c{RjDYIemhFkM`<-*}qv0w1IRDMip zLL$)bsD*~ae&Op<1v6oZiom|Z7OI7L#RVs0HL4=KVlbtM9bfy$V9Qjg_ zkPm=&h`Kpgv(V3Z{i_H|-1V|_dUR=T5K9qv?U;AHp)H8jamVLoGrwS#sPEbd?|wm^ zsn@dUM*tNUo)RH`A_7iUZB(Uu#jQrKXTRe{kcO*ftA7ZSVo32|#v{;$?f;Czgdx9l z4-W6=M_NJ#Cwp3Kz`=NeQL0_)W!V~Uz+f+&V;2mh?@RRcrTq-*14>{pEh(@HY6(dy ztsm518O(*aG>N4)SOHs2pzBdDtEwl{U*Go$HV*1T3qTsG+Mw?MHMA=7yIOdCmNBf6f_ckD9;2GQ9qb|q{oQ!W(fZu|_ zG?!XU8;TBlCS0EjwUkN^F-b>QT^1^po_5a(QieV|0Skp~=E4s#)aODkHJu8pLF5-i`A*yvk?-}Zik(b`}`7(>m z^yot_o%Q<$Z_bSHV^;Ho-qX}?Dx%xi=0GnQ^!pO(QnfL0woSpD<$${ptGzU!Rt=AW z?~Us>VV7R$A&~3b`k%>kNg>X@f&;>LXP#aAp7C@^%Xm2Zry$Q#!O6{yGbjS2)ziWE zdcG3o)sWTGVfWC!5^?s-y2ZqLHt9xyC7r%!hVBA~R+Q?xuzO@*i8Xs6-7Sc-wYvvm z5O?ssQT+&eQx7Uk0wETJMW&tzggK@z@0g4GUilmTV1ZsMJ`;xC5^H~-X~f>c^4$X= z$T@t6jM~<+z+nj=hLocR z$ixfjFksDbCGDfL<(;bf+Tkdw$i>y^T>0^ECH9e`s|(sV`rDx>ti{5iRQHKMo)Y_p z(Y$w_BzPI(;r7k4uy`3_7R-{e50XnEE_{+p65&WKBhsMS;1QZ=`$*YPiq>Ek>OUTT z?rTS&Fd%Pyzu6j=91e$XmyFnd90_MDm23pQ6a9nS4CG553caf2WTR6?7W$M@fFp+J ziz=A}!nZ?jPJAH?r5aI<%LjJhQbfn&1zC|<@TW%W=R1>IN*pF;3m*@_)@ zjh2u^HW6XJddaZ9QK+Iot@a5YiA2#j?ttWEC2OMCw`l|NBsV~}k0SstMWV1G`MWH` z{8n5{i>l;mX;9MY4TRV^X-c-=3rEptL9V9fw5+cxLGo^xw}a|KDXd0z8;<^&<@t_B znKWv#I*^HJhe3LeG+``3b<3teBWsW2b=lN11DQBq@-a&&i3I<6GQsjW>KX5njOJ!9 z>IbSHlefAAXCqGcrJOk?J3+$|zVH~>myRPg{*c;a5k}f}>CvLNmRVFT?K6%+t*PQS zhu{&Qun?oz$%s8%Dl!e*jbQ9Rf}AHRm=cK!mBRck z9<3;W3N{M1Ua3V@2CdAR>H`rmp*>`MQydv|(M+q~ns3~(tv$Bn=0exZF>hY<^<;uB z{cOF}IfhVqZoT1x7mpL{UAy9H7Ht>#Wk^KKKVIb9DhvX&fnRY8@*^@WWQCZUw3rQd zDv=^RdJ0Kl{1Ue*s>ZOH3@pOZR;ivdgJuM&eB#69$>ol|8KTLzIg#af)4U&6QA04D zkZ#&EejWtYByAp^InL}jCKXay9#k#X_T?GjMqU^acIK=#!x?@llwn_1=MXQja8QF& zC0@hi)J5WVLK=ka!Zh~D*RqI|cHI-dd)jFrS!H~8z|85-9Tawm>9Oh~94X_0{6R5{ zLJhliz@AOgf8Ft!?{k~M)wDfK{M>e5!p3}%Lst9{dj-1OHwXgh5}3>q9@!>R85gfc z>#c9~B6Yc|D6xe)Qk}pEi%9Mk--{BpO}y;~Z)rvFwH9{a4zdW~>85(|1UZ9h* zmRnItU9~kAX>wgm{XJg`8XI|H8eDihZQ5ziZcgPKspNe8McQ_9Zl~na;#`yo<8!;| z=cJ+gZ6!zI6I8$QZ<^8t z4%ah=mS|O5GB)3KGm+>c%Eb!ZC*vs+&E9_+y_pC}|9ai1;mv%qNEO(KE8^?S`@w}# zB-_edc~FWM#V_)dcn>%8yIMGv%W<|K_X0sQ7EM? zm9su(pMxKh7l&kp)#UXYhdv!aHqz9d(W082oB^yDvV^bJ3pz#@d@ba2dpTOj zv%*K;kgr*SprVs}k6f%Ynx`|Bf&tdtV(Uc8KlU10Y;f-E>PwMF#!n`=MMc^;Rz)|6 z_TDqoA(c_Q-s75acG9cc2hV4jK_0rfL11Cw*P$DEv{s;ZA0JBJ0hr$(i>)(2?}fd( z>$`Pj44+J*iKH%0lJR74Km;H5@HY`pjGtF~s)`JAo%cD`GPV~MQtx5mdP_Kvt#GU+ z&SiSAmk9HUAz7-I&Dz10>z*Y>?b@Q?65(pF8~ORi3fVT_5X}0+Xs(W&yuTvVE0vec}*qx?W8&GNA4 zEpMSoT_E7E3nu3f;!KA(qgDnW`lNmrI^~O-@l(V9wx;TxpeFuycW9%BSxh5X0>6*| zv+UvF*1X2929dAS!Mc`8r0uZVQ`vmv?Q&5rvxYIewYizR4`dhm9w~`T)YnkCr;nK{ zLnlN>+7OdA7>Xp^XrdT@hgSovvkjw!tk+pInc!&I4baz!Ph5i_H~O$#H*Ex!qE+>c z!2uFC0r^s)q`qI9i>-k$$Z^d(w{sN6V;nP@M45yL3%>cM9TQ?J3iQgGV!AlN?dYr; zC*?{Pp*-?~hR3uO(c8}9 z?M=wfRHC#gJx{V2`Pr36g_J3WtXwJrDSEGbglsK0y;gDLTfnN@FGrgBGY1tJ4|+3RKkKZGgmya{X~#d z37^{5_)4V^&ec+a47UQjB`Y!oigRy&We{rq})wokq zxZ^I;aMIz>)F+mg%(jr!D7Fb58{8Zz{koXN#hetJX1s{=Eg_q6N?+r<#94hoY4cGt z&*D~_*McSC&gOiVH8o_(8as;#>ln_vfco!#v)pj!?fJZ-w+^z{z8lvw>->gjqLSC8 zca*brHb+Y8yUmqXs)I>D&(gdkilmnpJw)`^!+07xuNu2!E~R>)9SJVpZOBH2g^F)^ zK@AmyK+5-X((!gkdbs4)DVomt7bCg)i$~c7Y1(Mn)UTB|lApSrec#211Vg$_%eu}~ z35;|7WcB>X7t&^5*_M~VYWqaVRj7Rx3fJ>Sh$`Lb>%@ddpFVsF^St>+bjo}VTyfMC zd+>=Hh%+7C4UcQ_FIKNG&xCOtBcAm5;CfI|tJtm2q%ynY?PSW%qazObT_jo|9QY!8 zgh@E4Enldh#Lq&d^WNpRZoMz+m@@>PcshQ2+*W6~?1x?WeZKMF%gp+OcLDz=LRQoG zQL6b={o^s@8q1BxeD)YrO&Zsd*ABa6n<}LA3^rn%*G97r-Cl7-`SHCKS#6cpIcF#?^`$dzfiBSEQ!mFIiS6`Svd|>;5gru0<$bPVO%!wFn@ zYJ?a**S$gYh91%KJ-0#i9z>3E9Y#du+AffYQ8^BOKuU@JV39zofckd!JCsI31PZ$V zSdFwC{Q_mYY|=(U+X4;5jd|6jm=p2ZO}-vbR@GwmgXPfooYA>Z4vkUD{A`(rOv)?o z3U-%)4qHd7rIjSsB|15!a(>0d%o^>}2zUk*RH&3}$@8FO8OXF1?64DC=(VvU3Lda%d5aYDIW^1t}K~-==Bxc8psM9n{{t6cP;u4 zSolM4*QA-{4H!5Si2gBjtGKcRR(u1*54d{F5#k?easksivyrd$y*<%p_< zHEZU8TDS9<_tBHK3eOt@l_?DAkC+cQfSAXEGv!c5h}~EW}|_3`Nh)iJjt9k>9oKLUaw<9L;Zst zbw*vol-^pqX6K7u+exhvZBn&E6qfZEG6M%`foj(lx$hTSMf zQZ{4zn%wh}fs(A|i0lI_&cp1nx_g@NT&_Aa{?`LU3rw17O)_Tp4RwnKWyCnN`;iWA z%3TVRSRXOHqIJ^!IOy3Afz|D1AMC0%x9RBeJ$#x)t&Byd zYv|XAlt!~9+$&LPK1$wiG%tbE5WY#Z495GDfGoI>2X}kt$^$x)CMbD+dUt>mUkw>jJ%}OzwlVk2x!O87WwqGzdJ8{ z&Ra_>Cs;nR<6M{J!W@0ilxMABU@vhI^Iq*$zSactY0MsoSgUdq-(q{~}-dNW}o_*tK;v!RzkUZw088azj z>geiEK6)O~_f&P^E$YVuCd|$D?~b&YHLqEjIf#BQ{)F%%Y+O8A?UD(vPztT5p^xOIx7 zw=0bn`l6x>mLd0lncyXmKooCkB36o+O}D=^JD?I{;^b+W*}o@HZ0s4rM4QbiUpQSL zq%S;bzC>P>?~3 zwQ{R#@5AriwR*W0S;;;t7$+bQ(hY~R7robFLyo}5eNB79$~sD>b0UjE(%{fb-@J<4 zWJmO-)N>3NBYof9l~$9EF3Yc`r^fmHo4jV5CvO@bY@x@k~yhtViCkFla_6pk7?N2hc3g(n}YxhjKx zkVe%$(=Y2PI<4{0BdjsZZxS3g36nx<UBKgeTuxN}!t7R}Y&e;Z_c^)3)L zp@SM@!I(QYz@1j}*0d7)8tQPuz95PYo-%R=esnZpEn&hva%mgPTt=E^VHYSXmmXtQz8$ zg{)+QLCRC6z7sT>TFs#hsfF{=k`_ZRUwIWspK7NR+Jxi2BJm{_S$$C1p;ouX8&SUG zs?|u}MxH^M?Se|D(*$t&-f(q1|?sadao`{5Mb>(uqoN+8FgLR*e^ zWL1mEMi+VNtApiKp+4P_kE^75M~p2CTLYhGvi{nq3ukq>ox|NtCp&wK;H8faYpk2H z0Wx*)vz%-QnV;CV#dwTIbXI68(Z;6^Y^U(eh#_bbnU;#vraxDT8*Gf{c-YjMx|=lF z%yv5~R=qOsca5r}xI`njzthW7uaOfd9W;!go1A>sU`ib>J*K9xCCFL7ULaWPaLqi` z%%@2)yGjdrR)gmY#^S1EZUJx)V_oXshHeshJ^QZEr-V0pcL`UP=}Fl*L@6r|G&+eP zdOUH|RmrpQBZk>>+Dj(OXcv=b4?hrFAy*-9tQ65T)b8N-3N>pKdUw1+kQ^wx%;9f} zC_3b`CpF0L#yA%}!_A)QhLb3;7G{)CpKhYi;`I+Tb7)n@o13V5HK4?%OJEN>kkifL zm&3{2BOQ3_XA#*730Ed!c<)hwwZ3K|jF#KIkMmHAn#Wkv=l1F=V9DpDu1r+Z&WW?6 z_Bc?RPufaaLz>KwS|xj_z_V_nkL=w*UqnTltEEoX+$b~h~(X|CI*nlA;oBqn% zfPH32*Y9ADx}P9Xy~33KK{J!216|#bvixI|{_7boVS*s!#J(ze+IvHbNEB<`3L$!! z-Th%R`&M2T$wQnetPhFszFG+Knj&4ggq832s>>NyVi;DG7uP53V_x~EB-Ci|dc^m{ ziN&S4yF+Z8OhUO0irf~(5${p*KF7^R2Bsh9Z7CZjZ^oa8agQKXJ=v6yfbWG?+NL%YWJ)u4S4ld;^I#ELs6VJ#| zbsI(LwqY5o2wn=K_8C-zR8t>ygpi9C4}-*ctHaTI8MtN(4~R80PpS0Tf!9n8S8quW z2UUG$tW;539Vd}rRaOZf=Fe8j;^rIsMMT;%^MP3TSF!AQaOB>Ywx!;b3a;82A**7N z(Fq$`8_D=NfihybX+mm?O6K^O^;E?Nx2Bd8gqkQ~`lLo)xmAG{44zZ}+Qas$4V%J( zhtDNn@#z(@$091LU4I{)Hx*|Ha%m)Ii)}#30N}*k`7LYx&XZFA4{cZdQwI}li%sI2|+|5*3 z(#fFe$|gq*do?OCZf^bYdwbTnU9u+0nGI1T&!X}5FD`B|gADD)PiWK z=^P;A*ZOZn-EULQAOb7}khqoQE8z`s(ef=fUO>_KsJMy4>24+^bySy3`NE=zl7bAYZ(`A%mvax}6=_&Ns7 z=z)ddA5BKtgYt(mei2jo_Zm}ik1P={htV~7FP>GW@l)x!5>=$jrL(BDuXlQ`?hhc>rE!y{W6@vv z;FB>hU3Ps$@_B0&qice56VxBIPo1nZi(#_jm6?L76-)hqBSeH zGdW}qs2v(?ia}F1w^>*yNnqbZ#+4NugST)2B~B;ws-(qMeO_S1G7GkL0*j1T@_b*{kN7zrF}1hc-oepniN( zN1t1+)YV>K-{3HHHZT|g8wXbbV^tmmFHROMn7^YhNY#1AB=1v%8v`xD{mQa7`Suw;O=p0>p(Dn^o-(i)vmH+|90UssU92 zWJ+u<$8o3Lsbz8zrxw3`Qh?~LudwJ@l=*X_59?S&Z_Ycy1&XMcRFN2an?2~D6MmDaKzub@Wy%W|)RUB}fbh`ihLy5>jOL9aTt28P4fDkaQqo@1B1v$u@3my5jfvz`fP!*we?JrkjZb;Kj zd7$We|-t9OP^i%W%PqRPCa%Lyl^7P zT{V?Q>6t)Ab~-y?@5#oMAwRR3j|*b37ZXPW79x3oW7izMM`~Z@P2`=)6FN7vORL#$ zVk-3|(X!oJR>$2>jZyb1(|diTkRE=hQx_tXI0rT`TR8nSjGRW_&~9}^OLny`bP9ca zMdv$(3D4<#=X+Ha37^eGiHzZE;H$p$5l~X^5xW%es1&P zicKdYla}$wMpUBxzbH&mBqwEc1MJzsYeP3^l4Ys(xQ6L5BQw8h)d^#aquV;kNgXlk zp9Rlba^piT+;7SDW>}USsp!Zb-_M`9JApEP?YERINYD99!ppIsQ^i&N2IiiVJXHP2 zy~Nqc47)n8vRlo19LV&d6Vn6?dU~U)I`jQvdG006g`DT+2*uc@Ek){`@P^~Eh#IAx zo07H)Upl?_YJmK|sSZMGjnAvgJ}iWF=8+i$7)4#STqDn7ci$Ua(_FL=hXeF@L-eMe zSIa(D#AIZL!C~&Iej5dx&JBnzFby|E-I9rk?em;tS*=iwXN$Gv`;(i_=l$?MpEdEgX2i!mn9dl0x%KP5^rs&5dpwSFYLkVItqbrcR90lEgo{P%ltYDzY;!w-0bh zAg|ht07tnBb(5lzv)>}m6ikh)k>%*?x! zBAFXb?ZWVEYHF%#-M+1IkDAKnFH22MxpqgR9(5fOx~xb=hW=GH$Ki79L~$m}fa3^)h)G>j1f&1Au8{r|p zKas!pH@w1&O``zwp=0?U#Z5pi=73&*1mnnC*3p;BE}2jii&9SVt;xbI0O$9*x_rRh zi*VKaov~1S-McUesMy=~b#BJ7>{XmUb-lE42Bb_70r*awU-|o1=V9SATpBzeqpsZ1 zTl=jhA@zWoC3^(0(3EeHmRN6Ck|qJG{3B=hW6AaguTbdh!ppZjpb9u?S$)|4`ClZ-!9F1d`EELHQCDedVt}|#6 z>Du<-K(_Booe0sf-i~@BhZ9!tCZoE)TH^?;3`X>&q1QFtCt}-Rp$!ZL#$wB6%^&u-LIgfXKcbEkUE>D0P}NN!Y~2V#8EOmnI@Y%Hb6r~gXG(l(fa zH`Q1DaJ`}$^Eb6}vLS4frXu}(+7=S~lQa(v{&rj3LR$IT^%RA;jq0q6H!hER^G=(C!=;^IM?#pkJbaqUt# z3q1owWv_?ug);5DeI`cc*BK-RxX7~_!^>76$Hbyeq(j zGVxMAHU_x}-MLED&G8p;JOQq3tjQ@pS7+tkWBoQ9QMlsxS6z+9jH}Hq`v&R?Wb@Z4nJk89dAh}oKM&BCL0KES7b{&DB>PU1k&FZdVR|^s(>$NH4RW*ChR!r@ zY{!GueJk1P)a;hBdiSga=gE%Bp1NAsM2_1}WsK%wz&gUcU#rmb~ zLI3?VqQ!U}CwWpWRh;M!=v;vDp)iMTEp0IFd{5t9P^4r}z>$tE*)T2X1W#BPO|Oh7 z)=`17sZ!zFu7$A4UykNS!rO=tw4YX}L&9g{5B|)wcv>5j^Y~mk5X7Q;Dc{c)@{@}G z4pr&YqM`Eo3d>@5>vATAf=nfmFrpcatkCEh!bBY;}N z%B8fvzFsjm?9A@_BG5N2W;GVQOw|PcK zli=hQHFSz26Qiz+Uj2&7Bq?7JO@Urhe#$4HoHS>bK#^bK>*$soQy?#@F6T;r472KnHK+oyTI>jU`^wKs>xW?g#|YKMD2Q5M_H+m-6Sh9jLp zLfa|#@S~2CUiM?>-a9VeOnQPB54eis7wn4x02W>>3|x#>f?R^}R9e|Y@-6v)Gda{p zh?gs4E*I$6V;S5>VierkGzpi{#=N?s~GRVoJ+}WbZ+8UAUTO7Ts z#}@JCwU+wXDudOBR%ep07Y8&JVI~4hD6!ZU6<+vFgX^pCC13`3ID%vgH~&JctdS(T zJJwc5QmsK{le07!yImBSF?i;Y4OXULUs$?`gx}u1dPD>0orPLz=~WPB6ScC=&9d_Q zIdcMZ>d&XBS@wkR&N315#~7rC-S0oLuBLyfni2c>`_*;6TYsTIE=qXi1a6|qJ;f3J zCp~O9HHdpS_=%Amr`*6OB_ow=&l}QL%acfmTN0^+5o2I7%v3+0Nl=6vQT;m=1-2lo z$d145(B&D!Rp^JteEzuCp_?<45AdtGs>C7?WPxB#_;O3bVs~ImmvEk~@{$NsZIHdcGs4_7&48LXrEYAX(mu zVRNU7U4?1*mLI}i`vsVljud5l_(UpkSnLx{w>2su52M?QU2Pg9eQRbwJacGsd2O?A zA_~znvV4UdWRT(t12r!_$8jQkmKYj*H&D}Jo@$NYaBz?U?%n$2a|7GZMBaWr|56t7 z=J@gHrt*=}yxzUSxD2(OY3C5i%C+oL=vPg*U*H)E`Af?i7y&;mYN}4q0$ti@=_nZM zO1ZFU=GYe-LtIW-?TB>-&A;rHtYP}bYT$hsO21boOnsv>82(1Br?8lnS+Bo@XQ|i0 zy)5R>D0HSxw7A{>wR2fHdrRdJE33cm!WDmUd;I(%(g;k)SMc)c-t45ryUZAIc5Qy{ z?pWlH1C7Zg~5k$pZvg)g}rKgMYua{88doCJM6`@ z$BuuW1eAPyR6aBL6dcmXK$t6K)UgY@ka~=Y$^QnFB$PE7dPyL2uJJ5)&{=!>cY6_O zws8%Jho2FVH(1Odna;lJ{HzZRM5c>$c(lL6EE#cR<#I90U9!OogTS8Kge^bkAYFf} z^}@+yij|t2Si-jWc3l3j2ixugM~!`Mi7V5VL3u`9$}K)@3TSVf!M*pSPV*`)5~u_b zO8nu;$UDGD;ydsb~w2hdRK=qg%0G0HxXxlJE~h> zZCyNNOp3rsO|PCHj5#CPYaIHST?CqNX^(q^D|_-yv$<-TEC=1YG!UXL3iNpzTZO*7 zgFz`Z>+<*fwD6Ltg2^yNhQc3dSzQ9`n0tKa2UazpR^q2#MV;j) zs&q4~jJ>K;Xa*q6p$GlupRTBjyd~1!IR`-Tx8{ZX?wVPs8nz}!68mcvF|OKGEKQ^(nTIcL5C{@0s49<9sgg0YFU++~X5 zQaPw}Yk~2L4%bh~##r@}p9LAmRc-i-in2BEKn$o9-cfEj?cHTj! zGeJp!e8|3ktd04i18Xt&>e(`=p*wHmS^dF z&Kl9L`Qvl8KkQ?WGHOu1nbgh>wh&TLZ@rxw6;`0F?~ms)XgQ;7ACKlT{cOX-XnA`^ z-?S?hZyNx;Us@NJ7+$>iQdjkvt&!{+N zr)3HQXVxegscp&jP~S1!gsjx}j?=0jBs|l4KURfgj<3E-f|x*$F_koSiDY71)VnUY zE@>I5(0XFU^&*&N&RxRCSm*QX-GUb<(QT?=7Iuo)W2N_L`f-KIupEp*1L|1{sB%tCb1O7C{Oq-$tO%{@2q$d8veO7h|d`KTSmKaRI^ zD7%849ssl(Ws`H|yt%rH!!8S!@@lPTvv@0?wHcd?pSQxU1m}}(mTq2Ggb33mN11C2 z$wJP4Xw&!wzPB{Y1Z0iU>EnvKJbyprwbFBz4~)o!xCj{8QBBC-f`-$){75G0Ti1j= z0y{0*u{T_p>UJX=cMM_K_9}o=k}>bSs=P#grw5td8yw5K_T@eBuNxSzdm&6IfhuL{ zvkf~HMT~DOjN6#tW(H|ZV77(G%XSCTP69GvTIAWMVP^%f(y2+?`TF8F zZ;1O>T5@Oo!iOJvs-H}=>kho0<(|XD#ssbJ85_Pw!98y5Ps=T$M}lt(~zVgKixJ~INrF{OOx=1 zv|+H<%2>~uy~_;pmQK2xnIshB(qV|At6=q=p?PxeK{KY zH+@a*q-t$qp*o)89u9ip6b*<}m`tEN)hQnteA4oK%$BTDE7h1;cAH9lTrO=3wyjZs zta=v~L)=Ejes)sHH0Mp+C3@E{^2WqHLKl^7-~9LAOh7Z(q}fL?R=|dnv|H-e`i-S( zB*$v~fn_m9$fQ5l^$TTx!3Lubq}4Riw64$cB1Q(YlRd7rMW{UM4PRX?+`?@+6VwD= zPuwv5=GbuI+~i`b!7*gJ)%5^vOHWBNa1h+4fL?)?Z<%$VcNclI>%5@ZJMSw}RE{NJ zZu%f|>}A?GvkH`#md6P;4l%zChgAZs*sx1yVF;j7Q64S`{ZqTesI`#Yy z{by3t%QLw?vu*>d(*D6d`}arB1t{4S8vX(VWs84wsa#oYgZ*Z@*2vo-HbX4WsH{MMJ7u7s!bkib2bdmF&Omj#PIYl z26eC-H$4nx19d*rf?QB+x zcImqK8R$v6*BLri>oO*7xK!(^Ty@xSUS>Op>7``Ljr85Xwkda5DG$Kb3CO!lx*^Q? z6kiz{fg?!!Uhmj0!S%l^P`=BMGss)b?7(o8NJP)$e|3PcxYP_Ye#;s-{+e*~DF2HZ zNeUQp>4+Ii9?Aa+ZF|wZx&b|92eH*Hp7Tjqr;wK9G8VV^t6mocb=FawFM=YVA!pW^+c99vFBnr4z2H5 zeFXI7>yaxZ6LsTwl~8_4$uEO(rEArRmyA73c0~0BF0#e#KBh};jV|#rN&VH{IcN$j zju+Vg6sFMx;YP!%kQe(Ap7!gQ<1z>Jpc(5b7zGAfR~RZ~n4_dG-Awu~GWasrHSCQv z?Ks-K3AvN!ewWgWU%%@CN7}M8H^~*sRKL#=y@gkxKkFk^Se;ed#)iIIy=2;6ZT(pA z-0lCzT7%PrQzKOfZfhB|fhZ)mK1E2nE^{+fb)Z$aP8DPe%aD6tL;Wmy@vqjU-#0i( zHAjrZ5<96r1{2hvl$WkjBbo70TGxf&YtgM~ue=*}nS|724*AD<@}tc# z)W&J1doj0Su6znm$(Xerqwx#3Rxso%hTS&xR8p&Q7xo|_&PM))P`9Bv+fqb^!EaK@ zKOI&SjJIJ;Y?^I16P1prv^iViMZ-#IBk18w<0Df$HW~gFnMc4gf}{39MYj1cH(nB3%LoZPpQ(7I3WC!yCBxRGmAJVhbS{#(_6n)wEe5witaB8*(HNx$!f4l9t73gZM_G$OharSlMM`SHOH-;S5Jmmt7gW2XPfJTSSG_RMP zqfixfdMp*~0@+s|^JZLUHW`rUvYhN6bs_Kiq(qectBPc}nQBB^t4m07 zw6EHasd3|dXq?tsoSd0Emq}UbPpj#vj01IX%Dk%Oa;c{4fi19FpK7w;%KxxYc1jAI zdGLM5XF^~-X&0Tg&iCY7onzl?f9K>mN3Gg!8pyXT z(j}9fk*mu2)JiT%nW{56(EIgM4oAl5tUe9yL*%^+ta-OzfI5XkKh=MD6C5#jNe*Xz zdwK?hJOP!qV357Lr{8Y_;naHI=WOt#t_>RBioK7>D zoKRd|Y~o7tYQ<(Qj?C;#@-utQO(zt0ZhU1B!f_(g+R73`$X{D?b+iZat8s}(15?*Y zmTI@O^(Z`$A~t7#G&rd;#vd7Pd862IX=JCRuq&YnSLaljH1(bAp$)k4y^P~P!A#}m z7k#w54^B+8*w^T|mTQv}k$+b!L~4pDovFz1+HO9I?7-(Gh?HKov-Z@;YzuQseVd?I zKh^5OB*l#*cQhf-&CI8O{@s*)C6{fPKQkEy=TThnR`Me;(j%aiJ#nWwhk6{sNT8WY zA0q3d_{C$j=`w6`JDHc}2OA}=(!R1EzcU#RjB=8AiFPo?AXM(i2*#)Z{WdwGb`HY9 z6=Q|k;Lgaww4AN&#BV933R`*W5uHt>Jx37weqG=Wp`77(9k~~2D#s1ADV}bP23%eh z*Q&@lmww7sMnM~Cs_cOGJUIsYb7E?34`(r*w3X8SSjnDb2Ow}=bFHb&A-RT?F_3^g zK@O$>ZFn>KL_Y!jvOpB+gMS~)kL=@R+a_q>VT?O8-g747gf5pLa`eq^?`V2_HgvG)BL)_zs=7Q%@?~B)*xs*m5G55=yZ3VEc7i zLo&Sw`lb|r8CWBD_0rT76txAfMDE7zZVyVB7WfJf8z0f0MEsH8>5_e6GMRWk0u&fzDNQDBd9VbhU}d-zHCJK=YM!%CS#h$`>!qd&ra zgyP5jc1FpYG#gImw{y%a^}?YzCVw1^s!D_e*wd0;(wpo>-7Zdz{b_aN@-6%B@nJWS z+Br=WU)34xmG2QQE9`R`vFm|Tu zh!T#z<_xklBE-z4_u*y};(5F!&y{K!>DEc1Ie1O@#Hdtksz zn7VpmUPZK?f01|fEwq_`$VAs!;g+*j3e{PXh=$oBILBJK(|dq8k+*w591v zGAHRa)|h$TJVW=I**bZpp>?%WIfFaoN#gE+n!2I)K;~w66KO(I9AmK@nCt2!z`y6W zg_NG#4Qy`9-+xEBzzyY9sl?1Mz0}zpAz-gI0H`5bwWo3<@@HJhU1Kd-w|rzwloCwm zA;MiW%4RP~9*><>?B322xx{HTNzY#_mZ!8@bfubU6{X$AA910(zV$XI+WntsC{ACa zoR=f05Bm^+RI0*ZO#m@Gbx=-VS`_BtfHm?uamX{T@Z1qZf7BOzTNU! zZj*ob5~C=&?zo7{jTe%S8q%)n9uHtr-=(14sOpnZb592_Y3yRsb|`~1z(2r!wwRA) ze>6Zem{&@MxqzqgKL#L;3j16Dyeel|9|>lO8fRsnl`3aJUlc$>jkBchot8JR&q~c* z5wr}3!~tqFb`3GN^7<+PcB+Q*pncjbMMHfM9HxA^y)AwEC`->a#8;zXE7lV;52NSs1hHU(Q8+S4Q<&8M8|k^e-B8s?XAxUDBW$ z^<68~XKls;`wMc*_Sa!30X2V+-C=dtkb^50J4j%nXO06%b_0T{AO`xXuGtLWPXL!M~gf&iaoeF9*}H0@g?;Iq818w~kWeRjkA z5CMIv?sls_+hKl4fIgGs2oAXxRB_aISuhzj@~eeKKqUYnPzr#IRyV(|44|OAJ4(wd z24cpnRyEWGH31aVc4;xI)pvi>^6G)i%j}~8)2h2#w7fc?<1&aYCO0jw0_eEnj|k}B z!3Y2>gY7#39A)-}01mKyJphAtqo7Y7(-mxA0cZx>w*%bD6enLBu*UN|=XiA;Wm{C_)wjz1MQT6#wu-T#rQ$;_idg=^V|g5!tXSWR%@j9H3s zRi0gaB@t&04x&jetMVbQBIATT9Fu8720@17sNEJDMG&`;K7#f>WQOhg$GDG=nOk_y zL_z5N|31XwCaE1ru6~+Du^6F+Ymxu{<^EDKY2L|TV!d{o64!bfb!dmsOPK{DyoAr| zSs~&{U9?UjVt}cgUxQq=pn#ZNk~?+J0ZPF@3QGRwn=zP`ax*{qOs-hoW~-WRgjAu( zail8N_QzXQ*k?Xd#7qVA{tjAgMhz?DA6?JLLcXKbX3t|kO;N zbNdub3X_>SsA2L`pvUH9+0T4r!3|XKLZSJ&nZNi_EbG@eqj;|oB3oTyMsJ_`dlnU^ z8K+q~rTq#?tSq|8=S4675PpBw^d@nSj(RvKX?ILvYbb6$`Wg3z9pG3ZIAt`lYW9}(+}f5o-FxUD(R0lF>>cJdpfTVH18GbT@_Y-N z5F+bhbebum%4)yD~TVNbi)L(lqeo8Pa8w~(*KCWW^4U^el-n}->dOf@m zdG-=}^L*=M@x}40iTJnuQFkoAcHB}b-@<#9nAhI~nSRhbW7g|Re^X-iis0nA!+m~Y z8q|JMalBv~#;QfJ0}K%EuAo1jP86&rt(&Xt7S)gZ$1z+H0dECe&T4_&x^LmF9}t6J z5g^n|Jic*ub8iFPmM!E)OtgvHEfYXUnb(f%jKZ?q&o@H`doTHw55RS$k8*DT#TOzJ zEB4bn3*NKCKc^>;iqvlFI2j@Z?a3096Zq|Q;rShK&j!VpEi^62=xg?-1-Q3{;tLg; z7F+VwfBOr#hlc8m6Jiqf^>cWm5YG!Ykd}L65%T0B>x2&Nr^Aoe7n7{PDq8+AXXVh) z!RYIUdioH2?@!zr5Wf``bSihl0Uy65ENO>X)XY4$?oioD_94G`c}-g6hB4<=w!Tf5 zc5OWIwD11*#c@Om%9HLt7lwR&L4sSMy*R`)k)^r;&0h3<5qf6zKLgJ{WTImK3@GZ} zD^Y$j6Pyq|wVYr;zmNybUw+t4p4K_B?*CRQZaW>$DGjX$7lY_zQFt4OF|sn;_Y zsYCM8YJ;nURBYH}{Nq=!bac>a+HNHyrQf7#<#l*gm*gGlqowMSp<{;ItS4$H!J zbJF-xo|)owN|g(iH#N``G}YF7LHBic9L!R10(XZ`qY!Cw#_j{AH2 z#L}E?v9*n6-tvFWR5v!BzfB+`w4TFxa=Ip0 zZSIKFLw73WwQ9~S4f&h|3*JF947AzU%!SG$IBVw(;{4o}@`6y>Vnz>b*Mpn&j@4om?ua|+&p~RcG z>sD57e>-k|47KXmU!i4%4!_u3qTRgeWl6A16~Z3t_j)*ASn7C1#olQSd1USI>f7g_ zuA5sa+~e=@2k=YfDa0VHtf^REf*GHEp#y4C(;1(&pnaSCb20Gi8jlG> z@pGI12=pasMYQ+9I`Ue|fEE4XJqSjEy3tZJXVO*VxxPw`1Wqp|})KdWqIa>*< z>MRLAu>zf(!yY~`o9x3|Un1$RaR7GYYL#@n>Z>{jVLH^l*hNOKuC3c#0tt7rq1`pC zyQ@0am$vqyw&?ty29a0RUTrR62zP>@pA|2(bzc9}{AWoN{~S96IX0F%{Afvf#R$9| zU2zHCLupWudMh;!wZ3F+delOJa6x(VyLMLj^e%O+2;R#G-;W30C9fFjyjs?izh->t zCT#!bnf>-w@}(Pdd~L1S=8}go)LWxx8w2uW%(1qHvUi8%@u{fjOHM5ib7+lZewv0h z@RvsBA-7iblk0AlNwa)hw(4Da?t}ZMtre#R2l+b#)q6Jahd$~jYUZCtfv?(^3h1B5 znp;aBMpk|h7U}5#j=cSNogCdd*O=pVOK-JB+yM-#;~#7NH7t{Z#Fer9Tp6Ck)fm`fpa` zTvu$ZFCpN-I%!4q;h2@(`3uM?5~ulpQ+T~xtm<|B=IoA!&(=a*5{gsNlPiW){MSw9 z&%EIR0_siuKv(xF_!hx0=SG-39bG~Qb^Z9kN8&=O-!mKgGx?-2<^OYz6y!1HSl_KK zHkEU?^3uZCqGW3tE_Zbg1$NC$8kPFHAv_moP9hsz$ocHbz_#h+r4F6BKC|$6w`w%f z!P=WzPazwah9(l`>3rdj zA-ZzfgobY3>XGfBL75vhuk0%E@E!#|AwK*2*Fq-7~%`Ow-@pp7(+GUt)n4IAL?g`4khYj zagGK0Mge`TMLLOw7u|U^_7M_x!V`A7lJi5?cd1r)sd5zub4kN0t%RM#En-R}j z!q=iyz}z_O=^>rS)7q{Eu}-ySAcMi`Qd47p4Z6N3yH0b2ngLm`K|9O61nDs^{;@RVZba`Lnj60+QCcxX=^aSks+}_JpfFIo5&Enh* z{0IPksTwROm8+lOR%zQ{`+dXUs+DW>;J}Tte#$z6CR1$HXmNbXTJFL>4Z41_TxjaT z-ppKfm14}c;ww-6aJqqU1Sj-erkY6B>hZ)!+HE_vpC^=SLJY+_EdGo6R>pe$GtjbPpiaqbZXRDdXT!x=lg*o_PHAZd~& z`tHe9s z8G+rUM$6EACgle;yWTknj<=%hqfwW$pW)4?GveM+t)S$#NGFy&`=YJ&kPp(g)RPIL5AcxBMJwID55vZF4*~gBw4_8wm z(9Iy$rR+OY?>x`*3A6|Or=k6j6I6i?JBr)GuHJdQvj&?V^dGS5rKi^gq3?loqXDR+333UdSogi~F)m(}f>)B(?#)*L3xmKljjM+hM|7PS|9*79LKsghtPyR_{ zrS{b?hd@S&FMm|;P1SvNdkl;`R6m99F$-!MEI~m`DBbO91=UTK#X;=IOX8t7752g8 zonMSddUV2=fZq5hT2c)D&;LRAjsDe8YZ*oTL?&R}S!>sNr)&GcBITR_NKD`7+fe_a zT!C$qWmOPE=#y_n*?Q&6SnuNn;q27)e>~kPc;Ta8>{z;7|4==8LM3>8alqTj9^ycL z9IUAoxWO~x?#YaCK}H^^arlv>^zWH+d{ZT|kBWR6Rv>c*m00;QW$5?_BNck^{R2t% z5DAF_Dj>nX$GM`*&Hee5%Pb9Pv@nJQLDCBjrRuEFSvsv*LnCIYB!NUq?+s9dTs3zU`_cb+x(jwenox(m*Qt zQb-l~yMKajkGQ&x{R-zx$q^*%&usjhWF?fR6(q91a3981cI9LR!XKMhB3FERqi*Bu z-X|cybTiQHt6zWvb3gPeu|LrmDrQoYU+myW-Nto=lrfjqQ6^rY-ZHXZ-Qllu{2*GM z8>|j6$K^RGf)E^8;3NY3&6ctK_S+XcLpgJ^ zRFyBAyNSr3K>T6-0$$TaBIMkd>G~wpUv}}iwP*hQ{0>@U|NW^Md9UO?fwZ>J7sIX? z9AHI8YrZxhrolx~x`!vtz8U+lOwnctven(ES zrStTHi8}7hU2CERX44pIBArX)-?oo=X^`;$avs~&e-4yGyC45Q!;dtQZf@fZV;chOsZ=ErqY#bQQD2O&#YDU9NrMN>w}*zQ@_gpU7Ms%&=x>9IwPA_zdRtLmxkJ^y-GUo9+$ zFryun2fZM~4q8!+IkX66F6m3ZfI3 zx@03}4Cq${7WVTKk)`r2orTPM^AHbGNfdR^AW9zo^&(NbfDcq{CHhZ!`DTxJaMklu zi)xEl(&Y##a6zv_B(5#i?Z1EYmZHQxK9V3+g)I`vhdp4Rs@?yB!+*fof z1JOJGfJLmX@;>jaq}=TY)kC!e6gZX_Am!j&AGW|7Yov_GCoTCG4oE}s0FuB3Gx6cY zX`d^}TV_kZfv@>!rQQ#e#4HOX*ue~h>_r_Uu?q=n`$`g)xe_AE@Vt2OKMA9ys5}US zGUhoX66BvaBO0C><0*@LzKF$8UWPI`emg~vHJ0LlaK^A<8~>!3Y)lU8z9pa2W&X=Fr%UX?^1C|NT08@hNP%S1C1z5}Ny`{)D5%3*uXgBfOeTxtEMZl)5`;Ae;1fjFeP>w4||l=n8vA3>Oy(Kw6^ionyzPoHE+@ ze#^@m2)(ez(n(D}wM5(-#a2i$J+*|~OUGJC)jXaEzTn5k6nP9)lTE6)@SWNaa>Q+& zI*^@q5^}_U^zWOo@JcktA@Fj?8=gDT;pSwmj~uu=Q|@b69k{X-6S~FS%mP~zzj;lz zkJzitY?`zfH6h|M#&w2%)9Blh2|+ZtChK>peoEY}TdFo`iFklw(XDt9`>W~_InEbD1OBNs-qIjG-oXhP z*i`0iik85?guROsPYB#U1c+O5{*v^{O@Lwlhp~4I&MfNsK4YhobZpzU)v;~cb~;8! zS8Ut1ZQITjvx5%aymh}*Q}an+vEg z79l(=1v4g!tP#WaC&sY-t|!Vt>r-YBM!vrCb@A<4hSU%6LFiNH5S3}Pumf!`0HQz9 zY7j=cRsZ{S#D0ns?V#$ZT9|K7#<$1e+t8H68X0a40e#>d@SeJXWla}E4!f(%sf&Ll zHNt`xL{VoBps*d=62hAK#~31)jte{JwJYWc=fY|vbAmD8*wgwm?4dj6mhZ%Upk)d_ zWS{SbtShTM`j+Oze&8a_2gbqlQyOdLLVv(fKY$eB)QxceW9lP>KfM?AukokwTBcWE z9peL0{x0Z;4h->Z;YvtwT3Gz468N_*A)OiJ~KzdATdQ#gP6lYN=+%lEu@*D-M+0NQq@g4!#Ss+qa`uXQd{;_ z732Z5%P!-6EHwBce+SCkwthaG77sow&4xYRlC0}5$We_K~5tKlZ+^H6^cskWCy zcJyzRTr=@6Wt#_fOwy@sPf;x61C|dJ^K$}E&Z#YHbAJ1%37%Ez2Qpg|O(_NM=bnBB=e{3?=TINNv>UDy)T?u4dG!Rd-LtO~S7ZcpIn>J)ZYGY#ooei+1^HPD&9(O zj@@K_DW4>M&H4#FDzy`1i@T<5%NHygz#Eq96+!c^JWg}El}^^b=O5`PengFt%;|Qr z$|v9yqz~eW>90Lb=?0lWbav8>6>?@P+$9W^g;r_H(`*ws#u=u5hOv`8hT3A%vX#GB zUDS_$F7h~sa|i;iLo={SvM-F)HCg{C`~VIh+~^I&vkgS z@L*;%`&vbq%(0Q+W?unqulbsbcYQanIOwW}WKU(ry%dW^*BW zrg33<_E&6YCE{nqy??+F72d&CO!GiQJ9Y~_=<-(tJVPa&Oo!ZeEh{FpqEu- z;GDJw7T!aPG`_d)CB4t)d3}1!u>=S<(Uc*TV&cJCpk+Z?V7LZ0!V!ct!smp$z>SDp z1g$&T_iJ<28ge#KPldRLHakk~U(My$A#Evg!SbNb1kZ#D_GO0#2&EPnxAm4`yV9P6 zDqzF}eWCdw%wklBpGJeeVQTaR9;h>wy?A4(zq9?JBS12VIvrd)h+)bvB2bhvNmF(v z@Ks#EE=lDBZ12TBCUJx*$mk4qE$A5fTM=q1zfsUJ>VZ{Cw+^hD zY2E6rkJsf_@xLptAh{>Wh47n28yT$IbFJmU)C3P`RdYt+~>`B9~1$-T96 zm%Hh6TqoV9LarWfBKfkM5Y$SIJzjQ5uI>}EZ*g1hnQAYP(`AGqarQ(uQ@g=!*`BiW-l+ixCLn z?JA;jd%5_H_%G&Zyf=$3NkB)q@8kaihZbr*?NbE-0y6Xs*ku3#0Woo~V{|mKwKH?J zFtRgqVKjELv9WSxv@>&cwlZ;Hl>5(O2s#FT?z2vG=@^HVAM5FP9AUt5HA*6|!S z%IRHGAS~!COguK2N`@J)h3ux0;UR)f)*o}u78Z!ZsPvc2-84gm{htYwt>AHb`_ezl{WLT;MdC{YsAS!9wY065|RtjhT^+t zl7(4B6OdpuR)ppAWwT9nSX7$3sgYpQirER=CaBlfV=I{%GfP3>6@4*{^Q)9r`pTFh zZf=UjvE|PEqvezm{W>#!0W*tNxa7i=CEYw{X&JX9D`J5fIlfjpcDzfCjXebgBo&yl zy>S@UP*Hj-TC>4nj?A!&P8&y*MsEIDNj0|BfQ2kTN=lKL+(_^`buKU>l zq^Eda*Aerx^9Jo3;w*f^0`Z~8L6XewPrirE1+B%d-WsSygG|DO>L!m)2KMYCjzHLni7f}9Z!C|Y!eZuxs!K1@_w|$JbHiv9^`=MZ z^!Cgi+4evSIDS5+O@i7YhSmm!*5uP2^}_9JP$gS|jO!vKE8uiYVw?4@dB zp(vndh7ul!bmG0i*us9+zhL6gyLrRmd1@S7T9lMD)(VkaZO zmyrt@zu>6_PeX1sdR|DpypaqQe%?Oud|Bv*5bXX#eviKWmof%TnBEg{(pGA}35JuR z_(0qe5VTQmv!>M87^t@o=Dw&dqzCF#(EquW~e1TMXNv;9x{<>xayyHK-fZyyZ_y*$IPl=$VlkrbS09NcT zg=v2%>z>Yw?W$bai!ox7dPn5I(0od?1`dJ|^h9=`f)TVw(m!53p3xJyfJ!P#FkU7F z7RnXX4^FF7lB2pxW5y=v=Y=^w-TJGA*a`0${5J-YSl6;M6C4D@00snv<$u2JNje)j zTK;G4%T|~AE=5QC^d_@u`h)pr9Zv+W#d7elc+7m5jsz>%jvGd{-;R#`K5zaHR*Wv$ zsBWT3o8oXNyy`wU1DJdsO|tGoA(j3!LIYi9RFZOe>8V@qjo*!5t0}kw47no#=8z+EEFZ)09X~^58%fRsO$|$kUEv6J80IzhMVLLd zyEvnFjg^KuR)O2(9p5zv7SzX6iG{Xzf=?3`Z3g=0Z3cseQ;e|Q-)9!fhnDH>E;BZq zEI!7|$0_=xtPFk5DjW}5w2u5*j!Lz~MVqXF6r8t$FFx$O=_%!^Uo%Z|4k`OW&YZJL zaApY}6S{S5c0Ef~)y~gh_15EESpcJItQzVaaFaD1)<~`0ESsfOtdY)QvS(EM=7DZ< zt(F8+>)L_g80U7iIG|}Qb@ZR5H|VcO{cY?wJ$;uIuV|4V7{=D7t>@panHjJ0n_mmm z9p-E+zSJV)OMI}SH=Kx-^TfJFPXvr!tmV8-{Rt1*h*(vLBIpMBp9L04710v>$V}&J zp&c5Q-YhfU;SDIJtj$8+4mlHLbv-X8;xMT&*XP(Gk9n&Oa{qO-qb5T$UB`JxnDAky zVMoi(zNJz%{T`9!0%aSl0RcpCEY;!T-K>oKB9 zrX?*c>(`wjvtRByh(B#42@^zIv3^ox- z0k2!|&zCayT|H#)xb@;bTz}JGVHB6H*UkOju+-E>B9S01mrNlwZI{BV6qyAF(o+Fj zVYYWfUeMnb(lsJ%rBjt)f0h8jLz3MPXatSLUSV_NKk{z=6mmh0rNc~|Jz$RnA$Ryf z8-2!(MPrzXVI}91|2c7hF~l-+;&bc~>lBBH$@<3oFE$ye~Vzw2&2<$!0XN zOTxDh{B)dvOBOGzuUDc|^bv3RJ$Q)pF_eQPfV4i1oQ+TkH6ouwI9HiJm$-y)G_Zkq ze$+Qay{C{X*lB<;uZ?FNP4*W825F#_lvc>hFPg{g%f0u87}f`+aG?*67CA%|X26W? z)!&*Hr>G__@!Mis7Uq9&1~UA;2|2sU;BYgT2fve>OVG{0@tXX#BJ82SaXxFm}|r#fs7b8y#qAQOL?l z#nN)ZG!uP)e-f1Ij52)gao%DY8k+!x$bXSTLHwkHd4ab@pd;#!Kz{B{n}dSFI`G(? z=0DAGx#Seg;fH35gXfmjVscsu3N_BD0Cc6$t1{UctLMaCPNj2=8oqRqW5LnlzB736 zU2|qPbGd$;fQkMETy)-8v`9aS@I*qWMA9}sy(L6hO=qJo_*>Q;itY$M1uModconv=tW)<$je z-5KM4U?sUYRNnbB zD0b7zyFy+;u>Csk!OYz<_{@^Zpdmac+xzG7ifOKX{|58tQ7(pNJ1B#LqpK}?{#2aDltjkE$zzvL;ohVf+GCgG zehuDN72g=&n&g~|BbV;@m!>5FlUqcd-Ls-QUloR%y-dWh^c99vO_?>IZ)Lo$*fR7x;Ja?B1gy>`TrUed-&R1-2doYYnc~$@jn+ z1E&SuN5g#$v*_C6``|6oe|$$pJpP)ek_i5)6>-?_Zoq)8J<5=t;n75S|0oX`msYmi znPUsjxOjyzi(17?cF)}YS)8uj@!7ivsNTIJ@b`lLU8WcEU<3Di+IP9vF6&!i%7Exz zyIUKmI3~}c{z8P$*#2Gi7au4>mbRt6n`n{0SdXaG0r8W9M}*_2qXl%G3a7a|)I)-a zv$Mtj+>8zpjn3q<1B`BUpuUtlc2c(ekBhj%i(fDBJ`umvGkOzeZ_FN%SZ*bQcbQ)l z<_PU5M6t5k6b{zY?~0IA6dizfuL0`UmAd zBjUzRO|k{&U#WP|xq@*OhNua;QqKgzigl0!e#TJl{*vBM@3QdHy_ZOe46(&814 zfi$~PNd4MszY__RLc?eP!k9Q~i2OvHa)|wSYPMxROK~c~fYxnOPQ1%7?8+L2eU&uH zvz9=H??yD+sEkE4hIvU-G-hzV{4OkGPZf1Jy@SSLK?giva|+Xl1vg08ph#dZQo>KE zq^cN2!IKr08JiZP*51;_(#re*s-){pkqPGk!laV_cbh`+`gxj)#%7D>UY8?3j(6rG7_#zSr>qdZi6+s0gTvI~VfJBXqh1 zTNp|9GVY;H>zm24yM!OOK#9v++>Fg* zSVzTRj!-J&0uXpFu5#4rYdD8nZQn3?mon#q8K|AZiMDlg^GA}8IRHjiZt|#NSM!M? zpig7_8VI*!;T|lZ)axa~6hpmxGDTRC!a>2!bNKn=taGrHc?TA;Hnc%xUsHx}1?%4a zs&*zNM#on_VHxE?jG2QXvAoQqv6htJR=nb(DmFQd1Sj(p>CFT_P5N6JVNI%1xKUtf zA9eUGxaY)kRl>lu*rKrR5{xvb&st%K@yfK6v}HZcgo?1pT)fbZInKi-krwF*5Oz0q$D1SrNZ-LyHw8 ziAQmK?8)=fT*L1=!~ZPXp1F7&zHDw$!bnlzS)qHd1&?Hah2$aQ;~LDjtYQZi#NIb! z^gGgc%Hmg<1NNbCslGf*4iE(GgnB740QGnmO(~MYcUz;_!g^bbd{V0GM{!~%u4rURRDjPIH)*5=Z3_Fu0KF>$KuLBgCICCuHXam+insyc}wK_ME1(I0M@NubRX0M~sT!C|ylEX7x-W(5+N0mWTO`f=%5o;0wI0e#)RQ!dA6Ti-zuxFlfZGUKZ95BI;UT<|Q?2;m zZxT9KSS)`$m=VF$bP}zDEh)HD2f6M(KO5yum6oU84S#1b`K-u5I zi2~%u{g>4(3Ku4ObP0AdKpI+bo?@73WD&Js3RCjmOB?A8EzY;HFf&&0!=(DT*}+ps zV`xS*MFtC-6c$b`QiA!p8IQPc)l$6$2APk%nyBbcQgu_P+X&RI?9-}?%UZw8M>D_{ z*LrHgg!)#2uuBp=M*IB&3V{wAMmZUS{XM9=9IK1~ikOK>wo3>Uq?QH-sm~x56*sEfa*lFsJ+}<&#(UQ3x7|EI zc}tlW#fRk3wlxjaqN*O38M-Nbx}!?kuNwN4-(;`I#G)KqAp6wYdY~$y%fo3cEUr>@ zoh>GrlxI(FX*485v~uX^yby^z_UsDwj)T-C{%xXYO6yrZRq$ z*;LpJb2PN(^4knnVPhc|{k}{+j2z`~IBNi7C;epN+d&zjPCw^yYxcA*OPftNPhL&Ti3pDPT`BzlVV_yE*=WDR(HuhVq6#y?c z_X5wSs(OQm@j8z_mjNO7!$5jR{tM!kEbfar>Nl^sUZPlpP&CPMx9vN>)Vv#`I+N1oGWgJq1116}3{x_&iKy!On|4II^U;K2xel6$H#%;YSa3TZ{doI z7`2*46_U#)mQyJ{spy$YwwjBp!(yY=L!tEu0i7t1lXQFf7)Ty_9U2rG;|I~_B>U=q8S(fdcZc3N=k-ICAvgAR(^6#tNJXPbeyv<3p~-yoT9BwsQw#{%~hEdMZDmgkhJ%`2)_TF(p;`mnsE*} zAEO;t=GdpoSm6Mok2qryIHBOG0v!FEm`<1@=lCJ$60ecz&%G2oIHogd@{$CL@6j!y zk9{WH&nB?kO@kE^KJ4a)PpvU7JM8DP93EfSJ^uVV$kGGZlLhV3;QT^p0h)+W5NZk! z$zB>Ns1k%>x%4#;dJ?}WKO_;j+Q1Hs+*4FVPw9C57uPtCLp3j!LwMki{3K#D3tQ+{* zaDw_~p^M5|$5)y|CX&>~{9IQN`Nx9$JAxNng8^k41=9I_?wuGkRA!(!UpCX$KBX~I zOYo1q;d|73CP(De0%K2$ERpcNU0O>%LqR`=`ysw^4>_w=Fdaw}_Y+)?KMsgpc0G#Y zz8qC_g4yAs>rLc`?TSfB{qr+w*Bi<@_3G*s!5~37Q^)#!P?HdTFW6I+PX|GG++E;`-BU!me*@R zmQd6m$6r`$GvB?i-Awc%D&=9*Ni60A+Kfk@GA(j}W+E<|4LF2!LOP+qLY0A%M}ThA zxTB-@3ySvgLONF~3#{1GQ<;1WUX-N?fwgtpbb$J2c(V{4tQ7^dfkcuP zT9l4Pn(kI`VUMbf5G2TuIkd8e9pg|{%sO%1j^F{5fia_* z#wBI9A0u{mQe!w5rIAZ=DnRE9DUEsGj*OJ~ z=BB8c!XF(u3?;Z{(j5u*#hI3v+ammBSNWS~_=-5zHld$l0WF_`@&gM3iw1Nt6@^3< zu5Xp{0icb)x=lqllnUgQzKG_bnaEtSFKpzy}qrL6m~cV1k?=D|+b@eXMwwy=L8^cHO2 zuQb)nii*&>iecxolRDq7ZZ*k-v5Cqbw+>A-7@hV3cl1JG9*~K# zKbNvUv{U~M2punyC6OYqk{l~ugr1@2`M?|`EHOP;Uei}~5tpW5R`wJMD*3C}`D=pL z%9c@XSI*+96x%T;y+#W*LoYe6QHjh_KFFF*OP<3`zqec}AgH@=UibC>2s{a~TvruL zC()UBTHNc0ZMNdBak9=ntg?OSWYxmTINg{8vPAeV2KT@Lqb#80+&D^xWUk?pQbj0F z3bP8OO;d8CC9g&4v^|xY;jm;~kanf}P(wH^iz{bhLtIeR6*eLA#p4}HM#PO0b8pX% zLe-AKkHi(rix;Xy{P;7YDYVY?-C27H^RVRC^nTD5*LZ{}?YfftV*(aBRxh|A*9_st zZ^HGmrdgPtBQfx@z?VRTv^|aD-Z5j!K4XT|iXd*HF8UR_0Ua=S@D{u!zW2(6KsI0Cg{ha73W$t5hW$7T|$qFbv%=Axn>IOjxXLmDT}7CV@*)2mx4$rMSt` zA*3io0n}{Kl~xQ2g~NROq8a4iQYw7$Y;dIxold+}a`Ik(uFBxC@0U5QOFP_OHGmbn zGSRxxcU}w9k^^Zf7`NO>qi)znCbG^Cd^BOe53r-;_c9CGY0VH5Y}oN0Gl#~I^6}=T z_SBRs(k*Rs?mdi2n+9*-R)%e5qY{_|s)Vak4hi&C@d?hL9h!bhUJASYAUj&f$fGiC z#c6xvJUu=T}QwrRmU@LWg~ z>{b9wpgnab)!RqzQwF(k0;AB;RvAywSVW?;jzUZOfX5tt&9sGS8Lb2Ux!=W#a+`vE z%f+DRj$M2lOXbkH6Tm|wt+*-xc29g#rySiUFzvWgJ2Ji zvPvF%`dgrByt}EpIqoZU@Z|^PXA_GD%dcv*d;%cH)FSnkSvn^Ub@H^l?vUDp~gRc(x>&To}nN&7_ zV|bU|(7fT+lUCq*0Q0A7=7oDXhSc)G-VaXafm5;df;3)nq}*Kv58{2IbT{3X2=t!#==DXr>L&!)9tfdSRsNBKgfJY5nuY^!)35DeyGP=Avl? z7bKa?F~{fIqd!KB-9rV4@TzggK!mJF~_dV`PlbS_#yOVDaW^w`Xs7(c2xl z?VX84JwSD2F&5aYi*nvcbOif7itmU$H|7$Y&^KkaF8KeL6TU9s%zom*`2EJ-t{T%rzI>?c;rs`24v$ z^!zaWj=VcyaH`{lwA;`4aQedQOZk;{bC7$t{SI|=w0q0opL%nQ^fGBpCs;&rH)xF^ zSaI@zYE3OzK66;QtnDx1aw586`PswqJ0MT(0jYWT9kn_%pvLRf&5pJ=-|o=BQsY5q zWBR@2FV~l}PewpB`3vWUz-P64{1?$YHgm@x50D>cwnQwWsEO zRJo~ixj07x26RYGH^NgB{d}HiHU=RP`ZpAl~%c|+YalSDN zN9^N6UH3KTJy(HY6Hhu*UL+2dAI&6g5kCe+DB@+hWgKqBinfT){oYU(u8A$}0NKX? z?ee^Vq9*h+@rF>fSU%}z6#)=rHr4XMx!YL=ip^%zOptza1nYtZpI8yE;PjeepRfRt zQ{o$wi6jNfj+y0^v7|v&rFY^O-Y5t?M{92>Jm|eV!hCWb1%8or9)*8t_Dk4orIQ4{ zDKo50+^yROiDjn9u3j`_YitV;Vkj(@1&&2&_+_o@r=_4m#uIk$ z63hIcZK-idf3YAD2MTVD$^8Q+{GI52v{X?Gy{L!q;}?$8=$2-UpUOGQAD`xDE5}Cp zlzL2F_p^UYUgDZF+Q8Rh*Rmh|JpsZ0M8-i7Y@^BD;sz$8k)I{y5?FTCLc{^ou_UfL zZnOE-%>X`Ljb6Ifo7jItg7Aqt^UN61hh&NHl}d4IM01MdB+4VJ_U@3^`9(zMFT~2s z0qys|#6fs0@<=bd>%5dXw;JRO8DI-qXSRn-0r&g?!z(XgDX>{Ft?=ATX5)ONJLppN z3=Ym_?ODS`Ni}o$I$n9qw-6_yIn7fK$@5*a|1B$EQ$P7d5E^avgs1~UD7q)zFNIN3 z8-WV}Q849pbzNM#%0*zaM9>&m5j&kb-u36;JiZ!%MfJxql?9I4N#NGHu1)p$G)U|E z(4?zpp~@$x+2;zkfn>g+^hiQ0N&be39o64!2hUic$Uc#DueyEpz==07;b z&bTaejjYuW^rGjfh=sm24QoDU*KXP?yLxW@Y zToqli1JW?9-t7AMrZ&)fr^bs$k8!P;J-G(ly}G=q?h>>@uD=#@US~sQw~mFCZQ&oIAaDTP_^!wk^JW&PKnlWe1riAy}VwWF*H5P>~+ zr84wLt@%j94NWncssdw?qdBQYaq`T%IZL2$rZ`g-b-N}5D8DS-x#ZQPQ=OMv!Qrh} zUDPUk@m!JpS+P+8qPRPs7d;1!*vMN&x=xVbQs$upY!h6B zG?0D><986sd(xD^K(B8XY5XHMK$a<=j94nMS*MjvPo-0)!JJfovq=ukQ5Mibd!@PR zCfBL)w$b4(x58nS>b_0tH~-bXOR3dh+D9vRk@c|ca^tn_GTWZY_;FG^i#+e`Uljid z5ID_~d3+Uto5wtQs150$TQY!u63_pXC}V_uY8CO*D(gi(rxod@S<(o7%TNqpToQzN ziWB)rRQ#e_vJvsqD|3K(lFRQQUuq3~!_5Eu##KDx=YPuec|iIq^!38O^aQR#b`kFh zLc9z0AwjdOS%`FU#s{Sor1Qr3$9sPdK`_|-5!3;ER=_(lD4xmol%zWN3CA_(0r z+UsaI%@}>A@o0nlF(Ryig}P(Z;uIU)GVjrMqFcwUQ05B?31$m+IX4md!`(3?!0AhEdzV(1x0UnP|MOG>3R33lxop%81lk zWt3LgK4(x`h$=M4!r)3zHDV2y81TH6naZoKkr_94eVfzo#^KbP*P-q~&V9%7P)>HH z4h8-Z`n^Z952h6-A)YZz_?dYZ)oWqySo`8H zZhnWb0aKAAlrJ&A_A0OIyC;!4X7J*mo5T(CHeuzajaZPMTo?*)Q2lrafufTxwT|`9 zza%Kl$RBOwkNP4>NkLjY?LP8iRoZ;|0hCI8M0}mjuG^}aw6k!qa(u&1PW-5<-*y2` z($xu#9E9t|yihKIM97M6YW$EdjPuZ+@nvbv)MilGCsr4EjP#$B;z^K*2D$BiC-spm z$LiG^!QHkjZ%p|^_%IjvqWSv#2TxBEKhSIuL%{3pWIrp?uODPjqw(ci_n#r3Ur0ce z9M=0@w!Ph~-lTd3sK&9YMJwDdz<*Qyh}u~NU`bNl8%u)E+nm@e&gVOB!1hlVD@>gV z?p))lLgh28d$Pi@$8HAZxFbxLu}qh1Cs&K1Pg3JWv19M2ZR{(%EGW_;SGf!t%ciFi zfY@fDha9V%*ngvLtNTYdMTgJ|0q0q;mCEQR0~EH6R_QUVdm!Fm;6?_vRAAM#tSP3; z(dY2RF;qdoW^zeEs}0gB>gM?oO%CX;KW`QcO2@7W8a$%W!1=TZ>^jx^Yfd*0IqHZq zJuQjEd`*xN)s&qnZ%tx~bTbNg4LX}?x-_bll#cS{pK4~6f|mFs;iFhlFHb9hmuFpn zRCP%6oA1~P5BE}&+2}i#Ah7$I!vn(o-?$ zNPMTU{*pBEd~1c|;c5dQ!%d#&%CCZ}AY51wF7M&paJZer|P7jw+pE$QF z=&lLaA=1#8GJrzGr)+*8XXUqHG(@hQgY1HpYjchNB$l1(joYtTLXL)d_*==qBC7N(D7sl`Tv_JKQJ zzqt5h`$*J$m!k-(?k;fc%mp<&PR-1EviQWDXMVM8*mQSSw>(6lEQv zjh{Gw5EYzM^nN5)X#xDa$z6dAde+E-RrGM85(4U(VZLDF! zg=B&&c@d6yy7g^7l0UV5_fgK+8JaxABXT&f#ujei-( zHhoUZNy-lgokCoOQ3Mqn`g~+|-Ih#v6%fp3~Iq>aSw)2lODj1N2nE0UY%$ZL+It*#nDE_^CJqltfHu57wN>4 zhRRh@%$%HQjNP+NsEqBiPNqcq?7WDVa;`s`G}G~r1#5))Sx zA(!W!wWDj@ni5tP-78A8-q2ZQ zTtHlI$1GD0l>?0+Xn|q3%Ny=C*4N_y1dMeSys~V7i?L5_0Qrtd{ars z8(%ecDNni)z=qiH&pl7o>{C2Ru8HcJQZ{9U&GN+YfI*GAx(=Cojck?fw^i)BGMkSW z7Z*>DWHRCC;#rvH0La`E6N$O-qR9((O^PMe7cM%Y-rJ1#wg@CFEd}D;vU=`hLHoz| zNY;X%R*dzAr+{&g8n^Co*^aJOuZ2qtc|w<|TjyuTyW+YnUd_$@z|Wpr0Hya3ii6JR z$hSaZ^GaCgB=#dzb`oqN2;32!^F_{x6Y^ke`gd!2UdWgzU#lc|3DXAv^#)hoEi!o| z)^rBpMus5BSJL!U0CZq>S}V_zjWUpxa{_cPdHvEp#fqPG&g<$6j@pjrQ1d(%s%RaF zS0xlS&Zyr}HqR8w_4~^D@wh?h1>}tDZ<&S_Tl;ve5e@WO+=JfyEq?vbFW!#-ujp#JQtjhB2NSg&xj>m2@ zNTllq>bd08)d=nDL^rfybGyM$>@g(uF&tgkCv}mI)fZB^5ht}LQaL{7w@Jn8mUyVg zUyjYhl@p;CD*NL7o|X!mJR%=Z6M5~Wz$`E;v^YH^^aBg#ew3;cOx`-IB^ftG65$F= zercbH1>lWLD4i$FD&2!sx5-`!(K4!3`oem};)Do_Bs*nUCWF05h-r^nl}>;?W6?*b zC;?iXgWRd11fh?099KFLDgQz>fC|J$y%0M}^uIFA?4xo8D-c%;0%S3eZe8|dKEtab z(#jJw0$^aXc%iFK6L-3;yjF98*{hE=+mAKNkM{qHJaA=i)JMx5qde?LRfAZ3H(}PZ zTjP{^7VSE0+Lxn6avW_49#J`p2&g+DVJ}AiJ{m#)ynZZhTg*L>=RaOG$fw~RQcx!N zJ1gPzeuqA#YVw+Bl9zF;8~h|P;8auWOa7>&=|}3XHcQpJqFeH>XhFZksIjFr)2-Dn zi$_9=Q`Gs_i9tyRS27tt=c#L~Vm(uRg2_=`Sn`7t&19Aim$077Nj+Y|(ppy_6j!Xz zWHePeX2MHt*_vg^9W@G&c=MdrGCLiGdJH3>i?)n;l^1hjhLTjnym-or6^nApR?D8p zY1HeS1DtY6#kKTkg3C*yoK${T9YWRGmW_KyiETsd;F6#?bR4oc@n>RW6D4`VxgvO2 zV&swP_LmFR2cJZ5pv&j5>Cfy2p0JQhSLrc#W#Mgf)$}Q*qiMQ&=c53~YE(BogP%E3 zuuJ_RCLa1le%xyUT}C->r~H+4>2VpUb^a+8h6ep(l~i8_GTQpF1_Sp|Xp{AF9#Q5g zU)58#5-utkN($br8JV^cjipu+wfXA4_|s>&mJGWgkh?)A4qr9XmL%(coU6=T>58%O z(@G-ovdrJ-*bc*M=UrQf=EQczabE;71}|WqahYDBEqMe(bOc2fz2JejCT!WcdBCoi zk_VM3wbl2D9sDUNF%I{i&{A&WidfK1cW|Vxs1e- zy+MNZ);ZKh)rf8&z*428&9*$7Mkj zlX969-n;Q4M?AVMv zLZo01{Do>L#|eZOE@OMWeLH==ySujwjB6+b8vX)3ZOw7swSIhW!qk(-dA!dXVWwVM zb;pQF=N~xK1sVQ=Om*!~FM&AlbiGI-l9C+-Q4~b6l1E*Dx_`Afg3kw2%&V$c{gebr z3M;`BC2H~mU$@+~CnvzDX5lEJKXbgRv#wQ}-wqh#@0b)M;*|>IgFjARpjaOM=-1qW zA!JDLU30{8|1z7bt3dK11EBQ6j0_ov3k($?88bDZ5hpTHt5nYom9w6^|HHog9S9m% z@gQZKUSVKNxGZ7`*?iw7YFx5o?;zO!((|`0_^<8865O=0yEJ6X<-l(+lPlT?B`B{D zr!U%HhqFXa#+7%V|J?_&6iQ%N6d)ixh9DqR|9^d;`oC{R{&Npf%?E9WH{5(P{cB^< zy82vyc0^p=t>18~j&4#7&}p_frKK%nk$ZjAnFyZ`Eg}UbMI}s;G$+dp0S+*eWgVtS z0s#dG!4SiS#OuQ{Lw!A)KmYwJZ-M>*$;r#hdo!K6TG}ULAn=I>BAbwV#)bZM)&FIB zfcCCB_;ns1mU}n(#l}|y|Jb`LO92T=!H_1t9W|)kDLPhwa#B)g1Kc_0viid7^*3~JBYnimf z=70@9W#58;FE0|Cr>dwTtvphTr)qyCJ0q=nkjFl|Fmln2E3wjrT`7N%`;U1}nd#7j zn-V#Oqa86)M}$o@>+sL|CDIBvB~t5lvvi7-i@J0&YV|plsw3lM$*R8*?0kvMS_Se| zlRqzpv30Y`BO9?UZ8K`QBvEl)*NA79Llta~QoQxpU|3~re_pW7pP|U{=u*AEd$F#z zc!~u|+MlEnVG`>#MbLMw(G2K{VF^r#S4!GGL|hTn2k*MySIr!v^o$I@cC-oUj`8(G zL`S!`g+$A=zwo&HYoK##e}Nj*-$&6nXS=Gzy8mCCokPqhKy-zF+qP{R@BOxI+qP}n zwr$(CZ5w?_+eN!-x|n1Zv%EJmcXH18EXaN`wY(xDZ5{1lnJ+ZxdIoEEmxo@R+Cr6! zB(z3pS53pQhobTBziI3f%@&8~aPd&snLF^^hG;X|SS7baG63)+H{CDzpTf9V>`UQr z4@_d)CW&uWhIqMnW^6lI?Q7v=9iI6{JbKCS#*jRR0yEsiLQjWcS?=rL=<9@DEe;TI zb&SGQ!bR0n@fL+U&-OOFV%J8suAjobzuxWX#I$qn!pPe{P|#&PhnVr~CX?0?;}LJE)e0z?}^c7 zZdvacTfh7fy$S|X4`R2z$Yb9cMZbdIe^h;bu~&a)hWXpxO38kTBYh)(&&ncYF)wQEJZO+PdhlMdiD+^LwH13#dFLeglZsb#I;MtowQBFripp+(#01OxX{%* zSd91+>ZeXtaTW;DD<^r*_(Or+h$bg$=FRL|AX9X%ORKGj&r_4tZXLpKk z{~yo9yrQYd zvue|O|3Mm1mzY0MRBS*v5GD#%A-xDnvUh?)n`IEQgi2hnXMsT*MMSsB#3!2m%+hGd zc)QTX!a6Kz^t178DU|guzb8GizQrqq05*H(vwUP427>;0gO_4)ZBMw}k=jo!>jiw$ z>YK)y=Lwas;T*a(?BeQjxUQ+Qb4oXnzPr~@x?>uw3CTdj4YUx#2o*{RJ&tw8f>p{W zf3hm4GFjyg{&TJ=7_lP49ZZlDGY%XgIo)lG-h%qsLSPy(&EjK25E|^TJ7X>pH?8uxdmz>O|4e1 zxR6kdO(mt&N64O~^?4mlEF7xHM&%#G=P9k&8Y&@Ft%=>|K|a)#IN%JQ>?xz(A*5r- zQO&H)?}Sku#md(mGR(vpxrCl9VSgYjA=>@@=#jK7i~lC+E-Yb9pIr!nGgsRkK(=FK z%T-4kt9?U?N8m_4idN7-zX(m0X-iY{1V%UH@*~Ywgdu`GJG)2G_!cqUz-P9gh z7kEBVbQrROBulHQr0Zw=%`Tojgzi+}ou~CnLpv?Ckb*{PG_#QI3A;8EMZw!8P*#6Qf#iAevcbC)Qb288%!GYl6OaNlGz`Y9CnD`R1z27pY3LqC?~#zioszwtyf5+2JA~#7{Cv$QSO=+Y{(6eZvRGF%4N4i8Xb2Hf@FQ*X*{ zIH7XnLw~Nark%C7#pfh@4nD43!qP@ZEPX57dKfhqTQ$!+`d||#!w7+CuF(jT6&Db) z1TeKSA!nD^YtLEykz!f|fTi3|(i|DiPOJD}Y>NaJEQV|3r`={1BbP3mv9ck+r!5>} zr7IbUX{9zV5iiBLZEWUqM-N$D%1|GJQO>St)2O-E)~{PGuxl{iYLrGWl~*@1=pdE~*9WY9{noR>Y-65z`ASm`$G}rGgA)rV`tDU!pzM zKos&TV33RqgB@2+2*V>aMz=q6Tp8bWkn287R&XOFg0C{X{vHlbcPx$g5-RYifiONJ ziG`p4V_ie+my`n@*vu$ZP(dL*kIXHDK7itG{EJCQVN51KR@mO}vzlO1afqaAJy`yC9=Vqaq$ z2lni|Q9Yrg5#{@}lCRElDMWJxrRRJu*(8j547`HQN@p|<+qZZ~RusCzK(+z%Xq;ji z)or@PU1PUJ^kuZ#dTwj;u;n51k&=4@St;h5cUSldjJJ+Gb{mqa`2&hz4i&kXLkF4c z;t`DW%+e8!^bFe_5ShFxgct0zPk~ho2{wQ6X8aj(u_o+_94d^8d9#^A4I%YW7lwo< za2fpCm2#@ZUygQFzk1~u;FOx4*P+@Vd)zhg?hyMwOaXk<^w|s4YZ}X&{xX)3c3``m z_Nj`xp{vPY8E!QTu+lT^MyNfOd(BHk=ys3n_gd0)EO+D%^Y$=#tG*dpR%4`ZdH&W_ z^nnS?=kC=%e}F{~8BJG|tE#lMI`6D(%Ui>KyDF*Bl-w;-rfVB^VcV5dup2^9x#&#* zUQ*^@=xNm;643N@EU}yW4x&Uoijx@Sz z$&a~jLdpp*)2c6F+I4dD$C!`RGk7-RPRC#~a3rBqcQS|u>efiEm$Or|jfXlZQF8uH zaiH5W6~(Givrl*gk*b(Z5@%g!+loNOukSsBc3Y@!c5dTaKPYfKQf)ri6p)Z9oK%O2 zOrM|y^I|=OOrz!UTaAH)#y7bOaHFVz2=%7wz;w5>q~TkP9y5oyLvU$0uDYMkPPrWcxsL*Bc8x)~PVXdO*zSznhSw=A6)@khs}g-IFF*jEilc_KiB; znu($aXP&%_rJzW#TtX)>Edd#$EkXS&`q+_@$9)7wMENc>5cB7AO?K+tA`~2=7`3Ih zRyE0uJPH>*eb4$q9mR%aI*9n(EQF(R7FO?iJZc&rEY zcO2yBE<)WtQ5g5Ixrsq7Px+si-(@C zW-@+;BU`nPotzg_*muqM&K#{w%TN_e!6_BhPog9_uQBN8SQszCpPZ^Vd7r3TqA`Tq z0kk37fnqk`4B}{PithD2c$-JiFW4t5bJF5pV9mr)Y^W4uyL1J^O%q~iu^ByY zMGh2_*400jItlvv3*AxS+BfEH-!Tv4Q$H(ZpC__79w*RZ?p(f zd@fQvfTkCV&PTAEL?#0CoeHyu465}55p|V< zgs8G_CgARp2L`fi)kX~)viRB1KHIg^RnCE^`nYiiIe*cD2B!HYHa&6tv`R3W^i&+0 z4c-rO95_z?3|-T&$^j27>6Buu_>i5dt&Ar%YVj7A4&J^gBpaIy#;bMnKG)0CRJf!) zS5Kgjqm&3(y2dywUaWp|?RN8{ZYB#*T&Vx4#Iemhj8)sD@eK zG2p#~&Nam%b#CL3F8M29I}qVku{Y3}aSdwe&H|-nY;luot3X>L*YmO$EG#*|xGMuu zk97%X#<+53l8%m~{e8~(942tFZ1oif(>LOS6ps5Ca)X-pigT?FL#}q_xOcmN9WN6< zrk_Y`f+J*_@|A3enltx7Q`*F7d7K#B;0N38Dg2d`RRyHA)_AI@7mC?KRf%v3J%Y8u z-$FT6enCe&1%jv!cI|_?;IbASZ#Clu>MTVj3V3OzOQ#2{>p2x{3zyDauB0cBspmF|y?6 zIV9rYshO*b5=9+^B%^L|b}obM**ZF$I)txhlOg@@wxlZA3pVEC0YXr^)xKmvU6OJ*ola)Uoj&BN}vaR}n4@*|cXYUmFgEDtr=%9@wZO%KW@14jEU z);&kVBaY3SxTv=F6NT$+;%%>okf>k%AC}g2M zJ0xr?%k;160G=%lrwe~xH)aTR-9z6?I=&@p^dPI<6cVN;MX3{K_N6nHlg4NuLjV1- zOCC%zFZYN!8C%Y^?`DWwJFTMnENN!xjWvYS(qxD#gC$4b=3&h ziSVp@RD39zg_M%c1-5-9p83Z`4IA z=_oeCZF@~fuK%odRHT%Q6ubxKeY*48PNMePq^eK~&I8lmI$%Ev6swS&UAb-Uux*TI&tA#YDV+4ypZJfKWg9^L%MutdH_c%G|6@i=RFP!su|)Kgt6#{JHQDw%Z=0x$0zFi{h_4!O%tut-xhMi zw3ZE=EQs4d)gsfggcR2E*VgN{CRu~qsk`$y!}7gjIJ#eMt?5gPzj&-)#L|TUt8`BZ z00SU^K31L71o~z@ zt(wzjLB3_^ww+#FFgb66Rq*CPy$bmKk2x0%k>`Ca{CPOya=wVm9TyDgXGSgla@-LG zZ=BW9)DDM^_!?O1{(WxTRsXRc6kFqy@=HPoMWIsz62XJXR zt=Lf)qIx1fQXdLROMs1BdM(2boLiSqE@_%ekf=|YqP-Fy)1|to-)M8Tgnwx)0xcsR z&|Uiyfa{X`X%0hq4+sDnhuH>te81Dnpo+2Gh6f zQY<($S+fRVvCHz2XGnp(vg_($Su84VgTOq}V*5(IM&Qf}Vt?2$1Z%60jegRdq={2W3lXOJPo?q zQ)|g8`M_)Lb9MP`(1ll2r6%iZZAKZ{90O1i0vmIk6v;s#2 z8i#_#&Aw}feNrVd~EIf2Q?beIS`^9 zH_s&g1|5Cr#sLLp|3hK5 zaA)}#_F5Rz#}N5`$~`qpXawT{>zQadW{O}6_ZM${>PS0}I$TTBwAxQ2rY*;ZeePD|!#mf9-B|z|FzGr}8v?3-`bzlpU*A_ffHRuN7(!v8g0|Mh zHm9{CeJHNWlr+V5S(C$rj_#9i037a%E3}u6UGfR$ybzS%H6F?55})wHOYR}0FGLQt zrH)7GkREzQf8AW#v3{ZSz}j|vU9!@J6bItuqzhWL1JF060oyV(t|f%8wd2}R+ZRz( z1KT8eh5@%G8h#M+-ii$evRD-E!ajA@Bi|IQ$h2Lm%q_SGV)>G{buPYeG-?68EA1NLf*SF0Qtz8JTXQE^7je71!axm>oa|Umh|h6hkr$9jqTO)A2)V&Cg0i&c}2EK>LGCN80rrkkrngad*zxGy<1YDJUxA&K%f;CNI8fbaC*Qn zF(_g{9W#J^PqGzkc+ZCudaV{Qdr0CHPOvjn{st&B7)v4giy}Kn%ppiHgMu}K#L1y4 zHPBuFL@k6mgS@OpsdC_j*gt&0q(xLSRBV9062Wbs&LPIxh6`{F|IgQW|vFcWK2#}u ze^KYg%B+KnQyUYl`gph;uhNX{lkNUp9XBn_d0&fpUx8Q)S66Y5P;kIl1D1`(;NBKv zaORQrM=Co2TaQiJ4pG_;^_eFW<7O00f*nhoH-jS9qC|@lqE*hRJN1DZZS+qhB-^EP z8*FdzZp->5APbY}^{t*=6H9zSDqh#j%x)qK_qMK4bI`?x^5|C$4u( z!XEr1|ApV~BxUn36?sNH8_D!cgo>SXu`vFu7=8lY;3K$z9G2jN40ciJG~NzaVQA5* zZ^G{=+?(Q0?s6gUj{~*Q{F~qcr#|1ypQxhkIQ8sb)rqpI``?m+*WJsdLwsjXWx4jm z6x!1D5f#ZCI6G{kJr@TDZUS^y0Z3y~=6lP!9HuD>;RS0qM6Xb$=}a+y+Y!lq8HHs} zF>%*JF`pFC1AZR8NkVJw*jC^TT^Yi4S1RYsUBtNFW%h*0MiMW_} zy>r2!$m(+tSKu8pQ;_4J*io_5s6BmC(zN`A{Y$NS_HFfcZ+u$`K$=8ZV3KU-PAtP$5(>pjjP8kMc60{y0l=vqBzn_*AL6TVar(>08?5o%8?4BtHj1rua} z^6BnzC!V7M;_37uTDU7B?3O>ESymYm?}Xfx5#)ks6{A{ZP)G|b@$9LT9jv65WTc5t zZW28^A+3t^U^@EbeZc>Ca&xx;S8BPxv)*^LrS1Frp%qpa;BPo)Z#?etf^=2D+DnKv zJYR&fIegc7{x^Nx*Zz1U!zacv#^hg`>yFal*3*R&R)#;a*5^KNDE?>)}} zSq&s;cE!Yd5?z^BqYW^?NAhDNmU`HBWcQff-Qcd9RXS$W3V^0>M=5-#X5LQxUW5ec z_qOdU6@8d>e`tx-eO?c|*%r__xQkCYvlf;}_4ojEYsg;(Z$}YOY`MaCKM`IF`PBrWbG)1qz%$KUXz26g+_QTo$e z=;c{qp~maCYEA58m?Isl)G1ob2@0_IOBCphB~t(7{Pd z(Z_xngQQn+yD$n*yXd%?6_H#_M9`Dhic*HeX~W|)8b8-2?`i(1M<6g{J&jN==)v() zQ_x02dT>P5yKsytlyFmDxYKRATpb!&B6g$W*PnNX?yNVJj-EM7buyT2R5urg>d8^g zi)>9>7X}q4iP5Vl_28B&loySWQ8|W9Xi=cK+c7Q6qJC?$Sziy=NvCqM@owv1J9(kt zOSYUBU`#XO^@^s25huMXx#o8e`Co`n?JaNwO45R4+4wW+J zh=DLhz3~BwM8q?QL${(Q+&$^b!o+ovs`_C zOoG{&_AiX%x}ioMjn2u zh#5i#zmC$WH^>~VHy%x^<8+m#H1LC+iyD#3JThgR9J35l6NqXZw?V>_mhebJa=x&n zhw+4l@o=x$OCus?+R;KIo9Fu^8oIB*>6T{;p*Ziw!Qn`V3zEYrLJrxfdIu#-kw|`O zs4}Tt6s6HCQklRyV0r6v79~=~N`dw46jPngz%1M=b8Gw#i36@|c%-g|7jER?({4cI zuI_x>k(L+0G7ZskcV=>u?AKH69v`hhMHH*J_1mjFVfZ4DH~o#N;2Z4pRulVMp9Vlq zCOXnNcDxOXJj}}wowGP>lSX^v{A54^Gr)dNyMVJD6IF%om{mU8-+FHvalrZJ_!V4@ zP9<{T5*2mattQdyO2OG=;t1IZ#_otvXZFR-7OvhmPI0sm*qX%G;tA0yj8QLyE zV#VG;p@Htjj}8w+kOu^KI99K2?J{9ODRim)O;S|CoFJ+SWMHR|rulM%oLIe8q1Jn6 zRJRmhMheV_j`R-vEfb}WbG)y%2;_(MhYr*Z{r25OVh{el5T!3L(SKJK^2_s!1N5%W zXfIX~=+}SYqNY!q=KYq^|2NE60+5Fb^Ue3)KFU`dkcSOYEh4GUceuA0ASVtcD;eqS z_AM5rPk6i!^xu(kkMGN0fd8p3QxQS=K7s`RSi%PYVE8|&%lxV8S)j1zFZv$n#nnYVt9AC$9^E~A)6D-4$@`HRWq0nXIlOiL3MA+$KHTK$ zA>O>bc+2tXtvv*P_!h$9(_Er6~QM7>lZ0)WgLFStC?({M=1`XIgH_t%1B8oNFkE>tX+F%IYwBd^Uf zIaj(F0(f`oNPEs(=h8kXf~qhQG>Zw8J!vpuku8-xu6gHrckYlX1tl`dr(nswE)nLU zT`>=rk#w$DDAy=8=2|{;Y8Pq7q9x}b+AnM7#*uhNF3aAt2^UVJWX{+y7FkG{sF=|= z>cw1NjVDGa%9LBO6+Q@3_vCuX1fT8*!@RD9Ej-^N}caDTcj@ZrKVv^2Yn5-h$Jbhh*iB*mNUtusvE6h-lS1T&0?XK zZs|$99knlu`DGB5C2+$*!DTboyVLrHI=yqGuk|=?!wLnviBeS4bPxPRelD-l zf&I!DE1C^ktGJfU47%B3NneiK`Mwd$Evf|xYe$<8yGgo8+i=dM-5&gU$t=}Nef_yt zI|3QaX>`GdS^vGTK8YXaIrC?TBYhX{_!tKoOq&`^t0R!w7wqyhx~?ekim2Bc7kLGH zNqW`1X*93<;Aa_3Tb3QeiFn&6j#3i-*+B^tC1GLU)?xzty0JCouXmGjp-2KGn+PnO*HId4PPaVynn+sSDiS8uFf5%F zT)uo`xOUe$tdJSNN$s7}f-fAc;dONY@Q5c2ifDD+!~UySGIa_qW5>$X%gh;x5>swl zIldN^GqzmIr}+)a+8M5^HtHK!E6J8n$I7RTVwXq@dEE@(69L=Z%vgM8qzPF{HZ2{? zQt9bzB5KO4#p#%g`8iQxjZ#&iBMKd9Ddd@$Or~1iY&DtW-qn~hI9Dz?8d)@LixOnh zd_Bb`A70~gCLVSP+N&vILrB@;V5uk6$>X0R;!8)I%BS3o?Mi%%W{!f=>+Ku@mz^!{ z18qh@|NQWuMv1yg=8T@7>u)pA-whOJ1u*rrHTGQOxw8hpG-A$a|DXXbBhqkvRX)vTW@f%YM_Y5kg;IY=!dm`eTjWN;%X)!EtBo0=P$TpVIM%gv-K)8@l#5c>D2J)3)?u>w7p{5)&*R{=aeC|i)kF0L>yr(k%N-6h^>0;-X5JgtqQ_G zF|P#r>9}NDO|9{_41Qnve2`uu!J)5DJ2@VO+K^otkNRux`Mmt_?*gO#86geTAcY6< z&E60qShfa#6GGr)8HM4rz0j)ni4AECLtq+BChFWuU{a@&@^4Ak^t@~8S2%t^;CW}*)BrOsjudjj1+!R_@Sw&@75g1a43 z<_?zfMy&Ihrhm#ODWCC~cF*q9!p7{4K8D zany)m0!u#nPk0f;N*Oh$9$tioAjWx*+B?M*SiaFrujsYF7$L5%N~+jSnmj{r1zl(8 z)1*aNeR8ZHh{s$*iz4EXZ=l%8UPstRyGT{Ub5k3S{S^d@?ka@gG#_JSdw7Ajl+iQo zQ%5x6(0<{R#w7z@eag05X3zn>g$KZ1fzC13R+J9)rq^Y!` zcuwZ?TEP)4I`3KV$Svg~rq+W=j){))-aX}u;ho~5&rOo2As1Cs)L&bLYd0SgBsRpa zpg@~`0pmH`(4l|e#i<#*8%xFY4P08m7XHjMVr)d=RgZuzJe!tZD+zwPRx4O-xaAs2 zugpVwl$-vo8V0Ljv6ZKEfB$qhj$8<~XqNOAz};8u)KP@5IquM!)S~7%Rdt}OH2ncf zse^i~$5L(!FbAfwT{`KJZv^pih2uWwXh9Z;QXsUjTcWTRtns zg^-6p+m7;fLjO1~T$9Zm0QA5>^njB0fV1ZcCg~1g@dgJ!C+8@l;HctYEK@pEF@_FV z``ApfZqsfDbfo~dD@_>Lp7?g_eE?{o5WV|*jMzjSdx&>zzE$ak`%1an_dVfyZ+{Hy zCGgIPC+Fi2p1iw9*o*^Tk&K~&eh}6Hm#eaQ7uJFKTB*%ZaWiswf$SEc`v&=J9#uAa z*Yxz4YF{;bcKcs9MtLuRz`hAHJ3bNM4GG#cwn%$@Ft#yH zA&->06)>vRI;0?-MttiSBZj!2D(nm?;OuKtUSbUozOld@JHOl#M?KcbWVi6ZTNZ6T z@F;BGV|uClpyS>aaVK_rCUK%rTr|4Dh;oWdEET%p$lh%=sqlu)?u)PR4W-2FQR4Xy zSa5Hmn_41Wh`c;A)9_E*K7>X&QpqL)`wl6lM(RF@z5yL>Exe+_TkMFCy5`Ww+-q;; z<{ak;@r0XmxPZ}(+%DOD!8pO{K19`5U!h>{9N_55VrPhg(xlUwm8K3d! z%RZ9d`*>22Zbd6%Y^dG;{?Cc=wCuhXDw4t89V$p zo2^(;+ZO3B3NJ7;bXzmE&%6feVzb|}jkN-+kFa1FQa%ajeZK4CKMk>FBI&C;(esPCpRZqS(Gf##};ys;_Z!JDuu!(i}w2QyE_)F4w#Ob*>1C}C9i8G9i`0b2{^%m?=RUfm z5C^ppsCS_48tDi7sYE-b1Yht(s~iK)htoJx&9r<^W+y&@ads~A71NLw?V?}|y7|9; zXyG)AnZ;@njLgF9Y@q{-DeNq(K1y`2IiD_OJMq-0h72D;r4BTJ|3% z$A|86r6$Q00|s$dj$ICF3}u}Ffyr6Ck<^Js{c9Q+qSD_N8eC1g~^cKeTUv6T0nQ~4>Y6}%7n0e=0OOa~iCd~cDNsJ0#RL90yAl+-iHu_)bN9-SPFp6L7}0#<5JL{=0JF{#*`sWI+N0E9IcCpvIT2rfF&mFdaAXPXS`BU$b5Tva!o*4$*PGd*If--U zIo99NQki-fcrnn$@Q7yUX5rRFsx7Y&XC%@~ol*8`b~aUhd+8URQbmUTTQiM*%c_XH zj^xY+sx*~KBe#mwFiVSIz`_XgHGQ$pMpBOi4jbCiG0BP(Vw)a+GNYJO7{Wf?>Mq)32p1c zFueUZxY?Z}hVJ<%gn3Rj?n$QHp&&5_97(}hAa$2-5iSM|u22>r6Y`0n^B1wXBzT-Y z1WNf4xquJg9}KiRHk|V#b-M9x3uJ4_J22*C`(l1`{H3}GgeQxr(ay&V*qR(MAeqnd z{|w)WeEcuy6N{+!IRXp-fH)2S0NekguK&y9sqU_avW)rLJx!LlEd?PC5$6|V2;4qq z05pb3KnRHh2`NoL;l{9zn-Dy0)6oezV$p2Ttl?pXTAR}%p-hEfB~_)dN!9YQQqf#i zt!AltZ4BS6vALU>uFaN73c14nGVN*G^Z4q0>$yuJ+x6Nv2tXwqj;#Jx1^nD51Gmau zhnJh!h@I7j_{n64Y$G#Di`jpD5itI!7sx;xg_&2ctFh?6n^zF;pzcazAntHf~j2l&R-f$?aF0nhG0(~SWb zeqW!{OA{`ZL*D;ZjCNP~t{VpBa2`e~5oGZ$4JT$|-yU=~HHiP8ndeJR;ajZXYb`u? zuhikz)Zz9Njwien=M6L`#dCJ7+m!T^{`i5j{VTcYFipuzs)wUw@7<}3V7MzS#u>_| zdXF6lK@J-jkXPw+bwHoDYL67KxF30IYqt=(==sf)+Z*to^o4xw`ey!X+oMeJa%J!) zW@o$88_|`djePEQhh{W6X}R?IgV^Zb#rjFA`X{!n)B9%|x1ZOi^?so`({>vTwf(B3 z0Tp>ppRsxsNT(OiK|MqvWT7;4poc(u+I*w<+1#cV?aZlFSfJ+*xo)ZQCs5Crg@4jP zf{R5Jv`0B(iR25rYJ9vJ9_5fr7Ty!|z_g4fLu9Q4im?op0UWKm#n9gy!f8yj~VCw9lusW6ex)f8tP>kGb*tH^Td0C z_oeuHavwAy>rw;VXCVilX9>_zbykoD$lhkn%lo;Hu)Z%Nh*9fir>g~CM2)QcbeicY zC=s?ISMblLGz{U$87B6N_?kTS7nAUKdB9z|-J89e9Y1a(&OwsP+ZABMR`FY`ei841 ziPUDS>$@~a-iZabx)v}&pWBH94|h18{uyL{2x_|1j}XQAP6 z4>WrXh3k9G<*9YFD_Hj@XTJ23#YCk5C`v_P>J6o=U|6b*`GNyuPOE`XlrNQG>bL9w zRpl={-#jL23aFp51Jz&zAo(^u4bE*Y6A zSybOqekG^A!h>8h`8#@4+XLDSd|qy|2N_+}|Y%H`QU^yPSaE3J}3EvjLG4 zkxr75=7Ew3lqQHNtWKt~0XhZccrp~>qRIintcWqWU@9h5MsZYiH$l|I<2{7+im~{) z=eJAi2LsrUDh>s}y3c~Ser3Vu4Clc~y5$^^SRA_eN`En!s7A9s1R|YJRR8+1^bOma9 z^W{3sT}ZO;CS2Nj>z~~-X$R!gyH7>!#qIv?EIoEAFgYsfEyd6eIT48#Hjit@u^UD) ziL*#pA^m*^mDoK}HZ%k&q(_q9d_w*7TC?i*RC$eQyq0_{sbRZH{be>v# zR1_Hqgt+>;NRA|n$P3M5;U`u1MKRePnkgo1K1gzc<7B-n_^Ujmys1{>WQ;Z1J8>W=0KI+lG8AJIFAfMDrLWb=0`aZW_`wCwX}409SSsHgU|QSNT!o*n)@SEpfBs2o2^(ZRwR% ze4x4I#jk=mCqp5$VD-_4c*Cd#+04r%11ee5rNF0pn-qYedXgw|LV%B=5DeCidfYS3 zAX6+ma}R(;I00Xc!AG*pF6aplJXyB#Dp*YZGzxHiKHw;yK5L3_LrED@rh7nw$+V3j z$$wf}3R#QEEHnfo*JsJ>saWUBMYx<-AWEh5aPI`zLBqIsOOE;s+G%<5siOsLBBg>{oKK{;L(?p_DpE{X;Hke6VG4Tls5e0 z;w8{A+|6CrA918A?P%zCNjem~?}EZzC6Qg#PKwpYI^Hy?q;ZD6zSRcT14QMvl-Qz> z{Hs6f?EpZV>X+)avQp3>b;d3bz1UUoiFyHSKRI<+Nh1y0n;O z;NFXk{O_;`>mD)10P=|egP?v^GHO(=Vuwr$(CZ9AD*6DON}_Qg}XuYOfs{TFoI+kN|-^O+Zfi8%@8WrqnLKWE3~M4g#H_YNTCqc*hP8l!VfR3eoj^qMYeSAoGJbjAC{XKjCWRH zvJ4_582!FT`&b`wzESbm5VcQo?VCJL~`mrah!BKRC1FPev1)z4vr|LQU@xcS?DOG zWJ4BU4qB2~72(Qo4i#i_E<@*42&kp8qxO#V1(I3+$o8DCI5}N%`YZsza3qia=uC+!_H9%wcqp=w{k%E18urLaxbfiFQ#G>1vn-8!D56hc+ zQ)cD&un*NN0ki@Z$v3b??U(QnmCt&Fc)1a5S(8=d))5B1WBR{%xLQ!ST+~Vd>;Nus z`$f)^L{IRG4GWb!i?PjT7HeX^cCXdGrlBL}s?)}L@?3bnpdHrN-bRYyt&ETF|C1bJ z;ZrWuMFa$dsR;zc^dG%3#Oxex4F5k>_KF9}{RhE$y2UZ>ncfw|SY?Pu_*+7V7&7b^ z(m)R>p&=5Yy#%?T0W*pjIpmV%g>CgpcL=psrKnYP8!I@PN>iCes%5qG_Jy8yXS>S$ z$LZGl&Sa(uaQfS;?`Q8#?4Mol=N!-fMsYs%-0iJCUxWDFX(eKSAHeB-VC|d@3%V!9 z2s{UbiWx9mFWjA2cY*!<+2817|*?*R6;!M`#_ zwYuC9TJGQYx?c1^ZWix+e0DE}ynW(N@=8=_f6re-8or+~hkyl^_@$mK2+$Y^2Ec}Cc9C7sa-9#97a@NtdWDY94 zT+bmZZKQS-$B0|N46`7hK2gQ={+-s=+13=t2;MkT+LG)9%ZML=e$O>m) zlX%4M28Y--EQlxr(>jt!j%`Ry*!r;bD&!@GNbd034bGv1Xohj<`Q_?;E6XCR@x`M> zJ&R<9?FaG8xr>N#JBI-4KqTO69v1oHQBUM!5+>c|NtOEs2x;4*sX)3M#912@ZcnTY2>jr zHBGnmF+gKGYzBKLo$_H5V!%LTYqqxS)irB>18;kMbV6@?O)gmxu74r%XU-_h(|JB3 z4g-D&C6Z)cfs~U1+X|8t5u9!Vbq$$P8nl&sqCyxhdVjC#_drIr5RFm)n*uLV6qwZ& z+NW{9dl@^XByB-BS-pX-c_rVm^4NgCgtw*(F?z%jN<>!ryaX>&7^xcQfUIE9RC&Gx zB@>(=4Q?ZFKMRYNbRi!)lA@|C98N$zz#nd(kR);ibbto99r-K5(k6sDWu7!m$bH93&u)7cj{Aw)n0;61ycxqX6y%T3$wF|v_ z7J2&QWFzOO79ri#T*~;7C0K_cx7WWXiE}qRc*x6RwHb60(*Jga8*C}DS^EYmWZ(xM9dl;I39Swb^-I`fMNsN)$!qco9cdr7z}#V*&`E>D zPn*z6NYM*{ndsFNKS*W+hf`WLP>9)2aq|AA8k!>Uz_`8{K z0e>W{%oKkG)Lr5rFM(}x4Y7yzlBq4MPYeHTlXc9RXpR>C5b6dpUPFH5G_f9Lqm;Z$NGJt5Ol`oYZs zfe5TW?RrDduP>^d0@wxA?*ljiq}&AC>s>ZO2ee_64dc5kt|PL~uXXM5=}}D!_h~cO zcdo&OC0r?#gXnsLyp+(^BuotPE!lS6cLF zrW1A@1Is)jGW!y8R=9qO`8+MB?4p)(k(O+EgdD98G;AP4KmX-I|-%iJpl`p zF!JoVP_gyRn#SaV9u);y$#QSAN=C|)Nbj-$%4%9h> zXbUF#*!d~K8*|;YSKl(Vdf5H$6_s(uL|_-dDKs;G60C5D`I(#ZH4H3$$jKs`7WIE{ zVIxZ+cR=Ou;LO1z1}0G(<;2)wnx)lnW=IHJUM-bf5lKoe=ALuN2`3CB*J9>PHxfJK zp{<(ANH!I_X$C#w;iD1>fD-l$-dMFUyAm*D3nSIl5p%G6Aaj}V<#Z~ep!Ih*yhD8! zhK)YxQnW@$siyi8wTk5P4aEih^bO9CBS$p2lkDBz518Z4TsOO1H39)`9@WS)U?E%jRJW1Si0g(M+B^L+ z*JC8fz~?>rvP>*yiJIDU$<~q>3mL6MZFtjEN(NQP+oze?{35y9yusS=n;y-kUPTpb z!bs&Xi3IWJUINbPNFRF(IZE~+u32uGRXJx6P8PL(P zwWP)fuM~_uK*|DIks)pFQ`{2OHD6`Gixg?g(v0%T)|f%Pml0jkA|!*o*6f078)?CYX6)kf z^*btfsPU^qqp5!vb4`r;^0e4T3o9y>Iy1Rugqgk}=gCBeQ-~)WxxMMyMuslWX091q zxpJADilCb|12X7Snv#*}EAQ%dv(!B4%y6QreEi$u+{{vtKb4zzcj<3?YrH3sE&Ki} z?%>#RhC377UhFM03d8WEvki+!+*1kq3N|G10HRh9hB%av)zJy6tMZRweqE1{6+_$^#tt8bO7C3-Y=S@#u-B0D;WHM&^jd{a@AQA zuL~)5&+24MSWk-$hoYBlcM!%BWDKpGWTBgo?F@%rR$aX2A9vH!o{I$+Dhb;Fq$BH! zlB$pG*+P;f|0=^*8Q&8u5J*ohzrm3%029z!)(D+otSrI2>`_#~`Ch~wj5hug>>|}U zF5|hvI&4Jh@ujDLRnS%zW8iNSjO?zMM7CXN@9)WhU(_vz=9)CFjN73VDt7OkMO?t?)w zl4;bk{I}k~ zIE`7R$JP-^_8)d7e9i)D)Dmc^Gh2=lFjhXNs>?^SK+Qd!&pdW3tCEOuyVhV@+-fF_rucW9}@A z6>$7tLPIRCwBLOY86?fCHCfB=#HXitf49SJ???dS_iYt{;h;zoeeL-#_na=(Q2|wl zW0iDk9x8f4=`IV8SVu^$8c23}tUA(|**KFCK;uOt$hG%SC87;a;i3q`X37O(od{QL zolP`kGZSy%4SKUBl;3j3N~N_m+pIaX#03*?J^8j-?RH2)S!EMiudvrN0k3P>5gEEk zRe7-{MA28KYqsQ$I26@qnW)LSxyc$Ds{Ped4kG*sz1Q6RYk7kbphDJXSZw6AYI*hNIvUC^*LV@?5L9UjQzr!*Vu!{T z<`K(?Bt@Vr1`N&FxON1`ff8Dqn_THdhTOSivN!`o)XXwMlTRH_V5>6Hn9yGZZT{YMl6 z4A&mBF#<_~n7v&)uiWrb_Llyj$91?UOjdV-W4UZS!=&6K*Yy9pi2uW5nE+k}G*Uso zh=Udmt~J@#Pz5V;CV_osq7p8L&w6|*#jS@EU^CeP0=ZHXBNjm2c)sYcR&nr7`kDEs>f=`F)F6Kt@{4 z>H$D`p-eVgv`BYirZ|Hx>22g~l<&QeUKAj`>~!U4CV#w<_pfvVA3lgrDdnV8^_2%a zooph*$}v^op4%}9p&7?cuk&uB>Dd`>eQ1L!DO2F}`b7Q}5r?$aTjWJwTVH+-Sxn*a4? zGFm?J-tpg7bwDtqqc#67X~B5pGk|nQY|!f0*3@w%Fj=fRpS1AT2{@Yv_UOr3dVXy? zAC|SVeN$Kj_SVkd#Xn;(066e4@JqgvG8!<$1~_W`QYMr4X%@f_T|BesL*~snD+Q8# zSablNw{R*rp_Yh=NK8*i)I_Jy4pXM0LpJHL^Q*@IuUUwwQ1^&Xv$bs<92u7cu7v{yRiXs_KnKFTNliUldLqiq6Koo)2K3XNEY{YEoIS3^~_a z5=_G5$h=UB&2faWx0zSA{k4MrU>^C}*0<1>PRbr~?nLmS{u;6kGKhiRJP@WvY3?82 ziASe`-4vFSJfrsE+e({+9v>W8r!;>_6$twVVV@|CBBrXy(y=9MW5{B%Xe@I~&*)y# zu(lAMpqBT%m4HszpUN7zkJAam>{Z-Co^<73sDWaQhCSMc;J*XQ)nw}hgWDZ>RP?6@ zswbR|QIhVe?iv#tZxcAt?RT!1JPdB9aCI-vgvTsZ*Qts)No-+AehHVtXsKUDjlxWw zf*NNZi!#uxQePw89vA%W7O6q#tuEtKe7s#x!dw99jBBIZp$_+g$6kCX83V*@{havKO>;LFB zK~RG^pL1pHDT|`G4H#)PiL`UEPolJG{?)Kx;}9m@V+Pi_2I4k7&C||5)1(>%foMWe z4yaZ#s2t}j&eAuYcDo8&vQ~$en07sOShB{TFF}*D3{kAEYr*<}=et;{c(VPyJAOF^ z!eihE#+Gttr$DIMxyQN6_-mzXP|0aMN2}o+Bf)3M{C8|(-8$XZL6(Y)6 zVxw$sjQARC>nOmtr*lGrw+5W21&WQyuI2U(wXR~RaJLR4yO_u%RU zlV31L<#iJifR)9CSqFzcVA1sbyidf5vJ=$E2zk11%1I#a4|8kuLZk?+kB5bqNjX#tO8Sx?qW_W31O4 zK6`2*4^y8L{Jgg!ETOH!KaYZIdNr}Cjbc59)A-YTT$QP2$7b>IxPF57>GB?jZfkTW zM`lN6np~orhr_Rbd_oErU$H#*Sc7zJQYU4!EuL`CByDIcp1M&PZUPPM1%{Wplfd|a zDCXp7Bt};U2kp6efmi!}wZY&Qua8=s5b}b__dVQdyCdZ!WoU^jb%t10Oc&*9+S4Z) zW8y$QoYx_f6eV+82Z?c|j4!w}yqGajH@@HwEK1l1xc2zndsN7ne>dKtt{4{_@L(3| zg)EuZ*e*#;aM8Yu!+QmT2&C_6PD&FMMz^d2s)%(pXtbZ~aQA31X-5wddw}lj&Q2?^ z(bxYN@`~<9IMU1e(_DPolF^8(HpugOLmXj@KPE2r+$aH0@V~;U_x-Kg^W^>Ze)hUs zo5^q~0p_RSa+;!i=0rTD40Fn6biqex8hBl@3x>()cL)+th{Ir>Lnz;c##nd3-fy8I z3X60bVDy}it;$!4tF{k^xmU8HWSg0kNVOT8T%JRljuVfi(cY^-e_NWavj$_LaN+%zoZ@LB z!!J8>6ar85$_+-7-j$QqRKk^U^5#=f{*Pzd zK{KY%Xje67d`7x;6xNmNGN)l}SK_%T-81FkzJcWM{PM$k)Dyt7GdaaUcQZWeReRVS z<+XUHcQn!UD%SbVO#AHeV>oH}vIVzQgWX#2|Fx1(g_?>g^Vrk1&k-OXP`Q<t8!!28$S+!lUb-51*QSk%n z`mJ|Kc28aFhoDz1^vPD{ziM&3+4N6W>l0oFnBXA&7Rm61B?rQ{_~XF13+>B)c0gd5 z_C;kXa8?A(i$0~lR}`}c(cwi&2RL+y|3!;8LZ~ZL^T6&5E!U{!1zC1FuzdsaGGEm| z-UjWh3H!2o*^rfN%`P~Zx7YISC`e`A_cr4udGymcSaMgZL$!lCFNYRp2;===tb zMp<{LXwJR{EuSxpqA%2Ps5Fz{RyKuaQnfjn8Y^QnG7Ywg6^TJ|6u2H8gpnhybmz2I zd@&!`>sk;C=hq+TOUQjJlkJBi_qXv16~EcTK|1Ee^w8S9@}&pFR1_1^al)SzJDMlv z@IxkMpR=J>{SgG=O$3}H8^x3;Qk1dEN<7L04NhuY+(bNFH29ctl`F^OPK1aJ17i2f zw1x~J$WX*Oe)9q#oNBA3^5bEkVoPj1Px*5bR?{x8o> z2(-UEop|(+FGK^)y8}=5G`vQKZ_xu!afypA82kS8i2N0Z_!0<)p5t{H6Ow)5N1znK z`dLEoKZNe#LjzK-i*imp(?lyiEHmY3eh6YtjF}-1do=nWD+i>lph!aodVl%xZJ4SN z!!}$Td$Q|6)dGkbi{2v)zB?XwY#!fu0N1zIhYoscjkFJ!nJ%{ycVTpUrn&bEkl2wT0ax&H(rp>ef#pOpI<#A^)@}F--|JR z7XYw-qk{`i5x^NvpgOhGb*q?{F5sRdU^N_QbJ~)>vmIVh*K(}^*RXdj0q&(>I{+PF z%vDd=ub##W2d6$<~XuaF- zwN9YiT>Q50UI?$QAp&p5!f7Ve&H*!3*oz*yMH?YnaQI<@`tn*!yd2h=*yn zcZ$wIUwp!;@7vEtu&-rUz6kH!wdV6hvIbrThdQr{Ixn$94x4MZT=DJnar!oTs5+74 zm+L7&adLZ=!M~SJ{Fef-9@^QxKbk9hgY6Vnx5CHi#`i4Rdo;FU&3&tEFs{wrmzQ&5 zJW&pXt!96id>tQ{*v5}MCRy5cW(a-B@&XRt9n&asE0O5Fo8jN$9~p?hU6|bOkQwio z(*o2HmsA-sd}Y>!Sgc3!?CJGDF!r100#^H-UXWGF6tlC0u4x2^iEi(l3_hHGbr! zsyVJxg>@9Wqvu?`c?1PCJVXb_ZI3+1-Djjf+9t0Mb-IOYKHW=esJcRuEAxMWp`IXA z&pF_=&pBP{gJ((q{ez!l=iL&k)ys^f_eg2-Cgq0FOjus0xDoN&{yo~&8AIB{djgpkgJE$V zGjbE|LMqK2G#EE|XdOEuGPOx}@Zg-~S3VG(Z6~f?=T!w7ucqmyS!ln$id-em$knxfHJ`ni5UB{n& zKTm@f-8z|W*d&I?*XQ7~H^3@lffZ%64g=j`={Ly#HtnoHR|jyz5vZ+GxLJl+NSUpJL) zs>jNYYo{NYd5QbaV`ySxSEx39I_`(yy+JM86^yLvL%eSTNDsD>u6R{RvwHilZh%N1`vJhf%y6q_~M zZaDzfkyq-f&NpE$mRjRNQ`Vv0WXdMr`g66dqX497o4cv)-}Vh|lQe?1L$!-r#xYj< z7_VoCwaZuj)_dtRFLLRDDm)BX2Et(0yaRe+=Vnv4^kpgA$=W+OY14E(17ppS?KFt+6oSd z^;Yi?$%TzDJz-fG_VI*7!zR2`Ev3cbAhJP5HAumdm2jb4KwNriK1^ zE4cG1(q<7+C%|rNHCb!JgHJD|R5?nkwXfAWd)(MNoGt{OVGYZK1gacOmuQ~uKm8Jh zAJpM~fSx8_=w3gUo95FzNTS&F$UAMY3$aEEIU{1oE*yZfia!r&VcrhSW(Bijlu_{D z>A7&w&tla1lJ7o=FOWY1dz%wG6Bqt1|DZJ16yrBOPLx@YEl5-7!n*nEoea`F@lpfG z(mk>YpW6V*ZZV?(s~s7Fmhu zMGGUZgay&-xq&q%>oj5U(Z;|mCMZMwv@YDCnM@G;BCJ=)4Kg3md)V2dh#vk$5f==%3dOyxlsi`r zS0rxut29RJ61 zlCA#ghO&zGm4iO(&TATP69&spZV(61hTbDJNC9O8)xuIbn#0T}F}APhOMUk*dYRi{Rojb|;BKSmk6P7=F-Wf}PYna%_eXoAre&6=&eZD^1 ze%|QH`;5|{bXD<~YwdXG# zy#L@pc86MFy>NEpk$0Ex_~01MUV1_>Tt0peBDj1=jK;cr4E4$1CB)=Pw&z~F1jp!G zreWNgWn=kY4~bf>M5J!Zu+Idi%lMGz7}#Mv!+<);?c^Bewvn{5g6;$U&o zAaedKvhi;Ym)YT0osnH1hO(lbOja0>)Ld^=V|nU_kRw9SN#Y_1H>>j@kyt`<8|jjpDx>G0O3Jf&G94F+9n_ZHBX zBIcN0^<$JMZJe;{cX#nn!lLlGf2^lacI}_$^f*^*iBQWuN#_-oxG71Uf_!8ZC7R1| zu3jp3sLZ<;YG4W!Z;WsKqM2o89J+@Er{wlWK$}P@`*@$a5NvVo0ireMq??P=P`%~zpzo$$} zXTPbnyBEY3s4$dUj`I6D0IQ7T$!Tk$ivH0YG`vbPV>|#O*xu#ai16Kg)pSj>5|bYv zh2??Xmbedf8Pn6jknP3SDrV(=LpY85_7GGSt3$6+=}xgm1uIS6>35}alveoz0Ht@7 zK;}~Q@6rSLe0o|RiHYyxJC(7++7NI}M%f-*LrcFX+a0->EbT!o`OW|ic1`+ABCMgd zuZ8(}tbYx}l5_@;jETMCV6JRebZ;Cc`By}5`U}qvk#T~ngPPu4{^tG=R%eprW`e^X zZ_IXGcBWW8jP7idQreq_7FxI=5a5m1uLWc8Pcr7MAs5ML{=X4)i)atd!Cm@I`z%#b^^lH_;qoriK4aQMIlI7HwAs^Wj^ed>9 z{@D2Uv{g*hM-{zfHQz~A51vKCvNFhAiSnFIZLme|s|LRYCnOX*iN1|yHN5T3n^s$| z^YcwB;bUpzyUYJZ2d({iv{=QxfWumRO_)#MpdF0~7_!Ix*|`9)uLGDS@X%?E~_U2s_|Grsduat0LoVMp&{`n#fB zJJh^Fe&%QFKGT%?!2?(2MFOd8_N!%}PMARcYT>cq9H4}?$1g@sX{|``bLCOWtUH9Hsw1GDC=*&p^$D$TJko!LFNG{L?l9NEc< zy?<@n;+fXsnOsRh*%%$R6Z*^oLh>PRkVO~2mn7AID_I(hovn5~IY0Q~2fbJZEeB-A zxw2=RFWWN5hQ3^3#c=PZ(iX_IorT%uI_Fzv_8<+3@b3~IPGr!zN}RoW_GS1Z+E-sK zD)E-1O!<9I5@ma-DfrMwNqivXH_yD-nwbUnSd=$n>_X0rj2v?;{}<`zP*=7xqMM3t zJmTiQCqhUF0@NKrh0U<>i#^(z%Rwr+c-p`m`W4-y?AxIK#hkGADH1G1LZZJpm>UH} zAP>!2N|rTNN+Wa&LtZcZrotW90A?&znPT!Q5^qdwnR!g#KvKjBq>|1uV_6wuqepw=1=X)j!av_`+P;eAN^?4BkKl(a6%qfGcd`O#QytPaP|bT?x=THCDS;QbBq#^K99q8Q%*I?|#3i*G%xN z*#Qiu{h=fRIMdOHGCprKL&qH%+qn|@7kX;rEo_czYOmA&P2*m_6Fu)uKa4vQ%&YrM zpzcdU!h6D>w+I{tnt6SfLo0f(?LfOdG>o3|A|Gkpo~!;!_vz@HveX;usPDZI0cyTo zr~S5sTlv5D-Y&0ZF0cML0xDKMNx{DT01iEMV&5u*kDV*aC}ygo-fN@mTz&3#l4`q+<&;HxjoD5_iQSX#}RCjc7`mv+VD zLo$zCF2OKDm`4^AtCNVck~xnC6Gq!K_Ae7a4_8W4?uQadR81EGyEc%w8rv=HnI!6O z;$!mFHf!wF?(8FTO^{GX0H57|^fN8SGUG%Azk(y$_l_a8c^Q@Js48|o2ye6+&MTsgV+J9Wwv&x1HZfzK-NF z_DQVW3AA;m zZHCEaS}mpd1?`Y_lU+_Oww}7$Wv1?noH8?lv_FTV(8CL-HH29FlW1~8lkD6cqckRl z>fuDP)J2-Kg=bDs)89OgkEz>N5*2#=`nP;t_N#^ACNCGm&}y_QF>QJvGyUNF?q?674tofTjxCQg&|pqIF%qcW#Tg zr|&Zy+2TSsVdOxM#9)MY3g-(Ib~=t**B;RrwqN-hf9)t-!e52*bg&8NGLO=LF(>No zHh$XZrPDm(ENCffQ*SiPj=(r}@Rl+}ww5(qKowK|)uN8e zFmyO5Xm-l*#S31yQFJxvND>D~T?;AaCrd|kD-qLxs&cHfdlai^o+Km%T?j2( z#g|cY(k!1sqbbqYcT_6vs*PJ7gZ??d@0yKle96N=pqwnhV|T3+`lmP1C8c?o&^)DX zwFQ~+=9;MD0mxSAH0f5iELtJM=~61aU8;PJrf*-T$t+S(_s%153WhS}q;^d|_ zF4Pl-)7%g-&N|lqWv8-&IgU)=R&h6N9hq}g%RQAW4()OYthY|Q*yR{${WQV8UZdlb zsqQ)^SIb&HGQ|w7hWv z_MvOOdWRf3>ECD0Z(6Zs>UD15dUDH{&hdFMl<*pJYZw#+=EX$urT)c(mCJ-7Feq{L zRR>>r={;u|f?W^p=Flf;$Dpdh%LE6KqPYdwP;+Uh0IJDl9xS_m{O zy6d)Ey7glv=1aS!J`|i;Bb62-5`c+yG&Kl)Vb=O7$%0=X=m#o?h)J2YTYE>QzEgJ2 zZ~<&dj5VH{vDp1snj-s}5$n9BILr^y374_H3gbzpYxZOQ60A$Mx6Fny_^Kr(G4lW& zlb{Nt2=^yNO4%{;=}FFtWM%FC66UqW+R%wdOpZ3&!lIW=?q{)2=(P~4rgRHxk>}D%;G_R+#yno_#==(8TyED*}-;AAyaf_ob4}@s%svx+-C+2 zYiYcHX=21DAL8{jwKbdvrU~kDv3T4KCz~P=iO(tV2WbX8XiSId^aGBT*G_ZAUC#mT z(3iq#+5SGCDf$KkLs>+q_69G2UBVOUF?P821VVq+pvDX!n)u-6H2=)FSQlq=w*Hz> zg66PWt_V2JaBiCot%2QOA>4cmS0DY*O$P|T0_oN`+MN7^{XgBy+L(gqXV)0?J`Xs} z1Q$4IT}YilW{eo!;ik%uD&8f-4xhD01+#$Ak=uzbfhhHpSoh+je9#t@0r-Fo$y(Mz zB)T=J%;$I=8!vvbh-|{8HV$k$I~7v*!o_PlC zl`71>0Tq0FA_P16$-%r~;oS3Mr}7$I)(rb;K#3JX(y;EPQIKhgqiy^7CUwkl?kMf? zf#c+$#?b!2L)zf}fFLb<&ly+@w&(XP1)LUi{nNfJtz^L|6n7KK6XZOSuCr$ve3bo( zZWhkrCFRb{%?%;fY=ZNhUzcv}rOEFVCVOgD_LE~IJnZ9KCpGh#bdlyW&7#2ito}6b zx!^ff30`7dQxW{b&g|z9CR`4N?8AE$T(b_Vmr|0d%o;2wg8iI+@{9&~7R7!y&07qO zTb#3yu#jB?X6gP}p^#tS)P=d_@D1d9c4>YH@J8nzmpCHxgeh#VdVZhbDkv$VPLxz>xvp=p#*BXC&A zScp~|nz2dC##by2DqfYVM`+EE3uuS)JEb$dQvX^%!JO#(&9>$>jO5G#RT=GItf3@+ zM@46O*dSJhDo~l8rL2j22BYjJuiCsW}=!$c1q4zC;GT z&OIVpRS7PV$S4PvRLiI}?*i(+t5%m)UTH3|b%2R-oUW#?%qJ4@EEF-M3wxrW5i z)jwrjQk>!qVSz__zWh`zeZ@a3Our*_(WCMPwz!_$Ds3RDB zdbm$WO{=)ICL!dt_`Wn$sNk5NWtT}hJ|j=17MG67xo4^YX@vO5BRnk*cOZXiwsh0 z+b@;6t0!{I^zDBw13dmsV2cMhv187ZD|cFU8x@g+$GbM1i`q&>W_l;)ZA1QG@-X5o z|G4n|b+=2>vQC6+)BS57^&Ds2)Rq#7w!sULZ?}M}Bx}=s5*O`g$rgIqHPYTPc%T(I z+^kJkGjHxnhj4yB2S^#RaW36gJ01YkjZW^PEx|SpB>;ZX7Kb%mgK0g3l&^HUL_Gg> zo5FbnSuXRp8sjp&DgApKo(52P{~RSAyP}6xoSw_y;g=%qtcIPe+C127TBcWw&-IQa z<%Vj+E1qjbSixsLSHJiAp)~5|`+OfjY1fjrEUF{jv~tk(qr3Zj$|npf9Z$F(a4{H5 z`*KdJsvMFrFxhh)ltyqq2WLyI!yWyIcZ6ba3B}==1mO$iZ3lVWd-Y@Xelf-TwgW6@ z)5^ce9 z-E7n5CP6vF=^UXukD34j=weHZ`ON#c%a-YL8J0rDE-~DZ2pL!oyQC}y{fw0k0a0ro z5Yv!_mOIi&&rBrO0I{r}Wh}Ne8^t+l?SA_0$v%WrEonL!Ix-f5KxQ_m>E(_qSIjMt ztek1*r;HGf7e9jEM2Il8|jPK%<)EDO2S2E~zcO;D^GyHFFGuS-w5#jIe{&D#Z&^OdWY5lVEzkf%&=rD)9bm$ehbU1x64`Z}- zjp#R*1Yci}J?m0_u!i}(!++jb-HuA@qqqoOjb2Jc@s-E2^dbtiRe^Z# z)tqO;c#PGhG?9V*m3FTVb?$)d5e@4XuO+>vTd-CFZG;2=4(2W}*d;mFL44y0`9PEC zmzm$o!|=$RO@U+yt9q;H|10vJu!*Ey30D6nK}z{aj0pUXNRiKlVk_VOKTDdYWv{U% zgCl|rMM!DfhWM#3bNb4jATiU-lGLJ1Pq|FX?FGygU3)giv7Dl=&3RJ{(jc$gskC`( z%)4-&^zhSh8{p#4QW@v!Ufgm2wd?*|^Y=xp{~zQ&;}0U;fp3DleC%Q9V=iP@g1l7g z-0UF+f=-P*@m6bFvfAM+7;}=`X@DLoQ0t;V|7*DKUBi|x@#g94#*wG-(%c*zu0`G zrBAlga@E!|!=9_}J5sRY$rNJ7s3`w!Mql0s*4Qmf!E0*UcSOXX_a!7-xG5llc%#Xn znP|Hbv3}Bis9j;^$ihH>F+kf{50>Y2yUW&U$8J3X=f~!shPA(Gn(O)+n+Yc!D~wOp zn7<3@yN#_ZtW=M(o!1h-_-r{jpA0mA8||gYIvBFI$G%g4NTPJLP86CM9xhnS6u#fK zp*-3U)jhDvWXJXePmK%gBBWB%ozt^R@lL6HF{b{-+uO9>_DS;(f@&%^Y4MT)#-Uqk z)%iI-(D($i`9FMi>v%{SSI#1JSu+f3H1RTYGVr~V=3i+6)2?ev}DB< z+WF_dhekO2xbJZLtW62A_b99ml?}P?SonedNxLn3Q@5hhRs>qOih!_aPDWZ7xifjI zaUK)yj`7l~i;8UikQtYoAfG5o-)9FP%Nu(mq^!(`{EkjUzH%NI6M)qcFue5 z#6u}85sLq!ui!wBd4>gZHyG~|{~l9S+e&;1l#Gao_KNsotz{nMx}cvml5Tn9izQr0 z6uGl0A%5*+&B$~5Gb&lT4#lfpN3ur5aQW;Gy0E^JY?@@Mcyp-7C3qG5Lt-foF_MbO z*dn+Zu(jwxeW1Y3Lnz}8rwc95=P0%I%ilG4$5u3&#u19Dv#&N9iFwFgmFS7znC@8} z>!c`-?<9v-ue!>~EZ~p{7{?rCUdSufg=%L{{05kS1{H~$3)3?2*LDGW zu8|h!amvX|o;(N%&4tm(t97Zvk-{2pS#SKpSLrw&q3}Ho1A>bZ>>v9*-=%gf3rN}V zl>bJ&ny{AwtOKyVEc#Fx@9!gp_JI$0$}|H`{=qbH!O}5 zN^l5GCKZM1zA?1{B$M%pLiPcerb?uziVUwP=y}R6UdOZ)XXEZ{s5AL#ZPuhsMKE+?opNUsH1rp9{a&?-7*!;4%Uk3hUu0GPksfDu(W!5x;f-`zChx4z)mE0xRAu4vepdP=Xl_1jL)&|$qf+1CF1L2M zWig~MXSC&LeHH*rIjqvpvU@sJ#U?C@F>>b)7`%<^y~o+{M76IL9O|VH+FVrXR&Z|W zGH8m08iP@a@`*U3+MH)Rgr${MGRrP}*t?LPzBOyk#7Ww3K9e>)X-<)gmV0Oz7*;GH zh^WlC)98)Mf8_l6#2HwoaKQmhAhprtLHD(4rOMbUiU$e&EzgGFE$9nmEXvYZf|%ai zZ-Fa9fl*+0mEMu(3_41k4Xc&X6oIhn%VLg$rNa^-VGQ2Oc=qtH4ZB3;rzQ1jR9R82d$VO&$v%lXzvKZj97NF!pv~kbBGvV`8ygiKVcxDU$%e9dw~2OB~9waht*fY7STq;1uYwv)6~=CBvBC*#y$_l64asY|r%S z=6FG_t80tAogx#qY#mq+N&|Ezn^OFW)UBR_j?nHfNRMwB@DpQSVkH>y%DT--zF?Dj zP{vuXF5D6SXTRt>a0pO+PSNDgei8n^>lYO>kFU;7N>*N04*%P$Rny*i(Ud@hl$1r4 zwA*K+=X#8G8hN&x^NfJA_6kCWmnM*cbXAXKR6Ogg9tWF;C_euk@`L2)p=a4DHkJb$ zLlBNq&3??(Xr4~sn$TeBSjZr4cxthRYwwl1k zSe;|gUv?DmV1$ckZ8VDWAcDIzJ%xmV*eK~mW5QBT4p3g6>L;C73qtp@+6!&YnEo1?HHt0=uDe!RI;r`z8ZoTFVlAi&l8NUQriw|&2N=hPdad2>G3^z=8P;Jx}&l8MM_6bz%2&@P! z2y8MH$T!46wax5m}N#nM#(~xA^QmLM}Mb-R)G=5z2$cI56e&{w3131LILE`@<>eg z+rlq?d-MmMqcR}cAPf(A1^=BpG~5p&6glMPMeseP_Uo58{radeL$(G3T7!K zgj$^_Xh{+jUlN+Y-H5=H3B9nTFx(u-kn{K)G}z6b6jO|q_Wf*?R|61|`#=MB;3>=)qu?{sIhZYYqnxH)A5CLklh@r!D+ zPq?ZLVvN&qf=~*dmi7H?EVz0>zF>@rv^}A0U(-z#yD``4$tFk5YU?yJZKhPkJMRc1 zPA2JMOYNiX*7ty^`0i9Ug0twzu8Xd8jT)KRDL}=nUS!P=Y?kF#P0?=O-Nw=4pzWK^ z>)59}8kX*!u41cIPJxJo+V~X@KMNa2#VIS^7A3zFi3Er8mfDtC_LnL(vk&Ouy1Rwb z;>L(rxv7&iT40W~z^Pwti@o-zm|Ho>QcdJf#DTBo78hDvha>-J$4~7F8LCy=ewA87 z_G`yt^E+N+HgF-<_KOaAw%ec^vv+dg3ld@0I{4iz0&AWeODg)*BPdQx#ra5)kUzjV?`~?rB zJvwug_KCM}=iEc;j+@cB0{OqFo)SdwA*UL0!i5*=L!?cYdIUeI82`37H}#AF{2vz( ziY-FvZpq)Njm8Mp624JclOWMf{9t&MOSyeGATIGQzZMF1i~CL?A)k~)Vb@H-64LSp z`xU#y2(JW~q#~VE=k?FKs84X`y+>14ZjNtlq3G=0v*p6KGXYJcetDskJd`xAo>A^z z{BTwN$6N~WctCJU2QAgP*20@#%E8`$_K0=bEybNG1cdJ4|1|CF|9sE=Z*DvQ(G*Ae z+1v9e3!D^&7#zkWK7cVq6EZ=QVhIJEGE5>ajtb-)kOLudVN>k3`|QCR`y2&V9}>2js|^78bx7hOaK zK|nWXPI_1UZ&%Z@bj9IZ!BU!4CX#6tk~|NH2++#PsUiTS;mOLWS2BD8u%Waes;S+x)qkVN&O;$Gse5MT3-O|i16pajvOQbNv=wrs| zt%SDw)4N$IEa zy4*4fuiY5Dnflq!2{S#>o4VGdY3W}GC!M5ro$32Wc!j^yh(z2|;5`#fk^y}YQqZY= zVMcv$2!&78151Sye7_Wo)rrg0DlwW_a5P-;>6iYMX^{%YDSul>aTjDN&C!q*&ZKK@WXloU&B40T3mZl zPdv%46zV&o#xK*$Ik{cwd$QAaSdF03WO{N2V8wWPwFp}lW)M+LDfL+ z)ZU1uIo0Swg$M;yEndx0RW0BOiWZ;duqxO0;!DnDC7>tqB?WMXbJ+nn!?8RVamlf4 z2qZPH@Qn~$R*fXI>np@NzjRTJ6@=0+NZ?*pixAvY9Vf6WEKJ~8c8w6+Eyb(EM)52v zB(tm-W%UH4mer%Rp35l`_9f z!8O%0!b^Xkk!b}o>XQr5$g;v1$ilVk2CQ|F|0nJx3asT`9*yW4QGJi-T2{?419R8# zd@s@_wBz|$C9tb4BrB};jL>(kK#kb6t(Zdf3@@zXUZy>V_WZ1R1W_yvS+h%9B_3+M zP(YL=3kVNTD<>(pO6eoA+65_30OrVS$5h;6UrDG$17HI3KxEb6oi~)7tsmR7Pcn>!d5`cD0g=i% ziMvsQa+0>=j`0BP=D6)5=h> zI6}RN(j!U$Rsuv)WQAMuf`G}>5^e;bPPtRctVBylP`DhLY!gB>zC0nw4S*}>Pp?#} zNa%>v{7K#e0#m&hKvr^4a#cy1)RhwIvBwAiPr1uvZi=r`O(b9>08?^7`O^H-*Xm@F zi^YV+1ewJ+n7rHw6%`;|d11=ZJoxMRaf@eH+it1jJcVCY1!-tyeAjB3{S6i+mg^rO zLCJ;tHdAK2m<#<#DbDK9JC_n_j7<_KO(`lu)MS>^QmK}7x$&-BzvyYS7OBm0Pq?j3 z;KI}3v#P`9W?ek-@ZDEhQ+?l(UXf)?^w#v|t2%lMLG%vKu(nipS{Z`|ivS&$00g`6 z>+b<+j&81+x%m9F9RmEdOk_?u+T_ttM^&bDP1Wf2zYxZ{i(J;eQce4FVcTb)!UwNL z7Cn&gN1PWkxK{LiBSKm*B99p#CcUzdZj*Z;@wZ5*P=6-WJ$I=xZzHY3Ey@Q*cL<8t zY}(oy`7rU)+{m=>N=cc!!hs#oy=044QJo$p8K;M=(^{qVdEtg`4mzYFOl2(2##Aes ztEySZemWpW7OA?z{vFI@^zxw8l~mN>Mgk4`G=LOC8d1w`(3Dr*yvs{3&LQuAlk2l` z;|MZ>Z7u$F*9kWKw0sw+pjjtOfZwY5Inh*Ci{|PG)1s9PX00jOKJH_T_3#LmN4YVr zRru9(U@Z~aAa?W*KcJzX14-F77RKPFu8E{{)7nekt0@RV7!^NQUa;x?4&(Qx9FD9| zH!^q95j}dCg=-Dn=u&E`=?%8}_Xk+|5!9+gc!N*%AeXMu)pD!yJXc>WOQDJbWQZ4N?>yZbd9vQ#rZ>5+WK>%W%^$&I21viHt2D#+WFs(P<=;GASRrZ z!&zxHP$Ef60WB9^Nkpu7>|bRaK1n7?84|4H+Vo)8-YZ>JqSWk%z|%+KH*$XigV^EI za+DJ1zt08AF$AWo7X#lB`RTImTY_7O%auv$(#HiVevA9_3OZOAb+9ZG#yKZN^$Fm_ zH>#+!W5Z?oD)MvIV%42pOd?{CH`;};5KGpU*$qf^aet`4DTo^Tz69hDW$IUxwS^D!VXRWM<66raVi_@s%vZUj^XP|n7k$A2$4No z-ij6wy4Zt>8W!BXp`@m65XOy3TDR$1rF@zkpbOy1?w;->t>6tIOdoQojmVCS!Tzjf z#`=m3TWF>6=h|6_%EpXA%D>S!MOy;jvti%)9>NKFM?4KTnH8@TrA7uJaZHfNEFvc@ z+4dXzk8>d-UnCj9Wyn>Ld8EH(9_e`K48>}xn=**Ebrf85gpkbmXwoZxY@Lrg>zX;xL}OOTTk7nrzbxG zI(_EQVPMPmqQhlZ8j{O!c@L##U6h+ z&l%tmXFvGk@O|XhyI@O6UWlI9g$lxv8NqV+Dsbnt$1wb%BxK5Q=}0T58sBZ@ogLq%C=Vcm4EsmtN~ojjeU=e^gMID@GXCB&Q%e5 zB_u;KA@nJ2vKa+d)Dngh`s=2tEAj&SZzvomxgwadCC@^aTr2c1pB{0Is-dl%*5OQO zH4;oz3%mp~$+lOJFR}Kq0f|y&=q-3lfgS5lEXlS}(cQKXu1zM)YaKX!WdbD?O^y^# zDD*velgGyJq9P+K*uwHLQM$@8---X7K|PmqWiXgP8+e=oK9ib)+p{PzGSf=sNMFU0 zvsacQt?{4cXe@teC{-u8c;m)I=;x^j36=IX6cH8J?#o`kSJ(|)ZK4=mEw1Qc5oQ&2 zZnl|v(|0j%ua4p1v3bqbvol2;?JOxx_w*^k%^#T85)Se^T{YA;_Eisl=fw$I5Sa)Y z?kx*9yiF4oyMsbS`r)MURICy?0M z8#T3>D+FlmPg2|}15sqPUXwvT3FK9TN4Z+aDc1kB^vcw(%!$O=j}3=rheVjx{& zl>bTtc0s}93cM(#C**tk3ZT#RA&@#D0eP8-z#P0;wJ`*?vR;-c za&30%sG#SXg3HOcmWXSHO@d#MnMuQ+t3VwyH_)~GF`V79LO4_DFleokRyMo-z*X(T zu0zsY$5l8F=m$@+R-%(nZD|ss4j*r=8WGCm=i(;tjEPr@>YB@LcI(MlxmZ-pK8p?2 zYR|8mUd`&F96`4|90Zp->zAqbAhkmoHVmA8yT?k_-iVcIUdxJv=wzD4+X#)%i2L3% zmXO{?F>O&>ZEDAKh1A}<8ouT{&>N*zS&B=kdnVKMhxuh3cr%Zz-8m?Hyvd58WTOz< za=@CG$55LlC+f8lfq;$gFX>~{5spZ}^^G<hV--q)?dtBnqibonRRq<>7 z7U~TTakP=bg-^5Ng$mSI1gM)f3E~l%=FEUp8&JbNQdy!~B0-b>(8ev#H@UBUh#H(4 z=6!k`TfNbPfP<(%?y%Bc1vY2;kZO!X(BeNO*CU2N7(~z}`Nb7l$*rD+&!6sHIq1WC z?4l{RILN%7bY)i0jmdfg@Fh`PC_B zqsxlR90sq1fD;61cG-~3tCFO`eD*;0(+M7U1ntpp?RcjjF0tUnWTU0%^+9kJhD%n! zgBbv5^rA=N`r#xjHq2#5eQg+-6}$yDwaqKE?fKR}$5Xr0eF8Qs=|#=JwQ!dSF*)_4 zdwCb>YJP2q6kBH&{S~L=SW!uBe|X!VJ*3bkVvCxcdI5o2zxm^eDP-sOcbYE3v-}qC{E!-FIMivBVlkL#}-8Ga%mWi1Qk1n@4pH9@~IOLXOI0?Zk zM^cz5?VdS}7%Ccrwb8f3WVq9;lhZq4V=960ZCxmF%ZAdcHPFAlX4@&t8nkCPetM>? zMGj=@$&;bqWqlD(9C?T|cqNDy|J~eJHrzuPfUrj(o~HRdV{70KHF3{wgsF!}&e?kN z4M{E`i#W8w&52;MUB+6G?y7K(DG&d}=3`i=yzlC=8b$(3csel8*xqJz4b#rXi343x zH)tf2aycSIjdy~*pK5t9&w&EQXt<|m#oJ2N2`QYxxm#c^QHgu&#|2cfZroIEFw2(V zC>ch#uKy5QOFAlMgi9ly1Fv#IIF@OY?JqBgq^X~ZGc#Y5FnQP|JYfd;Tu}|kHiToX z1k)k&k}3w2vBoj$NFFAl9yHeqN(84HQfa2T7Nm6Zvk4oxWv67jUF)c8h}|{Zlw9F` z&Wnb)Hx)9a@8t0|gLLTHSys(_ND=CrE%*^HRX2x8QQ2*78!~US#UIHMR-EdrHZVL| z3eJ55h?+K>h~hS$Rk&;2T(lcUQjN}YcSkW?riE261{@c4mEo($evDcu+4pGM{4^C> z>%v8$C*i_}3B8tl@Plzi-vS_b4RA*%LeC)Za71V*uBUWK9@ILFTJMN)-h7mNf~cO9 z{sa@=b|3{G2u^(;;s}0W3c?hxa-)giv&V=m4HA2T-z3+@2*V5YP5Zu@cIo}aw0)E~ zRw6hS39))o7B=?thEP^_4>8Y#nTA|=EEW-8&uE<-q6XAch3drF@#?QG8`MHAE_}mj z#n>}_8j5K&3FBL+>Eia*?kP&q5qP&l;yB7-kk#>GoDsu8nYRrSojEX_TyS0Fhc<~T z?e|-ev|P%c8Rp;R4dX|hLN4$lF5j$?w;fnrb2f<7sE+;&-=-Y~stQAJ0#8KMtQ`hw znNVR8`nRy;nR$WhP*0(aqYT%?7KqeN__i1tYKjGj@5K&<&!Nq*Oqb*~hgi2pnx0uIbaTPy48luNKZ2>XTKF{wvq#&8^ zStrDjEX2NKv*1&~wJiIcS*mx8Ig-h0cvJQt>#rOZZZ>iwZJHG9S8-CV@r!7b90m>g z-9rA&i<{SEcCv>Iu&YOrO{U{x_on3!grRvn+rb>|Ov87mwF~=rh6bqhzsfO$Z9{bQ zFDCqKw7!ncuT0$`aFK~b-IB`bNLO$X*$rx7H{gUpAmiIi4L7n&9qc9~$Zc=JkzM-t zS?z^>0Sf5MI+I=rKS-i_dw7j*+)wE@u6cxM!*oluu#Xx1rA$3Csv0R|aPM+SZ=?zB zbs~+m@A5Pv{cD6?Vd~gW%!9FUxGpAhR2eoq(lE8zHF@Z}o8Tg}HO+C_-g1Y(Z1|L1 zXNyckQOCA{(S)}7W%RWB0t%@i8vYrSU~sjX;Aubpb-cS3o86NNl#-MicZ_qR+3uB{ zCAg!EUh3{~gVJ-MGy*Mv4CV#cPz%6=JLOb>Ze$pOiLtc$J6PB-Sh$p+n0-8j=?7X^6+-Adggx+Qt3p7uHuTBgI5e-sPGSRYPG z?ihguLCtQfu(LJ32&rr?rvBQQrj6&n_wx+ZN}Lefi?DgmB}r zlybq~L=>Lt)oOUMTDMTQ(wbRk1dj|nTTr?#nex2xYi|Q~Ls~cF-%rxt&O3S7^MPYM zZmiqAV!fE+zE4uPIJ3mbBHfJ!OFl$2c6sF(Y{|2EFP)v&?`+-_nEUY>RoJ_>d%^D< zl(jG9b$OK=bSrL^+Ix4mn%KT{w0PFY-=I|6NIbZN7%xQyM2#kIaktFxDN4FK} zdM+@y8od@l2#_O75O&U(XjnEjb4Bsm9NwgMx>19$OQd{Fd+x}YE#lho;MI@eo~ad) zsCTvhqJI9kA$AiFADx=+J$jh@EP3U*De3>GsDUSpm3LWRA7Qq*A(joH{Bl#n>E`S5 zqN6I;PWXx#^_sk;wx_KkefAK{Ca!hP*HQ-9IFky`DuZv@-_Rt7J~xZWv?h#m=^X}- z@N0~3acaYzZq{@URvw9Lxd=X-&$W^==`r7qRob70dv|JkzhC+$+iR``Uabbwt#!6$ zu>X14B&V?3o|}R;eF?uZHPf@Lap^! zT-9c@X6(Kc*&?P-og^_I{r$mp3I0OFB`Dh9o6*+K)!q5s<<|D?&8^M+?M7+sK@iFHY4u+A|3;R}*D3!E zg`i{p#d_~G_=CVE_TPYHr&6Esny9CJ{@48Oi>-T?=(wN%0Gt!;>T7*2_Wu_8!Z^75 zlKPP~qC|8ic0vsPAURT&K56mm*oAuJq-&)5T z0}L<^`cR?0&C)X)V>vh@o7HK5f>-+RS#?9^A7Kb?MplEiCB-fRe+T2kN9oZmZ3d3V zX&)uWL^0w*ZtggB1eh9}8PLbODGi=riyc)u(o7awIV?|g!cAZ23BMwbvx{Lw7kLI! zo1p$=E5vlCYW9G_)_|aG8JZAm7O-aE<%AeR1;Y8eSXJ;?CMaT;rMZK5aFe|@(L z_CXVkyyM?9bf``@1~)={y;zYs#CI!wxHG6cOb|I%M%oWK@MdF+L_s|8mRoD`2tB2f zTbdeY`yJCJy_qI;x2ugg9yj0GpP}_j$0wg*|7r#9pA6gl(zdozHY%N)yLT`xDBE2# z#H(O1DYF;j90y;G4ZYnH8G`TuM(&t;xcl)bQw;(&Qfpn?o5qghC}Au6ehG|TS5g@s zd6ICCr$hPP);O6s!2JwkK6^xb7U}EF@9kh6_%~!252I5g;yt>u&LN$P>N?ZS*;dsG zf9)7S67!QL)~04zy$z(UA_fOwrSVCcXVb@GlKe)-FkQ&$W+QE4(hyb+@n%Bz%<9ZtL{M`gjun z273pEhC0+`ZWs3%=Zy8aK)$S!yPZ0m9FVg@@j(ruh^2~{+XoIZrmYi#$ zUb}&g2d)L#86;)fd}a)X+P1I4#58Y)1URy)Okd;6JtlqNDVwXNT~+I*8%b1lwujtg z)v&0Al@s3@GBgK06D?;6UNl^4i zyd?&R8L%Pe=5mN6PG5m8b0`5qKFH`nfszhDXzB{zyGM18*WI3V1gL2m9*oo=*@|I<|mkk<1?h7JE zjNM6&gZSFgtCG{hXlytUzbhju!=2tSaGv%>ovgTAOuT1@EP%;I4@n+(^*0NJug7>ftvxV2u+*SmfvoOoYv*m{jmPO-Kg=j{W6i=29z>k99d%3#;G^z@1=q?s z0h_SFH*zkoWqbcGH6`~`BIJtyT@=ufu=Gndq?+#?5+EW+Cbjta>d$5u;$$S9Pmvxj zv5DgUCiaT#|Db`F@I~F>KQf^-QDp9gIRhVY4Hcp%qE9!&b@?1xb zO!giIM3*cae*6_MN8yVHc9#o`KjxGBA$t!6!cYE-2mY1R6L$P!%M|2t#TJUl@L4Tk zPYEAL>Af+>Jb)mndqEIiLorEpa)d2COf{xa&{A!GX+NqW#`_nicT!Sq6B_uB+KBh3 z0IUvMIOdt4O>c^~-3N>vTe5xAb}Jh4$536WcVsqgX3PYohc*7|sm4N>8XC@v?`xOPrB@a73Tq*ETCpXzP>fO8&j(rC*wYh_HS zm8o%S_qD=BQ+9N7*HiYSW(LUIoggsbx6F?gt*E#IaGnCjW_|Tn5w?acZ5Idi#^FJa zsDrwmwoGJI7p7w1`pb0@ruuPLZZ%UP$qvk)Q4gVMS+zBMHB1CW$2rqWktL;bbfMKxQLdpX<;!r8vD z4_^W3HU?a$lh%w_{P0m18Kr2X(fFgK{~A%35I?K)84wpd{chMSc59|OV9?vK(7kTc z$E-HqS5XAJ0aW&4zl9JT9cn+g8(?wz#2N%cx9JG(qMrVaEUhdMj@V>yj8m6S2KN=E zGXu^2kMEonGFP`v*RntDjN@Aj2vc5uWmKDf#pfo+yZW6>^#BcDsBE-OcfGDF@GW?P z)Iyk;%Gv;JADd|3%Y%1%bNyRto}&-i4lb%^8?1q(v41Ef7a8I}Hly9@zJl=j7e8IA zpoEDTQ720iMpgUnr$N9KwB!(9AY*|u!Q|eVqD0^=^`N$J5Z$BoX*WHle*t|@07GVS zC6`O;!XmD0Q`=tv&sNIxE|{bN)z5j?DFe;r)gF z(OFzQe$u_2m-YAB!>08^%DqS?18WdRfi)EkXknGmW3km6GA_oGKNHh}RLL1FV)*7n z-KfEq3(`XpfBs}6k0H#=ELR8wFpf(Nncg%niITd1-;3w0fuJ01JfypwZ>(Zr&%M1F zB9MXJ6g=e^C0D=LVoj;eFeQYr?a!H80^=_Vvdrg2v7T=&AmZJKml z|D4YEJL6AwZyJPy6GSMSYi<;h36IJ>E`K%!Sp_OL>$47@j*r>o7y`ZOQ7wk$+P4hq z;^k`^jFclcX%|^XWzx8*!paR?E80LQJ4j^08s1VZn4#4yzB1euzpE>qWdU={lslc0r`r+>E}>5{B--M_%Bs;RHDY4%rj9Rl~=LtZ)> z(UsbQ=%?(dDtmzM?z$=)sbjQz+D6Q4K$dovBl1_w@^CKJr7Z{Dk{Ouf>gs@&tAI$q zXHo#|6(yP%>M6wW_f$Yaxd#x$ReMGORL?cmD;9(BBgqCC9aKA4R0pS{D0+gnnTj(` zdk>lH4dYnCdq{qq)z{TP3fK)ieNj>~eFqU~jGSI(!v&T0=OV(*5P#JZY`E9q<;h^X zD|#{BAkp1!fO(r?jbLsw=6#?87zlR#JIxk9#8ej{$CUmv8ay=c`iopU-WoaE4D!(} zSC>L-=5DvF1j~Uw&d9_9n1`R5oKMdY@4%6%LGz6Ru5cZX~xvs zaDUQe1#RPVIJ-$CwiN!PiHXC=tW=e7wlz1usBp_bxvoh?P9Ds1cW@8A?=V?c#Q=Sx zwemeQgp%0w2QAHBjW-4n^X$v+TiK=C`MT!1TLntly`XM;+H2uK?hX#I&OyCRY*K{a zKl71b`^tJ}Zt^fmzE!^OkfD^z@vemJS$J zP0kFitJ{!d5s+E_Oj?J}SI@M@TS1E1S|;UbXk1l~4Lh##e56-*<_j4hh-Zu45{K5~A zrF1&tuWfpSP~A7aMPw2z#6)AWk;(P1kw72(EvMGNhXHY>v9$i3Sdn0W_UCC9d-1x+ z#=K_iT-A(iOWWAC4d(+A79Z!YOzt{$;WENzN#{Zdj+}7Ty4#gtJ&6v7FOJIdjJM8H z3(7t|to%;Q?4-KdLr?Hj9Z6Fx#+SM1?ASnMvz%8AUp9TODp?ijf!}vc6}|MZx&~*r zUuc&T(V)}R4xZq%nTO5s3@Pa)rc7mc$`V1=PWrRwP!d+V_g3+(Px7J@aq7S2LtUf& z-8Di*qF#8p2jWe|JaIdS&t3X$_n!8vdLZ3fa7*zH{-X7^q7b<9u2YpGTke<~JRC9~ zXFBSkap6?3^K^UpvZSCycq=4F!MjTVHJVwxg}oRm$~H{);`;faGtHYCAT{@8fuy7C zaScv&e2(bL*R>Yod{`&!-Fmy|>5k05iD!`}eR$#^-NsS;>z7$AM+~%*Dn zF0W>^`KhG#-0=9;S=q!|A+S$1d67B}`5Pj9JMsDdU~yfoOVw^eubKYVx`8D(XIS?O zUqV7oBlvSX@nPKC);`)SG&3`5IyDwyi}6MDjOJ~u5qf4uh$UYSPrsIjn`EPPw~UcX zm?Zslk-08?m(ffx)OKQAHe3qH7m}Q2W>=6r(TH(c3o)nvBd

  • 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 |TTvF!@BqnJ3418jW8#ce)R{#t6Cp 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

    E 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 diff --git a/modules/Movecraft/pom.xml b/modules/Movecraft/pom.xml index b53ca5051..51a702767 100644 --- a/modules/Movecraft/pom.xml +++ b/modules/Movecraft/pom.xml @@ -51,24 +51,11 @@ API jar - - com.sk89q - worldguard - LATEST - provided - org.yaml snakeyaml 1.10 - - com.mewin - WGCustomFlags - LATEST - system - ${project.basedir}/../../libs/WGCustomFlags.jar - org.jetbrains annotations-java5 diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java index 46254db8a..94325b1a3 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java @@ -17,9 +17,6 @@ package net.countercraft.movecraft; -import com.mewin.WGCustomFlags.WGCustomFlagsPlugin; -import com.sk89q.worldguard.bukkit.WorldGuardPlugin; -import com.sk89q.worldguard.protection.flags.StateFlag; import net.countercraft.movecraft.async.AsyncManager; import net.countercraft.movecraft.commands.*; import net.countercraft.movecraft.config.Settings; @@ -31,8 +28,6 @@ import net.countercraft.movecraft.localisation.I18nSupport; import net.countercraft.movecraft.mapUpdater.MapUpdateManager; import net.countercraft.movecraft.sign.*; -import net.countercraft.movecraft.utils.WGCustomFlagsUtils; -import net.countercraft.movecraft.worldguard.WorldGuardCompatManager; import org.bukkit.Material; import org.bukkit.plugin.Plugin; import org.bukkit.plugin.java.JavaPlugin; @@ -43,17 +38,7 @@ import java.util.logging.Logger; public class Movecraft extends JavaPlugin { - public static StateFlag FLAG_PILOT = null; //new StateFlag("movecraft-pilot", true); - public static StateFlag FLAG_MOVE = null; //new StateFlag("movecraft-move", true); - public static StateFlag FLAG_ROTATE = null; //new StateFlag("movecraft-rotate", true); - public static StateFlag FLAG_SINK = null; //new StateFlag("movecraft-sink", true); private static Movecraft instance; - private static WorldGuardPlugin worldGuardPlugin; - private static WGCustomFlagsPlugin wgCustomFlagsPlugin = null; - /*public HashMap blockFadeTimeMap = new HashMap<>(); - public HashMap blockFadeTypeMap = new HashMap<>(); - public HashMap blockFadeWaterMap = new HashMap<>(); - public HashMap blockFadeWorldMap = new HashMap<>();*/ private Logger logger; private boolean shuttingDown; private WorldHandler worldHandler; @@ -83,7 +68,6 @@ public void onEnable() { Settings.LOCALE = getConfig().getString("Locale"); - Settings.RestrictSiBsToRegions = getConfig().getBoolean("RestrictSiBsToRegions", false); Settings.Debug = getConfig().getBoolean("Debug", false); Settings.DisableSpillProtection = getConfig().getBoolean("DisableSpillProtection", false); Settings.DisableIceForm = getConfig().getBoolean("DisableIceForm", true); @@ -164,46 +148,6 @@ public void onEnable() { worldHandler.disableShadow(Material.getMaterial(typ)); } } - //load up WorldGuard if it's present - Plugin wGPlugin = getServer().getPluginManager().getPlugin("WorldGuard"); - if (wGPlugin == null || !(wGPlugin instanceof WorldGuardPlugin)) { - logger.log(Level.INFO, I18nSupport.getInternationalisedString("Startup - WG Not Found")); - Settings.RestrictSiBsToRegions = false; - } else { - logger.log(Level.INFO, I18nSupport.getInternationalisedString("Startup - WG Found")); - Settings.WorldGuardBlockMoveOnBuildPerm = getConfig().getBoolean("WorldGuardBlockMoveOnBuildPerm", false); - Settings.WorldGuardBlockSinkOnPVPPerm = getConfig().getBoolean("WorldGuardBlockSinkOnPVPPerm", false); - logger.log(Level.INFO, "Settings: WorldGuardBlockMoveOnBuildPerm - {0}, WorldGuardBlockSinkOnPVPPerm - {1}", new Object[]{Settings.WorldGuardBlockMoveOnBuildPerm, Settings.WorldGuardBlockSinkOnPVPPerm}); - getServer().getPluginManager().registerEvents(new WorldGuardCompatManager(), this); - } - worldGuardPlugin = (WorldGuardPlugin) wGPlugin; - - - if (worldGuardPlugin != null && worldGuardPlugin instanceof WorldGuardPlugin) { - if (worldGuardPlugin.isEnabled()) { - Plugin tempWGCustomFlagsPlugin = getServer().getPluginManager().getPlugin("WGCustomFlags"); - if (tempWGCustomFlagsPlugin != null && tempWGCustomFlagsPlugin instanceof WGCustomFlagsPlugin) { - logger.log(Level.INFO, I18nSupport.getInternationalisedString("Startup - WGCF Found")); - wgCustomFlagsPlugin = (WGCustomFlagsPlugin) tempWGCustomFlagsPlugin; - WGCustomFlagsUtils WGCFU = new WGCustomFlagsUtils(); - FLAG_PILOT = WGCFU.getNewStateFlag("movecraft-pilot", true); - FLAG_MOVE = WGCFU.getNewStateFlag("movecraft-move", true); - FLAG_ROTATE = WGCFU.getNewStateFlag("movecraft-rotate", true); - FLAG_SINK = WGCFU.getNewStateFlag("movecraft-sink", true); - WGCFU.init(); - Settings.WGCustomFlagsUsePilotFlag = getConfig().getBoolean("WGCustomFlagsUsePilotFlag", false); - Settings.WGCustomFlagsUseMoveFlag = getConfig().getBoolean("WGCustomFlagsUseMoveFlag", false); - Settings.WGCustomFlagsUseRotateFlag = getConfig().getBoolean("WGCustomFlagsUseRotateFlag", false); - Settings.WGCustomFlagsUseSinkFlag = getConfig().getBoolean("WGCustomFlagsUseSinkFlag", false); - logger.log(Level.INFO, "Settings: WGCustomFlagsUsePilotFlag - {0}", Settings.WGCustomFlagsUsePilotFlag); - logger.log(Level.INFO, "Settings: WGCustomFlagsUseMoveFlag - {0}", Settings.WGCustomFlagsUseMoveFlag); - logger.log(Level.INFO, "Settings: WGCustomFlagsUseRotateFlag - {0}", Settings.WGCustomFlagsUseRotateFlag); - logger.log(Level.INFO, "Settings: WGCustomFlagsUseSinkFlag - {0}", Settings.WGCustomFlagsUseSinkFlag); - } else { - logger.log(Level.INFO, I18nSupport.getInternationalisedString("Startup - WGCF Not Found")); - } - } - } if (shuttingDown && Settings.IGNORE_RESET) { logger.log( @@ -271,14 +215,6 @@ public void onLoad() { - public WorldGuardPlugin getWorldGuardPlugin() { - return worldGuardPlugin; - } - - public WGCustomFlagsPlugin getWGCustomFlagsPlugin() { - return wgCustomFlagsPlugin; - } - public WorldHandler getWorldHandler(){ return worldHandler; } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/rotation/RotationTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/rotation/RotationTask.java index 9983138f1..11f309cdc 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/rotation/RotationTask.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/rotation/RotationTask.java @@ -17,8 +17,6 @@ package net.countercraft.movecraft.async.rotation; -import com.sk89q.worldguard.LocalPlayer; -import com.sk89q.worldguard.protection.ApplicableRegionSet; import net.countercraft.movecraft.CruiseDirection; import net.countercraft.movecraft.Movecraft; import net.countercraft.movecraft.MovecraftLocation; @@ -120,16 +118,6 @@ protected void execute() { break; } - // See if they are permitted to build in the area, if WorldGuard integration is turned on - Location plugLoc = newLocation.toBukkit(w); - if (craftPilot != null && - Movecraft.getInstance().getWorldGuardPlugin() != null && - Settings.WorldGuardBlockMoveOnBuildPerm && - !Movecraft.getInstance().getWorldGuardPlugin().canBuild(craftPilot, plugLoc)) { - failed = true; - failMessage = String.format(I18nSupport.getInternationalisedString("Rotation - Player is not permitted to build in this WorldGuard region") + " @ %d,%d,%d", newLocation.getX(), newLocation.getY(), newLocation.getZ()); - break; - } if (!withinWorldBorder(craft.getW(), newLocation)) { failMessage = I18nSupport.getInternationalisedString("Rotation - Failed Craft cannot pass world border") + String.format(" @ %d,%d,%d", newLocation.getX(), newLocation.getY(), newLocation.getZ()); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/BlockListener.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/BlockListener.java index e09aad3fb..85508cd85 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/BlockListener.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/BlockListener.java @@ -17,7 +17,6 @@ package net.countercraft.movecraft.listener; -import com.sk89q.worldguard.protection.ApplicableRegionSet; import net.countercraft.movecraft.Movecraft; import net.countercraft.movecraft.MovecraftLocation; import net.countercraft.movecraft.config.Settings; @@ -43,31 +42,6 @@ import java.util.List; public class BlockListener implements Listener { - @EventHandler - public void onBlockPlace(final BlockPlaceEvent e) { - if (!Settings.RestrictSiBsToRegions || - e.getBlockPlaced().getTypeId() != 54 || - !e.getItemInHand().hasItemMeta() || - !e.getItemInHand().getItemMeta().hasLore()) { - return; - } - List loreList = e.getItemInHand().getItemMeta().getLore(); - for (String lore : loreList) { - if (!lore.contains("SiB")) { - continue; - } - if (lore.toLowerCase().contains("merchant") || lore.toLowerCase().contains("mm")) { - return; - } - Location loc = e.getBlockPlaced().getLocation(); - ApplicableRegionSet regions = Movecraft.getInstance().getWorldGuardPlugin().getRegionManager(loc.getWorld()).getApplicableRegions(loc); - if (regions.size() == 0) { - e.getPlayer().sendMessage(I18nSupport.getInternationalisedString("SIB MUST BE PLACED IN REGION")); - e.setCancelled(true); - break; - } - } - } @EventHandler(priority = EventPriority.LOWEST) public void onBlockBreak(final BlockBreakEvent e) { diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/ExplosionUpdateCommand.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/ExplosionUpdateCommand.java index 214bab1c4..ef6646c8e 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/ExplosionUpdateCommand.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/ExplosionUpdateCommand.java @@ -1,9 +1,8 @@ package net.countercraft.movecraft.mapUpdater.update; -import com.sk89q.worldguard.protection.ApplicableRegionSet; -import com.sk89q.worldguard.protection.flags.DefaultFlag; import net.countercraft.movecraft.Movecraft; import net.countercraft.movecraft.config.Settings; +import net.countercraft.movecraft.events.ExplosionEvent; import org.bukkit.Bukkit; import org.bukkit.Location; @@ -33,7 +32,11 @@ public float getStrength() { public void doUpdate() { //if (explosionStrength > 0) { // don't bother with tiny explosions //Location loc = new Lo cation(explosionLocation.getWorld(), explosionLocation.getX() + 0.5, explosionLocation.getY() + 0.5, explosionLocation.getZ()); - if (Settings.Debug){ + ExplosionEvent e = new ExplosionEvent(explosionLocation, explosionStrength); + Bukkit.getServer().getPluginManager().callEvent(e); + if(e.isCancelled()) + return; + if (Settings.Debug) { Bukkit.broadcastMessage("Explosion strength: " + explosionStrength + " at " + explosionLocation.toVector().toString()); } this.createExplosion(explosionLocation.add(.5,.5,.5), explosionStrength); @@ -42,12 +45,6 @@ public void doUpdate() { } private void createExplosion(Location loc, float explosionPower) { - if (Movecraft.getInstance().getWorldGuardPlugin() != null) { - ApplicableRegionSet set = Movecraft.getInstance().getWorldGuardPlugin().getRegionManager(loc.getWorld()).getApplicableRegions(loc); - if (!set.allows(DefaultFlag.OTHER_EXPLOSION)) { - return; - } - } loc.getWorld().createExplosion(loc.getX(), loc.getY(), loc.getZ(), explosionPower); } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/WGCustomFlagsUtils.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/WGCustomFlagsUtils.java deleted file mode 100644 index 8980403d9..000000000 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/WGCustomFlagsUtils.java +++ /dev/null @@ -1,94 +0,0 @@ -package net.countercraft.movecraft.utils; - -import com.mewin.WGCustomFlags.WGCustomFlagsPlugin; -import com.sk89q.worldguard.LocalPlayer; -import com.sk89q.worldguard.protection.flags.Flag; -import com.sk89q.worldguard.protection.flags.StateFlag; -import net.countercraft.movecraft.Movecraft; -import org.bukkit.Location; - -import java.lang.reflect.Constructor; -import java.lang.reflect.InvocationTargetException; - -/** - * @author mwkaicz - */ -public class WGCustomFlagsUtils { - - - public StateFlag getNewStateFlag(String name, boolean def) { - Constructor cc = getStateFlagConstructor(); - if (cc == null) { - return null; - } - Object o; - try { - o = cc.newInstance(name, def); - return (StateFlag) o; - } catch (InstantiationException | InvocationTargetException | IllegalArgumentException | IllegalAccessException ex) { - return null; - } - } - - public Constructor getStateFlagConstructor() { - try { - Class c = Class.forName("com.sk89q.worldguard.protection.flags.StateFlag"); - return c.getConstructor(String.class, boolean.class); - } catch (ClassNotFoundException | SecurityException | NoSuchMethodException ex) { - return null; - } - } - - public boolean registerStageFlag(Object o) { - WGCustomFlagsPlugin wgcf = Movecraft.getInstance().getWGCustomFlagsPlugin(); - if (wgcf != null) { - Constructor cc = getStateFlagConstructor(); - if (cc == null) { - return false; - } - try { - wgcf.addCustomFlag((Flag) o); - } catch (Exception e) { - return false; - } - return true; - } - return false; - } - - - public void init() { - if (Movecraft.FLAG_PILOT != null) { - this.registerStageFlag(Movecraft.FLAG_PILOT); - } - if (Movecraft.FLAG_MOVE != null) { - this.registerStageFlag(Movecraft.FLAG_MOVE); - } - if (Movecraft.FLAG_ROTATE != null) { - this.registerStageFlag(Movecraft.FLAG_ROTATE); - } - if (Movecraft.FLAG_SINK != null) { - this.registerStageFlag(Movecraft.FLAG_SINK); - } - } - - public boolean validateFlag(Location loc, Object flag) { - if (flag != null) { - StateFlag.State state = (StateFlag.State) Movecraft.getInstance().getWorldGuardPlugin().getRegionManager(loc.getWorld()).getApplicableRegions(loc).getFlag((Flag) flag); - return state != null && state == StateFlag.State.ALLOW; - } else { - return true; - } - } - - public boolean validateFlag(Location loc, Object flag, LocalPlayer lp) { - if (flag != null) { - StateFlag.State state = (StateFlag.State) Movecraft.getInstance().getWorldGuardPlugin().getRegionManager(loc.getWorld()).getApplicableRegions(loc).getFlag((Flag) flag, lp); - return state != null && state == StateFlag.State.ALLOW; - } else { - return true; - } - } - - -} diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/WorldguardUtils.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/WorldguardUtils.java deleted file mode 100644 index 3a197291c..000000000 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/WorldguardUtils.java +++ /dev/null @@ -1,39 +0,0 @@ -package net.countercraft.movecraft.utils; - -import com.sk89q.worldguard.protection.regions.ProtectedRegion; -import org.bukkit.Bukkit; -import org.bukkit.OfflinePlayer; - -import java.util.UUID; - -public class WorldguardUtils { - public static String getRegionOwnerList(ProtectedRegion tRegion) { - StringBuilder output = new StringBuilder(); - if (tRegion == null) - return output.toString(); - boolean first = true; - if (tRegion.getOwners().getUniqueIds().size() > 0) { - for (UUID uid : tRegion.getOwners().getUniqueIds()) { - if (!first) - output.append(", "); - else - first = false; - OfflinePlayer offP = Bukkit.getOfflinePlayer(uid); - if (offP.getName() == null) - output.append(uid.toString()); - else - output.append(offP.getName()); - } - } - if (tRegion.getOwners().getPlayers().size() > 0) { - for (String player : tRegion.getOwners().getPlayers()) { - if (!first) - output.append(","); - else - first = false; - output.append(player); - } - } - return output.toString(); - } -} diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/worldguard/WorldGuardCompatManager.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/worldguard/WorldGuardCompatManager.java deleted file mode 100644 index 2fde49ea3..000000000 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/worldguard/WorldGuardCompatManager.java +++ /dev/null @@ -1,43 +0,0 @@ -package net.countercraft.movecraft.worldguard; - -import net.countercraft.movecraft.Movecraft; -import net.countercraft.movecraft.MovecraftLocation; -import net.countercraft.movecraft.config.Settings; -import net.countercraft.movecraft.events.CraftRotateEvent; -import net.countercraft.movecraft.events.CraftTranslateEvent; -import net.countercraft.movecraft.localisation.I18nSupport; -import org.bukkit.event.EventHandler; -import org.bukkit.event.Listener; - -public class WorldGuardCompatManager implements Listener { - @EventHandler - public void onCraftTranslateEvent(CraftTranslateEvent event){ - if(!Settings.WorldGuardBlockMoveOnBuildPerm) - return; - if(event.getCraft().getNotificationPlayer() == null) - return; - for(MovecraftLocation location : event.getNewHitBox()){ - if(!Movecraft.getInstance().getWorldGuardPlugin().canBuild(event.getCraft().getNotificationPlayer(),location.toBukkit(event.getCraft().getW()))){ - event.setCancelled(true); - event.setFailMessage(String.format( I18nSupport.getInternationalisedString( "Translation - WorldGuard - Not Permitted To Build" )+" @ %d,%d,%d", location.getX(), location.getY(), location.getZ() ) ); - return; - } - } - } - - @EventHandler - public void onCraftRotateEvent(CraftRotateEvent event){ - if(!Settings.WorldGuardBlockMoveOnBuildPerm) - return; - if(event.getCraft().getNotificationPlayer() == null) - return; - for(MovecraftLocation location : event.getNewHitBox()){ - if(!Movecraft.getInstance().getWorldGuardPlugin().canBuild(event.getCraft().getNotificationPlayer(),location.toBukkit(event.getCraft().getW()))){ - event.setCancelled(true); - event.setFailMessage(String.format( I18nSupport.getInternationalisedString("Rotation - WorldGuard - Not Permitted To Build" )+" @ %d,%d,%d", location.getX(), location.getY(), location.getZ())); - return; - } - } - } - -} diff --git a/modules/Movecraft/src/main/resources/config.yml b/modules/Movecraft/src/main/resources/config.yml index 0d7ee0b11..5f870e677 100644 --- a/modules/Movecraft/src/main/resources/config.yml +++ b/modules/Movecraft/src/main/resources/config.yml @@ -5,8 +5,6 @@ SinkCheckTicks: 100 TracerRateTicks: 5 TracerMinDistance: 60 # Minimum distance for tracers to appear PilotTool: 280 -WorldGuardBlockMoveOnBuildPerm: true -WorldGuardBlockSinkOnPVPPerm: true ManOverboardTimeout: 30 ManOverboardDistance: 1000 # maximum distance from a craft that you can manoverboard to it FireballLifespan: 6 @@ -47,10 +45,6 @@ DisableShadowBlocks: # These blocks will not cast shadows. This improves the spe - 165 - 173 - 206 -WGCustomFlagsUsePilotFlag: false -WGCustomFlagsUseMoveFlag: false -WGCustomFlagsUseRotateFlag: false -WGCustomFlagsUseSinkFlag: false DurabilityOverride: 121: 80 206: 80 diff --git a/modules/Movecraft/src/main/resources/localisation/movecraftlang_cz.properties b/modules/Movecraft/src/main/resources/localisation/movecraftlang_cz.properties index 7d48d7dd2..c2ea67029 100644 --- a/modules/Movecraft/src/main/resources/localisation/movecraftlang_cz.properties +++ b/modules/Movecraft/src/main/resources/localisation/movecraftlang_cz.properties @@ -53,11 +53,9 @@ Startup\ -\ Error\ -\ Disable\ warning\ for\ reload=Pokud chcete pouzit prikaz r Startup\ -\ Enabled\ message=[V %S] byl nacten. Item\ -\ Storage\ Crate\ name=Prepravni bedna Player-\ Craft\ has\ been\ released=Pustil jsi rizeni sveho stroje\! -Player-\ Craft\ should\ sink\ but\ PVP\ is\ not\ allowed\ in\ this\ WorldGuard\ region=Stroj by se mel potopit ale PVP neni povoleno v tomto WorldGuard regionu Player-\ Craft\ is\ sinking=Vas stroj je prilis poskozen a potapi se\! Opustit palubu\! Player-\ Error\ -\ You\ do\ not\ have\ a\ craft\ to\ release!=Nemas zadny stroj, ktery by jsi mohl opustit\! Player\ -\ Error\ -\ Already\ piloting\ craft=Uz jeden stroj ridis\! -Player\ -\ Sinking\ a\ craft\ is\ not\ allowed\ in\ this\ WorldGuard\ region=Potopeni stroje neni povoleno v tomto WorldGaurd regionu MCStats\ -\ \:(\ -\ Admin\ has\ opted\ out=Vybrali jste odhlaseni od odesilani dat na mcstats.org. Vyvojar Movecraftu by byl velmi vdecny za vase data. MCStats\ -\ Thank\ you\ message=Statistiky byly uspesne odeslany na mcstats.org. Dekujeme za vasi podporu. MCStats\ -\ Error\ -\ Unable\ to\ upload\ stats=Nemohu odeslat statistiky na mcstats.org. Prosim, zkontrolujte sve pripojeni k siti. @@ -71,8 +69,6 @@ Too\ much\ flyblock=Prilis mnoho bloku nezbytnych pro pohyb #Detection\ -\ Failed\ -\ Too\ much\ flyblock=Detekce selhala\! Prilis mnoho bloku ID %s. Maximum je: %.2f procent. Nyni ma %.2f procent Detection\ -\ ERROR\:\ Double\ chest\ found=Detekce selhala\! ERROR \: Nalezena dvojita truhlice Detection\ -\ Failed\ -\ Water\ contact\ required\ but\ not\ found=Detekce selahala\: Je vyzadovan kontakt s vodou, ale nebyl detekovan -Rotation\ -\ Player\ is\ not\ permitted\ to\ build\ in\ this\ WorldGuard\ region=Rotace - Nemas pravo stavet v tomto WorldGuard regionu -Translation\ -\ Failed\ Player\ is\ not\ permitted\ to\ build\ in\ this\ WorldGuard\ region=Sroj se nemuze pohnout - Nemas pravo stavet v tomto WorldGuard regionu Parent\ Craft\ is\ busy=Hlavni stroj je zaneprazdnen Insufficient\ Permissions=Nedostatecne opraveneni ERROR\:\ Remote\ Sign\ must\ be\ a\ part\ of\ a\ piloted\ craft\!=CHYBA\: Vzdalena cedule musi byt soucasti rizeneho stroje\! @@ -92,7 +88,3 @@ Repairs\ underway=Probihaji opravy Repairs\ complete\.\ You\ may\ now\ pilot\ the\ craft=Opravy dokonceny. Nyni muzes ridit stroj You\ do\ not\ have\ enough\ money=Nemas dostatek penez Need\ more\ of\ material=Je potreba vice materialu -WGCustomFlags\ -\ Translation\ Failed=Stroj se nemuze pohnout - Nemas pravo hybat se strojem v tomto WorldGuard regionu -WGCustomFlags\ -\ Rotation\ Failed=Stroj se nemuze otocit - Nemas pravo otocit stroj v tomto WorldGuard regionu -WGCustomFlags\ -\ Detection\ Failed=Detekce selhala - Nemas pravo ridit stroj v tomto WorldGuard regionu -WGCustomFlags\ -\ Sinking\ a\ craft\ is\ not\ allowed\ in\ this\ WorldGuard\ region=Potopeni stroje neni povoleno v tomto WorldGuard regionu\! diff --git a/modules/Movecraft/src/main/resources/localisation/movecraftlang_en.properties b/modules/Movecraft/src/main/resources/localisation/movecraftlang_en.properties index 1dafda089..ee10e1c1e 100644 --- a/modules/Movecraft/src/main/resources/localisation/movecraftlang_en.properties +++ b/modules/Movecraft/src/main/resources/localisation/movecraftlang_en.properties @@ -71,7 +71,6 @@ Pilot\ -\ No\ Craft\ Type=You need to supply a craft type Pilot\ -\ Invalid\ Craft\ Type=Invalid Craft Type Player\ -\ Not\ Found=That player could not be found. Player\ -\ Not\ Piloting=That player is not piloting a craft. -Player\ -\ Craft\ should\ sink\ but\ PVP\ is\ not\ allowed\ in\ this\ WorldGuard\ region=Player- Craft should sink but PVP is not allowed in this WorldGuard region Player\ -\ Craft\ is\ sinking=Your craft has taken too much damage and is sinking\! ABANDON SHIP\! Player-\ Error\ -\ You\ do\ not\ have\ a\ craft\ to\ release!=You do not have a craft to release\! Player\ -\ Block\ part\ of\ piloted\ craft=BLOCK IS PART OF A PILOTED CRAFT @@ -102,7 +101,6 @@ Rotation\ -\ Invalid\ Direction=Invalid direction, use 'Left' or 'Right'. Rotation\ -\ NULL\ Player\ Rotation\ Failed=NULL Player rotation failed Rotation\ -\ Turning\ Too\ Quickly=You're turning too quickly\! Rotation\ -\ Already\ Rotating=You are already rotating -Rotation\ -\ WorldGuard\ -\ Not\ Permitted\ To\ Build=Rotation - Player is not permitted to build in this WorldGuard region Scuttle\ -\ Must\ Be\ Online=Player supplied must be online. Scuttle\ -\ Must\ Be\ Player=You must be a player to scuttle your craft. Scuttle\ -\ Craft\ Already\ Sinking=The craft is already sinking\! @@ -118,10 +116,6 @@ Startup\ -\ Recognized\ Pilot\ Tool=Recognized PilotTool setting of\: Startup\ -\ No\ Pilot\ Tool=No PilotTool setting, using default of 280 Startup\ -\ Version\ Not\ Supported=Could not find support for this version. Startup\ -\ Loading\ Support=Loading support for -Startup\ -\ WG\ Found=Found a compatible version of WorldGuard. Enabling WorldGuard integration. -Startup\ -\ WG\ Not\ Found=Movecraft did not find a compatible version of WorldGuard. Disabling WorldGuard integration. -Startup\ -\ WGCF\ Found=Found a compatible version of WGCustomFlags. Enabling WGCustomFlags integration. -Startup\ -\ WGCF\ Not\ Found=Movecraft did not find a compatible version of WGCustomFlags. Disabling WGCustomFlags integration. Teleportation\ -\ Cooldown\ active=Teleportation cooldown is active. You need to wait %d seconds Translation\ -\ Failed\ Craft\ cannot\ pass\ world\ border=Translation Failed: You cannot move the craft past the world border Translation\ -\ Failed\ Craft\ hit\ height\ limit=Craft has hit the height limit @@ -131,7 +125,6 @@ Translation\ -\ Failed\ Craft\ is\ obstructed=The craft cannot move because its Translation\ -\ Failed\ Craft\ out\ of\ fuel=The craft is out of fuel\! Translation\ -\ Failed\ Craft\ hit\ minimum\ height\ limit=Craft has hit the minimum height limit Translation\ -\ Failed\ Craft\ over\ block=This craft cannot move over %s\! -Translation\ -\ WorldGuard\ -\ Not\ Permitted\ To\ Build=Translation Failed - Player is not permitted to build in this WorldGuard region Translation\ -\ Failed\ Craft\ Cannot\ Step\ Up=This craft is obstructed or the incline is too high\! @@ -144,7 +137,3 @@ Direct\ Control\ -\ Entering=Entering Direct Control Mode Direct\ Control\ -\ Leaving=Leaving Direct Control Mode You\ must\ be\ piloting\ a\ craft=You must be piloting a craft SIB\ MUST\ BE\ PLACED\ IN\ REGION=SIB MUST BE PLACED IN REGION -WGCustomFlags\ -\ Translation\ Failed=Translation Failed - You are not permitted to move a craft in this WorldGuard region -WGCustomFlags\ -\ Rotation\ Failed=Rotation Failed - You are not permitterd to rotate a craft in this WorldGuard region -WGCustomFlags\ -\ Detection\ Failed=Detection Failed - You are not permitted to pilot a craft in this WorldGuard region -WGCustomFlags\ -\ Sinking\ a\ craft\ is\ not\ allowed\ in\ this\ WorldGuard\ region=Sinking is not allowed in this WorldGuard region\! diff --git a/modules/Movecraft/src/main/resources/plugin.yml b/modules/Movecraft/src/main/resources/plugin.yml index f9add75d5..9fcd3fe53 100644 --- a/modules/Movecraft/src/main/resources/plugin.yml +++ b/modules/Movecraft/src/main/resources/plugin.yml @@ -1,5 +1,4 @@ name: Movecraft -softdepend: [WorldGuard, WGCustomFlags] version: ${project.version} #version: ${env.BUILD_NUMBER} description: The original flight and movement plugin for minecraft. diff --git a/modules/api/pom.xml b/modules/api/pom.xml index 0637925fe..d6278d150 100644 --- a/modules/api/pom.xml +++ b/modules/api/pom.xml @@ -34,18 +34,6 @@ spigot-api 1.10.2-R0.1-SNAPSHOT - - com.sk89q - worldguard - LATEST - provided - - - com.sk89q - worldedit - LATEST - provided - org.jetbrains annotations-java5 diff --git a/modules/api/src/main/java/net/countercraft/movecraft/config/Settings.java b/modules/api/src/main/java/net/countercraft/movecraft/config/Settings.java index 6de4ab286..d5de749d6 100644 --- a/modules/api/src/main/java/net/countercraft/movecraft/config/Settings.java +++ b/modules/api/src/main/java/net/countercraft/movecraft/config/Settings.java @@ -25,7 +25,6 @@ import java.util.Map; public class Settings { - public static boolean RestrictSiBsToRegions = false; public static boolean IGNORE_RESET = false; public static boolean Debug = false; public static int THREAD_POOL_SIZE = 5; @@ -38,8 +37,6 @@ public class Settings { public static boolean DelayColorChanges = false; public static double SinkRateTicks = 20.0; public static double SinkCheckTicks = 100.0; - public static boolean WorldGuardBlockMoveOnBuildPerm = false; - public static boolean WorldGuardBlockSinkOnPVPPerm = false; public static boolean ProtectPilotedCrafts = false; public static boolean DisableSpillProtection = false; public static boolean DisableIceForm = true; @@ -53,10 +50,6 @@ public class Settings { public static double ManOverboardDistSquared = 1000000; public static int CollisionPrimer = 1000; public static int MaxRemoteSigns = -1; - public static boolean WGCustomFlagsUsePilotFlag = false; - public static boolean WGCustomFlagsUseMoveFlag = false; - public static boolean WGCustomFlagsUseRotateFlag = false; - public static boolean WGCustomFlagsUseSinkFlag = false; public static boolean CraftsUseNetherPortals = false; public static boolean IsPaper = false; diff --git a/modules/api/src/main/java/net/countercraft/movecraft/events/ExplosionEvent.java b/modules/api/src/main/java/net/countercraft/movecraft/events/ExplosionEvent.java new file mode 100644 index 000000000..3edcb0e4f --- /dev/null +++ b/modules/api/src/main/java/net/countercraft/movecraft/events/ExplosionEvent.java @@ -0,0 +1,47 @@ +package net.countercraft.movecraft.events; + +import org.bukkit.Location; +import org.bukkit.event.Cancellable; +import org.bukkit.event.Event; +import org.bukkit.event.HandlerList; + +public class ExplosionEvent extends Event implements Cancellable { + private static final HandlerList HANDLERS = new HandlerList(); + private final Location explosionLocation; + private final float explosionStrength; + private boolean cancelled; + + public ExplosionEvent(Location explosionLocation, float explosionStrength) { + this.explosionLocation = explosionLocation; + this.explosionStrength = explosionStrength; + cancelled = false; + } + + public Location getExplosionLocation() { + return explosionLocation; + } + + public float getExplosionStrength() { + return explosionStrength; + } + + @Override + public HandlerList getHandlers() { + return HANDLERS; + } + + @SuppressWarnings("unused") + public static HandlerList getHandlerList() { + return HANDLERS; + } + + @Override + public boolean isCancelled() { + return cancelled; + } + + @Override + public void setCancelled(boolean cancelled) { + this.cancelled = cancelled; + } +} \ No newline at end of file From bdc3c225eb6ebe9a944984c6634bfc2155b40338 Mon Sep 17 00:00:00 2001 From: TylerS1066 Date: Sun, 21 Mar 2021 10:34:14 -0500 Subject: [PATCH 282/304] Bump version for release --- modules/Movecraft/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/Movecraft/pom.xml b/modules/Movecraft/pom.xml index 51a702767..8e88008bd 100644 --- a/modules/Movecraft/pom.xml +++ b/modules/Movecraft/pom.xml @@ -9,7 +9,7 @@ UTF-8 - 7.0.0_beta_9 + 7.0.0 From 06492f759b4cc808371853bae34c8e2810493f10 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Wed, 31 Mar 2021 23:41:55 +0200 Subject: [PATCH 283/304] Fixes --- modules/Movecraft/dependency-reduced-pom.xml | 27 +----- modules/Movecraft/pom.xml | 2 +- .../net/countercraft/movecraft/Movecraft.java | 18 ++-- .../movecraft/async/AsyncManager.java | 1 + .../movecraft/commands/MovecraftCommand.java | 10 +-- .../movecraft/listener/InteractListener.java | 82 ++++++++----------- .../movecraft/listener/PlayerListener.java | 29 +++++++ .../update/EntityUpdateCommand.java | 16 +++- .../movecraft/utils/UpdateManager.java | 2 +- .../Movecraft/src/main/resources/config.yml | 1 + modules/api/dependency-reduced-pom.xml | 6 -- .../countercraft/movecraft/RegionUtils.java | 8 -- .../movecraft/config/Settings.java | 1 + .../movecraft/craft/CraftType.java | 6 ++ .../movecraft/utils/LegacyUtils.java | 34 -------- .../movecraft/utils/MathUtils.java | 4 - modules/v1_15_R1/pom.xml | 2 +- modules/v1_16_R1/pom.xml | 2 +- modules/v1_16_R2/pom.xml | 2 +- 19 files changed, 107 insertions(+), 146 deletions(-) delete mode 100644 modules/api/src/main/java/net/countercraft/movecraft/RegionUtils.java diff --git a/modules/Movecraft/dependency-reduced-pom.xml b/modules/Movecraft/dependency-reduced-pom.xml index cd3e891d5..a2f730fd3 100644 --- a/modules/Movecraft/dependency-reduced-pom.xml +++ b/modules/Movecraft/dependency-reduced-pom.xml @@ -4,7 +4,7 @@ net.countercraft movecraft Movecraft - 7.0.0_for_1.8.8-1.16.5_beta_37 + 7.0.0_for_1.8.8-1.16.2 http://github.com/apdevteam/Movecraft src/main/java @@ -175,24 +175,6 @@ 1.16.5-R0.1-SNAPSHOT provided - - com.sk89q.worldguard - worldguard-core - 7.0.1-SNAPSHOT - compile - - - com.sk89q.worldguard - worldguard-bukkit - 7.0.1-SNAPSHOT - compile - - - com.sk89q - worldguard - 6.1.1-SNAPSHOT - provided - org.yaml snakeyaml @@ -205,13 +187,6 @@ RELEASE compile - - com.mewin - WGCustomFlags - LATEST - system - ${project.basedir}/../../libs/WGCustomFlags.jar - UTF-8 diff --git a/modules/Movecraft/pom.xml b/modules/Movecraft/pom.xml index 9ba0bc273..14e263f21 100644 --- a/modules/Movecraft/pom.xml +++ b/modules/Movecraft/pom.xml @@ -10,7 +10,7 @@ UTF-8 - 7.0.0_for_1.8.8-1.16.2_beta_37 + 7.0.0_for_1.8.8-1.16.2 diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java index 26eab1768..e258ef898 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java @@ -33,7 +33,6 @@ import org.bukkit.Material; import org.bukkit.configuration.file.FileConfiguration; import org.bukkit.configuration.file.YamlConfiguration; -import org.bukkit.plugin.Plugin; import org.bukkit.plugin.java.JavaPlugin; import java.io.*; @@ -70,11 +69,7 @@ public void onEnable() { String packageName = this.getServer().getClass().getPackage().getName(); String version = packageName.substring(packageName.lastIndexOf('.') + 1); // Read in config - if (!Settings.IsLegacy) { - this.saveDefaultConfig(); - } else { - saveLegacyConfig(); - } + saveDefaultConfig(); try { Class.forName("com.destroystokyo.paper.Title"); Settings.IsPaper = true; @@ -109,6 +104,7 @@ public void onEnable() { Settings.LOCALE = getConfig().getString("Locale"); + I18nSupport.init(); Settings.Debug = getConfig().getBoolean("Debug", false); Settings.DisableSpillProtection = getConfig().getBoolean("DisableSpillProtection", false); Settings.DisableIceForm = getConfig().getBoolean("DisableIceForm", true); @@ -196,7 +192,7 @@ public void onEnable() { for(String s : getConfig().getStringList("ForbiddenRemoteSigns")) { Settings.ForbiddenRemoteSigns.add(s.toLowerCase()); } - + Settings.GearshiftsWithPilotToolEnabled = getConfig().getBoolean("GearshiftsWithPilotToolEnabled", false); if (!Settings.CompatibilityMode) { for (Material typ : Settings.DisableShadowBlocks) { worldHandler.disableShadow(typ); @@ -275,6 +271,14 @@ public void onLoad() { logger = getLogger(); } + public void saveDefaultConfig() { + if (Settings.IsLegacy) { + saveLegacyConfig(); + return; + } + super.saveDefaultConfig(); + } + private void saveLegacyConfig(){ File configFile = new File(getDataFolder(), "config.yml"); if (configFile.exists()) diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java index d9ea9ed04..585e8fe61 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java @@ -731,6 +731,7 @@ private void clear(Craft c) { private void clearAll() { for (Craft c : clearanceSet) { + c.setTranslating(false); c.setProcessing(false); } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/MovecraftCommand.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/MovecraftCommand.java index 8e3bc0ed5..f6fd92230 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/MovecraftCommand.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/MovecraftCommand.java @@ -3,7 +3,6 @@ import net.countercraft.movecraft.Movecraft; import net.countercraft.movecraft.craft.CraftManager; import net.countercraft.movecraft.localisation.I18nSupport; -import org.bukkit.Bukkit; import org.bukkit.command.Command; import org.bukkit.command.CommandSender; import org.bukkit.command.TabExecutor; @@ -37,12 +36,9 @@ public boolean onCommand(CommandSender commandSender, Command command, String s, commandSender.sendMessage(MOVECRAFT_COMMAND_PREFIX + I18nSupport.getInternationalisedString("Movecraft - Reloaded Types")); return true; } - if (args.length == 1 && args[0].equalsIgnoreCase("reloadplugin") && commandSender.hasPermission("movecraft.commands.movecraft.reloadconfig")){ + if (args.length == 1 && args[0].equalsIgnoreCase("reloadconfig") && commandSender.hasPermission("movecraft.commands.movecraft.reloadconfig")){ Movecraft.getInstance().reloadConfig(); - Movecraft.getInstance().getLogger().info("Reloading Movecraft"); - Bukkit.getServer().getPluginManager().disablePlugin(Movecraft.getInstance()); - Bukkit.getServer().getPluginManager().enablePlugin(Movecraft.getInstance()); - commandSender.sendMessage(MOVECRAFT_COMMAND_PREFIX + "Reloaded Movecraft"); + commandSender.sendMessage(MOVECRAFT_COMMAND_PREFIX + "Reloaded config"); return true; } commandSender.sendMessage(MOVECRAFT_COMMAND_PREFIX + I18nSupport.getInternationalisedString("Movecraft - Invalid Argument")); @@ -56,7 +52,7 @@ public List onTabComplete(CommandSender commandSender, Command command, return Collections.emptyList(); List completions = new ArrayList<>(); completions.add("reloadtypes"); - completions.add("reloadplugin"); + completions.add("reloadconfig"); List returnValues = new ArrayList<>(); for(String completion : completions) if(completion.toLowerCase().startsWith(args[args.length-1].toLowerCase())) diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/InteractListener.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/InteractListener.java index 4b9be63e4..a27758459 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/InteractListener.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/InteractListener.java @@ -24,6 +24,7 @@ import net.countercraft.movecraft.localisation.I18nSupport; import net.countercraft.movecraft.utils.LegacyUtils; import net.countercraft.movecraft.utils.MathUtils; +import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; @@ -31,7 +32,6 @@ import org.bukkit.event.block.Action; import org.bukkit.event.player.PlayerInteractEvent; import org.bukkit.material.Button; -import org.bukkit.util.Vector; import java.util.Arrays; import java.util.HashMap; @@ -89,7 +89,7 @@ public void onPlayerInteractStick(PlayerInteractEvent event) { } final CraftType type = craft.getType(); int currentGear = craft.getCurrentGear(); - /*if (player.isSneaking() && !craft.getPilotLocked()) { + if (player.isSneaking() && !craft.getPilotLocked() && Settings.GearshiftsWithPilotToolEnabled) { final int gearShifts = type.getGearShifts(); if (gearShifts == 1) { player.sendMessage(I18nSupport.getInternationalisedString("Gearshift - Disabled for craft type")); @@ -101,12 +101,15 @@ public void onPlayerInteractStick(PlayerInteractEvent event) { player.sendMessage(I18nSupport.getInternationalisedString("Gearshift - Gear changed") + " " + currentGear + " / " + gearShifts); craft.setCurrentGear(currentGear); return; - }*/ + } Long time = timeMap.get(player); int tickCooldown = craft.getType().getTickCooldown(craft.getWorld()); if (type.getGearShiftsAffectDirectMovement() && type.getGearShiftsAffectTickCooldown()) { tickCooldown *= currentGear; } + if (!MathUtils.locationNearHitBox(craft.getHitBox(), event.getPlayer().getLocation(), 2)) { + return; + } if (time != null) { long ticksElapsed = (System.currentTimeMillis() - time) / 50; @@ -121,53 +124,26 @@ public void onPlayerInteractStick(PlayerInteractEvent event) { return; } } - - if (!MathUtils.locationNearHitBox(craft.getHitBox(), event.getPlayer().getLocation(), 2)) { - return; - } - - if (!event.getPlayer().hasPermission("movecraft." + craft.getType().getCraftName() + ".move")) { - event.getPlayer().sendMessage( - I18nSupport.getInternationalisedString("Insufficient Permissions")); - return; - } - if (craft.getPilotLocked()) { - // right click moves up or down if using direct - // control - int DY = 1; - if (event.getPlayer().isSneaking()) - DY = -1; - if (craft.getType().getGearShiftsAffectDirectMovement()) - DY *= currentGear; - craft.translate(0, DY, 0); - timeMap.put(event.getPlayer(), System.currentTimeMillis()); - craft.setLastCruiseUpdate(System.currentTimeMillis()); - return; - } - // Player is onboard craft and right clicking - - final Vector direction = player.getLocation().getDirection(); - float p = event.getPlayer().getLocation().getPitch(); - - direction.setY(-(Math.abs(p) >= 25 ? 1 : 0) * (int) Math.signum(p)); - direction.normalize(); + } + if (!event.getPlayer().hasPermission("movecraft." + craft.getType().getCraftName() + ".move")) { + event.getPlayer().sendMessage( + I18nSupport.getInternationalisedString("Insufficient Permissions")); + return; + } + // Player is onboard craft and right clicking + if (craft.getPilotLocked()) { + // right click moves up or down if using direct + // control + int DY = 1; + if (event.getPlayer().isSneaking()) + DY = -1; if (craft.getType().getGearShiftsAffectDirectMovement()) - direction.multiply(currentGear); - int dx = (int) Math.rint(direction.getX()); - int dz = (int) Math.rint(direction.getZ()); - int dy = (int) Math.rint(direction.getY()); - if (Math.abs(p) >= 75) { - dx = 0; - dz = 0; - } - - craft.translate(dx, dy, dz); + DY *= currentGear; + craft.translate(0, DY, 0); timeMap.put(event.getPlayer(), System.currentTimeMillis()); craft.setLastCruiseUpdate(System.currentTimeMillis()); return; } - // Player is onboard craft and right clicking - float rotation = (float) Math.PI * event.getPlayer().getLocation().getYaw() / 180f; float nx = -(float) Math.sin(rotation); @@ -208,9 +184,21 @@ public void onPlayerInteractStick(PlayerInteractEvent event) { craft.setPilotLocked(false); event.getPlayer().sendMessage( I18nSupport.getInternationalisedString("Direct Control - Leaving")); - event.setCancelled(true); + } else { + craft.setPilotLocked(true); + event.getPlayer().sendMessage( + I18nSupport.getInternationalisedString("Direct Control - Entering")); + if (craft.getType().getLockPilotAtDirectControl()) { + Location pLoc = event.getPlayer().getLocation().clone(); + craft.setPilotLockedX(pLoc.getBlockX() + .5); + craft.setPilotLockedY(pLoc.getBlockY()); + craft.setPilotLockedZ(pLoc.getBlockZ() + .5); + pLoc.setX(craft.getPilotLockedX()); + pLoc.setZ(craft.getPilotLockedZ()); + event.getPlayer().teleport(pLoc); + } } - + event.setCancelled(true); } } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/PlayerListener.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/PlayerListener.java index e493faeb2..aae9b3119 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/PlayerListener.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/PlayerListener.java @@ -35,12 +35,15 @@ import org.bukkit.event.entity.PlayerDeathEvent; import org.bukkit.event.player.PlayerMoveEvent; import org.bukkit.event.player.PlayerQuitEvent; +import org.bukkit.util.Vector; +import java.util.HashMap; import java.util.Map; import java.util.WeakHashMap; public class PlayerListener implements Listener { private final Map timeToReleaseAfter = new WeakHashMap<>(); + private final Map timeMap = new HashMap<>(); private String checkCraftBorders(Craft craft) { String ret = ""; @@ -125,6 +128,32 @@ public void onPlayerMove(PlayerMoveEvent event) { if(MathUtils.locationNearHitBox(c.getHitBox(), p.getLocation(), 2)){ timeToReleaseAfter.remove(c); + if (c.getType().getLockPilotAtDirectControl() && c.getPilotLocked()) { + Vector from = event.getFrom().toVector(); + Vector to = event.getTo().toVector(); + if (to.getX() - from.getX() != 0.0 || to.getZ() - from.getZ() != 0.0) { + event.setCancelled(true); + } + int dx = (int) Math.signum(Math.abs(to.getX() - from.getX()) > .07 ? to.getX() - from.getX() : 0.0); + int dz = (int) Math.signum(Math.abs(to.getZ() - from.getZ()) > .07 ? to.getZ() - from.getZ() : 0.0); + final long time = timeMap.getOrDefault(p, 0L); + long ticksElapsed = (System.currentTimeMillis() - time) / 50; + long tickCooldown = c.getTickCooldown(); + // if the craft should go slower underwater, make time + // pass more slowly there + if (c.getType().getHalfSpeedUnderwater() && c.getHitBox().getMinY() < c.getWorld().getSeaLevel()) + ticksElapsed = ticksElapsed >> 1; + + if (Math.abs(ticksElapsed) < c.getType().getTickCooldown(c.getWorld())) { + + if (Math.abs(ticksElapsed) < tickCooldown) { + return; + } + } + c.setLastCruiseUpdate(System.currentTimeMillis()); + c.translate(dx, 0 , dz); + + } return; } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/EntityUpdateCommand.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/EntityUpdateCommand.java index 2d3898914..14bce4bae 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/EntityUpdateCommand.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/EntityUpdateCommand.java @@ -17,6 +17,8 @@ package net.countercraft.movecraft.mapUpdater.update; +import net.countercraft.movecraft.craft.Craft; +import net.countercraft.movecraft.craft.CraftManager; import net.countercraft.movecraft.utils.TeleportUtils; import org.bukkit.Location; import org.bukkit.Sound; @@ -87,7 +89,7 @@ public void doUpdate() { final Location destLoc = new Location(world, entityLoc.getX() + x, entityLoc.getY() + y, entityLoc.getZ() + z,yaw + entityLoc.getYaw(),pitch + entityLoc.getPitch()); if (!entity.getWorld().equals(world)) { entity.teleport(destLoc); - if (sound != null) { + if (sound != null && (entity instanceof Player)) { ((Player) entity).playSound(entityLoc, sound, volume, 1.0f); } return; @@ -97,8 +99,18 @@ public void doUpdate() { } Location playerLoc = entity.getLocation(); + Player player = (Player) entity; + Craft craft = CraftManager.getInstance().getCraftByPlayer(player); + Location location; + if (craft != null && craft.getNotificationPlayer() == player && craft.getPilotLocked()) { + craft.setPilotLockedX(craft.getPilotLockedX() + x); + craft.setPilotLockedY(craft.getPilotLockedY() + y); + craft.setPilotLockedZ(craft.getPilotLockedZ() + z); + location = new Location(world, craft.getPilotLockedX(), craft.getPilotLockedY(), craft.getPilotLockedZ()); + } else { + location = new Location(world, playerLoc.getX() + x, playerLoc.getY() + y, playerLoc.getZ() + z); + } //Movecraft.getInstance().getWorldHandler().addPlayerLocation((Player) entity,x,y,z,yaw,pitch); - Location location = new Location(world, playerLoc.getX() + x, playerLoc.getY() + y, playerLoc.getZ() + z); TeleportUtils.teleport((Player) entity, location, yaw); } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/UpdateManager.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/UpdateManager.java index 0c7cab6a4..9b7547f41 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/UpdateManager.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/UpdateManager.java @@ -108,7 +108,7 @@ private String getNewVersion() { } String baseVersion = newVersion.split("-")[0]; baseVersion = baseVersion.replace("v", "").replace(".", ""); - int nv = Integer.parseInt(baseVersion) * 100; + int nv = Integer.parseInt(baseVersion) * 10000; nv += betaNo; //Then get the current version String currentVersion = Movecraft.getInstance().getDescription().getVersion(); diff --git a/modules/Movecraft/src/main/resources/config.yml b/modules/Movecraft/src/main/resources/config.yml index 0d81dd9b3..b4761e7cf 100644 --- a/modules/Movecraft/src/main/resources/config.yml +++ b/modules/Movecraft/src/main/resources/config.yml @@ -54,3 +54,4 @@ ForbiddenRemoteSigns: # These strings will be ignored when searching for signs t - "Denied" - "[private]" RequireNamePerm: true # Require movecraft.name.place to place Name: signs and movecraft.name.use to use Name: signs +GearshiftsWithPilotToolEnabled: false \ No newline at end of file diff --git a/modules/api/dependency-reduced-pom.xml b/modules/api/dependency-reduced-pom.xml index 7fe3aa7ec..9e2702c5a 100644 --- a/modules/api/dependency-reduced-pom.xml +++ b/modules/api/dependency-reduced-pom.xml @@ -97,12 +97,6 @@ 1.10.2-R0.1-SNAPSHOT compile - - com.sk89q - worldguard - LATEST - provided - org.jetbrains annotations-java5 diff --git a/modules/api/src/main/java/net/countercraft/movecraft/RegionUtils.java b/modules/api/src/main/java/net/countercraft/movecraft/RegionUtils.java deleted file mode 100644 index bf3935869..000000000 --- a/modules/api/src/main/java/net/countercraft/movecraft/RegionUtils.java +++ /dev/null @@ -1,8 +0,0 @@ -package net.countercraft.movecraft; - -import com.sk89q.worldguard.protection.regions.ProtectedRegion; -import org.bukkit.util.Vector; - -public abstract class RegionUtils { - public abstract Vector getRegionPoint(ProtectedRegion region, boolean minPoint); -} diff --git a/modules/api/src/main/java/net/countercraft/movecraft/config/Settings.java b/modules/api/src/main/java/net/countercraft/movecraft/config/Settings.java index 5db275b5a..0457750f7 100644 --- a/modules/api/src/main/java/net/countercraft/movecraft/config/Settings.java +++ b/modules/api/src/main/java/net/countercraft/movecraft/config/Settings.java @@ -61,4 +61,5 @@ public class Settings { public static boolean UseFAWE = false; public static HashSet DisableShadowBlocks = new HashSet<>(); public static boolean CheckForUpdates; + public static boolean GearshiftsWithPilotToolEnabled; } diff --git a/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java b/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java index 76ccc2fed..7bf9cda85 100644 --- a/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java +++ b/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java @@ -126,6 +126,7 @@ final public class CraftType { private final boolean gearShiftsAffectTickCooldown; private final boolean gearShiftsAffectDirectMovement; private final boolean gearShiftsAffectCruiseSkipBlocks; + private final boolean lockPilotAtDirectControl; @SuppressWarnings("unchecked") public CraftType(File f) { final Map data; @@ -397,6 +398,7 @@ public CraftType(File f) { gearShiftsAffectTickCooldown = (boolean) data.getOrDefault("gearShiftsAffectTickCooldown", true); gearShiftsAffectDirectMovement = (boolean) data.getOrDefault("gearShiftsAffectDirectMovement", false); gearShiftsAffectCruiseSkipBlocks = (boolean) data.getOrDefault("gearShiftsAffectCruiseSkipBlocks", false); + lockPilotAtDirectControl = (boolean) data.getOrDefault("lockPilotAtDirectControl", false); } private int integerFromObject(Object obj) { @@ -1010,6 +1012,10 @@ public boolean getGearShiftsAffectCruiseSkipBlocks() { return gearShiftsAffectCruiseSkipBlocks; } + public boolean getLockPilotAtDirectControl() { + return lockPilotAtDirectControl; + } + public class TypeNotFoundException extends RuntimeException { public TypeNotFoundException(String s) { super(s); diff --git a/modules/api/src/main/java/net/countercraft/movecraft/utils/LegacyUtils.java b/modules/api/src/main/java/net/countercraft/movecraft/utils/LegacyUtils.java index 73cc4f5b3..6423f242f 100644 --- a/modules/api/src/main/java/net/countercraft/movecraft/utils/LegacyUtils.java +++ b/modules/api/src/main/java/net/countercraft/movecraft/utils/LegacyUtils.java @@ -1,19 +1,9 @@ package net.countercraft.movecraft.utils; -import com.sk89q.worldguard.LocalPlayer; -import com.sk89q.worldguard.bukkit.WorldGuardPlugin; -import com.sk89q.worldguard.protection.ApplicableRegionSet; -import com.sk89q.worldguard.protection.flags.Flag; -import com.sk89q.worldguard.protection.flags.StateFlag; -import com.sk89q.worldguard.protection.managers.RegionManager; -import net.countercraft.movecraft.MovecraftLocation; import net.countercraft.movecraft.config.Settings; -import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.Sound; -import org.bukkit.World; import org.bukkit.block.Block; -import org.bukkit.entity.Player; public class LegacyUtils { @@ -133,28 +123,4 @@ private String getColorFromData(byte data){ } return color; } - - public static RegionManager getRegionManager(WorldGuardPlugin worldGuardPlugin, World world){ - return worldGuardPlugin.getRegionManager(world); - } - - public static ApplicableRegionSet getApplicableRegions(RegionManager regionManager, Location location){ - return regionManager.getApplicableRegions(location); - } - - public static boolean canBuild(WorldGuardPlugin worldGuardPlugin, World world, MovecraftLocation location, Player player){ - return worldGuardPlugin.canBuild(player, location.toBukkit(world)); - } - - public static boolean allows(ApplicableRegionSet applicableRegionSet, StateFlag stateFlag){ - return applicableRegionSet.allows(stateFlag); - } - - public static StateFlag.State getFlag(WorldGuardPlugin wgPlugin, Location loc, Object flag, LocalPlayer lp){ - return (StateFlag.State) wgPlugin.getRegionManager(loc.getWorld()).getApplicableRegions(loc).getFlag((Flag) flag, lp); - } - - public static StateFlag.State getFlag(WorldGuardPlugin wgPlugin, Location loc, Object flag){ - return (StateFlag.State) wgPlugin.getRegionManager(loc.getWorld()).getApplicableRegions(loc).getFlag((Flag) flag); - } } diff --git a/modules/api/src/main/java/net/countercraft/movecraft/utils/MathUtils.java b/modules/api/src/main/java/net/countercraft/movecraft/utils/MathUtils.java index 2056b50c2..b60b05ab2 100644 --- a/modules/api/src/main/java/net/countercraft/movecraft/utils/MathUtils.java +++ b/modules/api/src/main/java/net/countercraft/movecraft/utils/MathUtils.java @@ -23,7 +23,6 @@ import org.bukkit.Location; import org.bukkit.World; import org.bukkit.WorldBorder; -import org.bukkit.util.Vector; import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; @@ -31,9 +30,6 @@ public class MathUtils { - public static Vector we6vectorToBukkitVector(com.sk89q.worldedit.Vector weVector){ - return new Vector(weVector.getBlockX(), weVector.getBlockY(), weVector.getBlockZ()); - } /** * checks if location is within the bounding box box restricted by minimum values on x and z * @param box the bounding box to check within diff --git a/modules/v1_15_R1/pom.xml b/modules/v1_15_R1/pom.xml index 970041345..3fe56f5d2 100644 --- a/modules/v1_15_R1/pom.xml +++ b/modules/v1_15_R1/pom.xml @@ -6,7 +6,7 @@ movecraft-parent net.countercraft parent - ../../ + ../../pom.xml 4.0.0 diff --git a/modules/v1_16_R1/pom.xml b/modules/v1_16_R1/pom.xml index 9ad776677..365c93723 100644 --- a/modules/v1_16_R1/pom.xml +++ b/modules/v1_16_R1/pom.xml @@ -6,7 +6,7 @@ movecraft-parent net.countercraft parent - ../../ + ../../pom.xml 4.0.0 diff --git a/modules/v1_16_R2/pom.xml b/modules/v1_16_R2/pom.xml index 14944f7c4..c99017d3f 100644 --- a/modules/v1_16_R2/pom.xml +++ b/modules/v1_16_R2/pom.xml @@ -6,7 +6,7 @@ movecraft-parent net.countercraft parent - ../../ + ../../pom.xml 4.0.0 From b4b490c641b35a4ec05f67ee23f798e8f6bf3012 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Thu, 1 Apr 2021 00:14:18 +0200 Subject: [PATCH 284/304] Fixes --- .../net/countercraft/movecraft/listener/PlayerListener.java | 4 ++++ .../java/net/countercraft/movecraft/utils/UpdateManager.java | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/PlayerListener.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/PlayerListener.java index aae9b3119..b67d1fd05 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/PlayerListener.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/PlayerListener.java @@ -150,6 +150,10 @@ public void onPlayerMove(PlayerMoveEvent event) { return; } } + if (c.getType().getGearShiftsAffectDirectMovement()) { + dx *= c.getCurrentGear(); + dz *= c.getCurrentGear(); + } c.setLastCruiseUpdate(System.currentTimeMillis()); c.translate(dx, 0 , dz); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/UpdateManager.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/UpdateManager.java index 9b7547f41..f33ada7a9 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/UpdateManager.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/UpdateManager.java @@ -108,7 +108,7 @@ private String getNewVersion() { } String baseVersion = newVersion.split("-")[0]; baseVersion = baseVersion.replace("v", "").replace(".", ""); - int nv = Integer.parseInt(baseVersion) * 10000; + int nv = Integer.parseInt(baseVersion) * betaNo > 0 ? 10000 : 1; nv += betaNo; //Then get the current version String currentVersion = Movecraft.getInstance().getDescription().getVersion(); From 811ebc761c98e0d09d1663aa5fb1a6697973ffe0 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Sat, 3 Apr 2021 23:58:04 +0200 Subject: [PATCH 285/304] Fixed malfunctioning cruise and speed signs --- modules/Movecraft/dependency-reduced-pom.xml | 2 +- modules/Movecraft/pom.xml | 2 +- .../java/net/countercraft/movecraft/sign/CruiseSign.java | 5 ++--- .../main/java/net/countercraft/movecraft/sign/SpeedSign.java | 2 +- 4 files changed, 5 insertions(+), 6 deletions(-) diff --git a/modules/Movecraft/dependency-reduced-pom.xml b/modules/Movecraft/dependency-reduced-pom.xml index a2f730fd3..2a7cd6f5d 100644 --- a/modules/Movecraft/dependency-reduced-pom.xml +++ b/modules/Movecraft/dependency-reduced-pom.xml @@ -4,7 +4,7 @@ net.countercraft movecraft Movecraft - 7.0.0_for_1.8.8-1.16.2 + 7.0.0.1_for_1.8.8-1.16.2 http://github.com/apdevteam/Movecraft src/main/java diff --git a/modules/Movecraft/pom.xml b/modules/Movecraft/pom.xml index 14e263f21..ac464d69e 100644 --- a/modules/Movecraft/pom.xml +++ b/modules/Movecraft/pom.xml @@ -10,7 +10,7 @@ UTF-8 - 7.0.0_for_1.8.8-1.16.2 + 7.0.0.1_for_1.8.8-1.16.2 diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CruiseSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CruiseSign.java index 212b5855c..68c86d5e5 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CruiseSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CruiseSign.java @@ -12,7 +12,6 @@ import org.bukkit.ChatColor; import org.bukkit.World; import org.bukkit.block.Block; -import org.bukkit.block.BlockFace; import org.bukkit.block.Sign; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; @@ -52,7 +51,7 @@ public final void onSignClick(PlayerInteractEvent event) { Sign sign = (Sign) event.getClickedBlock().getState(); Craft c = CraftManager.getInstance().getCraftByPlayer(event.getPlayer()); if (ChatColor.stripColor(sign.getLine(0)).equalsIgnoreCase("Cruise: OFF")) { - if (CraftManager.getInstance().getCraftByPlayer(event.getPlayer()) == null) { + if (c == null) { return; } @@ -65,7 +64,7 @@ public final void onSignClick(PlayerInteractEvent event) { sign.update(true); org.bukkit.material.Sign materialSign = (org.bukkit.material.Sign) block.getState().getData(); - if(block.getType().name().endsWith("SIGN") || block.getType() == LegacyUtils.SIGN_POST) + if(!block.getType().name().endsWith("SIGN") && block.getType() != LegacyUtils.SIGN_POST) c.setCruiseDirection(CruiseDirection.NONE); else c.setCruiseDirection(CruiseDirection.fromBlockFace(materialSign.getFacing())); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/SpeedSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/SpeedSign.java index 839cab9a5..3b229e3e5 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/SpeedSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/SpeedSign.java @@ -56,7 +56,7 @@ public void onSideClick(PlayerInteractEvent event) { return; } Block block = event.getClickedBlock(); - if (block == null || block.getType().name().endsWith("SIGN") || block.getType().name().startsWith("SIGN_")) { + if (block == null || !(block.getType().name().endsWith("SIGN") || block.getType().name().startsWith("SIGN_"))) { return; } Sign sign = (Sign) event.getClickedBlock().getState(); From f061850d69b9c240b1f45e1e35f0edf5047ccae1 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Mon, 31 May 2021 10:34:43 +0200 Subject: [PATCH 286/304] Added 1.17 module, in preparation for 1.17 --- .../countercraft/movecraft/craft/ICraft.java | 3 ++- modules/api/dependency-reduced-pom.xml | 6 +++--- modules/v1_17_R1/pom.xml | 18 ++++++++++++++++++ pom.xml | 1 + 4 files changed, 24 insertions(+), 4 deletions(-) create mode 100644 modules/v1_17_R1/pom.xml diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/ICraft.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/ICraft.java index 889a97029..fc64c366a 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/ICraft.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/ICraft.java @@ -7,6 +7,7 @@ import net.countercraft.movecraft.async.rotation.RotationTask; import net.countercraft.movecraft.async.translation.TranslationTask; import net.countercraft.movecraft.localisation.I18nSupport; +import net.countercraft.movecraft.utils.SignUtils; import org.bukkit.ChatColor; import org.bukkit.World; import org.bukkit.block.Block; @@ -113,7 +114,7 @@ public Set getContacts() { public void resetSigns(@NotNull Sign clicked) { for (final MovecraftLocation ml : hitBox) { final Block b = ml.toBukkit(world).getBlock(); - if (!(b.getState() instanceof Sign)) { + if (!SignUtils.isSign(b)) { continue; } final Sign sign = (Sign) b.getState(); diff --git a/modules/api/dependency-reduced-pom.xml b/modules/api/dependency-reduced-pom.xml index 9e2702c5a..08973c63c 100644 --- a/modules/api/dependency-reduced-pom.xml +++ b/modules/api/dependency-reduced-pom.xml @@ -155,10 +155,10 @@ - 1.2.0 - ${junit.jupiter.version} - 5.2.0 UTF-8 4.13.1 + 5.2.0 + ${junit.jupiter.version} + 1.2.0 diff --git a/modules/v1_17_R1/pom.xml b/modules/v1_17_R1/pom.xml new file mode 100644 index 000000000..cec96ddd7 --- /dev/null +++ b/modules/v1_17_R1/pom.xml @@ -0,0 +1,18 @@ + + + + movecraft-parent + net.countercraft + parent + ../../pom.xml + + 4.0.0 + + movecraft-v1_17_R1 + Movecraft-v1_17_R1 + v1_17_R1 + + + \ No newline at end of file diff --git a/pom.xml b/pom.xml index 87e9d6e88..c7d37c10f 100644 --- a/pom.xml +++ b/pom.xml @@ -33,6 +33,7 @@ modules/v1_16_R2 modules/v1_16_R3 modules/Movecraft + modules/v1_17_R1 From 58dbc7c302dfe3de2d268ec9414cd597c72c8048 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Mon, 31 May 2021 16:12:47 +0200 Subject: [PATCH 287/304] Added CraftInfoCommand and CraftTypeCommand --- .../movecraft/commands/CraftInfoCommand.java | 116 +++++++++++++++ .../movecraft/commands/CraftTypeCommand.java | 135 ++++++++++++++++++ .../movecraft/utils/MathUtils.java | 11 ++ 3 files changed, 262 insertions(+) create mode 100644 modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/CraftInfoCommand.java create mode 100644 modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/CraftTypeCommand.java diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/CraftInfoCommand.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/CraftInfoCommand.java new file mode 100644 index 000000000..13e207aec --- /dev/null +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/CraftInfoCommand.java @@ -0,0 +1,116 @@ +package net.countercraft.movecraft.commands; + +import net.countercraft.movecraft.craft.Craft; +import net.countercraft.movecraft.craft.CraftManager; +import net.countercraft.movecraft.utils.MathUtils; +import net.countercraft.movecraft.utils.TopicPaginator; +import org.bukkit.command.Command; +import org.bukkit.command.CommandSender; +import org.bukkit.command.TabExecutor; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; + +import java.util.ArrayList; +import java.util.List; +import java.util.OptionalInt; +import java.util.function.Function; + +public class CraftInfoCommand implements TabExecutor { + private static final List>> providers = new ArrayList<>(); + static { + registerMultiProvider(CraftInfoCommand::allowedBlockProvider); + registerProvider((craft -> "Craft size: " + craft.getHitBox().size())); + registerProvider((craft -> "Craft midpoint: " + craft.getHitBox().getMidPoint())); + registerProvider((craft -> "Craft min x: " + craft.getHitBox().getMinX())); + registerProvider((craft -> "Craft min y: " + craft.getHitBox().getMinY())); + registerProvider((craft -> "Craft min z: " + craft.getHitBox().getMinZ())); + registerProvider((craft -> "Craft max x: " + craft.getHitBox().getMaxX())); + registerProvider((craft -> "Craft max y: " + craft.getHitBox().getMaxY())); + registerProvider((craft -> "Craft max z: " + craft.getHitBox().getMaxZ())); + registerProvider((craft -> "Craft world: " + craft.getWorld().getName())); + registerProvider((craft -> "Craft type: " + craft.getType().getCraftName())); + registerProvider((craft -> "Craft name: " + craft.getName())); + registerProvider((craft -> "Is cruising: " + craft.getCruising())); + registerProvider((craft -> "Cruise direction: " + craft.getCruiseDirection())); + registerProvider((craft -> "Craft speed: " + craft.getSpeed())); + registerProvider((craft -> "Mean cruise time: " + craft.getMeanCruiseTime())); + registerProvider((craft -> "Is disabled: " + craft.getDisabled())); + registerProvider((craft -> "Current gear: " + craft.getCurrentGear())); + } + + private static @NotNull List allowedBlockProvider(@NotNull Craft craft){ + return new ArrayList<>(); + } + + public static void registerMultiProvider(@NotNull Function> provider){ + providers.add(provider); + } + + public static void registerProvider(@NotNull Function< Craft, String> provider){ + providers.add(provider.andThen((String t) -> new ArrayList<>())); + } + + + @Override + public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command, @NotNull String label, @NotNull String[] args) { + if(args.length == 0){ + if (!(sender instanceof Player)){ + sender.sendMessage("Supply a parameter."); + return true; + } + Craft craft = CraftManager.getInstance().getCraftByPlayer(((Player) sender)); + if(craft == null){ + sender.sendMessage("You must be piloting a craft."); + return true; + } + craftInfo(sender, craft, 1); + return true; + } + OptionalInt pageQuery; + if (sender instanceof Player && (pageQuery = MathUtils.parseInt(args[0])).isPresent()){ + Craft craft = CraftManager.getInstance().getCraftByPlayer(((Player) sender)); + if(craft == null){ + sender.sendMessage("You must be piloting a craft."); + return true; + } + craftInfo(sender, craft, pageQuery.getAsInt()); + return true; + } + final Craft craft = CraftManager.getInstance().getCraftByPlayerName(args[0]); + if (craft == null) { + sender.sendMessage("No player found"); + return true; + } + if(args.length > 1){ + pageQuery = MathUtils.parseInt(args[1]); + if(!pageQuery.isPresent()){ + sender.sendMessage("Parameter " + args[1] + " must be a page number."); + return true; + } + } else { + pageQuery = OptionalInt.of(1); + } + craftInfo(sender, craft, pageQuery.getAsInt()); + return true; + } + + public void craftInfo(@NotNull CommandSender commandSender, @NotNull Craft craft, int page){ + TopicPaginator paginator = new TopicPaginator("Craft Info"); + for(Function> provider : providers){ + for(String line : provider.apply(craft)){ + paginator.addLine(line); + } + } + if(!paginator.isInBounds(page)){ + commandSender.sendMessage(String.format("Page %d is out of bounds.", page)); + return; + } + for(String line : paginator.getPage(page)) + commandSender.sendMessage(line); + } + + @Override + public List onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, @NotNull String[] args) { + return null; + } +} diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/CraftTypeCommand.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/CraftTypeCommand.java new file mode 100644 index 000000000..512b13242 --- /dev/null +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/CraftTypeCommand.java @@ -0,0 +1,135 @@ +package net.countercraft.movecraft.commands; + +import net.countercraft.movecraft.craft.Craft; +import net.countercraft.movecraft.craft.CraftManager; +import net.countercraft.movecraft.craft.CraftType; +import net.countercraft.movecraft.utils.MathUtils; +import net.countercraft.movecraft.utils.TopicPaginator; +import org.bukkit.command.Command; +import org.bukkit.command.CommandSender; +import org.bukkit.command.TabExecutor; +import org.bukkit.entity.Player; +import org.bukkit.util.ChatPaginator; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.lang.reflect.Field; +import java.util.*; + +public class CraftTypeCommand implements TabExecutor { + + private static final Field[] craftTypeFields; + static { + craftTypeFields = CraftType.class.getDeclaredFields(); + for(Field field : craftTypeFields){ + field.setAccessible(true); + } + } + + @Override + public boolean onCommand(@NotNull CommandSender commandSender, @NotNull Command command, @NotNull String label, @NotNull String[] args) { + CraftType type; + int page; + if(args.length == 0 || (args.length == 1 && MathUtils.parseInt(args[0]).isPresent())){ + Optional typeQuery = tryGetCraftFromPlayer(commandSender); + if(!typeQuery.isPresent()){ + commandSender.sendMessage("You must supply a craft type!"); + return true; + } + type = typeQuery.get(); + page = args.length == 0 ? 1 : MathUtils.parseInt(args[0]).getAsInt(); + } else { + if(args.length > 1){ + OptionalInt pageQuery = MathUtils.parseInt(args[1]); + if(!pageQuery.isPresent()){ + commandSender.sendMessage("Argument " + args[1] + " must be a page number"); + return true; + } + page = pageQuery.getAsInt(); + } else { + page = 1; + } + if(args[0].equalsIgnoreCase("list")){ + sendTypeListPage(page, commandSender); + return true; + } + type = CraftManager.getInstance().getCraftTypeFromString(args[0]); + } + if(!commandSender.hasPermission("movecraft." + type.getCraftName() + ".pilot")){ + commandSender.sendMessage("You don't have permission for that craft type!"); + return true; + } + sendTypePage(type, page, commandSender); + return true; + } + + @Nullable + @Override + public List onTabComplete(@NotNull CommandSender commandSender, @NotNull Command command, @NotNull String s, @NotNull String[] strings) { + if(strings.length !=1 || !commandSender.hasPermission("movecraft.commands") || !commandSender.hasPermission("movecraft.commands.crafttype")) + return Collections.emptyList(); + List completions = new ArrayList<>(); + for(CraftType type : CraftManager.getInstance().getCraftTypes()) + if(commandSender.hasPermission("movecraft." + type.getCraftName() + ".pilot")) + completions.add(type.getCraftName()); + completions.add("list"); + List returnValues = new ArrayList<>(); + for(String completion : completions) + if(completion.toLowerCase().startsWith(strings[strings.length-1].toLowerCase())) + returnValues.add(completion); + return returnValues; + } + + private void sendTypePage(@NotNull CraftType type, int page, @NotNull CommandSender commandSender){ + TopicPaginator paginator = new TopicPaginator("Type Info"); + for(Field field : craftTypeFields){ + if(field.getName().equals("data")){ // don't include the backing data object + continue; + } + Object value; + try { + value = field.get(type); + } catch (IllegalAccessException e) { + paginator.addLine(field.getName() + ": failed to access"); + continue; + } + String repr = field.getName() + ": " + value; + if(repr.length() > ChatPaginator.GUARANTEED_NO_WRAP_CHAT_PAGE_WIDTH){ + paginator.addLine(field.getName() + ": too long"); + } else { + paginator.addLine(field.getName() + ": " + value); + } + } + if(!paginator.isInBounds(page)){ + commandSender.sendMessage(String.format("Page %d is out of bounds.", page)); + return; + } + for(String line : paginator.getPage(page)) + commandSender.sendMessage(line); + } + + private void sendTypeListPage(int page, @NotNull CommandSender commandSender){ + TopicPaginator paginator = new TopicPaginator("Type Info"); + for(CraftType entry : CraftManager.getInstance().getCraftTypes()){ + paginator.addLine(entry.getCraftName()); + } + if(!paginator.isInBounds(page)){ + commandSender.sendMessage(String.format("Page %d is out of bounds.", page)); + return; + } + for(String line : paginator.getPage(page)) + commandSender.sendMessage(line); + } + + @NotNull + private Optional tryGetCraftFromPlayer(CommandSender commandSender){ + if (!(commandSender instanceof Player)) { + return Optional.empty(); + } + Craft c = CraftManager.getInstance().getCraftByPlayer((Player) commandSender); + if(c == null){ + return Optional.empty(); + } + return Optional.of(c.getType()); + } +} diff --git a/modules/api/src/main/java/net/countercraft/movecraft/utils/MathUtils.java b/modules/api/src/main/java/net/countercraft/movecraft/utils/MathUtils.java index b60b05ab2..5b19c86d0 100644 --- a/modules/api/src/main/java/net/countercraft/movecraft/utils/MathUtils.java +++ b/modules/api/src/main/java/net/countercraft/movecraft/utils/MathUtils.java @@ -26,6 +26,8 @@ import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.NotNull; +import java.util.OptionalInt; + public class MathUtils { @@ -195,4 +197,13 @@ public static boolean withinWorldBorder(@NotNull World world, @NotNull Movecraft location.getZ() >= minZ && location.getZ() <= maxZ; } + + @NotNull + public static OptionalInt parseInt(@NotNull String encoded){ + try { + return OptionalInt.of(Integer.parseInt(encoded)); + }catch(NumberFormatException e){ + return OptionalInt.empty(); + } + } } From 274a8b9b496a926bb77b3e963b45542685b19f51 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Mon, 31 May 2021 16:19:22 +0200 Subject: [PATCH 288/304] Added CraftInfoCommand and CraftTypeCommand --- .../main/java/net/countercraft/movecraft/Movecraft.java | 2 ++ modules/Movecraft/src/main/resources/plugin.yml | 8 +++++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java index e258ef898..0ffdd185e 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java @@ -227,6 +227,8 @@ public void onEnable() { this.getCommand("manoverboard").setExecutor(new ManOverboardCommand()); this.getCommand("contacts").setExecutor(new ContactsCommand()); this.getCommand("scuttle").setExecutor(new ScuttleCommand()); + this.getCommand("crafttype").setExecutor(new CraftTypeCommand()); + this.getCommand("craftinfo").setExecutor(new CraftInfoCommand()); getServer().getPluginManager().registerEvents(new BlockListener(), this); getServer().getPluginManager().registerEvents(new PlayerListener(), this); diff --git a/modules/Movecraft/src/main/resources/plugin.yml b/modules/Movecraft/src/main/resources/plugin.yml index c41fbca49..7ae0a117d 100644 --- a/modules/Movecraft/src/main/resources/plugin.yml +++ b/modules/Movecraft/src/main/resources/plugin.yml @@ -33,4 +33,10 @@ commands: usage: /manoverboard scuttle: description: Sinks piloted craft - usage: /scuttle \ No newline at end of file + usage: /scuttle + crafttype: + description: Get information on a specifc craft type + usage: /crafttype [type] [page] + craftinfo: + description: Get information on a piloted craft + usage: /crafttype [player] [page] \ No newline at end of file From 967aff1cebd6dcf2bda89357d04e08aff16d20ef Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Sat, 12 Jun 2021 15:36:32 +0200 Subject: [PATCH 289/304] Added 1.17 compatibility --- modules/Movecraft/dependency-reduced-pom.xml | 16 +- modules/Movecraft/pom.xml | 22 +- .../movecraft/craft/ChunkManager.java | 2 + .../movecraft/sign/CruiseSign.java | 3 +- .../movecraft/utils/TeleportUtils.java | 82 +++- modules/v1_17_R1/pom.xml | 41 +- .../compat/v1_17_R1/IWorldHandler.java | 464 ++++++++++++++++++ .../compat/v1_17_R1/NextTickProvider.java | 73 +++ pom.xml | 2 +- 9 files changed, 667 insertions(+), 38 deletions(-) create mode 100644 modules/v1_17_R1/src/main/java/net/countercraft/movecraft/compat/v1_17_R1/IWorldHandler.java create mode 100644 modules/v1_17_R1/src/main/java/net/countercraft/movecraft/compat/v1_17_R1/NextTickProvider.java diff --git a/modules/Movecraft/dependency-reduced-pom.xml b/modules/Movecraft/dependency-reduced-pom.xml index 2a7cd6f5d..16bad94ab 100644 --- a/modules/Movecraft/dependency-reduced-pom.xml +++ b/modules/Movecraft/dependency-reduced-pom.xml @@ -4,7 +4,7 @@ net.countercraft movecraft Movecraft - 7.0.0.1_for_1.8.8-1.16.2 + 7.0.0.2_for_1.8.8-1.17 http://github.com/apdevteam/Movecraft src/main/java @@ -45,8 +45,8 @@ maven-compiler-plugin 3.7.0 - 1.8 - 1.8 + 13 + 13 @@ -58,7 +58,7 @@ maven-shade-plugin - 3.2.3 + 3.2.4 package @@ -140,6 +140,12 @@ ** + + net.countercraft:movecraft-v1_17_R1 + + ** + + @@ -172,7 +178,7 @@ org.spigotmc spigot-api - 1.16.5-R0.1-SNAPSHOT + 1.17-R0.1-SNAPSHOT provided diff --git a/modules/Movecraft/pom.xml b/modules/Movecraft/pom.xml index ac464d69e..249cbc109 100644 --- a/modules/Movecraft/pom.xml +++ b/modules/Movecraft/pom.xml @@ -10,7 +10,7 @@ UTF-8 - 7.0.0.1_for_1.8.8-1.16.2 + 7.0.0.2_for_1.8.8-1.17 @@ -32,9 +32,15 @@ org.spigotmc spigot-api - 1.16.5-R0.1-SNAPSHOT + 1.17-R0.1-SNAPSHOT provided + + net.countercraft + movecraft-v1_17_R1 + v1_17_R1 + jar + net.countercraft movecraft-v1_16_R3 @@ -175,8 +181,8 @@ maven-compiler-plugin 3.7.0 - 1.8 - 1.8 + 13 + 13 @@ -190,7 +196,7 @@ org.apache.maven.plugins maven-shade-plugin - 3.2.3 + 3.2.4 package @@ -272,6 +278,12 @@ ** + + net.countercraft:movecraft-v1_17_R1 + + ** + + diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/ChunkManager.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/ChunkManager.java index d0d4a6151..30a6f912a 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/ChunkManager.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/ChunkManager.java @@ -71,9 +71,11 @@ private static void removeChunksToLoad(List list) { Bukkit.getScheduler().callSyncMethod(Movecraft.getInstance(), () -> { for (MovecraftChunk chunk : list) { chunk.toBukkit().setForceLoaded(false); + chunk = null; } return true; }); + } @EventHandler diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CruiseSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CruiseSign.java index 68c86d5e5..bf0c97b13 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CruiseSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CruiseSign.java @@ -63,11 +63,10 @@ public final void onSignClick(PlayerInteractEvent event) { sign.setLine(0, "Cruise: ON"); sign.update(true); - org.bukkit.material.Sign materialSign = (org.bukkit.material.Sign) block.getState().getData(); if(!block.getType().name().endsWith("SIGN") && block.getType() != LegacyUtils.SIGN_POST) c.setCruiseDirection(CruiseDirection.NONE); else - c.setCruiseDirection(CruiseDirection.fromBlockFace(materialSign.getFacing())); + c.setCruiseDirection(CruiseDirection.fromBlockFace(SignUtils.getFacing(sign))); c.setLastCruiseUpdate(System.currentTimeMillis()); c.setCruising(true); diff --git a/modules/api/src/main/java/net/countercraft/movecraft/utils/TeleportUtils.java b/modules/api/src/main/java/net/countercraft/movecraft/utils/TeleportUtils.java index 2af4aff4c..dd8651b7f 100644 --- a/modules/api/src/main/java/net/countercraft/movecraft/utils/TeleportUtils.java +++ b/modules/api/src/main/java/net/countercraft/movecraft/utils/TeleportUtils.java @@ -46,46 +46,52 @@ public class TeleportUtils { private static Field activeContainer; private static Field defaultContainer; + private static Field t; + static { - Class packet = getNmsClass("Packet"); - Class entity = getNmsClass("Entity"); - Class entityPlayer = getNmsClass("EntityPlayer"); - Class entityHuman = getNmsClass("EntityHuman"); - Class connectionClass = getNmsClass("PlayerConnection"); - Class packetClass = getNmsClass("PacketPlayOutPosition"); - Class vehiclePacket = getNmsClass("PacketPlayOutVehicleMove"); - Class vecClass = getNmsClass("Vec3D"); - Class worldClass = getNmsClass("World"); + Class packet = v1_17() ? getNmnClass("protocol.Packet") : getNmsClass("Packet"); + Class entity = v1_17() ? getNmwClass("entity.Entity") : getNmsClass("Entity"); + Class entityPlayer = getNmsClass((v1_17() ? "level." : "") + "EntityPlayer"); + Class entityHuman = v1_17() ? getNmwClass("entity.player.EntityHuman") : getNmsClass("EntityHuman"); + Class connectionClass = getNmsClass((v1_17() ? "network." : "") + "PlayerConnection"); + Class packetClass = v1_17() ? getNmnClass("protocol.game.PacketPlayOutPosition") : getNmsClass("PacketPlayOutPosition"); + Class vehiclePacket = v1_17() ? getNmnClass("protocol.game.PacketPlayOutVehicleMove") : getNmsClass("PacketPlayOutVehicleMove"); + Class vecClass = v1_17() ? getNmwClass("phys.Vec3D") : getNmsClass("Vec3D"); + Class worldClass = v1_17() ? getNmwClass("level.World") : getNmsClass("World"); + try { sendMethod = connectionClass.getMethod("sendPacket", packet); position = entity.getDeclaredMethod("setLocation", Double.TYPE, Double.TYPE, Double.TYPE, Float.TYPE, Float.TYPE); closeInventory = entityPlayer.getDeclaredMethod("closeInventory"); getBukkitEntity = entity.getDeclaredMethod("getBukkitEntity"); - spawnIn = entity.getDeclaredMethod("spawnIn", worldClass); - - yaw = getField(entity, "yaw"); - pitch = getField(entity, "pitch"); - connectionField = getField(entityPlayer, "playerConnection"); - activeContainer = getField(entityHuman, "activeContainer"); - defaultContainer = getField(entityHuman, "defaultContainer"); - - packetConstructor = packetClass.getConstructor(Double.TYPE, Double.TYPE, Double.TYPE, Float.TYPE, Float.TYPE, Set.class, Integer.TYPE); + if (!v1_17()) + spawnIn = entity.getDeclaredMethod("spawnIn", worldClass); + else + t = entity.getDeclaredField("t"); + yaw = getField(entity, v1_17() ? "ay" : "yaw"); + pitch = getField(entity, v1_17() ? "az" : "pitch"); + connectionField = getField(entityPlayer, v1_17() ? "b" : "playerConnection"); + activeContainer = getField(entityHuman, v1_17() ? "bU" : "activeContainer"); + defaultContainer = getField(entityHuman, v1_17() ? "bV" : "defaultContainer"); + + packetConstructor = v1_17() ? packetClass.getConstructor(Double.TYPE, Double.TYPE, Double.TYPE, Float.TYPE, Float.TYPE, Set.class, Integer.TYPE, Boolean.TYPE) + : packetClass.getConstructor(Double.TYPE, Double.TYPE, Double.TYPE, Float.TYPE, Float.TYPE, Set.class, Integer.TYPE); vec3D = vecClass.getConstructor(Double.TYPE, Double.TYPE, Double.TYPE); vehiclePacketConstructor = vehiclePacket.getConstructor(entity); - Object[] enumObjects = getNmsClass("PacketPlayOutPosition$EnumPlayerTeleportFlags").getEnumConstants(); + Object[] enumObjects = v1_17() ? getNmnClass("protocol.game.PacketPlayOutPosition$EnumPlayerTeleportFlags").getEnumConstants() : getNmsClass("PacketPlayOutPosition$EnumPlayerTeleportFlags").getEnumConstants(); teleportFlags = Collections.unmodifiableSet(new HashSet<>(Arrays.asList(enumObjects[4], enumObjects[3]))); justTeleportedField = getField(connectionClass, "justTeleported"); - teleportPosField = getField(connectionClass, "teleportPos"); + teleportPosField = getField(connectionClass, v1_17() ? "y" : "teleportPos"); lastPosXField = getField(connectionClass, "lastPosX"); lastPosYField = getField(connectionClass, "lastPosY"); lastPosZField = getField(connectionClass, "lastPosZ"); - teleportAwaitField = getField(connectionClass, "teleportAwait"); + teleportAwaitField = getField(connectionClass, v1_17() ? "z" : "teleportAwait"); AField = getField(connectionClass, "A"); - eField = getField(connectionClass, "e"); + eField = getField(connectionClass, v1_17() ? "f" : "e"); } catch (Exception e) { e.printStackTrace(); } @@ -140,7 +146,7 @@ public static void teleport(Player player, Location location, float yawChange) { teleportAwaitField.set(connection, teleportAwait); AField.set(connection, eField.get(connection)); - Object packet = packetConstructor.newInstance(x, y, z, yawChange, 0, teleportFlags, teleportAwait); + Object packet = v1_17() ? packetConstructor.newInstance(x, y, z, yawChange, 0, teleportFlags, teleportAwait, true) : packetConstructor.newInstance(x, y, z, yawChange, 0, teleportFlags, teleportAwait); sendPacket(packet, player); if (vehicle == null) return; @@ -184,11 +190,39 @@ private static Object getHandle(Entity entity) { return null; } } + private static boolean v1_17() { + return Integer.parseInt(getVersion().split("_")[1]) >= 17; + } + private static Class getNmsClass(String name) { Class clazz = null; try { - clazz = Class.forName("net.minecraft.server." + getVersion() + "." + name); + clazz = Class.forName("net.minecraft.server." + (v1_17() ? "" : getVersion() + ".") + name); + } catch (ClassNotFoundException var3) { + var3.printStackTrace(); + } + + return clazz; + } + + private static Class getNmnClass(String name) { + Class clazz = null; + + try { + clazz = Class.forName("net.minecraft.network." + name); + } catch (ClassNotFoundException var3) { + var3.printStackTrace(); + } + + return clazz; + } + + private static Class getNmwClass(String name) { + Class clazz = null; + + try { + clazz = Class.forName("net.minecraft.world." + name); } catch (ClassNotFoundException var3) { var3.printStackTrace(); } diff --git a/modules/v1_17_R1/pom.xml b/modules/v1_17_R1/pom.xml index cec96ddd7..f2c159dbf 100644 --- a/modules/v1_17_R1/pom.xml +++ b/modules/v1_17_R1/pom.xml @@ -13,6 +13,45 @@ movecraft-v1_17_R1 Movecraft-v1_17_R1 v1_17_R1 - + + + net.countercraft + movecraft-api + API + jar + + + org.bukkit + craftbukkit + 1.17-R0.1-SNAPSHOT + + + + src/main/java + + + org.apache.maven.plugins + maven-compiler-plugin + 3.7.0 + + + net/countercraft/movecraft/compat/v1_17_R1/** + + 13 + 13 + + + + org.apache.maven.plugins + maven-jar-plugin + 2.4 + + + net/countercraft/movecraft/compat/v1_17_R1/** + + + + + \ No newline at end of file diff --git a/modules/v1_17_R1/src/main/java/net/countercraft/movecraft/compat/v1_17_R1/IWorldHandler.java b/modules/v1_17_R1/src/main/java/net/countercraft/movecraft/compat/v1_17_R1/IWorldHandler.java new file mode 100644 index 000000000..24a7c2884 --- /dev/null +++ b/modules/v1_17_R1/src/main/java/net/countercraft/movecraft/compat/v1_17_R1/IWorldHandler.java @@ -0,0 +1,464 @@ +package net.countercraft.movecraft.compat.v1_17_R1; + +import net.countercraft.movecraft.MovecraftLocation; +import net.countercraft.movecraft.Rotation; +import net.countercraft.movecraft.WorldHandler; +import net.countercraft.movecraft.craft.Craft; +import net.countercraft.movecraft.utils.CollectionUtils; +import net.countercraft.movecraft.utils.MathUtils; +import net.minecraft.core.BaseBlockPosition; +import net.minecraft.core.BlockPosition; +import net.minecraft.server.level.LightEngineThreaded; +import net.minecraft.server.level.WorldServer; +import net.minecraft.server.network.PlayerConnection; +import net.minecraft.world.level.NextTickListEntry; +import net.minecraft.world.level.block.*; +import net.minecraft.world.level.block.entity.TileEntity; +import net.minecraft.world.level.block.state.IBlockData; +import net.minecraft.world.level.chunk.Chunk; +import net.minecraft.world.level.chunk.ChunkSection; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.block.data.BlockData; +import org.bukkit.craftbukkit.v1_17_R1.CraftWorld; +import org.bukkit.craftbukkit.v1_17_R1.block.data.CraftBlockData; +import org.bukkit.craftbukkit.v1_17_R1.util.CraftMagicNumbers; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.*; + +public class IWorldHandler extends WorldHandler { + private static final EnumBlockRotation ROTATION[]; + static { + ROTATION = new EnumBlockRotation[3]; + ROTATION[Rotation.NONE.ordinal()] = EnumBlockRotation.a; + ROTATION[Rotation.CLOCKWISE.ordinal()] = EnumBlockRotation.b; + ROTATION[Rotation.ANTICLOCKWISE.ordinal()] = EnumBlockRotation.d; + + } + private final NextTickProvider tickProvider = new NextTickProvider(); + private final HashMap> bMap = new HashMap<>(); + private MethodHandle internalTeleportMH; + + public IWorldHandler() { + MethodHandles.Lookup lookup = MethodHandles.lookup(); + Method teleport = null; + try { + teleport = PlayerConnection.class.getDeclaredMethod("a", double.class, double.class, double.class, float.class, float.class, Set.class); + teleport.setAccessible(true); + internalTeleportMH = lookup.unreflect(teleport); + + } catch (NoSuchMethodException | IllegalAccessException e) { + e.printStackTrace(); + } + } + + @Override + public void rotateCraft(@NotNull Craft craft, @NotNull MovecraftLocation originPoint, @NotNull Rotation rotation) { + //******************************************* + //* Step one: Convert to Positions * + //******************************************* + HashMap rotatedPositions = new HashMap<>(); + Rotation counterRotation = rotation == Rotation.CLOCKWISE ? Rotation.ANTICLOCKWISE : Rotation.CLOCKWISE; + for(MovecraftLocation newLocation : craft.getHitBox()){ + rotatedPositions.put(locationToPosition(MathUtils.rotateVec(counterRotation, newLocation.subtract(originPoint)).add(originPoint)),locationToPosition(newLocation)); + } + //******************************************* + //* Step two: Get the tiles * + //******************************************* + WorldServer nativeWorld = ((CraftWorld) craft.getWorld()).getHandle(); + List tiles = new ArrayList<>(); + //get the tiles + for(BlockPosition position : rotatedPositions.keySet()){ + //TileEntity tile = nativeWorld.removeTileEntity(position); + TileEntity tile = removeTileEntity(nativeWorld,position); + if(tile == null) + continue; + //tile.a(ROTATION[rotation.ordinal()]); + //get the nextTick to move with the tile + tiles.add(new TileHolder(tile, tickProvider.getNextTick(nativeWorld, position), position)); + } + + //******************************************* + //* Step three: Translate all the blocks * + //******************************************* + // blockedByWater=false means an ocean-going vessel + //TODO: Simplify + //TODO: go by chunks + //TODO: Don't move unnecessary blocks + //get the blocks and rotate them + HashMap blockData = new HashMap<>(); + for(BlockPosition position : rotatedPositions.keySet()){ + + blockData.put(position,nativeWorld.getType(position).a(ROTATION[rotation.ordinal()])); + } + HashMap redstoneComponents = new HashMap<>(); + //create the new block + for(Map.Entry entry : blockData.entrySet()) { + final BlockPosition newPosition = rotatedPositions.get(entry.getKey()); + final IBlockData iBlockData = entry.getValue(); + if (nativeWorld.getTileEntity(newPosition) != null) { + removeTileEntity(nativeWorld, newPosition); + } + if (isRedstoneComponent(iBlockData)) + redstoneComponents.put(newPosition, iBlockData); + + setBlockFast(nativeWorld, newPosition, iBlockData); + } + + + //******************************************* + //* Step four: replace all the tiles * + //******************************************* + //TODO: go by chunks + for(TileHolder tileHolder : tiles){ + moveTileEntity(nativeWorld, rotatedPositions.get(tileHolder.getTilePosition()),tileHolder.getTile()); + if(tileHolder.getNextTick()==null) + continue; + final long currentTime = nativeWorld.E.getTime(); + nativeWorld.getBlockTickList().a(rotatedPositions.get(tileHolder.getNextTick().a), tileHolder.getNextTick().b(), (int) (tileHolder.getNextTick().b - currentTime), tileHolder.getNextTick().c); + } + + //******************************************* + //* Step five: Destroy the leftovers * + //******************************************* + //TODO: add support for pass-through + Collection deletePositions = CollectionUtils.filter(rotatedPositions.keySet(),rotatedPositions.values()); + for(BlockPosition position : deletePositions){ + setBlockFast(nativeWorld, position, Blocks.a.getBlockData()); + } + + //******************************************* + //* Step six: Process fire spread * + //******************************************* + for (BlockPosition position : rotatedPositions.values()) { + IBlockData type = nativeWorld.getType(position); + if (!(type.getBlock() instanceof BlockFire)) { + continue; + } + BlockFire fire = (BlockFire) type.getBlock(); + fire.tick(type, nativeWorld, position, nativeWorld.w); + } + + for (Map.Entry entry : redstoneComponents.entrySet()) { + final BlockPosition position = entry.getKey(); + final IBlockData data = entry.getValue(); + Chunk chunk = nativeWorld.getChunkAtWorldCoords(position); + ChunkSection chunkSection = chunk.getSections()[position.getY()>>4]; + if (chunkSection == null) { + // Put a GLASS block to initialize the section. It will be replaced next with the real block. + chunk.setType(position, Blocks.au.getBlockData(), true); + chunkSection = chunk.getSections()[position.getY() >> 4]; + + } + chunkSection.setType(position.getX()&15, position.getY()&15, position.getZ()&15, data); + nativeWorld.update(position, data.getBlock()); + } + } + + @Override + public void translateCraft(@NotNull Craft craft, @NotNull MovecraftLocation displacement, @NotNull org.bukkit.World world) { + //TODO: Add supourt for rotations + //A craftTranslateCommand should only occur if the craft is moving to a valid position + //******************************************* + //* Step one: Convert to Positions * + //******************************************* + BlockPosition translateVector = locationToPosition(displacement); + List positions = new ArrayList<>(); + for(MovecraftLocation movecraftLocation : craft.getHitBox()) { + positions.add(moveBlockPosition(locationToPosition(movecraftLocation), translateVector, true)); + } + WorldServer oldNativeWorld = ((CraftWorld) craft.getWorld()).getHandle(); + WorldServer nativeWorld = ((CraftWorld) world).getHandle(); + //******************************************* + //* Step two: Get the tiles * + //******************************************* + List tiles = getTiles(positions, oldNativeWorld); + //******************************************* + //* Step three: Translate all the blocks * + //******************************************* + // blockedByWater=false means an ocean-going vessel + //TODO: Simplify + //TODO: go by chunks + //TODO: Don't move unnecessary blocks + //get the blocks and translate the positions + List blockData = new ArrayList<>(); + List newPositions = new ArrayList<>(); + for(BlockPosition position : positions){ + blockData.add(oldNativeWorld.getType(position)); + newPositions.add(moveBlockPosition(position, translateVector, false)); + } + //create the new block + setBlocks(newPositions, blockData, nativeWorld); + //******************************************* + //* Step four: replace all the tiles * + //******************************************* + //TODO: go by chunks + processTiles(tiles, nativeWorld, translateVector); + //******************************************* + //* Step five: Destroy the leftovers * + //******************************************* + Collection deletePositions = oldNativeWorld == nativeWorld ? CollectionUtils.filter(positions,newPositions) : positions; + setAir(deletePositions, oldNativeWorld); + //******************************************* + //* Step six: Process fire spread * + //******************************************* + processFireSpread(newPositions, nativeWorld); + //******************************************* + //* Step six: Process redstone * + //******************************************* + processRedstone(newPositions, nativeWorld); + } + + + private void setBlocks(List newPositions, List blockData, WorldServer nativeWorld){ + Map redstoneComponents = new HashMap<>(); + for(int i = 0; i getTiles(Iterable positions, WorldServer nativeWorld){ + List tiles = new ArrayList<>(); + //get the tiles + for(BlockPosition position : positions){ + if(nativeWorld.getType(position) == Blocks.a.getBlockData()) + continue; + //TileEntity tile = nativeWorld.removeTileEntity(position); + TileEntity tile = removeTileEntity(nativeWorld,position); + if(tile == null) + continue; + //get the nextTick to move with the tile + + //nativeWorld.capturedTileEntities.remove(position); + //nativeWorld.getChunkAtWorldCoords(position).getTileEntities().remove(position); + tiles.add(new TileHolder(tile, tickProvider.getNextTick(nativeWorld, position), position)); + + } + return tiles; + } + + private BlockPosition moveBlockPosition(BlockPosition original, BlockPosition translateVector, boolean opposite) { + if (opposite) + return new BlockPosition(original.getX() - translateVector.getX(), original.getY() - translateVector.getY(), original.getZ() - translateVector.getZ()); + + return new BlockPosition(original.getX() + translateVector.getX(), original.getY() + translateVector.getY(), original.getZ() + translateVector.getZ()); + } + + + private void processTiles(Iterable tiles, WorldServer world, BlockPosition translateVector){ + for(TileHolder tileHolder : tiles){ + BlockPosition newPos = moveBlockPosition(tileHolder.getTilePosition(), translateVector, false); + moveTileEntity(world, newPos,tileHolder.getTile()); + if(tileHolder.getNextTick()==null) + continue; + final long currentTime = world.E.getTime(); + world.getBlockTickList().a(newPos, tileHolder.getNextTick().b(), (int) (tileHolder.getNextTick().b - currentTime), tileHolder.getNextTick().c); + } + } + + private void processFireSpread(Iterable positions, WorldServer world){ + for (BlockPosition position : positions) { + IBlockData type = world.getType(position); + if (!(type.getBlock() instanceof BlockFire)) { + continue; + } + BlockFire fire = (BlockFire) type.getBlock(); + fire.tick(type, world, position, world.w); + } + } + + private void processRedstone(List redstone, WorldServer world) { + Map redstoneComponents = new HashMap<>(); + for (int i = 0 ; i < redstone.size(); i++) { + BlockPosition pos = redstone.get(i); + IBlockData data = world.getType(pos); + if (isRedstoneComponent(data)) + redstoneComponents.put(pos, data); + } + for (Map.Entry entry : redstoneComponents.entrySet()) { + final BlockPosition position = entry.getKey(); + final IBlockData data = entry.getValue(); + Chunk chunk = world.getChunkAtWorldCoords(position); + ChunkSection chunkSection = chunk.getSections()[position.getY()>>4]; + if (chunkSection == null) { + // Put a GLASS block to initialize the section. It will be replaced next with the real block. + chunk.setType(position, Blocks.au.getBlockData(), true); + chunkSection = chunk.getSections()[position.getY() >> 4]; + + } + chunkSection.setType(position.getX()&15, position.getY()&15, position.getZ()&15, data); + //world.notifyAndUpdatePhysics(position, chunk, data, data, data, 3); + world.update(position, data.getBlock()); + } + } + + private void setAir(Iterable positions, WorldServer world){ + for(BlockPosition position : positions){ + setBlockFast(world, position, Blocks.a.getBlockData()); + } + } + + @Nullable + private TileEntity removeTileEntity(@NotNull WorldServer world, @NotNull BlockPosition position){ + TileEntity tile = world.getTileEntity(position); + if(tile == null) + return null; + //cleanup + world.capturedTileEntities.remove(position); + world.getChunkAtWorldCoords(position).getTileEntities().remove(position); + //if(!Settings.IsPaper) + //world.tileEntityList.remove(tile); + //world.tileEntityListTick.remove(tile); +/* + if(!bMap.containsKey(world)){ + try { + Field bField = World.class.getDeclaredField("tileEntityListPending"); + bField.setAccessible(true); + bMap.put(world, (List) bField.get(world));//TODO bug fix + } catch (IllegalAccessException | IllegalArgumentException | NoSuchFieldException | SecurityException e1) { + e1.printStackTrace(); + } + } + bMap.get(world).remove(tile);*/ + return tile; + } + + @NotNull + private BlockPosition locationToPosition(@NotNull MovecraftLocation loc) { + return new BlockPosition(loc.getX(), loc.getY(), loc.getZ()); + } + + private void setBlockFast(@NotNull WorldServer world, @NotNull BlockPosition position,@NotNull IBlockData data) { + Chunk chunk = world.getChunkAtWorldCoords(position); + ChunkSection chunkSection = chunk.getSections()[position.getY()>>4]; + if (chunkSection == null) { + // Put a GLASS block to initialize the section. It will be replaced next with the real block. + chunk.setType(position, Blocks.au.getBlockData(), true); + chunkSection = chunk.getSections()[position.getY() >> 4]; + + } + chunkSection.setType(position.getX() & 15, position.getY() & 15, position.getZ() & 15, data); + world.notify(position, data, data, 3); + world.getChunkProvider().getLightEngine().a(position); + chunk.markDirty(); + } + + @Override + public void setBlockFast(@NotNull Location location, @NotNull Material material, Object data){ + setBlockFast(location, Rotation.NONE, material, data); + } + + @Override + public void setBlockFast(@NotNull Location location, @NotNull Rotation rotation, @NotNull Material material, Object data) { + IBlockData blockData; + if (!(data instanceof BlockData)) { + blockData = CraftMagicNumbers.getBlock(material).getBlockData(); + } else { + blockData = ((CraftBlockData) data).getState(); + } + + blockData = blockData.a(ROTATION[rotation.ordinal()]); + WorldServer world = ((CraftWorld)(location.getWorld())).getHandle(); + BlockPosition blockPosition = locationToPosition(bukkit2MovecraftLoc(location)); + if (world.getTileEntity(blockPosition) != null) { + removeTileEntity(world, blockPosition); + } + setBlockFast(world,blockPosition,blockData); + } + + @Override + public void disableShadow(@NotNull Material type) { + Method method; + //try { + Block tempBlock = CraftMagicNumbers.getBlock(type); + //method = Block.class.getDeclaredMethod("d", int.class); + //method.setAccessible(true); + //method.invoke(tempBlock, 0); + //} catch (NoSuchMethodException | InvocationTargetException | IllegalArgumentException | IllegalAccessException | SecurityException e1) { + // TODO Auto-generated catch block + // e1.printStackTrace(); + //} + } + + private static MovecraftLocation bukkit2MovecraftLoc(Location l) { + return new MovecraftLocation(l.getBlockX(), l.getBlockY(), l.getBlockZ()); + } + + private void recalculateLighting(WorldServer world, Collection positions) { + final LightEngineThreaded engine = world.getChunkProvider().getLightEngine(); + for (BlockPosition pos : positions) { + engine.a(pos); + } + } + + private void moveTileEntity(@NotNull WorldServer nativeWorld, @NotNull BlockPosition newPosition, @NotNull TileEntity tile){ + Chunk chunk = nativeWorld.getChunkAtWorldCoords(newPosition); + //tile.invalidateBlockCache(); + if(nativeWorld.captureBlockStates) { + //tile.setLocation(nativeWorld, newPosition); + nativeWorld.capturedTileEntities.put(newPosition, tile); + return; + } + try { + final Method uMethod = BaseBlockPosition.class.getDeclaredMethod("u", int.class); + final Method tMethod = BaseBlockPosition.class.getDeclaredMethod("t", int.class); + final Method sMethod = BaseBlockPosition.class.getDeclaredMethod("s", int.class); + uMethod.setAccessible(true); + tMethod.setAccessible(true); + sMethod.setAccessible(true); + uMethod.invoke(tile.getPosition(), newPosition.getX()); + tMethod.invoke(tile.getPosition(), newPosition.getY()); + sMethod.invoke(tile.getPosition(), newPosition.getZ()); + } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) { + e.printStackTrace(); + } + chunk.l.put(newPosition, tile); + } + + private class TileHolder{ + @NotNull private final TileEntity tile; + @Nullable + private final NextTickListEntry nextTick; + @NotNull private final BlockPosition tilePosition; + + public TileHolder(@NotNull TileEntity tile, @Nullable NextTickListEntry nextTick, @NotNull BlockPosition tilePosition){ + this.tile = tile; + this.nextTick = nextTick; + this.tilePosition = tilePosition; + } + + + @NotNull + public TileEntity getTile() { + return tile; + } + + @Nullable + public NextTickListEntry getNextTick() { + return nextTick; + } + + @NotNull + public BlockPosition getTilePosition() { + return tilePosition; + } + } + + private boolean isRedstoneComponent(IBlockData blockData) { + final Block block = blockData.getBlock(); + return block instanceof BlockRedstoneWire || + block instanceof BlockDiodeAbstract || + block instanceof BlockButtonAbstract || + block instanceof BlockLever; + + } + + +} + diff --git a/modules/v1_17_R1/src/main/java/net/countercraft/movecraft/compat/v1_17_R1/NextTickProvider.java b/modules/v1_17_R1/src/main/java/net/countercraft/movecraft/compat/v1_17_R1/NextTickProvider.java new file mode 100644 index 000000000..342f58729 --- /dev/null +++ b/modules/v1_17_R1/src/main/java/net/countercraft/movecraft/compat/v1_17_R1/NextTickProvider.java @@ -0,0 +1,73 @@ +package net.countercraft.movecraft.compat.v1_17_R1; + + +import net.minecraft.core.BlockPosition; +import net.minecraft.server.level.WorldServer; +import net.minecraft.world.level.NextTickListEntry; +import net.minecraft.world.level.TickListServer; +import net.minecraft.world.level.block.Block; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.lang.reflect.Field; +import java.util.*; + +public class NextTickProvider { + private Map,Collection>> tickMap = new HashMap<>(); + + private boolean isRegistered(@NotNull WorldServer world){ + return tickMap.containsKey(world); + } + + @SuppressWarnings("unchecked") + private void registerWorld(@NotNull WorldServer world){ + final Collection W = new ArrayList<>(); + final Set nextTickList = new HashSet<>(); + TickListServer blockTickListServer = world.getBlockTickList(); + try { + Field gField = TickListServer.class.getDeclaredField("g"); + gField.setAccessible(true); + W.addAll((Collection) gField.get(blockTickListServer)); + Field ntlField = TickListServer.class.getDeclaredField("e"); + ntlField.setAccessible(true); + nextTickList.addAll((Set) ntlField.get(blockTickListServer)); + } catch (IllegalAccessException | IllegalArgumentException | NoSuchFieldException | SecurityException e1) { + e1.printStackTrace(); + } + tickMap.put(world, new AbstractMap.SimpleImmutableEntry<>(nextTickList,W)); + } + + @Nullable + public NextTickListEntry getNextTick(@NotNull WorldServer world, @NotNull BlockPosition position) { + if (!isRegistered(world)) + registerWorld(world); + AbstractMap.SimpleImmutableEntry, Collection> listPair = tickMap.get(world); + if(listPair.getKey().contains(fakeEntry(position))) { + for (Iterator iterator = listPair.getKey().iterator(); iterator.hasNext(); ) { + NextTickListEntry listEntry = iterator.next(); + if (position.equals(listEntry.a)) { + iterator.remove(); + return listEntry; + } + } + } + for(Iterator iterator = listPair.getValue().iterator(); iterator.hasNext();) { + NextTickListEntry listEntry = iterator.next(); + if (position.equals(listEntry.a)) { + iterator.remove(); + return listEntry; + } + } + return null; + + } + @NotNull + public Object fakeEntry(@NotNull BlockPosition position){ + return new Object(){ + @Override + public int hashCode() { + return position.hashCode(); + } + }; + } +} diff --git a/pom.xml b/pom.xml index c7d37c10f..e4d6c1964 100644 --- a/pom.xml +++ b/pom.xml @@ -32,8 +32,8 @@ modules/v1_16_R1 modules/v1_16_R2 modules/v1_16_R3 - modules/Movecraft modules/v1_17_R1 + modules/Movecraft From c02848ff784fabdd0f621c3d425294eef82e9efa Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Sat, 12 Jun 2021 23:12:02 +0200 Subject: [PATCH 290/304] Added interior blocks and fixed bugs --- .../movecraft/async/AsyncManager.java | 2 +- .../async/detection/DetectionTask.java | 59 +++++++++++++++++++ .../movecraft/listener/BlockListener.java | 6 ++ .../movecraft/sign/CraftSign.java | 11 ++-- .../movecraft/utils/WaterlogUtils.java | 2 + .../movecraft/craft/CraftType.java | 7 +++ 6 files changed, 80 insertions(+), 7 deletions(-) diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java index 585e8fe61..228f8a39d 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java @@ -227,7 +227,7 @@ private void processDetection(DetectionTask task){ for (MovecraftLocation location : entireHitbox) { if (location.getY() <= waterLine) { - c.getPhaseBlocks().put(location.toBukkit(c.getW()), new Pair<>(Material.WATER, (byte) 0)); + c.getPhaseBlocks().put(location.toBukkit(c.getW()), new Pair<>(Material.WATER, Settings.IsLegacy ? (byte) 0 : Bukkit.createBlockData(Material.WATER))); } } } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/detection/DetectionTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/detection/DetectionTask.java index 088ebcd63..b9cc1b1bb 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/detection/DetectionTask.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/detection/DetectionTask.java @@ -18,6 +18,7 @@ package net.countercraft.movecraft.async.detection; +import com.google.common.collect.Lists; import net.countercraft.movecraft.Movecraft; import net.countercraft.movecraft.MovecraftBlock; import net.countercraft.movecraft.MovecraftLocation; @@ -51,6 +52,7 @@ public class DetectionTask extends AsyncTask { @NotNull private final Player notificationPlayer; @NotNull private final BlockContainer allowedBlocks; @NotNull private final BlockContainer forbiddenBlocks; + @NotNull private final BlockContainer interiorBlocks; @NotNull private final String[] forbiddenSignStrings; private int maxX; private int maxY; @@ -74,6 +76,7 @@ public DetectionTask(Craft c, @NotNull MovecraftLocation startLocation, @Nullabl this.allowedBlocks = craft.getType().getAllowedBlocks(); this.forbiddenBlocks = craft.getType().getForbiddenBlocks(); this.forbiddenSignStrings = craft.getType().getForbiddenSignStrings(); + this.interiorBlocks = craft.getType().getInteriorBlocks(); } @Override @@ -85,6 +88,7 @@ public void execute() throws ExecutionException, InterruptedException { do { detectSurrounding(blockStack.pop()); } while (!blockStack.isEmpty()); + detectInterior(); if (failed) { return; } @@ -117,6 +121,57 @@ public void execute() throws ExecutionException, InterruptedException { } } + private void detectInterior() { + //The subtraction of the set of coordinates in the HitBox cube and the HitBox itself + final BitmapHitBox invertedHitBox = new BitmapHitBox(hitBox.boundingHitBox()).difference(hitBox); + + //A set of locations that are confirmed to be "exterior" locations + final BitmapHitBox confirmed = new BitmapHitBox(); + + //place phased blocks + final int minX = hitBox.getMinX(); + final int maxX = hitBox.getMaxX(); + final int minY = hitBox.getMinY(); + final int maxY = hitBox.getMaxY(); + final int minZ = hitBox.getMinZ(); + final int maxZ = hitBox.getMaxZ(); + final HitBox[] surfaces = { + new SolidHitBox(new MovecraftLocation(minX, minY, minZ), new MovecraftLocation(minX, maxY, maxZ)), + new SolidHitBox(new MovecraftLocation(minX, minY, minZ), new MovecraftLocation(maxX, maxY, minZ)), + new SolidHitBox(new MovecraftLocation(maxX, minY, maxZ), new MovecraftLocation(minX, maxY, maxZ)), + new SolidHitBox(new MovecraftLocation(maxX, minY, maxZ), new MovecraftLocation(maxX, maxY, minZ)), + new SolidHitBox(new MovecraftLocation(minX, minY, minZ), new MovecraftLocation(maxX, minY, maxZ))}; + final BitmapHitBox validExterior = new BitmapHitBox(); + for (HitBox hitBox : surfaces) { + validExterior.addAll(new BitmapHitBox(hitBox).difference(this.hitBox)); + } + + //Check to see which locations in the from set are actually outside of the craft + //use a modified BFS for multiple origin elements + BitmapHitBox visited = new BitmapHitBox(); + Queue queue = Lists.newLinkedList(validExterior); + while (!queue.isEmpty()) { + MovecraftLocation node = queue.poll(); + if (visited.contains(node)) + continue; + visited.add(node); + //If the node is already a valid member of the exterior of the HitBox, continued search is unitary. + for (MovecraftLocation neighbor : CollectionUtils.neighbors(invertedHitBox, node)) { + if (neighbor.subtract(node).getY() <= -1) + continue; + queue.add(neighbor); + } + } + confirmed.addAll(visited); + for (MovecraftLocation interiorLoc : invertedHitBox.difference(confirmed)) { + Block block = interiorLoc.toBukkit(world).getBlock(); + if (!isInteriorBlock(block.getType(), block.getData())) { + continue; + } + addToBlockList(interiorLoc); + } + } + private void detectBlock(int x, int y, int z) throws ExecutionException, InterruptedException { MovecraftLocation workingLocation = new MovecraftLocation(x, y, z); @@ -228,6 +283,10 @@ private boolean isForbiddenBlock(Material test, int testData) { return forbiddenBlocks.contains(test) || forbiddenBlocks.contains(test, (byte) testData); } + private boolean isInteriorBlock(Material test, int testData) { + return interiorBlocks.contains(test) || interiorBlocks.contains(test, (byte) testData); + } + private boolean isForbiddenSignString(String testString) { for (String s : forbiddenSignStrings) { diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/BlockListener.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/BlockListener.java index 936ccb206..4e31f9dda 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/BlockListener.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/BlockListener.java @@ -24,6 +24,7 @@ import net.countercraft.movecraft.localisation.I18nSupport; import net.countercraft.movecraft.utils.LegacyUtils; import net.countercraft.movecraft.utils.MathUtils; +import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.Location; import org.bukkit.Material; @@ -194,6 +195,11 @@ public void onFlow(BlockFromToEvent e){ } } + @EventHandler + public void onPlace(BlockPlaceEvent event) { + Bukkit.broadcastMessage(event.getBlock().getType().name()); + } + @Nullable private Craft adjacentCraft(@NotNull Location location) { for (Craft craft : CraftManager.getInstance().getCraftsInWorld(location.getWorld())) { diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CraftSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CraftSign.java index 172672737..eba81836c 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CraftSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CraftSign.java @@ -3,10 +3,10 @@ import net.countercraft.movecraft.CruiseDirection; import net.countercraft.movecraft.Movecraft; import net.countercraft.movecraft.MovecraftLocation; -import net.countercraft.movecraft.craft.Craft; -import net.countercraft.movecraft.craft.CraftType; import net.countercraft.movecraft.config.Settings; +import net.countercraft.movecraft.craft.Craft; import net.countercraft.movecraft.craft.CraftManager; +import net.countercraft.movecraft.craft.CraftType; import net.countercraft.movecraft.craft.ICraft; import net.countercraft.movecraft.events.CraftPilotEvent; import net.countercraft.movecraft.events.CraftReleaseEvent; @@ -19,7 +19,6 @@ import org.bukkit.block.Block; import org.bukkit.block.BlockFace; import org.bukkit.block.Sign; -import org.bukkit.block.data.type.WallSign; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; import org.bukkit.event.block.Action; @@ -70,11 +69,11 @@ public final void onSignClick(PlayerInteractEvent event) { if (c.getType().getCruiseOnPilot()) { c.detect(null, event.getPlayer(), startPoint); - org.bukkit.material.Sign materialSign = (org.bukkit.material.Sign) block.getState().getData(); - if(block.getType().name().endsWith("SIGN") || block.getType() == LegacyUtils.SIGN_POST) + BlockFace face = SignUtils.getFacing(sign); + if(!SignUtils.isWallSign(block) || block.getType() == LegacyUtils.SIGN_POST) c.setCruiseDirection(CruiseDirection.NONE); else - c.setCruiseDirection(CruiseDirection.fromBlockFace(materialSign.getFacing())); + c.setCruiseDirection(CruiseDirection.fromBlockFace(face)); c.setLastCruiseUpdate(System.currentTimeMillis()); c.setCruising(true); new BukkitRunnable() { diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/WaterlogUtils.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/WaterlogUtils.java index b003ea439..be0e2a4c5 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/WaterlogUtils.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/WaterlogUtils.java @@ -24,6 +24,8 @@ public static void waterlogBlocksOnCraft(Craft craft, HitBox interior) { for (MovecraftLocation ml : craft.getHitBox()) { final Pair block = craft.getPhaseBlocks().getOrDefault(ml.toBukkit(craft.getWorld()), DEFAULT_PHASE_BLOCK); final Material phaseBlock = block.getLeft(); + if (block.getRight() instanceof Byte) + Bukkit.broadcastMessage(String.valueOf(block.getRight())); final BlockData phaseBlockData = (BlockData) block.getRight(); boolean waterlog = phaseBlock == Material.WATER && phaseBlockData instanceof Levelled && ((Levelled) phaseBlockData).getLevel() == 0; Block b = ml.toBukkit(craft.getWorld()).getBlock(); diff --git a/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java b/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java index 7bf9cda85..f78c2fc57 100644 --- a/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java +++ b/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java @@ -105,6 +105,7 @@ final public class CraftType { private final float collisionExplosion; @NotNull private final String craftName; @NotNull private final BlockContainer allowedBlocks; + @NotNull private final BlockContainer interiorBlocks; @NotNull private final BlockContainer forbiddenBlocks; @NotNull private final String[] forbiddenSignStrings; @NotNull private final BlockLimitManager flyBlocks; @@ -145,6 +146,7 @@ public CraftType(File f) { maxSize = integerFromObject(data.get("maxSize")); minSize = integerFromObject(data.get("minSize")); allowedBlocks = new BlockContainer(data.get("allowedBlocks")); + interiorBlocks = new BlockContainer(data.getOrDefault("interiorBlocks", new ArrayList<>())); forbiddenBlocks = new BlockContainer(data.get("forbiddenBlocks")); forbiddenSignStrings = stringListFromObject(data.get("forbiddenSignStrings")); tickCooldown = (int) Math.ceil(20 / (doubleFromObject(data.get("speed")))); @@ -1016,6 +1018,11 @@ public boolean getLockPilotAtDirectControl() { return lockPilotAtDirectControl; } + @NotNull + public BlockContainer getInteriorBlocks() { + return interiorBlocks; + } + public class TypeNotFoundException extends RuntimeException { public TypeNotFoundException(String s) { super(s); From 29dafa788ebf0c8e57bfadf0e79674fd5856b842 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Sat, 12 Jun 2021 23:26:27 +0200 Subject: [PATCH 291/304] fix --- .../net/countercraft/movecraft/listener/BlockListener.java | 6 ------ 1 file changed, 6 deletions(-) diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/BlockListener.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/BlockListener.java index 4e31f9dda..936ccb206 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/BlockListener.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/BlockListener.java @@ -24,7 +24,6 @@ import net.countercraft.movecraft.localisation.I18nSupport; import net.countercraft.movecraft.utils.LegacyUtils; import net.countercraft.movecraft.utils.MathUtils; -import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.Location; import org.bukkit.Material; @@ -195,11 +194,6 @@ public void onFlow(BlockFromToEvent e){ } } - @EventHandler - public void onPlace(BlockPlaceEvent event) { - Bukkit.broadcastMessage(event.getBlock().getType().name()); - } - @Nullable private Craft adjacentCraft(@NotNull Location location) { for (Craft craft : CraftManager.getInstance().getCraftsInWorld(location.getWorld())) { From cb9dbb12a2250f14251b0b6b0046e437c3c36bc0 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Sat, 12 Jun 2021 23:29:34 +0200 Subject: [PATCH 292/304] Removed FAWE warning due to WorldEdit no longer being a dependency --- .../java/net/countercraft/movecraft/Movecraft.java | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java index 0ffdd185e..2d14bd81f 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java @@ -87,20 +87,6 @@ public void onEnable() { logger.warning("Download at papermc.io/downloads"); logger.warning("======== Movecraft === Use Paper ======="); } - try { - Class.forName("com.boydti.fawe.Fawe"); - if (!Settings.IsLegacy){ - logger.warning("======= Movecraft === FAWE detected ========"); - logger.warning("FAWE has been detected on the server"); - logger.warning("the 1.13+ version of FAWE has critical"); - logger.warning("bugs that will break the repair system"); - logger.warning("Therefore, use WorldEdit instead or disable"); - logger.warning("repair functionality and assault"); - logger.warning("======= Movecraft === FAWE detected ========"); - } - } catch (ClassNotFoundException e) { - - } Settings.LOCALE = getConfig().getString("Locale"); From 0259044387760ab42f4a6d3a0c1551ca1223a367 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Wed, 23 Jun 2021 01:26:16 +0200 Subject: [PATCH 293/304] fixes --- .../countercraft/movecraft/async/detection/DetectionTask.java | 2 ++ .../java/net/countercraft/movecraft/craft/ChunkManager.java | 2 +- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/detection/DetectionTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/detection/DetectionTask.java index b9cc1b1bb..1d0990f35 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/detection/DetectionTask.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/detection/DetectionTask.java @@ -122,6 +122,8 @@ public void execute() throws ExecutionException, InterruptedException { } private void detectInterior() { + if (hitBox.isEmpty()) + return; //The subtraction of the set of coordinates in the HitBox cube and the HitBox itself final BitmapHitBox invertedHitBox = new BitmapHitBox(hitBox.boundingHitBox()).difference(hitBox); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/ChunkManager.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/ChunkManager.java index 30a6f912a..2a5303421 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/ChunkManager.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/ChunkManager.java @@ -75,7 +75,7 @@ private static void removeChunksToLoad(List list) { } return true; }); - + System.gc(); } @EventHandler From 6bb7bfa895fd7a26999fdc3c51da0a237869edd2 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Wed, 23 Jun 2021 14:51:30 +0200 Subject: [PATCH 294/304] Update README.md --- README.md | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/README.md b/README.md index ebebe29a5..de7b15d4f 100644 --- a/README.md +++ b/README.md @@ -34,6 +34,27 @@ mvn clean install ``` Jars are located in `/target`. +## For developers + +### Maven + +```xml + + + jitpack.io + https://jitpack.io + + +``` + +```xml + + com.github.eirikh1996 + Movecraft + v7.0.0.2-for-1.8.8-1.17 + +``` + ## Support [Github Issues](https://github.com/eirikh1996/Movecraft/issues) From b4ea785d2368152efc3d2b1c5c0e3e54d86cef3f Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Tue, 29 Jun 2021 23:50:53 +0200 Subject: [PATCH 295/304] Fixed NPE in 1.17 World handler and fixed max height to fit the new 1.17 changes --- modules/api/dependency-reduced-pom.xml | 4 ---- modules/api/pom.xml | 4 ---- .../net/countercraft/movecraft/craft/CraftType.java | 9 +++++---- modules/v1_10_R1/pom.xml | 13 +------------ modules/v1_11_R1/pom.xml | 13 +------------ modules/v1_12_R1/pom.xml | 6 ------ modules/v1_13_R2/pom.xml | 2 +- modules/v1_14_R1/pom.xml | 2 +- .../movecraft/compat/v1_17_R1/IWorldHandler.java | 8 ++++++-- modules/v1_8_R3/pom.xml | 2 +- modules/v1_9_R2/pom.xml | 2 +- 11 files changed, 17 insertions(+), 48 deletions(-) diff --git a/modules/api/dependency-reduced-pom.xml b/modules/api/dependency-reduced-pom.xml index 08973c63c..27dba7fea 100644 --- a/modules/api/dependency-reduced-pom.xml +++ b/modules/api/dependency-reduced-pom.xml @@ -85,10 +85,6 @@ spigot-repo https://hub.spigotmc.org/nexus/content/groups/public/ - - sk89q-repo - http://maven.sk89q.com/repo/ - diff --git a/modules/api/pom.xml b/modules/api/pom.xml index bbeab6111..c446bf8ba 100644 --- a/modules/api/pom.xml +++ b/modules/api/pom.xml @@ -28,10 +28,6 @@ spigot-repo https://hub.spigotmc.org/nexus/content/groups/public/ - - sk89q-repo - http://maven.sk89q.com/repo/ - diff --git a/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java b/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java index f78c2fc57..97ec93e10 100644 --- a/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java +++ b/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java @@ -20,6 +20,7 @@ import net.countercraft.movecraft.config.Settings; import net.countercraft.movecraft.utils.BlockContainer; import net.countercraft.movecraft.utils.BlockLimitManager; +import org.bukkit.Bukkit; import org.bukkit.Material; import org.bukkit.Sound; import org.bukkit.World; @@ -226,18 +227,18 @@ public CraftType(File f) { } }); - int value = Math.min(integerFromObject(data.getOrDefault("maxHeightLimit", 254)), 255); + int value = Math.min(integerFromObject(data.getOrDefault("maxHeightLimit", 254)), Bukkit.getWorlds().get(0).getMaxHeight()); if (value <= minHeightLimit) { - value = 255; + value = Bukkit.getWorlds().get(0).getMaxHeight(); } maxHeightLimit = value; perWorldMaxHeightLimit = new HashMap<>(); Map maxHeightMap = stringToIntMapFromObject(data.getOrDefault("perWorldMaxHeightLimit", new HashMap<>())); maxHeightMap.forEach((world, height) -> { - int worldValue = Math.min(height, 255); + int worldValue = Math.min(height, Bukkit.getWorlds().get(0).getMaxHeight()); int worldMinHeight = perWorldMinHeightLimit.getOrDefault(world, minHeightLimit); - if (worldValue <= worldMinHeight) worldValue = 255; + if (worldValue <= worldMinHeight) worldValue = Bukkit.getWorlds().get(0).getMaxHeight(); perWorldMaxHeightLimit.put(world, worldValue); }); diff --git a/modules/v1_10_R1/pom.xml b/modules/v1_10_R1/pom.xml index 5093f7826..a9f1d88c4 100644 --- a/modules/v1_10_R1/pom.xml +++ b/modules/v1_10_R1/pom.xml @@ -10,25 +10,14 @@ UTF-8 - - - sk89q-repo - http://maven.sk89q.com/repo/ - - net.countercraft movecraft-parent parent - ../../ + ../../pom.xml - - com.sk89q - worldguard - 6.1.1-SNAPSHOT - org.bukkit craftbukkit diff --git a/modules/v1_11_R1/pom.xml b/modules/v1_11_R1/pom.xml index 7bba80fb0..e0f1042db 100644 --- a/modules/v1_11_R1/pom.xml +++ b/modules/v1_11_R1/pom.xml @@ -15,20 +15,9 @@ net.countercraft movecraft-parent parent - ../../ + ../../pom.xml - - - sk89q-repo - http://maven.sk89q.com/repo/ - - - - com.sk89q - worldguard - 6.1.1-SNAPSHOT - org.bukkit craftbukkit diff --git a/modules/v1_12_R1/pom.xml b/modules/v1_12_R1/pom.xml index a08b55f40..09d343898 100644 --- a/modules/v1_12_R1/pom.xml +++ b/modules/v1_12_R1/pom.xml @@ -17,12 +17,6 @@ parent ../../pom.xml - - - sk89q-repo - http://maven.sk89q.com/repo/ - - net.countercraft diff --git a/modules/v1_13_R2/pom.xml b/modules/v1_13_R2/pom.xml index 3d0367264..cfbc5565d 100644 --- a/modules/v1_13_R2/pom.xml +++ b/modules/v1_13_R2/pom.xml @@ -17,7 +17,7 @@ net.countercraft movecraft-parent parent - ../../ + ../../pom.xml diff --git a/modules/v1_14_R1/pom.xml b/modules/v1_14_R1/pom.xml index 9582428b7..6b19693b7 100644 --- a/modules/v1_14_R1/pom.xml +++ b/modules/v1_14_R1/pom.xml @@ -17,7 +17,7 @@ movecraft-parent net.countercraft parent - ../../ + ../../pom.xml diff --git a/modules/v1_17_R1/src/main/java/net/countercraft/movecraft/compat/v1_17_R1/IWorldHandler.java b/modules/v1_17_R1/src/main/java/net/countercraft/movecraft/compat/v1_17_R1/IWorldHandler.java index 24a7c2884..e8c844534 100644 --- a/modules/v1_17_R1/src/main/java/net/countercraft/movecraft/compat/v1_17_R1/IWorldHandler.java +++ b/modules/v1_17_R1/src/main/java/net/countercraft/movecraft/compat/v1_17_R1/IWorldHandler.java @@ -292,7 +292,9 @@ private void processRedstone(List redstone, WorldServer world) { chunkSection = chunk.getSections()[position.getY() >> 4]; } - chunkSection.setType(position.getX()&15, position.getY()&15, position.getZ()&15, data); + chunk.setType(position, data, true); + if (chunkSection != null) + chunkSection.setType(position.getX()&15, position.getY()&15, position.getZ()&15, data); //world.notifyAndUpdatePhysics(position, chunk, data, data, data, 3); world.update(position, data.getBlock()); } @@ -343,7 +345,9 @@ private void setBlockFast(@NotNull WorldServer world, @NotNull BlockPosition pos chunkSection = chunk.getSections()[position.getY() >> 4]; } - chunkSection.setType(position.getX() & 15, position.getY() & 15, position.getZ() & 15, data); + chunk.setType(position, data, true); + if (chunkSection != null) + chunkSection.setType(position.getX() & 15, position.getY() & 15, position.getZ() & 15, data); world.notify(position, data, data, 3); world.getChunkProvider().getLightEngine().a(position); chunk.markDirty(); diff --git a/modules/v1_8_R3/pom.xml b/modules/v1_8_R3/pom.xml index 7a0959e0c..fb839eb69 100644 --- a/modules/v1_8_R3/pom.xml +++ b/modules/v1_8_R3/pom.xml @@ -6,7 +6,7 @@ movecraft-parent net.countercraft parent - ../../ + ../../pom.xml 4.0.0 diff --git a/modules/v1_9_R2/pom.xml b/modules/v1_9_R2/pom.xml index c3e517e9f..fc929a2e3 100644 --- a/modules/v1_9_R2/pom.xml +++ b/modules/v1_9_R2/pom.xml @@ -6,7 +6,7 @@ movecraft-parent net.countercraft parent - ../../ + ../../pom.xml 4.0.0 From 93bcf1311d42edfdb18ee923147971fa71bba4b5 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Sat, 3 Jul 2021 21:54:19 +0200 Subject: [PATCH 296/304] Fixed world height stuff --- .../async/translation/TranslationTask.java | 4 +- .../movecraft/craft/ChunkManager.java | 1 - .../update/EntityUpdateCommand.java | 7 +- .../Movecraft/src/main/resources/plugin.yml | 4 + modules/api/dependency-reduced-pom.xml | 4 +- modules/api/pom.xml | 4 +- .../movecraft/craft/CraftType.java | 67 +++- modules/v1_17_R1/pom.xml | 39 +- .../compat/v1_17_R1/IWorldHandler.java | 364 ++++++++---------- .../compat/v1_17_R1/NextTickProvider.java | 73 +--- 10 files changed, 289 insertions(+), 278 deletions(-) diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java index f47b9b767..eb024dd9d 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java @@ -239,10 +239,10 @@ protected void execute() throws InterruptedException, ExecutionException { } } //Fail the movement if the craft is too high - if (dy>0 && maxY + dy > craft.getType().getMaxHeightLimit()) { + if (dy>0 && maxY + dy > craft.getType().getMaxHeightLimit(world)) { fail(I18nSupport.getInternationalisedString("Translation - Failed Craft hit height limit")); return; - } else if (minY + dy < craft.getType().getMinHeightLimit() && dy < 0 && !craft.getSinking()) { + } else if (minY + dy < craft.getType().getMinHeightLimit(world) && dy < 0 && !craft.getSinking()) { fail(I18nSupport.getInternationalisedString("Translation - Failed Craft hit minimum height limit")); return; } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/ChunkManager.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/ChunkManager.java index 2a5303421..18849f682 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/ChunkManager.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/craft/ChunkManager.java @@ -75,7 +75,6 @@ private static void removeChunksToLoad(List list) { } return true; }); - System.gc(); } @EventHandler diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/EntityUpdateCommand.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/EntityUpdateCommand.java index 31cef8a3c..0f727eab4 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/EntityUpdateCommand.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/EntityUpdateCommand.java @@ -156,10 +156,13 @@ public void doUpdate() { craft.setPilotLockedX(craft.getPilotLockedX() + x); craft.setPilotLockedY(craft.getPilotLockedY() + y); craft.setPilotLockedZ(craft.getPilotLockedZ() + z); + + } + if (craft != null && craft.getType().getLockPilotAtDirectControl()) location = new Location(world, craft.getPilotLockedX(), craft.getPilotLockedY(), craft.getPilotLockedZ()); - } else { + else location = new Location(world, playerLoc.getX() + x, playerLoc.getY() + y, playerLoc.getZ() + z); - } + //Movecraft.getInstance().getWorldHandler().addPlayerLocation((Player) entity,x,y,z,yaw,pitch); TeleportUtils.teleport((Player) entity, location, yaw); } diff --git a/modules/Movecraft/src/main/resources/plugin.yml b/modules/Movecraft/src/main/resources/plugin.yml index 7ae0a117d..ad7dfcb11 100644 --- a/modules/Movecraft/src/main/resources/plugin.yml +++ b/modules/Movecraft/src/main/resources/plugin.yml @@ -6,6 +6,10 @@ authors: [BaccaYarro, cccm5, TylerS1066, eirik1996] website: https://github.com/APDevTeam/Movecraft main: net.countercraft.movecraft.Movecraft database: false +softdepend: + - Multiverse-Core + - Multiverse + - Multiworld commands: movecraft: description: base movecraft command diff --git a/modules/api/dependency-reduced-pom.xml b/modules/api/dependency-reduced-pom.xml index 27dba7fea..97031bd7d 100644 --- a/modules/api/dependency-reduced-pom.xml +++ b/modules/api/dependency-reduced-pom.xml @@ -22,8 +22,8 @@ net/countercraft/movecraft/** - 1.8 - 1.8 + 9 + 9 diff --git a/modules/api/pom.xml b/modules/api/pom.xml index c446bf8ba..ebf3098aa 100644 --- a/modules/api/pom.xml +++ b/modules/api/pom.xml @@ -84,8 +84,8 @@ net/countercraft/movecraft/** - 1.8 - 1.8 + 9 + 9 diff --git a/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java b/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java index 97ec93e10..8efe4bb3f 100644 --- a/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java +++ b/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java @@ -227,18 +227,20 @@ public CraftType(File f) { } }); - int value = Math.min(integerFromObject(data.getOrDefault("maxHeightLimit", 254)), Bukkit.getWorlds().get(0).getMaxHeight()); + final int defaultMaxHeight = Bukkit.getWorlds().get(0).getMaxHeight() - 1; + int value = Math.min(integerFromObject(data.getOrDefault("maxHeightLimit", defaultMaxHeight)), defaultMaxHeight); if (value <= minHeightLimit) { - value = Bukkit.getWorlds().get(0).getMaxHeight(); + value = defaultMaxHeight; } maxHeightLimit = value; perWorldMaxHeightLimit = new HashMap<>(); Map maxHeightMap = stringToIntMapFromObject(data.getOrDefault("perWorldMaxHeightLimit", new HashMap<>())); maxHeightMap.forEach((world, height) -> { - int worldValue = Math.min(height, Bukkit.getWorlds().get(0).getMaxHeight()); + final World foundWorld = Bukkit.getWorld(world); + int worldValue = Math.min(height, foundWorld != null ? foundWorld.getMaxHeight() : 255); int worldMinHeight = perWorldMinHeightLimit.getOrDefault(world, minHeightLimit); - if (worldValue <= worldMinHeight) worldValue = Bukkit.getWorlds().get(0).getMaxHeight(); + if (worldValue <= worldMinHeight) worldValue = defaultMaxHeight; perWorldMaxHeightLimit.put(world, worldValue); }); @@ -665,7 +667,10 @@ public boolean getCanCruise() { return canCruise; } - @Deprecated + @Deprecated( + since = "7.0.0 beta 5", + forRemoval = true + ) public int getCruiseSkipBlocks() { return cruiseSkipBlocks; } @@ -673,7 +678,10 @@ public int getCruiseSkipBlocks(@NotNull World world) { return perWorldCruiseSkipBlocks.getOrDefault(world.getName(), cruiseSkipBlocks); } - @Deprecated + @Deprecated( + since = "7.0.0 beta 5", + forRemoval = true + ) public int getVertCruiseSkipBlocks() { return vertCruiseSkipBlocks; } @@ -730,7 +738,10 @@ public boolean allowRemoteSign() { return allowRemoteSign; } - @Deprecated + @Deprecated( + since = "7.0.0 beta 5", + forRemoval = true + ) public double getFuelBurnRate() { return fuelBurnRate; } @@ -746,7 +757,10 @@ public double getOverallSinkPercent() { return overallSinkPercent; } - @Deprecated + @Deprecated( + since = "7.0.0 beta 5", + forRemoval = true + ) public double getDetectionMultiplier() { return detectionMultiplier; } @@ -754,7 +768,10 @@ public double getDetectionMultiplier(@NotNull World world) { return perWorldDetectionMultiplier.getOrDefault(world.getName(), detectionMultiplier); } - @Deprecated + @Deprecated( + since = "7.0.0 beta 5", + forRemoval = true + ) public double getUnderwaterDetectionMultiplier() { return underwaterDetectionMultiplier; } @@ -782,7 +799,10 @@ public float getCollisionExplosion() { return collisionExplosion; } - @Deprecated + @Deprecated( + since = "7.0.0 beta 5", + forRemoval = true + ) public int getTickCooldown() { return tickCooldown; } @@ -790,7 +810,10 @@ public int getTickCooldown(@NotNull World world) { return perWorldTickCooldown.getOrDefault(world.getName(), tickCooldown); } - @Deprecated + @Deprecated( + since = "7.0.0 beta 5", + forRemoval = true + ) public int getCruiseTickCooldown() { return cruiseTickCooldown; } @@ -799,7 +822,10 @@ public int getCruiseTickCooldown(@NotNull World world) { return perWorldCruiseTickCooldown.getOrDefault(world.getName(), cruiseTickCooldown); } - @Deprecated + @Deprecated( + since = "7.0.0 beta 5", + forRemoval = true + ) public int getVertCruiseTickCooldown() { return vertCruiseTickCooldown; } @@ -834,15 +860,21 @@ public BlockLimitManager getMoveBlocks() { return moveBlocks; } - @Deprecated + @Deprecated( + since = "7.0.0 beta 5", + forRemoval = true + ) public int getMaxHeightLimit() { return maxHeightLimit; } public int getMaxHeightLimit(@NotNull World world) { - return perWorldMaxHeightLimit.getOrDefault(world.getName(), maxHeightLimit); + return perWorldMaxHeightLimit.getOrDefault(world.getName(), Math.min(maxHeightLimit, world.getMaxHeight() - 1)); } - @Deprecated + @Deprecated( + since = "7.0.0 beta 5", + forRemoval = true + ) public int getMinHeightLimit() { return minHeightLimit; } @@ -850,7 +882,10 @@ public int getMinHeightLimit(@NotNull World world) { return perWorldMinHeightLimit.getOrDefault(world.getName(), minHeightLimit); } - @Deprecated + @Deprecated( + since = "7.0.0 beta 5", + forRemoval = true + ) public int getMaxHeightAboveGround() { return maxHeightAboveGround; } diff --git a/modules/v1_17_R1/pom.xml b/modules/v1_17_R1/pom.xml index f2c159dbf..9a90113ec 100644 --- a/modules/v1_17_R1/pom.xml +++ b/modules/v1_17_R1/pom.xml @@ -21,9 +21,11 @@ jar - org.bukkit - craftbukkit + org.spigotmc + spigot 1.17-R0.1-SNAPSHOT + remapped-mojang + provided @@ -51,6 +53,39 @@ + + net.md-5 + specialsource-maven-plugin + 1.2.2 + + + package + + remap + + remap-obf + + org.spigotmc:minecraft-server:1.17-R0.1-SNAPSHOT:txt:maps-mojang + true + org.spigotmc:spigot:1.17-R0.1-SNAPSHOT:jar:remapped-mojang + true + remapped-obf + + + + package + + remap + + remap-spigot + + ${project.build.directory}/${project.artifactId}-${project.version}-remapped-obf.jar + org.spigotmc:minecraft-server:1.17-R0.1-SNAPSHOT:csrg:maps-spigot + org.spigotmc:spigot:1.17-R0.1-SNAPSHOT:jar:remapped-obf + + + + diff --git a/modules/v1_17_R1/src/main/java/net/countercraft/movecraft/compat/v1_17_R1/IWorldHandler.java b/modules/v1_17_R1/src/main/java/net/countercraft/movecraft/compat/v1_17_R1/IWorldHandler.java index e8c844534..e823e0fcb 100644 --- a/modules/v1_17_R1/src/main/java/net/countercraft/movecraft/compat/v1_17_R1/IWorldHandler.java +++ b/modules/v1_17_R1/src/main/java/net/countercraft/movecraft/compat/v1_17_R1/IWorldHandler.java @@ -6,17 +6,14 @@ import net.countercraft.movecraft.craft.Craft; import net.countercraft.movecraft.utils.CollectionUtils; import net.countercraft.movecraft.utils.MathUtils; -import net.minecraft.core.BaseBlockPosition; -import net.minecraft.core.BlockPosition; -import net.minecraft.server.level.LightEngineThreaded; -import net.minecraft.server.level.WorldServer; -import net.minecraft.server.network.PlayerConnection; -import net.minecraft.world.level.NextTickListEntry; +import net.minecraft.core.BlockPos; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.TickNextTickData; import net.minecraft.world.level.block.*; -import net.minecraft.world.level.block.entity.TileEntity; -import net.minecraft.world.level.block.state.IBlockData; -import net.minecraft.world.level.chunk.Chunk; -import net.minecraft.world.level.chunk.ChunkSection; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.chunk.LevelChunkSection; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.block.data.BlockData; @@ -25,37 +22,38 @@ import org.bukkit.craftbukkit.v1_17_R1.util.CraftMagicNumbers; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import sun.misc.Unsafe; import java.lang.invoke.MethodHandle; -import java.lang.invoke.MethodHandles; -import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.*; public class IWorldHandler extends WorldHandler { - private static final EnumBlockRotation ROTATION[]; + private static final net.minecraft.world.level.block.Rotation ROTATION[]; + @Nullable private static final Unsafe unsafe; static { - ROTATION = new EnumBlockRotation[3]; - ROTATION[Rotation.NONE.ordinal()] = EnumBlockRotation.a; - ROTATION[Rotation.CLOCKWISE.ordinal()] = EnumBlockRotation.b; - ROTATION[Rotation.ANTICLOCKWISE.ordinal()] = EnumBlockRotation.d; + Unsafe deferred; + try { + Field theUnsafeField = Unsafe.class.getDeclaredField("theUnsafe"); + theUnsafeField.setAccessible(true); + deferred = (Unsafe) theUnsafeField.get(null); + } catch (NoSuchFieldException | IllegalAccessException e) { + deferred = null; + e.printStackTrace(); + } + unsafe = deferred; + + ROTATION = new net.minecraft.world.level.block.Rotation[3]; + ROTATION[Rotation.NONE.ordinal()] = net.minecraft.world.level.block.Rotation.NONE; + ROTATION[Rotation.CLOCKWISE.ordinal()] = net.minecraft.world.level.block.Rotation.CLOCKWISE_90; + ROTATION[Rotation.ANTICLOCKWISE.ordinal()] = net.minecraft.world.level.block.Rotation.COUNTERCLOCKWISE_90; } private final NextTickProvider tickProvider = new NextTickProvider(); - private final HashMap> bMap = new HashMap<>(); private MethodHandle internalTeleportMH; public IWorldHandler() { - MethodHandles.Lookup lookup = MethodHandles.lookup(); - Method teleport = null; - try { - teleport = PlayerConnection.class.getDeclaredMethod("a", double.class, double.class, double.class, float.class, float.class, Set.class); - teleport.setAccessible(true); - internalTeleportMH = lookup.unreflect(teleport); - - } catch (NoSuchMethodException | IllegalAccessException e) { - e.printStackTrace(); - } } @Override @@ -63,7 +61,7 @@ public void rotateCraft(@NotNull Craft craft, @NotNull MovecraftLocation originP //******************************************* //* Step one: Convert to Positions * //******************************************* - HashMap rotatedPositions = new HashMap<>(); + HashMap rotatedPositions = new HashMap<>(); Rotation counterRotation = rotation == Rotation.CLOCKWISE ? Rotation.ANTICLOCKWISE : Rotation.CLOCKWISE; for(MovecraftLocation newLocation : craft.getHitBox()){ rotatedPositions.put(locationToPosition(MathUtils.rotateVec(counterRotation, newLocation.subtract(originPoint)).add(originPoint)),locationToPosition(newLocation)); @@ -71,12 +69,12 @@ public void rotateCraft(@NotNull Craft craft, @NotNull MovecraftLocation originP //******************************************* //* Step two: Get the tiles * //******************************************* - WorldServer nativeWorld = ((CraftWorld) craft.getWorld()).getHandle(); + ServerLevel nativeWorld = ((CraftWorld) craft.getWorld()).getHandle(); List tiles = new ArrayList<>(); //get the tiles - for(BlockPosition position : rotatedPositions.keySet()){ - //TileEntity tile = nativeWorld.removeTileEntity(position); - TileEntity tile = removeTileEntity(nativeWorld,position); + for(BlockPos position : rotatedPositions.keySet()){ + //BlockEntity tile = nativeWorld.removeBlockEntity(position); + BlockEntity tile = removeBlockEntity(nativeWorld,position); if(tile == null) continue; //tile.a(ROTATION[rotation.ordinal()]); @@ -92,18 +90,18 @@ public void rotateCraft(@NotNull Craft craft, @NotNull MovecraftLocation originP //TODO: go by chunks //TODO: Don't move unnecessary blocks //get the blocks and rotate them - HashMap blockData = new HashMap<>(); - for(BlockPosition position : rotatedPositions.keySet()){ + HashMap blockData = new HashMap<>(); + for(BlockPos position : rotatedPositions.keySet()){ - blockData.put(position,nativeWorld.getType(position).a(ROTATION[rotation.ordinal()])); + blockData.put(position,nativeWorld.getBlockState(position).rotate(ROTATION[rotation.ordinal()])); } - HashMap redstoneComponents = new HashMap<>(); + HashMap redstoneComponents = new HashMap<>(); //create the new block - for(Map.Entry entry : blockData.entrySet()) { - final BlockPosition newPosition = rotatedPositions.get(entry.getKey()); - final IBlockData iBlockData = entry.getValue(); - if (nativeWorld.getTileEntity(newPosition) != null) { - removeTileEntity(nativeWorld, newPosition); + for(Map.Entry entry : blockData.entrySet()) { + final BlockPos newPosition = rotatedPositions.get(entry.getKey()); + final BlockState iBlockData = entry.getValue(); + if (nativeWorld.getBlockEntity(newPosition) != null) { + removeBlockEntity(nativeWorld, newPosition); } if (isRedstoneComponent(iBlockData)) redstoneComponents.put(newPosition, iBlockData); @@ -117,47 +115,52 @@ public void rotateCraft(@NotNull Craft craft, @NotNull MovecraftLocation originP //******************************************* //TODO: go by chunks for(TileHolder tileHolder : tiles){ - moveTileEntity(nativeWorld, rotatedPositions.get(tileHolder.getTilePosition()),tileHolder.getTile()); + moveBlockEntity(nativeWorld, rotatedPositions.get(tileHolder.getTilePosition()),tileHolder.getTile()); if(tileHolder.getNextTick()==null) continue; - final long currentTime = nativeWorld.E.getTime(); - nativeWorld.getBlockTickList().a(rotatedPositions.get(tileHolder.getNextTick().a), tileHolder.getNextTick().b(), (int) (tileHolder.getNextTick().b - currentTime), tileHolder.getNextTick().c); + final long currentTime = nativeWorld.E.getGameTime(); + nativeWorld.getBlockTickList().scheduleTick(rotatedPositions.get(tileHolder.getNextTick().pos), (Block) tileHolder.getNextTick().getType(), (int) (tileHolder.getNextTick().triggerTick - currentTime), tileHolder.getNextTick().priority); } //******************************************* //* Step five: Destroy the leftovers * //******************************************* //TODO: add support for pass-through - Collection deletePositions = CollectionUtils.filter(rotatedPositions.keySet(),rotatedPositions.values()); - for(BlockPosition position : deletePositions){ - setBlockFast(nativeWorld, position, Blocks.a.getBlockData()); + Collection deletePositions = CollectionUtils.filter(rotatedPositions.keySet(),rotatedPositions.values()); + for(BlockPos position : deletePositions){ + setBlockFast(nativeWorld, position, Blocks.AIR.defaultBlockState()); } //******************************************* //* Step six: Process fire spread * //******************************************* - for (BlockPosition position : rotatedPositions.values()) { - IBlockData type = nativeWorld.getType(position); - if (!(type.getBlock() instanceof BlockFire)) { + for (BlockPos position : rotatedPositions.values()) { + BlockState type = nativeWorld.getBlockState(position); + if (!(type.getBlock() instanceof FireBlock)) { continue; } - BlockFire fire = (BlockFire) type.getBlock(); - fire.tick(type, nativeWorld, position, nativeWorld.w); + FireBlock fire = (FireBlock) type.getBlock(); + fire.tick(type, nativeWorld, position, nativeWorld.random); } - for (Map.Entry entry : redstoneComponents.entrySet()) { - final BlockPosition position = entry.getKey(); - final IBlockData data = entry.getValue(); - Chunk chunk = nativeWorld.getChunkAtWorldCoords(position); - ChunkSection chunkSection = chunk.getSections()[position.getY()>>4]; + for (Map.Entry entry : redstoneComponents.entrySet()) { + final BlockPos position = entry.getKey(); + final BlockState data = entry.getValue(); + LevelChunk chunk = nativeWorld.getChunkAt(position); + LevelChunkSection chunkSection = chunk.getSections()[position.getY()>>4]; if (chunkSection == null) { // Put a GLASS block to initialize the section. It will be replaced next with the real block. - chunk.setType(position, Blocks.au.getBlockData(), true); - chunkSection = chunk.getSections()[position.getY() >> 4]; + chunk.setBlockState(position, Blocks.GLASS.defaultBlockState(), false); + chunkSection = chunk.getSections()[chunk.getSectionIndex(position.getY())]; } - chunkSection.setType(position.getX()&15, position.getY()&15, position.getZ()&15, data); - nativeWorld.update(position, data.getBlock()); + if (chunkSection.getBlockState(position.getX()&15, position.getY()&15, position.getZ()&15).equals(data)) { + return; + } + chunkSection.setBlockState(position.getX()&15, position.getY()&15, position.getZ()&15, data); + nativeWorld.sendBlockUpdated(position, data, data, 3); + nativeWorld.getLightEngine().checkBlock(position); // boolean corresponds to if chunk section empty + chunk.markUnsaved(); } } @@ -168,13 +171,13 @@ public void translateCraft(@NotNull Craft craft, @NotNull MovecraftLocation disp //******************************************* //* Step one: Convert to Positions * //******************************************* - BlockPosition translateVector = locationToPosition(displacement); - List positions = new ArrayList<>(); + BlockPos translateVector = locationToPosition(displacement); + List positions = new ArrayList<>(); for(MovecraftLocation movecraftLocation : craft.getHitBox()) { - positions.add(moveBlockPosition(locationToPosition(movecraftLocation), translateVector, true)); + positions.add(moveBlockPos(locationToPosition(movecraftLocation), translateVector, true)); } - WorldServer oldNativeWorld = ((CraftWorld) craft.getWorld()).getHandle(); - WorldServer nativeWorld = ((CraftWorld) world).getHandle(); + ServerLevel oldNativeWorld = ((CraftWorld) craft.getWorld()).getHandle(); + ServerLevel nativeWorld = ((CraftWorld) world).getHandle(); //******************************************* //* Step two: Get the tiles * //******************************************* @@ -187,11 +190,11 @@ public void translateCraft(@NotNull Craft craft, @NotNull MovecraftLocation disp //TODO: go by chunks //TODO: Don't move unnecessary blocks //get the blocks and translate the positions - List blockData = new ArrayList<>(); - List newPositions = new ArrayList<>(); - for(BlockPosition position : positions){ - blockData.add(oldNativeWorld.getType(position)); - newPositions.add(moveBlockPosition(position, translateVector, false)); + List blockData = new ArrayList<>(); + List newPositions = new ArrayList<>(); + for(BlockPos position : positions){ + blockData.add(oldNativeWorld.getBlockState(position)); + newPositions.add(moveBlockPos(position, translateVector, false)); } //create the new block setBlocks(newPositions, blockData, nativeWorld); @@ -203,7 +206,7 @@ public void translateCraft(@NotNull Craft craft, @NotNull MovecraftLocation disp //******************************************* //* Step five: Destroy the leftovers * //******************************************* - Collection deletePositions = oldNativeWorld == nativeWorld ? CollectionUtils.filter(positions,newPositions) : positions; + Collection deletePositions = oldNativeWorld == nativeWorld ? CollectionUtils.filter(positions,newPositions) : positions; setAir(deletePositions, oldNativeWorld); //******************************************* //* Step six: Process fire spread * @@ -216,21 +219,21 @@ public void translateCraft(@NotNull Craft craft, @NotNull MovecraftLocation disp } - private void setBlocks(List newPositions, List blockData, WorldServer nativeWorld){ - Map redstoneComponents = new HashMap<>(); + private void setBlocks(List newPositions, List blockData, ServerLevel nativeWorld){ + Map redstoneComponents = new HashMap<>(); for(int i = 0; i getTiles(Iterable positions, WorldServer nativeWorld){ + private List getTiles(Iterable positions, ServerLevel nativeWorld){ List tiles = new ArrayList<>(); //get the tiles - for(BlockPosition position : positions){ - if(nativeWorld.getType(position) == Blocks.a.getBlockData()) + for(BlockPos position : positions){ + if(nativeWorld.getBlockState(position) == Blocks.AIR.defaultBlockState()) continue; - //TileEntity tile = nativeWorld.removeTileEntity(position); - TileEntity tile = removeTileEntity(nativeWorld,position); + //BlockEntity tile = nativeWorld.removeBlockEntity(position); + BlockEntity tile = removeBlockEntity(nativeWorld,position); if(tile == null) continue; //get the nextTick to move with the tile @@ -243,114 +246,98 @@ private List getTiles(Iterable positions, WorldServer return tiles; } - private BlockPosition moveBlockPosition(BlockPosition original, BlockPosition translateVector, boolean opposite) { + private BlockPos moveBlockPos(BlockPos original, BlockPos translateVector, boolean opposite) { if (opposite) - return new BlockPosition(original.getX() - translateVector.getX(), original.getY() - translateVector.getY(), original.getZ() - translateVector.getZ()); + return new BlockPos(original.getX() - translateVector.getX(), original.getY() - translateVector.getY(), original.getZ() - translateVector.getZ()); - return new BlockPosition(original.getX() + translateVector.getX(), original.getY() + translateVector.getY(), original.getZ() + translateVector.getZ()); + return new BlockPos(original.getX() + translateVector.getX(), original.getY() + translateVector.getY(), original.getZ() + translateVector.getZ()); } - private void processTiles(Iterable tiles, WorldServer world, BlockPosition translateVector){ + private void processTiles(Iterable tiles, ServerLevel world, BlockPos translateVector){ for(TileHolder tileHolder : tiles){ - BlockPosition newPos = moveBlockPosition(tileHolder.getTilePosition(), translateVector, false); - moveTileEntity(world, newPos,tileHolder.getTile()); + BlockPos newPos = moveBlockPos(tileHolder.getTilePosition(), translateVector, false); + moveBlockEntity(world, newPos,tileHolder.getTile()); if(tileHolder.getNextTick()==null) continue; - final long currentTime = world.E.getTime(); - world.getBlockTickList().a(newPos, tileHolder.getNextTick().b(), (int) (tileHolder.getNextTick().b - currentTime), tileHolder.getNextTick().c); + final long currentTime = world.E.getGameTime(); + world.getBlockTickList().scheduleTick(newPos, (Block) tileHolder.getNextTick().getType(), (int) (tileHolder.getNextTick().triggerTick - currentTime), tileHolder.getNextTick().priority); } } - private void processFireSpread(Iterable positions, WorldServer world){ - for (BlockPosition position : positions) { - IBlockData type = world.getType(position); - if (!(type.getBlock() instanceof BlockFire)) { + private void processFireSpread(Iterable positions, ServerLevel world){ + for (BlockPos position : positions) { + BlockState type = world.getBlockState(position); + if (!(type.getBlock() instanceof FireBlock)) { continue; } - BlockFire fire = (BlockFire) type.getBlock(); - fire.tick(type, world, position, world.w); + FireBlock fire = (FireBlock) type.getBlock(); + fire.tick(type, world, position, world.random); } } - private void processRedstone(List redstone, WorldServer world) { - Map redstoneComponents = new HashMap<>(); + private void processRedstone(List redstone, ServerLevel world) { + Map redstoneComponents = new HashMap<>(); for (int i = 0 ; i < redstone.size(); i++) { - BlockPosition pos = redstone.get(i); - IBlockData data = world.getType(pos); + BlockPos pos = redstone.get(i); + BlockState data = world.getBlockState(pos); if (isRedstoneComponent(data)) redstoneComponents.put(pos, data); } - for (Map.Entry entry : redstoneComponents.entrySet()) { - final BlockPosition position = entry.getKey(); - final IBlockData data = entry.getValue(); - Chunk chunk = world.getChunkAtWorldCoords(position); - ChunkSection chunkSection = chunk.getSections()[position.getY()>>4]; + for (Map.Entry entry : redstoneComponents.entrySet()) { + final BlockPos position = entry.getKey(); + final BlockState data = entry.getValue(); + LevelChunk chunk = world.getChunkAt(position); + LevelChunkSection chunkSection = chunk.getSections()[position.getY()>>4]; if (chunkSection == null) { // Put a GLASS block to initialize the section. It will be replaced next with the real block. - chunk.setType(position, Blocks.au.getBlockData(), true); - chunkSection = chunk.getSections()[position.getY() >> 4]; + chunk.setBlockState(position, Blocks.GLASS.defaultBlockState(), false); + chunkSection = chunk.getSections()[chunk.getSectionIndex(position.getY())]; } - chunk.setType(position, data, true); - if (chunkSection != null) - chunkSection.setType(position.getX()&15, position.getY()&15, position.getZ()&15, data); - //world.notifyAndUpdatePhysics(position, chunk, data, data, data, 3); - world.update(position, data.getBlock()); + if (chunkSection.getBlockState(position.getX()&15, position.getY()&15, position.getZ()&15).equals(data)) { + return; + } + chunkSection.setBlockState(position.getX()&15, position.getY()&15, position.getZ()&15, data); + world.sendBlockUpdated(position, data, data, 3); + world.getLightEngine().checkBlock(position); // boolean corresponds to if chunk section empty + chunk.markUnsaved(); } } - private void setAir(Iterable positions, WorldServer world){ - for(BlockPosition position : positions){ - setBlockFast(world, position, Blocks.a.getBlockData()); + private void setAir(Iterable positions, ServerLevel world){ + for(BlockPos position : positions){ + setBlockFast(world, position, Blocks.AIR.defaultBlockState()); } } @Nullable - private TileEntity removeTileEntity(@NotNull WorldServer world, @NotNull BlockPosition position){ - TileEntity tile = world.getTileEntity(position); - if(tile == null) - return null; - //cleanup - world.capturedTileEntities.remove(position); - world.getChunkAtWorldCoords(position).getTileEntities().remove(position); - //if(!Settings.IsPaper) - //world.tileEntityList.remove(tile); - //world.tileEntityListTick.remove(tile); -/* - if(!bMap.containsKey(world)){ - try { - Field bField = World.class.getDeclaredField("tileEntityListPending"); - bField.setAccessible(true); - bMap.put(world, (List) bField.get(world));//TODO bug fix - } catch (IllegalAccessException | IllegalArgumentException | NoSuchFieldException | SecurityException e1) { - e1.printStackTrace(); - } - } - bMap.get(world).remove(tile);*/ - return tile; + private BlockEntity removeBlockEntity(@NotNull ServerLevel world, @NotNull BlockPos position){ + return world.getChunkAt(position).blockEntities.remove(position); } @NotNull - private BlockPosition locationToPosition(@NotNull MovecraftLocation loc) { - return new BlockPosition(loc.getX(), loc.getY(), loc.getZ()); + private BlockPos locationToPosition(@NotNull MovecraftLocation loc) { + return new BlockPos(loc.getX(), loc.getY(), loc.getZ()); } - private void setBlockFast(@NotNull WorldServer world, @NotNull BlockPosition position,@NotNull IBlockData data) { - Chunk chunk = world.getChunkAtWorldCoords(position); - ChunkSection chunkSection = chunk.getSections()[position.getY()>>4]; + private void setBlockFast(@NotNull ServerLevel world, @NotNull BlockPos position,@NotNull BlockState data) { + LevelChunk chunk = world.getChunkAt(position); + LevelChunkSection chunkSection = chunk.getSections()[chunk.getSectionIndex(position.getY())]; + if (chunkSection == null) { // Put a GLASS block to initialize the section. It will be replaced next with the real block. - chunk.setType(position, Blocks.au.getBlockData(), true); - chunkSection = chunk.getSections()[position.getY() >> 4]; + chunk.setBlockState(position, Blocks.GLASS.defaultBlockState(), false); + chunkSection = chunk.getSections()[chunk.getSectionIndex(position.getY())]; } - chunk.setType(position, data, true); - if (chunkSection != null) - chunkSection.setType(position.getX() & 15, position.getY() & 15, position.getZ() & 15, data); - world.notify(position, data, data, 3); - world.getChunkProvider().getLightEngine().a(position); - chunk.markDirty(); + if (chunkSection.getBlockState(position.getX()&15, position.getY()&15, position.getZ()&15).equals(data) && data != Blocks.GLASS.defaultBlockState()) { + return; + } + chunkSection.setBlockState(position.getX()&15, position.getY()&15, position.getZ()&15, data); + world.sendBlockUpdated(position, data, data, 3); + world.getLightEngine().checkBlock(position); // boolean corresponds to if chunk section empty + chunk.markUnsaved(); } @Override @@ -360,18 +347,18 @@ public void setBlockFast(@NotNull Location location, @NotNull Material material, @Override public void setBlockFast(@NotNull Location location, @NotNull Rotation rotation, @NotNull Material material, Object data) { - IBlockData blockData; + BlockState blockData; if (!(data instanceof BlockData)) { - blockData = CraftMagicNumbers.getBlock(material).getBlockData(); + blockData = CraftMagicNumbers.getBlock(material).defaultBlockState(); } else { blockData = ((CraftBlockData) data).getState(); } - blockData = blockData.a(ROTATION[rotation.ordinal()]); - WorldServer world = ((CraftWorld)(location.getWorld())).getHandle(); - BlockPosition blockPosition = locationToPosition(bukkit2MovecraftLoc(location)); - if (world.getTileEntity(blockPosition) != null) { - removeTileEntity(world, blockPosition); + blockData = blockData.rotate(ROTATION[rotation.ordinal()]); + ServerLevel world = ((CraftWorld)(location.getWorld())).getHandle(); + BlockPos blockPosition = locationToPosition(bukkit2MovecraftLoc(location)); + if (world.getBlockEntity(blockPosition) != null) { + removeBlockEntity(world, blockPosition); } setBlockFast(world,blockPosition,blockData); } @@ -394,44 +381,29 @@ private static MovecraftLocation bukkit2MovecraftLoc(Location l) { return new MovecraftLocation(l.getBlockX(), l.getBlockY(), l.getBlockZ()); } - private void recalculateLighting(WorldServer world, Collection positions) { - final LightEngineThreaded engine = world.getChunkProvider().getLightEngine(); - for (BlockPosition pos : positions) { - engine.a(pos); - } - } - - private void moveTileEntity(@NotNull WorldServer nativeWorld, @NotNull BlockPosition newPosition, @NotNull TileEntity tile){ - Chunk chunk = nativeWorld.getChunkAtWorldCoords(newPosition); - //tile.invalidateBlockCache(); - if(nativeWorld.captureBlockStates) { - //tile.setLocation(nativeWorld, newPosition); - nativeWorld.capturedTileEntities.put(newPosition, tile); - return; - } + private void moveBlockEntity(@NotNull ServerLevel nativeWorld, @NotNull BlockPos newPosition, @NotNull BlockEntity tile){ + LevelChunk chunk = nativeWorld.getChunkAt(newPosition); try { - final Method uMethod = BaseBlockPosition.class.getDeclaredMethod("u", int.class); - final Method tMethod = BaseBlockPosition.class.getDeclaredMethod("t", int.class); - final Method sMethod = BaseBlockPosition.class.getDeclaredMethod("s", int.class); - uMethod.setAccessible(true); - tMethod.setAccessible(true); - sMethod.setAccessible(true); - uMethod.invoke(tile.getPosition(), newPosition.getX()); - tMethod.invoke(tile.getPosition(), newPosition.getY()); - sMethod.invoke(tile.getPosition(), newPosition.getZ()); - } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) { + var positionField = BlockEntity.class.getDeclaredField("o"); + setField(positionField, tile, newPosition); + } catch (NoSuchFieldException e) { e.printStackTrace(); } - chunk.l.put(newPosition, tile); + tile.setLevel(nativeWorld); + tile.clearRemoved(); + if (nativeWorld.captureBlockStates) + nativeWorld.capturedTileEntities.put(newPosition, tile); + chunk.setBlockEntity(tile); + chunk.blockEntities.put(newPosition, tile); } private class TileHolder{ - @NotNull private final TileEntity tile; + @NotNull private final BlockEntity tile; @Nullable - private final NextTickListEntry nextTick; - @NotNull private final BlockPosition tilePosition; + private final TickNextTickData nextTick; + @NotNull private final BlockPos tilePosition; - public TileHolder(@NotNull TileEntity tile, @Nullable NextTickListEntry nextTick, @NotNull BlockPosition tilePosition){ + public TileHolder(@NotNull BlockEntity tile, @Nullable TickNextTickData nextTick, @NotNull BlockPos tilePosition){ this.tile = tile; this.nextTick = nextTick; this.tilePosition = tilePosition; @@ -439,30 +411,36 @@ public TileHolder(@NotNull TileEntity tile, @Nullable NextTickListEntry n @NotNull - public TileEntity getTile() { + public BlockEntity getTile() { return tile; } @Nullable - public NextTickListEntry getNextTick() { + public TickNextTickData getNextTick() { return nextTick; } @NotNull - public BlockPosition getTilePosition() { + public BlockPos getTilePosition() { return tilePosition; } } - private boolean isRedstoneComponent(IBlockData blockData) { + private boolean isRedstoneComponent(BlockState blockData) { final Block block = blockData.getBlock(); - return block instanceof BlockRedstoneWire || - block instanceof BlockDiodeAbstract || - block instanceof BlockButtonAbstract || - block instanceof BlockLever; + return block instanceof RedStoneWireBlock || + block instanceof ComparatorBlock || + block instanceof ButtonBlock || + block instanceof LeverBlock; } + private void setField(Field field, Object holder, Object value) { + if (unsafe == null) + return; + unsafe.putObject(holder, unsafe.objectFieldOffset(field), value); + } + } diff --git a/modules/v1_17_R1/src/main/java/net/countercraft/movecraft/compat/v1_17_R1/NextTickProvider.java b/modules/v1_17_R1/src/main/java/net/countercraft/movecraft/compat/v1_17_R1/NextTickProvider.java index 342f58729..b66318834 100644 --- a/modules/v1_17_R1/src/main/java/net/countercraft/movecraft/compat/v1_17_R1/NextTickProvider.java +++ b/modules/v1_17_R1/src/main/java/net/countercraft/movecraft/compat/v1_17_R1/NextTickProvider.java @@ -1,73 +1,30 @@ package net.countercraft.movecraft.compat.v1_17_R1; -import net.minecraft.core.BlockPosition; -import net.minecraft.server.level.WorldServer; -import net.minecraft.world.level.NextTickListEntry; -import net.minecraft.world.level.TickListServer; +import net.minecraft.core.BlockPos; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.ServerTickList; +import net.minecraft.world.level.TickNextTickData; import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.levelgen.structure.BoundingBox; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.lang.reflect.Field; -import java.util.*; +import java.util.List; +import java.util.logging.Logger; public class NextTickProvider { - private Map,Collection>> tickMap = new HashMap<>(); - - private boolean isRegistered(@NotNull WorldServer world){ - return tickMap.containsKey(world); - } - - @SuppressWarnings("unchecked") - private void registerWorld(@NotNull WorldServer world){ - final Collection W = new ArrayList<>(); - final Set nextTickList = new HashSet<>(); - TickListServer blockTickListServer = world.getBlockTickList(); - try { - Field gField = TickListServer.class.getDeclaredField("g"); - gField.setAccessible(true); - W.addAll((Collection) gField.get(blockTickListServer)); - Field ntlField = TickListServer.class.getDeclaredField("e"); - ntlField.setAccessible(true); - nextTickList.addAll((Set) ntlField.get(blockTickListServer)); - } catch (IllegalAccessException | IllegalArgumentException | NoSuchFieldException | SecurityException e1) { - e1.printStackTrace(); - } - tickMap.put(world, new AbstractMap.SimpleImmutableEntry<>(nextTickList,W)); - } - @Nullable - public NextTickListEntry getNextTick(@NotNull WorldServer world, @NotNull BlockPosition position) { - if (!isRegistered(world)) - registerWorld(world); - AbstractMap.SimpleImmutableEntry, Collection> listPair = tickMap.get(world); - if(listPair.getKey().contains(fakeEntry(position))) { - for (Iterator iterator = listPair.getKey().iterator(); iterator.hasNext(); ) { - NextTickListEntry listEntry = iterator.next(); - if (position.equals(listEntry.a)) { - iterator.remove(); - return listEntry; - } - } + public TickNextTickData getNextTick(@NotNull ServerLevel world, @NotNull BlockPos position){ + ServerTickList tickList = world.getBlockTickList(); + var box = BoundingBox.encapsulatingPositions(List.of(position)); + if(box.isEmpty()){ + return null; } - for(Iterator iterator = listPair.getValue().iterator(); iterator.hasNext();) { - NextTickListEntry listEntry = iterator.next(); - if (position.equals(listEntry.a)) { - iterator.remove(); - return listEntry; - } + for(var tick : tickList.fetchTicksInArea(box.get(), false, false)){ + Logger.getAnonymousLogger().info("" + tick); + return tick; } return null; - - } - @NotNull - public Object fakeEntry(@NotNull BlockPosition position){ - return new Object(){ - @Override - public int hashCode() { - return position.hashCode(); - } - }; } } From f1732b08b038d2d6d20e3f5da67906bafa46a52a Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Sat, 3 Jul 2021 22:14:08 +0200 Subject: [PATCH 297/304] Fixed world min height stuff --- modules/Movecraft/pom.xml | 2 +- .../net/countercraft/movecraft/Movecraft.java | 1 + .../movecraft/config/Settings.java | 1 + .../movecraft/craft/CraftType.java | 32 +++++++++++++++++-- 4 files changed, 33 insertions(+), 3 deletions(-) diff --git a/modules/Movecraft/pom.xml b/modules/Movecraft/pom.xml index 249cbc109..1daad384b 100644 --- a/modules/Movecraft/pom.xml +++ b/modules/Movecraft/pom.xml @@ -10,7 +10,7 @@ UTF-8 - 7.0.0.2_for_1.8.8-1.17 + 7.0.0.3_for_1.8.8-1.17 diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java index 2d14bd81f..a11af63de 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java @@ -255,6 +255,7 @@ public void onLoad() { Settings.IsPre1_9 = versionNumber < 9; Settings.IsLegacy = versionNumber <= 12; Settings.is1_14 = versionNumber >= 14; + Settings.IsV1_17 = versionNumber >= 17; instance = this; logger = getLogger(); } diff --git a/modules/api/src/main/java/net/countercraft/movecraft/config/Settings.java b/modules/api/src/main/java/net/countercraft/movecraft/config/Settings.java index 0457750f7..a19d4ea0b 100644 --- a/modules/api/src/main/java/net/countercraft/movecraft/config/Settings.java +++ b/modules/api/src/main/java/net/countercraft/movecraft/config/Settings.java @@ -62,4 +62,5 @@ public class Settings { public static HashSet DisableShadowBlocks = new HashSet<>(); public static boolean CheckForUpdates; public static boolean GearshiftsWithPilotToolEnabled; + public static boolean IsV1_17; } diff --git a/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java b/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java index 8efe4bb3f..47f7364d1 100644 --- a/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java +++ b/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java @@ -33,6 +33,8 @@ import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; import java.util.*; import static java.lang.Math.max; @@ -193,10 +195,36 @@ public CraftType(File f) { smokeOnSink = integerFromObject(data.getOrDefault("smokeOnSink", 0)); explodeOnCrash = floatFromObject(data.getOrDefault("explodeOnCrash", 0F)); collisionExplosion = floatFromObject(data.getOrDefault("collisionExplosion", 0F)); - minHeightLimit = max(0, integerFromObject(data.getOrDefault("minHeightLimit", 0))); + int minHeight = 0; + if (Settings.IsV1_17) { + final Method getMinHeight; + try { + getMinHeight = World.class.getDeclaredMethod("getMinHeight"); + minHeight = (int) getMinHeight.invoke(Bukkit.getWorlds().get(0)); + } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) { + e.printStackTrace(); + } + } + minHeightLimit = max(minHeight, integerFromObject(data.getOrDefault("minHeightLimit", 0))); perWorldMinHeightLimit = new HashMap<>(); Map minHeightMap = stringToIntMapFromObject(data.getOrDefault("perWorldMinHeightLimit", new HashMap<>())); - minHeightMap.forEach((world, height) -> perWorldMinHeightLimit.put(world, max(0, height))); + minHeightMap.forEach((world, height) -> { + int worldMinHeight = 0; + if (Settings.IsV1_17) { + final Method getMinHeight; + final World foundWorld = Bukkit.getWorld(world); + if (world != null) { + try { + getMinHeight = World.class.getDeclaredMethod("getMinHeight"); + worldMinHeight = (int) getMinHeight.invoke(foundWorld); + } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) { + + } + } + + } + perWorldMinHeightLimit.put(world, max(worldMinHeight, height)); + }); double cruiseSpeed = doubleFromObject(data.getOrDefault("cruiseSpeed", 20.0 / tickCooldown)); cruiseTickCooldown = (int) Math.round((1.0 + cruiseSkipBlocks) * 20.0 / cruiseSpeed); From 2298964946b7305440a8601f25fa52d259b08d10 Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Thu, 8 Jul 2021 18:27:22 +0200 Subject: [PATCH 298/304] small fixes --- modules/Movecraft/dependency-reduced-pom.xml | 2 +- .../net/countercraft/movecraft/sign/CraftSign.java | 13 +++++++------ .../net/countercraft/movecraft/craft/CraftType.java | 12 ++++++++++-- 3 files changed, 18 insertions(+), 9 deletions(-) diff --git a/modules/Movecraft/dependency-reduced-pom.xml b/modules/Movecraft/dependency-reduced-pom.xml index 16bad94ab..705f6ee5b 100644 --- a/modules/Movecraft/dependency-reduced-pom.xml +++ b/modules/Movecraft/dependency-reduced-pom.xml @@ -4,7 +4,7 @@ net.countercraft movecraft Movecraft - 7.0.0.2_for_1.8.8-1.17 + 7.0.0.3_for_1.8.8-1.17 http://github.com/apdevteam/Movecraft src/main/java diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CraftSign.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CraftSign.java index eba81836c..58bc805b2 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CraftSign.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CraftSign.java @@ -76,12 +76,13 @@ public final void onSignClick(PlayerInteractEvent event) { c.setCruiseDirection(CruiseDirection.fromBlockFace(face)); c.setLastCruiseUpdate(System.currentTimeMillis()); c.setCruising(true); - new BukkitRunnable() { - @Override - public void run() { - c.sink(); - } - }.runTaskLater(Movecraft.getInstance(), (20 * 15)); + if (type.getCruiseOnPilotSinkAfter() > -1) + new BukkitRunnable() { + @Override + public void run() { + c.sink(); + } + }.runTaskLater(Movecraft.getInstance(), (20L * type.getCruiseOnPilotSinkAfter())); } else { if (CraftManager.getInstance().getCraftByPlayer(event.getPlayer()) == null) { c.detect(event.getPlayer(), event.getPlayer(), startPoint); diff --git a/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java b/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java index 47f7364d1..300e2c8ba 100644 --- a/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java +++ b/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java @@ -40,6 +40,10 @@ import static java.lang.Math.max; final public class CraftType { + //Mandatory flags + @NotNull private final String craftName; + @NotNull private final BlockContainer allowedBlocks; + private final boolean blockedByWater; private final boolean requireWaterContact; private final boolean tryNudge; @@ -73,6 +77,7 @@ final public class CraftType { private final int maxHeightAboveGround; @NotNull private final Map perWorldMaxHeightAboveGround; private final int cruiseOnPilotVertMove; + private final int cruiseOnPilotSinkAfter; private final int maxStaticMove; private final int cruiseSkipBlocks; @NotNull private final Map perWorldCruiseSkipBlocks; @@ -106,8 +111,6 @@ final public class CraftType { private final double chestPenalty; private final float explodeOnCrash; private final float collisionExplosion; - @NotNull private final String craftName; - @NotNull private final BlockContainer allowedBlocks; @NotNull private final BlockContainer interiorBlocks; @NotNull private final BlockContainer forbiddenBlocks; @NotNull private final String[] forbiddenSignStrings; @@ -168,6 +171,7 @@ public CraftType(File f) { canBeNamed = (boolean) data.getOrDefault("canBeNamed", true); cruiseOnPilot = (boolean) data.getOrDefault("cruiseOnPilot", false); cruiseOnPilotVertMove = integerFromObject(data.getOrDefault("cruiseOnPilotVertMove", 0)); + cruiseOnPilotSinkAfter = integerFromObject(data.getOrDefault("cruiseOnPilotSinkAfter", 15)); allowVerticalMovement = (boolean) data.getOrDefault("allowVerticalMovement", true); rotateAtMidpoint = (boolean) data.getOrDefault("rotateAtMidpoint", false); allowHorizontalMovement = (boolean) data.getOrDefault("allowHorizontalMovement", true); @@ -1087,6 +1091,10 @@ public BlockContainer getInteriorBlocks() { return interiorBlocks; } + public int getCruiseOnPilotSinkAfter() { + return cruiseOnPilotSinkAfter; + } + public class TypeNotFoundException extends RuntimeException { public TypeNotFoundException(String s) { super(s); From f8bbe095b9d8ea96354212ae3c010d2d14c23bd3 Mon Sep 17 00:00:00 2001 From: BuildTools Date: Sun, 28 Nov 2021 17:01:06 +0100 Subject: [PATCH 299/304] Changes --- .github/workflows/maven.yml | 6 +++ README.md | 1 + .../movecraft/commands/ContactsCommand.java | 7 ++-- .../movecraft/commands/CraftInfoCommand.java | 20 +++++---- .../commands/CraftReportCommand.java | 12 ++++-- .../movecraft/commands/CraftTypeCommand.java | 13 +++--- .../update/EntityUpdateCommand.java | 2 +- .../movecraft/utils/TopicPaginator.java | 42 ++++++++++++++----- .../countercraft/movecraft/craft/Craft.java | 13 +++--- modules/v1_18_R1/pom.xml | 22 ++++++++++ pom.xml | 1 + 11 files changed, 101 insertions(+), 38 deletions(-) create mode 100644 modules/v1_18_R1/pom.xml diff --git a/.github/workflows/maven.yml b/.github/workflows/maven.yml index 84045a550..7c27d960e 100644 --- a/.github/workflows/maven.yml +++ b/.github/workflows/maven.yml @@ -106,6 +106,12 @@ jobs: - name: Build 1.16.5 if: steps.nether3.outputs.sucess != 'true' run: cd BuildTools && java -jar BuildTools.jar --rev 1.16.5 --compile craftbukkit + - name: Check 1.17 + id: caves&cliffs + run: test -f ~/.m2/repository/org/bukkit/craftbukkit/1.17-R0.1-SNAPSHOT/craftbukkit-1.17-R0.1-SNAPSHOT.jar && echo "::set-output name=sucess::true" || echo "::set-output name=sucess::false" + - name: Build 1.17 + if: steps.caves&cliffs.output.sucess != 'true' + run: cd BuildTools && java -jar BuildTools.jar --rev 1.17 --remapped # EXAMPLE - Copy/paste as required to add version support to CI # - name: Test [version] diff --git a/README.md b/README.md index de7b15d4f..f499e9bd0 100644 --- a/README.md +++ b/README.md @@ -26,6 +26,7 @@ java -jar BuildTools.jar --rev 1.15.2 --compile craftbukkit java -jar BuildTools.jar --rev 1.16.1 --compile craftbukkit java -jar BuildTools.jar --rev 1.16.3 --compile craftbukkit java -jar BuildTools.jar --rev 1.16.5 --compile craftbukkit +java -jar BuildTools.jar --rev 1.17 --remapped ``` Then, run the following to build Movecraft through `maven`. diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/ContactsCommand.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/ContactsCommand.java index d2295001f..a2be4de69 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/ContactsCommand.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/ContactsCommand.java @@ -6,6 +6,7 @@ import net.countercraft.movecraft.localisation.I18nSupport; import net.countercraft.movecraft.utils.HitBox; import net.countercraft.movecraft.utils.TopicPaginator; +import net.md_5.bungee.api.chat.TextComponent; import org.bukkit.ChatColor; import org.bukkit.command.Command; import org.bukkit.command.CommandExecutor; @@ -43,7 +44,7 @@ public boolean onCommand(CommandSender commandSender, Command command, String s, return true; } - TopicPaginator pageinator = new TopicPaginator(I18nSupport.getInternationalisedString("Contacts")); + TopicPaginator pageinator = new TopicPaginator(I18nSupport.getInternationalisedString("Contacts"), "/contacts {PAGE}"); Craft ccraft = CraftManager.getInstance().getCraftByPlayer(player); HitBox hitBox = ccraft.getHitBox(); MovecraftLocation center = hitBox.getMidPoint(); @@ -91,8 +92,8 @@ else if (diffz < 0) commandSender.sendMessage(MOVECRAFT_COMMAND_PREFIX + I18nSupport.getInternationalisedString("Paginator - Invalid page") + "\"" + page + "\""); return true; } - for(String line :pageinator.getPage(page)) - commandSender.sendMessage(line); + for(TextComponent line : pageinator.getPage(page)) + commandSender.spigot().sendMessage(line); return true; } } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/CraftInfoCommand.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/CraftInfoCommand.java index 13e207aec..5ec72d675 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/CraftInfoCommand.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/CraftInfoCommand.java @@ -4,7 +4,9 @@ import net.countercraft.movecraft.craft.CraftManager; import net.countercraft.movecraft.utils.MathUtils; import net.countercraft.movecraft.utils.TopicPaginator; +import net.md_5.bungee.api.chat.TextComponent; import org.bukkit.command.Command; +import org.bukkit.command.CommandExecutor; import org.bukkit.command.CommandSender; import org.bukkit.command.TabExecutor; import org.bukkit.entity.Player; @@ -15,7 +17,7 @@ import java.util.OptionalInt; import java.util.function.Function; -public class CraftInfoCommand implements TabExecutor { +public class CraftInfoCommand implements CommandExecutor { private static final List>> providers = new ArrayList<>(); static { registerMultiProvider(CraftInfoCommand::allowedBlockProvider); @@ -94,8 +96,12 @@ public boolean onCommand(@NotNull CommandSender sender, @NotNull Command command return true; } - public void craftInfo(@NotNull CommandSender commandSender, @NotNull Craft craft, int page){ - TopicPaginator paginator = new TopicPaginator("Craft Info"); + public void craftInfo(@NotNull CommandSender commandSender, @NotNull Craft craft, int page) { + craftInfo(commandSender, craft, page, ""); + } + + public void craftInfo(@NotNull CommandSender commandSender, @NotNull Craft craft, int page, String playerName) { + TopicPaginator paginator = new TopicPaginator("Craft Info", "/craftinfo " + playerName + " {PAGE}"); for(Function> provider : providers){ for(String line : provider.apply(craft)){ paginator.addLine(line); @@ -105,12 +111,8 @@ public void craftInfo(@NotNull CommandSender commandSender, @NotNull Craft craft commandSender.sendMessage(String.format("Page %d is out of bounds.", page)); return; } - for(String line : paginator.getPage(page)) - commandSender.sendMessage(line); + for(TextComponent line : paginator.getPage(page)) + commandSender.spigot().sendMessage(line); } - @Override - public List onTabComplete(@NotNull CommandSender sender, @NotNull Command command, @NotNull String alias, @NotNull String[] args) { - return null; - } } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/CraftReportCommand.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/CraftReportCommand.java index ae42889ae..0c8c2254f 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/CraftReportCommand.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/CraftReportCommand.java @@ -6,10 +6,12 @@ import net.countercraft.movecraft.localisation.I18nSupport; import net.countercraft.movecraft.utils.HitBox; import net.countercraft.movecraft.utils.TopicPaginator; +import net.md_5.bungee.api.chat.TextComponent; import org.bukkit.ChatColor; import org.bukkit.command.Command; import org.bukkit.command.CommandExecutor; import org.bukkit.command.CommandSender; +import org.bukkit.entity.Player; import static net.countercraft.movecraft.utils.ChatUtils.MOVECRAFT_COMMAND_PREFIX; @@ -37,7 +39,7 @@ public boolean onCommand(CommandSender commandSender, Command command, String s, commandSender.sendMessage(MOVECRAFT_COMMAND_PREFIX + I18nSupport.getInternationalisedString("Craft Report - None Found")); return true; } - TopicPaginator paginator = new TopicPaginator(I18nSupport.getInternationalisedString("Craft Report")); + TopicPaginator paginator = new TopicPaginator(I18nSupport.getInternationalisedString("Craft Report"), "/craftreport {PAGE}"); for (Craft craft : CraftManager.getInstance()) { HitBox hitBox = craft.getHitBox(); paginator.addLine((craft.getSinking() ? ChatColor.RED : craft.getDisabled() ? ChatColor.BLUE : "") + @@ -45,6 +47,7 @@ public boolean onCommand(CommandSender commandSender, Command command, String s, ChatColor.RESET + (craft.getNotificationPlayer() != null ? craft.getNotificationPlayer().getName() + " " : I18nSupport.getInternationalisedString("None") +" ")+ hitBox.size() + " @ " + + craft.getWorld().getName() + "," + hitBox.getMinX() + "," + hitBox.getMinY() + "," + hitBox.getMinZ() + " - " + @@ -54,8 +57,11 @@ public boolean onCommand(CommandSender commandSender, Command command, String s, commandSender.sendMessage(MOVECRAFT_COMMAND_PREFIX + I18nSupport.getInternationalisedString("Paginator - Invalid page") + "\"" + page + "\""); return true; } - for(String line : paginator.getPage(page)) - commandSender.sendMessage(line); + for(TextComponent line : paginator.getPage(page)) + if (commandSender instanceof Player) + commandSender.spigot().sendMessage(line); + else + commandSender.sendMessage(line.getText()); return true; } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/CraftTypeCommand.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/CraftTypeCommand.java index 512b13242..bb350dff6 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/CraftTypeCommand.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/CraftTypeCommand.java @@ -5,6 +5,7 @@ import net.countercraft.movecraft.craft.CraftType; import net.countercraft.movecraft.utils.MathUtils; import net.countercraft.movecraft.utils.TopicPaginator; +import net.md_5.bungee.api.chat.TextComponent; import org.bukkit.command.Command; import org.bukkit.command.CommandSender; import org.bukkit.command.TabExecutor; @@ -81,7 +82,7 @@ public List onTabComplete(@NotNull CommandSender commandSender, @NotNull } private void sendTypePage(@NotNull CraftType type, int page, @NotNull CommandSender commandSender){ - TopicPaginator paginator = new TopicPaginator("Type Info"); + TopicPaginator paginator = new TopicPaginator("Type Info", "/crafttype " + type.getCraftName() + " {PAGE}"); for(Field field : craftTypeFields){ if(field.getName().equals("data")){ // don't include the backing data object continue; @@ -104,12 +105,12 @@ private void sendTypePage(@NotNull CraftType type, int page, @NotNull CommandSe commandSender.sendMessage(String.format("Page %d is out of bounds.", page)); return; } - for(String line : paginator.getPage(page)) - commandSender.sendMessage(line); + for(TextComponent line : paginator.getPage(page)) + commandSender.spigot().sendMessage(line); } private void sendTypeListPage(int page, @NotNull CommandSender commandSender){ - TopicPaginator paginator = new TopicPaginator("Type Info"); + TopicPaginator paginator = new TopicPaginator("Type Info", "/crafttype list {PAGE}"); for(CraftType entry : CraftManager.getInstance().getCraftTypes()){ paginator.addLine(entry.getCraftName()); } @@ -117,8 +118,8 @@ private void sendTypeListPage(int page, @NotNull CommandSender commandSender){ commandSender.sendMessage(String.format("Page %d is out of bounds.", page)); return; } - for(String line : paginator.getPage(page)) - commandSender.sendMessage(line); + for(TextComponent line : paginator.getPage(page)) + commandSender.spigot().sendMessage(line); } @NotNull diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/EntityUpdateCommand.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/EntityUpdateCommand.java index 0f727eab4..e732abc67 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/EntityUpdateCommand.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/EntityUpdateCommand.java @@ -152,7 +152,7 @@ public void doUpdate() { Player player = (Player) entity; Craft craft = CraftManager.getInstance().getCraftByPlayer(player); Location location; - if (craft != null && craft.getNotificationPlayer() == player && craft.getPilotLocked()) { + if (craft != null && craft.getNotificationPlayer() == player && craft.getPilotLocked() && craft.getType().getLockPilotAtDirectControl()) { craft.setPilotLockedX(craft.getPilotLockedX() + x); craft.setPilotLockedY(craft.getPilotLockedY() + y); craft.setPilotLockedZ(craft.getPilotLockedZ() + z); diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/TopicPaginator.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/TopicPaginator.java index 7864e7e7e..e62d14216 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/TopicPaginator.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/TopicPaginator.java @@ -1,24 +1,33 @@ package net.countercraft.movecraft.utils; import net.countercraft.movecraft.localisation.I18nSupport; +import net.md_5.bungee.api.chat.BaseComponent; +import net.md_5.bungee.api.chat.ClickEvent; +import net.md_5.bungee.api.chat.TextComponent; import java.util.ArrayList; -import java.util.Collections; +import java.util.Comparator; import java.util.List; import static org.bukkit.util.ChatPaginator.CLOSED_CHAT_PAGE_HEIGHT; public class TopicPaginator { - private String title; - private List lines = new ArrayList<>(); + private final String title; + private final List lines = new ArrayList<>(); + private final String command; - public TopicPaginator(String title){ + public TopicPaginator(String title, String command){ this.title = title; + this.command = command; } public boolean addLine(String line){ + return addLine(new TextComponent(line)); + } + + public boolean addLine(TextComponent line){ boolean result = lines.add(line); - Collections.sort(lines); + lines.sort(Comparator.comparing(TextComponent::getText)); return result; } @@ -27,13 +36,26 @@ public boolean addLine(String line){ * @param pageNumber * @return An array of lines to send as a page */ - public String[] getPage(int pageNumber){ + public TextComponent[] getPage(int pageNumber){ if(!isInBounds(pageNumber)) throw new IndexOutOfBoundsException(I18nSupport.getInternationalisedString("Paginator - Page Number")+ " " + pageNumber + " "+ I18nSupport.getInternationalisedString("Paginator - Exceeds Bounds") + "<1, " + getPageCount() + ">"); - String[] tempLines = new String[pageNumber == getPageCount() ? (lines.size()%CLOSED_CHAT_PAGE_HEIGHT) + 1 : CLOSED_CHAT_PAGE_HEIGHT]; - tempLines[0] = "§e§l--- §r§6" + title +" §e§l-- §r§6page §c" + pageNumber + "§e/§c" + getPageCount() + " §e§l---"; - for(int i = 0; i< tempLines.length-1; i++) - tempLines[i+1] = lines.get(((CLOSED_CHAT_PAGE_HEIGHT-1) * (pageNumber-1)) + i); + TextComponent[] tempLines = new TextComponent[pageNumber == getPageCount() ? (lines.size()%CLOSED_CHAT_PAGE_HEIGHT) + 1 : CLOSED_CHAT_PAGE_HEIGHT]; + tempLines[0] = new TextComponent("§e§l--- §r§6" + title +" §e§l-- §r§6page §c" + pageNumber + "§e/§c" + getPageCount() + " §e§l---"); + for(int i = 0; i< tempLines.length-2; i++) + tempLines[i+1] = new TextComponent(lines.get(((CLOSED_CHAT_PAGE_HEIGHT-1) * (pageNumber-1)) + i)); + BaseComponent prevPage = new TextComponent(pageNumber == 1 ? "§4---" : "§2<<<"); + BaseComponent nextPage = new TextComponent(pageNumber == getPageCount() ? "§4---" : "§2>>>"); + if (pageNumber > 1) { + prevPage.setClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, command.replace("{PAGE}", String.valueOf(pageNumber - 1)))); + } + if (pageNumber < getPageCount()) { + nextPage.setClickEvent(new ClickEvent(ClickEvent.Action.RUN_COMMAND, command.replace("{PAGE}", String.valueOf(pageNumber + 1)))); + } + TextComponent arrows = new TextComponent(); + arrows.addExtra(prevPage); + arrows.addExtra("|"); + arrows.addExtra(nextPage); + tempLines[tempLines.length - 1] = arrows; return tempLines; } diff --git a/modules/api/src/main/java/net/countercraft/movecraft/craft/Craft.java b/modules/api/src/main/java/net/countercraft/movecraft/craft/Craft.java index a0d3eeb75..cf3a853ff 100644 --- a/modules/api/src/main/java/net/countercraft/movecraft/craft/Craft.java +++ b/modules/api/src/main/java/net/countercraft/movecraft/craft/Craft.java @@ -128,18 +128,14 @@ public World getW() { return world; } + @NotNull public World getWorld() { return world; } @Deprecated public void setW(World world) { - this.world = world; - if (type.getMaxHeightLimit(world) > world.getMaxHeight() - 1) { - this.maxHeightLimit = world.getMaxHeight() - 1; - } else { - this.maxHeightLimit = type.getMaxHeightLimit(world); - } + setWorld(world); } public abstract void detect(Player player, Player notificationPlayer, MovecraftLocation startPoint); @@ -498,6 +494,11 @@ public void setCurrentGear(int currentGear) { public void setWorld(World world) { this.world = world; + if (type.getMaxHeightLimit(world) > world.getMaxHeight() - 1) { + this.maxHeightLimit = world.getMaxHeight() - 1; + } else { + this.maxHeightLimit = type.getMaxHeightLimit(world); + } } public boolean isTranslating() { diff --git a/modules/v1_18_R1/pom.xml b/modules/v1_18_R1/pom.xml new file mode 100644 index 000000000..c35133d7f --- /dev/null +++ b/modules/v1_18_R1/pom.xml @@ -0,0 +1,22 @@ + + + + movecraft-parent + net.countercraft + parent + ../../pom.xml + + 4.0.0 + + movecraft-v1_18_R1 + Movecraft-v1_18_R1 + v1_18_R1 + + + 14 + 14 + + + \ No newline at end of file diff --git a/pom.xml b/pom.xml index e4d6c1964..60a0f9f1d 100644 --- a/pom.xml +++ b/pom.xml @@ -33,6 +33,7 @@ modules/v1_16_R2 modules/v1_16_R3 modules/v1_17_R1 + modules/Movecraft From cc87e290bc6ec72e0bd0f315d3549fd20c2e5480 Mon Sep 17 00:00:00 2001 From: BuildTools Date: Fri, 3 Dec 2021 01:50:08 +0100 Subject: [PATCH 300/304] Update to 1.18 --- modules/Movecraft/dependency-reduced-pom.xml | 6 + modules/Movecraft/pom.xml | 13 +- .../net/countercraft/movecraft/Movecraft.java | 1 + .../update/EntityUpdateCommand.java | 2 +- modules/api/dependency-reduced-pom.xml | 6 - .../movecraft/config/Settings.java | 1 + .../movecraft/craft/CraftType.java | 7 +- .../movecraft/utils/TeleportUtils.java | 17 +- modules/v1_18_R1/pom.xml | 77 ++- .../compat/v1_18_R1/IWorldHandler.java | 459 ++++++++++++++++++ .../compat/v1_18_R1/NextTickProvider.java | 44 ++ pom.xml | 8 +- 12 files changed, 619 insertions(+), 22 deletions(-) create mode 100644 modules/v1_18_R1/src/main/java/net/countercraft/movecraft/compat/v1_18_R1/IWorldHandler.java create mode 100644 modules/v1_18_R1/src/main/java/net/countercraft/movecraft/compat/v1_18_R1/NextTickProvider.java diff --git a/modules/Movecraft/dependency-reduced-pom.xml b/modules/Movecraft/dependency-reduced-pom.xml index 705f6ee5b..fe6fff449 100644 --- a/modules/Movecraft/dependency-reduced-pom.xml +++ b/modules/Movecraft/dependency-reduced-pom.xml @@ -146,6 +146,12 @@ ** + + net.countercraft:movecraft-v1_18_R1 + + ** + + diff --git a/modules/Movecraft/pom.xml b/modules/Movecraft/pom.xml index 1daad384b..84886ce29 100644 --- a/modules/Movecraft/pom.xml +++ b/modules/Movecraft/pom.xml @@ -28,7 +28,12 @@ - + + net.countercraft + movecraft-v1_18_R1 + v1_18_R1 + jar + org.spigotmc spigot-api @@ -284,6 +289,12 @@ ** + + net.countercraft:movecraft-v1_18_R1 + + ** + + diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java index a11af63de..97f324605 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java @@ -256,6 +256,7 @@ public void onLoad() { Settings.IsLegacy = versionNumber <= 12; Settings.is1_14 = versionNumber >= 14; Settings.IsV1_17 = versionNumber >= 17; + Settings.IsV1_18 = versionNumber >= 18; instance = this; logger = getLogger(); } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/EntityUpdateCommand.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/EntityUpdateCommand.java index e732abc67..15ac94633 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/EntityUpdateCommand.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/EntityUpdateCommand.java @@ -158,7 +158,7 @@ public void doUpdate() { craft.setPilotLockedZ(craft.getPilotLockedZ() + z); } - if (craft != null && craft.getType().getLockPilotAtDirectControl()) + if (craft != null && craft.getType().getLockPilotAtDirectControl() && craft.getPilotLocked()) location = new Location(world, craft.getPilotLockedX(), craft.getPilotLockedY(), craft.getPilotLockedZ()); else location = new Location(world, playerLoc.getX() + x, playerLoc.getY() + y, playerLoc.getZ() + z); diff --git a/modules/api/dependency-reduced-pom.xml b/modules/api/dependency-reduced-pom.xml index 97031bd7d..12b39ffaa 100644 --- a/modules/api/dependency-reduced-pom.xml +++ b/modules/api/dependency-reduced-pom.xml @@ -143,12 +143,6 @@ - - com.destroystokyo.paper - paper-api - 1.16.5-R0.1-SNAPSHOT - provided - UTF-8 diff --git a/modules/api/src/main/java/net/countercraft/movecraft/config/Settings.java b/modules/api/src/main/java/net/countercraft/movecraft/config/Settings.java index a19d4ea0b..96fdd4d8f 100644 --- a/modules/api/src/main/java/net/countercraft/movecraft/config/Settings.java +++ b/modules/api/src/main/java/net/countercraft/movecraft/config/Settings.java @@ -63,4 +63,5 @@ public class Settings { public static boolean CheckForUpdates; public static boolean GearshiftsWithPilotToolEnabled; public static boolean IsV1_17; + public static boolean IsV1_18; } diff --git a/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java b/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java index 300e2c8ba..47baff7f1 100644 --- a/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java +++ b/modules/api/src/main/java/net/countercraft/movecraft/craft/CraftType.java @@ -201,11 +201,12 @@ public CraftType(File f) { collisionExplosion = floatFromObject(data.getOrDefault("collisionExplosion", 0F)); int minHeight = 0; if (Settings.IsV1_17) { - final Method getMinHeight; try { - getMinHeight = World.class.getDeclaredMethod("getMinHeight"); + final Class clazz = Settings.IsV1_18 ? Class.forName("org.bukkit.generator.WorldInfo") : World.class ; + final Method getMinHeight; + getMinHeight = clazz.getDeclaredMethod("getMinHeight"); minHeight = (int) getMinHeight.invoke(Bukkit.getWorlds().get(0)); - } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) { + } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException | ClassNotFoundException e) { e.printStackTrace(); } } diff --git a/modules/api/src/main/java/net/countercraft/movecraft/utils/TeleportUtils.java b/modules/api/src/main/java/net/countercraft/movecraft/utils/TeleportUtils.java index dd8651b7f..e25e89417 100644 --- a/modules/api/src/main/java/net/countercraft/movecraft/utils/TeleportUtils.java +++ b/modules/api/src/main/java/net/countercraft/movecraft/utils/TeleportUtils.java @@ -60,17 +60,17 @@ public class TeleportUtils { Class worldClass = v1_17() ? getNmwClass("level.World") : getNmsClass("World"); try { - sendMethod = connectionClass.getMethod("sendPacket", packet); + sendMethod = connectionClass.getMethod(v1_18() ? "a" : "sendPacket", packet); - position = entity.getDeclaredMethod("setLocation", Double.TYPE, Double.TYPE, Double.TYPE, Float.TYPE, Float.TYPE); - closeInventory = entityPlayer.getDeclaredMethod("closeInventory"); + position = entity.getDeclaredMethod(v1_18() ? "a" : "setLocation", Double.TYPE, Double.TYPE, Double.TYPE, Float.TYPE, Float.TYPE); + closeInventory = entityPlayer.getDeclaredMethod(v1_18() ? "q" : "closeInventory"); getBukkitEntity = entity.getDeclaredMethod("getBukkitEntity"); if (!v1_17()) spawnIn = entity.getDeclaredMethod("spawnIn", worldClass); else t = entity.getDeclaredField("t"); - yaw = getField(entity, v1_17() ? "ay" : "yaw"); - pitch = getField(entity, v1_17() ? "az" : "pitch"); + yaw = getField(entity, v1_17() ? (v1_18() ? "aA" : "ay") : "yaw"); + pitch = getField(entity, v1_17() ? (v1_18() ? "aB" : "az") : "pitch"); connectionField = getField(entityPlayer, v1_17() ? "b" : "playerConnection"); activeContainer = getField(entityHuman, v1_17() ? "bU" : "activeContainer"); defaultContainer = getField(entityHuman, v1_17() ? "bV" : "defaultContainer"); @@ -112,7 +112,8 @@ public static void teleportEntity(Entity entity, Location location) { try { if (location.getWorld() != entity.getWorld()) { Method wHandle = location.getWorld().getClass().getDeclaredMethod("getHandle"); - spawnIn.invoke(handle, wHandle.invoke(location.getWorld())); + if (!v1_17()) + spawnIn.invoke(handle, wHandle.invoke(location.getWorld())); } position.invoke(handle, x,y,z, location.getYaw(), location.getPitch()); } catch (Exception e) { @@ -194,6 +195,10 @@ private static boolean v1_17() { return Integer.parseInt(getVersion().split("_")[1]) >= 17; } + private static boolean v1_18() { + return Integer.parseInt(getVersion().split("_")[1]) >= 18; + } + private static Class getNmsClass(String name) { Class clazz = null; diff --git a/modules/v1_18_R1/pom.xml b/modules/v1_18_R1/pom.xml index c35133d7f..9db6400c1 100644 --- a/modules/v1_18_R1/pom.xml +++ b/modules/v1_18_R1/pom.xml @@ -13,10 +13,85 @@ movecraft-v1_18_R1 Movecraft-v1_18_R1 v1_18_R1 + jar 14 14 - + + + net.countercraft + movecraft-api + API + jar + + + org.spigotmc + spigot + 1.18-R0.1-SNAPSHOT + remapped-mojang + provided + + + + src/main/java + + + org.apache.maven.plugins + maven-compiler-plugin + 3.7.0 + + + net/countercraft/movecraft/compat/v1_18_R1/** + + 13 + 13 + + + + org.apache.maven.plugins + maven-jar-plugin + 2.4 + + + net/countercraft/movecraft/compat/v1_18_R1/** + + + + + net.md-5 + specialsource-maven-plugin + 1.2.3 + + + package + + remap + + remap-obf + + org.spigotmc:minecraft-server:1.18-R0.1-SNAPSHOT:txt:maps-mojang + true + org.spigotmc:spigot:1.18-R0.1-SNAPSHOT:jar:remapped-mojang + true + remapped-obf + + + + package + + remap + + remap-spigot + + ${project.build.directory}/${project.artifactId}-${project.version}-remapped-obf.jar + org.spigotmc:minecraft-server:1.18-R0.1-SNAPSHOT:csrg:maps-spigot + org.spigotmc:spigot:1.18-R0.1-SNAPSHOT:jar:remapped-obf + + + + + + \ No newline at end of file diff --git a/modules/v1_18_R1/src/main/java/net/countercraft/movecraft/compat/v1_18_R1/IWorldHandler.java b/modules/v1_18_R1/src/main/java/net/countercraft/movecraft/compat/v1_18_R1/IWorldHandler.java new file mode 100644 index 000000000..958378730 --- /dev/null +++ b/modules/v1_18_R1/src/main/java/net/countercraft/movecraft/compat/v1_18_R1/IWorldHandler.java @@ -0,0 +1,459 @@ +package net.countercraft.movecraft.compat.v1_18_R1; + +import net.countercraft.movecraft.MovecraftLocation; +import net.countercraft.movecraft.Rotation; +import net.countercraft.movecraft.WorldHandler; +import net.countercraft.movecraft.craft.Craft; +import net.countercraft.movecraft.utils.CollectionUtils; +import net.countercraft.movecraft.utils.MathUtils; +import net.minecraft.core.BlockPos; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.block.*; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.chunk.LevelChunk; +import net.minecraft.world.level.chunk.LevelChunkSection; +import net.minecraft.world.ticks.ScheduledTick; +import org.bukkit.Location; +import org.bukkit.Material; +import org.bukkit.block.data.BlockData; +import org.bukkit.craftbukkit.v1_18_R1.CraftWorld; +import org.bukkit.craftbukkit.v1_18_R1.block.data.CraftBlockData; +import org.bukkit.craftbukkit.v1_18_R1.util.CraftMagicNumbers; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import sun.misc.Unsafe; + +import java.lang.invoke.MethodHandle; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.*; + +public class IWorldHandler extends WorldHandler { + private static final net.minecraft.world.level.block.Rotation[] ROTATION; + @Nullable private static final Unsafe unsafe; + static { + Unsafe deferred; + try { + Field theUnsafeField = Unsafe.class.getDeclaredField("theUnsafe"); + theUnsafeField.setAccessible(true); + deferred = (Unsafe) theUnsafeField.get(null); + } catch (NoSuchFieldException | IllegalAccessException e) { + deferred = null; + e.printStackTrace(); + } + unsafe = deferred; + + ROTATION = new net.minecraft.world.level.block.Rotation[3]; + ROTATION[Rotation.NONE.ordinal()] = net.minecraft.world.level.block.Rotation.NONE; + ROTATION[Rotation.CLOCKWISE.ordinal()] = net.minecraft.world.level.block.Rotation.CLOCKWISE_90; + ROTATION[Rotation.ANTICLOCKWISE.ordinal()] = net.minecraft.world.level.block.Rotation.COUNTERCLOCKWISE_90; + + } + private final NextTickProvider tickProvider = new NextTickProvider(); + private MethodHandle internalTeleportMH; + + public IWorldHandler() { + } + + @Override + public void rotateCraft(@NotNull Craft craft, @NotNull MovecraftLocation originPoint, @NotNull Rotation rotation) { + //******************************************* + //* Step one: Convert to Positions * + //******************************************* + HashMap rotatedPositions = new HashMap<>(); + Rotation counterRotation = rotation == Rotation.CLOCKWISE ? Rotation.ANTICLOCKWISE : Rotation.CLOCKWISE; + for(MovecraftLocation newLocation : craft.getHitBox()){ + rotatedPositions.put(locationToPosition(MathUtils.rotateVec(counterRotation, newLocation.subtract(originPoint)).add(originPoint)),locationToPosition(newLocation)); + } + //******************************************* + //* Step two: Get the tiles * + //******************************************* + ServerLevel nativeWorld = ((CraftWorld) craft.getWorld()).getHandle(); + List tiles = new ArrayList<>(); + //get the tiles + for(BlockPos position : rotatedPositions.keySet()){ + //BlockEntity tile = nativeWorld.removeBlockEntity(position); + BlockEntity tile = removeBlockEntity(nativeWorld,position); + if(tile == null) + continue; + //tile.setBlockState(tile.getBlockState().rotate(ROTATION[rotation.ordinal()])); + //get the nextTick to move with the tile + tiles.add(new TileHolder(tile, tickProvider.getNextTick(nativeWorld, position), position)); + } + + //******************************************* + //* Step three: Translate all the blocks * + //******************************************* + // blockedByWater=false means an ocean-going vessel + //TODO: Simplify + //TODO: go by chunks + //TODO: Don't move unnecessary blocks + //get the blocks and rotate them + HashMap blockData = new HashMap<>(); + for(BlockPos position : rotatedPositions.keySet()){ + + blockData.put(position,nativeWorld.getBlockState(position).rotate(ROTATION[rotation.ordinal()])); + } + HashMap redstoneComponents = new HashMap<>(); + //create the new block + for(Map.Entry entry : blockData.entrySet()) { + final BlockPos newPosition = rotatedPositions.get(entry.getKey()); + final BlockState iBlockData = entry.getValue(); + if (nativeWorld.getBlockEntity(newPosition) != null) { + removeBlockEntity(nativeWorld, newPosition); + } + if (isRedstoneComponent(iBlockData)) + redstoneComponents.put(newPosition, iBlockData); + + setBlockFast(nativeWorld, newPosition, iBlockData); + } + + + //******************************************* + //* Step four: replace all the tiles * + //******************************************* + //TODO: go by chunks + for(TileHolder tileHolder : tiles){ + moveBlockEntity(nativeWorld, rotatedPositions.get(tileHolder.getTilePosition()),tileHolder.getTile()); + if(tileHolder.getNextTick()==null) + continue; + final long currentTime = nativeWorld.getGameTime(); + nativeWorld.getBlockTicks().schedule( + new ScheduledTick<>( + (Block) tileHolder.getNextTick().type(), + rotatedPositions.get(tileHolder.getNextTick().pos()), + tileHolder.getNextTick().triggerTick() - currentTime, + tileHolder.getNextTick().priority(), + tileHolder.getNextTick().subTickOrder()) + ); + } + + //******************************************* + //* Step five: Destroy the leftovers * + //******************************************* + //TODO: add support for pass-through + Collection deletePositions = CollectionUtils.filter(rotatedPositions.keySet(),rotatedPositions.values()); + for(BlockPos position : deletePositions){ + setBlockFast(nativeWorld, position, Blocks.AIR.defaultBlockState()); + } + + //******************************************* + //* Step six: Process fire spread * + //******************************************* + for (BlockPos position : rotatedPositions.values()) { + BlockState type = nativeWorld.getBlockState(position); + if (!(type.getBlock() instanceof FireBlock)) { + continue; + } + FireBlock fire = (FireBlock) type.getBlock(); + fire.tick(type, nativeWorld, position, nativeWorld.random); + } + + for (Map.Entry entry : redstoneComponents.entrySet()) { + final BlockPos position = entry.getKey(); + final BlockState data = entry.getValue(); + LevelChunk chunk = nativeWorld.getChunkAt(position); + LevelChunkSection chunkSection = chunk.getSections()[position.getY()>>4]; + if (chunkSection == null) { + // Put a GLASS block to initialize the section. It will be replaced next with the real block. + chunk.setBlockState(position, Blocks.GLASS.defaultBlockState(), false); + chunkSection = chunk.getSections()[chunk.getSectionIndex(position.getY())]; + + } + if (chunkSection.getBlockState(position.getX()&15, position.getY()&15, position.getZ()&15).equals(data)) { + return; + } + chunkSection.setBlockState(position.getX()&15, position.getY()&15, position.getZ()&15, data); + nativeWorld.sendBlockUpdated(position, data, data, 3); + nativeWorld.getLightEngine().checkBlock(position); // boolean corresponds to if chunk section empty + chunk.setUnsaved(true); + } + } + + @Override + public void translateCraft(@NotNull Craft craft, @NotNull MovecraftLocation displacement, @NotNull org.bukkit.World world) { + //TODO: Add supourt for rotations + //A craftTranslateCommand should only occur if the craft is moving to a valid position + //******************************************* + //* Step one: Convert to Positions * + //******************************************* + BlockPos translateVector = locationToPosition(displacement); + List positions = new ArrayList<>(); + for(MovecraftLocation movecraftLocation : craft.getHitBox()) { + positions.add(moveBlockPos(locationToPosition(movecraftLocation), translateVector, true)); + } + ServerLevel oldNativeWorld = ((CraftWorld) craft.getWorld()).getHandle(); + ServerLevel nativeWorld = ((CraftWorld) world).getHandle(); + //******************************************* + //* Step two: Get the tiles * + //******************************************* + List tiles = getTiles(positions, oldNativeWorld); + //******************************************* + //* Step three: Translate all the blocks * + //******************************************* + // blockedByWater=false means an ocean-going vessel + //TODO: Simplify + //TODO: go by chunks + //TODO: Don't move unnecessary blocks + //get the blocks and translate the positions + List blockData = new ArrayList<>(); + List newPositions = new ArrayList<>(); + for(BlockPos position : positions){ + blockData.add(oldNativeWorld.getBlockState(position)); + newPositions.add(moveBlockPos(position, translateVector, false)); + } + //create the new block + setBlocks(newPositions, blockData, nativeWorld); + //******************************************* + //* Step four: replace all the tiles * + //******************************************* + //TODO: go by chunks + processTiles(tiles, nativeWorld, translateVector); + //******************************************* + //* Step five: Destroy the leftovers * + //******************************************* + Collection deletePositions = oldNativeWorld == nativeWorld ? CollectionUtils.filter(positions,newPositions) : positions; + setAir(deletePositions, oldNativeWorld); + //******************************************* + //* Step six: Process fire spread * + //******************************************* + processFireSpread(newPositions, nativeWorld); + //******************************************* + //* Step six: Process redstone * + //******************************************* + processRedstone(newPositions, nativeWorld); + } + + + private void setBlocks(List newPositions, List blockData, ServerLevel nativeWorld){ + Map redstoneComponents = new HashMap<>(); + for(int i = 0; i getTiles(Iterable positions, ServerLevel nativeWorld){ + List tiles = new ArrayList<>(); + //get the tiles + for(BlockPos position : positions){ + if(nativeWorld.getBlockState(position) == Blocks.AIR.defaultBlockState()) + continue; + //BlockEntity tile = nativeWorld.removeBlockEntity(position); + BlockEntity tile = removeBlockEntity(nativeWorld,position); + if(tile == null) + continue; + //get the nextTick to move with the tile + + //nativeWorld.capturedTileEntities.remove(position); + //nativeWorld.getChunkAtWorldCoords(position).getTileEntities().remove(position); + tiles.add(new TileHolder(tile, tickProvider.getNextTick(nativeWorld, position), position)); + + } + return tiles; + } + + private BlockPos moveBlockPos(BlockPos original, BlockPos translateVector, boolean opposite) { + if (opposite) + return new BlockPos(original.getX() - translateVector.getX(), original.getY() - translateVector.getY(), original.getZ() - translateVector.getZ()); + + return new BlockPos(original.getX() + translateVector.getX(), original.getY() + translateVector.getY(), original.getZ() + translateVector.getZ()); + } + + + private void processTiles(Iterable tiles, ServerLevel world, BlockPos translateVector){ + for(TileHolder tileHolder : tiles){ + BlockPos newPos = moveBlockPos(tileHolder.getTilePosition(), translateVector, false); + moveBlockEntity(world, newPos,tileHolder.getTile()); + if(tileHolder.getNextTick()==null) + continue; + final long currentTime = world.getGameTime(); + world.getBlockTicks().schedule( + new ScheduledTick<>( + (Block) tileHolder.getNextTick().type(), + newPos, + tileHolder.getNextTick().triggerTick() - currentTime, + tileHolder.getNextTick().priority(), + tileHolder.getNextTick().subTickOrder())); + } + } + + private void processFireSpread(Iterable positions, ServerLevel world){ + for (BlockPos position : positions) { + BlockState type = world.getBlockState(position); + if (!(type.getBlock() instanceof FireBlock)) { + continue; + } + FireBlock fire = (FireBlock) type.getBlock(); + fire.tick(type, world, position, world.random); + } + } + + private void processRedstone(List redstone, ServerLevel world) { + Map redstoneComponents = new HashMap<>(); + for (int i = 0 ; i < redstone.size(); i++) { + BlockPos pos = redstone.get(i); + BlockState data = world.getBlockState(pos); + if (isRedstoneComponent(data)) + redstoneComponents.put(pos, data); + } + for (Map.Entry entry : redstoneComponents.entrySet()) { + final BlockPos position = entry.getKey(); + final BlockState data = entry.getValue(); + LevelChunk chunk = world.getChunkAt(position); + LevelChunkSection chunkSection = chunk.getSections()[position.getY()>>4]; + if (chunkSection == null) { + // Put a GLASS block to initialize the section. It will be replaced next with the real block. + chunk.setBlockState(position, Blocks.GLASS.defaultBlockState(), false); + chunkSection = chunk.getSections()[chunk.getSectionIndex(position.getY())]; + + } + if (chunkSection.getBlockState(position.getX()&15, position.getY()&15, position.getZ()&15).equals(data)) { + return; + } + chunkSection.setBlockState(position.getX()&15, position.getY()&15, position.getZ()&15, data); + world.sendBlockUpdated(position, data, data, 3); + world.getLightEngine().checkBlock(position); // boolean corresponds to if chunk section empty + chunk.setUnsaved(true); + } + } + + private void setAir(Iterable positions, ServerLevel world){ + for(BlockPos position : positions){ + setBlockFast(world, position, Blocks.AIR.defaultBlockState()); + } + } + + @Nullable + private BlockEntity removeBlockEntity(@NotNull ServerLevel world, @NotNull BlockPos position){ + return world.getChunkAt(position).blockEntities.remove(position); + } + + @NotNull + private BlockPos locationToPosition(@NotNull MovecraftLocation loc) { + return new BlockPos(loc.getX(), loc.getY(), loc.getZ()); + } + + private void setBlockFast(@NotNull ServerLevel world, @NotNull BlockPos position,@NotNull BlockState data) { + LevelChunk chunk = world.getChunkAt(position); + LevelChunkSection chunkSection = chunk.getSections()[chunk.getSectionIndex(position.getY())]; + + if (chunkSection == null) { + // Put a GLASS block to initialize the section. It will be replaced next with the real block. + chunk.setBlockState(position, Blocks.GLASS.defaultBlockState(), false); + chunkSection = chunk.getSections()[chunk.getSectionIndex(position.getY())]; + + } + if (chunkSection.getBlockState(position.getX()&15, position.getY()&15, position.getZ()&15).equals(data) && data != Blocks.GLASS.defaultBlockState()) { + return; + } + chunkSection.setBlockState(position.getX()&15, position.getY()&15, position.getZ()&15, data); + world.sendBlockUpdated(position, data, data, 3); + world.getLightEngine().checkBlock(position); // boolean corresponds to if chunk section empty + chunk.setUnsaved(true); + } + + @Override + public void setBlockFast(@NotNull Location location, @NotNull Material material, Object data){ + setBlockFast(location, Rotation.NONE, material, data); + } + + @Override + public void setBlockFast(@NotNull Location location, @NotNull Rotation rotation, @NotNull Material material, Object data) { + BlockState blockData; + if (!(data instanceof BlockData)) { + blockData = CraftMagicNumbers.getBlock(material).defaultBlockState(); + } else { + blockData = ((CraftBlockData) data).getState(); + } + + blockData = blockData.rotate(ROTATION[rotation.ordinal()]); + ServerLevel world = ((CraftWorld)(location.getWorld())).getHandle(); + BlockPos blockPosition = locationToPosition(bukkit2MovecraftLoc(location)); + if (world.getBlockEntity(blockPosition) != null) { + removeBlockEntity(world, blockPosition); + } + setBlockFast(world,blockPosition,blockData); + } + + @Override + public void disableShadow(@NotNull Material type) { + Method method; + //try { + Block tempBlock = CraftMagicNumbers.getBlock(type); + //method = Block.class.getDeclaredMethod("d", int.class); + //method.setAccessible(true); + //method.invoke(tempBlock, 0); + //} catch (NoSuchMethodException | InvocationTargetException | IllegalArgumentException | IllegalAccessException | SecurityException e1) { + // TODO Auto-generated catch block + // e1.printStackTrace(); + //} + } + + private static MovecraftLocation bukkit2MovecraftLoc(Location l) { + return new MovecraftLocation(l.getBlockX(), l.getBlockY(), l.getBlockZ()); + } + + private void moveBlockEntity(@NotNull ServerLevel nativeWorld, @NotNull BlockPos newPosition, @NotNull BlockEntity tile){ + LevelChunk chunk = nativeWorld.getChunkAt(newPosition); + try { + var positionField = BlockEntity.class.getDeclaredField("o"); + setField(positionField, tile, newPosition); + } catch (NoSuchFieldException e) { + e.printStackTrace(); + } + tile.setLevel(nativeWorld); + tile.clearRemoved(); + if (nativeWorld.captureBlockStates) + nativeWorld.capturedTileEntities.put(newPosition, tile); + chunk.setBlockEntity(tile); + chunk.blockEntities.put(newPosition, tile); + } + + private class TileHolder{ + @NotNull private final BlockEntity tile; + @Nullable + private final ScheduledTick nextTick; + @NotNull private final BlockPos tilePosition; + + public TileHolder(@NotNull BlockEntity tile, @Nullable ScheduledTick nextTick, @NotNull BlockPos tilePosition){ + this.tile = tile; + this.nextTick = nextTick; + this.tilePosition = tilePosition; + } + + + @NotNull + public BlockEntity getTile() { + return tile; + } + + @Nullable + public ScheduledTick getNextTick() { + return nextTick; + } + + @NotNull + public BlockPos getTilePosition() { + return tilePosition; + } + } + + private boolean isRedstoneComponent(BlockState blockData) { + final Block block = blockData.getBlock(); + return block instanceof RedStoneWireBlock || + block instanceof ComparatorBlock || + block instanceof ButtonBlock || + block instanceof LeverBlock; + + } + + private void setField(Field field, Object holder, Object value) { + if (unsafe == null) + return; + unsafe.putObject(holder, unsafe.objectFieldOffset(field), value); + } + + +} + diff --git a/modules/v1_18_R1/src/main/java/net/countercraft/movecraft/compat/v1_18_R1/NextTickProvider.java b/modules/v1_18_R1/src/main/java/net/countercraft/movecraft/compat/v1_18_R1/NextTickProvider.java new file mode 100644 index 000000000..744e2d379 --- /dev/null +++ b/modules/v1_18_R1/src/main/java/net/countercraft/movecraft/compat/v1_18_R1/NextTickProvider.java @@ -0,0 +1,44 @@ +package net.countercraft.movecraft.compat.v1_18_R1; + + +import net.minecraft.core.BlockPos; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.levelgen.structure.BoundingBox; +import net.minecraft.world.ticks.LevelTicks; +import net.minecraft.world.ticks.ScheduledTick; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.lang.reflect.Field; +import java.util.List; +import java.util.Queue; + +public class NextTickProvider { + @Nullable + public ScheduledTick getNextTick(@NotNull ServerLevel world, @NotNull BlockPos position){ + LevelTicks tickList = world.getBlockTicks(); + var box = BoundingBox.encapsulatingPositions(List.of(position)); + if(box.isEmpty()){ + return null; + } + Queue> toRunThisTick; + try { + Field toRunThisTickField = LevelTicks.class.getDeclaredField("g"); + toRunThisTickField.setAccessible(true); + toRunThisTick = (Queue>) toRunThisTickField.get(tickList); + } catch (NoSuchFieldException | IllegalAccessException e) { + e.printStackTrace(); + return null; + } + for (var iter = toRunThisTick.iterator(); iter.hasNext(); ) { + var next = iter.next(); + if (!next.pos().equals(position)) { + continue; + } + iter.remove(); + return next; + } + return null; + } +} diff --git a/pom.xml b/pom.xml index 60a0f9f1d..13158c423 100644 --- a/pom.xml +++ b/pom.xml @@ -7,9 +7,9 @@ parent - com.destroystokyo.paper - paper-api - 1.16.5-R0.1-SNAPSHOT + org.spigotmc + spigot-api + 1.18-R0.1-SNAPSHOT provided @@ -33,7 +33,7 @@ modules/v1_16_R2 modules/v1_16_R3 modules/v1_17_R1 - + modules/v1_18_R1 modules/Movecraft From b3ae205a4b8fe084ab5e4b9187b78685edf84089 Mon Sep 17 00:00:00 2001 From: BuildTools Date: Fri, 3 Dec 2021 02:28:55 +0100 Subject: [PATCH 301/304] Fixed rotating signs --- .../movecraft/mapUpdater/update/CraftRotateCommand.java | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftRotateCommand.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftRotateCommand.java index 69d8cca6d..406fb3629 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftRotateCommand.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/mapUpdater/update/CraftRotateCommand.java @@ -19,6 +19,7 @@ import org.bukkit.Material; import org.bukkit.block.Block; import org.bukkit.block.Sign; +import org.bukkit.block.data.BlockData; import org.bukkit.entity.Entity; import org.bukkit.entity.EntityType; import org.jetbrains.annotations.NotNull; @@ -290,15 +291,20 @@ public boolean equals(String[] a, String[] b) { continue; } for(MovecraftLocation location : entry.getValue()){ - Block block = location.toBukkit(craft.getW()).getBlock(); + Block block = location.toBukkit(craft.getWorld()).getBlock(); if (!SignUtils.isSign(block)) { continue; } + Object blockData = null; + if (!Settings.IsLegacy) + blockData = block.getBlockData(); Sign sign = signStates.get(location); for(int i = 0; i<4; i++){ sign.setLine(i, entry.getKey()[i]); } sign.update(false, false); + if (blockData != null) + block.setBlockData((BlockData) blockData); } } } From 1d042c68c5ef3bce56fa0fc47d0275e1ae11404a Mon Sep 17 00:00:00 2001 From: BuildTools Date: Fri, 3 Dec 2021 02:29:58 +0100 Subject: [PATCH 302/304] bump version --- modules/Movecraft/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/Movecraft/pom.xml b/modules/Movecraft/pom.xml index 84886ce29..6deb413b9 100644 --- a/modules/Movecraft/pom.xml +++ b/modules/Movecraft/pom.xml @@ -10,7 +10,7 @@ UTF-8 - 7.0.0.3_for_1.8.8-1.17 + 7.0.0.4_for_1.8.8-1.18 From b34551ad1c88de9ddddd3b5cf0ee7d15999c3aeb Mon Sep 17 00:00:00 2001 From: BuildTools Date: Thu, 23 Dec 2021 00:42:25 +0100 Subject: [PATCH 303/304] . --- modules/Movecraft/dependency-reduced-pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/Movecraft/dependency-reduced-pom.xml b/modules/Movecraft/dependency-reduced-pom.xml index fe6fff449..aea3854b2 100644 --- a/modules/Movecraft/dependency-reduced-pom.xml +++ b/modules/Movecraft/dependency-reduced-pom.xml @@ -4,7 +4,7 @@ net.countercraft movecraft Movecraft - 7.0.0.3_for_1.8.8-1.17 + 7.0.0.4_for_1.8.8-1.18 http://github.com/apdevteam/Movecraft src/main/java From ff2dabdfe2cfc7089fae6fcd300edb94731ddd38 Mon Sep 17 00:00:00 2001 From: Yksteldus <28742897+ykgamma@users.noreply.github.com> Date: Mon, 31 Jan 2022 17:05:36 -0500 Subject: [PATCH 304/304] Fix issue of redstone blocks spawning under ships - Make IWorldHandler for 1.18 properly use chunk.getSectionIndex where needed --- .../countercraft/movecraft/compat/v1_18_R1/IWorldHandler.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/modules/v1_18_R1/src/main/java/net/countercraft/movecraft/compat/v1_18_R1/IWorldHandler.java b/modules/v1_18_R1/src/main/java/net/countercraft/movecraft/compat/v1_18_R1/IWorldHandler.java index 958378730..34d7cdbda 100644 --- a/modules/v1_18_R1/src/main/java/net/countercraft/movecraft/compat/v1_18_R1/IWorldHandler.java +++ b/modules/v1_18_R1/src/main/java/net/countercraft/movecraft/compat/v1_18_R1/IWorldHandler.java @@ -154,7 +154,7 @@ public void rotateCraft(@NotNull Craft craft, @NotNull MovecraftLocation originP final BlockPos position = entry.getKey(); final BlockState data = entry.getValue(); LevelChunk chunk = nativeWorld.getChunkAt(position); - LevelChunkSection chunkSection = chunk.getSections()[position.getY()>>4]; + LevelChunkSection chunkSection = chunk.getSections()[chunk.getSectionIndex(position.getY())]; if (chunkSection == null) { // Put a GLASS block to initialize the section. It will be replaced next with the real block. chunk.setBlockState(position, Blocks.GLASS.defaultBlockState(), false); @@ -301,7 +301,7 @@ private void processRedstone(List redstone, ServerLevel world) { final BlockPos position = entry.getKey(); final BlockState data = entry.getValue(); LevelChunk chunk = world.getChunkAt(position); - LevelChunkSection chunkSection = chunk.getSections()[position.getY()>>4]; + LevelChunkSection chunkSection = chunk.getSections()[chunk.getSectionIndex(position.getY())]; if (chunkSection == null) { // Put a GLASS block to initialize the section. It will be replaced next with the real block. chunk.setBlockState(position, Blocks.GLASS.defaultBlockState(), false);

    TPfKQ=J z+sQrUJUf&ped1&$a6|+-pWY52`Td@vMmkP}pGq}5+3>`4_!VPmL0D0j-2Ebd-Ut3t zKP`mu5(}CQk-!{_;fhR}wR2*98L`Tu%O#a~fLt0)RbUxP=@q{d#$@ zuzhUYyYu;jgY~ItXHVmJcC3Vj-c(q6_56T)eOR0x!Vetuz=Rd+fk1?XO<; z7$+B0Gv28J+rUq{6Y0Gwd(u?(+lHsXI5chfrUCnvuM#$6==Fa{O$K8jDqAIA63LpU zrNwM8;@NO}RCw2NZRB!lzJjR@5-TEP;56W%8IY)t0a_y@;)GBF?Cc6emT_50}tD zuw!6`z7ntCUIvD8ZUJ_O;fJ7f$ZJ}lsr;q^OCz89$@)OdjFrtEq%m`j z>a~t{_S6;`O$Q*R#Jd#yLmC|ThnQ5{4={A2;*#vmBIOq*I6BQD;TL*+BPpAtzi;%6 zRHE$J{)WYRFx{#Q?w7mKn1~1NvOM#~zrTCvegtwJLJ%atI*Jh)oz{n8j`oY4#nnR8 zrywa)xYL9u(+o<`rDoSq;MX*U7PXD^460B5tW#m7AG66**2toI_zlg7Quuy#x;(4& z_A4QL$QZ{|8#4wt(frHnuQ|hY>9em)8#hlnD(WXZ5nwH$rdjEfQ$$M`(KsvFGK(V2 zV6FT9Fl`#GTG%*Y3f+cOf-9X{F*3erRh8Auhg7_kY*nxcCfLtYk}B9;$!EyLP} zupCUE{CNz%DFgpH7yKeO{Z~BDvO;jmsi>$N|7?$leN(s*5sCTuivY@NaPz)U(4Q+@ zybiaiufip%6J85wW%Y*1`bpY?=)8`+IKlvlm zWh?iv8H961jQiN+uo(uWOCpbeD?0r?$^r7T1J?vV3dfWFPxO{-s%1*?3Q%Kn!Go85 zEDh46VMfK1KEK?k_LHfaj}74F)d;1#uf+z}JStKgS9D7$m7<%{3R}DK@RWU=R89%S;|1thk;p3rJGAp4kS`i!mHuK; zMG~%sW98av$W-ie#G&06w4XAj;k>p5HRB6SH6~zmik!Sow$az{b|<8GG9v zHKM8aJWZL2hB2g13=^^Ge$ll?ucR5S+sc7i3&5I`RSwAe=^$e$0ezWZA*I;YKJ;M5 z2u3mHkTV!@Bs?wU=t#!088|8@YGg;gW14HjEY~k?jMUp&Q_PRNn~?Dc;11P#=zj^_IJi9PvEs{zElWR7%(!Nd4Bjxf~hZ2avrfj*~+C<1%&hy6|a_)eucSUcQtH_of!i_2fHuOaWg z^^o>!c7GGv-#0%5O#L<1x7jg0=G?S17i_cNeb+v!TY&hq%f_(Aj zMojw9&FG)jd{`A$6N=_mYpfTzT1fLizVtIqufVbErtARA2JAOYcP|~e>3bn|*`I5y zhTW7CE$TP6VxUQ1gWMYYy3JPD>f>oVeT|Q-#f_Ynmpz1sNAa5H;(fNutBg;_tfSPf zBaJh5Z)+({H)!qtj%%W{DVYdalztZ$i4B?~=<*`!0zla=IyyR$aJAR>Y&Z{@g`eo( zi25m-2$st*(@JTt0=x(m%91tz=JZ6LN&A$j8|G?_6EwvZm)%#goOZQYVSoxNRz0og zIuvbOG_L%YVtxujt-YS!{Xxc25Wt_MN^|6}<9ZjC&Kl$IvhEJHkA}{%Bkq<}BBL z=D5fAS9+gvuXumszlZ(QB;3(23x1PyjUZNL4=V2$DJL(etH5l-D`+w+2tF!kz$%Dy z8?ao%G`FG&JNeEc8$JNn9y@1g1hAuET#6agcfnxMHjm5-yWEE-xGX>+Db}9pwr^F98gm3u7 zBA&M%^LRmog-;3Jfjs*pKc)4i?P;wYNOXd{uC`O+)a($UJQNKqzuhi)I{z$g5X+5q{`b* zpdl_ro*4SE5LkUKV9v6k13Satk>xM*A4M~CX>ayFiZ*?k70e0$&{Mb$AUuh%XAly5 z$nzAlf8lP5f7mlHL5ucjZU3oci8ueoDnXR6685+*9~qZlw^S;+Kr!1{4b#7YYp|0( zF;tk~m2@AcCH9g>{w#_1LtUxjlD7qwzh33J|0FBhYDsx?yLqU`)XxQGn{ed&YI(PD ztS|gWEWh(lKMkZXjiQC(>>>fAaE%qJ4?E1yM;5tjs}H^OI*U$X>D3WI5_Yz~QI|C8 zYH$5HjH9^nN@Zk@WAE{TC4EnK>5m_+yN}hJ=J|rV)cm>)sB=Pswic8Soa@$dIYtQn z_86al!YF?tk8Vke3?|5Zi!^`Fx9aPNu_bOs_(T1}Ry0$=2Zq!K*(M^*;C*fi1>ful z#cN21ptSPP2ydo0xop$MYK8Q~#EkDhOnomBAag37TTEfBCT>MzS4Mz;54P8Px_ely zF0>rFWl^n7qM0QdF$tx*ZYm4(11zdz3nRf1e4Fs%FaKOf*(}oTy#&5L!3+F#ijN|p z;25=bl;+d!mHgLTTiqb{`_m`I$Kgk>FR>@Azr%^QTF~ ztKrA?2pv{H;g8QG)NxOtL*YIFE3(C?-N)40k00OBkVM{TpLDyW4KRU=obWdLsp}*V z!>A2k-3t<2YwA)o=QcWBc^E9S-CRo!__vcPgPz?(Pz>dt;G!_j-uat~TuTTDWxV17 zcI6*&HB#m^g>R2+V|sVelqWq|JXaw+@o3uE8~FvE5p9n(L({{c3y* zA)&Z8dC@sS>})AMOkJ40L5N8CRLo8JG_ZJ%Lqa_wrXT$%-%ZKwe@itE)H<@xFI9aBM(g3}I}?E$mH6$b>&(d_w9#F3A6O7VyuW| z*eLxF4|EwH`fA7+CkE{_scLtq;@5#_-~F9gW;U)qt=b^_&bYEcZz}5k+mcKTB7LFY&Ub_lMi9Z5C!M!V*sEuc4cIHp zRzZlJN_WVfa#h%!qq5#9iJtS{GHb#_eI}4c4N$c_AuKRhAW^06`7yzBZ995u7lt2v zYlzz$oc*_tzY4EuKeV}Z%+n<^o=spCUD``oVJuL|4qTY<1(wDl%g)@1w10#4Vx>B>3hHNQm9(dH zt4E4ExzH@n9ZYd zlpB57>tuuevciTUOIIQ_9g@zf#ZtNv zY0FFuG+*eYOBC--q7F!`M0J+-G|m;cxQ%h@PY}9bG=TD%?HHCXa*c}}GfKeFEiX=( zQ~!O17hk|K@s3p&EW%y5W{F^*R#z&=J!@x$;Bd_g-TAWqPQXV3_X~*R#f0xycB};T z04vw(jeaPUtKq_goXyW-LltkEe7bO6!^I z5!n|~S-y}2FX2Uju^ch~>}!;=tF>50~ygGlHiYTC;WeT6#f2q2yHHg+?GpOU67U1V^ncQat>wfx-p;zv@+ z&nUMScbCQ2SruX-LEk@$bty$1qOGdS20Y0%GvSWK0zsJ~a8mEZ!aPBA?^oKQRc6qR zz70XG-M{zT*0^Je_a^T{F3M``)(fi-HB8Fwzu zIv4{pERR@w6=cpnu`=#CFJuV?SUR77>UXmvGG`6r)kax^eaDgSl4>npJ`I>sc9c4> zWomg=qJ^o#Eu~2Li_nmZNvM;eFhndP!sl3iEZ`L9Q{fPP+fPu$G7HNvk}iWLLSpZ) zS437<@^t+X)Rcd;LNJDu<>16Td}?N*q`Z&L+sI)VUJ*=Kf$Ubcww>?7hglTs!Dku1 zCPdUr5_b_r#b7l{8m|^Y2~B5R+M#k_zs~qdU;Eb=w!C!KgAmW0kvS;y-sh+LVLF18 z9mb>&E`6H-y;C3AoRFy5dacElqVELj1+f|@CA}8gLW?$(@8^clW*W>{Sh%=d7k58d z4ehD_MTq#g*Q!qcUWjqn!8)no?AeJq1>R5Mn#Xh4w~wm+y@7o`LHaccq@TkAm0%yh zA4cddc)ph%3NlFZ0;ZvSV#eX}Rs_ngS*3P^Gi7g@i*|8pe-Bh>_E^dj(F4deYzli^*X8N6a--7m^$MW=_J5}KS zqM7y-HnFw*PuX;~>bl)OgDO9W%W*%W@hhBrMv72&QI#~YA}L&Xln~jkwjWA*9!`77 zpdmf%_1&8&k3isVV6?{$)YFfF%EW*9d=;b7hl%s_bbj;UkL%lY_b=-f2l1l6!^70F zE1RHomX&&ukT}^ZSq~C?nW{I8R!$N7dw3e(10<^nuU7B?lH^Qv30KJ;#X4HUp{^hbR>uf>%aD^%m0b>>t59ip)9v^;Mo){k5VYD3-ha6$~(u!h@(}uw`CU zMj-S7(n%TqN)MIj?kSg(r>8rr1iZUCyA5tF$+58>Hx8H}^TlXle*i(+o9^P>=Irs@ zW5B_?yBTp+^f!QlCD*+OCdD3M`HTw9awe&->0dt5A4zxXaCD&5ne#6-_vFht*qblb zHkD(d7DwgZcd;_)h&U?;5&4PP@*|pZ>~7Nfj@)2;{HADB`DCf?2W(EIKz+!UZ%r@M zwQECW((jOm#!D=utve*}bccdJxBoB2-ON`;fahjC*s9!^nnd z=UT4-S*7==^UIg^35_lC8XqZd9E^iTNtjfX15BObmMCk@-cy(C;*Js!_W!o2j!rMN zOEY}=(rxzT3*Z0y6#kEea?!`rKvn$4U+q!m$n=K9P^2|(H$e!!K!+^#4=QsSl+>3t zK%z+kqO4ipL`c7yV^`e0fMJ&|t}7Ze%U2~;ol9eWbq(D(UEP|+MYUxFrEazNEuGPj zuaA$@_N%`0HSHbk?d@kOi5u&q5a5E;wg+?&J8xYcZMatZN`Fx#CzKxJYmo70kLtnmqNOT zd)vKkEMkaq81gItPsA1#%Me|__d*xPBwYX&H~k2XF5qyft$m~++J_}p|C@`CF193V zu<^N3XIjrdWP93xvO;sDu`A0Ua)Vd}V{Aioxlu-}y+h(@ds;7$)zy*jb82qTM)&)g zSUlrVE$ZNeZMEFQ{x-&Wf!IV#G=@0Ma`LKpTiMPsbi3vVFgi`SJeqcC*GQLscQ^HH zk3yHeA@Z7d4NX0? zn+sLI_S0p%UDwk6>Vmc)E``m|t~pG_9j>nCN{x8bTA-WPSTDQqxv2EM7or-PStl%US}=P>Ub{H-CR}TL&2n!D&G^nO`~8D?Kc=&Ng2@r9?cT>}WyHZldwjCb0Na0l zgs^kHGOC{Gc6r2L8{~NVN7}&NOs`{%sWs}iy9=?M8}yYawc4$fW|uZS@_Av3^yW-5 zm%;VINbpCm7B;fWRG52%5_a7Ap^AY(Y1C&YAY1P%LfSh>+B?xGuQ94@gk9e|m3Z#r z(5nj&m^M#k*c>6eb>NlyN@>tt9i`<4s$}{a%rRPm%-A$?2LYLOmq+wEU-9*3x2BH? z`Tdx8E$F@Ci2cvTgxe2&{e1e-|56JJnX?KXE{<&L?>OmvCE( z`7Q}qz%FAa#<8fXDsu%Z?+BAxNsN(umwb|kU-8xAyah5>oMGp6#S}uUJQBXzY>&_>>FBACk1T z2~cNt{!~O~cJb6ir+{XfnwwWPQ`w~}UQJf^EP_=$??gtYK(4>lg=;Gle118897_F~?OeTcj{y|8jv9PQ84fFko6b zaW$x&Kan-4T|AlStX@5#?R2|nluB#qtX?Y7OMB|HpSLJt671Bknd0nxylj+76Uutr zGH?24iwA=!8b1349ob!LJWnX`)8V<51Kzgn4GMu1 z`+Dk)fz4ONFQV=k<#^ONbz7S#5GByAc0##l-Jc=QZY(c?z&PR9joeJGu1VWd4Jy}xhxh#v)HnPr#~J))=zfKc|7US;Vv^QLv;$MK6%H7}w}3onEP4R`i0Rtr{S#Y_>1( zoK0^x#N@2nX|b>N%`^zi?+RY5AS*++ur}0nhd98Mkw2R5qBurs7xUw)uur-MVJE8( z(~G@ytZ8xm79O2t#PHKlTk%;?G;f7kKj zwll;6w6Y`s9074Vc-0EeAH$8bEvM5Ct`EgsXz^)G3CE}sWFe>~4%P>2Ek3L^1G?Qc zny}LinSKG#*yhFTn+_?om&JOwk8>@PinFjL8EMfa&dac5YUWJQ@d~GsvD|*!s3#^( zyZxYLSop!sCEZWsI58_ACV|M3Y}9eqt*}Vzg`%G^Wxw11*70?Yj>4uNOQNCYpwH2E~6)Ew<%HODc zs!A<0jDb*|%X1nI-H*>LjJG6dxB!~Ub~r8wd;|B}a3s?eNcbX2q^d6%sPhCWItuA` z>GI~sT44L`b&-2*jHri3VRKZRrE}TqxbU)@skGL)TL|1QMRuDCZdF++8%#p*ja&`I4(v^`arCH&)qW8*U@vZ2H08g7I*b(3Kyi!T$M$;S~ z2*h*g=h*N0x`|94>fnok0(m+H#^dlOl2DFk8xF(n5J|vp?XOs|2vX*RG`t74?$n3I zXLOe1lLrB`8-TbWDQrCF>>h%>=pd0ytK)dp@d}hsOdEcC8gbmcneeV+6^d$=>An@9 zOTo}=-0sAk%d3Z!dx{bGA=qm_j(;4(<&{M0l-d^mFs@Lw6DZPxxma~2Ac~oEQUmN( z*!?LtR9McVHRLkezqQO$>a=-$1N;c?9_sJgx09$TsNY?*AFpAvPx8b&w9b9w6p)cl zsw&v5u0{Iy+|d~7BJBl`2*bFxH3s)sVA3UlEU&?qdS)muK`GsFSv4K=Lk!AzBkQ@0>t8$cb7W5)*rYsFs5p* z%BJ_JLg-M~H50wEvg=b3NilWL(`)&&e{}rtFU*QY3#7wiH znA9ESHpP}!P?)Oh9HA(h??B>zGVbzWB^9vkS36MH8Mj*Qk;KVnvZ89mU^%ZXU3&>| z0v9n|@HZuaSWRO7`JEM%IF+?7NrZ`V!eqpp$7TTL5;fp9Gck9YmTj4aZ?wYKM7&Zw zf26~MjPBj%0WAGQlQhyi(_~%)p_<*Y`6aJRwG{MBC6;6M z2UWP#<+31i`5ofgn)13hC$@?BIal;7PB)(&j1iarC^xIJL61iWZ`nS(R7NbvQHiQ? zkLw|^trKYoZ;d`9R7RY~M#pwsZ=Iyybe@#Wgb+yfn{t+d|jK0 zq!=~Ie|1h6OoZF+iz6B5FZcED;P|d+__$uT-6!Yu#>*#uuE$Nl^>i2Z0D4xtU`P#w z*s?GAgehaBQ{(U+9NuCTdhL?#a3Ag-h!HC9wvM5JA7vl&@x&8xw3Gr2Q}OieqX=x0 zRMVfDex~C}3HxPj8^g`F+J<&oA(tdN^gY$#>L{+Ca;jupEK&uE+0ba!9c#Y=Gkuu8 zXIRhS#rOhszSnr55?bIRRuBO*M zsxUaxZyP-xD930+ zA?`=r*ET_n@Kz)s5||9lb*%J|PwJoAhw~5*1q5c25HC=K^4jHhx(IwmAt;b%b1()# zSC+2Z%`9uGs~GC2=-OM;Zc|9Ynp;<7#;A#_5e)7Ed?gb7eM5B$FD#@Zt5bMFALADJ zD=Elztt3Sh))uXIGk4|}X~*q=t3#zv9L)%fOY`0~Na9nA-g>MH*LXS5H?RndS$6Q> zFN9DLSi%M=NiWuiI{{0&RL>5YgG>z{1QS7>!J>_Fgdg4B9zjvzdMNqF(nXEQ!5YSj?F%a8<|XRBJUNFc0a3XC1g7@ z^OoE+9SBO`b-~HY)EHS!lDE#BY^{%-uvuKY^HlXL=q)n#Kavn{ zv>hS~2**hF>U>L=3GTVOevobgpVZM7H=)OqR}-ETEM}0-I9fc5wZ`x2sC;&`XDZi9 z8~&F5s=|E`$l_X>k3Dm-nviqYv=^s8P9u|I3x3b?D#_x)=sDyxy*XsldR13HX`jlX zc?gq<+E(~-cbw(Dd~2tU3>3vY3(iK#;6(uUH;@zY>gUPg8k>)7>ELq6Ey&4Va9kqV z+TCb=19}u{+FDyw#}sw8(H0w|6{P$zrw4H9G{kIOi}bf7cseyp7&z=9IDm(B9UHHYDnklC}ChPdu2)q#3bs|~1uRa-X3eR3O zn8q@S)7V(km?Z}KWuPRk=FOQxbd~;LF9nQCsnW|S?Sf@Bw%moL$M#Y-gY%l!^spl2 zrPflSNGB_(?fR0a^87kgT+M2LI+PtuWpcJW+sP>m$4AGzA5{1JXyOD;tuSUZ!X(B{ z9$mJyj1 z_UgC^<{^ow%bdy9qSkf^SG z>BKvnk1b$FL9|~Pi~pyj7qjK6nUGbCKrV7+u;rI(8@gXm{Nq;XjixZMS&&Fl%clfS zo(2bmOlUTCKHHi}rLq;A&XhM_fwS&`PjB#xVq_zhu_o= zc){-Si@;Px--Si*tPo7&4%8W(%w#okMdHo7OfSVz^v#+LEy=l1;O(O&&732qp_Pt$ zq5boH%{uKM$B8PEyWLJtEZdxiZCJiD3?T<X&H{$M0e`dx})7nol@z*dC#Z`W+ zk{bRt=^uH3_3w=o*Xd^qLEM8z{uHwbMW2dLTYb+ByN9>H9u;a-#cXB!2V^d3wf-r*=U(GAy)SS3` zPPk+syxzWkc7TqFMi!Oa*-vQw01<2+amvejBVk<|X0b|eV@lZ7dd6B)B|x1kUj2(# z)H?p-Uo^7KTjO|wON)1wU|Dr>Hrw|t{A%nCN9c3O*VAo42iW93rX}$TqgKZ13a?q3 zE@}P2I}iuAV4npWeB$Qle!OtB#x3kMJep%8_*7dKfov8VI$-q^;UZ8q3d>VcaO?Gf zRmRCVeTD#zHNi&yd{X4nR$j(5CtPj-)q`{)8NFeS=&N1Yy_$>%Ia>rYI7O}GV=g!* z*;TUa?fxPC=98##%jDNklTK=Gsj7GJtiX&*+7KxjH)u4&r0Z>TNS6<1jtvG;i;8|YMuk^JGv z=Yw))W`AD zLMf&bR4MmC-O%_#DeR2oJ-JF*ZiVJa^oLet1k@t^+TL58OE~okRA@?X+utWo&k#!a zIY#9!sI*(s|GiDmU%}40cy*VSNmN{1G8IL)-Ur4^Vx6LY7t?~Zupaf{MrF|nmeF~g zQ9ot0FPBs%C{>TQmhaiuY597qV&+q1Qti=`)~9x4;yR(h91q!Tv5h=eoh^R}zjn9Rl`tBk|vB&j8uJ0wx_F01A6WUXDgwAYqbCq8q8uOv_>MMy@DvqYi&4|1i-+OB4DJ>RJUIc`JL3N}DCiKA-L3ZNii+A#-|8 z#dPd(8|q;2mcK+SEAr_>v_HYGAd#Wr^3}_bcvB-GltH8Rgq$IAf9pQ`IVR~*s7Q}^ zf{+T5N31w1rpM>a^~nOr_wP@Hm6WP;M>oTM#vhZig1%g7LaY|WKe?s*cNK1oRgN8b zM3A(5=G0gX{Dq0O6|Kcn;o)Q=@5qTpj+JI4x>HQ*J#KW1)zp1FB}%lH4aBc4^K@)T z_-ZGns93j68S#}z@(3lu754Ten_mgWaa{OKD_TKji4GjHiFX{GZ9Q@COi{vtC2bq- z>blAHBb|a{ibAm_=PkY7e4SYn%KBf)3OzL~|K#51#YtvK;hTcX%4M|F-nMJQF8rTs ziUO8oeRzn=P<;7{7ygpFO~pGlVr3bw3_lvOW{r_j7nst>efCx8X7Gmk&qj|$h-QqWw-8} zCEA?6mAGy@p6;wRC+g&z=o(9`KuVXEQL2Q;u%v&|Q`p84^sIBuV5wXYELVKdM^!Cj zCtsQIw;Q%Ff}_b<#90v4r3o9}p}LLvS`Gg$coV=%k~0`k4xRg;;Y-<_!p3mvfm?;T zlQYeZ;~j(<%nF$XV4ZqV5hvvB!!bD;9(kxS{H9B~y&3ioK!FA(L;_DbzH+Q z2$mJc@*UphJ@E}8BN@pW_97tEbud9oeSw=bPr&{DsAKSR@oi7>Q#gB|LAriGej3d? zlUutX4wtU;lN)^J?b!%YSBZtoYm<_Y>W2lvg5bc<@l*6_UPmX0VoZ6W3q@vL<4Oth z+%=;iD;G_&MK3aK4OS;Zn}&;|n_D+3!T}rSX8gROilU&BS`iQ*rs|SR?t0b`diGK6 zQ>XT(>z^g4kZKaUB0hvhaLZx&qwV}*kG6Fv5@UZQ<|5P0^HuY9Sd;1aacO;0?I;#%F!M!2-ZPe1#WQ)pYiuy!X~`KbJ#12mB!m zCd-a+FFnz7W%_!`XPiI`-nj}+BLO7m+z!`{{oC)N*UAcW1y)M&kJVs^SV2fp_xj#f zW?Z9x?tQ>CIs-z)O+82r%^Qb_mYGv7S7T>1EB-iq71D=vVt)x$|sm62FLK@N2<7!Hu$FrrMehrHbj~772n@8 zp!eT1=(x;7d9>bKDi7AL*uM)Lg-Hfg9O0F2u!fcD4Oq-WQz?b3hnN6LYXD}-4T*oy zWOD~scV@B|qM@BlSF*;4ors#^4g%lj_&eb53#!Vf&5ktu9d*JQT>?T=5^Xr1$bV=F z-%z2i=vEh`I-Hdste$&V=^{}ZR@9F>KR!_=AD%`0LuOb4;C`SGg$AAoIDQe~P>}eX z2eSwz(2wy$wf&E^Iw?xLq8%5`BdDp1VD{8;NWG27?AMktfIfP@mDR=kKbK?~0lGk* zO^QT2H0VJ2Yfq6_-LD8fz>U=@iNUCmRd|W-Gg(+_zvvGRNh#dU{IIIAo;XO z;o-cR%Q|Ax;JsF6Pr|lc?v8DulR$}!i_#P`fwe- z25W*d<4y@Hcp5elq8*Q(LbBnCk1xz5%{(y5FqLQ+0{f^h4QwDno!f$2I_T0c{JvcMl#077ku)jk~n zsWxz}Vx`Mj@Pp8iWT`vB=gaaMy6q6Aop5Y`5I_*(g0vlqc`vPxv<1Rw$L^_*D&7*! zZ$*!w?@*xsBHFyy1faAHh_~ZEANTvhbmAsNAtsBXgbqn_eJR;S2u{XL zUA(kL7T;jIpsBMDhU1cHB(rFMpR`7tB6o_?EofwjTkWFLDq0(Hs6S5D)UI58r8rEi zY*+qloV38>tk54FRat?W%3#hgH5`W0iU&!0H4n;;RfcosW}lU7&Z(VG1k>Z%F=&y> zgqz(gvY1!G4esyC?}_pe!kLl8751yI!+8cqS-!zs#|7E*rhx5Itouai_9{5+6|LTh z2<_hY?MZ~sS(7N-8hF4cd~Zl&$PB@FM*Sz)p7d4oksXHd4u;XQWQ`k5l*u= z6llk(@oxnSyn0}yQ6 zGe+!AATE>I_@GkE-PYu(K~z*?TgQb}b=v%4MRpyy=c;VD(R-r<>o9jKQTi)9mp2#e zYWo$6zc9fO#tY$JD*3{ma>zR~0?_F|ciDxZ^dKUgXo|ajS=Z)=)q!vO(8C7ZJW>K{ zW>rU$|6SWbt$6mlHib>1{cArd&PES#xGTkHQ~z5bB2xi!`XQJ$@J9hrSU)5W2Gf8^$g%W*rr0A(EX6PpRXagT|eT+7~VXH5#%c&`&G~JF>&gRMXB(_-l$pg`5*`?)3cg)?v*%$iZ6vs;% zBVcM7&kA&SlA*h|2-UZTI>YX$oWH4)TM*;9U0#fvk|j3oyo3d{ZR7R02*({}bAmhW z#2W0511zr&)V$Pu%0%_jfS1P7f-)5A44s#F9`5`2g0l(VGm1F8b$vjZ+#p5&V+?aT zL=o9t0^mqKkkF1yGQlK*H_ZM|fd_GR=)xIuHYDpFpgX72j1`JuAxATaHI($6ndUektitkI3F@!^qmt?;0?#KNWk)dA;mh zU3qxlW+^P2`Z@4hdXKX`DbuHS3^JyPR~QtsrYNJfR-s-(4y0>0Yb$};Ko=(>>}sl) zmVsE7?#Y_zXqRT(F3-k#tk=b>&sc+m@oy2FFBJBL6I67@=uB(7Tr=*8l)^>?B3Xw` zwnBV%BteH{uW|?pN`l{m^(+hJ@LnO%D=?oOMTuNo^)Jh%m~IrznYszOkbKug8OYuTdu~JtqAw2K|Z9-DQPy`i?=Lr*gHa{|fph6N#gfVFUO7n@$ z+dHCBN~OMe-!PqfoEeUQ7OIG){;Il&FZNBszK-=EB{vnJNt;v2qm zqd%oy5qJMPTU<1ZZd3W*s(8_CM;^Lo*@aY6%YDbPP$NG4yr;Aff~LWfi`)`)M#fUz zXQXD=4u5w>C4Hi!%MGk z4SVl^bS0|$h%^~&&jI98@JCPDqrh3AhWza4RZuD0>0m?6{i?dywvCU^GxwDzDs`$; z+aSM}P0hU{k;*Q+;K7~TO2L?L>gkjwKo|k(M1amtOf3t!H6T~%^IL|0^mm!9 z{NMNtzh+#i<6j46cF9WBdrCvbd6|P{9(kygdE7b6XMea}UzU?UzK%1ELJnpC*T_Rn z)z!=^2(61>f4Rn0n!c3yEqqU2`4pj@-PL~-M>#nL5gfi4(d|gNq^ypC9Nc~rMcHle zmwy=W&K>@iZPYt}X4;i|NXVaS9f)&q?oa+pt;P*)GnS2?=M`oW|L~Y+mi28!);-Zc z>yaIWJ@4^i)Si;f0^f%+G@?3=MlON*of#V=SP-78q!Rhf(c*k=1%$HnaRbMSZEBHCdfBDoH!xaCmI(c?eBpV4~Fnq!mATO zu+bswD{*$v-af)dDwoEd%H#{Vrt-CJr0|h!q!H(T4Wd6EqcH4ID*&DIApJ-SY#4q+ z3UB3q!Stv-_gDx0HHFB#l-@@>WcbASu36_{acbSar4R=DA_oM-KSZN3I&ma_2}WA- zNgaplCon$@L$E4hL={P9@BmMRWf&+YWlRgpOI&->sb*1@MyOcTz-KE$YPiy)=jKPn zhoXLRV;?m^h~*6hzh=v-_L(^swbRk&&JCPJl%j%_9>PNi(qcf=z(fi6%lfE{>=BHs zfl-afxPV@!tv>|Wky;glqVxI%FR6LnthD7j7$ui;M@h#m`q>U_^57cZU(FBZD#G&p z2UW!9WS~vRIC&t@(JnsGl>g;gY)CNXdzBN;ap3Zr*awRrf1SY)NOZZ11**2*YZhly zQ@-?y>V*6AJVFJ_W5K~&6n5Q!!+}LvPmZvNOot|z5)n`;2KcBHCSP%cHBt$I0ckn^ zobdP8&{s7(HgprI8?tiM(*Z!wj{ zFRg5hnUhp;8sd09U}(;wu4+&VI>=Aj#xzEUAD6)rC02nIA3@usUQ{5?-9LYPq{alq`5-hyj5?T?l_>#fh|$9L?`ddVZDV}*Cn^WrW14QzBo)rSbb0k@rtkoHxXxwR#o4sa0{k%80oJ{ z2kP~|Te>dMov9N$QD$Aq(a|JM(2T02$s)AvFrifY=F<&G)S5{Xfz}}y4S3#BoGhAv z1HeJBjwvHXBua8PqB5OszI=7Cg{dF|cG&=)3zR+;*8u0C{5sie(ALPteJW2_vM+2b zYT6Nm3#KBL);@*{C00b0OKm%nuW1xpT1vdsmaUNSwk(iK^6e|jIM~jZzcY3zMCc;=p`{u81J zDd9rr4WaS-PsZ_Hzom-(YarrxMQoAK@n)PKn0Pc*)hCW{gJMZ8spz=JL4iQyPV~06 ztQRsRQSr$Ko$meHh`w%@*0Y0?-*6cTn@3@-`^&&=H5cHG$Qhn!FubGx9xO z@fxgd9rkL3sXZkA))fS%PwO$1v+UTl4$VItT(2eofgBlTQU{P=1PHEA+@F>&A>ix7 zVwBS8wIpB=g}POQ99gO5cPBd6gK-`7S<7(ZAeS9r(UtTo{#3KljZQ?CR5>Me?})4% zJ~b{pwyuAg#ohXsY@}T%RzPLOoNi|MEHYYLJTVMKec^oz~sPm_8)Kce9I~l2z${Fh)chRDH z#_?i*FKT##!P(%++pNeiDtLCQ(=jWw3)&LIT zscnA+(`1{QxZtQZIoG;#qG3sOY&hmZ&O{zHM4EZw=c3FtP}~YJ!=Iu1WiTkIGsuxs z(~X6>c#$%{xmNi@H6|6Ib*Bju>d8quiH91tTU^j;4r)*zE zW{*AAWRTeJVRL40V)eVV&9&6=mXk@H+a!2vC&c1F2Bc+@oy$x&H>U+=E^B-%^x*Yk zatbk3_}js86>4m8HB&Y(>*`$u=V4NzTaSn^v~Ijw1uZQ%aX_>kjGh(R7XZC0(|5@O z`)im)g*J8GNqL*`wqQ@`WWn{ngQSdj9 z_=-V4BCSm+B$f6Wl6W^qqx^}lglV*odnnf}?i1q~`K_GziP@^^75562hq8A#b;$3d z;1dTu0xm$|mv4V1y&z72l5t3#IWw1R{w+rPOsYZ~s!b-!kV11=zD-gBGl|h4QySS+ zqOi?)b4XMXb;G7`UGgAg6K-X$1hUEy)pZVcGEYrr(<`0oElvt_4Z3Ego&;|c<2#Y% z)jzOf4{gDw<^3j5A{VI&%B9Pf-8_6`kxR~%l$9$gxmj4`W)U}ON=7%yAGDk>#u3$} z%ZLEPrklsOr2NG)omO)GEDuf|ArA2KU9wcM*C?S$+ijKSUUK1gA zRrbYz0Q9A-?;_7yS2#7h?J7E39z?cJX;4cSVt!~>_`Lodj%3isl&nmG z&1kIW^ZuDw45D2H7bROsN!CqD*3C-RO$)h9&knscXXB5RTlKbOGgZM_rOxvZSLMZP znn#!ZcWJf8E*=EjyJa~Xd#Dnenwj8xbk;G9Cc0SFH#X4N-~$9EOCD&I@TGgXB4m?b z@#8{C0|LN=+eprC| z%F5Yx#&M545iCMhAjuF>Ba3|_1q?7m1BMosgk)6a;V1Ba=xm7a_u3k}72O5RWnDGQ zssJDfBx+Twquau&qi)LT=CfxTUE#;scH4B~L{JU!Ue^0!%MUvoc5w zl6kT}3WSEqJQETK$cRj<0))cX4Oi&{I1P`;F!n43_Do*w*g<^Vxy0NwfFgLO!8^;t z89-EITW5dpp4s2Fj{A2&SLBvP_fV+kA+r9fc=uE&|GgvjZtzRxD>>$!8f#X>M>=S) z&XnKmJ0cSK{ylga_Q2=oNRIqplhM~D1Rn@u3%V|Sj?J4v!PoSlxT^Jo!JhStAg^|% z5o-1AyTQBza49$C5o+A$c=)`*AvmF%ppw^LhF(CcT=#=tuke1KC6RM~?%+QF2^&5# zBWXIBk%8%$cn>> zW!%W%m8y5dw5R4!1@pV~a8JWWdc>dRmFd@$5;g?LNZ@Z< z@Nr9=`bYYjkP1j0Q&xzOsnZeLA9XD^!_BT%JlKRw@RA*JuyFw z3e!ZoZh`FSINFc&%1E2a^joyD2r-RmV+wXm)+tD6mn1UFuKjo#OE^jn^3(exH^1qV zF#*Z!1n{{CRgGya30&kU%!YtAW{NtrD2xUk^w@prV)_ONOgT)KQnFN9(++q;Ow3B{ zf=F2nA302V4V98eTa9Yfk$**HM5j`_D$>1DyDqXxqv0RT!7_=bkzECsM`x>{QWoj0 zabCGz9towvQ8`!#W7;W$3Lf&9DqGuR+O@W} ztDn)EnL~qU^Qp0!5B6TiF1K0!!3gvDk1KQldFd5>1$br%qm}sLYJ36nnK$uPaorCe z2#y5z;kf`+g(m*>1?EhF?Fh?IlL$wYc>kpPe+OYcqd{1L1fZ~R2Tv`1ie&=-dE%TX z7ScLqRR#T+eFpdy^s0@i57C~&mJUs1t#{iWeCRMMZ~s;Knh5u0CCyqF2?w#%SY0=- zU&F8Bt4~H_A1XdUldBlj$KIQV1f2>Dj&@rVI0uIg1aYQSJsS5AFniI_IzXVZ!2F9rR*#YNHe66{t4>AS+IJIx&CzH*hKKKjye)1$$J#5 za;JDrvWI@=(;mi9Wc&`D0A8NuXKL1pRclG=;f6v~GsK6=EE*soNE{Qj7)}Z^4kF?A zTKx|7S;@T43!LSgIGm-Hd-+H!46jaz8yf}d=%#Kp5B*&tucDL}8>Wk;&TGtkefggs z1)ZgsdbArd5}){w=au<+O>v4s*pzW@XA0MupNrx(3#pok_C9GVj){3_HV6)s$Wk~9 z!D)?hmZ->!a49DKIf?|+7nBntT~c(0vuMrhHOh?aC$BX^2}0N=vr8HVKKiFey9`6aF?^Ms5qg+@WK zqi;Hvqk4~`oYQX`lBd93?zps&pmnX^<|@&WV&J|S5=N*9%_>8u$V_Bx&+qL*kG=Zu z9JlP)AwvcC4=|KF8NN0dYR~<#mO!nuWytBIAo4g+SEX3Z0iSO{Ueas8>#Yk~(E^PH zxAi^k2egSb+wNPu za5^;E;1W zRNlZ@=4LG814|xLRVbRg|VqjB4dVBs+8!%}c{a!zN1d2x@DIt|h zL11LoIbGwCrRv-UR8HkL8)pSLYC7Zf?gUiz23fso;vv*Li+|N*8kY55s+2T zScBLZ+C<|q&u9`UGb0qbZ0{phWs7yuqGn{ zXlc*I02PVAX2;W_&G9wJ<(frfA=9jBc$P9irLRH|OE&3%;pkL<^sUid5z)qjTcQ`n z^WVan8s7FkYgL#I$1avMCWu?%!=RfSGE)|IdcSL(oZ5O$cv$6uPpZDML}pDd(WRUI zt0KZb!r$)jdss!Gdu%JBMyGpZiB6Qp%G=f#^&vw!K2ShqvNRK5q%Xa(i=K>anmaG0 zBu6sLns{~44}y4P^zKiRo+9E8pi(S!X8Rm&GDIb|{^yZIEzxmJJt)?CfSdECZ82|3 zM9H-Go1S*C;APjG2W9wlq-(#1bhLoge8bdNvM!tc=QpXxhQ*NtmcRvkLsp7z4%c{Z zy+D z#Iir0@A7x;+RC<-{X0FP@5iWUjpUqvin5%;L-66;h#z~N(0cmwSFu_l|F+OC{e|TT zRHS?O@e;u!GFZ&r;uB?n=l8K%#;I}yv@~!il;zD_&--vEL54G^JT}Yn7t0d6zl3I&mKv z^8_u#vzD4!ar2ZIPU874Tq@IuI3~&D&dWP}(O6x9d=Imk$$XzE&i7w$PC3zuMc;9M zI&|gb{CC5hB{L!akx>()2tMPZGO4v39JBKkpH}J0A`8}8m*G?_lZGiIR23tyBaJXU zg`Wu<_De0iX&@v->A%$KfA~Ur5LJTxL7NDRjE&2lnR?&NjW}BE>XDEfZA|aa&|XG5 zGQx4<~v32&WkS59`c_ca#biP66Oh1%RN>pi7j5fCo$$Dv1a>44Bg^^SC`?DgIh zO}M`ipV+qQ1biCDmiCnMHAE1xnXMe4{sa9CsP&j8Wmj z3bH54cwP4Nhva6g6Oe7l`;VAE4;mxllAd9uk^#D!U!;5${P~BwJ&8_}Dl+#wd3JQP z9c9Q{4{q}a6e}}IqD%5)s_zl&Z~(p7lRh)FW}UWL!)hmFWr7pTi0>IKEcsrGl=zgG z-c$X-Hk-{j^M#<1{39Lpo2+`=a7Fyz0V1L35~PaUsLW!$66v=eNEfBV4T@H0P*psS z;O!i$XD?H69vh>?5)x0U0`ZZpF0YrZpv%TlaOUh@E2Juu`I5Y|NKZu zZ%X91$S7!SZ|*FubY(PJ{kuMOZlew8KuG#ZwieTSe68?9l_hk!Q&YU1!&+tK#{C+{ zGg=>ysdn?$sh6ZPmUV*5UtO#EV@QNTU{i2j3|20SF8SvVfbU79#HSz?{d*?x(l$VS zg81Kr$`0t;SVW$dds6TOL=I~-mAYBX9BQ0MrOz98FrOz`^-lCmtgq`5gGNcb-HVDp zVg4Bq=27NlbSDCAN9Bs4dA0Bxj1Bov{|z?zT2{mUxhfE8&b)ewjoA%_(NQ!-MkF(% zj``LZ{KQStbM-bVq<2M2S$og4IW0I28FjT4eAh?O@iXU-HS!9EyFV4De)I1S@9C@? z{FgQw+88eVfj**p77kYx@K)I7sq!rkMycuC zPCzc;JVaZYcl+!e{69s?NydwVOA{O1t8R4je%yRGnkk`IoBStJ5|)A*^DbmVHc@=I z<}6~%lTJaK)KD*&g>W$cZVwMe`I%YaiR2{KEv1(I^`X+~9!mVyWZ%>UWu2a^-pr>D z4MEPH<#YLk$)wx%dHrQ|7RQ(Md~qA)7i*z!|IaPc0LxW5ECvZF{3sTFN!05rTHBwd zne{@T(dQR>URn#onfG`%5H$7SPKIZ^wbW-2%`B3zi9*`0nTu9{QRV2`z1es zCuhYcJTHUy9t=}1MBP71?||FBEJ2+&98%77gB~~oMF}ur{c72U@kzU|Mb87);5XE} z*3yh)7wMNoOW-;2ovD7jmo&%2K^%nz39mgqhRwqpqNiNLt83|lG4*X5GY}!h5GHp6aZ8}BUsc4b&OEH$0jD$z;D2n(XuUbJ3GFITAu{2VH|D3B-oC`c+8c92wB+?j?4gt4g$ zwqZ1QdlX+|Jj;qhu1HIe`GgrQ{YRr0!I@C{02fbZRs1x!TBiyYvXzXSx98Bc#QnB}vyEiL!HhwUvb>^}*gPRi z*$>6LfDTWQ?@tz|n)hf$njQE*dFIm=Xn#TmgJ<83wF`b#cIhjctHEGAdU_59dHB@j zqhqxm@pt0D%Q}il|Ghj0f)bD z!(Y#1BLvB0uG4XOJO9vj>l8Jd@Ai*ZQ9hKgY1C{YmEk@c?tt6z?K33iAdY9PI)?cP z+y=PcumGh)%|oC5A7$qhTxrz(>DW%kwr$($*tTuEV;kMEtrI6FwrwY!q;ukQN0UL- z%r`glpPOCv-n~_8->m&x>v^tOTSfWBY4RP>HU=a&#cF6tCuWN-3^llnB6;?ibPzs^ zaIa+gnLvF$V5ftyhe3bsk7I(x*@W~bRyqc3))A!UVbW;*(}(`= zFg^4j)|cnIB40({d}lO9WEu2yfvTsmV!&5MYJ;~@^fPMZ&@@Ith4bD0I6-4~PCJg_4q%fc8Jfs2&^Z`p6 z3G3i{|wN6ARiU12Dgbm%}P#bEmw7=RHS(w~3h8Nxhd<|X|TT_L+jGZOA1 zdlgk-X;jQF1*DUIi^f_;ssWlrl>0QZl6O&-wV3X#1-q2(bYs=M@rVSby2ob^F==cP6`Jj=LW%?cz-7d zmk`OD$8jM1jI7dn@u3Z%6}Z%T!DSj41)|veN~UckkIYWg9K+Kn04oeve1ZNu#3C0n zx3rD;9f3s+IRO3*#6AK*#$w`9mVKO++RvDL25zcP?|pv85@N-#5QQe%QhpOxYA;%vkJh zwwyFzT!Mr~n)Z{^}UxnmIa5Ga^6w8(DxVOB9wtI<*~`Wi~{?~%J=m2{GhZbnw= z+H>f(9MGp~xT?-oHy%U{OE#->iak^*P6U3_48V1fkM0fi!wl&c4fZL>e?-nk2#%xz zQFFOEt13KmOVa8ZLIjrt23LH0N8!5?*@w3~{Sbx!pnZ#*<@g*02N9nFUwOfW2XsMX z%n?bA2*TwLukcP$Dz|3zSZhPp%Zq`^OxHLsNQ5QaSG;9=4YwTp)8joZ~MhJN}clCZ#`BmY@5{W zWn(0~QoDmH3r~F`O{T*W z_>Af4Eg;fGtT;F$!RF-UH8wK@6ZNxv z6!ar9v|Z57;Ud;7tEq2Gr(%IP^O`M_i2-_c?8wE-BYMfg-ucGCle&o34;$Zs^A#!l z>DM4lJVX3@75qD6`5@#3en2{55GztR`f?<}MF7Qd@|jBUz=PUXOvWhh8BUjiToQsW zX3C9Wtro3=l-2~rt=_O5TOmO+8~O7<@C9LRfQ^@g#srUf(5(j>XMYMH8$UWCK2`=y zvW~TP&GCWP9(T!8CgV!&T3*<0b932cD8Nb55SU#&)i{6Gbc7gL$8 zHXgu8QOGy*mJ+K5^K52?P_>QFmCCJb8Cn@b1x*|Mbdx1XEirem26abrR z@I0Phc>JhtQ#SHDKW=D{853gzlG!Ic2< zT1%z($4l{{-h2lcyp7_kDTa$hjN@3RTr;$?ulR1Ifee>kK(P^f zs+y=;LrcBB+|ioxJ78--SL<8oF4IqI{f{4(e*-}bP%ZTzdi(#D#1m%rm8eF~y29VQ3%lUG6rF zF$KU-xNr~^2{d6n9cA)Pp^{BCWM)3+X7=Na9^vPzUnHyB>FvT^I!uu?G6fH`zkzSv zC2eKy+3E#haZ>B<4)|xbzJYHn6~X&XM;UAtoX}9|236bMcv{>%w)YxyUGHpk_l|8n z1#w|t^eZ$z-S~BQS*olSTIs#6K-qgc|1L083>41!2f_XrX;B_WJHS#7)(=I0t5yk| zs)YC&vIijm2pcHd8^ZEHcI)A5qOd^%v&-S*%hn3&I638g@T1?8e=1EnmmQmCcfqW# zm;Y&1+Of^+TH<~zX|LK+Qr8YGw6KG`fwBFqywO_n-~UpuLO>mdI%m^9w<}69uztsI zmcr^qo6hCaXxE9VJ(EY2e;4;TP_oHVZMp=8e9wqrTwcin5BksA@rW;bm;N|fhu3}Q z2*5-7<1<9jV~>K&w_)uCWASHygvK|l$?i^r?v77LE~rQ?bx}^DrtTl64zN81K07G* zyJEyHG#j_k7K22o@T*PI|E%PE`q!++>~}(!WGf)ER7(mx)C3|W*MA_x#F^3JdY}5w z$ZkM(KH0Pj*|o|n51(~?(l#hvl{nSEs&Jb2>$+KXeqI&QHBbUR|00SsZ#Q@s_?28P z8+R-B;^j4WS3sFLckX$SWW(K2n|-sk6kqSSc1;PMIy!NB4r{(n(w+Rknc7XJ~}U;Ft6XskTG@L5~k8BwER zz=TCe0dtch;l|BGGerk%Fj(P9e?`gN!9k|w@N&SL)ahjv+qjBV{qkG`>_>4!;cT}t zd)Dc-u4w7k)IHU_2X)hB?D0MKZlubEJw3k%d|uG_?Dd`%`pZW%Hu_7Hs#cZ=&Z~2OEx_Kty6v^PK49hM2Lgv5|c=Cu2Xar!(UixUY4lIuXPE~ z7_)4Cu^_VdsP!}_VqSBNOl0sBlp52-uU8)9@~Muh=sd8=uRFT9tD6h?;{D4sBqBRG z3{!*WIvGUIIF+{>NrK>ake#-F1PwY(41m>pnxpA+2}+D56Aa-lG${>v5k+^K5<5)} z%mAduI4nUzwzC+Ad)`MIK8eYKJdnX5XL9a+Q8<8G@wcMy8}ttya20Wjw`SX?r>7V^ zMzJD`F5QV)ou=?c%x;E7M;T#F65~cx$u(sgbd4la|Li@ssSv#{ed^Bt@Dl|ej$Yov z5IKJ<&6E7d+wno%rI&PGy7fX9*mmKc^*SQ*sZiW2JJ@lu84z;nfxXE%6-K`C9^wxW z9qZ*6t~`<`uK)Raz3NC<*MM4Px$G#2h-CE^orq-RmW>GY`~{Gx0(V4XsiFeEQBmeA zJ!b70pgeYF`6-fi3LV-{JEPzh%X0bRPGr1rs|nsqJ#)$5S9Fxe{~<2zEO+0Ycys=u zK!p1Hr5@}3Lf8n-+KZthcYud0Nv48E>oapn{5e>wPMy|;37aAgw zv_EHyZ@Ocji?@guL3A_59&gS>pE6y+8K=(tABJPWvd=#k1Imup_=!_{-xMBR5~8Aa z=H>RODJMx``8dXV+1LS zv(<6?JT6@_EDu6o{XLUL79UKm-h`n%uKUTm^v=it^KCfm4|H>!+2mxz=_`@k7+ z=TasMgq`CHzSZ>`WX`N*Y4JYM`>W0#3loT)Mm(``okLV^pLc{X7sb6rXaer+1ayV* zjOH-9@|j!cfRs)+-@h`=ZE_4~`H104jBZwCEGAkVZJgOf{LbM&$qFY;O4j;;1a}kb zF#Hskfu<3{^Nzz4$1RkdMUo6iVWOH^&ZlLs)gh0+HfDs9F-LSZwJ^RT z!{x4A+%owm)hje?{^%z$Q@cAzXCZ_8o#2++srIgY)0(Yvg#aNh=J!cB9|Tvq8WI5n z`^4YCpEaGG3l0e{VWBQ^o~&x-+%1lIWGz*K2w6-o8_8(nJjAB5K%q(#MQ2Ld-@nKF zFaWfW@}++eI{pQsduCbNoFD6qrzn)<5Ne`r2W84!gnRO`^grKU8_N`#(Hl5! z49nTVS<=BlYV)D6O51jfxQZ}jhKuaccSuUM)z$OK!PB#4BFqo*4ddx4oJ+lpqBd@2 zs#}=iro%cg3Xro^S)^mdB*hB-u`w-BAdojyCf&j-*$k;BP>aaTgZP;ntPt6ool`=! zJzdSYl|wA9D^gCXGl?+yHaMElWnFMo8gM733F+w-`?Y4DVO`8EzXCqB%mOT!nkIkQoMI+us#7oO{2Z zJ$l3}TUmXb?CxB0yZp_PW9H2_vZSu=J^b_Z0z&_>)+DF!9v;{8F?ruvIO!^owMU8G zZC=2<=~B)rCi7}TS5GSm2djt7F?c7mR@kPUC;@W6d&!pc zN#LY^OIVpV>Xs}aS68(41me&9GOAvL4DVSU=v(|H zU44`=!%-Qd7{02SAvV)$MDbIMz@|hj$j(&6?t2I}!MD;?O0!H9F8-lk$?Ikmk;t*% z^Q5m~9E)dQ9MQQ7Z0DcP86)uaX8P}&q&lp+)BjN$>jaP)ldFDy7mQ8%!8HHt263sy zwl{QycVPg2d!7$MK)co@d4A*Al7BbErjgEO9`#&MzX>?dg)kTr94B_R1nuC$zVuuB z_i5hue!6c+ocD%&Y3@si$p6S3PhMBB(d2R9f5zG7NoV1D(CI_I%R12Pbn)jKG*_q` zbaHJv&0BhOifPYhz@_yYdQ~8$zqg7B{7|{2@5=4i7%CuWRp&nPsV)&~yZT1!ouKoQ z^!GtUz0nhDb1`s%!jO&zBvj3Eo6^RG*!E_7>Gatymm8A3pOl#k37acLu_}AmLk&yhtz81-)KDoP%HwWa)%fdgrQ>I z2#1DY*-hEtoo#hj209Qk@l{_6_id%5f&ww`DWFiZiw#6HCBEN-4|11G;|!r%6U+)i%(n+`vv_j*{I3&9NHq-`=F#gn2d~s=`1kL-(+kXet!Ja;?Wxpjr}3`}#9#e~{6c}(;SnB9lsw;K%n23Z+Zn`+>W5pU|2mCb!&+TD)m7Q@P z%0+|3oSXboJ**Zu&mCPCH+IbHSmrmW&$6ZxlLAL9n(U1%tyRt*s4H{l3~||&R<%_- zDaR2d^k06z)(sXXcktoTruvV}4jXH10UaGQCg#LBxT|aG^|9~TvX!LT9Xs+g-%jlw zVqKlzMKVdtUHh}60|eaGOl_uRvi zX?TQ-Fi*5G&Eatv&5XZ(zfkYnaBw)1VHS4^zM;@km>YBDETs`X>dJtu?NP3lnc$+1 zfbVsXDry{yU4{-1dV;}Qy>FYvNonL@6B!X;()>Gk;CMJ=efFF#HAxTso|RWTn&h$f$d1Fk1@g-V26;?M?iU^Jo?1KFm;?3?H|YD0IL>sTcP< zMF+@3fo5t{-XVn`x4WvP{-hBg>DT^~uIIZsktV|yaq3SuoRaPv@q!jE!ai@bQ0gFE`;d6s6)gOmzjn#qLo<;I-{F;)Z^({}>~4S=c3cm7 z!(+8{_9($knxcBR6nUR4_n^j=Uz`o|0kL#VsqT&`9MxVbDzG^H>~9@Id*u6;8CC_` z?&*0+L4hLeHzZ9tEGm`}OT|D&+f`%g4x51d4{t~fowEFoFcBmMa@-p&rvlqGj7iiztaM|&HK7}P%S!t{}Q34lEJZ7 z7xwzZ^b{c~GO*e_)c|kxttHB8??DUR6J>islSyp(y`zIy82_q+$~o^-dY#(Z^SyHi zz2@lB9baUgV-3{%N_%pV*Kv$4kXQavLgDr`V)%z@FzHkT{wOd0Rzvk+bz5Lt4bogN zZZBcyP!Qo-G;FLD-_iQRY_NyDzK(i?6-e}S_ghLq7n)Hg0q==RcVzG8O1y+~9V)gD zS=e6F(c1SH-MGHFt=S*Oh6V=R@_$|*$0`1+y{$hBjxi2L-XCl@QzQSJ zM>x{c<8O;=({*7RdtTt~KlWf&wG-sVn6}1uDFrl&l3ZCKA^sCHUq~r7H+4)|NjX&i zEu}5~iojPez(0Yy!y}UPeX?4Ab69hZW#&*m0Y18xftIv2Dc6=|%`}qBIw5u&gFCm& zinmls%BJI>@1^q-EE{f@+Lh=NPD(2QwIo><5;>}dEU{Y7&0U(_L#b!c*V;NH8(wPs z=)KQ!mfP%JY~@*oJ*&)Xei!_5+*&k74g}$J7I6kzV$%+KL`d1c+o!_5oj0eHbg}4s ztNVj=Ev#N6uSl2a(!A6xSo@(8lDurn*QP(qLMYHikpF9xp5;tRxWU-2!-yK2L`DAM zS)DQCXIkBJASyV+RrTV2VNilMe-|H>Upn)pAkEj}u0fD6^^aMzo7`ZL^z!~HXw(<(gA@lJ{6JVKA zioPGl3HI;@I(lpay8b;`x=~F!cWmPG!Z3Lk`b#VV11Th3odaGNS~ZYE%=G0Dg~~4! zs~RMp+qWQ>5Zr(-Mm9~|C@hk*ufj~+M7}Rh8%m{S(n+-TL0$g=)dQq4J!a0$#cWcLzGav zDgO?`zwd7k!R~*TX@h9)EEtvXVpI&dU`4fJb)a?#(FH;BqSQxjxX?_8j+uZ9!dilu z87(e#BA^sliIfKvE58^O7==(Y=1j}`_?07mmFhCWIEy|(`~k?(FD8F=N}}g_g9mv+ zs=aYX901Yd8bsA+qBOiIYmI;B*JO=3ywmqYnIv3;#;t%+;sQ;ZY8pkf)m?}PanBOy zz#v-ecg53QuK}vES+hB|-$)gL-#tut;%OfgPm1o@vfC#Q_}beM%WtCbpisZ@mHSzF z0c&>})w&=xI-1Wz?x}G{TH^p~oNbtiEwnhEVz!#F7TENM*pVo>n!m3y1n-Ru-UO$& z5upuP{Y9n^WPWgrb&@2?tV5TS^57i6XKVkapLX>e3}~xA0>Kio{#w^thDJ0q`x7Qz z&Mj5oz+QE*BfH@td^Mo{Z-^QDik+aFv^vU=wF(it87Ypxs0S1KCaPA(WP*MUzGoru z`>l_dt0_(XI{0TgG))!s$ZFW65l-VrHGfeTWMPU_j-9F&QeP|N6Wn&mzERwI^YU=l z{;^>#nMy+7c-S_4TQ{^8PB_!tWS1BzgM;j?y9+sDXEP)=LW%mf5?$;P%__Xx)DlJt z^=D^Kn%WC6?Wz_?nC6s;KmkqKmI^{R^S{CwqL>CS0>2`F9>j*@NBwHtj^R|C>C{!u z;4@l#e65;&t96p7jAmQLBhO~Y0+Z@Fn-_`=p>(Sf#I=#;1BmL`Pe`mq2&-aTwPy=3 zA6szNp(M;9VE4$tlljqY2^X#iQ&h=);&ou+z9RO!ze_UPC!94$zx&^Iqwx+B99Vv;aU-KX_)s(}%Kl@aiHIgurts zazHH~u0I~4Peegp_wzSi8N^*ym?6lo1) z4+XF)BXe*~FS;a;jz#06%;NG1mBjb+MU(0ekr@y2%AaWtX^3Q@h;{8uE#1eL+_A%= zx}7mu2OLXnI6Zkw+|mlLDqD5W>&}Ko&J87#&)H6fUF#!7C&BQoK#f@{ttb7$Z zr396X(3&b&KXmGoT%Zzn^F3PqW*gHI zaY>hn(EgzO@PKXggl+YPb%=%JH;`#bV%kQ`izCuv-ASEXYL*d}@IA&Ne0edZ$?qiK ztiYx8XPMKDKT|{3n&Dclchi&Y7JUx*Sa_#|wgh(^SkB)oG1X5Y9wo4RZZ zM!2JDimq2y73Hf0Nd zeb!8dJg&yC5zw4uIM0KP_%E*!z@IZR%Ns{R(+ntwjVlPe3af9^y+Xt8PSw3iYyohm zjCcy^Tw!C2pkuE+Td+-8xyCmF$Z|#!T(NnmngN}#aRjgH(0!Io13wYt^iy@W@vU9; z$>X;C8v$)B*kpMlFs2JB(}#(?aRQjS+biKCM1h1nR-25Rrmo)XaYC-x&y>x84%j%M zz{U_EY(#*j&UV)H;g>B37DM;ydhqb0Pe)^&5u5V(apA|yFTsJ~qy$yN#K4_Z71J@Y zy=Y!YCXJq;t~>N|gOQ!U#)kBkxBB-+5;3#wp*PtdebbFZ%10m8get<(j6v=R2VeZw zL|MeY$VOugE@{2~0_ILfvhEZjW1iULhbd&^9Y#7Jg6Q;DKeH zW{;3tujb&DaR8%@=;Tol8nl*!>rxOdw$_R3<~YQ?rtILo6Q!@gJP%KtxWAD-ma-G0 zVBXuiKy2NyuzRX=(`z%w#Mg`Q$Vc|jJ!2kfBLrHNGVIt@~BfqhbD2$8h-Ua@(^=2rdW*`_jjx&5Np)kuO?yHPXKqxCw5Oc$tcOPBs~ef3RZR)o54*4$E)z zJtZ)F5RZ)CSBmbRVObhF_F+xfk5Br$9xJj#>a`5M@ujg(6n4zgf;=0_A#X8@9h4 zwH0%>L-PF>4qZ?ht=&&qFV!;?^z#n+U-ucJy3-~yMQ0M8+*`Q)>l3|aq}k_<%eQ@sgX|0)2bmh8Hcxcg63 zFYFuWOkO_^Mp{eo7ec0i46en1s~uhI=k<_ zDvUt{tf|KIyDjfG5HWxPWrRLfn}|i+UT(b;uV0#ugx{8%a6b2a;6z+|2Hvx7RT9@g z9Ah`P?qg#wkw=Jc3XCiT-|9?(`!>j!TB9b2W^J>kjfgZuKLKkKon?ts`9+BlMQ<>q z^K{7Nhu>!L4Aa3!c(L4HP*5TujPfAyE7ApAa%;=%&Fn=YPkd?z2vMa>56??{>7K88 z(*3=Re!ncvDwOqQOc^Vb&*kKf9NgpX%w5Z`;jtc|A^lM$FJQA9t(0(Sk6P*vYqG?j z{jS-7N0?@l{>q93EyNbYhTk#X{02$Qw#ciS!Z8^LcglcpWV3v108KEuAU~GFJN2RJ z9{Vo?gLKQw0yT_cm4MutL*r4pLwxGUSvb1?s8lh&>=X4rb5G&7{UKLyFtEZenHk6b zYd_h-j78eP)I-|V!O~d6)ZPAn?j~obDycxQp#?^2LTQUZ^(%2MK!HkPcuH=~4r9*2 zhgLj_bP;w8n?1PR7*U6Z!$k&2Ec3%i(7(_rOFSF}&qf>#&T}ka%8dm>NLno}jaEZ` zFa&rG?7Vu&ND@W6SkGZJ(zZqwlXw#CMQ`7;DKnA$)vxd6>ZQ)_qhd7Ae;UsJSi&hE z`u?_KnJuJU#EygXnqgbFH&>%X-W|V5Sl7^c1^;BU*K^DM+H|;#F`E;j|EwT!YpWnW3K*Ct1sE9Xf1!fvs*1+y z<~Ej&rvIyaI`BROYp#XhVkU56nUV#`lJLt?YS>cp?Ur$=gtw_mF;H|E>5TeKUhuWQ zutE)Sb#ydRxg8D9Tn;IP3~1!>E85IEwe3dg7zL^>OPkVopAUwc(ui%DD>}EN9T#;9 zHVi|+euSTn-RzC{yZ7;MI6nzJPo}AW4=7JV?eBnGMc&lG1VOH0D&zM#)But~su#+^ z3OHdU5aFOToUj6jFKiAoAap+t%9#9xeNY>&PaY&VxCYm!41yTsfit4?iP_JC+9Q9l z4htrG(GClyc;O!G#|((x?}pl=co7~%mE4q5Yw`qPn8Eq9H^h3y*+>b0+V}arprvJs<;`0?~nR2eb#c2c|$*AUu%v zfbswxSOVSyodgZi>X}Izdwk#1ty1G%Z78=Q>!GBBwR#Vrbu2!bvGUYb6yZe#5aMB@g-llw^8{s&_#<7y2 zl}5*u_FY}C-JYIDs7~K7(|4423+w0aTwcKdGjcC^g{s#=BPay2cyyU304N# z%aJ+_k`ZS6dwh=EsLC)q{*=`gvZgFTKhC%rRuI#qjjqrv%r|N5sW*+qc%`hSO&IhlQitm!fxNeAZR|+#ex%`xX03loF5&f zIE?W?$R!bre-PbCMyFDmP70I z0h=mQ<1wALI-)|6LpK`<6^Zz~fG{y?t7|KpwYKy|agBPTHlK6jvCBiBh`))!QrXfT z(^>T@yHaJnJb&5OpD%62$8pjz@#Al52i>M3zpWJ?#%1p_^ zZGZ2Pb*GrWP`6&CU1s$Iao(amk>k2d5M4l*o<_nt=Ox0_s z$IUIwxhN3C7+?d^0qoEn69p`KLAfFjA9D`~?U&6qsGHg8bu3$Oap+@l<*l@2+UaN- z>elJl6>nO^6;r2it(p?8F)(R{n@}nIOu0ytQ)kNAsKwPwv{z|f^^5o$(Uynn>Rpy9 zQlqfkR9hx5f7s#BD&?9RY1dxIqD$n@-LO@*Zt*icusk;=3yzLLpT`=03a(yj+iiAL zHZ6T>wb-amF()edJZh!STt>#UZ;P9MW@eaOsCht~2HzRtC+9M;SQbG^=daU^&tje;uny&@NqX(1Oy?KE>w3rEHhrc}MwCW3EF zTqFMeUWowmViz`5OTN0;oO*3>?zOY|vQw3=`QE&eM2d}V!K4kmvLzFREt_{xc(FBw`TJw8 zrjUQKws_6bM(uZ$(=`TXY8o?Ba{jgJGK8;wrOv^lGj+x?zWH>BnWn8ea>nPYM=#M4 zCeDAaZt)(!NUI5gt<|uKy<#cwHO$DdDhnI5U*AXI+gj}$(yb5J__CGP>R2yLV-dv? zPTgpiJ?^HXo@{P4iyahaEw(u28S*i4)2FIGdikUQu~uc5DeUQlY6@0%M{Bwg)*2|_ zf>BWKD$LN#ai2@Dhtsn6bs9y;hW@PO79!^@)ddM+NfN2tuWG%SoMz)rTTCkgjQzZv zD1ll{$;2OM`BAXp*~3d>KC+t;mWi1GE&G)Rc802og|R0Cu#w#x2VTm%f;X}3%+~ER zaHxn=2+@}9lE)iBEX~=)rjUDblapFyo``!4?yp`+a(&1V2;4n5-v_*A)RJ=2Ze;}A z{{jVQ-wcQXf<1iPC@~6EdKuWp+eiL3Cw0KEMfOnG6V+TT@WrVaFiQD*H$DB;%vm+d zq=%+4P*ykc=jCCzQrJxco~HAuw(?O)NeSB0Y3UYWJJ1z2XkyDlY4Xy`zcr|d$!B^7 zjac}zDZF<9Uk&J(t+gB5>~N36F%POg)b$+ntd8E0ClqU7MrFq2^KV*i^1g}WiYY2= z@S+b3P%^d8ex{0d~201-#Gn*I3N2r%0X8>i%fs z?Dy>0eBKU`{-Vr?fAc2qUI$M*OY(;|h-a7>4JS7^M4k_9< z9a@)+0rJoh2nDEI=u8AgOdaM%ag(wE`q1P7yHG9&duTnVRrp#QIK);22eftCMmdv~ z0qjujP_L-C`P<4~(Uu?Tv*KCLN+l1H_@d5U)^9-+U4VfI&l+f}nsv4^<6i3mt+ug204O4V4R}fRKT9 zLg%G+u@?$gbC~}dCT49IzKj5~L+xU)-v-fvn2+`yLAn}39fBdROW|=lRt#A|Gv%r1C?xHbf)aCWH^ZG}QdY@)G_l)+15QHn%?AZ_KNyse4zxY5vDXl7{5=Qa^FZ(08=4^G&%?8+04q*Wgtd||wxHecxvws? z=aBD|Z}uM93-F2Y#3nqjNPLVI443KVs1F@Hk~%k}ryO#*ueu8Io<|Hug*_m@{6}lw z4W;UXf%JlF9|&WFItSdTy(fNQ)CUpvUIPE`dDD|6!{Kgj*Yj-3)Xb zSiTUy5%!_>N0GSny+<&;lW_x+zNq5}(fd3;xJH9p>yXgzZ^$QN$i3O4(obe=!jV(A zx(1=f!J z*xL-&)c;JlUVG3!Qr{g-oFzbOAfC5XMC}c8qbIjEp;Jo|oDK7Ys{)SI@jgCt;ipNw z`zDpy?4P}^qiAZ9-BX zA@3pRp!)%*IoyEkJ$%wjUGSvaJRIQ&mfN5L^H-x$R8V~ZBniqvQ2P_%*4?+8nWH!9 zLSaD6^DQAx7mdz~zsW7u?gNa7;6-#2NaPoZFn$+s>X0e^Bznyt)N@`((187jA&)NS zVXlC2+BhmG$e|O7V)h6ixIPd(u5A|Zqrl0+UBsB@^K*S7o9|?E;-y{IT6k?0`^^8W zhTgh95n)Bhc)CYzfdQ)}RXli5`1ENoNO_8v=5Q$TK@dz~{Sy6rfbINLvb$_joXQ_xSS=!08vfUY=bZZmN9QX{T6?8=P46X|jjncxK2 z(}sJN*>1d_L^vBt+{_ndauL&ERFv)3NTe+PvTd17R13VMPX# z*z4V4{EAl4mZCRWo_5b_+h(uVZb(GHdnBnMc?-*vMakqI6r-5%3a7rumwbz^BICwy zmE5zLWvSMh%yp_^1JZP))+wV5=mkB3(d-^WHeU$*wVc&~6bo6XCVAcGm zT?josV0O2U-|U(GAaWA+b=Ve0z+bKOD4s60Q&iPG8eAZL(0{inB&$*K<}Ki%Wj z(sQp{P(Ly%PM-fzqWa^L2vi$oBaOhr@d7<>AXEP2K#Q|Xcp@R~ET2`JEc zo^gPf?OiFxl8L{5e6IwGA+RWgT4>f#4MqrE%jOM3a=KSD5)rPXoMRqbl{~(XeXl8C+5;Q(@RzB zH5yVFzq={O+ORe;JkL@+y90Ut*qHSwale zDx-0&#lxGO_1*no!@d}$w9c8ty3@LtQWG|gRJ0bp|E%VX@HJrVjd?igiOx2w|-OMfj z7hq2pF+jsQLxd*hSecp!9ty6kjH*Y%NS$_Go;DfECX`YXSR$$~kkhFML+!rg3s$97 zr&Twncg>(tm(;$T`L7bg=C$<+n*?Z@)&AzUye$#X9u_-Y56fAukUUXDA69o<;+fGt z&<#j;ZNLV^yUS8{&1C(s9{%yQ=*Am-GW*C{%tiWACE4!eM{#br4ccQEG9H8tN{g0c zCUO1<4}=ShX3cSKvaLuD#0&IhiSb#|8-!b@zKMMyvM%E4V)urCYfLwHzCB<{XKR!)9uyCWzBv=yF@vY>o1 zCo5p@qWn@sN`kT=d?7-9JxIDo_J%ALR00wRf1^Hd=6+#<*&F#LySWgq=q`XFi6RB; zbRfq|+^n);E@)TVXhgCC68&OQ95kSJ9hbLeEVt(`_6qhPO}*+^yp`?GfPX$kAy%{) z(tUNYV|92YZYAkB%RQBy=@?lGuKLw=@N%yIBWVenzeY)~%6*x*te z@l@~v_w6QvOs`Iqoculc_^fw9l(I|dR~^cex{W1AQ(7kgxzQ&XWqT3no%qO~*N|jE zA>_qOgtbn#!Hq6Q{U;>9*Yjvl82A)65(#A|TUJj;2$?y` z@pbE3gF9tX%7UUC&r=zVlA_87K$E9jddQ?;@=Wf!!D$@wAW2b`o)Kjm`^w?U_LA*6 zPqk@HQ=HkMme9V@P8)WRDrrX=T^X1+=zUbmfhQ+`VXs7;;onq~5<}Rm(JdZ)-M%z| zJ0D%zD`b5lnSs_QS$CW$3!^HiY4JmMi_%2^BZqP6+lBk1cbB4f?ow^KRTg{Lk}4UI z9glJMR;)hV&+$SH3(_TP>p=FN0uDb^Z~fsNDWG(8M7QXM(D|f=9sZtMPHkqCw1yc% zl5-P>Ars3zQb>vLM;+`629;^`i%ly{sdGBbw(Vx@;`DvQ*DA}w58T^`)_Wn-f8L?! zJ47Da0BO2=O8Z7Q*8Z=I=9`HgcMwM<)+7SLRC{SbMgXw&keq$7SV!lS0lj$~o#GEJ zy1RL(dzbA}YRr^Xtg=qc#Fg4bX|V$5Ftf@$6(Iv0JfAqVYh&ZO2e!(c&Gj9|^D!!p zg+_u6>%}=CTf}n2J!P;WyT{3G^RF*1ezM7?yTtu)4=I%;_>zaQ+(raH_Qa-|dYEqa z*6$8f@a1oNNPIiEbrURq!XcePjd|?;{EjizTQUP}AqPb(2bopHZ{usEFDHq}?jNLV zBf^)_5z!}L#(XOn+=!0ThH*t)*Curt{a05@gC0%iW(%0?YU&ZC>r%SiRHQs(eZ zg*QK?ZCO7Y|0BQ0zfE*uV_A7sl;Pf-;AHs%l(9rt;um6x5E0)+-fj#bSb6pbW5w7N&{u(Za|LL@}=&WJAS_Jr4A0c;dlwB4wl7#4hNe>q!t-K z#eYklK)p{Mlu-(bFarC~ds|9^)pFc1;cc_fteYUoY^pNfg;(s#6M=AjQ%xf|@xKk< zJ5IXoRTQ+j8~cm-G9qGQsrXS^Ip<=gI%%cXqk?ylxruzyT2QZ~zYyUGH(zs(dK^TyhkeIH_DOndFHVfkPI+9JOcP0nc^8p97AZ)5{3_l@ zbKEW7M{&#{E=+Yy2k}-#1Sp0lXPHM1nm!&IL0FQmozGR4fuRz}et`6oy8=Z_jJ?Pi za4TWkvQDc1H_px~sE%N3)JSj*?(XjH&c@vd2@u@f0|a+>X9F9826xxs?(Pm7x1XwW z@56b!_kWnGsp+Yj>Z$HE-BaKCRx_zG)v)3-o8OnNB16I!x#UXi9_|*iKRo6Z-y7xr zEOeAD4x&3XL@D{}|M^zmjIU#y6c+_o#UDrIhMDHx8U1!O{3FRIFF`oO`HrZz`I;oj^<6@y^8eXiTBtPe0_T=V(oB9QEeBlc{Jf( zo+58y_HYm}Pn#qnp4UIwbWN_>1tkQb;Y|^CQ#e^%N=>J@UcK&Q_|E|JBBUWq8L4w* ztP`w)lzR1rR1VUNs>xOhv2{D{?5|bDL*j7>?1!Yu#t&L{NLzok0Xx^TODV%of%WXo zhDx6i4}%&}(4Ttj+X5@X>R$`Rx&bx$@dK1s9wi(tfsleZ4L=OvzEIOV{xs%eNl{Y^ zr3Q{bGmn;eD?L0lFpJ41?F#G4TR<+P}dNN<9 zhgc@63cDTVzXY9zXei!3vP#B|)S_M7HGmu3X}?wlTb%M+5-^t*@J0h-+ISv2K}0S4 z@Rrk)t*H~T@mLD0boG(4HMCyOjiTZ#%2m(CEXchE6v`XW@E8hV2vjQ4VCdYlb6yR5 zSMcIqCO6&dxpn#&wB;yDw7xWADSDO`(Omi;`WPi_S{Whw`6F9qPpA~KbO(7+*6NzD z41nUop}34L2v3ljPzIc~Rf%-aul)L*gCWQB-Jr2|qbz0Khmq%81elbP0+VQWe- z(n~Ees5MNuG6Oola8|HR7lt3q5O*6E_w$yWU-44ZYr54xI@aRc!vY0n3CVYqRnFU{ zN=>p0w_5qlA4DaTNIs`nY-5^wFK$qjKUKt zxsn>EefxVcPD*~B1V*?|!LA_WxKER;C^gL}xe}gJN7>69Z3Jz#Ygx4s5sa7ev}SEo z{mZ)VrBJ%e_mH@y_}3A(0Yf5|-cIN@Fj~(E0&^qcfk}cld{Xt1y}upL&2XBTjJzBh z+nv624`lnChFQI%pF)M$hmn=nBF@pov0g8Ob02@PlA(Ye5ghS;|J zow#GKIGgw12SZ!|>bELZ@5u)$HZ4O9YZmoupC@_Kw;~F88n1fK?K|J{F*DH^{S%ex z--(2)AFZAXcfJ*}GQML!a}IoDca}eXn?hpndj(qD%h=r)c3-PS9B%r`u-srwF0Q4l zA*Bs(`_{GYV^xYMEmAsE9iyWzRtn3XhJqUYUh`XH-Zt(OM(ENy=sknq_{~%W|hw|y98l696^#{hgCyeo1O5Ff~E={!JJH;Ee zYhDc3{UX?H=|EY(_yu*!dL6FKGE0jrvr~NY_x!ue>g@58fe{Kz>8E(JQ9Qt6YO@P) zZc%o`l(O@J9Em@6`TZPpNd65`+ry3a4295xzQ~o!vZ(&^us#3dKvZHUYn3p`xB49& z?0!gC`uOI%ob2!H6Y*VKdQ%d%Ymxcc`Gx#KQLhJg8sxm(rh_k?!@Z|#DE zh(QeM_0A$o^=rNIAc93n@@W5xUnIh@B!Uw~L(0IRDqmrDLGLv#RAC6v?~DVduk$YK zcHfg}d>wXYgoNKS-p!%BecOJK_z(%-=gP+U0phZ5@0tgucNeaY)KG;LkJKQA846^v z!DYWlW^cfcI@wFtr`NV)b|1abe!)z8y9?&GH45#F%u9wOiKj-E2A%s+rOOOsCX z*zZW=0iY*F5&4hG6-vQ3#Pg4W4`S-4#ZK&x(iKWZ|KNLvg#80WrD?QS?{-a5D@y`T7#^3n#r zu{}w%evqep+ey=S!uHq7T=Y#IQbA}C1>CkW-Gs(H-)7CUQ;+BUo>=`%6)$Nwy=l9- zGDhs0B!%Bb^V6JY19}-{#{J$K;@HQudRNI*0X``jze<<9&JX3?Zti_1miry=RzKRP z4Q=jU6BfLp={@HahNmgLr}@Y%Ea+0l*OfHy#n9xnY8_i;(qmpN^)4gI*hwp)#nI|8+mAD=eJFm2 z1;yS>FY8a2H|gAcMf5YTHT?Rdly_44Jmvwd$UP;SCI;Y^%Y{=&GA}2;$znj-M~Enx z*+Y7{e9{bL;L=KntHM+Z1O51F$(O24S&UCVPG=>fz}a0fIDBbhRrmX!?r{vJ_GW@{ z`7pO}CW5gRMHeP8gGwWgXWoo--R9IbGFp)vTWHV!I{syj3m^YbV|E@nFB9}L!@99X zST?hTLr4WDo%IsOQ!4{G?d9lu?O?T(sqnmn70$>mdx`#8(a=1GUb#eP)~S}lev_dw zYmzaLYp7Rl&RL`KYWntsFT<}L9iMC*VJ4eyTz=+ND)X1_qbRURJ(Izz9Ebq;3&@o)$M5XKE-l^vDKilp+L| zW}P5wff}oLcrr$Y30tE_IE4*~%}(m_8(DNWYTV7))W7QD_sSgvIckyBGogc0 zEG(ulD?l+EF-EG`#s-F@@RcYs+Hec7MFWh43x7Z{*h9Uir#x6X)l60K6VYN!H5}+D z69{u!VL=HIiXiU5qaBm_Mgd)1)6r1_M`shG{7;difl)gZ4ye*V*y#w7W)J`kuF!}& zg|cBc6l$_JBGWW5iXHfwtB?IBZa(x>Y%+K;a}oN84agh;Q@)T4bHaVutw4i0hGd~g zf0P3E8!@Rt056IYX1ipM8D3UQc*RIS{+>R?WCCM}p z-jV}Fus*k!Q3X|dAad7cS3xAj>a{==ad04R1z-=16{F&a2N?+3?wHf*hNTIm$$=os2HfL+Z(7OCx^u|-=cV&u(fj4Y7&(cH+-5cs{mUVMA>g67@5ksxG=;6UsMV8 zP0>fze@GY-8x4^Fi+I@2mfp-$pU$u$)XHqA-?3}T+4EF#JH1%w@qH>!HmD-lEnIy& z{awHFYf?-Do9f!go!S@~TT=pbquQL4cs;Vw_b4?m1!svTkdL#A1mltyINmx50!p)-sG^dKl5i zu7AdtilLdwzit%rfWWD2mS|=Jn>q`F*1ah9S5pGnz{+rt><{3UV*P`NaBg~kX)gzr zOXH^U@o&OLhhb{sri5}wBTu`EIx--SfUxQ}LZsiSgj7>`IH+MkkQoW(IYPgt%X#+a zq8*_*o+27A`HZnpwN}Zud^L=I1sPW-t z7%7{54`OJw9^wSk4Bk2;|LYT@LyuwpgH)iKnnzE0IHoTBkLDA475HSmC6pMm(3n~WP^$f49Sk5W;54x_2X$xFcj23(rJQ zTyy8w;Y2Gob<~@iY(cWE#U7@gNQ8G#t)YVudmC$mx;j?;(|xU{H;)N5jLbk$$D*mN zQbyM0V@z%>t-YFr%x=I|MCxpye|Z(pJa=lVw$aesWsP|!uu4Zq_XO4r=1)_|?u;B& zjrdZdCj^?5mnA3<;j?hLwy?p8%=e0E^{lzcz!A|Z&%bj@C%CF%t;>a%N1{`1(n@T+ zv0qyxVWq?N7Gzvbdu!KlFbP8+SL>jW?s5%IaNHQ-uhoC2OyIQu?KPSVPEhX@qL7-W z)IG{8m}s`CbvzT|P$y)KWyhy?z6#C!z-fI8sj}OHE6v_?GO3v}syplxz!ikpe{LF| zc~fjyR`;mziEq|FF?P!XHkN%8r#x~BY~57vDsf=S{ii_|6CI;!z=4VsAW!^T_Cr5`}PP{ZaOhC9TdBArvN>)%B^Ic@Tf65E_^{J+e`L!oGn88-N zqvSpOM@LamYA8jI*j=c*A;feYbGD*Q8HyH?$%}%4?|0!|OM69wi4~J7ps|ia_vC;( z6wmqEO6yvvrDHm9LsQ4#g!ztEp@TW-U9ZEm+~bhZNiO$wT#e5ft z{A4DF`wj0&_2^7nr_a*WACAU_xO)PnnxQ8;&JzR_(NYISR@iM1e!Ecc&8Zu7LqnOzo~c^0_?>4@h!qFx!i^5(1x!K$}%0X;zRQBu~Z_2?Ihl&5=|;H__T(0281k?Iu~Xmi6L_)#H#bs z_T2Q$6WdpbsjT2fTlWr^2ogRK(eQHsb)3LyN`|GXYBS}2MTRjIFvz5zELpJty}|0i znua06@Nywr3C&P};1Wpr4Ec4xQ@O+pNSX|WB6y)xx1w2E;M1$NY$wrZ$;f!59jOc-Q4A!klxt&HNCTMVPDHM#5c2E`kkM<-0&4aYMTMNMN{CBFV-ixHjSn%J3@ z{-c;soCR)`oRmpDJINmqAe?!DKK&E^<)pA8=&PqBi*w_en3h(v`0rsJZ(SKwioe^q z48k$S#H(2Y_B1v&!SD7&=J*{08KHa%tD^$_JBCz(vv59UU}#dbuVf^zup6>a_v|Y0)bqV9p}XOlFQF5+zuZ3|HtgoXe>?Qx>#VVahwQ+=Y3Y z*D=T4?c-IcS>UVDWJ=(E&t7<)E1xW&{(Z!9#6g-nv2Gi8ipe=TiRzmBtQ7YN<$kMNhglBMkYP(xAFJysS`hyad~#m!#j6fOI6q?4mhxsW5g z$npxrS*1!$9;FS8hl2_P$kvE-!k#*yx20z7Pb!>B%(2ZrwljMLss3vCn8J7C(hH{6 zIY}6HzZ|4u9AAP3ai|OYELH-(9Sv6ci+z_Drcw>r@<%QZVm|DA%qbfllOaBe%))?! zI{EufhB;E&xRBNLKWZ0?e@xZC@ZE@F^)Z8KT6?2Q7EJ_$=F5z1bb5$s-FAGdP=wk0 zw~5!HfBUp2Z3%@`cXvM4f;XZl)lTX>nsv;L;%1XN2Xj)y{T*4y?b&@_u1Z6oFi(4P$)X>@ z-DE+=Z9D{5HJcHhqoogiibRs2j+02GN>^9Uf2JM=sdTa_hWxsd8s8=*R3Z$Xj?qlr zPxwcMOc83oed$%><>iiirrIV1`4Fi9JPAXg?mj0Yrr3z7k7n1Gs;}S*0*bFAwhgWW zNM?c=&m=z)zu1=j9q}^%I*rR_*t!qIcEQ~tmnLDrWie*!>m+H~&4|6?3}PhIK80ru z*f(7~x)_&zWnT{s!r@hkw#6L|ijNH>GcyU{-&SqVReQB0A}7&TDMzy{gXc^+96#d25o9D5TGcO5S*Mm+mUz)8TNVF# zyfTBvuL&ij^uVa9A$9IEF6|v`n;aAk4bh6A72DxAP)QR3{Oqpn9|m;9V*rZd(sOl! zt9a#e8Gs*zcR)w7h2;(vq zk=QE1+>JyC{*qlsOb@!Dh3v=7b{ab1*QGhoWv^D^OC{dQ#lD*MMs&gX2A;H0lcAN0 zF-^Vg;2IKW&RSS>JH^Igx#o{Mv($UE>V>Xth1>uyvx-$E#dE^ie)SZtI~>zmOO~sx zyO&i)+cHnt*w3QFGt1)ymPAM5tOF*@O=(c<&jE*QeHQ*4ByxP+WY0^kDo!umiY!{a zvVkM*HW}P53pZ`W*?rqFYJz-IW1>cV`--4WqnKoHLjDV(go-{4}XRxIKWRcw$ zEW+s3kadIOem%yO%xOy-8DX#6djFzIe(VQlmN#{xze&porFbrWSa>MuVRR>HXzSySv(+;ER}n7W;Z=0(Ie#o=Q` zki`dJHv-8fDW4qR!w=5#=k{0Qb+J=DUvq~BY4A;x{wDrSv@iY9Ma$@A7Ljqun?+aI zZ?N}ZU+OBIl11OqZ?N^iqqg{Sw3#e}_cEZxlJV%FD1i&M!i!5bnEMUG(u-n)NJ-L) zV}AUJnxVR=q>;a*{fbF#S=r{! zjU&QSqoEhLoctzhdqfhuo06TEbP+zIERL*|n?*!#2frF|cXx^3Qn8b9g?ScCqm@Ph zqc>~HZ;^G0GO1L!2QRg8R!##nDe1UW;(3?Yks>dukcw2Z(-x$b;(Op3L-66Q5&i~C z{KsFm_-3h6qG}e zsSLnWMzm|N?+X}rN)MLWX1!j0NiCLQ)w<%6WCzD?-`ei(Z-aDFcgC4+iRGBn2F*!h zOsj*P={7ckT)dUbx#}5OB(!I~kTgnfXz*w1+#$az2)+L#aQN*4ewGe|{)fuUd00rTulaLO!AwJJN$rh=h?WZr% zBxs+OrVFfJ{5szmgSa3Eg)^*8F388dMKm2oaI8!+#Awihrla~;TzS8LhwAU%J49+H zN*NEnKI(C#p(1uROI;}4O~rwk$9q1#y3lMlLUa02Q;+gNsWA4!s<)zASt+Tj4|qv+ zzZYj_CdK+(nHP9gm|E?A7xTkpX6CiGdRx)eS5W;We}@U820xi*0{(I3h_86! zoIWSR%hQmq%9ulghg!BAIy-6~8T-#3)^*Lk3TFOvstfYczJE2ZN4Y9^o$EdB?B`Oz zh<#*3BkFhF&inI&)ZmqIM^&O8O5#WlK6lRA%5~)E)$x4y^TCKWwwxX~&YZR@UtSsB z;259p0uMc|{_|DGimvkl*EJ=ak+On+@?aTyy#um}$XR5)%tIzsGk^M*IU3T9*79Rg zl6%8<#gT~zdZ_*#`%2g13-)*%F0K*^9TLborruC!p^38@n0}PBn~cA2I;;)0pZucA z6d3J3=!V&e5i8rMx~lx7Xdbc(`t^NWc$(fUXlh?tRZNYN8ryEY{e#jzf!`qO!iDQs zZWw2~m^7Fo`h%Jm6`3qAby`e42}vWb?7^(KA}T>>WF0dqx?^sBuPAOMSdS@y$IK;? zpQluz1=$zbrnu^no@G^Wd&gpqAxPc z9USWVnn7BOprm;Nk**M^@>5K28D1wTK4;`oQD{|yB{cAB2P(}*|3A_17j5ZpJR4oX z8Km7*qEa|bgil+tayO#l?+^5y9~j9ZlG=~BX1~4#tsD-+bme=|p)jaog$L1?_L*=A zVat6t`H8_+gw>&k?jA=HJX}?tdcrok^#eg=_c(SLOsT=vJ#`_{x0kUpF3d0gS234c zwsmUHHh0(38B+xFV|m!z5OqM239~zCNfacsA*g?2_NqMbKq;QCPER7p-4y{~EI7iN z-l-p@IL78*5pInr;kB;LnO5XH57dj9L$eocqZ-KrbD6&+6#QFOE)(NbixeH1RlGeT zPOtV5YvhH2jYn8_4_4mI{3h*R|1tRDz`iS*ek=U*yyp)on}g`jiz1>WFVgM}F|&7= zGe`-VS-kt1FD6G=_tUOhr-sVG3o}+QQ}qOv-W+x9oXvtcaJub5Z!Gqug3adzL`@zX z+UZf&63Bi@5t#blT|#oCDpj37iE3ON?J|L#=j8MCa`INrWbk~rq5>-emNJ-d8+ zbg4RxehYl*J$;5d|0W9U6xvMiMsjKe69NEvsplaT}o&`$2VpaTW+6Xf3vMTYo%y+Pq| zJtEE$n#lYIR1r=j%`&Bt=|(XdMMNDNr;c4(NL#_e~)A*WO*5I4pR0U|%#IuD%Z_fIK zIl86lLnRGrXE&4@f2#ckVA0BT^D38m3YWBq)y__o>D*zkUNGqz5hGE=Y8eZb$gtWF zBP#=cEQ-~V)48Kywc$iozL3(nhnzOXiB$^F;Ux3(E4++W@R!|$E{%?1?$0+q9*yWr zC#U~##wv3XaNFhlrDQQJBofB(xc2)u3ps~ip}d*>wM5QTOpvNwKR-+ELRm{bo5{rD=5F#~dUE#|W(Us7JK8`?Bg&W<6@*=_9!Sm; z#;8~M>(L>dM5dIftMQj=#+mTknm?jW%f5Ox1n6&+f=z(1W%(*cL=2`89EwVGF8yW2 zS{Z;%NvI6RwKuVG^-!C}R{z0QC0*CTVD3%X&1;5U5B&zFZzQ+e?6}u@YqxvY zE}Ws9c_OG^41Jak&8+2zb?>cxf$+d+lQRfJ&e*bC{u1o- z<#ADJxjo1GwutMO$CTgMq{kgD6fd?{ngWNud?3poB6VjZYzTh(|=!iI{sZwoxZYkj9<>av}d{B!hzWX zqyqL;Ow#jyw296R>czR*LKtq*cAKG%h8m_H1Hk1(!FN;Ao`Q0O7Q*WAt9(tzSdEAs zaqDI{+FyA!?gfsGVf`v%G{glr9UG{Ot1?zDcVr7ChaaF(7Vr5!S=b)yB~#}$EVvxY z8wL?QXZ`eD>)%Lru`<-@iH3)TkM#c_50N06ZzzUbaj^MQIhWWc2ze8Lf-x~%Yb21V zM-wzXOzSUR<^}17M1zU_OAw}AbyfB6`r>ePOr~W25Hx$<9)2W zYUQsR2#s$W|JpJw|Gv3+bRtJF3IlVjk-c>Wg^MFDYIC-Yx9?-^T)zcz+B#WR9*ec< zW!3icY8l<%)e5Lmhi;ZZ*_oY3?^IpZ>WL}SUEmwcm7-K#B(63p;BCe<_m!PXsGyTIY@F6d%W2LOkbq?k|D!4GP@qxnQ5wkGrrb;?f5`<{IE+j$?Ht&P!sfd=V zU8uc#6D%Vc6SCAAMRr~GPw1Ud1fvb3$QIc(^KoY78h!(=eCo>`_ZfZ}V*ExPm5;ZH zWL)Gk-jreaL=Wk7CLo73K~Q@$62bT$GInImt0q6oNIkp(xo zr#g$FYLK1s@bAv3u*5%0VqDn8;C+P}_onXZ^xDXMvcx=}+GZL+6Mc%=JI3I=+B?{z zxBqvw|Kg{tjJmtN>~3wmquGUK@TN=YcBjDHGWK>8=RD)o9X+^;pci<$khO(Q(6c1&F+pxAvR89BJ>=~6K7Lt9YHl+6@G4&CnSG)hlvzT zUT5_-Q5ex~^gfJLo2EKIz{(X^YcYbN5Y9eOT{tZ_xFNe&n1F;{?@`C%6jR-p2v zBPim3%EA7fQ-SEhd`W&yCw<6mRPx*M!}>tQYsi05Ikj%-v~U3;bN3TM%_sA%x_9~d zc}2l`7&l8+z5<9FW@djiT&Fm#xK*||)gXKZPS@feLz4snm$pVbztP_(#H*=2>W|%_ zjhrrTL90LJUPV;}(ns)H^9I!;S)6{JV9?SUA7w{%Ti$r7pJq?$VKQC?W6j#=2>OhK zDF?=;iTGHG-nmU^6H7RMq?{0iPe$j_p8@Nk8LyEZCE&DKAd;M4Yuij~IBHP-eEIZ3 zHd*OTTPB`CjVL`&E3+j56mz}k6f&9&RccKz*yg$x8CNK<)Ppcz*Fo6A6``|io}Knq@txJ1o>^5Wx1k&(+)<;mlGm%hM?XH1>> z&(#Q0JUqKLQok-wzfd*#LCBYIFEvTUIwbaaSHuAbW`lV8i~KMz2IqeCjbaG1ctK}Q zQHCzmxpqJiB=;nQwK42mJ8YR3jOr~z{(+m=IN`6%CP?mp&#Nl)CzARV?z8kKrjejH z%baH{$6J`3qR!%qIUU!I=gbTB%_*Ea*1gfqY1BK1y|K+1%oCqy^v1W0XGrwFdGGe< zZ>wyd4uMj9c|%L8Tg|?)+h{Cf+s8+~z8wb27@HVHRD7f6iQz4}=hNs5U(|zK2eaFA z8MKWb;62%B3WCV(ei@C>Fmdno`0I#(sDhv`lNQO zEOtSLa@Yd5_f9;OZV-p=w1f}W*a*LFk#HRu47=%N-TiQ=q2(K|2B7$|Wtxtd3?M9; zkoekihzz}XwzB&eF(G6*^t0?qMm@3y*{0BsTB7RoB~@}=gh?E%MUIdl=D^7Sxhtt zgYBifoE|Bns1bQhW%UC=C2$pNt!)60*q`oAV8jOFm4{v71JWzL5?CD5Pj_ol>ds*6 zGE}`;tj5eEu*(P2PjhS1x-br@4$?Lc%M69*`?<6w=?}2(u=vC0w@P%USQ_)#+=hVLt=bDO)SaC~FrF z{Ed*lq8V}_mMJ`tP9T+hwbP4Z>55!mpp!e6Tm>R&j_IpuympxDJCF_-fC^L6`L23mz@;o8;|nw3o% zdN_9?Wf0%D&Jfhz!+)eX`5Q0KjlrP#YoilP zmxJLzTTBHu;bNKQuJ`dxTYkc=E zJz^u{SNT}{z}?n7YT3`*RaE4My_~skhkpJWikNq+L<18E4SAv-ox=qeua(e!l90eO z==>xT<4c=gyb0``eS}Ydr6IX@%x@vNaf4(-FZADHvh9Vs1{d?wLa~hxZ1}Mk>Z23J zp{m-Zu3v3BNjj?P6EC+3A1#u_xqaa_!{<3bs8^e1)#sBTSk8f~IV>`WjR+k~Q$jHT zsLFqzett>FVxwu)AqWf5Iw1lnOoo2Aax*}_%Ss|qo6O_y;zeVYhyV z`2xq1fAKPXM@7_xL^pP>DbV_26~3n4(B9W2c9}sE_j+B2$$mq>Yog)m+ug<6)cwJ5 zve2`9UqtND3520}@lus|J+81?!i9D0Q~v5EYUfiuC15>(EpfZrlHMkbd(`wU`ro|a z43c5hA7}`ON;n7z!T(p@@c%ll{*xa_#r_}QFh|Qq14|Z57-b9<*>s6aDm>8^nP!Xv znPCuakSdWH{inG30Is#Sg`mRN*}tD8bRYmwot`meRCJ1T%c3GWv6vxc@|{Ywe=S#> z4T*YRc^mT>t3zw7rQO9~jK_H5zxIgQ<0|I88O-q!I_ z`tp-sUoW8m-`iu2`>#5Wf;HRzl_NmlM^BWmfg*Yj{_*G)Q{RZ82C`%nGDyCf000}^>K`V=u>W?P&Lo_{*}lTxaW&=z$DjnlJ7 zrye!f-)h+dCbKhG*BYdSlXDgPnRi$udDsQkDl=UYcC#Of2@yZEx*9JjwyW9G+Zep* z540oT7{U9wA@Qq>(#CPTgrswzM=2y^??T-cPVjk6ni_TVj;^EK5K^%LbEM;Ph2`T) zHxm=|rAc0(2oaZRe|D%B^r2Hvw=@%5bbEp(G_@f|P52l=6<%|s4YH31JV9S)r6u!k zkq7}?`BDns(A=O)AAg>$ir+uGs87!17P{S-@S6j(2<-76Ve1PXj7c3sp%EwE<5K!^$C5&CBk5gGN-gG?=TP1C5jx>>Om?QF^(NY7Fe$Hb@>U3I#*Kg z6lo1EQ<9pw(xMbnhu;w`*oYuz){xxW|Iwr7Rij=g((hg)i-we}8`3()^N;B-zIo9* zXd*?tbmfi8-y^T4HE#9qfmnThOm@nvc<5RW4l2YP27}(qTgm1iA_8~>*OG_FT zVW)@oDG{og^r)-Ahf>(g=f`!f*yZ-W5G ze}Vu|L&;%Q4BhWEeF=eu8xlYeNjDer8#*x7jVw}E z7_^0$1bo3egg@2~9%;ldXDjN)X}q>P=B)NZTzZ;-=|81(Ev%1*z_ry1KQF zi@gkej1Ha{xZ7r7q+SJpc1jk^gcvUhXI8q>+2$)mw?zM|!tT|@{7;EV6cDeR11W^I zSWZfR4|z~LuV(|&z`=@fPowp%!l1(juCE~2bV|@6NuPCbj`HzzL`(H z!TARn^@;s~T4m_HiXe5n7#9iO?XRNwBtA|k3|eWwhqh#1uc|0zkrg}FWWke^2Nljb zS29D~>~$<14MUydW-l}x$pZ0G8NX+^Eb7V;Tm8FA&^EsO{s(1B08NT$(r6sihY*Md zuX_tTt7*2Hc-TTVzxHHvA0+t|2U&%6D*O8_Me;$D#pL(9^f7f8pXCc8WR}@f`wEVe z&hJaDwuB1iYT3^GgcY4_fLq&XU(P1br4nVGo8dfE(gP~CME8wH&1~LXHCyLV=?zLr z%LBr}>7=V+pVBjamFfu;P}?o=?du}E;O{Im-0d0voK%?I$`Dw(C)gI)lnn}-9})LH z^#oWI){_mOV~hpk`ge%`9yr=cg`!oT%7cYZ<$=Wi^6O!4Yi?(5@9Oe@#*e0r3Z^)g z@a($#syY1<6ygqH1C06CejOVxpp+c8WG%w8RU4DrcT%%9=~o>g40ZyPyf?K$!C7m7 z?W;-C$iKCY!wr{%GsS?{*Bjz)t^mr3&171Khu2{?H1FI!1Pp6U^j3fBPA0oY`$>8rSC^#qb>CaJ*fzC;5*-MX z2jFd$7k83{tp{8JuBWSR8!f_MLJLrxwd=6UQ8!oj0EM=TLX@^&=Hy4Oezy`o+GCEO z*P`OVuIgiWtvF=;B2-!!_GF=x_=hpR$C4`mfb~+|G$6H%Np>(t6^nK;$=o$BPvg^YQC zvYZ+`Dj_bw%|vDd)Dt4tl}IEso{s#2mWw zXxmhyc$K;e>Nd5N91>dnx-gYoDj)TNG-@A>m7zpGD~Y$Vsm(-aI%3Na@nqD-J#;{r z{woTBGah!Rf%9*A*=Ms@qWxgOJD!M;C$lu}VF1$fo$-Mdy3YJS3;i1=z+~ed ze{xmLUQ2SWMFdX$-l4`el!CG4NEDM-Ewzrma|-p!Or-IT(RqU9VO%?nlj!RQtqh}_WpJ0IB^lumeU5$IZ$^JGYmrPH>>_>1KiI54RdKlwF zW=~Pn0o2k@F^C~xJo{@My0`Vj0M+MG>W@P3FX|E3__c()_yB_&HsFWu4g7ssxB5SI zq9Ki5^~CaI5HcweJ*So)pUxk7_LRv|^%T2u{ZtB@{FC%@7T}#?icGS3I>Wm99rHW{ zwm5gaCMAH7vO+5q7+WNPsX(k^rJ<=a|4)4!wAG}E1W>8bQ~(%E7c~G^bjz8|IsM9W zM(Z?ruvZMqp@GEA^AR%>BJPJq6KyOuV3}J8ma$H~s^L*G$XX=Tp zRe%D@r-VdUz`zRDqNkJuu(6`d@l#jRL4t3XKA1wPQ^Z;UI9j zLY%MnKgkYFnB*)KPb4NSIjgVuwKU0$jhf*z7z)f%Z|ZJGYSth&pgEYXbV$sbj21_& zbxB=;&Ik~fkg6|pj8BE;#?+8K!^!N11GF$WAyTN!KWj-9h?}`(c7p`s>Yq>mSR3a6 z03E#(48SJ|t`1n#J>dYbHqBut8(V=Il8wzl74#j0>WhhGhO!}Usro9%unKm?u1UbE zQZTH-x+N%!u5DSJ_mj9+SO)-^!AsVlRVKGK;6*;hGJ30?_KD2lQzy7D3YTohP;D@{;tONzrVi6>a zSaaDgp3u*LG(gRh>M9z~(ZF0Fm_N_k_-#m?Rdrk1yWI?wMlW6KGoW6re$TDZVb8Eu zC=)-%X4nytRqQ=hx}klUZY?_B9))IQa3UPku7b99qEp!SD{k}nIt?gNKPQ{|yriC| zd!oT5dcvvTr+kbHeoTb5R@w_N2UW|%b=A%_l{`-jxlH$78{P>E`{xhEQGGt^qEz$l zuhjU!@;ksTfOGz`wHa369BasuUH}WmVSq&&KzDXzXBFfqbPdHm3j&acKRJp^;P+W*zhvYhcf_t9F;?@xYH1{Q z@bNNAGxR!n&M5x_Ye1C0aB@aNETUs$G(ta&dLLsnrbh<)8^&?ykr_=a<9N$xY8lN; zqq%ALO``<^U|{DI7Y9p+6b8cKVAwQHU|YR!t!A0(v!=B@{a z3Un$jD=6%wtNJiVnN*Np94IRl=+G((^(8vtT z;^5*j1;sdWnlo}?pg6zNq_Wb2;(P@AN<*Qt;i1C3U?~>z0%d_np>{Y}R)$F7NJUCv zC_j=n`W6%yl=WvIGTTi>dWMAZaD+NE(75uVIlJI9UsWF$clrB}jD{{*A)bz?C1Y>%8@KP$n-e!S=hc>`e%l zBO?zbx-2-QxI7%pn-~li5ZW)i- zx3Ub9Jg4Ue%VLM5aZpu`vbHXxA`SbrOD5n}sS9S%@z}b?-VK@*Bx78FmMKcez?u=_G)qp3QLKRs+8;|-4C*2|(?X?%c~NSH)|@R%b<^Y& zsl^0i(D_(38D$YTgHFfTA%ps^DC=^RN%aatfjqB%OhLFzoAenBcyI|yS@q)tJ@e6N zTnH67AKM2@gL$!ba%hda7*tpq4CF0M-i=WfS`Z{Nl|C~Wa~KlKa`0~%qT*&7Dvg?M zjTzgQEY$mZeu6##|K5})o?}dzYRX!s(GnGam=-Y; z4$tfeADv=zuTx_6IND*$i(}?v$~4?ysg0vmPODl}p#|D0r^RmX5kcn#t#CDCtZEMO zDo_?ef{j+DZ0>e5ktEUSMukfX3ox}vj!7il8B8h;l!WJn+!^?^?hOfrN^7iu)4Uda zTn(Ru}oF)21M(%Zb__Zki+M+id)8REwXup7LQy<7NFH2NL>yju@x#W zD+z_kjaBml1%;Se#5kfCPxGeCGiAt>t4+BUWh5%GXoHSz2SRSCU~#Z$sj1SmFX@Up zx`~h5XVtk(h2P{4%jKDcoBNI z$n2tEjM-4NP_850I_+vxG0uumMT`}(W5+@sM4BVSUHd_$r2&+w6k2~b?~C?|0Ix@P zQiBQ$V>wVOZlbtJ9`k-T!|f!-YDuzIn9M~YlUeC$r3GbVrPb>$JLAn+8m;D-grzFV zth}-{SNLNzXn208jn*uuI4`(l{9JO0-93Dc!=+j}rFzFErxwIwvc+idv`MA|=FnhC zX%N*rh%1mWu^gqiC^)qsT!1e2pyJ|CS-|z-8^+8p+6J{CqY^u!10RF)<}6obCh9X_ zp6*REep0MJAYH986BRS5i{mScX_Fq)WMm*b4^KX1Hnlhms-&^UHUm0yTvECJns?(G zqL?nU;`}>W(734YOmQcJDT#bK_Rf+rR@;CH-u8duzj2MpfV-l5oTrTh8jn__ybQ+* z28#OVNYH-Q9f*!NGKuEpbBf8lGBD{FudQiD9P@IDqr7vsUT11*5&1FhWQ|*XDcpL#ENmHaZ*G=rbgCkCr78Dhlf($YR=2O=rRKD3BW2W$TcV zchI)5gR|-RynQ`v8(oa9IKgO5$Fe2lmU*2!W$g;M`Bb-Sr{tW(B4}DWoqSr@b#Z1d zBvw+TZFHm2(v!p}8FU{KDlg3QqkrJfMFUe7^v}h0B(3)61?L9J3(Nde2>S!YdH%UN zMi}mB8r^NVl$S^fHa!w$aDvYa0D*qd(tn8Ut)&AhBN- zhl+!?F-Tl)8iQ?P2;XiSLycj$x9F*q1(%d{np99!QbQC9c~*VjFGmHV~j#`?eE|xxfo3+N;mRp#~%J{V~jBt@s<^oAR!$wv5j%Y zc+;3*8z+-IpD?93TwYQVD#eA5^2`aI`peL9@@JxlhGIC;m}DE1jVZPy~9SbDe5QUYZ} zK$C){xPAMz8FvxFMww}p+r}beF`f)BgB&W@3d$T`RFzHsVzY@r&GjB{*bg>kOUU*a#@#(7AwxQu_r zpv6(cDq7tr4iE^JjV~q}ZX4&L*)}dPF0_q{jEm`olDD?DvC_EMHdc{ZtAg;j2}4Zd z65CiUF1L+KjWuYo3&NxD%t@G+Q8|T5lPEAj`ixjt7&w|mwY03Zv6ezKRNF zxV)4?nYM8?iR3lLwYG7cxW+Zf9ZCbm`Ye&ePdANqwz1yWKn&Sv8=H*l(M&jo*lA`P zH&C7FM5VBJBdzUC#%9~NSzLt+Tv8e;L*`cpe!OQUd}o9p&-| z{6#?uCHX^hF;9H(XA*0+;0E8WBQmfkuryR^8(XO_C#)O_pkx@g5l2N?0L{ehlP>&`JH94@vHg-@k9Vdqq z%Pj~LPKeN88x;hq7Z1{Hb`qd2@-+|+FO6xii|T8~)NAbB8at3zR8Ty$AWW~q@+K_8 z?d3tDN`^{;D9n2(Z!v_NSwuJJ5f-7LQs0`#M= zf}2uV$WI3>e}NMw!h#e0!`00`Dzdk`AolV8ybyW- z+Qy^CW60Aa@kr9I$4%o2+j!D=$~N{HPus>b^mx{IjzP2PBbDekMFNy$7EqO0AKQ4I zTKaUjQrFtXf2gKQ4RuaygsX3F@wd^oy0+ibIN}g#+Y4k#%-ldpL0O>CHeRHn5hyGy zAfbB6KDmY4e{I%s*NtcMdez$OnfQ|&B1BCt*x_OYNz5I zs_@M%K=V~XMA*iDs;Q&f#a6$o5ra!m_vrYGP2YV}-_zV0l_Y`b9)F2zWn z|IpTIx|Y*6j?k1+ace9p2#1|BtciPZaXv1J33?l%5vatd)FyiV&{NaRTzk^quTR8! z8e#)&Rkg>uV8SJ5q(u}3IbOOH_X>afao9FFwd_$tE+>#f0kc4Ub@Ex^31s8{p0r z>%k+iA#uraU3e@vqH?`N&m94c%?#5#PREnni%$LYVa5&GAVw1+!O*@lmX0@@+GaDV zasxyC&?7LLBXQ^mBAWtEBR`Gj^L%WqX`$l-=wxI51j^en&N9}uq)0&B1aBGZTTy*# z)WyZB)|w*i<6^0e*_L>VQtI=ZYOHQ&wsqhAqi2fcEGpMe;`|~kn_y{`ykCU0CrG_S z_ZI;j2v8^9|HbN#RPFP8coc>ry@KTWBDfP3>LvQe2Nv$%?1FM-cGY6!IigtI z&FpTQC+gXUUCHWUo@5)d&7QU~1NmU~B4*5@TyL`vv8AtV_QRanpIX(9b1Jd*0AsOj z4kS=&)UCw&L9~2^4%K04FdOtU5^mUBM4oh ztA+WIluwEHURaSs6+K(}hXjiKj7Nqur2OPc`6F@PjBM(_s7 zygtM@g@E;wxP1tlUb&&`_aShGj_Xu%{Lp~RZ0VmoFG#`F!q8$e`w?3GfzqHqR9v{! zPuDH|1#|sNL*=@Xj$+y$!PQ>skJ+^S$izixjY|E_)l=J?NwU=_xnGHcPp@+D+z{@| zp+ek|0%guw&mqVScKgdqaJvdbH*No%Ahq{K!d0l!J4Jq+O01qm#5JzMM@8y_|1EXe z68n)k<(gUkww-7&)Q@1Gw5^|vSb#1QHLuD|D8~)219X50w^ReW1`Iqhs!h(dt_mm^Vn0|lk1x^t4q zORO{xjAK9PMqZ!@@%*^~twM8_`lALYGDHdXO)Lu*&P4_^t?od8lglMR$Rj%ZM>%02 zJtrLXbb&nviCqIp(s31C0oMx}c0wu6ba1u&uF=!J?$UU}j+CcHPbk>yT%t4IoM)N^ zwwNrYP#DSCj*a%_eA`^0_mzn6g0(l9P04%0vjMg)G>c3Vtw)F)ipc#htS_Nn7gAF@ z#_IH=9nU!{VAgcb35Z=vh?QPRIJa^VUP(BW2pG%rB(&iJ?7<{$EpP;IKZj}Zf+m52q=dR%Cm7tz>a>ad9@AX6p}@6gjUFSgB< z<|^B~#9WR1HZR48ai?vrLEqiHjB=N2C%V!-1O~lo#M`(Pb&hnIM9mfS%HvF$(x1XsQ<5d)#Q#XzXDD{XVFc@^c5{;SPvZ1Y<4I@?@FlUPfS^)!dIezKWNv2AM9O%ukQVJG;`{OHYvqPYmJY?UYA&iNu37WU z`1}6xC4D1pSwTspfxZ&%k0?vkZB95k!_X3;pI2TIVO*V%p zIDJjh-&|UezUcPaQEpTw`&O%N?6*ixm)fWd4bCag*G45hI(7GJ9Ga~~Q3&T-R>KkI zg!_gO!9i-kQ&dp>(x@#K19xN#$S^ zef1D58{-Apk#}g`raINpJ5tUzABz^_dk@CVH5j0;IrMN|(ZDXoO&CI5>dB{I*$K>7 zp&Uu>6>GgL^Wyik`bn_#-B=gT5lXs=IhmsQ^dSk#q!Y?_Oo)Tg|G!c?61Q-qtGWqy zd&1<6g&jY!b)5ebzpum!ct-5K`yrviLg(dxV`JTsCc0ONDu2o_)%jT7Q9~EaEC>%P zDj`=iHD&|Q-!%WriN}1GoPy#y-2GOLMxGG+W-k?i(ec_JgMsejtelQ|Mdz*GTR8GG zIgsxRI5_&of&@(KP#O^u|JEYTQ6CyA*B*YVmeWWnsbUOuM)zJb&=^A_YcVqNPJzDr zA)1y>38>_sBOb;xM+$%xSU3(Hgxc3Dk zwW+UB2j%6BcLG#yi+Yjj7^`HW#5=ZtmVAiwddAt-B3t9Yf30@jXYVx1ph7wiSeP3| zpE5cFj&t7aI1_i-Pl7rm@-D_Pq(BI?J6=7gPwx(}yFVl=#<)bWrU zT&GBYVM|I1V*pN()Nq*l)@6e8)&+MytaQb5f_~*P*?FgemM;n!;=XV3U=4BS7*lDd zAtxLgO{w&bC1HDrpzEDCv4Q*2#nH_yx0?2)`{C%)};-?CEsD0G;-ePZbE7^n z?qP#?MU8&;mmlZ7HAr^O>*HunjPsTsb>8x0oj2Ur9gN5>=DIq~lZMco-kl(toFAf} zTIf*|{w5{Nc%~AQk+)WxD&=O=cbFk_~m&*3fWC;_Z5Vr z-cD*kIL0L+VqzSfIxc3^6Vl(E($<^mf}9doJC07I+9}n;>O`-nVL>>#)6>`kRPuQ! zdYa6&X^@%R6|(0z*{ROgx{VT>M;)C+i09}e0-}yiBE;DhnpbL|_wBLK-??Z~5U$Qw z$*;y&@h5E>?{-vb9|ul8xaX8qY8>yBR0791CC!ue9Osi%YM#_5sRqmSNo;p0*CnYH zdu|JpciAp^z##GpF`=GftVxVzG{%~W+7RQ)BXL6BbX;QZrW0Yu|gxDIi@!k}OAA+M%JessXO1yGE5 zxXt4czO2&_C#CP(Law{nvFfm3l9qj(t!nVnGFq}`nN=gUqhC%?nKK9LI3(@2!GipG z^jkD~opqp`w&9rH$vF{MM2`Ft!4XP+3SHDvUhWpj&iIa({U%=_{%D^AWV*oA~trU;?M# z2mr>nV2Sgs_;(w>9rN|+Gk;7aed({$yWI3{H@!!v-LdVxd^NkP{HLt;JD_1!_6}&2)xH86Bh__NABK$SBI^P0O`0xUf~bVVU{cSaY0`9+ z6y#EVTm;Lg4y#E7%RCyEn>{|#z^bl6(+F1GYDaIHq~E&LQqs&rt9JZm$vRG{u0?YX z%~u_o-$mO6E$W(jm8!!&A<}8`MRc)R)@VIj)o49i*JwT4)Mydg)@%_oJ(jfF3Mu2# zvUfrItXNIsG+FFkj9_qFG3awtxs9t!{8Rb%jX_k!eZcX#7MorjqsBgWpcedb?1fV=do zhpD}#s@fF9^yi9XcG@5ue;urqx>bgx$~`c6dQ~=LCk!EQhQ!P+7@8EdLCsOqlcH{g zz1eBQG+}FuhY=u-LXw_owUlUGsg{6AG4KpYd>Zb-cEO0PkcH@tDq!Ru$co^lr~-^<>H``Cx@Ktz=I1i16)fk^5u>o}Vze*+K?QxmRb8j%MPxCfAG>f3z1z$Ni9hKSf&fE< zG6#)#Zt_hf-Wl5oc{?FE7G3SR)5q+Cnb~P66_CIF$j{kn^D3ZVT!+2JW-zuM`8cbC z=vo2ud&{lRpto{Lgx8b^-vv@PK^xNKs7Kbpm-~&-saXLn`Qs@`@qIwN~lIQ z-8Qa61(b>&GPYVZklT7&u{9|f)+6Y4%!EA1hXt?_u7s;0gxkw4xSeF7v#}BGgoUsZ z_P}1Z`~))MPPkvE&%z7vGS)ug^KRQ|#ihw$8T7zV>XFdDf&k#Y35 z1k7Y9kjEN8K1+oHmIfs(9hS02u!1#)m8=O|i5uC~?0C4AHHY=A1#Dzla3gCEx3G?| zm36>Pt|Q#ZTEaHg8aKH%a6iI#B76_l??w2dm_C7Z&tlyRn131TUS%EilAn(oX#v#b zU-NH}#%ob3cJptM(upvPf5*Q^JD&&Lw1!Jq0S);N=nE?3O>Ok^ene5g!zBM1y+H|& zx;X{gpb_@+3$}gLt)o-h8?IOlfNS`#dbcpqa{tDEcYVd(Q0FkR$K-z;ffj(f?4P*N zV#(xx0gN{Jfxn@i$qycZCSb+_v5ujLn*7ia>{ECk9Qp`uLD7yh(xWVbMI%wo-$&5x zRc-|qJv1JNc9=R#iB!;kSm&UkX8aS;5557JVj*-(TDZpg(K4xi)c5ow3l+I+>yfXM z3U+xC!LCx^jo2D9!*~RBc{^(JwUOZV6r~Yi}i!StUn6=0GPxE!4x(Irn7M{i%o#j z*?5?PX&xH_K{gbXU>Fo4yaeH8SiczIOEF!}M!=bDBq~M@oR9E}5xyGhFGKhhm|lf- z>#^>7%-@7{H?s*^$WKK9oZ|`VQcqBWT2Q}5LA}DOJJS>1o83B-R?`#Sd{209h!Ngf zp_V7S8F4~bBN;ptFN24wkilaSRWmB8v4VQU6Vz8-LA^I^QH=$)Rh*!11s@6860t40 z$S(bVNn}%z`Msbo3TZA{>iH;oLtr)(qv$S!v(QR8fjq5aOn{EfQoi0(De8b$XM6x|spy0cJp1JIY92L0G<7{pG8AuJchusjsuAc}83 z%x0yK%gWGxFM|2397T5#6te;dvH1{Y3t$n#mm&NttY3lf^Dw=T6~RTU7%pKUScC8@ z5q=HUuS56-Os~hfTd?jn%-@N1cdU&+G&WRD~+hc_KUZ{Np*&HKUf*Jp}!d~ZVeUWf9%0p)uW z%J)W;?@j-|eAhs}h3AN$;>!0|6eigRgVUCym^&epGk4=!phI;wgE85=;T(oSasp;n zF!a*S9h=pDH?9$&PrVhaaa%!-+j`{PwDW7MC2eZpt`sKK4f$W`g$-Sx5A;U~pmZ?$ z=r`ady#?iaEXu+iSbrZ*YPVb7i~8{#ya=zjg zDC3Wyj6VlAu>YV7@*-?uFQA;i2zRi@P}ZM-yAgID!YZ(CH^TN{x|cl#kFb5{r#}t* z5dIv(U&Q)X5dIpbZ(`khSoaa;KgGJw*^8e4KEUk42LUCy=YQiR)&AenvJ`I@In_PxK9F`njrF5#QvK+Wc-*A}t#g)jPO=qn zVQ-ls_Z@jTLyBE+(bgkR%N{CL3ycP8TW^)2w8q5iM*}0-Y1Tw1{T#HN{7VH3h{ zz;rX#-G+7BFn)cjQIS^gQKuLNt=qZBFeX?U0h>H%SYqK%5jkv!dkc% z1k+;Y(;KkvR;;@n^V_iQZr<1v zv-zMzEm0eVYa;kvfjieTg&RGAyT}zYiCc(MN1N|oa_bQ?ilO_t6%;dK|qB=&%!pIE#JhI<|q*HS5^gJ#ZO8 zF7K_fGgR6Y6>#M)SX%*CVc}{lj71Tso!ws7U9%NZv$4BtF^k~qTyQFZ*HyrJtlN-K zw-M_$#nxS40XJaXjc%QljpB6^R&0)~xEU*MiLJO5E4H{5b~e4j-&z5;Vdd>^Wuxpp zaL4raS_yW+ojYM$1>A-3yQ_iUgYbJ@_;3f*+sH7`12OmZutblP1}P1!&5)g8Hc08( z+n0e#xqUq}%%aSFy;Cz%_d!Z_MrsAze|`$vdgOKN?txgMcVI<@Tj9%U&yaIFw}QWS z_e1FY+<)Djy5)^6~H~p8#L-li?7bgvYMQC~Q+$6F!Z# z6fYs!L@#&_tx6viVpyI7y_V%9^YvbQSgak6^Jr z&`BuFrLa!WN5?P?$YOb-foO>P*ji}f?iK@CiB?%o`Va|uW6pVNWFQUnPD?;twplb1 zjX}DBp7bLy-q|2ThF0FEO>vwlnxM|5r>EDgTep7m=HvqTDx>IVN2IfYV}nS$j7=pQr?j;*}r}5#a|>cB#%0;6SWy^wYYrXDf8?ZAZ`_ zBJ@=E9pA%lVXyn{?GaB8v_7pwx*mD3TL^tS0s4*yeFvfY6QJ*U(038~UIO%e z5BferKS+Rn=s`b3=tl`N`Z#VzpCmv(je~xc0R21;8e=cB@w~MYtG;ln_Ojf4ly@|!+*Nt-`GCwFWT`?(b2WD z_V!2-J$wy(4N^A41sPTYUsuxNDoC_l5^K36)^SO!r%ALM*J@m+aXlh2Jwjr7l*IHH z64NW-0Fh`Di8hgFpYKE6UxtJp{69wMp`?V;h90@OmG*aZ(c?Dsmgp5<0&5@yKf@nz z0FV96SR2+37P7uw$43^s=aFkdAyM|rQZo)F9Td@29dx$-P>8or% zdmq!E*k9}rEabI$L!Npd<);k z@4+&q4`BIQVT(FgrnD2aKuD-9UYuyxT&21X?!`Hz|VpX{2VxuufP++ zx#;Aa2h;ia5a1WU5`H0`1}?&rz)EyzR>K;;3NGiDz$1wB6kiK3@T-vit6@LC89wK? z!uNa&{LF8IKX8jbz;8z<<_^aAT`Yy)&1&&`SQ_8Xj^p>SX8ZxxhVNwU_zsrMD_Cc~ zoAu-mvcCKwHk3cYM(~Hx$=S=s@yFOy{y3Y#pJa3R(=5oJV)=X@E9B3zGX5M}!vDk0 z;V+@H^8&j7(~J3wY!!cnUCCc%*YMZb_53Y%6Muu_5gp6J;Xm` zkMQ@|WBdcQkAKWwfwe@`;bBpWmt(p_)aJ{?ar|7-gkLC{@-@QGuMo}nT1>AI z&G~hr1;0_8z;6+)_%_j&-y>S{?U+6w+VBd|i|-Y^`QxGwe^&J4uZaHq4KaYfCkCQq z4Mr&&#(x#V`5`ev7-A&K+;}|7RdUCa~@i&Mo@VwQM8oF?87r;9H{KzuLeh`&Ux6e1{7M1i!$ zTv;2_dLmz@W7<&6lZ{1@^owHIN`z#4Q6h(ng>sxIm6Ju8JYAH_d18?)5sT##u~e=U z%jD(a47oupms`YHsO#s-d&JptJEjkab7TdkyTuB*2m5(UTqK_r7t0sKO8JIZC4Ur` z$Untud04DbDdI9!Ph74t#1*QASgX2wHhj}QRBsRYKqvXP7&+W3`}Q<^=dYz zbHoOfCswKX;$~GOZd4(0le$=JR;$FVYPHx(&a^lICcx#;Nr(MxJhczdE^jJKhq;bh z4MX5u$E}8uaHiu{!)RFMxYaNawamF1a7YL0o1y!ituKZCg1Hb84z6<*!1kfAR& zSo{#w(-#|3gaHQ1?&shW^`IHf(hrvCPC5P!=BDYoX4v9eSf#H=m|~d=HTiq+ki#MI zFpSY*SW`TO2eKcK_m+48`ihpA^NBa0JO2rDw)g^CidLdE)Rwi0Dxy!OyTM#jHr91* zu$Mcb$mv<0?)GfUd2Y|OWQp5z9l6Bqxt?6<_M9%ayFJ^o!tL3Xd)%IFIULGSFYkm@ zIS!AA&KRBH3M~hgJP}rFIY^N`VWpM>pKK3Ti%gOdl@g&v)r-)gG9t9777_U8IkC64KOik%dP+MMpgWF#HILy>pJs)+esNVvllkjynQ_!LAxXmojwh z`T%sMGoR@pL(HMC{%NLYZ`PfPhdd+pAvz4Dm`_Y50pY0lZU&E(!*qNo8KDR1%~yvx zCO^^s!^IlY7$8F z41ENO=tfX--bdLVM^cq*6~T|A4jEJRn*ARl&`2bM`r?slNQ@yQMQ4@JDT>fpbaA2x z@-RxCdwnJ-iKXev5peM4fufUZTyWmu@8}h`1aE90e=ZS~l zV%+rBVEt9%ao8lDfSbgVaEEvm?h~&;1#WqJ#M`h}ya|trw_u;x4=;&#;WhCd>=*CD zui^tZBtB$9e8epAF{>@!XZ6Jwtf}~twGdyiOz|}vB)(xe;#+pI_>N5#-?LM(ZjShc z%@@D2V(~j$B>rMc#UJbp@h3Y+9AqoSA$F-a%&rzk*mdF`wq8oMNiueWzb9 z!_p$xh#iO8aUP`VjUg3Ig|4ncG#tjc4$)}HaUG&@Fx+*BhQP_LL-eTU5D6Wv+>gEd z8i`iI`;llRd=iOP!sn4_CG3aZPA}|aY}=LEvO!*?Guw-FcJ?Bj-MmO=rq}ii&v9BG zac`hA@;^dA-4aoey_n}C?#*$5M-6A2^syc8me_#Zp`)LAON19G`Z>ahoVBMeCxd#DE)77JNh!G?Q~5&v5(8tDz0lR)Mu4>Hf4>CT1qzSHH(mcj5IXT{Rl2_uvCPqI(ia?*^iVW(i4&qAye(-mwb zTaD=kcC!wb?qCnIM=^bgy~Xxp`ZfER{RRuU;I(-@O#M8Ycf_n8Wo;E?PKM`V9y%7M%$2QXU>W)0*JmLZ3+7IFk@C5N*%GKY1NqgXdN zhV_x-SbsT|4U`jDjy#!-m6O;MiK`|jvl((4%ay0Fd^v-K^51*w#y>6Lx#|&TgV=jCG2q-X3xtq_L5x0 z-jYk$ez};vCzr9$h6EwA8Xv9`^OWwiXk$3V>5%#sb zi~lI^;lIec`EPPNKP>MPOgi;uuzXmIl8=a!?FUEUF0{ixBM0*`+GS;{vd<$N0j!TWtsdHW&Tfjk^Eh*lz+&z2wNxr zLis-^H_HR^7WuclOCCl|I3jl|CLdBD_bMTuRuZ+rkgqFK{-P|@5FhG@jn7nknkr4z zLS3n&nyA{Usj8>iU`>{)k9yNkov0e9lMp%(U9_QyF$OWltK(6JTB*sZg_^2PP{pdH zD#2EzDpRdi?dVLv55gE|0*yrveIe*B?{shhbaVas5R7;I`Z5^h`t^%pgzMKA!bJCU z@V4iX|Kf!_Z7``eCd)JOMsIMNH+%t)?_mn)0VELTQomca4KZ}Ixu z8_6l#3(5Wh$GQEz2R+>WK1NEN{yxLeoc>;ip`tJKr5%(-)XV$~4#7b0Bb$NuGGMv}*5dK`h)PCPGR zI8zKT#Xu*X*U5>`Re=$S&K-o*zd(5r&_wc?N6Y`wAv0?@B&*qw|CguQ`hR|^Zgimu zMHdD|ZuiO;(EeMf6Lr#3#$;8nN&4fAaUGnGGuZDPoR2fu8wDr2kd z-GD+mn~E;?nCyK}FGFUd?_R;CdEWRb6>K_z>N_AENSqP5@v+4PW@PDRuoY`1`S~-w z_NTfi{%n0bh+y6q!JOq`p5|f_5p++A&Gta2$AR!n5b!{AT+$mm{d+UW^)T{W3~vV5 zKIlQ`CV}S1&ks9Z2cy071s;NGw~vXTAg2pF;CvUD&K7tmbWk~!Vl;$WxD|3@4l+ft zo#9EP1|8vwIUW6Dp%4^LliT$7w{swfZhV=(s=pAffX#3#rhDK&@DipUz?bk1rUw{j z3XdyISS!{R(;jRv8;0p*b~?*N_+aN2h!ehL$H8zk^PSPacY_wHJ7nTE(N*G>Ic)+0GOi&K~N2Zd^H40)KDl>!{Hn?63$a2-~u%YE>)x93N;ossBy4aO@LeR z=&@BzgnQK_*rTSvQ@FwWN1XyMscG}f-lu<_(q)u->CrnuI9i2mB+Z6 z%ajT-Q_W*_RRL?F7O+;Tn6*_!teq-hT@}tsh1pW@YLec8OZSu2AQ)yVZGYhdQ4Fdw{^1bcy0x!1#6`LG96SjJFPvLeqn7@j-SG>CKJV(p)a_zj_ z2rn1(ayzhR{iYbkuo5>Q`xs<6n=|{AokMtK(U-SVsib1t#*J;;y0LBBwr!`P8>?d5 zuB5_>ZKIOT_k2D1_o#bt277#-z0X?f?BDy2hT+bobyJ4VJ;KqiTD)Rmlbbds+#gOA zVeDt zS`f6WI(N|B7^hTu|2nrUzOfhno|AXc5yIWKBwVaB(mlCd4OTPe;?bXav%)Jc>z#a9 zySD>oZ*fnBFrjj@4eZS^;p>sioMI!Ujkr`8go^Gs{o(qA>D1IBhhOY!y_cILjo_c3 z+|fzk(GH5q$`q}K>eVID%370@-;$KCge@Mvv77-j%LNip zD35Zb=&W`cOnXL?xzjXR%4Ljh_ogH@c<)NprhK#VUw)e8c%79@zw_q4AaUIlI3D)? zo%$TgB8tr6?pAy)$bQMRw(yt0U^S?<5O`TN-#Vmb9SunDFKQtvYBCbyB*QqwY1uVb zpnMOoJ~ScQzPPrVnfeoPIW_w0iEbcEVeDS}D&i~`Ac-=w0DXQ=gEHfUtbT5ML@CKN zE6mj^^VNif!g(~rB$Mf$6IaV2>KzC%N+arB2rPojiW5e0GTZD*2ve@_%IGKRAnMaRr>C!-FK~9T ze(f~)WfsU4918p7gU%fI9`)VRo+vz-m*Ms%%Bo~Pc^X?;%XwvVGe*I5^GAdm9&G~- zEoV)Ly7JT+!4zJX-TYvu6M?D3jlJ_VhmQwo^7z;^;sSk|1{T(|4Ee1(l#lE!z}Bs> zl_H{}(a9&+Rt)9R5&5!OrRot41 zvDFjea}cUgYsj@>8nh37Xaq>ib5(d%hhl&XaiB!)c83{i=Y|F)-w`>#8g&N%Wn=&j zuFl_$I3jtI?{u9X_vD|Ktu-SuvXq-%-%MTw?PX7(i+*wI1@%u5;~etIgP@C{{!%=G zmYJPV4dm6XGELjLT6M!-$ITw~v#STuUeUrKmh53Gs zLk!9rvI6y_G+WcU@?AybG3H@~4An3d&8Aj|DN%N&MBY*L#^Y&ge=<{0zHAcP4x9UJ8U zstHRqYuSK=39Kzk*m(PEc(%}nAv zr`uG!>~%@D*lW>=aBWIiYLjDPs}5B5aN7qo85ub^#+FAUyb2nmTi9wf>|*g$CHK_X zr{-Fhjc_jcb4Yp9#^%4>ec|}{lT%}5&#r5ZPNmLQc8B<%E*!&ue4WWWt=K$SVq<;ImeC3q$5(Hh&Se0~*X zyC-mLy@8YxOTaW(A=I!9i5ClHRCj~yYs)v#c7ttWb#BrfXHnd1KKbg+pk(kQkUQL= z;T+U43M~SA-D`vjD?+Qg8kH1dDpA=~4^mEpdy|*<9d#hsxB_iB_jn-tONmKY2vQb* z>=%CMni=$RLHDXhUFUrL`%8lk;DQeLT4aPc7RrQ%APyAKpyVQ*tnSdDd^jP;tA_On zlR2tWfO{Z|k&49LWz3j~jkm2q*_Fg0lsAC>np1EF>Nr&Z5J73^%UBVo8+!*mKP%kv zL3eL;8w%0dJ_fPEf8Fqx*2cq_@+8-n*P-l+FBWp$A3zTYi(cNOCTF}CxT$ecN|fB&2HLe>iIsMZCg$FUG8dlmiZTj&5GpQ=Ff;xc04?G zJZdIQS$R|DpWuG;x;>#BZ)(kd>O?*E=rfJGzQ@FR?BMV5w~ar85poIyE5<2ivI&^g z#LfP3+=EMZ@EvC0=rL-=+ip0DCHjLmqIfR4r|}qegZG3JaP2)(@GiCoc4dRVUyc`W z=ex($JH$0m#}>408~XEDR-8|spOJrMCZmo%K7H*NftSq2VsX% zx9&~lzBA`!2CQ!rPt)ISiCikI4G|MAIYCKBo@~zB!#W@ZiqR5mgz;^}sf2DgT7a%4iAt2Q*ua=yXiDAqp_G-&*#phjuX>YvV&U*kZ z2v+pkejKB?^E-b-@RL;I4wn&?ze;jFn)*{Lg5b42qWx7Uleq44(34Z*tNOKngM&~p z^gn{oZ)t9RhSerxP~4s&RnZLBB!~ljG&L(qP)3?=*8CLeHQd#64h&d*dao8wq|DV$ ziSaBhu=lJMgoUc!L0YiA*$34K|-$K|-s-#P-m;!GRV12xdvs^^lHitW2!LhE&)P@o@1+ZBxo91VcFY zT!c7DU;bGkVwWoY2U)1GzV}QbX|+v_y3?MO)=L$)?d~c)cKen%{jCB7ZU-&y#OFrq z%7jOQW?rp-8+p|#7Q8k*C`L(mKdX3AiV(w}1ZXREIMG+Gzhz*+#BXa3JJ8HEYfM9p zJWt2(oLp)@HFf^(BEIpo^{l?Mt)||wm6IH5Rf!&nzY$Jr>2yK-tNq&WL!)@TP)3)P zdd#6xf(=CG`7klREtX|N32oBDiSifD=V{)7YBN#~U$*|+lOdja@~{17gHo!kz?!m+ z1kM|deuH7cMfc|cG1EDRE_7W6NsV@JvI7~qq^}&Zx?#&kD7!P+Z{rgBklZ=(TSr{k9fBoyJ5sNx^D$=)=o zT!L!i!0fH?-Br}##g>=kI{gDYq0^93qEjr@D9Uo>0OhOOiLA)p){fU-?s8PhRgFwR zib{c9ju?>+I~`;oPg`LmPuuw((-;w?MGu+Kr7b}^R0Sdy_3l;uoiK8edmZ7|5!js&-_Z;bY)L}}13f-^{}B~Gpu zXSQTP@c<~dIjflcLBol9P7!QZ^m+yJD{g||7D1GS6Lq9J($qDPbGmppw6UKeHH@Li zR+czbkD=&XiZ~TDxj*z5_5u09HhSXM`VimN4gL63(o zV)^jni4Lr^@F^VQ~d1aLFe_`QE4gYk3KxS z{i?}><34w|QC+D@G8OaYz61)0rLHp$Q@1&xCy%?>L}?kgG6xuA^B40S1kjKbdARoY zG7qsxkj7nN9*B^9dnUee{(FulM}r|kT=gqeDZGDA9ECD7`K)#V(SA~4E5Me91#<+6 zdUrj@`+KVftfvyjHO#lK1yS>ljHcU2*~iAgaB>IkpF4WDNyjFX%=_icG2majBi`OH z7Dct&WH@;gcZ8327bM><-m_Vm0je80RAAByRAH1UwGP?^yX1x((MKKeJ@&q<_t}#G z$|jA-C!;lC@FYt`hj@`oiEc!n45bk<)#b%&3#Yu z+V9l_y=SqfQArc#8`~XdrPI$g)HbF+D92(@6LpGvX_BN3reov*j!?X~)D;kNwSt8XfrCS-$ z88=vA<1Ltwlf9Ss*8**r9CtX>+2oH@T`5LcwMXn2v(xe}kwbwv(I~500Q2UvvEOcd zRk@zSK)zI`tK=w}qr`@}=CUgDw2|6R7-$!!f+LB#TU!xpgv0Cs%8Ug@KXyk;D4Tc0Kh7;1CvvNXb zHa<|)$q28^uJ!1jEv7R%I}Nd8t>|O=W$VtxQ_q?2&L9^5c?(($ZJ*_VSFq_yXjPR# zDh!RA@sNf05SLiBG)Mb6UVnR`Unw^$bmLFrgFV;p z;1${~@fGF{wuY=u%0Z!wV>Nhtf4%o&-Fbeu+ntQ8hK4g|qat$JS9!bew(7su+#W79=CnbT1U!n z-NwJv!17da&JxxB z>h;JP$zovv+Oeye!zPpW9_(I0Q0M6Lck&#!hkopWz1+2%2nMbe8$ts*Uk2tJJ_j~2 zSz`sW3*`kOiMi8kjVK*AhRU2X{F7(j(RAlKgi|Kp2XMl(&QmBpcVeEu4fDZ!FZr*@ ztGt#y66oam@;MZXWCTNu9j4zfjd8}z$LWUq2-Kgbwb6*XPj(Wzj8XSFzIh|}iSUTFJ@U}2WzGvyq2KduL8iyfnts*u8SRJVzn zuL6gOW}eJ#@;eMWVPd9;jMnKZIXspHC6%TrgxQf!PL0?!;1VkdhcQ4?E!^Y_c3ai1 zoq$6M<|}rYcuW(mTI@+w7lO1fLv5J7va&R$qwaYTf*MXTwvW5>CkTDK@pe^4j=Y7U zXhHRvk)`Y4-CP>|GQj4`{R-`^Z>$)YfmGGajq&M|7)Ah#!RsTn{G<_u6d^x*ad^6q zrrJ&U-9O&v;`-ifLA1SDcQ!bV6$bTx8D%(c#wo6GmpaA*5PxM&d~vdp-Iypkkg3lR zXcaT8KXRK~e&%d-n2)tCpIiNA4)N@6$|`AF(Qah@8rvhJwTw=gzKX0tVj&hP8R*se z-K$Z&o<#5l=41YrALOwT1&nB%!f8Ebh)BO3Ge^RzTcK(aJlayx zNENf^P6RiPtg{kL{-xEV-HX0zE@>X|sn4%YuzMyoD3`(sv zb3R0Rk=f}3lR9sAst0k^ayV7HLCa{hmL>RIjdsqit+4 zHLcefE}=vc!s8I)lOSDc&j*08?WmK0gRTsZ+7~gd&Atf9^y$RLQ zxw#OsXr{7@O{tNpq39+VSHm#!lyX3AQAXm)NzQxd|jP(O>q z!V{If6b~UNYYnIX<}YW_Co`^f#+T+T!Cc^WzNMy@@{{Ga(AiN=S1dM4+?R_={Lt9( z&O`tE$C(<{U^by*v3ZdVP9=bf{*Bkza1=#-n~K~$uB{qitmO@>GGv@&d1GHh+*1?g2k#Yev+OOZoZp({81oyLz=#%hg!Q*YQ_H55Y zQi7)-Vsoqqrkg`^OvsWh6e-^|Vvg_zK5f50*L98_^Pnrz4Fq2kz`Af}Si3m?W(>=ME2M)5iMXbHWQ9CmYJ2`N1x4Un`) zd|3@<4UW--B|{+or!wVke4Xza4Ge6F9t@2Cf6Mxpl6NruPj}LPOE0uxd{vj11*x*K zp3HAo!G%kRjZj2Up@WM<#i6mG$w?Y<9et$r2l`CSd02yl^puo_ATcxqT4)%Yid3+| z!62Q!DOde2)qb!3S6w4prPr)BX_50W>vN}1X+#X8c6aG~$^EqD^6_N@$SbJ(@LAC( z#T~qQJJx=kl07?ddGXyT5nL$v`B*ArApK$y_E9`%;J05oyMM>|;#;%8N%K#yG~oGI z=T)KfO6|2=CPM8s;N)4jD8TDvdkMtylF2Q9;7ZiFTGKc>3R{J9Zf5YqqCUN!zpdQY z8?eC}67EPuRC6R3_V#+LdRgw6o}jSjPxF-FUob!wxfTU$LF=15Kvl)pCmF^!Ct320 z{sOPUJt|3qlzt=X%a_cIU?y^%kWcG(hIZCSHbnuqQ%T zb9+LQpzK+lAT#6-Q$SL{ia~f(qUD=DVIj-CH7d?0%ti^~lb#sA<(4cREuB*HicSTp zF{pcGCzQt=xTrBCox-PC$Y_CX=>Qg0x|C+^6BsHp%Izu>cdGfc2YhKqvh6|#VFLO? zN3ta{2g521$}ivmM%5Qm0HgW~YML97#$+lx%?ij?s!HL&8;}7y$FiUUdbKxyr{S!) zx2ZHPE=>KZ+F?JXcA!%%iUp4oy{EpyHxO!mY_z4C)XIsha3i zOQ0}MQF@!v@@iLA0#dDfwd5;`n5v<0W2L&c48`E8@G=;mMqy2g()!iHT9(7^N?Drt zRCQ42Oej7AnHiU`E14<5q*=NRke)RLw{|y7bXcb4xE?c=9#~2!%@OpF@9UUIl}&SKKuSn}%qka?RYv5aGRUmN#g5E;zozCA z=Ust^Qo`Z24(zZkBSn|B8|YT~ZN5vU;!u@y7REF!7+YCza5s`EsH6$&$B!8;r^IDV zTF=S#%{5S-_bnE-mPrt(pP?7i-Ubs;`m8g(pZ0AzNNL)+Y=8j|fC;IIYfH~n2z3Tm z!>WWD&34@29vBstj)z*%BbzKS8zcVS?;W{#1|dhqV@YdYU4=F~Elw9Z1_2dWrrxNh z0S2Yml{IjDTuU|$3+AcztXlDb6J`R-8I0E-DVOc(Q;YJjf-4+&dap2}H_%+eBuso< z8S@-ROezTS=?IKH;XPMN5DOnqk0XYiy~PlLmlI8>w-B-T)nHvjXvt=pnA;cG5EdoA>;m^eJjfyVpO5|@LVB3}-577L+H>k5N&z08jG+i_7! z*aQ791DPdTb#O?qdBOngH^-yqz`%~42nYsKlS!D@3wEA6U!9&ag0 zR1B-}FKo3A0irci{)Ot_0pOPuyi8FMCIvy+)h#o?4go9uW}k z9R2qxv)}$gxKhnXhK%A>JXH8eXuRHV+y_{E!AQo<0j>dw+zxHCQ)tsUGkh zev8B&?F)@(iQV4{O`sgxbicZ26GpXpok&FB6k*&-bX*UBfhcUn%9q_>kj*9PBmvH4 zCQeKwsW{iFXhg_PfeC%G@>|$wEdHO1F`hP=zld}+6T zEc||U@6g!eeO74eBHOd^%@DI}(q#O&Vx*4yjHorqe&60ymMdS2*K0)A3^53Ch7)x) ziidWV+mc+8bi2Z~^5xwAeyO{#xi`8b_|P2~Na2#c`3F&+eIA1gw@X+6dPossNVo9D z&$o93=^8VPXz7{6Uvp2gO>0l`g?X-LB;gJX*WsYR`kmat1b1m1q5Nic=)n)Dt1^}p zf2o**5bfO8N{OGzvZkOwGREU%n9K>f0fK|dPxN(r@{)Vo{fdP6acSX5Y!;t!{MC0Z za7Vo&M(DfH%2{`bh4=KjfP0(oE|kL^&0u@{yW!H03g;z>T;4P0F6s|q&iTNqvSuN-h_t5EGioY_I31B%S=sm69 z`Fg?VLi-bCA1ah>JbI}&w;YMlt74yR{!V6i_HHzIr+hp4W<^b!R~I5|kZ$hn3AykY zg4;V#XZ?=*3H~a9HX=4X*2_R3a2$b<=!Crg5Psiw`i`O*06g96JmLJ4dC^27`IO~m z61n0yjG}JVWL=cS))#^MnOx8pZhc=bSO&%BFPlxsk9<98zkTRIUIPuGZuQRa3H$xv zG8DR{a2`7*a>A!E1ZHz1s0G;v$%5d>2P(rYgN@hPj4(@>^}s#NJ@L?$7E&U7Aukru z%X{Sx=i02bKz5ApG;Vc6iCW!w%h6M1KVB-0_>ENB#5b8_6(NBTF=w0xwTBEnp*c+o zoqRer?A+DZP{ur&DQ$%lx^$V2-8x-|72NTk3$W`ehjiLBGTyQ&V5bGyW8HTH&pwiD z0OI=HkA08OZ6uZ&$XBH(dJ^$bJWb=2MS9NC;>Id8HkizFY(YfBd;JdC+Nugwn za9#G=LapY}DSR{w7Q`kEL&bVrHg(E{C4HmGcF)Awgkxv$w6Ccxid4k_!0eE9mH+|jU31;4GC2L#2r$_)bHAS|bvY8!u9)L(#bmxDOSe=X z|6PM7f`=mUy65-bGIEgPQF{7BZS&9o>ZVC)=Q^VUh4odf4ic+e0SWvLvdWFq8|6t> zHi|sQp9?A$%!Atgyl5t$*sn8)5c{Lz;a+;wIV;>FDmE9*@G&iH-`9JZOY0#uD4SxI zolHF(-%4TbRlYxsR~B=5a3ehrUuz?qkB(m>wcFdyPI@<}Ajtccbv80h_P23kD2B_p z)_%X`Q1m(rX4ZVD1m!F3dO3Z%eQ93v*xbqCALN+i_A$H#+(2{QYRm|cZ=z6QY>Q9| ztfhGS93I_IMc zV)AVksmmZu5WXO4DDZCAKO# z4C_jr8u{6>R%&Es{TXL@b8npTpJ8dtmag*5Rv6=BR`{dXA4TQNa0CpH;mpgI6!29H z0zws~i)MXQT&^_yLSDJDmcG6c zC`+Al7p2WtTn0tcG-960B|5~34iahc@Sj@JJ4c}xoi|4!Re~RvMLuXkW8s8>LNP3g z))>?bHmwzUs+Hm z+$}j!YWsA}RokyJhp-nXwy?5(9F>`}MN|gb;{0cYpvf}hqG7Nnw%E+5eCH(@E1qeQ zDtz3gO88IpVu1u2%WruW_LuOM3Zo00^NNNIQ`MUhYg{~0ml1o5meg@&^!J4)q2e%9 zk*pCZM^Lz+InkO(^$roF63`sk5G?zw(((M@K98K0a~omPX6i4v_%!5RDs1d;@cY96 zMn9x}G)SxKp|N{rj7}@nWqX=xnYhw<%yjp;6JATXB-(Y1@&+|CDC+bAFNxe4I>yy1 zzPVR3{U9H?+!2g+xP{T?IjucDNQNd=33IPT!=rO^XROMok!Mo&b-zI0Kh(RbsWpcf zo`w7*3TS4Tt?du_q^*&ZoUQha*3gqJEDzj$O)Zg?Cpvmx2}(+BQ5%%f&dMx8$yA22 zn&vpltOJE+#j=ol++q{)E9W+aF3TAx1Yp@j3MJ+J2DJHl2;F2yv6TB6W$6PpTPbSkRl)pHXC1_PQ zg)oHeGQa^X;OC&IrUKgL(Ni@`#wHlWWmN*uezmU&g8W|nU^6*;WJ}2<Pr3)9UGoYSb|=cFF~zj&MI6b|TBQOdb3Rg0DN9Rs}&u`>OR*aw;D zX2mgfyG^eku!PI2qwi(hXlo za}R5u5)$}JrnirIGdLTIHICiry#JNMaHuNq@rhV0r~%KWdj-NF8?3+G>&H&w#b}T0 zF*03?;da_RW#8wIK*qVAkggi+Q|5+;G8pCeC)uzq@aI>UjMsSdET*mRKYmaWJyu@?J%9L3 zn%yhrD@MHdK1-IXd+r+ON`4+5OyM7}c@9DbQ2SzZdJ#-KobMo?v(mpFT!+XG zN#uX`3Qpu-8uR!Qn)`c_(sYSD#wfcVN?yc$UU$m`wQ-$%AIs8^mcy#yQlHntl1x9s z4Z{M0!pU8bfbUF;xl2ncO?sPH}o$-i|C`cpHo2*~iG|Lw}k6gD_)iyNclBqXE02DP4Bn zNo(MgTe69V@6YK$x*EOU9c)9Vd6LyL^0}^8u6ymN;SqGY!P(ricH|1hP&b;XkDE+> zcbSP)vKL2QRX>jK^={hV2)w?K9}fFExooFuxnjE_xP2uzKk-GIJn88BnpXchp&vF? z!c4gWu;#V%g`Td(yd$Ydn6u^9=e7_>)&>`k!Dfp%+mg2q?~ajYA#N;5 z1^a>eSYrB_Wc$dm98nCQ<9j15u7`D_9z|+}tJFUNc&nFZg=>$P7!M?x8TP=`35V7O zeZNQ4KVtlCgWiV4+!$f@$1K_17^3f5+b`J~`y>KK8<(CI>ae(*XGbK`ySkp2h)DR& z8alMgs_;EUeB|H>YujjPF*MiQj=SM28en7cj5~mR#&~K9w#A8NQ4ZzywEUZ;?;4R? ze$!D|H>eozRI+^^`5*{_MHO5lu-fbRSzx=6Yj7@b8vJFZ;I3d3bVA3i0 zfcj5u=&>1Y@y?e-_Ye{cjN^YhN(3s){il6BO;zXriE}@G$Y@M}V<3|i7m}tI>)F#x zh?fQyiq~wQ>W?+&rIxO5c3{c#4Z zlUFAw;P+!LLX6#d9!G?LA#5&43ZVlztxTu?z#76yJUf#un~k3Zq>(KE`49F7x~>^? z2W`jV{NP-Ql#W+TUtCvx6CWc!{lS5AM^*c8U{i&e%35yj6eU_yx<&ag@&V#m*=0P- z7oArAQri%Es3z91Lh-oF^X~z0Ab$@K!iNAuI~@mUf9BkM1}{|%Z>Ur*4_tK$;f*I& zG{~~>xJP}ES!W%WAWr~M<=4l+&x-~@n|Q_Za)VdoeIb)L2jK+xPq{=ZLIo>jJK_Qe zadi%Ca;@{27Q+vY&D|y1Xw@b9*)dj_D@bGaXmIC1yFct{uvM62Q7}r{hLO2x7%{$N zvBTKAG$YJK#;6`@az@(2{2S%G46Q(TBWYdMwyb5sGIjB_(z8D<{Eu=?uKW$Rg_Sxg zygZ!u7R{PGVnY76bDt)31^NKjt)-RFi&R(4-IHcVseOL(JI@yt`R51kT6;@rMNgHN z2Pj?m=u5eMIQx05Wz_K&L!2L?KvPaX1E_SHh zQi-q|eNkS11<$MLS^t1hrIU9%jU`)QQkOg%USZ39Xz?adU-5c{=hbK~G2Tz?zZBWy zpbxw4rA2!#?itQ`Vy0TGrCm`9W}UTCJSzUM15j6p02w9Oo){1WjFEALnd_P9Ar zYs{7Tw(V|6H>ZC`;p8eOXxwmN=d?6?>}%IQ@;qZuYz=>`dxjDe7_uf=io#n^Ypcj# zs@Rn%%cA$1XbQh^E@>bibN7ziwF!NG^G;&iO*J5R!2P)TAFkb|GXs5)A{baq3m6#N z|9R8=|FQdWH-1^CUuLq(&+QwVeYUSY{~7q3zvgng98LjP@2VLI zJ*86ihs zib{_qEB64$S6Eb$-%@dp(YOVY&LY%{c_Bk89GObPpNEy0r_cuhghtUxWn(4#)CJgf z(P;mSW3kV$_J*X~8=kzrQydGq8DpJ(lkKo?j^>m7ATcTpP8`LF7_mR>iWc(dTOYLUX^_4DBc1%k! zu#T>hcZvhlvJbndcFv%m$vbre?3sq+%G$=!IdgU~fg3VuttiOnjX}F^=o|LYywFv= zd&7Fgzo{-C2WgxVzAn8C`}sF0!x!DY0XzePo1%UoW$%&z`D~-*Lr=-dR^{r6C}K}{ zhcT5E`_&6pF_AK2M&)lHh844S0YKaGEJ6A2myuYrk$LF3cF`8{4U_1zS-W1qE+I3< zk(i7jLAej=VaCP6x=h~~gDx6XBQ24UKXq*#H{8(xw}sI(8O=w9kAo9Nz3MTFLWaWJXFfHnGi-t z;y6H#j>vY#9v+nE4&F^Fn=0{41xNyYivgobe7{ros0GGT_W=2Zw;qlSW&&oEulwXc z1ºZDgB2vDB&ZlcT1y~$`Xmg47JR$w-%<72| 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 b*OFbf-adUy;UYz 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�&*upi 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%0D|3+b4RD@LH+I``2WLn*+S>^qH~K{V!ab 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 X4&eY-g5SEtqQzox1|>`osnakeyaml 1.10 - - - com.palmergames - Towny - LATEST - system - ${project.basedir}/../../libs/Towny.jar - com.mewin WGCustomFlags diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java index 7ecbaeafb..46254db8a 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java @@ -18,7 +18,6 @@ package net.countercraft.movecraft; import com.mewin.WGCustomFlags.WGCustomFlagsPlugin; -import com.palmergames.bukkit.towny.Towny; import com.sk89q.worldguard.bukkit.WorldGuardPlugin; import com.sk89q.worldguard.protection.flags.StateFlag; import net.countercraft.movecraft.async.AsyncManager; @@ -32,13 +31,10 @@ import net.countercraft.movecraft.localisation.I18nSupport; import net.countercraft.movecraft.mapUpdater.MapUpdateManager; import net.countercraft.movecraft.sign.*; -import net.countercraft.movecraft.towny.TownyCompatManager; -import net.countercraft.movecraft.utils.TownyUtils; import net.countercraft.movecraft.utils.WGCustomFlagsUtils; import net.countercraft.movecraft.worldguard.WorldGuardCompatManager; import org.bukkit.Material; import org.bukkit.plugin.Plugin; -import org.bukkit.plugin.RegisteredServiceProvider; import org.bukkit.plugin.java.JavaPlugin; import java.io.File; @@ -54,7 +50,6 @@ public class Movecraft extends JavaPlugin { private static Movecraft instance; private static WorldGuardPlugin worldGuardPlugin; private static WGCustomFlagsPlugin wgCustomFlagsPlugin = null; - private static Towny townyPlugin = null; /*public HashMap blockFadeTimeMap = new HashMap<>(); public HashMap blockFadeTypeMap = new HashMap<>(); public HashMap blockFadeWaterMap = new HashMap<>(); @@ -209,20 +204,6 @@ public void onEnable() { } } } - Plugin tempTownyPlugin = getServer().getPluginManager().getPlugin("Towny"); - if (tempTownyPlugin != null && tempTownyPlugin instanceof Towny) { - logger.log(Level.INFO, I18nSupport.getInternationalisedString("Startup - Towny Found")); - townyPlugin = (Towny) tempTownyPlugin; - TownyUtils.initTownyConfig(); - Settings.TownyBlockMoveOnSwitchPerm = getConfig().getBoolean("TownyBlockMoveOnSwitchPerm", false); - Settings.TownyBlockSinkOnNoPVP = getConfig().getBoolean("TownyBlockSinkOnNoPVP", false); - getServer().getPluginManager().registerEvents(new TownyCompatManager(), this); - logger.log(Level.INFO, "Settings: TownyBlockMoveOnSwitchPerm - {0}", Settings.TownyBlockMoveOnSwitchPerm); - logger.log(Level.INFO, "Settings: TownyBlockSinkOnNoPVP - {0}", Settings.TownyBlockSinkOnNoPVP); - - } else { - logger.log(Level.INFO, I18nSupport.getInternationalisedString("Startup - Towny Not Found")); - } if (shuttingDown && Settings.IGNORE_RESET) { logger.log( @@ -298,10 +279,6 @@ public WGCustomFlagsPlugin getWGCustomFlagsPlugin() { return wgCustomFlagsPlugin; } - public Towny getTownyPlugin() { - return townyPlugin; - } - public WorldHandler getWorldHandler(){ return worldHandler; } diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/rotation/RotationTask.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/rotation/RotationTask.java index cc9507a13..9983138f1 100644 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/rotation/RotationTask.java +++ b/modules/Movecraft/src/main/java/net/countercraft/movecraft/async/rotation/RotationTask.java @@ -17,9 +17,6 @@ package net.countercraft.movecraft.async.rotation; -import com.palmergames.bukkit.towny.object.Town; -import com.palmergames.bukkit.towny.object.TownBlock; -import com.palmergames.bukkit.towny.object.TownyWorld; import com.sk89q.worldguard.LocalPlayer; import com.sk89q.worldguard.protection.ApplicableRegionSet; import net.countercraft.movecraft.CruiseDirection; @@ -61,11 +58,6 @@ public class RotationTask extends AsyncTask { //private int[][][] hitbox; //private Integer minX, minZ; - private boolean townyEnabled; - private Set townBlockSet; - private TownyWorld townyWorld; - private TownyWorldHeightLimits townyWorldHeightLimits; - private final BitmapHitBox oldHitBox; private final BitmapHitBox newHitBox; private final BitmapHitBox oldFluidList; @@ -139,9 +131,6 @@ protected void execute() { break; } - //TODO: ADD TOWNY - - //isTownyBlock(plugLoc,craftPilot); if (!withinWorldBorder(craft.getW(), newLocation)) { failMessage = I18nSupport.getInternationalisedString("Rotation - Failed Craft cannot pass world border") + String.format(" @ %d,%d,%d", newLocation.getX(), newLocation.getY(), newLocation.getZ()); failed = true; @@ -341,58 +330,6 @@ public boolean getIsSubCraft() { return isSubCraft; } - private void isTownyBlock(Location plugLoc, Player craftPilot) { - //towny - Player p = craftPilot == null ? getCraft().getNotificationPlayer() : craftPilot; - if (p == null) { - return; - } - if (Movecraft.getInstance().getWorldGuardPlugin() != null && Movecraft.getInstance().getWGCustomFlagsPlugin() != null && Settings.WGCustomFlagsUsePilotFlag) { - LocalPlayer lp = Movecraft.getInstance().getWorldGuardPlugin().wrapPlayer(p); - WGCustomFlagsUtils WGCFU = new WGCustomFlagsUtils(); - if (!WGCFU.validateFlag(plugLoc, Movecraft.FLAG_ROTATE, lp)) { - failed = true; - failMessage = String.format(I18nSupport.getInternationalisedString("WGCustomFlags - Rotation Failed") + " @ %d,%d,%d", plugLoc.getX(), plugLoc.getY(), plugLoc.getZ()); - return; - } - } - - if (!townyEnabled) { - return; - } - TownBlock townBlock = TownyUtils.getTownBlock(plugLoc); - if (townBlock == null || townBlockSet.contains(townBlock)) { - return; - } - if (TownyUtils.validateCraftMoveEvent(p, plugLoc, townyWorld)) { - townBlockSet.add(townBlock); - return; - } - Town town = TownyUtils.getTown(townBlock); - if (town == null) { - return; - } - Location locSpawn = TownyUtils.getTownSpawn(townBlock); - if (locSpawn == null || !townyWorldHeightLimits.validate(newHitBox.getMaxY(), locSpawn.getBlockY())) { - failed = true; - } - if (failed) { - if (Movecraft.getInstance().getWorldGuardPlugin() != null && Movecraft.getInstance().getWGCustomFlagsPlugin() != null && Settings.WGCustomFlagsUsePilotFlag) { - LocalPlayer lp = Movecraft.getInstance().getWorldGuardPlugin().wrapPlayer(p); - ApplicableRegionSet regions = Movecraft.getInstance().getWorldGuardPlugin().getRegionManager(plugLoc.getWorld()).getApplicableRegions(plugLoc); - if (regions.size() != 0) { - WGCustomFlagsUtils WGCFU = new WGCustomFlagsUtils(); - if (WGCFU.validateFlag(plugLoc, Movecraft.FLAG_ROTATE, lp)) { - failed = false; - } - } - } - } - if (failed) { - failMessage = String.format(I18nSupport.getInternationalisedString("Towny - Rotation Failed") + " %s @ %d,%d,%d", town.getName(), plugLoc.getX(), plugLoc.getY(), plugLoc.getZ()); - } - } - private boolean checkChests(Material mBlock, MovecraftLocation newLoc) { Material testMaterial; diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/towny/TownyCompatManager.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/towny/TownyCompatManager.java deleted file mode 100644 index cdd44044d..000000000 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/towny/TownyCompatManager.java +++ /dev/null @@ -1,143 +0,0 @@ -package net.countercraft.movecraft.towny; - -import com.palmergames.bukkit.towny.object.Town; -import com.palmergames.bukkit.towny.object.TownBlock; -import com.palmergames.bukkit.towny.object.TownyWorld; -import net.countercraft.movecraft.MovecraftLocation; -import net.countercraft.movecraft.config.Settings; -import net.countercraft.movecraft.craft.Craft; -import net.countercraft.movecraft.events.*; -import net.countercraft.movecraft.localisation.I18nSupport; -import net.countercraft.movecraft.utils.HitBox; -import net.countercraft.movecraft.utils.TownyUtils; -import net.countercraft.movecraft.utils.TownyWorldHeightLimits; -import org.bukkit.Location; -import org.bukkit.entity.Player; -import org.bukkit.event.EventHandler; -import org.bukkit.event.Listener; - -import java.util.HashSet; -import java.util.Set; - -public class TownyCompatManager implements Listener { - - @EventHandler - public void onCraftTranslate(CraftTranslateEvent event){ - final Set townBlocks = new HashSet<>(); - final Craft craft = event.getCraft(); - final TownyWorld townyWorld = TownyUtils.getTownyWorld(craft.getW()); - if (!Settings.TownyBlockMoveOnSwitchPerm) - return; - for (MovecraftLocation ml : event.getNewHitBox()) { - - TownBlock townBlock = TownyUtils.getTownBlock(ml.toBukkit(event.getCraft().getW())); - if (townBlock == null || townBlocks.contains(townBlock)) { - continue; - } - if (TownyUtils.validateCraftMoveEvent(craft.getNotificationPlayer(), ml.toBukkit(craft.getW()), townyWorld)) { - townBlocks.add(townBlock); - continue; - } - Town town = TownyUtils.getTown(townBlock); - if (town == null) - continue; - final TownyWorldHeightLimits whLim = TownyUtils.getWorldLimits(event.getCraft().getW()); - final Location spawnLoc = TownyUtils.getTownSpawn(townBlock); - if (whLim.validate(ml.getY(), spawnLoc.getBlockY())) { - continue; - } - event.setFailMessage(String.format(I18nSupport.getInternationalisedString("Towny - Translation Failed") + " %s @ %d,%d,%d", town.getName(), ml.getX(), ml.getY(), ml.getZ())); - event.setCancelled(true); - break; - } - - } - - @EventHandler - public void onCraftRotate(CraftRotateEvent event) { - final Set townBlocks = new HashSet<>(); - final Craft craft = event.getCraft(); - final TownyWorld townyWorld = TownyUtils.getTownyWorld(craft.getW()); - if (!Settings.TownyBlockMoveOnSwitchPerm) - return; - for (MovecraftLocation ml : event.getNewHitBox()) { - - TownBlock townBlock = TownyUtils.getTownBlock(ml.toBukkit(event.getCraft().getW())); - if (townBlock == null || townBlocks.contains(townBlock)) { - continue; - } - if (TownyUtils.validateCraftMoveEvent(craft.getNotificationPlayer(), ml.toBukkit(craft.getW()), townyWorld)) { - townBlocks.add(townBlock); - continue; - } - Town town = TownyUtils.getTown(townBlock); - if (town == null) - continue; - final TownyWorldHeightLimits whLim = TownyUtils.getWorldLimits(event.getCraft().getW()); - final Location spawnLoc = TownyUtils.getTownSpawn(townBlock); - if (whLim.validate(ml.getY(), spawnLoc.getBlockY())) { - continue; - } - event.setFailMessage(String.format(I18nSupport.getInternationalisedString("Towny - Rotation Failed") + " %s @ %d,%d,%d", town.getName(), ml.getX(), ml.getY(), ml.getZ())); - event.setCancelled(true); - break; - } - } - - @EventHandler - public void onHitboxDetect(CraftDetectEvent event) { - final Set townBlocks = new HashSet<>(); - final Craft craft = event.getCraft(); - final TownyWorld townyWorld = TownyUtils.getTownyWorld(craft.getW()); - for (MovecraftLocation ml : event.getCraft().getHitBox()) { - - TownBlock townBlock = TownyUtils.getTownBlock(ml.toBukkit(event.getCraft().getW())); - if (townBlock == null || townBlocks.contains(townBlock)) { - continue; - } - if (TownyUtils.validateCraftMoveEvent(craft.getNotificationPlayer(), ml.toBukkit(craft.getW()), townyWorld)) { - townBlocks.add(townBlock); - continue; - } - Town town = TownyUtils.getTown(townBlock); - if (town == null) - continue; - final TownyWorldHeightLimits whLim = TownyUtils.getWorldLimits(event.getCraft().getW()); - final Location spawnLoc = TownyUtils.getTownSpawn(townBlock); - if (whLim.validate(ml.getY(), spawnLoc.getBlockY())) { - continue; - } - event.setFailMessage(String.format(I18nSupport.getInternationalisedString("Towny - Detection Failed") + " %s @ %d,%d,%d", town.getName(), ml.getX(), ml.getY(), ml.getZ())); - event.setCancelled(true); - break; - } - } - - @EventHandler - public void onCraftSink(CraftSinkEvent event) { - final Set townBlocks = new HashSet<>(); - final Craft craft = event.getCraft(); - if (!Settings.TownyBlockSinkOnNoPVP) - return; - final HitBox hitBox = craft.getHitBox(); - if (hitBox.isEmpty()) - return; - for (MovecraftLocation ml : hitBox) { - - TownBlock townBlock = TownyUtils.getTownBlock(ml.toBukkit(event.getCraft().getW())); - if (townBlock == null || townBlocks.contains(townBlock)) { - continue; - } - if (TownyUtils.validatePVP(townBlock)) { - townBlocks.add(townBlock); - continue; - } - final Player notifyP = craft.getNotificationPlayer(); - if (notifyP != null) { - notifyP.sendMessage(String.format(I18nSupport.getInternationalisedString("Towny - Sinking a craft is not allowed in this town plot") + " @ %d,%d,%d", ml.getX(), ml.getY(), ml.getZ())); - } - event.setCancelled(true); - break; - } - } -} diff --git a/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/TownyUtils.java b/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/TownyUtils.java deleted file mode 100644 index 567741fc8..000000000 --- a/modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/TownyUtils.java +++ /dev/null @@ -1,240 +0,0 @@ -package net.countercraft.movecraft.utils; - -import com.palmergames.bukkit.towny.exceptions.NotRegisteredException; -import com.palmergames.bukkit.towny.exceptions.TownyException; -import com.palmergames.bukkit.towny.object.Coord; -import com.palmergames.bukkit.towny.object.PlayerCache; -import com.palmergames.bukkit.towny.object.PlayerCache.TownBlockStatus; -import com.palmergames.bukkit.towny.object.Resident; -import com.palmergames.bukkit.towny.object.Town; -import com.palmergames.bukkit.towny.object.TownBlock; -import com.palmergames.bukkit.towny.object.TownyPermission; -import com.palmergames.bukkit.towny.object.TownyUniverse; -import com.palmergames.bukkit.towny.object.TownyWorld; -import com.palmergames.bukkit.towny.utils.PlayerCacheUtil; -import com.palmergames.bukkit.towny.war.flagwar.TownyWarConfig; -import net.countercraft.movecraft.Movecraft; -import net.countercraft.movecraft.config.Settings; -import net.countercraft.movecraft.localisation.I18nSupport; -import org.bukkit.Location; -import org.bukkit.Material; -import org.bukkit.World; -import org.bukkit.configuration.ConfigurationSection; -import org.bukkit.configuration.file.FileConfiguration; -import org.bukkit.entity.Player; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.logging.Level; - -/** - * @author mwkaicz - */ -public class TownyUtils { - public static final String TOWN_MIN = "worldMin"; - public static final String TOWN_MAX = "worldMax"; - public static final String TOWN_ABOVE = "aboveTownSpawn"; - public static final String TOWN_UNDER = "underTownSpawn"; - public static final String TOWN_HEIGHT_LIMITS = "TownyWorldHeightLimits"; - - public static TownyWorld getTownyWorld(World w) { - TownyWorld tw; - try { - tw = TownyUniverse.getDataSource().getWorld(w.getName()); - if (!tw.isUsingTowny()) - return null; - } catch (NotRegisteredException e) { - return null; - } - return tw; - } - - public static TownBlock getTownBlock(Location loc) { - Coord coo = Coord.parseCoord(loc); - TownyWorld tw = getTownyWorld(loc.getWorld()); - TownBlock tb = null; - try { - if (tw != null) { - tb = tw.getTownBlock(coo); - } - } catch (NotRegisteredException ex) { - //Logger.getLogger(TownyUtils.class.getName()).log(Level.SEVERE, null, ex); - //free land - } - return tb; - } - - public static Town getTown(TownBlock townBlock) { - try { - Town town; - town = townBlock.getTown(); - return town; - } catch (TownyException e) { - //Logger.getLogger(TownyUtils.class.getName()).log(Level.SEVERE, null, ex); - //none - } - return null; - } - - public static Location getTownSpawn(TownBlock townBlock) { - if (townBlock == null) return null; - Town t = getTown(townBlock); - if (t != null) { - try { - return t.getSpawn(); - } catch (TownyException ex) { - Movecraft.getInstance().getLogger().log(Level.SEVERE, String.format(I18nSupport.getInternationalisedString("Towny - Spawn Not Found"),t.getName()), ex); - //town hasn't spawn - } - } - return null; - } - - - public static boolean validateResident(Player player) { - Resident resident; - try { - resident = TownyUniverse.getDataSource().getResident(player.getName()); - return true; - } catch (TownyException e) { - //System.out.print("Failed to fetch resident: " + player.getName()); - //return TownBlockStatus.NOT_REGISTERED; - } - return false; - } - - public static boolean validateCraftMoveEvent(Player player, Location loc, TownyWorld world) { - // Get switch permissions (updates if none exist) - if (player != null && !validateResident(player)) { - return true; //probably NPC or CBWrapper Dummy player - } - int id = Material.STONE_BUTTON.getId(); - byte data = 0; - - boolean bSwitch = PlayerCacheUtil.getCachePermission(player, loc, id, data, TownyPermission.ActionType.SWITCH); - - // Allow move if we are permitted to switch - if (bSwitch) - return true; - - PlayerCache cache = Movecraft.getInstance().getTownyPlugin().getCache(player); - TownBlockStatus status = cache.getStatus(); - - return !cache.hasBlockErrMsg() && status == TownBlockStatus.WARZONE && TownyWarConfig.isAllowingSwitchesInWarZone(); - - } - - public static boolean validatePVP(TownBlock tb) { - Town t = getTown(tb); - if (t != null) { - return t.getPermissions().pvp || tb.getPermissions().pvp; - } else { - return tb.getPermissions().pvp; - } - } - - public static boolean validateExplosion(TownBlock tb) { - Town t = getTown(tb); - if (t != null) { - return t.getPermissions().explosion || tb.getPermissions().explosion; - } else { - return tb.getPermissions().explosion; - } - } - - public static void initTownyConfig() { - Settings.TownProtectionHeightLimits = getTownyConfigFromUniverse(); - loadTownyConfig(); - } - - private static Map getTownyConfigFromUniverse() { - Map worldsMap = new HashMap<>(); - List worlds = Movecraft.getInstance().getServer().getWorlds(); - for (World w : worlds) { - TownyWorld tw = getTownyWorld(w); - if (tw != null) { - if (tw.isUsingTowny()) { - worldsMap.put(w.getName(), new TownyWorldHeightLimits()); - } - } - } - return worldsMap; - } - - public static TownyWorldHeightLimits getWorldLimits(World w) { - boolean oNew = false; - String wName = w.getName(); - Map worldsMap = Settings.TownProtectionHeightLimits; - if (!worldsMap.containsKey(wName)) { - TownyWorld tw = getTownyWorld(w); - if (tw != null) { - if (tw.isUsingTowny()) { - worldsMap.put(wName, new TownyWorldHeightLimits()); - Settings.TownProtectionHeightLimits = worldsMap; - Movecraft.getInstance().getLogger().log(Level.INFO, I18nSupport.getInternationalisedString("Towny - Added Config Defaults"), w.getName()); - oNew = true; - } else { - return null; - } - } else { - return null; - } - } - if (oNew) { - saveWorldLimits(); - } - return worldsMap.get(wName); - } - - private static void saveWorldLimits() { - Map worldsMap = Settings.TownProtectionHeightLimits; - Map townyWorldsMap = new HashMap<>(); - Set worlds = worldsMap.keySet(); - - for (String world : worlds) { - World w = Movecraft.getInstance().getServer().getWorld(world); - if (w != null) { - TownyWorld tw = getTownyWorld(w); - if (tw != null) { - if (tw.isUsingTowny()) { - Map townyTWorldMap = new HashMap<>(); - TownyWorldHeightLimits twhl = worldsMap.get(world); - townyTWorldMap.put(TOWN_MIN, twhl.world_min); - townyTWorldMap.put(TOWN_MAX, twhl.world_max); - townyTWorldMap.put(TOWN_ABOVE, twhl.above_town); - townyTWorldMap.put(TOWN_UNDER, twhl.under_town); - townyWorldsMap.put(world, townyTWorldMap); - Movecraft.getInstance().getConfig().set(TOWN_HEIGHT_LIMITS + "." + world, townyTWorldMap); - } - } - } - } - Movecraft.getInstance().saveConfig(); - Movecraft.getInstance().getLogger().log(Level.INFO, I18nSupport.getInternationalisedString("Towny - Saved Settings")); - } - - private static void loadTownyConfig() { - FileConfiguration fc = Movecraft.getInstance().getConfig(); - ConfigurationSection csObj = fc.getConfigurationSection(TOWN_HEIGHT_LIMITS); - Map townyWorldHeightLimits = new HashMap<>(); - - if (csObj != null) { - Set worlds = csObj.getKeys(false); - for (String worldName : worlds) { - TownyWorldHeightLimits twhl = new TownyWorldHeightLimits(); - twhl.world_min = fc.getInt(TOWN_HEIGHT_LIMITS + "." + worldName + "." + TOWN_MIN, TownyWorldHeightLimits.DEFAULT_WORLD_MIN); - twhl.world_max = fc.getInt(TOWN_HEIGHT_LIMITS + "." + worldName + "." + TOWN_MAX, TownyWorldHeightLimits.DEFAULT_WORLD_MAX); - twhl.above_town = fc.getInt(TOWN_HEIGHT_LIMITS + "." + worldName + "." + TOWN_ABOVE, TownyWorldHeightLimits.DEFAULT_TOWN_ABOVE); - twhl.under_town = fc.getInt(TOWN_HEIGHT_LIMITS + "." + worldName + "." + TOWN_UNDER, TownyWorldHeightLimits.DEFAULT_TOWN_UNDER); - townyWorldHeightLimits.put(worldName, twhl); - Movecraft.getInstance().getLogger().log(Level.INFO, I18nSupport.getInternationalisedString("Towny - Loaded Settings"), worldName); - } - } - if (!townyWorldHeightLimits.equals(Settings.TownProtectionHeightLimits)) { - Settings.TownProtectionHeightLimits.putAll(townyWorldHeightLimits); - saveWorldLimits(); - } - } -} diff --git a/modules/Movecraft/src/main/resources/config.yml b/modules/Movecraft/src/main/resources/config.yml index 835facd61..0d7ee0b11 100644 --- a/modules/Movecraft/src/main/resources/config.yml +++ b/modules/Movecraft/src/main/resources/config.yml @@ -54,14 +54,6 @@ WGCustomFlagsUseSinkFlag: false DurabilityOverride: 121: 80 206: 80 -TownyBlockMoveOnSwitchPerm: false -TownyBlockSinkOnNoPVP: false -TownyWorldHeightLimits: - world: - worldMin: -1 - worldMax: -1 - aboveTownSpawn: 96 - underTownSpawn: 255 ForbiddenRemoteSigns: # These strings will be ignored when searching for signs to trigger from a remote sign - "Mounted" - "Denied" diff --git a/modules/Movecraft/src/main/resources/localisation/movecraftlang_cz.properties b/modules/Movecraft/src/main/resources/localisation/movecraftlang_cz.properties index db1f06589..7d48d7dd2 100644 --- a/modules/Movecraft/src/main/resources/localisation/movecraftlang_cz.properties +++ b/modules/Movecraft/src/main/resources/localisation/movecraftlang_cz.properties @@ -92,10 +92,6 @@ Repairs\ underway=Probihaji opravy Repairs\ complete\.\ You\ may\ now\ pilot\ the\ craft=Opravy dokonceny. Nyni muzes ridit stroj You\ do\ not\ have\ enough\ money=Nemas dostatek penez Need\ more\ of\ material=Je potreba vice materialu -Towny\ -\ Detection\ Failed=Detekce selhala - Nemas pravo ridit stroj na teto parcele ve meste -Towny\ -\ Translation\ Failed=Stroj se nemuze pohnout - Nemas pravo hybat se strojem na teto parcele ve meste -Towny\ -\ Rotation\ Failed=Stroj se nemuze otocit - Nemas pravo otocit stroj na teto parcele ve meste -Towny\ -\ Sinking\ a\ craft\ is\ not\ allowed\ in\ this\ town\ plot=Potopeni stroje neni povoleno na teto parcele mesta\! WGCustomFlags\ -\ Translation\ Failed=Stroj se nemuze pohnout - Nemas pravo hybat se strojem v tomto WorldGuard regionu WGCustomFlags\ -\ Rotation\ Failed=Stroj se nemuze otocit - Nemas pravo otocit stroj v tomto WorldGuard regionu WGCustomFlags\ -\ Detection\ Failed=Detekce selhala - Nemas pravo ridit stroj v tomto WorldGuard regionu diff --git a/modules/Movecraft/src/main/resources/localisation/movecraftlang_en.properties b/modules/Movecraft/src/main/resources/localisation/movecraftlang_en.properties index b2e6d7843..1dafda089 100644 --- a/modules/Movecraft/src/main/resources/localisation/movecraftlang_en.properties +++ b/modules/Movecraft/src/main/resources/localisation/movecraftlang_en.properties @@ -122,8 +122,6 @@ Startup\ -\ WG\ Found=Found a compatible version of WorldGuard. Enabling WorldGu Startup\ -\ WG\ Not\ Found=Movecraft did not find a compatible version of WorldGuard. Disabling WorldGuard integration. Startup\ -\ WGCF\ Found=Found a compatible version of WGCustomFlags. Enabling WGCustomFlags integration. Startup\ -\ WGCF\ Not\ Found=Movecraft did not find a compatible version of WGCustomFlags. Disabling WGCustomFlags integration. -Startup\ -\ Towny\ Found=Found a compatible version of Towny. Enabling Towny integration. -Startup\ -\ Towny\ Not\ Found=Movecraft did not find a compatible version of Towny. Disabling Towny integration. Teleportation\ -\ Cooldown\ active=Teleportation cooldown is active. You need to wait %d seconds Translation\ -\ Failed\ Craft\ cannot\ pass\ world\ border=Translation Failed: You cannot move the craft past the world border Translation\ -\ Failed\ Craft\ hit\ height\ limit=Craft has hit the height limit @@ -146,14 +144,6 @@ Direct\ Control\ -\ Entering=Entering Direct Control Mode Direct\ Control\ -\ Leaving=Leaving Direct Control Mode You\ must\ be\ piloting\ a\ craft=You must be piloting a craft SIB\ MUST\ BE\ PLACED\ IN\ REGION=SIB MUST BE PLACED IN REGION -Towny\ -\ Detection\ Failed=Detection Failed - You are not permitted to pilot a craft on this plot in the town -Towny\ -\ Translation\ Failed=Translation Failed - You are not permitted to move a craft on this plot in the town -Towny\ -\ Rotation\ Failed=Rotation Failed - You are not permitted to rotate a craft on this plot in the town -Towny\ -\ Sinking\ a\ craft\ is\ not\ allowed\ in\ this\ town\ plot=Sinking a craft is not allowed in this town plot\! -Towny\ -\ Spawn\ Not\ Found=Town spawn of %s not found\! -Towny\ -\ Added\ Config\ Defaults=Added default Towny settings for world {0} to the config file. -Towny\ -\ Saved\ Settings=Saved settings for Towny worlds to the config file. -Towny\ -\ Loaded\ Settings=Loaded Towny settings for world {0} WGCustomFlags\ -\ Translation\ Failed=Translation Failed - You are not permitted to move a craft in this WorldGuard region WGCustomFlags\ -\ Rotation\ Failed=Rotation Failed - You are not permitterd to rotate a craft in this WorldGuard region WGCustomFlags\ -\ Detection\ Failed=Detection Failed - You are not permitted to pilot a craft in this WorldGuard region diff --git a/modules/Movecraft/src/main/resources/plugin.yml b/modules/Movecraft/src/main/resources/plugin.yml index 29d6b9a1b..f9add75d5 100644 --- a/modules/Movecraft/src/main/resources/plugin.yml +++ b/modules/Movecraft/src/main/resources/plugin.yml @@ -1,5 +1,5 @@ name: Movecraft -softdepend: [WorldGuard, WGCustomFlags, Towny] +softdepend: [WorldGuard, WGCustomFlags] version: ${project.version} #version: ${env.BUILD_NUMBER} description: The original flight and movement plugin for minecraft. diff --git a/modules/api/src/main/java/net/countercraft/movecraft/config/Settings.java b/modules/api/src/main/java/net/countercraft/movecraft/config/Settings.java index 080b23b2b..6de4ab286 100644 --- a/modules/api/src/main/java/net/countercraft/movecraft/config/Settings.java +++ b/modules/api/src/main/java/net/countercraft/movecraft/config/Settings.java @@ -17,7 +17,6 @@ package net.countercraft.movecraft.config; -import net.countercraft.movecraft.utils.TownyWorldHeightLimits; import org.bukkit.Material; import java.util.HashMap; @@ -58,9 +57,6 @@ public class Settings { public static boolean WGCustomFlagsUseMoveFlag = false; public static boolean WGCustomFlagsUseRotateFlag = false; public static boolean WGCustomFlagsUseSinkFlag = false; - public static boolean TownyBlockMoveOnSwitchPerm = false; - public static boolean TownyBlockSinkOnNoPVP = false; - public static Map TownProtectionHeightLimits; public static boolean CraftsUseNetherPortals = false; public static boolean IsPaper = false; diff --git a/modules/api/src/main/java/net/countercraft/movecraft/utils/TownyWorldHeightLimits.java b/modules/api/src/main/java/net/countercraft/movecraft/utils/TownyWorldHeightLimits.java deleted file mode 100644 index 311e5c18a..000000000 --- a/modules/api/src/main/java/net/countercraft/movecraft/utils/TownyWorldHeightLimits.java +++ /dev/null @@ -1,44 +0,0 @@ -package net.countercraft.movecraft.utils; - -/** - * @author mwkaicz - */ -public class TownyWorldHeightLimits { - public static final int DEFAULT_WORLD_MIN = -1; - public static final int DEFAULT_WORLD_MAX = -1; - public static final int DEFAULT_TOWN_ABOVE = 96; - public static final int DEFAULT_TOWN_UNDER = 255; - public int world_min = DEFAULT_WORLD_MIN; - public int world_max = DEFAULT_WORLD_MAX; - public int above_town = DEFAULT_TOWN_ABOVE; - public int under_town = DEFAULT_TOWN_UNDER; - - public boolean validate(int y, int spawnY) { - - if (world_min > -1 && world_max > -1) { - if (y > world_min && y < world_max) { - return false; - } - } else if (world_min > -1) { - if (y > world_min) { - return false; - } - } else if (world_max > -1) { - if (y < world_max) { - return false; - } - } - - if (above_town > -1 && under_town > -1) { - return y >= spawnY + above_town || y <= spawnY - under_town; - } else if (above_town > -1) { - return y < spawnY || y >= spawnY + above_town; - } else if (under_town > -1) { - return y > spawnY || y <= spawnY - under_town; - } - - return true; - - //return !((y > world_min && y < world_max) || (y < spawnY + above_town && y > spawnY - under_town ) ); - } -} From 728fd75a13fa194dd132eec4628cc85971a9121e Mon Sep 17 00:00:00 2001 From: eirikh1996 Date: Sat, 13 Mar 2021 21:40:37 +0100 Subject: [PATCH 277/304] Merge https://github.com/APDevTeam/Movecraft # Conflicts: # .github/workflows/maven.yml # README.md # modules/Movecraft/pom.xml # modules/Movecraft/src/main/java/net/countercraft/movecraft/Movecraft.java # modules/Movecraft/src/main/java/net/countercraft/movecraft/async/AsyncManager.java # modules/Movecraft/src/main/java/net/countercraft/movecraft/async/rotation/RotationTask.java # modules/Movecraft/src/main/java/net/countercraft/movecraft/async/translation/TranslationTask.java # modules/Movecraft/src/main/java/net/countercraft/movecraft/commands/ManOverboardCommand.java # modules/Movecraft/src/main/java/net/countercraft/movecraft/listener/InteractListener.java # modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/CrewSign.java # modules/Movecraft/src/main/java/net/countercraft/movecraft/sign/SpeedSign.java # modules/Movecraft/src/main/resources/config.yml # modules/Movecraft/src/main/resources/localisation/movecraftlang_en.properties # modules/Movecraft/src/main/resources/plugin.yml # modules/api/src/main/java/net/countercraft/movecraft/config/Settings.java # modules/api/src/main/java/net/countercraft/movecraft/craft/Craft.java --- modules/Movecraft/src/main/resources/plugin.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/Movecraft/src/main/resources/plugin.yml b/modules/Movecraft/src/main/resources/plugin.yml index f6ec91b13..b1a7db8d2 100644 --- a/modules/Movecraft/src/main/resources/plugin.yml +++ b/modules/Movecraft/src/main/resources/plugin.yml @@ -1,5 +1,5 @@ name: Movecraft -softdepend: [WorldGuard, WorldEdit, FastAsyncWorldEdit, Cannons, Vault ,Essentials, WGCustomFlags] +softdepend: [WorldGuard, WorldEdit, WGCustomFlags] version: ${project.version} api-version: 1.13 description: The original flight and movement plugin for minecraft. From 24f6f7eb8f3aba68272f805ccab37f0d60184c7f Mon Sep 17 00:00:00 2001 From: TylerS1066 Date: Sat, 20 Mar 2021 11:37:05 -0500 Subject: [PATCH 278/304] Bump spigot api version --- modules/Movecraft/pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/Movecraft/pom.xml b/modules/Movecraft/pom.xml index a33998ab0..3a294e446 100644 --- a/modules/Movecraft/pom.xml +++ b/modules/Movecraft/pom.xml @@ -32,7 +32,7 @@ org.spigotmc spigot - 1.16.4-R0.1-SNAPSHOT + 1.16.5-R0.1-SNAPSHOT provided From ca56ee5eb905c1c6dddbdffcaca215a11e567e4a Mon Sep 17 00:00:00 2001 From: cccm5 Date: Sat, 20 Mar 2021 14:03:23 -0400 Subject: [PATCH 279/304] 1.12.2 moving redstone --- .../compat/v1_12_R1/IWorldHandler.java | 217 ++++++++++-------- .../compat/v1_12_R1/NextTickProvider.java | 33 ++- 2 files changed, 149 insertions(+), 101 deletions(-) diff --git a/modules/v1_12_R1/src/main/java/net/countercraft/movecraft/compat/v1_12_R1/IWorldHandler.java b/modules/v1_12_R1/src/main/java/net/countercraft/movecraft/compat/v1_12_R1/IWorldHandler.java index 1d3df8ad2..2d59f2b4c 100644 --- a/modules/v1_12_R1/src/main/java/net/countercraft/movecraft/compat/v1_12_R1/IWorldHandler.java +++ b/modules/v1_12_R1/src/main/java/net/countercraft/movecraft/compat/v1_12_R1/IWorldHandler.java @@ -3,11 +3,24 @@ import net.countercraft.movecraft.MovecraftLocation; import net.countercraft.movecraft.Rotation; import net.countercraft.movecraft.WorldHandler; -import net.countercraft.movecraft.config.Settings; import net.countercraft.movecraft.craft.Craft; import net.countercraft.movecraft.utils.CollectionUtils; import net.countercraft.movecraft.utils.MathUtils; -import net.minecraft.server.v1_12_R1.*; +import net.minecraft.server.v1_12_R1.Block; +import net.minecraft.server.v1_12_R1.BlockFire; +import net.minecraft.server.v1_12_R1.BlockPosition; +import net.minecraft.server.v1_12_R1.Blocks; +import net.minecraft.server.v1_12_R1.Chunk; +import net.minecraft.server.v1_12_R1.ChunkSection; +import net.minecraft.server.v1_12_R1.EntityPlayer; +import net.minecraft.server.v1_12_R1.EnumBlockRotation; +import net.minecraft.server.v1_12_R1.IBlockData; +import net.minecraft.server.v1_12_R1.NextTickListEntry; +import net.minecraft.server.v1_12_R1.PacketPlayOutPosition; +import net.minecraft.server.v1_12_R1.PlayerConnection; +import net.minecraft.server.v1_12_R1.TileEntity; +import net.minecraft.server.v1_12_R1.World; +import net.minecraft.server.v1_12_R1.WorldServer; import org.bukkit.Location; import org.bukkit.Material; import org.bukkit.craftbukkit.v1_12_R1.CraftWorld; @@ -19,14 +32,22 @@ import java.lang.invoke.MethodHandle; import java.lang.invoke.MethodHandles; -import java.lang.reflect.Field; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; -import java.util.*; +import java.util.ArrayList; +import java.util.Collection; +import java.util.EnumSet; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; @SuppressWarnings("unused") public class IWorldHandler extends WorldHandler { private static final EnumBlockRotation ROTATION[]; + private final HashMap> bMap = new HashMap<>(); + private MethodHandle internalTeleportMH; static { ROTATION = new EnumBlockRotation[3]; ROTATION[Rotation.NONE.ordinal()] = EnumBlockRotation.NONE; @@ -34,8 +55,6 @@ public class IWorldHandler extends WorldHandler { ROTATION[Rotation.ANTICLOCKWISE.ordinal()] = EnumBlockRotation.COUNTERCLOCKWISE_90; } private final NextTickProvider tickProvider = new NextTickProvider(); - private final HashMap> bMap = new HashMap<>(); - private MethodHandle internalTeleportMH; public IWorldHandler() { MethodHandles.Lookup lookup = MethodHandles.lookup(); @@ -75,21 +94,11 @@ public void rotateCraft(@NotNull Craft craft, @NotNull MovecraftLocation originP for(MovecraftLocation newLocation : craft.getHitBox()){ rotatedPositions.put(locationToPosition(MathUtils.rotateVec(counterRotation, newLocation.subtract(originPoint)).add(originPoint)),locationToPosition(newLocation)); } + WorldServer nativeWorld = ((CraftWorld) craft.getW()).getHandle(); //******************************************* //* Step two: Get the tiles * //******************************************* - World nativeWorld = ((CraftWorld) craft.getW()).getHandle(); - List tiles = new ArrayList<>(); - //get the tiles - for(BlockPosition position : rotatedPositions.keySet()){ - //TileEntity tile = nativeWorld.removeTileEntity(position); - TileEntity tile = removeTileEntity(nativeWorld,position); - if(tile == null) - continue; - tile.a(ROTATION[rotation.ordinal()]); - //get the nextTick to move with the tile - tiles.add(new TileHolder(tile, tickProvider.getNextTick((WorldServer)nativeWorld,position), position)); - } + List tiles = getTiles(rotatedPositions.keySet(), rotation, nativeWorld); //******************************************* //* Step three: Translate all the blocks * @@ -114,11 +123,17 @@ public void rotateCraft(@NotNull Craft craft, @NotNull MovecraftLocation originP //******************************************* //TODO: go by chunks for(TileHolder tileHolder : tiles){ - moveTileEntity(nativeWorld, rotatedPositions.get(tileHolder.getTilePosition()),tileHolder.getTile()); + if(tileHolder.getTile() != null) + moveTileEntity(nativeWorld, rotatedPositions.get(tileHolder.getTilePosition()),tileHolder.getTile(), tileHolder.isCaptured); if(tileHolder.getNextTick()==null) continue; final long currentTime = nativeWorld.worldData.getTime(); - nativeWorld.b(rotatedPositions.get(tileHolder.getNextTick().a), tileHolder.getNextTick().a(), (int) (tileHolder.getNextTick().b - currentTime), tileHolder.getNextTick().c); + if(!rotatedPositions.containsKey(tileHolder.getNextTick().a)){ + nativeWorld.b(tileHolder.getNextTick().a, tileHolder.getNextTick().a(), (int) (tileHolder.getNextTick().b - currentTime), tileHolder.getNextTick().c); + } else { + nativeWorld.b(rotatedPositions.get(tileHolder.getNextTick().a), tileHolder.getNextTick().a(), (int) (tileHolder.getNextTick().b - currentTime), tileHolder.getNextTick().c); + } + } //******************************************* @@ -126,9 +141,7 @@ public void rotateCraft(@NotNull Craft craft, @NotNull MovecraftLocation originP //******************************************* //TODO: add support for pass-through Collection deletePositions = CollectionUtils.filter(rotatedPositions.keySet(),rotatedPositions.values()); - for(BlockPosition position : deletePositions){ - setBlockFast(nativeWorld, position, Blocks.AIR.getBlockData()); - } + setAir(deletePositions, nativeWorld); //******************************************* //* Step six: Process fire spread * //******************************************* @@ -144,7 +157,7 @@ public void rotateCraft(@NotNull Craft craft, @NotNull MovecraftLocation originP @Override public void translateCraft(@NotNull Craft craft, @NotNull MovecraftLocation displacement, @NotNull org.bukkit.World world) { - //TODO: Add support for rotations + //TODO: Add supourt for rotations //A craftTranslateCommand should only occur if the craft is moving to a valid position //******************************************* //* Step one: Convert to Positions * @@ -153,28 +166,21 @@ public void translateCraft(@NotNull Craft craft, @NotNull MovecraftLocation disp List positions = new ArrayList<>(); for(MovecraftLocation movecraftLocation : craft.getHitBox()) { positions.add(locationToPosition((movecraftLocation)).b(translateVector)); - } - World oldNativeWorld = ((CraftWorld) craft.getW()).getHandle(); - World nativeWorld = ((CraftWorld) world).getHandle(); + WorldServer oldNativeWorld = ((CraftWorld) craft.getW()).getHandle(); + WorldServer nativeWorld = ((CraftWorld) world).getHandle(); //******************************************* //* Step two: Get the tiles * //******************************************* - List tiles = new ArrayList<>(); - //get the tiles - for(BlockPosition position : positions){ - if(oldNativeWorld.getType(position) == Blocks.AIR.getBlockData()) - continue; - //TileEntity tile = nativeWorld.removeTileEntity(position); - TileEntity tile = removeTileEntity(oldNativeWorld,position); - if(tile == null) - continue; - //get the nextTick to move with the tile - - //nativeWorld.capturedTileEntities.remove(position); - //nativeWorld.getChunkAtWorldCoords(position).getTileEntities().remove(position); - tiles.add(new TileHolder(tile, tickProvider.getNextTick((WorldServer)oldNativeWorld,position), position)); - + Set validTickLocations = new HashSet<>(positions); + List tiles = getTiles(positions, oldNativeWorld); + final long currentTime = oldNativeWorld.worldData.getTime(); + for(TileHolder tile : tiles){ + if(tile.getNextTick() != null && !validTickLocations.contains(tile.getNextTick().a)){ + NextTickListEntry tick = tile.getNextTick(); + oldNativeWorld.b(tick.a, tick.a(), (int) (tick.b - currentTime), tick.c); + tile.nextTick = null; + } } //******************************************* //* Step three: Translate all the blocks * @@ -191,64 +197,91 @@ public void translateCraft(@NotNull Craft craft, @NotNull MovecraftLocation disp newPositions.add(position.a(translateVector)); } //create the new block - for(int i = 0; i deletePositions = positions; if (oldNativeWorld == nativeWorld) deletePositions = CollectionUtils.filter(positions,newPositions); - for(BlockPosition position : deletePositions){ - setBlockFast(oldNativeWorld, position, Blocks.AIR.getBlockData()); - } - + setAir(deletePositions, oldNativeWorld); //******************************************* //* Step six: Process fire spread * //******************************************* - for (BlockPosition position : newPositions) { - IBlockData type = nativeWorld.getType(position); + processFireSpread(newPositions, nativeWorld); + } + + private void setBlocks(List newPositions, List blockData, World nativeWorld){ + for(int i = 0; i getTiles(Iterable positions, WorldServer nativeWorld){ + return getTiles(positions, null, nativeWorld); + } + + private List getTiles(Iterable positions, Rotation rotation, WorldServer nativeWorld){ + List tiles = new ArrayList<>(); + //get the tiles + for(BlockPosition position : positions){ + if(nativeWorld.getType(position) == Blocks.AIR.getBlockData()) + continue; + TileHolder holder = removeTileEntity(nativeWorld,position); + if(holder == null) + continue; + if(holder.tile != null && rotation != null){ + holder.tile.a(ROTATION[rotation.ordinal()]); + } + tiles.add(holder); + + } + return tiles; + } + + private void processTiles(Iterable tiles, World world, BlockPosition translateVector){ + for(TileHolder tileHolder : tiles){ + if(tileHolder.getTile() != null) + moveTileEntity(world, tileHolder.getTilePosition().a(translateVector),tileHolder.getTile(), tileHolder.isCaptured()); + if(tileHolder.getNextTick()==null) + continue; + final long currentTime = world.worldData.getTime(); + NextTickListEntry tick = tileHolder.getNextTick(); + world.b(tick.a.a(translateVector), tick.a(), (int) (tick.b - currentTime), tick.c); + } + } + + private void processFireSpread(Iterable positions, World world){ + for (BlockPosition position : positions) { + IBlockData type = world.getType(position); if (!(type.getBlock() instanceof BlockFire)) { continue; } BlockFire fire = (BlockFire) type.getBlock(); - fire.b(nativeWorld, position, type, nativeWorld.random); + fire.b(world, position, type, world.random); + } + } + + private void setAir(Iterable positions, World world){ + for(BlockPosition position : positions){ + setBlockFast(world, position, Blocks.AIR.getBlockData()); } } @Nullable - private TileEntity removeTileEntity(@NotNull World world, @NotNull BlockPosition position){ + private TileHolder removeTileEntity(@NotNull World world, @NotNull BlockPosition position){ TileEntity tile = world.getTileEntity(position); - if(tile == null) + NextTickListEntry tick = tickProvider.getNextTick((WorldServer) world, position); + if(tile == null && tick == null){ return null; - //cleanup - world.capturedTileEntities.remove(position); - world.getChunkAtWorldCoords(position).getTileEntities().remove(position); - if(!Settings.IsPaper) - world.tileEntityList.remove(tile); - world.tileEntityListTick.remove(tile); - if(!bMap.containsKey(world)){ - try { - Field bField = World.class.getDeclaredField("b"); - bField.setAccessible(true); - bMap.put(world, (List) bField.get(world)); - } catch (IllegalAccessException | IllegalArgumentException | NoSuchFieldException | SecurityException e1) { - e1.printStackTrace(); - } } - bMap.get(world).remove(tile); - return tile; + boolean isCaptured = world.capturedTileEntities.remove(position) != null; + world.getChunkAtWorldCoords(position).getTileEntities().remove(position); + return new TileHolder(tile, tick, position, isCaptured); } @NotNull @@ -256,7 +289,7 @@ private BlockPosition locationToPosition(@NotNull MovecraftLocation loc) { return new BlockPosition(loc.getX(), loc.getY(), loc.getZ()); } - private void setBlockFast(@NotNull World world, @NotNull BlockPosition position,@NotNull IBlockData data) { + private void setBlockFast(@NotNull World world, @NotNull BlockPosition position, @NotNull IBlockData data) { Chunk chunk = world.getChunkAtWorldCoords(position); ChunkSection chunkSection = chunk.getSections()[position.getY()>>4]; if (chunkSection == null) { @@ -271,7 +304,7 @@ private void setBlockFast(@NotNull World world, @NotNull BlockPosition position, chunkSection.setType(position.getX()&15, position.getY()&15, position.getZ()&15, data); world.notify(position, data, data, 3); - chunk.markDirty(); + chunk.markDirty(); // mark dirty } @Override @@ -306,34 +339,32 @@ private static MovecraftLocation bukkit2MovecraftLoc(Location l) { return new MovecraftLocation(l.getBlockX(), l.getBlockY(), l.getBlockZ()); } - private void moveTileEntity(@NotNull World nativeWorld, @NotNull BlockPosition newPosition, @NotNull TileEntity tile){ + private void moveTileEntity(@NotNull World nativeWorld, @NotNull BlockPosition newPosition, @NotNull TileEntity tile, boolean captured){ Chunk chunk = nativeWorld.getChunkAtWorldCoords(newPosition); - tile.invalidateBlockCache(); - if(nativeWorld.captureBlockStates) { - tile.a(nativeWorld); - tile.setPosition(newPosition); + if(captured){ nativeWorld.capturedTileEntities.put(newPosition, tile); - return; } tile.a(nativeWorld); tile.setPosition(newPosition); chunk.tileEntities.put(newPosition, tile); } - private class TileHolder{ - @NotNull private final TileEntity tile; + private static class TileHolder{ + @Nullable private final TileEntity tile; @Nullable - private final NextTickListEntry nextTick; + private NextTickListEntry nextTick; @NotNull private final BlockPosition tilePosition; + private final boolean isCaptured; - public TileHolder(@NotNull TileEntity tile, @Nullable NextTickListEntry nextTick, @NotNull BlockPosition tilePosition){ + public TileHolder(@Nullable TileEntity tile, @Nullable NextTickListEntry nextTick, @NotNull BlockPosition tilePosition, boolean isCaptured){ this.tile = tile; this.nextTick = nextTick; this.tilePosition = tilePosition; + this.isCaptured = isCaptured; } - @NotNull + @Nullable public TileEntity getTile() { return tile; } @@ -347,5 +378,9 @@ public NextTickListEntry getNextTick() { public BlockPosition getTilePosition() { return tilePosition; } + + public boolean isCaptured() { + return isCaptured; + } } -} \ No newline at end of file +} diff --git a/modules/v1_12_R1/src/main/java/net/countercraft/movecraft/compat/v1_12_R1/NextTickProvider.java b/modules/v1_12_R1/src/main/java/net/countercraft/movecraft/compat/v1_12_R1/NextTickProvider.java index ae3e8a69b..fd9a01d64 100644 --- a/modules/v1_12_R1/src/main/java/net/countercraft/movecraft/compat/v1_12_R1/NextTickProvider.java +++ b/modules/v1_12_R1/src/main/java/net/countercraft/movecraft/compat/v1_12_R1/NextTickProvider.java @@ -4,11 +4,11 @@ import net.minecraft.server.v1_12_R1.NextTickListEntry; import net.minecraft.server.v1_12_R1.WorldServer; import org.apache.commons.lang3.tuple.ImmutablePair; +import org.bukkit.craftbukkit.v1_12_R1.util.HashTreeSet; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import org.bukkit.craftbukkit.v1_12_R1.util.HashTreeSet; - +import java.lang.ref.WeakReference; import java.lang.reflect.Field; import java.util.ArrayList; import java.util.HashMap; @@ -17,10 +17,13 @@ import java.util.Map; public class NextTickProvider { - private Map,List>> tickMap = new HashMap<>(); + private Map>,WeakReference>>> tickMap = new HashMap<>(); private boolean isRegistered(@NotNull WorldServer world){ - return tickMap.containsKey(world); + if(!tickMap.containsKey(world)) + return false; + ImmutablePair>, WeakReference>> listPair = tickMap.get(world); + return listPair.right.get() != null && listPair.left.get() != null; } @SuppressWarnings("unchecked") @@ -39,16 +42,17 @@ private void registerWorld(@NotNull WorldServer world){ } catch (IllegalAccessException | IllegalArgumentException | NoSuchFieldException | SecurityException e1) { e1.printStackTrace(); } - tickMap.put(world, new ImmutablePair<>(nextTickList,W)); + tickMap.put(world, new ImmutablePair<>(new WeakReference<>(nextTickList), new WeakReference<>(W))); } @Nullable + @SuppressWarnings("ConstantConditions") public NextTickListEntry getNextTick(@NotNull WorldServer world,@NotNull BlockPosition position){ if(!isRegistered(world)) registerWorld(world); - ImmutablePair, List> listPair = tickMap.get(world); - if(listPair.left.contains(fakeEntry(position))) { - for (Iterator iterator = listPair.left.iterator(); iterator.hasNext(); ) { + ImmutablePair>, WeakReference>> listPair = tickMap.get(world); + if(listPair.left.get().contains(fakeEntry(position))) { + for (Iterator iterator = listPair.left.get().iterator(); iterator.hasNext(); ) { NextTickListEntry listEntry = iterator.next(); if (position.equals(listEntry.a)) { iterator.remove(); @@ -56,7 +60,8 @@ public NextTickListEntry getNextTick(@NotNull WorldServer world,@NotNull BlockPo } } } - for(Iterator iterator = listPair.right.iterator(); iterator.hasNext();) { + + for(Iterator iterator = listPair.right.get().iterator(); iterator.hasNext();) { NextTickListEntry listEntry = iterator.next(); if (position.equals(listEntry.a)) { iterator.remove(); @@ -66,6 +71,7 @@ public NextTickListEntry getNextTick(@NotNull WorldServer world,@NotNull BlockPo return null; } + @NotNull public Object fakeEntry(@NotNull BlockPosition position){ return new Object(){ @@ -73,6 +79,13 @@ public Object fakeEntry(@NotNull BlockPosition position){ public int hashCode() { return position.hashCode(); } + @Override + public boolean equals(Object other){ + if (!(other instanceof NextTickListEntry)) { + return false; + } + return position.equals(((NextTickListEntry)other).a); + } }; } -} +} \ No newline at end of file From 079c4291726f8f418ae0a4e08570ae7547f83374 Mon Sep 17 00:00:00 2001 From: TylerS1066 Date: Sat, 20 Mar 2021 17:15:53 -0500 Subject: [PATCH 280/304] Fix version --- modules/Movecraft/dependency-reduced-pom.xml | 16 ++++++---------- modules/Movecraft/pom.xml | 2 +- 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/modules/Movecraft/dependency-reduced-pom.xml b/modules/Movecraft/dependency-reduced-pom.xml index def69ffdb..cd3e891d5 100644 --- a/modules/Movecraft/dependency-reduced-pom.xml +++ b/modules/Movecraft/dependency-reduced-pom.xml @@ -167,12 +167,14 @@ jitpack.io https://jitpack.io - - ess-repo - https://ci.ender.zone/plugin/repository/everything/ - + + org.spigotmc + spigot-api + 1.16.5-R0.1-SNAPSHOT + provided + com.sk89q.worldguard worldguard-core @@ -197,12 +199,6 @@ 1.10 compile - - net.ess3 - EssentialsX - 2.16.1 - provided - org.jetbrains annotations-java5 diff --git a/modules/Movecraft/pom.xml b/modules/Movecraft/pom.xml index 3a294e446..271506cdd 100644 --- a/modules/Movecraft/pom.xml +++ b/modules/Movecraft/pom.xml @@ -31,7 +31,7 @@ org.spigotmc - spigot + spigot-api 1.16.5-R0.1-SNAPSHOT provided From 0d60b059bab622e6f2722de2e4416909e9fc7e1e Mon Sep 17 00:00:00 2001 From: TylerS1066 Date: Sun, 21 Mar 2021 10:22:17 -0500 Subject: [PATCH 281/304] Movecraft-WorldGuard (#386) * First pass * Cleanup * Update ExplosionEvent.java --- libs/WGCustomFlags.jar | Bin 52607 -> 0 bytes modules/Movecraft/pom.xml | 13 --- .../net/countercraft/movecraft/Movecraft.java | 64 ------------ .../async/rotation/RotationTask.java | 12 --- .../movecraft/listener/BlockListener.java | 26 ----- .../update/ExplosionUpdateCommand.java | 15 ++- .../movecraft/utils/WGCustomFlagsUtils.java | 94 ------------------ .../movecraft/utils/WorldguardUtils.java | 39 -------- .../worldguard/WorldGuardCompatManager.java | 43 -------- .../Movecraft/src/main/resources/config.yml | 6 -- .../localisation/movecraftlang_cz.properties | 8 -- .../localisation/movecraftlang_en.properties | 11 -- .../Movecraft/src/main/resources/plugin.yml | 1 - modules/api/pom.xml | 12 --- .../movecraft/config/Settings.java | 7 -- .../movecraft/events/ExplosionEvent.java | 47 +++++++++ 16 files changed, 53 insertions(+), 345 deletions(-) delete mode 100644 libs/WGCustomFlags.jar delete mode 100644 modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/WGCustomFlagsUtils.java delete mode 100644 modules/Movecraft/src/main/java/net/countercraft/movecraft/utils/WorldguardUtils.java delete mode 100644 modules/Movecraft/src/main/java/net/countercraft/movecraft/worldguard/WorldGuardCompatManager.java create mode 100644 modules/api/src/main/java/net/countercraft/movecraft/events/ExplosionEvent.java diff --git a/libs/WGCustomFlags.jar b/libs/WGCustomFlags.jar deleted file mode 100644 index 281da9bc3d81b305ba5a7cb52489d0a992205c84..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 52607 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