From 328b8d670f621c7a09b20e2def75704dd0745ff8 Mon Sep 17 00:00:00 2001 From: stijnb1234 Date: Mon, 1 Jun 2020 13:43:13 +0200 Subject: [PATCH] Fixed a lot of issues, removed sbutil, ... --- pom.xml | 48 ++-- ...hemepark-1.3.2.jar => themepark-1.4.4.jar} | Bin 69906 -> 71329 bytes .../themeparkplus/api/PlusAPI.java | 31 --- .../themeparkplus/ThemeParkPlus.java | 100 +++++---- .../themeparkplus/api/PlusAPI.java | 94 ++++++++ .../api/enums/WalkingDirection.java | 0 .../themeparkplus/api/objects/Gate.java | 0 .../api/objects/MalfunctionReport.java | 1 + .../themeparkplus/api/objects/WaitingRow.java | 6 +- .../themeparkplus/commands/TPPCMD.java | 45 ++++ .../listeners/AntiFreerunListener.java | 3 + .../listeners/DirectionalGateListener.java | 7 +- .../listeners/FastpassListeners.java | 60 +---- .../listeners/SignListeners.java | 69 ++++++ .../listeners/StatusChangeListener.java | 6 +- .../themeparkplus/managers/DBManager.java | 4 +- .../sbutils/LocationSerializer.java | 81 +++++++ .../themeparkplus/sbutils/SQLiteDB.java | 90 ++++++++ .../themeparkplus/sbutils/UpdateManager.java | 205 ++++++++++++++++++ .../themeparkplus/sbutils/YamlFile.java | 71 ++++++ .../themeparkplus/util/ConfigUtil.java | 0 .../themeparkplus/util/Cuboid.java | 0 .../themeparkplus/util/DirectionUtil.java | 0 .../themeparkplus/util/LGUtil.java | 0 .../themeparkplus/util/License.java | 0 .../themeparkplus/util/WEUtil.java | 52 +++++ .../themeparkplus/util/XMaterial.java | 0 src/main/resources/config.yml | 8 + src/main/resources/messages.yml | 9 +- 29 files changed, 841 insertions(+), 149 deletions(-) rename src/lib/{themepark-1.3.2.jar => themepark-1.4.4.jar} (53%) delete mode 100644 src/main/java/nl/sbdeveloper/themeparkplus/api/PlusAPI.java rename src/main/{java => lombok}/nl/sbdeveloper/themeparkplus/ThemeParkPlus.java (58%) create mode 100644 src/main/lombok/nl/sbdeveloper/themeparkplus/api/PlusAPI.java rename src/main/{java => lombok}/nl/sbdeveloper/themeparkplus/api/enums/WalkingDirection.java (100%) rename src/main/{java => lombok}/nl/sbdeveloper/themeparkplus/api/objects/Gate.java (100%) rename src/main/{java => lombok}/nl/sbdeveloper/themeparkplus/api/objects/MalfunctionReport.java (87%) rename src/main/{java => lombok}/nl/sbdeveloper/themeparkplus/api/objects/WaitingRow.java (81%) rename src/main/{java => lombok}/nl/sbdeveloper/themeparkplus/commands/TPPCMD.java (89%) rename src/main/{java => lombok}/nl/sbdeveloper/themeparkplus/listeners/AntiFreerunListener.java (95%) rename src/main/{java => lombok}/nl/sbdeveloper/themeparkplus/listeners/DirectionalGateListener.java (94%) rename src/main/{java => lombok}/nl/sbdeveloper/themeparkplus/listeners/FastpassListeners.java (71%) create mode 100644 src/main/lombok/nl/sbdeveloper/themeparkplus/listeners/SignListeners.java rename src/main/{java => lombok}/nl/sbdeveloper/themeparkplus/listeners/StatusChangeListener.java (92%) rename src/main/{java => lombok}/nl/sbdeveloper/themeparkplus/managers/DBManager.java (95%) create mode 100644 src/main/lombok/nl/sbdeveloper/themeparkplus/sbutils/LocationSerializer.java create mode 100644 src/main/lombok/nl/sbdeveloper/themeparkplus/sbutils/SQLiteDB.java create mode 100644 src/main/lombok/nl/sbdeveloper/themeparkplus/sbutils/UpdateManager.java create mode 100644 src/main/lombok/nl/sbdeveloper/themeparkplus/sbutils/YamlFile.java rename src/main/{java => lombok}/nl/sbdeveloper/themeparkplus/util/ConfigUtil.java (100%) rename src/main/{java => lombok}/nl/sbdeveloper/themeparkplus/util/Cuboid.java (100%) rename src/main/{java => lombok}/nl/sbdeveloper/themeparkplus/util/DirectionUtil.java (100%) rename src/main/{java => lombok}/nl/sbdeveloper/themeparkplus/util/LGUtil.java (100%) rename src/main/{java => lombok}/nl/sbdeveloper/themeparkplus/util/License.java (100%) create mode 100644 src/main/lombok/nl/sbdeveloper/themeparkplus/util/WEUtil.java rename src/main/{java => lombok}/nl/sbdeveloper/themeparkplus/util/XMaterial.java (100%) diff --git a/pom.xml b/pom.xml index f36ccd4..401313a 100644 --- a/pom.xml +++ b/pom.xml @@ -52,6 +52,33 @@ + + + org.projectlombok + lombok-maven-plugin + 1.18.12.0 + + + generate-sources + + delombok + + + + + + + maven-javadoc-plugin + 3.2.0 + + 8 + + nl/sbdeveloper/themeparkplus/api/*.java + nl/sbdeveloper/themeparkplus/api/enums/*.java + nl/sbdeveloper/themeparkplus/api/objects/*.java + + + @@ -66,10 +93,6 @@ spigot-repo https://hub.spigotmc.org/nexus/content/repositories/snapshots/ - - iobyte-repo - https://nexus.iobyte.nl/repository/maven-public/ - codemc-repo https://repo.codemc.org/repository/maven-public/ @@ -100,23 +123,17 @@ 1.15.2-R0.1-SNAPSHOT provided - - nl.SBDevelopment - SBUtilities - 1.4 - compile - me.paradoxpixel themepark - 1.3.2 + 1.4.4 system - ${pom.basedir}/src/lib/themepark-1.3.2.jar + ${pom.basedir}/src/lib/themepark-1.4.4.jar com.sk89q.worldedit worldedit-bukkit - 6.1.4-SNAPSHOT + 7.1.0 provided @@ -141,5 +158,10 @@ discord-webhooks 0.3.0 + + com.zaxxer + HikariCP + 3.4.2 + diff --git a/src/lib/themepark-1.3.2.jar b/src/lib/themepark-1.4.4.jar similarity index 53% rename from src/lib/themepark-1.3.2.jar rename to src/lib/themepark-1.4.4.jar index 652c353f400933ff03a158141e7e4f4a98d30bcf..dcc345c50a61185344b689b9d76129fe2d4f5c53 100644 GIT binary patch delta 27559 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 W&`&IA91K|~S*T{nST%X~!1{mo_-+;e delta 26148 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 R0BYDTB^d(3^6BlT{{ULUW@7*V diff --git a/src/main/java/nl/sbdeveloper/themeparkplus/api/PlusAPI.java b/src/main/java/nl/sbdeveloper/themeparkplus/api/PlusAPI.java deleted file mode 100644 index 1f1b74d..0000000 --- a/src/main/java/nl/sbdeveloper/themeparkplus/api/PlusAPI.java +++ /dev/null @@ -1,31 +0,0 @@ -package nl.sbdeveloper.themeparkplus.api; - -import nl.sbdeveloper.themeparkplus.api.objects.Gate; -import org.bukkit.Location; -import org.jetbrains.annotations.NotNull; - -import java.util.HashMap; - -public class PlusAPI { - private static HashMap gates = new HashMap<>(); - - public static void addGate(Gate gate) { - gates.put(gate.getLoc(), gate); - } - - public static void removeGate(@NotNull Gate gate) { - gates.remove(gate.getLoc()); - } - - public static boolean isGate(Location loc) { - return gates.containsKey(loc); - } - - public static Gate getGate(Location loc) { - return gates.get(loc); - } - - public static HashMap getGates() { - return gates; - } -} diff --git a/src/main/java/nl/sbdeveloper/themeparkplus/ThemeParkPlus.java b/src/main/lombok/nl/sbdeveloper/themeparkplus/ThemeParkPlus.java similarity index 58% rename from src/main/java/nl/sbdeveloper/themeparkplus/ThemeParkPlus.java rename to src/main/lombok/nl/sbdeveloper/themeparkplus/ThemeParkPlus.java index 360e8f2..0fe4120 100644 --- a/src/main/java/nl/sbdeveloper/themeparkplus/ThemeParkPlus.java +++ b/src/main/lombok/nl/sbdeveloper/themeparkplus/ThemeParkPlus.java @@ -3,20 +3,17 @@ package nl.sbdeveloper.themeparkplus; import club.minnced.discord.webhook.WebhookClient; import club.minnced.discord.webhook.WebhookClientBuilder; import net.milkbowl.vault.economy.Economy; -import nl.SBDevelopment.SBUtilities.Data.YamlFile; -import nl.SBDevelopment.SBUtilities.Logger.Logger; -import nl.SBDevelopment.SBUtilities.PrivateManagers.UpdateManager; -import nl.SBDevelopment.SBUtilities.SBUtilities; import nl.sbdeveloper.themeparkplus.commands.TPPCMD; import nl.sbdeveloper.themeparkplus.listeners.AntiFreerunListener; import nl.sbdeveloper.themeparkplus.listeners.DirectionalGateListener; import nl.sbdeveloper.themeparkplus.listeners.FastpassListeners; import nl.sbdeveloper.themeparkplus.listeners.StatusChangeListener; import nl.sbdeveloper.themeparkplus.managers.DBManager; +import nl.sbdeveloper.themeparkplus.sbutils.UpdateManager; import nl.sbdeveloper.themeparkplus.util.LGUtil; import nl.sbdeveloper.themeparkplus.util.License; +import nl.sbdeveloper.themeparkplus.sbutils.YamlFile; import org.bukkit.Bukkit; -import org.bukkit.ChatColor; import org.bukkit.configuration.file.YamlConfiguration; import org.bukkit.plugin.RegisteredServiceProvider; import org.bukkit.plugin.java.JavaPlugin; @@ -40,21 +37,19 @@ public final class ThemeParkPlus extends JavaPlugin { private static Economy econ = null; private static WebhookClient webhookClient; - private int configVersion = 1; + private int configVersion = 2; @Override public void onEnable() { instance = this; - new SBUtilities(this, "ThemeParkPlus"); + Bukkit.getLogger().info("[ThemeParkPlus] -------------------------------"); + Bukkit.getLogger().info("[ThemeParkPlus] ThemeParkPlus v" + this.getDescription().getVersion()); + Bukkit.getLogger().info("[ThemeParkPlus] Made by SBDeveloper"); - Logger.logInfo("-------------------------------", true); - Logger.logInfo("ThemeParkPlus v" + this.getDescription().getVersion(), true); - Logger.logInfo("Made by SBDeveloper", true); + Bukkit.getLogger().info("[ThemeParkPlus] "); - Logger.logInfo(" ", true); - - Logger.logInfo("Loading Files...", true); + Bukkit.getLogger().info("[ThemeParkPlus] Loading Files..."); config = new YamlFile("config"); config.loadDefaults(); @@ -76,53 +71,70 @@ public final class ThemeParkPlus extends JavaPlugin { } if (!Objects.equals(config.getFile().getString("Version"), String.valueOf(configVersion))) { - Logger.logInfo("Updating outdated config...", true); + Bukkit.getLogger().info("[ThemeParkPlus] Updating outdated config..."); updateConfig(); } - Logger.logInfo("Checking license...", true); + Bukkit.getLogger().info("[ThemeParkPlus] Checking license..."); if (config.getFile().contains("License")) { - Logger.logInfo("Licence code: " + config.getFile().getString("License"), true); + Bukkit.getLogger().info("[ThemeParkPlus] Licence code: " + config.getFile().getString("License")); } else { - Logger.logError("Licence code unknown! Please change the config.yml!", true); + Bukkit.getLogger().severe("[ThemeParkPlus] Licence code unknown! Please change the config.yml!"); return; } new License(this, "TP", config.getFile().getString("License")); - new UpdateManager(this, 6, UpdateManager.CheckType.SBDPLUGINS).handleResponse((versionResponse, version) -> { - if (versionResponse == UpdateManager.VersionResponse.FOUND_NEW) { - Logger.logWarning("There is a new version available! Curent: " + this.getDescription().getVersion() + " New: " + version, true); - } else if (versionResponse == UpdateManager.VersionResponse.LATEST) { - Logger.logInfo("You are running the latest version [" + this.getDescription().getVersion() + "]!", true); - } else if (versionResponse == UpdateManager.VersionResponse.UNAVAILABLE) { - Logger.logError("Unable to perform an update check.", true); - } - }).check(); + if (getSConfig().getFile().getBoolean("UpdateChecker.Enabled")) { + UpdateManager updateManager = new UpdateManager(this, 7, UpdateManager.CheckType.SBDPLUGINS); - if (Bukkit.getPluginManager().getPlugin("ThemePark") == null) { - Logger.logError("Missing ThemePark! Please install it first.", true); + updateManager.handleResponse((versionResponse, version) -> { + if (versionResponse == UpdateManager.VersionResponse.FOUND_NEW) { + Bukkit.getLogger().warning("[ThemeParkPlus] There is a new version available! Curent: " + this.getDescription().getVersion() + " New: " + version); + if (getSConfig().getFile().getBoolean("UpdateChecker.Download")) { + Bukkit.getLogger().info("[ThemeParkPlus] Trying to download the update..."); + + updateManager.handleDownloadResponse((downloadResponse, fileName) -> { + if (downloadResponse == UpdateManager.DownloadResponse.DONE) { + Bukkit.getLogger().info("[ThemeParkPlus] Update downloaded! If you restart your server, it will be loaded. Filename: " + fileName); + } else if (downloadResponse == UpdateManager.DownloadResponse.ERROR) { + Bukkit.getLogger().severe("[ThemeParkPlus] Something went wrong when trying downloading the latest version."); + } else if (downloadResponse == UpdateManager.DownloadResponse.UNAVAILABLE) { + Bukkit.getLogger().warning("[ThemeParkPlus] Unable to download the latest version. The paid plugins will support this feature soon."); + } + }).runUpdate(); + } + } else if (versionResponse == UpdateManager.VersionResponse.LATEST) { + Bukkit.getLogger().info("[ThemeParkPlus] You are running the latest version [" + this.getDescription().getVersion() + "]!"); + } else if (versionResponse == UpdateManager.VersionResponse.UNAVAILABLE) { + Bukkit.getLogger().severe("[ThemeParkPlus] Unable to perform an update check."); + } + }).check(); + } + + if (Bukkit.getPluginManager().isPluginEnabled("ThemePark")) { + Bukkit.getLogger().severe("[ThemeParkPlus] Missing ThemePark! Please install it first."); getServer().getPluginManager().disablePlugin(this); return; } - if (Bukkit.getPluginManager().getPlugin("WorldEdit") == null) { - Logger.logError("Missing WorldEdit! Please install it first.", true); + if (Bukkit.getPluginManager().isPluginEnabled("WorldEdit")) { + Bukkit.getLogger().severe("[ThemeParkPlus] Missing WorldEdit! Please install it first."); getServer().getPluginManager().disablePlugin(this); return; } if (!setupEconomy()) { - Logger.logError("Missing Vault! Please install it first.", true); + Bukkit.getLogger().severe("[ThemeParkPlus] Missing Vault! Please install it first."); getServer().getPluginManager().disablePlugin(this); return; } - Logger.logInfo("Loading commands...", true); + Bukkit.getLogger().info("[ThemeParkPlus] Loading commands..."); Objects.requireNonNull(getCommand("themeparkplus"), "Couldn't read command from plugin.yml!").setExecutor(new TPPCMD()); - Logger.logInfo("Loading listeners...", true); + Bukkit.getLogger().info("[ThemeParkPlus] Loading listeners..."); Bukkit.getPluginManager().registerEvents(new DirectionalGateListener(), this); Bukkit.getPluginManager().registerEvents(new FastpassListeners(), this); if (getSConfig().getFile().getBoolean("AntiFreerun.Enabled")) { @@ -134,7 +146,7 @@ public final class ThemeParkPlus extends JavaPlugin { if (URL != null) { Bukkit.getPluginManager().registerEvents(new StatusChangeListener(), this); - Logger.logInfo("Loading Discord webhook...", true); + Bukkit.getLogger().info("[ThemeParkPlus] Loading Discord webhook..."); WebhookClientBuilder builder = new WebhookClientBuilder(URL); builder.setThreadFactory((job) -> { Thread thread = new Thread(job); @@ -145,40 +157,40 @@ public final class ThemeParkPlus extends JavaPlugin { builder.setWait(true); webhookClient = builder.build(); } else { - Logger.logError("Couldn't load the webhook builder! The URL is null.", true); + Bukkit.getLogger().severe("[ThemeParkPlus] Couldn't load the webhook builder! The URL is null."); } } - Logger.logInfo("Loading Lamp & Gate utils...", true); + Bukkit.getLogger().info("[ThemeParkPlus] Loading Lamp & Gate utils..."); try { new LGUtil(); } catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException | InvocationTargetException e) { e.printStackTrace(); - Logger.logError("Couldn't find classes for Lamp & Gate util. The plugin won't work as intended.", true); + Bukkit.getLogger().severe("[ThemeParkPlus] Couldn't find classes for Lamp & Gate util. The plugin won't work as intended."); } - Logger.logInfo("Loading data...", true); + Bukkit.getLogger().info("[ThemeParkPlus] Loading data..."); try { data.load(); } catch (SQLException e) { e.printStackTrace(); - Logger.logError("Couldn't load data! Something went wrong.", true); + Bukkit.getLogger().severe("[ThemeParkPlus] Couldn't load data! Something went wrong."); } - Logger.logInfo("Plugin enabled!", true); - Logger.logInfo("-------------------------------", true); + Bukkit.getLogger().info("[ThemeParkPlus] Plugin enabled!"); + Bukkit.getLogger().info("[ThemeParkPlus] -------------------------------"); } @Override public void onDisable() { - Logger.logInfo("Saving data to data file...", true); + Bukkit.getLogger().info("[ThemeParkPlus] Saving data to data file..."); data.save(); if (getSConfig().getFile().getBoolean("DiscordWebhook.Enabled")) { - Logger.logInfo("Breaking discord connection...", true); + Bukkit.getLogger().info("[ThemeParkPlus] Breaking discord connection..."); webhookClient.close(); } - Logger.logInfo("Plugin disabled!", true); + Bukkit.getLogger().info("[ThemeParkPlus] Plugin disabled!"); instance = null; } diff --git a/src/main/lombok/nl/sbdeveloper/themeparkplus/api/PlusAPI.java b/src/main/lombok/nl/sbdeveloper/themeparkplus/api/PlusAPI.java new file mode 100644 index 0000000..e7c94f2 --- /dev/null +++ b/src/main/lombok/nl/sbdeveloper/themeparkplus/api/PlusAPI.java @@ -0,0 +1,94 @@ +package nl.sbdeveloper.themeparkplus.api; + +import de.tr7zw.changeme.nbtapi.NBTItem; +import me.paradoxpixel.themepark.api.attraction.Attraction; +import nl.sbdeveloper.themeparkplus.ThemeParkPlus; +import nl.sbdeveloper.themeparkplus.api.objects.Gate; +import nl.sbdeveloper.themeparkplus.util.ConfigUtil; +import nl.sbdeveloper.themeparkplus.util.XMaterial; +import org.bukkit.Location; +import org.bukkit.inventory.ItemStack; +import org.bukkit.inventory.meta.ItemMeta; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.Collections; +import java.util.HashMap; +import java.util.List; + +public class PlusAPI { + private static HashMap gates = new HashMap<>(); + + /** + * Add a gate + * + * @param gate The gate + */ + public static void addGate(Gate gate) { + gates.put(gate.getLoc(), gate); + } + + /** + * Remove a gate + * + * @param gate The gate + */ + public static void removeGate(@NotNull Gate gate) { + gates.remove(gate.getLoc()); + } + + /** + * Check if a location is a gate + * + * @param loc The location + * @return true/false + */ + public static boolean isGate(Location loc) { + return gates.containsKey(loc); + } + + /** + * Get a gate by the location + * + * @param loc The location + * @return The gate + */ + public static Gate getGate(Location loc) { + return gates.get(loc); + } + + /** + * Get all the gates + * + * @return Map with location and gate + */ + public static HashMap getGates() { + return gates; + } + + /** + * Get the ticket itemstack + * + * @param att The attraction + * + * @return The ticket as ItemStack + */ + @Nullable + public static ItemStack getFastpassTicket(Attraction att) { + String ticketName = ConfigUtil.makecolored(ThemeParkPlus.getSConfig().getFile().getString("Fastpass.Item.DisplayName")); + + ItemStack ticket = XMaterial.PAPER.parseItem(); + if (ticket == null) return null; + ItemMeta meta = ticket.getItemMeta(); + if (meta == null) return null; + meta.setDisplayName(ticketName); + List ticketLores = ConfigUtil.getLore("Fastpass.Item.Lore", Collections.singletonMap("%ridename%", att.getName())); + meta.setLore(ticketLores); + ticket.setItemMeta(meta); + + NBTItem item = new NBTItem(ticket); + item.setString("RideID", att.getId()); + ticket = item.getItem(); + return ticket; + } +} diff --git a/src/main/java/nl/sbdeveloper/themeparkplus/api/enums/WalkingDirection.java b/src/main/lombok/nl/sbdeveloper/themeparkplus/api/enums/WalkingDirection.java similarity index 100% rename from src/main/java/nl/sbdeveloper/themeparkplus/api/enums/WalkingDirection.java rename to src/main/lombok/nl/sbdeveloper/themeparkplus/api/enums/WalkingDirection.java diff --git a/src/main/java/nl/sbdeveloper/themeparkplus/api/objects/Gate.java b/src/main/lombok/nl/sbdeveloper/themeparkplus/api/objects/Gate.java similarity index 100% rename from src/main/java/nl/sbdeveloper/themeparkplus/api/objects/Gate.java rename to src/main/lombok/nl/sbdeveloper/themeparkplus/api/objects/Gate.java diff --git a/src/main/java/nl/sbdeveloper/themeparkplus/api/objects/MalfunctionReport.java b/src/main/lombok/nl/sbdeveloper/themeparkplus/api/objects/MalfunctionReport.java similarity index 87% rename from src/main/java/nl/sbdeveloper/themeparkplus/api/objects/MalfunctionReport.java rename to src/main/lombok/nl/sbdeveloper/themeparkplus/api/objects/MalfunctionReport.java index 4cc4fbd..ac67429 100644 --- a/src/main/java/nl/sbdeveloper/themeparkplus/api/objects/MalfunctionReport.java +++ b/src/main/lombok/nl/sbdeveloper/themeparkplus/api/objects/MalfunctionReport.java @@ -8,6 +8,7 @@ import lombok.Setter; import java.time.LocalDateTime; import java.util.UUID; +/** @deprecated Please don't use! It's not implemented yet. */ @Getter @Setter @NoArgsConstructor @AllArgsConstructor public class MalfunctionReport { private String rideID; diff --git a/src/main/java/nl/sbdeveloper/themeparkplus/api/objects/WaitingRow.java b/src/main/lombok/nl/sbdeveloper/themeparkplus/api/objects/WaitingRow.java similarity index 81% rename from src/main/java/nl/sbdeveloper/themeparkplus/api/objects/WaitingRow.java rename to src/main/lombok/nl/sbdeveloper/themeparkplus/api/objects/WaitingRow.java index b67dc17..f1767d2 100644 --- a/src/main/java/nl/sbdeveloper/themeparkplus/api/objects/WaitingRow.java +++ b/src/main/lombok/nl/sbdeveloper/themeparkplus/api/objects/WaitingRow.java @@ -1,6 +1,8 @@ package nl.sbdeveloper.themeparkplus.api.objects; +import com.sk89q.worldedit.bukkit.selections.Polygonal2DSelection; import com.sk89q.worldedit.regions.AbstractRegion; +import com.sk89q.worldedit.regions.Region; import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; @@ -12,12 +14,12 @@ import java.util.ArrayList; @NoArgsConstructor @AllArgsConstructor public class WaitingRow { @Getter @Setter private String rideID; - @Getter @Setter private AbstractRegion region; + @Getter @Setter private Region region; @Getter @Setter private int waitingPlayers = 0; @Getter @Setter private int waitingTimeMinutes = 0; private ArrayList signLocations = new ArrayList<>(); - public WaitingRow(String rideID, AbstractRegion region) { + public WaitingRow(String rideID, Region region) { this.rideID = rideID; this.region = region; } diff --git a/src/main/java/nl/sbdeveloper/themeparkplus/commands/TPPCMD.java b/src/main/lombok/nl/sbdeveloper/themeparkplus/commands/TPPCMD.java similarity index 89% rename from src/main/java/nl/sbdeveloper/themeparkplus/commands/TPPCMD.java rename to src/main/lombok/nl/sbdeveloper/themeparkplus/commands/TPPCMD.java index 8a2162a..53d86ac 100644 --- a/src/main/java/nl/sbdeveloper/themeparkplus/commands/TPPCMD.java +++ b/src/main/lombok/nl/sbdeveloper/themeparkplus/commands/TPPCMD.java @@ -1,5 +1,7 @@ package nl.sbdeveloper.themeparkplus.commands; +import me.paradoxpixel.themepark.api.API; +import me.paradoxpixel.themepark.api.attraction.Attraction; import nl.sbdeveloper.themeparkplus.ThemeParkPlus; import nl.sbdeveloper.themeparkplus.api.PlusAPI; import nl.sbdeveloper.themeparkplus.api.enums.WalkingDirection; @@ -14,6 +16,8 @@ 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.inventory.ItemStack; import org.jetbrains.annotations.NotNull; import java.util.Collections; @@ -136,10 +140,49 @@ public class TPPCMD implements CommandExecutor { return true; } return lampsTurnOffCommand(sender, args); + } else if (args[0].equalsIgnoreCase("givefpticket") && (args.length == 2 || args.length == 3)) { + if (!sender.hasPermission("tpp.givefpticket")) { + sender.sendMessage(ConfigUtil.getMessage("General.NoPermission")); + return true; + } + return giveFPTicketCommand(sender, args); } return helpCommand(sender); } + private boolean giveFPTicketCommand(CommandSender sender, String[] args) { + if (args.length == 2 && !(sender instanceof Player)) { + sender.sendMessage(ConfigUtil.getMessage("General.NoPlayer")); + return true; + } + + if (!API.isAttraction(args[1])) { + sender.sendMessage(ConfigUtil.getMessage("Fastpass.UnknownRide", Collections.singletonMap("%ridename%", args[1]))); + return true; + } + + Attraction att = API.getAttraction(args[1]); + + Player target; + if (args.length == 3) { + target = Bukkit.getPlayer(args[2]); + + if (target == null) { + sender.sendMessage(ConfigUtil.getMessage("Fastpass.UnknownPlayer", Collections.singletonMap("%playername%", args[2]))); + return true; + } + } else { + target = (Player) sender; + } + + ItemStack ticket = PlusAPI.getFastpassTicket(att); + if (ticket == null) return true; + target.getInventory().addItem(ticket); + + sender.sendMessage(ConfigUtil.getMessage("Fastpass.Given")); + return true; + } + private boolean infoCommand(@NotNull CommandSender sender) { sender.sendMessage("§1=================================="); sender.sendMessage("§6ThemeParkPlus plugin made by §aSBDeveloper"); @@ -161,6 +204,8 @@ public class TPPCMD implements CommandExecutor { sender.sendMessage("§6/themeparkplus lampoff §f: Turn a lamp off!"); sender.sendMessage("§6/themeparkplus lampson [Seconds on]§f: Turn multiple lamps on."); sender.sendMessage("§6/themeparkplus lampsoff §f: Turn multiple lamps off."); + sender.sendMessage(" "); + sender.sendMessage("§6/themeparkplus givefpticket [Player]§f: Give yourself or someone else a Fastpass ticket (for free)."); return true; } diff --git a/src/main/java/nl/sbdeveloper/themeparkplus/listeners/AntiFreerunListener.java b/src/main/lombok/nl/sbdeveloper/themeparkplus/listeners/AntiFreerunListener.java similarity index 95% rename from src/main/java/nl/sbdeveloper/themeparkplus/listeners/AntiFreerunListener.java rename to src/main/lombok/nl/sbdeveloper/themeparkplus/listeners/AntiFreerunListener.java index 0c55dff..89d37bf 100644 --- a/src/main/java/nl/sbdeveloper/themeparkplus/listeners/AntiFreerunListener.java +++ b/src/main/lombok/nl/sbdeveloper/themeparkplus/listeners/AntiFreerunListener.java @@ -8,6 +8,9 @@ import org.bukkit.potion.PotionEffect; import org.bukkit.potion.PotionEffectType; import org.jetbrains.annotations.NotNull; +/** + * Anti-Freerun effect + */ public class AntiFreerunListener implements Listener { @EventHandler public void onJoin(@NotNull PlayerJoinEvent e) { diff --git a/src/main/java/nl/sbdeveloper/themeparkplus/listeners/DirectionalGateListener.java b/src/main/lombok/nl/sbdeveloper/themeparkplus/listeners/DirectionalGateListener.java similarity index 94% rename from src/main/java/nl/sbdeveloper/themeparkplus/listeners/DirectionalGateListener.java rename to src/main/lombok/nl/sbdeveloper/themeparkplus/listeners/DirectionalGateListener.java index f78e7d9..119619a 100644 --- a/src/main/java/nl/sbdeveloper/themeparkplus/listeners/DirectionalGateListener.java +++ b/src/main/lombok/nl/sbdeveloper/themeparkplus/listeners/DirectionalGateListener.java @@ -6,16 +6,19 @@ import nl.sbdeveloper.themeparkplus.api.objects.Gate; import nl.sbdeveloper.themeparkplus.util.ConfigUtil; import nl.sbdeveloper.themeparkplus.util.DirectionUtil; import nl.sbdeveloper.themeparkplus.util.LGUtil; -import org.bukkit.ChatColor; import org.bukkit.Location; import org.bukkit.block.Block; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; import org.bukkit.event.player.PlayerMoveEvent; +import org.jetbrains.annotations.NotNull; +/** + * Gate move listeners (directional and count checks) + */ public class DirectionalGateListener implements Listener { @EventHandler - public void onWalkThroughFenceGate(PlayerMoveEvent e) { + public void onWalkThroughFenceGate(@NotNull PlayerMoveEvent e) { if (e.getTo() != null && (e.getFrom().getBlockX() != e.getTo().getBlockX() || e.getFrom().getBlockY() != e.getTo().getBlockY() diff --git a/src/main/java/nl/sbdeveloper/themeparkplus/listeners/FastpassListeners.java b/src/main/lombok/nl/sbdeveloper/themeparkplus/listeners/FastpassListeners.java similarity index 71% rename from src/main/java/nl/sbdeveloper/themeparkplus/listeners/FastpassListeners.java rename to src/main/lombok/nl/sbdeveloper/themeparkplus/listeners/FastpassListeners.java index 92479fc..c9b523d 100644 --- a/src/main/java/nl/sbdeveloper/themeparkplus/listeners/FastpassListeners.java +++ b/src/main/lombok/nl/sbdeveloper/themeparkplus/listeners/FastpassListeners.java @@ -5,6 +5,7 @@ import me.paradoxpixel.themepark.api.API; import me.paradoxpixel.themepark.api.attraction.Attraction; import me.paradoxpixel.themepark.api.attraction.component.Status; import nl.sbdeveloper.themeparkplus.ThemeParkPlus; +import nl.sbdeveloper.themeparkplus.api.PlusAPI; import nl.sbdeveloper.themeparkplus.util.ConfigUtil; import nl.sbdeveloper.themeparkplus.util.LGUtil; import nl.sbdeveloper.themeparkplus.util.XMaterial; @@ -14,64 +15,29 @@ import org.bukkit.Location; import org.bukkit.Material; 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.EquipmentSlot; import org.bukkit.inventory.ItemStack; -import org.bukkit.inventory.meta.ItemMeta; +import org.jetbrains.annotations.NotNull; import java.util.Collections; import java.util.HashMap; -import java.util.List; +/** + * Fastpass machine & scanner signs + */ public class FastpassListeners implements Listener { @EventHandler - public void onCreate(SignChangeEvent e) { - Player p = e.getPlayer(); - String[] lines = e.getLines(); - - //Only check themeparkplus signs! - if (!lines[0].equalsIgnoreCase("[ThemeParkPlus]")) return; - - if (!p.hasPermission("tpp.fastpass.create")) { - p.sendMessage(ConfigUtil.getMessage("General.NoPermission")); - return; - } - - if (!API.isAttraction(e.getLine(2))) { - p.sendMessage(ConfigUtil.getMessage("Fastpass.UnknownRide", Collections.singletonMap("ridename", e.getLine(2)))); - return; - } - - String mLineOne = ConfigUtil.makecolored(ThemeParkPlus.getSConfig().getFile().getString("Fastpass.MachineSign.Row1")); - String mLineTwo = ConfigUtil.makecolored(ThemeParkPlus.getSConfig().getFile().getString("Fastpass.MachineSign.Row2")); - String sLineOne = ConfigUtil.makecolored(ThemeParkPlus.getSConfig().getFile().getString("Fastpass.ScannerSign.Row1")); - String sLineTwo = ConfigUtil.makecolored(ThemeParkPlus.getSConfig().getFile().getString("Fastpass.ScannerSign.Row2")); - - if (lines[1].equalsIgnoreCase("Machine") && !lines[2].isEmpty() && !lines[3].isEmpty()) { - e.setLine(0, mLineOne); - e.setLine(1, mLineTwo); - } else if (lines[1].equalsIgnoreCase("Scanner") && !lines[2].isEmpty() && !lines[3].isEmpty()) { - e.setLine(0, sLineOne); - e.setLine(1, sLineTwo); - } else { - p.sendMessage(ConfigUtil.getMessage("Fastpass.IncorrectSign")); - } - } - - @EventHandler - public void onSignClick(PlayerInteractEvent e) { + public void onSignClick(@NotNull PlayerInteractEvent e) { if (e.getClickedBlock() == null || e.getAction() != Action.RIGHT_CLICK_BLOCK || !(e.getClickedBlock().getState() instanceof Sign) || e.getHand() != EquipmentSlot.HAND) return; String mLineOne = ChatColor.stripColor(ConfigUtil.makecolored(ThemeParkPlus.getSConfig().getFile().getString("Fastpass.MachineSign.Row1"))); String mLineTwo = ChatColor.stripColor(ConfigUtil.makecolored(ThemeParkPlus.getSConfig().getFile().getString("Fastpass.MachineSign.Row2"))); String sLineOne = ChatColor.stripColor(ConfigUtil.makecolored(ThemeParkPlus.getSConfig().getFile().getString("Fastpass.ScannerSign.Row1"))); String sLineTwo = ChatColor.stripColor(ConfigUtil.makecolored(ThemeParkPlus.getSConfig().getFile().getString("Fastpass.ScannerSign.Row2"))); - String ticketName = ConfigUtil.makecolored(ThemeParkPlus.getSConfig().getFile().getString("Fastpass.Item.DisplayName")); Sign sign = (Sign) e.getClickedBlock().getState(); if (!ChatColor.stripColor(sign.getLine(0)).equalsIgnoreCase(mLineOne) && !ChatColor.stripColor(sign.getLine(0)).equalsIgnoreCase(sLineOne)) return; @@ -90,19 +56,9 @@ public class FastpassListeners implements Listener { return; } - ItemStack ticket = XMaterial.PAPER.parseItem(); - if (ticket == null) return; - ItemMeta meta = ticket.getItemMeta(); - if (meta == null) return; - meta.setDisplayName(ticketName); - List ticketLores = ConfigUtil.getLore("Fastpass.Item.Lore", Collections.singletonMap("%ridename%", att.getName())); - meta.setLore(ticketLores); - ticket.setItemMeta(meta); + ItemStack ticket = PlusAPI.getFastpassTicket(att); - NBTItem item = new NBTItem(ticket); - item.setString("RideID", attID); - item.setDouble("Price", price); - ticket = item.getItem(); + if (ticket == null) return; if (ThemeParkPlus.getEconomy().getBalance(e.getPlayer()) < price) { e.getPlayer().sendMessage(ConfigUtil.getMessage("Fastpass.NotEnoughMoney")); diff --git a/src/main/lombok/nl/sbdeveloper/themeparkplus/listeners/SignListeners.java b/src/main/lombok/nl/sbdeveloper/themeparkplus/listeners/SignListeners.java new file mode 100644 index 0000000..19d79e4 --- /dev/null +++ b/src/main/lombok/nl/sbdeveloper/themeparkplus/listeners/SignListeners.java @@ -0,0 +1,69 @@ +package nl.sbdeveloper.themeparkplus.listeners; + +import me.paradoxpixel.themepark.api.API; +import nl.sbdeveloper.themeparkplus.ThemeParkPlus; +import nl.sbdeveloper.themeparkplus.api.objects.WaitingRow; +import nl.sbdeveloper.themeparkplus.util.ConfigUtil; +import org.bukkit.entity.Player; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.block.SignChangeEvent; +import org.jetbrains.annotations.NotNull; + +import java.util.Collections; + +/** + * Sign setup listener + */ +public class SignListeners implements Listener { + /* + [ThemeParkPlus] + XXXX + + XXXX + */ + + @EventHandler + public void onCreate(@NotNull SignChangeEvent e) { + Player p = e.getPlayer(); + String[] lines = e.getLines(); + + //Only check themeparkplus signs! + if (!lines[0].equalsIgnoreCase("[ThemeParkPlus]")) return; + + if (!p.hasPermission("tpp.fastpass.create")) { + p.sendMessage(ConfigUtil.getMessage("General.NoPermission")); + return; + } + + if (!API.isAttraction(e.getLine(2))) { + p.sendMessage(ConfigUtil.getMessage("Fastpass.UnknownRide", Collections.singletonMap("ridename", e.getLine(2)))); + return; + } + + String mLineOne = ConfigUtil.makecolored(ThemeParkPlus.getSConfig().getFile().getString("Fastpass.MachineSign.Row1")); + String mLineTwo = ConfigUtil.makecolored(ThemeParkPlus.getSConfig().getFile().getString("Fastpass.MachineSign.Row2")); + String sLineOne = ConfigUtil.makecolored(ThemeParkPlus.getSConfig().getFile().getString("Fastpass.ScannerSign.Row1")); + String sLineTwo = ConfigUtil.makecolored(ThemeParkPlus.getSConfig().getFile().getString("Fastpass.ScannerSign.Row2")); + String wrLineOne = ConfigUtil.makecolored(ThemeParkPlus.getSConfig().getFile().getString("WaitingRow.Sign.Row1")); + String wrLineTwo = ConfigUtil.makecolored(ThemeParkPlus.getSConfig().getFile().getString("WaitingRow.Sign.Row2")); + + if (lines[1].equalsIgnoreCase("Machine") && !lines[2].isEmpty() && !lines[3].isEmpty()) { + e.setLine(0, mLineOne); + e.setLine(1, mLineTwo); + } else if (lines[1].equalsIgnoreCase("Scanner") && !lines[2].isEmpty() && !lines[3].isEmpty()) { + e.setLine(0, sLineOne); + e.setLine(1, sLineTwo); + } else if (lines[1].equalsIgnoreCase("WaitingRow") && !lines[2].isEmpty() && !lines[3].isEmpty()) { + e.setLine(0, wrLineOne); + e.setLine(1, wrLineTwo); + + //AND SETUP + WaitingRow row = new WaitingRow(); + + p.sendMessage(ConfigUtil.getMessage("WaitingRow.SignCreated")); + } else { + p.sendMessage(ConfigUtil.getMessage("General.IncorrectSign")); + } + } +} diff --git a/src/main/java/nl/sbdeveloper/themeparkplus/listeners/StatusChangeListener.java b/src/main/lombok/nl/sbdeveloper/themeparkplus/listeners/StatusChangeListener.java similarity index 92% rename from src/main/java/nl/sbdeveloper/themeparkplus/listeners/StatusChangeListener.java rename to src/main/lombok/nl/sbdeveloper/themeparkplus/listeners/StatusChangeListener.java index 3e6d758..845d851 100644 --- a/src/main/java/nl/sbdeveloper/themeparkplus/listeners/StatusChangeListener.java +++ b/src/main/lombok/nl/sbdeveloper/themeparkplus/listeners/StatusChangeListener.java @@ -10,10 +10,14 @@ import nl.sbdeveloper.themeparkplus.util.ConfigUtil; import org.bukkit.ChatColor; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; +import org.jetbrains.annotations.NotNull; +/** + * Status change listener for discord webhook + */ public class StatusChangeListener implements Listener { @EventHandler - public void onStatusChange(StatusChangeEvent e) { + public void onStatusChange(@NotNull StatusChangeEvent e) { if (e.getStatusAfter() != Status.GLOBAL) { String title = ThemeParkPlus.getSConfig().getFile().getString("DiscordWebhook.Embed.Title"); if (title == null) return; diff --git a/src/main/java/nl/sbdeveloper/themeparkplus/managers/DBManager.java b/src/main/lombok/nl/sbdeveloper/themeparkplus/managers/DBManager.java similarity index 95% rename from src/main/java/nl/sbdeveloper/themeparkplus/managers/DBManager.java rename to src/main/lombok/nl/sbdeveloper/themeparkplus/managers/DBManager.java index 27a7135..cd0c910 100644 --- a/src/main/java/nl/sbdeveloper/themeparkplus/managers/DBManager.java +++ b/src/main/lombok/nl/sbdeveloper/themeparkplus/managers/DBManager.java @@ -1,10 +1,10 @@ package nl.sbdeveloper.themeparkplus.managers; import com.google.gson.Gson; -import nl.SBDevelopment.SBUtilities.Data.SQLiteDB; -import nl.SBDevelopment.SBUtilities.Utils.LocationSerializer; import nl.sbdeveloper.themeparkplus.api.PlusAPI; import nl.sbdeveloper.themeparkplus.api.objects.Gate; +import nl.sbdeveloper.themeparkplus.sbutils.LocationSerializer; +import nl.sbdeveloper.themeparkplus.sbutils.SQLiteDB; import org.bukkit.Location; import java.sql.Connection; diff --git a/src/main/lombok/nl/sbdeveloper/themeparkplus/sbutils/LocationSerializer.java b/src/main/lombok/nl/sbdeveloper/themeparkplus/sbutils/LocationSerializer.java new file mode 100644 index 0000000..350767b --- /dev/null +++ b/src/main/lombok/nl/sbdeveloper/themeparkplus/sbutils/LocationSerializer.java @@ -0,0 +1,81 @@ +package nl.sbdeveloper.themeparkplus.sbutils; + +import org.bukkit.Bukkit; +import org.bukkit.Location; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +public class LocationSerializer { + + /** + * Deserialize a serialized location, without {@link Location#getYaw()} and {@link Location#getPitch()} + * + * @param string The location string + * + * @return The location or null if error + */ + @Nullable + public static Location deserialize(@Nonnull String string) { + String[] split = string.split("_"); + + if (split.length < 4) return null; + + //world_x_y_z + return new Location( + Bukkit.getWorld(split[0]), + Double.parseDouble(split[1]), + Double.parseDouble(split[2]), + Double.parseDouble(split[3]) + ); + } + + /** + * Deserialize a serialized location, with {@link Location#getYaw()} and {@link Location#getPitch()} + * + * @param string The location string + * + * @return The location or null if error + */ + @Nonnull + public static Location deserializePY(@Nonnull String string) { + String[] split = string.split("_"); + + //world_x_y_z + return new Location( + Bukkit.getWorld(split[0]), + Double.parseDouble(split[1]), + Double.parseDouble(split[2]), + Double.parseDouble(split[3]), + Float.parseFloat(split[4]), + Float.parseFloat(split[5]) + ); + } + + /** + * Serialize a location, without {@link Location#getYaw()} and {@link Location#getPitch()} + * + * @param loc The location + * + * @return The serialized string + */ + @Nullable + public static String serialize(@Nonnull Location loc) { + if (loc.getWorld() == null) return null; + return loc.getWorld().getName() + "_" + loc.getX() + "_" + loc.getY() + "_" + loc.getZ(); + } + + /** + * Serialize a location, with {@link Location#getYaw()} and {@link Location#getPitch()} + * + * @param loc The location + * + * @return The serialized string + */ + @Nullable + public static String serializePY(@Nonnull Location loc) { + if (loc.getWorld() == null) return null; + return loc.getWorld().getName() + "_" + loc.getX() + "_" + loc.getY() + "_" + loc.getZ() + "_" + loc.getYaw() + "_" + loc.getPitch(); + } + +} \ No newline at end of file diff --git a/src/main/lombok/nl/sbdeveloper/themeparkplus/sbutils/SQLiteDB.java b/src/main/lombok/nl/sbdeveloper/themeparkplus/sbutils/SQLiteDB.java new file mode 100644 index 0000000..9fc1473 --- /dev/null +++ b/src/main/lombok/nl/sbdeveloper/themeparkplus/sbutils/SQLiteDB.java @@ -0,0 +1,90 @@ +package nl.sbdeveloper.themeparkplus.sbutils; + +import com.zaxxer.hikari.HikariConfig; +import com.zaxxer.hikari.HikariDataSource; +import nl.sbdeveloper.themeparkplus.ThemeParkPlus; +import org.bukkit.Bukkit; + +import java.io.File; +import java.io.IOException; +import java.sql.Connection; +import java.sql.SQLException; +import java.util.Properties; + +public class SQLiteDB { + + private String dbName; + private HikariDataSource source; + private Connection con; + + /** + * Initialize a new connection + * + * @param dbName The database name + */ + public SQLiteDB(String dbName) { + this.dbName = dbName; + + File dbFile = new File(ThemeParkPlus.getInstance().getDataFolder(), dbName + ".db"); + + if (!dbFile.exists()) { + try { + Bukkit.getLogger().info("[ThemeParkPlus] Generating the " + dbName + ".db!"); + if (!dbFile.createNewFile()) { + Bukkit.getLogger().severe("[ThemeParkPlus] Couldn't generate the " + dbName + ".db!"); + return; + } + } catch (IOException e) { + Bukkit.getLogger().severe("[ThemeParkPlus] Couldn't generate the " + dbName + ".db!"); + return; + } + } + + HikariConfig config = new HikariConfig(); + config.setPoolName("ThemeParkPlus"); + config.setUsername(null); + config.setPassword(null); + config.setDriverClassName("org.sqlite.JDBC"); + config.setConnectionTestQuery("SELECT 1"); + config.setMaximumPoolSize(1); + + Properties prop = new Properties(); + prop.setProperty("date_string_format", "yyyy-MM-dd HH:mm:ss"); + + config.setJdbcUrl("jdbc:sqlite:" + dbFile.getAbsolutePath()); + config.setDataSourceProperties(prop); + this.source = new HikariDataSource(config); + + try { + this.con = this.source.getConnection(); + } catch (SQLException e) { + e.printStackTrace(); + } + } + + /** + * Get the connection, to execute queries + * + * CREATE TABLE -> execute() + * SELECT -> executeQuery() + * UPDATE -> executeUpdate() + * + * @return Connection + */ + public Connection getConnection() { + return this.con; + } + + /** + * Close the connection + */ + public void closeSource() { + Bukkit.getLogger().info("[ThemeParkPlus] Closing the database connection for " + dbName + ".db!"); + try { + this.con.close(); + } catch (SQLException e) { + e.printStackTrace(); + } + this.source.close(); + } +} diff --git a/src/main/lombok/nl/sbdeveloper/themeparkplus/sbutils/UpdateManager.java b/src/main/lombok/nl/sbdeveloper/themeparkplus/sbutils/UpdateManager.java new file mode 100644 index 0000000..f185406 --- /dev/null +++ b/src/main/lombok/nl/sbdeveloper/themeparkplus/sbutils/UpdateManager.java @@ -0,0 +1,205 @@ +package nl.sbdeveloper.themeparkplus.sbutils; + +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import org.bukkit.Bukkit; +import org.bukkit.plugin.Plugin; +import org.bukkit.plugin.java.JavaPlugin; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import javax.net.ssl.HttpsURLConnection; +import java.io.*; +import java.lang.reflect.Method; +import java.net.HttpURLConnection; +import java.net.URL; +import java.nio.channels.Channels; +import java.nio.channels.ReadableByteChannel; +import java.util.function.BiConsumer; + +/** + * Update class for SBDevelopment + * @author Stijn [SBDeveloper] + * @since 05-03-2020 + * @version 1.2 + * + * © Stijn Bannink - All rights reserved. + */ +public class UpdateManager { + + private static final String SPIGOT_API = "https://api.spigotmc.org/legacy/update.php?resource=%d"; + + /* Port 4000 is now legacy, 4443 has a SSL cert */ + /* As of 24-05-2020, using the legacy port because of SSL errors */ + private static final String SBDPLUGINS_API = "http://updates.sbdplugins.nl:4000/api/resources/%d"; + + private static final String RESOURCE_DOWNLOAD = "http://api.spiget.org/v2/resources/%s/download"; + + private Plugin plugin; + private double currentVersion; + private int resourceID; + private CheckType type; + private BiConsumer versionResponse; + private BiConsumer downloadResponse; + + /** + * Construct a new UpdateManager + * + * @param plugin The javaplugin (Main class) + * @param resourceID The resourceID on spigot/sbdplugins + * @param type The check type + */ + public UpdateManager(@NotNull Plugin plugin, int resourceID, CheckType type) { + this.plugin = plugin; + this.currentVersion = Double.parseDouble(plugin.getDescription().getVersion()); + this.resourceID = resourceID; + this.type = type; + } + + /** + * Handle the response given by check(); + * @param versionResponse The response + * @return The updatemanager + */ + public UpdateManager handleResponse(BiConsumer versionResponse) { + this.versionResponse = versionResponse; + return this; + } + + public UpdateManager handleDownloadResponse(BiConsumer downloadResponse) { + this.downloadResponse = downloadResponse; + return this; + } + + /** + * Check for a new version + */ + public void check() { + Bukkit.getScheduler().runTaskAsynchronously(this.plugin, () -> { + try { + BufferedReader in = null; + if (type == CheckType.SPIGOT) { + HttpsURLConnection con = (HttpsURLConnection) new URL(String.format(SPIGOT_API, this.resourceID)).openConnection(); + con.setRequestMethod("GET"); + con.setRequestProperty("User-Agent", "Mozilla/5.0"); + + in = new BufferedReader(new InputStreamReader(con.getInputStream())); + } else if (type == CheckType.SBDPLUGINS) { + HttpURLConnection con = (HttpURLConnection) new URL(String.format(SBDPLUGINS_API, this.resourceID)).openConnection(); + con.setRequestMethod("GET"); + con.setRequestProperty("User-Agent", "Mozilla/5.0"); + + in = new BufferedReader(new InputStreamReader(con.getInputStream())); + } + + if (in == null) return; + + String version = null; + + String inputLine; + StringBuilder response = new StringBuilder(); + while ((inputLine = in.readLine()) != null) { + response.append(inputLine); + } + in.close(); + + JsonParser parser = new JsonParser(); + + if (type == CheckType.SPIGOT) { + JsonArray array = parser.parse(response.toString()).getAsJsonArray(); + + version = array.get(0).getAsJsonObject().get("name").getAsString(); + } else if (type == CheckType.SBDPLUGINS) { + JsonObject object = parser.parse(response.toString()).getAsJsonObject(); + + version = object.get("data").getAsJsonObject().get("version").getAsString(); + } + + if (version == null) return; + + boolean latestVersion = Double.parseDouble(version) >= this.currentVersion; + + double versionDouble = Double.parseDouble(version); + + Bukkit.getScheduler().runTask(this.plugin, () -> this.versionResponse.accept(latestVersion ? VersionResponse.LATEST : VersionResponse.FOUND_NEW, latestVersion ? this.currentVersion : versionDouble)); + } catch (IOException | NullPointerException e) { + e.printStackTrace(); + Bukkit.getScheduler().runTask(this.plugin, () -> this.versionResponse.accept(VersionResponse.UNAVAILABLE, null)); + } + }); + } + + public void runUpdate() { + File pluginFile = getPluginFile();// /plugins/XXX.jar + if (pluginFile == null) { + this.downloadResponse.accept(DownloadResponse.ERROR, null); + return; + } + File updateFolder = Bukkit.getUpdateFolderFile(); + if (!updateFolder.exists()) { + if (!updateFolder.mkdirs()) { + this.downloadResponse.accept(DownloadResponse.ERROR, null); + return; + } + } + final File updateFile = new File(updateFolder, pluginFile.getName()); + + Bukkit.getScheduler().runTaskAsynchronously(this.plugin, () -> { + if (this.type == CheckType.SBDPLUGINS) { + Bukkit.getScheduler().runTask(this.plugin, () -> this.downloadResponse.accept(DownloadResponse.UNAVAILABLE, null)); + return; + } + + ReadableByteChannel channel; + try { + //https://stackoverflow.com/questions/921262/how-to-download-and-save-a-file-from-internet-using-java + HttpURLConnection connection = (HttpURLConnection) new URL(String.format(RESOURCE_DOWNLOAD, this.resourceID)).openConnection(); + connection.setRequestProperty("User-Agent", "Mozilla/5.0"); + if (connection.getResponseCode() != 200) { + throw new RuntimeException("Download returned status #" + connection.getResponseCode()); + } + channel = Channels.newChannel(connection.getInputStream()); + } catch (IOException e) { + Bukkit.getScheduler().runTask(this.plugin, () -> this.downloadResponse.accept(DownloadResponse.ERROR, null)); + return; + } + try { + FileOutputStream output = new FileOutputStream(updateFile); + output.getChannel().transferFrom(channel, 0, Long.MAX_VALUE); + output.flush(); + output.close(); + } catch (IOException e) { + Bukkit.getScheduler().runTask(this.plugin, () -> this.downloadResponse.accept(DownloadResponse.ERROR, null)); + return; + } + + Bukkit.getScheduler().runTask(this.plugin, () -> this.downloadResponse.accept(DownloadResponse.DONE, updateFile.getPath())); + }); + } + + @Nullable + private File getPluginFile() { + if (!(this.plugin instanceof JavaPlugin)) { return null; } + try { + Method method = JavaPlugin.class.getDeclaredMethod("getFile"); + method.setAccessible(true); + return (File) method.invoke(this.plugin); + } catch (ReflectiveOperationException e) { + throw new RuntimeException("Could not get plugin file", e); + } + } + + public enum CheckType { + SPIGOT, SBDPLUGINS + } + + public enum VersionResponse { + LATEST, FOUND_NEW, UNAVAILABLE + } + + public enum DownloadResponse { + DONE, ERROR, UNAVAILABLE + } + +} \ No newline at end of file diff --git a/src/main/lombok/nl/sbdeveloper/themeparkplus/sbutils/YamlFile.java b/src/main/lombok/nl/sbdeveloper/themeparkplus/sbutils/YamlFile.java new file mode 100644 index 0000000..8d72f1e --- /dev/null +++ b/src/main/lombok/nl/sbdeveloper/themeparkplus/sbutils/YamlFile.java @@ -0,0 +1,71 @@ +package nl.sbdeveloper.themeparkplus.sbutils; + +import nl.sbdeveloper.themeparkplus.ThemeParkPlus; +import org.bukkit.Bukkit; +import org.bukkit.configuration.file.FileConfiguration; +import org.bukkit.configuration.file.YamlConfiguration; + +import java.io.File; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.Reader; +import java.nio.charset.StandardCharsets; +import java.util.Objects; + +public class YamlFile { + //SBYamlFile file = new SBYamlFile(this, "data"); + + private FileConfiguration fileConfiguration; + private File file; + private String name; + + public YamlFile(String name) { + this.name = name; + + if (!ThemeParkPlus.getInstance().getDataFolder().exists()) { + if (!ThemeParkPlus.getInstance().getDataFolder().mkdir()) { + Bukkit.getLogger().severe("[ThemeParkPlus] Couldn't generate the pluginfolder!"); + return; + } + } + + this.file = new File(ThemeParkPlus.getInstance().getDataFolder(), name + ".yml"); + if (!this.file.exists()) { + try { + if (!this.file.createNewFile()) { + Bukkit.getLogger().severe("[ThemeParkPlus] Couldn't generate the " + name + ".yml!"); + return; + } + Bukkit.getLogger().info("[ThemeParkPlus] Generating the " + name + ".yml!"); + } catch (IOException e) { + Bukkit.getLogger().severe("[ThemeParkPlus] Couldn't generate the " + name + ".yml!"); + return; + } + } + this.fileConfiguration = YamlConfiguration.loadConfiguration(this.file); + } + + public void loadDefaults() { + Reader defConfigStream1 = new InputStreamReader(Objects.requireNonNull(ThemeParkPlus.getInstance().getResource(name + ".yml"), "Resource is null"), StandardCharsets.UTF_8); + YamlConfiguration defConfig1 = YamlConfiguration.loadConfiguration(defConfigStream1); + getFile().setDefaults(defConfig1); + getFile().options().copyDefaults(true); + saveFile(); + } + + public FileConfiguration getFile() { + return this.fileConfiguration; + } + + public void saveFile() { + try { + this.fileConfiguration.save(this.file); + } catch (IOException e) { + Bukkit.getLogger().severe("[ThemeParkPlus] Couldn't save the " + name + ".yml!"); + } + } + + public void reloadConfig() { + this.fileConfiguration = YamlConfiguration.loadConfiguration(this.file); + } +} diff --git a/src/main/java/nl/sbdeveloper/themeparkplus/util/ConfigUtil.java b/src/main/lombok/nl/sbdeveloper/themeparkplus/util/ConfigUtil.java similarity index 100% rename from src/main/java/nl/sbdeveloper/themeparkplus/util/ConfigUtil.java rename to src/main/lombok/nl/sbdeveloper/themeparkplus/util/ConfigUtil.java diff --git a/src/main/java/nl/sbdeveloper/themeparkplus/util/Cuboid.java b/src/main/lombok/nl/sbdeveloper/themeparkplus/util/Cuboid.java similarity index 100% rename from src/main/java/nl/sbdeveloper/themeparkplus/util/Cuboid.java rename to src/main/lombok/nl/sbdeveloper/themeparkplus/util/Cuboid.java diff --git a/src/main/java/nl/sbdeveloper/themeparkplus/util/DirectionUtil.java b/src/main/lombok/nl/sbdeveloper/themeparkplus/util/DirectionUtil.java similarity index 100% rename from src/main/java/nl/sbdeveloper/themeparkplus/util/DirectionUtil.java rename to src/main/lombok/nl/sbdeveloper/themeparkplus/util/DirectionUtil.java diff --git a/src/main/java/nl/sbdeveloper/themeparkplus/util/LGUtil.java b/src/main/lombok/nl/sbdeveloper/themeparkplus/util/LGUtil.java similarity index 100% rename from src/main/java/nl/sbdeveloper/themeparkplus/util/LGUtil.java rename to src/main/lombok/nl/sbdeveloper/themeparkplus/util/LGUtil.java diff --git a/src/main/java/nl/sbdeveloper/themeparkplus/util/License.java b/src/main/lombok/nl/sbdeveloper/themeparkplus/util/License.java similarity index 100% rename from src/main/java/nl/sbdeveloper/themeparkplus/util/License.java rename to src/main/lombok/nl/sbdeveloper/themeparkplus/util/License.java diff --git a/src/main/lombok/nl/sbdeveloper/themeparkplus/util/WEUtil.java b/src/main/lombok/nl/sbdeveloper/themeparkplus/util/WEUtil.java new file mode 100644 index 0000000..a70c7fb --- /dev/null +++ b/src/main/lombok/nl/sbdeveloper/themeparkplus/util/WEUtil.java @@ -0,0 +1,52 @@ +package nl.sbdeveloper.themeparkplus.util; + +import com.sk89q.worldedit.IncompleteRegionException; +import com.sk89q.worldedit.LocalSession; +import com.sk89q.worldedit.WorldEdit; +import com.sk89q.worldedit.bukkit.WorldEditPlugin; +import com.sk89q.worldedit.bukkit.selections.Polygonal2DSelection; +import com.sk89q.worldedit.bukkit.selections.Selection; +import com.sk89q.worldedit.regions.Polygonal2DRegion; +import com.sk89q.worldedit.regions.Region; +import com.sk89q.worldedit.world.World; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.Nullable; + +public class WEUtil { + private static boolean newVersion; + private static WorldEditPlugin wep; + + public WEUtil() { + newVersion = XMaterial.isNewVersion(); + wep = (WorldEditPlugin) Bukkit.getPluginManager().getPlugin("WorldEdit"); + } + + @Nullable + public static Region getSelection(Player p) { + if (newVersion) { + LocalSession l = WorldEdit.getInstance().getSessionManager().get(BukkitAdapter.adapt(p)); + Region s; + try { + s = l.getSelection(l.getSelectionWorld()); + } catch (IncompleteRegionException e) { + return null; + } + if (s instanceof Polygonal2DSelection) { + Polygonal2DSelection polySel = (Polygonal2DSelection) s; + int minY = polySel.getNativeMinimumPoint().getBlockY(); + int maxY = polySel.getNativeMaximumPoint().getBlockY(); + return new Polygonal2DRegion((World) polySel.getWorld(), polySel.getNativePoints(), minY, maxY); + } + } else { + Selection sel = wep.getSelection(p); + if (sel instanceof Polygonal2DSelection) { + Polygonal2DSelection polySel = (Polygonal2DSelection) sel; + int minY = polySel.getNativeMinimumPoint().getBlockY(); + int maxY = polySel.getNativeMaximumPoint().getBlockY(); + return new Polygonal2DRegion((World) polySel.getWorld(), polySel.getNativePoints(), minY, maxY); + } + } + return null; + } +} diff --git a/src/main/java/nl/sbdeveloper/themeparkplus/util/XMaterial.java b/src/main/lombok/nl/sbdeveloper/themeparkplus/util/XMaterial.java similarity index 100% rename from src/main/java/nl/sbdeveloper/themeparkplus/util/XMaterial.java rename to src/main/lombok/nl/sbdeveloper/themeparkplus/util/XMaterial.java diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index cdcc7bc..a94c745 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -1,7 +1,15 @@ License: 'TPABCD-1234-ABCD-1234SBD' AntiFreerun: Enabled: false +UpdateChecker: + Enabled: true + DownloadOnUpdate: true MessageInConsole: true +WaitingRow: + MinutesPerPlayer: 1.5 + Sign: + Row1: "&8[&6ThemeParkPlus&8]" + Row2: "&bWaitingRow" Fastpass: Item: DisplayName: '&6Fastpass Ticket' diff --git a/src/main/resources/messages.yml b/src/main/resources/messages.yml index 7beb2af..b7d3c7f 100644 --- a/src/main/resources/messages.yml +++ b/src/main/resources/messages.yml @@ -1,6 +1,8 @@ General: NoPermission: '&cYou don''t have the permission to do this.' + NoPlayer: '&cYou have to be a player to do this.' IncorrectAmount: '&cThis amount is incorrect.' + IncorrectSign: '&cThis sign is incorrect. Please read the wiki for more information.' Gates: WrongDir: '&cYou can''t walk through this gate in that direction.' UnknownDir: '&cThis direction is unknown. Choose between: NORTH, SOUTH, EAST, WEST' @@ -12,11 +14,12 @@ Gates: OpenedAmount: '&aThe gate is opened for &f%amount% &aplayer(s)!' Closed: '&aThe gate is closed!' Fastpass: - IncorrectSign: '&cThis sign is incorrect. Please read the wiki for more information.' UnknownRide: '&cThe ride %ridename% &cdoesn''t exists.' + UnknownPlayer: '&cThe player %playername% &cdoesn''t exists or is not online.' NotEnoughMoney: '&cYou can''t pay this ticket.' AlreadyHaveTicket: '&cYou''ve already got a ticket for this ride.' Bought: '&aYou''ve successfully bought a ticket for the ride %ridename%&a. You''ve paid &f%price% &afor it.' + Given: '&aYou''ve successfully given a ticket.' NoTicket: '&cYou need a fastpass ticket to go through the fastpass line.' RideClosed: '&cThis ride is closed.' Redeemed: '&aSuccessfully redeemed your fastpass ticket!' @@ -29,4 +32,6 @@ Lamp: Lamps: TurnedOn: '&aLamps in region turned on!' TurnedOnSec: '&aLamps in region turned on for &f%sec% &asecond(s)!' - TurnedOff: '&aLamps in region turned off!' \ No newline at end of file + TurnedOff: '&aLamps in region turned off!' +WaitingRow: + SignCreated: '&aYou''ve successfully created a waitingrow sign!' \ No newline at end of file