From 454e4951145e927ccd573c44523504b07c70832f Mon Sep 17 00:00:00 2001 From: Aleksi Lassila Date: Sat, 31 Oct 2020 14:29:57 +0200 Subject: [PATCH] 4.7.0: Neutral teleporting home command configuration and fixes creation gui improvements queue bug fix fixed island generation bug (generation was totally screwed, how no one noticed this before me lol) --- src/config.yml | 6 ++ .../aleksilassila/islands/GUIs/CreateGUI.java | 2 +- src/me/aleksilassila/islands/Islands.java | 10 +-- ...andCommands.java => TeleportCommands.java} | 82 ++++++++++++++----- .../commands/subcommands/ClearSubcommand.java | 2 +- .../islands/generation/Biomes.java | 18 ++-- .../islands/generation/IslandGeneration.java | 49 +++++++---- .../islands/utils/Permissions.java | 1 + src/messages.properties | 3 +- src/messages_en.properties | 3 +- src/plugin.yml | 6 +- 11 files changed, 125 insertions(+), 57 deletions(-) rename src/me/aleksilassila/islands/commands/{IslandCommands.java => TeleportCommands.java} (65%) diff --git a/src/config.yml b/src/config.yml index 1d0e577..fbb6ad4 100644 --- a/src/config.yml +++ b/src/config.yml @@ -33,6 +33,8 @@ generation: generationDelayInTicks: 0.3 # 2 Will generate 1 row per 2 ticks, 0.5 will generate 2 rows per 1 tick. maxVariationsPerBiome: 5 # Max locations generated for each biome, lower the value to speed up server startup. clearSpeedMultiplier: 3 # Removing blocks should be faster than placing them, so you might swant to speed up clearing. + maxBiomeSize: 80 # Minimum width of biome block so that it gets picked up by the generator and added as available variation. + # Should be the same as the biggest island size being generated. biomeBlacklist: # These biomes do not get picked up by island generator. - DEEP_OCEAN # Ocean biomes work poorly with islands. @@ -55,4 +57,8 @@ voidTeleport: true # If enabled, void kills again in island islandDamage: false # Enable / disable damage on islands restrictIslandBlockFlows: true # Let water / lava only flow inside a sphere containing island disableWilderness: false # Disable wilderness, do not touch unless you know what you are doing +allowHomeOnlyFromOverworld: true # Disable /home in nether and end +disableNeutralTeleports: false # Disable teleporting neutrals to islands with /home command +neutralTeleportRange: 2 # How far neutrals are being teleported around the player +unfinishedIslandTeleports: true # Deny teleports to island that are still being generated. locale: en diff --git a/src/me/aleksilassila/islands/GUIs/CreateGUI.java b/src/me/aleksilassila/islands/GUIs/CreateGUI.java index ecbcae1..85ddd8e 100644 --- a/src/me/aleksilassila/islands/GUIs/CreateGUI.java +++ b/src/me/aleksilassila/islands/GUIs/CreateGUI.java @@ -76,7 +76,7 @@ private List availableIslandPanes() { BiomeMaterials.valueOf(biome.name()).getMaterial(), Messages.get("gui.create.BIOME_NAME", biome.name()), false, - Messages.get("gui.create.BIOME_LORE") + Messages.get("gui.create.BIOME_LORE", availableLocations.get(biome).size()) ), event -> { getSizeGui(biome).show(event.getWhoClicked()); diff --git a/src/me/aleksilassila/islands/Islands.java b/src/me/aleksilassila/islands/Islands.java index 6a974d2..92adc47 100644 --- a/src/me/aleksilassila/islands/Islands.java +++ b/src/me/aleksilassila/islands/Islands.java @@ -3,7 +3,7 @@ import com.sk89q.worldedit.bukkit.WorldEditPlugin; import com.sun.istack.internal.NotNull; import com.sun.istack.internal.Nullable; -import me.aleksilassila.islands.commands.IslandCommands; +import me.aleksilassila.islands.commands.TeleportCommands; import me.aleksilassila.islands.commands.IslandManagmentCommands; import me.aleksilassila.islands.commands.TrustCommands; import me.aleksilassila.islands.generation.IslandGeneration; @@ -105,7 +105,7 @@ public void onEnable() { new IslandManagmentCommands(this); - IslandCommands islandCommands = new IslandCommands(this); + TeleportCommands islandCommands = new TeleportCommands(this); islandCommands.new HomeCommand(); islandCommands.new VisitCommand(); @@ -151,8 +151,7 @@ public String createNewIsland(Biome biome, int islandSize, Player player) throws getIslandsConfig().getInt(islandId + ".z") ), false, - 0, - 0, + islandId, shape ); @@ -191,8 +190,7 @@ public boolean recreateIsland(String islandId, Biome biome, int islandSize, Play getIslandsConfig().getInt(islandId + ".z") ), true, - getIslandsConfig().getInt(islandId + ".xIndex"), - getIslandsConfig().getInt(islandId + ".zIndex"), + islandId, shape ); } catch (IllegalArgumentException e) { diff --git a/src/me/aleksilassila/islands/commands/IslandCommands.java b/src/me/aleksilassila/islands/commands/TeleportCommands.java similarity index 65% rename from src/me/aleksilassila/islands/commands/IslandCommands.java rename to src/me/aleksilassila/islands/commands/TeleportCommands.java index f0173f0..9a5066c 100644 --- a/src/me/aleksilassila/islands/commands/IslandCommands.java +++ b/src/me/aleksilassila/islands/commands/TeleportCommands.java @@ -7,19 +7,24 @@ import me.aleksilassila.islands.utils.Permissions; import org.bukkit.Location; import org.bukkit.Material; +import org.bukkit.World; import org.bukkit.command.Command; import org.bukkit.command.CommandExecutor; import org.bukkit.command.CommandSender; +import org.bukkit.entity.Animals; +import org.bukkit.entity.Entity; +import org.bukkit.entity.Monster; import org.bukkit.entity.Player; import java.util.Date; import java.util.List; +import java.util.Optional; -public class IslandCommands { +public class TeleportCommands { private final Islands plugin; private final IslandLayout layout; - public IslandCommands(Islands plugin) { + public TeleportCommands(Islands plugin) { this.plugin = plugin; this.layout = plugin.layout; } @@ -70,9 +75,19 @@ public boolean onCommand(CommandSender sender, Command command, String label, St } public class HomeCommand implements CommandExecutor { + private final boolean allowHomeOnlyFromOverworld; + private final boolean disableNeutralTeleports; + private final int neutralTeleportRange; + private final boolean unfinishedIslandTeleports; + public HomeCommand() { plugin.getCommand("home").setExecutor(this); plugin.getCommand("homes").setExecutor(this); + + this.allowHomeOnlyFromOverworld = plugin.getConfig().getBoolean("allowHomeOnlyFromOverworld"); + this.disableNeutralTeleports = plugin.getConfig().getBoolean("disableNeutralTeleports"); + this.neutralTeleportRange = plugin.getConfig().getInt("neutralTeleportRange"); + this.unfinishedIslandTeleports = plugin.getConfig().getBoolean("unfinishedIslandTeleports"); } @Override @@ -102,33 +117,34 @@ public boolean onCommand(CommandSender sender, Command command, String label, St } return true; - } else { - if (!player.hasPermission(Permissions.command.home)) { - player.sendMessage(Messages.get("error.NO_PERMISSION")); - return true; - } + } - if (!canTeleport(player) && !player.hasPermission(Permissions.bypass.home)) { - player.sendMessage(Messages.get("error.COOLDOWN", teleportCooldown(player))); - return true; - } + if (!player.hasPermission(Permissions.command.home)) { + player.sendMessage(Messages.get("error.NO_PERMISSION")); + return true; + } - try { - if (args.length != 0) { - Integer.parseInt(args[0]); - } - } catch (NumberFormatException e) { - player.sendMessage(Messages.help.HOME); - return true; + if (!canTeleport(player) && !player.hasPermission(Permissions.bypass.home)) { + player.sendMessage(Messages.get("error.COOLDOWN", teleportCooldown(player))); + return true; + } + + try { + if (args.length != 0) { + Integer.parseInt(args[0]); } + } catch (NumberFormatException e) { + player.sendMessage(Messages.help.HOME); + return true; } - if (player.getWorld().getName().equals("world_nether") && !player.hasPermission(Permissions.bypass.home)) { + if (allowHomeOnlyFromOverworld && !player.getWorld().getEnvironment().equals(World.Environment.NORMAL) + && !player.hasPermission(Permissions.bypass.home)) { player.sendMessage(Messages.get("info.IN_OVERWORLD")); return true; } - if (player.getWorld().getName().equals("world") && !player.hasPermission(Permissions.bypass.home)) { + if (!player.hasPermission(Permissions.bypass.home)) { // Check if is on surface Location playerLocation = player.getLocation(); @@ -149,9 +165,33 @@ public boolean onCommand(CommandSender sender, Command command, String label, St homeId = 1; } - Location location = layout.getIslandSpawn(layout.getHomeIsland(player.getUniqueId(), homeId)); + String islandId = layout.getHomeIsland(player.getUniqueId(), homeId); + + if (plugin.islandGeneration.queue.size() > 0 + && plugin.islandGeneration.queue.get(0).getIslandId().equals(islandId) + && !unfinishedIslandTeleports) { + Messages.send(player, "error.ISLAND_UNFINISHED"); + return true; + } + + if (plugin.islandGeneration.queue.size() != 0) + System.out.println("IslanId " + islandId + " and " + plugin.islandGeneration.queue.get(0).getIslandId()); + + Location location = layout.getIslandSpawn(islandId); if (location != null) { + if (!disableNeutralTeleports && player.hasPermission(Permissions.bypass.neutralTeleport)) { + List entities = player.getNearbyEntities(neutralTeleportRange, neutralTeleportRange, neutralTeleportRange); + entities.removeIf(entity -> entity instanceof Monster || !entity.getType().isAlive()); + + Location animalLocation = location.clone(); + animalLocation.setY(plugin.islandsWorld.getHighestBlockYAt(location) + 1); + + for (Entity entity : entities) { + entity.teleport(animalLocation); + } + } + player.teleport(location); } else { player.sendMessage(Messages.get("error.HOME_NOT_FOUND")); diff --git a/src/me/aleksilassila/islands/commands/subcommands/ClearSubcommand.java b/src/me/aleksilassila/islands/commands/subcommands/ClearSubcommand.java index dac9fac..6d7f748 100644 --- a/src/me/aleksilassila/islands/commands/subcommands/ClearSubcommand.java +++ b/src/me/aleksilassila/islands/commands/subcommands/ClearSubcommand.java @@ -43,7 +43,7 @@ public void onCommand(Player player, String[] args, boolean confirmed) { return; } - if (!plugin.islandGeneration.clearIsland(player, Integer.parseInt(islandId.split("x")[0]), Integer.parseInt(islandId.split("x")[1]))) { + if (!plugin.islandGeneration.clearIsland(player, islandId)) { player.sendMessage(Messages.get("error.ONGOING_QUEUE_EVENT")); return; } diff --git a/src/me/aleksilassila/islands/generation/Biomes.java b/src/me/aleksilassila/islands/generation/Biomes.java index d767eb6..16ec4f6 100644 --- a/src/me/aleksilassila/islands/generation/Biomes.java +++ b/src/me/aleksilassila/islands/generation/Biomes.java @@ -23,7 +23,7 @@ public class Biomes { public Biomes(Islands plugin, World world) { this.world = world; - this.biggestIslandSize = plugin.getConfig().getInt("island.BIG"); + this.biggestIslandSize = plugin.getConfig().getInt("generation.maxBiomeSize"); this.plugin = plugin; this.biomeSearchJumpBlocks = plugin.getConfig().getInt("generation.searchJump"); @@ -72,7 +72,7 @@ private void loadBiomesFromConfig() { private void generateAndSaveBiomes() { plugin.clearBiomesCache(); - this.availableLocations = generateIslandLocations(biggestIslandSize); + this.availableLocations = generateIslandLocations(); plugin.getBiomesCache().set("seed", String.valueOf(plugin.islandsSourceWorld.getSeed())); @@ -118,17 +118,17 @@ private boolean isBlacklisted(Biome biome) { } @NotNull - public HashMap> generateIslandLocations(int maxIslandSize) { + public HashMap> generateIslandLocations() { HashMap> locations = new HashMap<>(); List usedPositions = new ArrayList(); plugin.getLogger().info("Generating biomes..."); - for (int x = 0; x < biomeSearchSize - maxIslandSize; x += biomeSearchJumpBlocks) { - zLoop: for (int z = 0; z < biomeSearchSize - maxIslandSize; z += biomeSearchJumpBlocks) { + for (int x = 0; x < biomeSearchSize - biggestIslandSize; x += biomeSearchJumpBlocks) { + zLoop: for (int z = 0; z < biomeSearchSize - biggestIslandSize; z += biomeSearchJumpBlocks) { for (int[] pos : usedPositions) { - if (pos[0] <= x && x <= pos[0] + maxIslandSize && pos[1] <= z && z <= pos[1] + maxIslandSize) { - z += maxIslandSize; + if (pos[0] <= x && x <= pos[0] + biggestIslandSize && pos[1] <= z && z <= pos[1] + biggestIslandSize) { + z += biggestIslandSize; continue zLoop; } } @@ -140,7 +140,7 @@ public HashMap> generateIslandLocations(int maxIslandSize) continue; } - if (isSuitableLocation(x, z, maxIslandSize, biome)) { + if (isSuitableLocation(x, z, biggestIslandSize, biome)) { Location location = new Location(world, x, 0, z); if (locations.containsKey(biome)) { @@ -152,7 +152,7 @@ public HashMap> generateIslandLocations(int maxIslandSize) } usedPositions.add(new int[]{x, z}); - z += maxIslandSize; + z += biggestIslandSize; } } diff --git a/src/me/aleksilassila/islands/generation/IslandGeneration.java b/src/me/aleksilassila/islands/generation/IslandGeneration.java index 7a2e419..88f1cb4 100644 --- a/src/me/aleksilassila/islands/generation/IslandGeneration.java +++ b/src/me/aleksilassila/islands/generation/IslandGeneration.java @@ -72,7 +72,7 @@ public IslandGeneration(Islands plugin) { } } - public boolean copyIsland(Player player, Biome biome, int islandSize, Vector target, boolean shouldClearArea, int xIndex, int zIndex, Shape shape) throws IllegalArgumentException { + public boolean copyIsland(Player player, Biome biome, int islandSize, Vector target, boolean shouldClearArea, String islandId, Shape shape) throws IllegalArgumentException { List locations = biomes.availableLocations.get(biome); if (locations == null) @@ -105,7 +105,7 @@ public boolean copyIsland(Player player, Biome biome, int islandSize, Vector tar int startY = centerY - islandSize / 2; int startZ = sourceLocation.getBlockZ(); - CopyTask task = new CopyTask(player, new Vector(startX, startY, startZ), target, islandSize, shouldClearArea, xIndex, zIndex, shape); + CopyTask task = new CopyTask(player, new Vector(startX, startY, startZ), target, islandSize, shouldClearArea, islandId, shape); if (queue.size() == 0) { task.runTaskTimer(plugin, 0, buildDelay); @@ -116,11 +116,11 @@ public boolean copyIsland(Player player, Biome biome, int islandSize, Vector tar return true; } - public boolean clearIsland(Player player, int xIndex, int zIndex) { + public boolean clearIsland(Player player, String islandId) { if (!canAddQueueItem(player)) return false; - ClearTask task = new ClearTask(player, xIndex, zIndex); + ClearTask task = new ClearTask(player, islandId); if (queue.size() == 0) { task.runTaskTimer(plugin, 0, buildDelay); @@ -169,14 +169,14 @@ public void removeFromQueue(Player player) { } public int getBypassIndex(Player player) { - if (queue.size() == 1) return 1; + if (queue.size() < 2) return queue.size(); else { for (int index = 1; index < queue.size(); index++) { if (!queue.get(index).getPlayer().getUniqueId().equals(player.getUniqueId())) return index; } - return Math.max(queue.size(), 0); + return queue.size(); } } @@ -188,8 +188,9 @@ private boolean queueContainsPlayer(Player player) { return false; } - abstract static class Task extends BukkitRunnable { + public abstract static class Task extends BukkitRunnable { public abstract Player getPlayer(); + public abstract String getIslandId(); @Override public synchronized BukkitTask runTaskTimer(Plugin plugin, long delay, long period) throws IllegalArgumentException, IllegalStateException { @@ -200,16 +201,18 @@ public synchronized BukkitTask runTaskTimer(Plugin plugin, long delay, long peri } class ClearTask extends Task { - private Player player; - private int xIndex; - private int zIndex; + private final Player player; + private final int xIndex; + private final int zIndex; + private final String islandId; private int index = 0; - public ClearTask(Player player, int xIndex, int zIndex) { + public ClearTask(Player player, String islandId) { this.player = player; - this.xIndex = xIndex; - this.zIndex = zIndex; + this.xIndex = Integer.parseInt(islandId.split("x")[0]); + this.zIndex = Integer.parseInt(islandId.split("x")[1]); + this.islandId = islandId; } @@ -218,6 +221,11 @@ public Player getPlayer() { return player; } + @Override + public String getIslandId() { + return islandId; + } + @Override public void run() { for (int count = 0; count < rowsClearedPerDelay; count++) { @@ -291,9 +299,11 @@ class CopyTask extends Task { private final int xIndex; private final int zIndex; + private final String islandId; + private final Shape shape; - public CopyTask(Player player, Vector start, Vector target, int islandSize, boolean shouldDoClearing, int xIndex, int zIndex, Shape shape) { + public CopyTask(Player player, Vector start, Vector target, int islandSize, boolean shouldDoClearing, String islandId, Shape shape) { this.startX = start.getBlockX(); this.startY = shape != null ? start.getBlockY() - (shape.getHeight() - islandSize / 2) : start.getBlockY(); @@ -310,8 +320,10 @@ public CopyTask(Player player, Vector start, Vector target, int islandSize, bool this.shouldDoClearing = shouldDoClearing; this.clearingIndex = 0; - this.xIndex = xIndex; - this.zIndex = zIndex; + this.xIndex = Integer.parseInt(islandId.split("x")[0]); + this.zIndex = Integer.parseInt(islandId.split("x")[1]); + + this.islandId = islandId; this.shape = shape; @@ -323,6 +335,11 @@ public Player getPlayer() { return player; } + @Override + public String getIslandId() { + return islandId; + } + @Override public void run() { if (shouldDoClearing) { diff --git a/src/me/aleksilassila/islands/utils/Permissions.java b/src/me/aleksilassila/islands/utils/Permissions.java index f6a24e9..486572a 100644 --- a/src/me/aleksilassila/islands/utils/Permissions.java +++ b/src/me/aleksilassila/islands/utils/Permissions.java @@ -20,6 +20,7 @@ public static class bypass { public static final String queue = "islands.bypass.queue"; public static final String queueLimit = "islands.bypass.queue.limit"; public static final String info = "islands.bypass.info"; + public static final String neutralTeleport = "islands.bypass.neutralTeleport"; } public static class command { diff --git a/src/messages.properties b/src/messages.properties index 602addc..76fec91 100644 --- a/src/messages.properties +++ b/src/messages.properties @@ -23,6 +23,7 @@ error.ERROR=\u00a77[\u00a74\u00a7lError\u00a77] \u00a7cAn internal error occurre error.COOLDOWN=\u00a77[\u00a74\u00a7lError\u00a77] \u00a7cYou took damage recently. You have to wait for {0}s before teleporting. error.ISLAND_SAVE_ERROR=\u00a77[\u00a74\u00a7lError\u00a77] \u00a7cCould not save {0}.schem. error.INSUFFICIENT_FUNDS=\u00a77[\u00a74\u00a7lError\u00a77] \u00a7cInsufficient funds. +error.ISLAND_UNFINISHED=\u00a77[\u00a74\u00a7lError\u00a77] \u00a7cIsland is still being generated. error.PRIVATE_ISLAND=info.CLEAR_CONFIRM success.DELETED=\u00a77[\u00a72\u00a7lIslands\u00a77] \u00a7aIsland deleted successfully. It will be overwritten when someone creates a new island. @@ -80,7 +81,7 @@ gui.visit.SORT=\u00a76\u00a7lSort by {0, choice, 0#date|1#name} gui.create.TITLE=Create Island gui.create.BIOME_NAME=\u00a76\u00a7l{0} -gui.create.BIOME_LORE=\u00a77Click for available sizes +gui.create.BIOME_LORE=\u00a77Click for available sizes\n\u00a77{0} variations available gui.create.SIZE_TITLE=Choose island size gui.create.SIZE_NAME=\u00a76\u00a7l{0} gui.create.SIZE_LORE=\u00a77Buy price: \u00a7a${1,number,#} \n\u00a77Size: {0}x{0}\n\n\u00a77Click to purchase diff --git a/src/messages_en.properties b/src/messages_en.properties index 602addc..76fec91 100644 --- a/src/messages_en.properties +++ b/src/messages_en.properties @@ -23,6 +23,7 @@ error.ERROR=\u00a77[\u00a74\u00a7lError\u00a77] \u00a7cAn internal error occurre error.COOLDOWN=\u00a77[\u00a74\u00a7lError\u00a77] \u00a7cYou took damage recently. You have to wait for {0}s before teleporting. error.ISLAND_SAVE_ERROR=\u00a77[\u00a74\u00a7lError\u00a77] \u00a7cCould not save {0}.schem. error.INSUFFICIENT_FUNDS=\u00a77[\u00a74\u00a7lError\u00a77] \u00a7cInsufficient funds. +error.ISLAND_UNFINISHED=\u00a77[\u00a74\u00a7lError\u00a77] \u00a7cIsland is still being generated. error.PRIVATE_ISLAND=info.CLEAR_CONFIRM success.DELETED=\u00a77[\u00a72\u00a7lIslands\u00a77] \u00a7aIsland deleted successfully. It will be overwritten when someone creates a new island. @@ -80,7 +81,7 @@ gui.visit.SORT=\u00a76\u00a7lSort by {0, choice, 0#date|1#name} gui.create.TITLE=Create Island gui.create.BIOME_NAME=\u00a76\u00a7l{0} -gui.create.BIOME_LORE=\u00a77Click for available sizes +gui.create.BIOME_LORE=\u00a77Click for available sizes\n\u00a77{0} variations available gui.create.SIZE_TITLE=Choose island size gui.create.SIZE_NAME=\u00a76\u00a7l{0} gui.create.SIZE_LORE=\u00a77Buy price: \u00a7a${1,number,#} \n\u00a77Size: {0}x{0}\n\n\u00a77Click to purchase diff --git a/src/plugin.yml b/src/plugin.yml index 940a095..3f44535 100644 --- a/src/plugin.yml +++ b/src/plugin.yml @@ -1,5 +1,5 @@ name: Islands -version: 4.6.0 +version: 4.6.1 author: Aleksi Lassila main: me.aleksilassila.islands.Islands api-version: 1.15 @@ -58,6 +58,7 @@ permissions: islands.bypass.*: description: Access to all island bypasses children: + islands.bypass.neutralTeleport: true islands.bypass.islandLimit: true islands.bypass.recreate: true islands.bypass.clear: true @@ -147,6 +148,9 @@ permissions: description: Access to island setspawn command default: "op" + islands.bypass.neutralTeleport: + description: Allow players to teleport neutrals in their islands + default: true islands.bypass.islandLimit: description: Bypass island limit restrictions default: "op"