From 56546dbe2d95dda06a85e23b10f8d8c6bf4e7112 Mon Sep 17 00:00:00 2001 From: Tofpu Date: Wed, 23 Aug 2023 20:43:53 +0300 Subject: [PATCH] 1.0.12 Bugfixes (#33) * Fix randomjoin not being random * Fix lobby world not loading non-default worlds This commit will address the issue sending a player to a world that was not loaded/created before. * Append -bugfixes suffix to version * Fix empty messages being shown * Replace outdated links with new ones * Add commit patch to version * Fix improper island positioning Due to island position being inaccurate, it caused some islands to clash together. This commit solves #31 issue. * Add debug commands for islands --- build.gradle.kts | 20 ++++- speedbridge2-spigot-plugin/build.gradle.kts | 2 +- .../io/tofpu/speedbridge2/SpeedBridge.java | 13 ++- .../speedbridge2/command/CommandManager.java | 14 ++- .../subcommand/HelpCommandGenerator.java | 4 +- .../subcommand/SpeedBridgeCommand.java | 24 +++-- .../subcommand/debug/DestroyableLand.java | 67 ++++++++++++++ .../subcommand/debug/EmptyBridgePlayer.java | 11 +++ .../command/subcommand/debug/GameIsland2.java | 22 +++++ .../debug/SpeedBridgeDebugCommand.java | 84 +++++++++++++++++ .../general/PlayerConnectionListener.java | 2 +- .../config/serializer/LocationSerializer.java | 28 +++++- .../model/common/util/BridgeUtil.java | 17 ++++ .../model/island/arena/ArenaManager.java | 89 ++++++++++++++++++- .../model/island/object/GameIsland.java | 3 +- .../model/island/object/land/IslandLand.java | 8 +- .../object/umbrella/GameIslandUmbrella.java | 4 +- .../src/main/resources/plugin.yml | 1 - 18 files changed, 386 insertions(+), 27 deletions(-) create mode 100644 speedbridge2-spigot-plugin/src/main/java/io/tofpu/speedbridge2/command/subcommand/debug/DestroyableLand.java create mode 100644 speedbridge2-spigot-plugin/src/main/java/io/tofpu/speedbridge2/command/subcommand/debug/EmptyBridgePlayer.java create mode 100644 speedbridge2-spigot-plugin/src/main/java/io/tofpu/speedbridge2/command/subcommand/debug/GameIsland2.java create mode 100644 speedbridge2-spigot-plugin/src/main/java/io/tofpu/speedbridge2/command/subcommand/debug/SpeedBridgeDebugCommand.java diff --git a/build.gradle.kts b/build.gradle.kts index f616d0a5..5124c46a 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -12,7 +12,7 @@ allprojects { } group = "io.tofpu.speedbridge2" - version = "1.1.0" + version = "1.1.0-" + "git rev-parse --short=8 HEAD".runCommand(rootDir) repositories { mavenLocal() @@ -72,3 +72,21 @@ allprojects { } } } + +fun String.runCommand( + workingDir: File = File("."), + timeoutAmount: Long = 60, + timeoutUnit: TimeUnit = TimeUnit.SECONDS +): String = ProcessBuilder(split("\\s(?=(?:[^'\"`]*(['\"`])[^'\"`]*\\1)*[^'\"`]*$)".toRegex())) + .directory(workingDir) + .redirectOutput(ProcessBuilder.Redirect.PIPE) + .redirectError(ProcessBuilder.Redirect.PIPE) + .start() + .apply { waitFor(timeoutAmount, timeoutUnit) } + .run { + val error = errorStream.bufferedReader().readText().trim() + if (error.isNotEmpty()) { + throw Exception(error) + } + inputStream.bufferedReader().readText().trim() + } diff --git a/speedbridge2-spigot-plugin/build.gradle.kts b/speedbridge2-spigot-plugin/build.gradle.kts index 2997045b..7f6bb267 100644 --- a/speedbridge2-spigot-plugin/build.gradle.kts +++ b/speedbridge2-spigot-plugin/build.gradle.kts @@ -1,5 +1,5 @@ plugins { - id("xyz.jpenilla.run-paper") version "1.0.6" + id("xyz.jpenilla.run-paper") version "2.0.1" } dependencies { diff --git a/speedbridge2-spigot-plugin/src/main/java/io/tofpu/speedbridge2/SpeedBridge.java b/speedbridge2-spigot-plugin/src/main/java/io/tofpu/speedbridge2/SpeedBridge.java index da96111c..8c2a6f0f 100644 --- a/speedbridge2-spigot-plugin/src/main/java/io/tofpu/speedbridge2/SpeedBridge.java +++ b/speedbridge2-spigot-plugin/src/main/java/io/tofpu/speedbridge2/SpeedBridge.java @@ -30,6 +30,8 @@ import org.bukkit.plugin.java.JavaPlugin; import java.io.IOException; +import java.lang.reflect.Field; +import java.util.Map; public final class SpeedBridge { private static BukkitAudiences adventure; @@ -71,13 +73,18 @@ public void enable() { arenaManager, leaderboard); DynamicClass.alternativeScan(getClass().getClassLoader(), "io.tofpu" + ".speedbridge2"); - } catch (final IOException | NoClassDefFoundError e) { + + Field objectMap = DynamicClass.class.getDeclaredField("OBJECT_MAP"); + objectMap.setAccessible(true); + Map, Object> o = (Map, Object>) objectMap.get(null); + BridgeUtil.debug("key set of dynamic class: " + o.keySet()); + } catch (final IOException | NoClassDefFoundError | NoSuchFieldException | IllegalAccessException e) { throw new IllegalStateException(e); } if (Bukkit.getPluginManager().isPluginEnabled("PlaceholderAPI")) { ExpansionHandler.INSTANCE.load(); - + log("Hooking into PlaceholderAPI..."); new PluginExpansion(javaPlugin, playerService); } @@ -88,7 +95,7 @@ public void enable() { IslandSetupHandler.INSTANCE.load(); log("Registering the commands..."); - CommandManager.load(javaPlugin, playerService, islandService); + CommandManager.load(javaPlugin, playerService, islandService, arenaManager); log("Loading the Block Menu GUI."); BlockMenuManager.INSTANCE.load(); diff --git a/speedbridge2-spigot-plugin/src/main/java/io/tofpu/speedbridge2/command/CommandManager.java b/speedbridge2-spigot-plugin/src/main/java/io/tofpu/speedbridge2/command/CommandManager.java index 688c844a..cd4f24a0 100644 --- a/speedbridge2-spigot-plugin/src/main/java/io/tofpu/speedbridge2/command/CommandManager.java +++ b/speedbridge2-spigot-plugin/src/main/java/io/tofpu/speedbridge2/command/CommandManager.java @@ -9,8 +9,10 @@ import io.tofpu.speedbridge2.command.parser.LampParseRegistry; import io.tofpu.speedbridge2.command.subcommand.CommandCompletion; import io.tofpu.speedbridge2.command.subcommand.SpeedBridgeCommand; +import io.tofpu.speedbridge2.command.subcommand.debug.SpeedBridgeDebugCommand; import io.tofpu.speedbridge2.model.common.util.BridgeUtil; import io.tofpu.speedbridge2.model.island.IslandService; +import io.tofpu.speedbridge2.model.island.arena.ArenaManager; import io.tofpu.speedbridge2.model.island.object.Island; import io.tofpu.speedbridge2.model.player.PlayerFactory; import io.tofpu.speedbridge2.model.player.PlayerService; @@ -31,8 +33,8 @@ public final class CommandManager { private static BukkitCommandHandler commandHandler; public static void load(final @NotNull Plugin plugin, - final @NotNull PlayerService playerService, - final @NotNull IslandService islandService) { + final @NotNull PlayerService playerService, + final @NotNull IslandService islandService, ArenaManager arenaManager) { commandHandler = BukkitCommandHandler.create(plugin); commandHandler.registerResponseHandler(String.class, (response, actor, command) -> { @@ -83,6 +85,7 @@ public boolean isCustomType(final Class type) { constructCommandConditions(); commandHandler.register(new SpeedBridgeCommand(playerService, islandService)); + commandHandler.register(new SpeedBridgeDebugCommand(arenaManager)); } private static void constructTabCompleter(final @NotNull IslandService islandService) { @@ -96,8 +99,10 @@ private static void constructTabCompleter(final @NotNull IslandService islandSer private static void constructContext() { final AbstractLampRegistry> registry = DynamicClass.getInstance(LampContextRegistry.class); + if (registry == null) { - return; + BridgeUtil.debug("Unable to find LampContextRegistry instance... shutting down!"); + throw new RuntimeException("Unable to find LampContextRegistry instance... shutting down now!"); } BridgeUtil.debug("Constructing contexts..."); @@ -113,7 +118,8 @@ private static void constructContext() { private static void constructParsers() { final AbstractLampRegistry> lampParseRegistry = DynamicClass.getInstance(LampParseRegistry.class); if (lampParseRegistry == null) { - return; + BridgeUtil.debug("Unable to find LampParseRegistry instance... shutting down!"); + throw new RuntimeException("Unable to find LampParseRegistry instance... shutting down now!"); } BridgeUtil.debug("Constructing parsers..."); diff --git a/speedbridge2-spigot-plugin/src/main/java/io/tofpu/speedbridge2/command/subcommand/HelpCommandGenerator.java b/speedbridge2-spigot-plugin/src/main/java/io/tofpu/speedbridge2/command/subcommand/HelpCommandGenerator.java index cdfe48ad..c55fbb5e 100644 --- a/speedbridge2-spigot-plugin/src/main/java/io/tofpu/speedbridge2/command/subcommand/HelpCommandGenerator.java +++ b/speedbridge2-spigot-plugin/src/main/java/io/tofpu/speedbridge2/command/subcommand/HelpCommandGenerator.java @@ -24,6 +24,7 @@ public final class HelpCommandGenerator { private static final String KEY_STYLE = "%s"; private static final String VALUE_STYLE = "%s"; private static final String COMMAND_STYLE = "/sb %s %s- %s"; + private static final String DISCORD_LINK = "https://discord.gg/cDQjsHugPw"; private static Component helpMessageComponent = null; @@ -65,8 +66,7 @@ public static void generateHelpCommand(final @NotNull Plugin plugin) { builder.title(String.format(TITLE, "Support")) .pair(String.format(KEY_STYLE, "Discord"), String.format(VALUE_STYLE, - "tofpu" + - ".me/discord")); + "" + DISCORD_LINK)); return builder.build(); }); diff --git a/speedbridge2-spigot-plugin/src/main/java/io/tofpu/speedbridge2/command/subcommand/SpeedBridgeCommand.java b/speedbridge2-spigot-plugin/src/main/java/io/tofpu/speedbridge2/command/subcommand/SpeedBridgeCommand.java index c8671b9b..65772d70 100644 --- a/speedbridge2-spigot-plugin/src/main/java/io/tofpu/speedbridge2/command/subcommand/SpeedBridgeCommand.java +++ b/speedbridge2-spigot-plugin/src/main/java/io/tofpu/speedbridge2/command/subcommand/SpeedBridgeCommand.java @@ -25,6 +25,7 @@ import org.bukkit.Location; import org.bukkit.command.CommandSender; import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; import revxrsal.commands.annotation.AutoComplete; import revxrsal.commands.annotation.Command; import revxrsal.commands.annotation.Default; @@ -39,7 +40,9 @@ import java.util.Optional; import java.util.UUID; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ThreadLocalRandom; import java.util.function.Consumer; +import java.util.stream.Collectors; import static io.tofpu.speedbridge2.model.common.Message.INSTANCE; import static io.tofpu.speedbridge2.model.common.util.MessageUtil.Symbols.ARROW_RIGHT; @@ -77,9 +80,7 @@ public void onLobbySet(final BridgePlayer bridgePlayer) { ConfigurationManager.INSTANCE.getLobbyCategory() .setLobbyLocation(bridgePlayer.getPlayer() .getLocation()) - .whenComplete((unused, throwable) -> { - BridgeUtil.sendMessage(bridgePlayer, INSTANCE.lobbySetLocation); - }); + .thenRun(() -> BridgeUtil.sendMessage(bridgePlayer, INSTANCE.lobbySetLocation)); } @Subcommand("create") @@ -346,11 +347,7 @@ public String onRandomJoin(final BridgePlayer bridgePlayer) { return INSTANCE.alreadyInAIsland; } - final Optional optionalIsland = islandService.getAllIslands() - .stream() - .parallel() - .filter(Island::isReady) - .findAny(); + final Optional optionalIsland = getRandomIsland(); if (!optionalIsland.isPresent()) { return INSTANCE.noAvailableIsland; @@ -362,6 +359,17 @@ public String onRandomJoin(final BridgePlayer bridgePlayer) { return String.format(INSTANCE.joinedAnIsland, island.getSlot() + ""); } + @NotNull + private Optional getRandomIsland() { + final List filteredIslands = islandService.getAllIslands() + .stream() + .parallel() + .filter(Island::isReady) + .collect(Collectors.toList()); + + return Optional.ofNullable(filteredIslands.get(ThreadLocalRandom.current().nextInt(filteredIslands.size()))); + } + @Subcommand("setup") @Description("Create an island setup") @CommandPermission("speedbridge.setup.admin") diff --git a/speedbridge2-spigot-plugin/src/main/java/io/tofpu/speedbridge2/command/subcommand/debug/DestroyableLand.java b/speedbridge2-spigot-plugin/src/main/java/io/tofpu/speedbridge2/command/subcommand/debug/DestroyableLand.java new file mode 100644 index 00000000..79437af0 --- /dev/null +++ b/speedbridge2-spigot-plugin/src/main/java/io/tofpu/speedbridge2/command/subcommand/debug/DestroyableLand.java @@ -0,0 +1,67 @@ +package io.tofpu.speedbridge2.command.subcommand.debug; + +import com.sk89q.worldedit.EditSession; +import com.sk89q.worldedit.MaxChangedBlocksException; +import com.sk89q.worldedit.WorldEditException; +import com.sk89q.worldedit.bukkit.BukkitWorld; +import com.sk89q.worldedit.extent.clipboard.Clipboard; +import com.sk89q.worldedit.function.operation.ForwardExtentCopy; +import com.sk89q.worldedit.function.operation.Operation; +import com.sk89q.worldedit.function.operation.Operations; +import io.tofpu.multiworldedit.EditSessionWrapper; +import io.tofpu.multiworldedit.MultiWorldEditAPI; +import io.tofpu.speedbridge2.model.common.util.BridgeUtil; +import io.tofpu.speedbridge2.model.island.object.land.IslandLand; + +import java.io.IOException; + +public class DestroyableLand extends IslandLand { + private EditSession editSession; + + public DestroyableLand(IslandLand islandLand) { + super(islandLand.getIsland(), islandLand.getWorld(), islandLand.getPositions()); + } + + @Override + public void generatePlot() throws WorldEditException { + // TODO: Make this generation operation async + BridgeUtil.debug("Generating plot at " + getPlotLocation().toString() + " for " + + "island " + getIsland().getSlot()); + + final BukkitWorld bukkitWorld = new BukkitWorld(getWorld()); + + try (final EditSessionWrapper editSessionWrapper = MultiWorldEditAPI.getMultiWorldEdit() + .create(bukkitWorld, -1)) { + final Clipboard schematicClipboard = getIsland().getSchematicClipboard(); + this.editSession = editSessionWrapper.to(); + + final Operation operation = MultiWorldEditAPI.getMultiWorldEdit() + .create(schematicClipboard, editSession, bukkitWorld) + .to((int) getX(), (int) getY(), (int) getZ()) + .ignoreAirBlocks(true) + .build(); + + Operations.completeLegacy(operation); + } catch (IOException e) { + throw new IllegalStateException(e); + } + } + + public void destroy() { + // TODO: Make this generation operation async + BridgeUtil.debug("Generating plot at " + getPlotLocation().toString() + " for " + + "island " + getIsland().getSlot()); + + final BukkitWorld bukkitWorld = new BukkitWorld(getWorld()); + + try (final EditSessionWrapper editSessionWrapper = MultiWorldEditAPI.getMultiWorldEdit() + .create(bukkitWorld, -1)) { + EditSession session = editSessionWrapper.to(); + this.editSession.undo(session); +// session.undo(this.editSession); + } catch (IOException e) { + throw new IllegalStateException(e); + } + this.free(); + } +} diff --git a/speedbridge2-spigot-plugin/src/main/java/io/tofpu/speedbridge2/command/subcommand/debug/EmptyBridgePlayer.java b/speedbridge2-spigot-plugin/src/main/java/io/tofpu/speedbridge2/command/subcommand/debug/EmptyBridgePlayer.java new file mode 100644 index 00000000..7449e1d9 --- /dev/null +++ b/speedbridge2-spigot-plugin/src/main/java/io/tofpu/speedbridge2/command/subcommand/debug/EmptyBridgePlayer.java @@ -0,0 +1,11 @@ +package io.tofpu.speedbridge2.command.subcommand.debug; + +import io.tofpu.speedbridge2.model.player.object.BridgePlayer; + +import java.util.UUID; + +public class EmptyBridgePlayer extends BridgePlayer { + protected EmptyBridgePlayer(UUID id) { + super(null, null, id); + } +} diff --git a/speedbridge2-spigot-plugin/src/main/java/io/tofpu/speedbridge2/command/subcommand/debug/GameIsland2.java b/speedbridge2-spigot-plugin/src/main/java/io/tofpu/speedbridge2/command/subcommand/debug/GameIsland2.java new file mode 100644 index 00000000..9c88ca4f --- /dev/null +++ b/speedbridge2-spigot-plugin/src/main/java/io/tofpu/speedbridge2/command/subcommand/debug/GameIsland2.java @@ -0,0 +1,22 @@ +package io.tofpu.speedbridge2.command.subcommand.debug; + +import io.tofpu.speedbridge2.model.island.arena.ArenaManager; +import io.tofpu.speedbridge2.model.island.object.GameIsland; +import io.tofpu.speedbridge2.model.island.object.land.IslandLand; + +public class GameIsland2 extends GameIsland { + private IslandLand islandLand; + + public GameIsland2(final ArenaManager arenaManager, GameIsland gameIsland) { + super(arenaManager, gameIsland.getIsland(), gameIsland.getGamePlayer()); + } + + public void setIslandPlot(final IslandLand islandLand) { + this.islandLand = islandLand; + } + + @Override + public IslandLand getIslandPlot() { + return this.islandLand; + } +} diff --git a/speedbridge2-spigot-plugin/src/main/java/io/tofpu/speedbridge2/command/subcommand/debug/SpeedBridgeDebugCommand.java b/speedbridge2-spigot-plugin/src/main/java/io/tofpu/speedbridge2/command/subcommand/debug/SpeedBridgeDebugCommand.java new file mode 100644 index 00000000..3c0e128e --- /dev/null +++ b/speedbridge2-spigot-plugin/src/main/java/io/tofpu/speedbridge2/command/subcommand/debug/SpeedBridgeDebugCommand.java @@ -0,0 +1,84 @@ +package io.tofpu.speedbridge2.command.subcommand.debug; + +import com.sk89q.worldedit.WorldEditException; +import io.tofpu.speedbridge2.model.island.IslandFactory; +import io.tofpu.speedbridge2.model.island.arena.ArenaManager; +import io.tofpu.speedbridge2.model.island.object.GameIsland; +import io.tofpu.speedbridge2.model.island.object.Island; +import io.tofpu.speedbridge2.model.island.object.land.IslandLand; +import io.tofpu.speedbridge2.model.player.object.GamePlayer; +import org.bukkit.Location; +import org.bukkit.entity.Player; +import revxrsal.commands.annotation.Command; +import revxrsal.commands.annotation.Default; +import revxrsal.commands.annotation.Subcommand; +import revxrsal.commands.annotation.Usage; +import revxrsal.commands.bukkit.annotation.CommandPermission; + +import java.util.*; + +@Command("speedbridge debug") +@CommandPermission("speedbridge.debug") +public class SpeedBridgeDebugCommand { + private final Map> generatedGames = new HashMap<>(); + private final ArenaManager arenaManager; + + public SpeedBridgeDebugCommand(ArenaManager arenaManager) { + this.arenaManager = arenaManager; + } + + @Subcommand("arena teleport") + public String islandTeleport(final Player player) { + double[] positions = arenaManager.getPositions(); + player.teleport(new Location(this.arenaManager.getWorld(), positions[0], positions[1], positions[2])); + return String.format("Teleported you to world %s with %s coordinates", arenaManager.getWorld().getName(), positions); + } + + @Subcommand("island generate") + @Usage("island generate [amount]") + public String generateGame(final Island island, final @Default("1") int amount) { + for (int i = 0; i < amount; i++) { + generateGame(island); + } + return String.format("Generated %s games of island type %s", amount, island.getSlot()); + } + + @Subcommand("island destroy") + @Usage("island destroy") + public String islandClear(final Island island) { + int gameAmountDestroyed = destroyGames(island); + int islandType = island.getSlot(); + return String.format("Destroyed %s games of island type %s!", gameAmountDestroyed, islandType); + } + + private int destroyGames(final Island island) { + List games = this.generatedGames.get(island); + games.forEach(game -> { + DestroyableLand islandPlot = (DestroyableLand) game.getIslandPlot(); + islandPlot.destroy(); + }); + return games.size(); + } + + public void generateGame(final Island island) { + final GamePlayer gamePlayer = GamePlayer.of(new EmptyBridgePlayer(UUID.randomUUID())); + final GameIsland2 gameIsland = new GameIsland2(arenaManager, IslandFactory.createGame(island, gamePlayer)); + + DestroyableLand islandLand = new DestroyableLand(arenaManager.justReservePlot(gameIsland)); + try { + islandLand.generatePlot(); + } catch (WorldEditException e) { + throw new RuntimeException(e); + } + + gameIsland.setIslandPlot(islandLand); + + this.generatedGames.compute(island, (island1, gameIslands) -> { + if (gameIslands == null) { + gameIslands = new ArrayList<>(); + } + gameIslands.add(gameIsland); + return gameIslands; + }); + } +} diff --git a/speedbridge2-spigot-plugin/src/main/java/io/tofpu/speedbridge2/listener/general/PlayerConnectionListener.java b/speedbridge2-spigot-plugin/src/main/java/io/tofpu/speedbridge2/listener/general/PlayerConnectionListener.java index cf957053..e70dbba8 100644 --- a/speedbridge2-spigot-plugin/src/main/java/io/tofpu/speedbridge2/listener/general/PlayerConnectionListener.java +++ b/speedbridge2-spigot-plugin/src/main/java/io/tofpu/speedbridge2/listener/general/PlayerConnectionListener.java @@ -66,4 +66,4 @@ private void onPlayerQuit(final @NotNull PlayerQuitEvent event) { playerService.invalidate(player); } -} +} \ No newline at end of file diff --git a/speedbridge2-spigot-plugin/src/main/java/io/tofpu/speedbridge2/model/common/config/serializer/LocationSerializer.java b/speedbridge2-spigot-plugin/src/main/java/io/tofpu/speedbridge2/model/common/config/serializer/LocationSerializer.java index d87bef7c..85e00985 100644 --- a/speedbridge2-spigot-plugin/src/main/java/io/tofpu/speedbridge2/model/common/config/serializer/LocationSerializer.java +++ b/speedbridge2-spigot-plugin/src/main/java/io/tofpu/speedbridge2/model/common/config/serializer/LocationSerializer.java @@ -1,8 +1,10 @@ package io.tofpu.speedbridge2.model.common.config.serializer; +import io.tofpu.speedbridge2.model.common.util.BridgeUtil; import org.bukkit.Bukkit; import org.bukkit.Location; import org.bukkit.World; +import org.bukkit.WorldCreator; import org.checkerframework.checker.nullness.qual.Nullable; import org.spongepowered.configurate.ConfigurationNode; import org.spongepowered.configurate.serialize.SerializationException; @@ -19,11 +21,22 @@ private LocationSerializer() {} @Override public Location deserialize(final Type type, final ConfigurationNode node) throws SerializationException { final String worldName = nonVirtualNode(node, "world").getString(); - final World world = Bukkit.getWorld(worldName); + + // if the world name is nonexistent, return the default + // location if (worldName == null) { return defaultLocation(); } + final World world = getWorld(worldName); + + + // if the world was not loaded before, or it was deleted + // then we will create/load it manually +// if (world == null) { +// world = Bukkit.createWorld(WorldCreator.name(worldName)); +// } + final double x = nonVirtualNode(node, "x").getDouble(); final double y = nonVirtualNode(node, "y").getDouble(); final double z = nonVirtualNode(node, "z").getDouble(); @@ -33,6 +46,19 @@ public Location deserialize(final Type type, final ConfigurationNode node) throw return new Location(world, x, y, z, yaw, pitch); } + private World getWorld(final String worldName) { + // attempts to get a world that are already loaded + World world = Bukkit.getWorld(worldName); + if (world != null) { + return world; + } + + // loads/creates a world with the given worldName + // and notifies the administrators of the given action + BridgeUtil.log("Loading " + worldName + " world for the speedbridge2 lobby!"); + return Bukkit.createWorld(WorldCreator.name(worldName)); + } + private ConfigurationNode nonVirtualNode(final ConfigurationNode source, final Object... path) throws SerializationException { if (!source.hasChild(path)) { throw new SerializationException("Required field " + Arrays.toString(path) + diff --git a/speedbridge2-spigot-plugin/src/main/java/io/tofpu/speedbridge2/model/common/util/BridgeUtil.java b/speedbridge2-spigot-plugin/src/main/java/io/tofpu/speedbridge2/model/common/util/BridgeUtil.java index 85fe50d2..02dc9787 100644 --- a/speedbridge2-spigot-plugin/src/main/java/io/tofpu/speedbridge2/model/common/util/BridgeUtil.java +++ b/speedbridge2-spigot-plugin/src/main/java/io/tofpu/speedbridge2/model/common/util/BridgeUtil.java @@ -27,6 +27,17 @@ * This class is a utility class that provides utility methods for the SpeedBridge plugin */ public final class BridgeUtil { + /** + * A function used to log info-related messages to Bukkit's logger. + * This function also does add this plugin's name as a prefix + * to differentiate the message from one plugin to another + * + * @param content the content that will be printed + */ + public static void log(final String content) { + Bukkit.getLogger().info("[Speedbridge2] " + content); + } + /** * Convert nanoseconds to seconds * @@ -92,6 +103,9 @@ public static Component sendMessage(final CommandSender sender, */ public static Component sendMessage(final CommonBridgePlayer sender, final String content) { + if (content.isEmpty()) { + return null; + } final Component component = translateMiniMessage(content); sendMessage(sender.getPlayer(), component); return component; @@ -107,6 +121,9 @@ public static Component sendMessage(final CommonBridgePlayer sender, */ public static Component sendMessage(final CommandSender sender, final String content) { + if (content.isEmpty()) { + return null; + } final Component component = translateMiniMessage(content); sendMessage(sender, component); return component; diff --git a/speedbridge2-spigot-plugin/src/main/java/io/tofpu/speedbridge2/model/island/arena/ArenaManager.java b/speedbridge2-spigot-plugin/src/main/java/io/tofpu/speedbridge2/model/island/arena/ArenaManager.java index 8aec18e9..7013355f 100644 --- a/speedbridge2-spigot-plugin/src/main/java/io/tofpu/speedbridge2/model/island/arena/ArenaManager.java +++ b/speedbridge2-spigot-plugin/src/main/java/io/tofpu/speedbridge2/model/island/arena/ArenaManager.java @@ -6,6 +6,7 @@ import io.tofpu.speedbridge2.model.island.object.Island; import io.tofpu.speedbridge2.model.island.object.GameIsland; import io.tofpu.speedbridge2.model.island.object.land.IslandLand; +import io.tofpu.speedbridge2.model.support.worldedit.Vector; import org.apache.commons.io.FileUtils; import org.bukkit.Bukkit; import org.bukkit.Location; @@ -49,6 +50,10 @@ private void protectWorld(final @NotNull World world) { world.setGameRuleValue("doDaylightCycle", "false"); } + public @NotNull IslandLand justReservePlot(final GameIsland gameIsland) { + return justGetPlot(gameIsland.getIsland(), gameIsland); + } + public @Nullable IslandLand reservePlot(final GameIsland gameIsland) { if (world == null) { Bukkit.getLogger() @@ -62,6 +67,25 @@ private void protectWorld(final @NotNull World world) { return getPlot(island, gameIsland); } + private IslandLand justGetPlot(final Island island, final GameIsland gameIsland) { + final int islandSlot = island.getSlot(); + + // retrieving a collection of plots that is associated with the given island slot + final Collection islandLands = retrieve(islandSlot); + + // attempt to get an available plot with the given island slot + IslandLand islandLand = getAvailablePlot(islandLands, islandSlot); + + // if we found an available plot, start reserving the plot + if (islandLand != null) { + islandLand.reserveWith(gameIsland); + } else { + // otherwise, create our own island plot + islandLand = createIslandPlotWithNoGeneration(islandLands, island, gameIsland); + } + return islandLand; + } + private IslandLand getPlot(final Island island, final GameIsland gameIsland) { final int islandSlot = island.getSlot(); @@ -95,15 +119,65 @@ private IslandLand getAvailablePlot(final Collection islandLands, return null; } +// private IslandLand getNewPlot(final Island target) { +// return getNewPlot(target, getPositions()); +// } + + private IslandLand getNewPlot(final Island target, double[] positions) { + return new IslandLand(target, world, positions); + } + + private IslandLand createIslandPlotWithNoGeneration(final Collection islandLandList + , final Island target, final GameIsland gameIsland) { + BridgeUtil.debug("SchematicManager#createIslandPlot: Creating a new island plot for " + target.getSlot() + " slot!"); + + final double[] positions = getPositions(); + + positions[0] += Math.abs(positions[0] - new IslandLand(target, world, positions).region().getMinimumPoint().getX()); + + BridgeUtil.debug("=== island " + target.getSlot() + " ==="); + BridgeUtil.debug("Placing schematic at: " + Arrays.toString(positions)); + + final IslandLand islandLand = getNewPlot(target, positions); + BridgeUtil.debug("Island width is: " + islandLand.getWidth()); + + COUNTER.getAndAdd(islandLand.getWidth() + ConfigurationManager.INSTANCE.getGeneralCategory().getIslandSpaceGap()); + + BridgeUtil.debug("minimumPoint=" + serializeVector(islandLand.region().getMinimumPoint())); + BridgeUtil.debug("maximumPoint=" + serializeVector(islandLand.region().getMaximumPoint())); + BridgeUtil.debug("=========="); + + // reserving the plot to player + islandLand.reserveWith(gameIsland); + + // adding the plot for usability + islandLandList.add(islandLand); + + // adding the new island plot to the schematic plot map + ISLAND_PLOTS.put(target.getSlot(), islandLandList); + return islandLand; + } + private IslandLand createIslandPlot(final Collection islandLandList , final Island target, final GameIsland gameIsland) { BridgeUtil.debug("SchematicManager#createIslandPlot: Creating a new island plot for " + target.getSlot() + " slot!"); - final double[] positions = {COUNTER.get(), 100, 100}; + final double[] positions = getPositions(); + + positions[0] += Math.abs(positions[0] - new IslandLand(target, world, positions).region().getMinimumPoint().getX()); + + BridgeUtil.debug("=== island " + target.getSlot() + " ==="); + BridgeUtil.debug("Placing schematic at: " + Arrays.toString(positions)); + + final IslandLand islandLand = getNewPlot(target, positions); + BridgeUtil.debug("Island width is: " + islandLand.getWidth()); - final IslandLand islandLand = new IslandLand(target, world, positions); COUNTER.getAndAdd(islandLand.getWidth() + ConfigurationManager.INSTANCE.getGeneralCategory().getIslandSpaceGap()); + BridgeUtil.debug("minimumPoint=" + serializeVector(islandLand.region().getMinimumPoint())); + BridgeUtil.debug("maximumPoint=" + serializeVector(islandLand.region().getMaximumPoint())); + BridgeUtil.debug("=========="); + // reserving the plot to player islandLand.reserveWith(gameIsland); try { @@ -121,6 +195,15 @@ private IslandLand createIslandPlot(final Collection islandLandList return islandLand; } + public double[] getPositions() { + return new double[]{COUNTER.get(), 100, 100}; + } + + @NotNull + private static String serializeVector(Vector vector) { + return String.format("%s, %s, %s", vector.getX(), vector.getY(), vector.getZ()); + } + public void resetWorld() { final File worldFile = getWorldDirectory(); if (worldFile != null && worldFile.exists()) { @@ -177,6 +260,8 @@ public World getWorld() { return this.world; } + + private static final class EmptyChunkGenerator extends ChunkGenerator { @Override public @NotNull ChunkData generateChunkData(final World world, final Random random, final int x, final int z, final BiomeGrid biome) { diff --git a/speedbridge2-spigot-plugin/src/main/java/io/tofpu/speedbridge2/model/island/object/GameIsland.java b/speedbridge2-spigot-plugin/src/main/java/io/tofpu/speedbridge2/model/island/object/GameIsland.java index e0a0ac4d..0aa88406 100644 --- a/speedbridge2-spigot-plugin/src/main/java/io/tofpu/speedbridge2/model/island/object/GameIsland.java +++ b/speedbridge2-spigot-plugin/src/main/java/io/tofpu/speedbridge2/model/island/object/GameIsland.java @@ -16,7 +16,7 @@ import org.bukkit.entity.Player; import org.bukkit.inventory.ItemStack; -public final class GameIsland { +public class GameIsland { private final ArenaManager arenaManager; private final Umbrella umbrella; private final Island island; @@ -27,6 +27,7 @@ public final class GameIsland { public GameIsland(final ArenaManager arenaManager, final Island island, final GamePlayer gamePlayer) { this.arenaManager = arenaManager; + // todo: memory leak, as this does not get invalidated once done this.umbrella = new GameIslandUmbrella(this).getUmbrella(); this.island = island; this.gamePlayer = gamePlayer; diff --git a/speedbridge2-spigot-plugin/src/main/java/io/tofpu/speedbridge2/model/island/object/land/IslandLand.java b/speedbridge2-spigot-plugin/src/main/java/io/tofpu/speedbridge2/model/island/object/land/IslandLand.java index e2c4c79b..221de308 100644 --- a/speedbridge2-spigot-plugin/src/main/java/io/tofpu/speedbridge2/model/island/object/land/IslandLand.java +++ b/speedbridge2-spigot-plugin/src/main/java/io/tofpu/speedbridge2/model/island/object/land/IslandLand.java @@ -22,10 +22,11 @@ import java.io.IOException; -public final class IslandLand { +public class IslandLand { private final Island island; private final World world; + private final double[] positions; private final double x; private final double y; private final double z; @@ -42,6 +43,7 @@ public final class IslandLand { public IslandLand(final Island island, final World world, double[] positions) { this.island = island; this.world = world; + this.positions = positions; this.x = positions[0]; this.y = positions[1]; this.z = positions[2]; @@ -204,6 +206,10 @@ public int hashCode() { .toHashCode(); } + public double[] getPositions() { + return this.positions; + } + private static class LandState { private GameIsland gameIsland; diff --git a/speedbridge2-spigot-plugin/src/main/java/io/tofpu/speedbridge2/model/island/object/umbrella/GameIslandUmbrella.java b/speedbridge2-spigot-plugin/src/main/java/io/tofpu/speedbridge2/model/island/object/umbrella/GameIslandUmbrella.java index 62866893..9ac5c7dc 100644 --- a/speedbridge2-spigot-plugin/src/main/java/io/tofpu/speedbridge2/model/island/object/umbrella/GameIslandUmbrella.java +++ b/speedbridge2-spigot-plugin/src/main/java/io/tofpu/speedbridge2/model/island/object/umbrella/GameIslandUmbrella.java @@ -7,6 +7,8 @@ import io.tofpu.umbrella.UmbrellaAPI; import io.tofpu.umbrella.domain.Umbrella; +import java.util.UUID; + public final class GameIslandUmbrella { private final Umbrella umbrella; @@ -14,7 +16,7 @@ public GameIslandUmbrella(final GameIsland gameIsland) { this.umbrella = UmbrellaAPI.getInstance() .getUmbrellaService() .getUmbrellaFactory() - .create("island"); + .create(UUID.randomUUID().toString()); for (final SerializableUmbrellaItem serializableUmbrellaItem : ConfigurationManager .INSTANCE.getGameCategory().getUmbrellaItems()) { diff --git a/speedbridge2-spigot-plugin/src/main/resources/plugin.yml b/speedbridge2-spigot-plugin/src/main/resources/plugin.yml index 4a937c55..35106099 100644 --- a/speedbridge2-spigot-plugin/src/main/resources/plugin.yml +++ b/speedbridge2-spigot-plugin/src/main/resources/plugin.yml @@ -2,7 +2,6 @@ name: SpeedBridge2 version: ${version} main: io.tofpu.speedbridge2.plugin.SpeedBridgePlugin authors: [ Tofpu ] -website: https://tofpu.me api-version: 1.13 depend: - WorldEdit