diff --git a/pom.xml b/pom.xml index bc2f010..e7614ec 100644 --- a/pom.xml +++ b/pom.xml @@ -5,11 +5,11 @@ com.magmaguy ResourcePackManager - 1.0-SNAPSHOT + 1.2.1 - 22 - 22 + 17 + 17 UTF-8 @@ -22,6 +22,11 @@ central https://repo1.maven.org/maven2/ + + magmaguy-repo-releases + MagmaGuy's Repository + https://repo.magmaguy.com/releases + @@ -47,10 +52,39 @@ httpclient5 5.3.1 + + com.magmaguy + MagmaCore + 1.7 + compile + + + com.magmaguy + FreeMinecraftModels + 1.4.0 + provided + + + + org.bstats + bstats-bukkit + 3.0.2 + compile + + ResourcePackManager + + + maven-compiler-plugin + + 17 + 17 + + + org.apache.maven.plugins maven-shade-plugin @@ -68,6 +102,10 @@ org.apache.hc com.magmaguy.resourcepackmanager.org.apache.hc + + org.bstats + com.magmaguy.freeminecraftmodels + @@ -75,4 +113,15 @@ + + + magmaguy-repo-snapshots + https://magmaguy.com/snapshots + + + magmaguy-repo-snapshots + MagmaGuy's Repository + https://repo.magmaguy.com/releases + + diff --git a/src/main/java/com/magmaguy/resourcepackmanager/Logger.java b/src/main/java/com/magmaguy/resourcepackmanager/Logger.java deleted file mode 100644 index 3881571..0000000 --- a/src/main/java/com/magmaguy/resourcepackmanager/Logger.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.magmaguy.resourcepackmanager; - -import org.bukkit.Bukkit; - -public class Logger { - private Logger(){} - public static void warn(String message){ - Bukkit.getLogger().warning("[ResourcePackManager] " + message); - } - - public static void info(String message){ - Bukkit.getLogger().info("[ResourcePackManager] " + message); - } -} diff --git a/src/main/java/com/magmaguy/resourcepackmanager/ResourcePackManager.java b/src/main/java/com/magmaguy/resourcepackmanager/ResourcePackManager.java index 179a3af..93ff44a 100644 --- a/src/main/java/com/magmaguy/resourcepackmanager/ResourcePackManager.java +++ b/src/main/java/com/magmaguy/resourcepackmanager/ResourcePackManager.java @@ -1,16 +1,26 @@ package com.magmaguy.resourcepackmanager; +import com.magmaguy.freeminecraftmodels.bukkit.Metrics; +import com.magmaguy.magmacore.MagmaCore; +import com.magmaguy.magmacore.command.CommandManager; +import com.magmaguy.magmacore.util.Logger; import com.magmaguy.resourcepackmanager.autohost.AutoHost; -import com.magmaguy.resourcepackmanager.commands.CommandManager; +import com.magmaguy.resourcepackmanager.commands.DataComplianceRequestCommand; +import com.magmaguy.resourcepackmanager.commands.ReloadCommand; +import com.magmaguy.resourcepackmanager.config.BlueprintFolder; +import com.magmaguy.resourcepackmanager.config.DataConfig; import com.magmaguy.resourcepackmanager.config.DefaultConfig; +import com.magmaguy.resourcepackmanager.listeners.ResourcePackGeneratedEvent; import com.magmaguy.resourcepackmanager.mixer.Mix; +import com.magmaguy.resourcepackmanager.playermanager.PlayerManager; +import com.magmaguy.resourcepackmanager.utils.VersionChecker; import org.bukkit.Bukkit; -import org.bukkit.plugin.Plugin; +import org.bukkit.event.HandlerList; import org.bukkit.plugin.java.JavaPlugin; public class ResourcePackManager extends JavaPlugin { - public static Plugin plugin; + public static JavaPlugin plugin; @Override public void onEnable() { @@ -20,17 +30,36 @@ public void onEnable() { " | /\\__ \\ _/ |\\/| / _` | ' \\/ _` / _` / -_) '_|\n" + " |_|_\\|___/_| |_| |_\\__,_|_||_\\__,_\\__, \\___|_| \n" + " |___/ "); - Logger.info("Enabling ResourcePackManager v." + this.getDescription().getVersion()); + Bukkit.getLogger().info("ResourcePackManager v." + this.getDescription().getVersion()); + plugin = this; - DefaultConfig.initializeConfig(); + new DefaultConfig(); + new DataConfig(); + BlueprintFolder.initialize(); Mix.initialize(); + if (DefaultConfig.isAutoHost()) + Bukkit.getPluginManager().registerEvents(new PlayerManager(), this); + CommandManager commandManager = new CommandManager(this, "resourcepackmanager"); + commandManager.registerCommand(new ReloadCommand()); + commandManager.registerCommand(new DataComplianceRequestCommand()); + if (Bukkit.getPluginManager().isPluginEnabled("FreeMinecraftModels")) + Bukkit.getPluginManager().registerEvents(new ResourcePackGeneratedEvent(), this); + Bukkit.getPluginManager().registerEvents(new VersionChecker.VersionCheckerEvents(), this); AutoHost.initialize(); - new CommandManager(this); + + Metrics metrics = new Metrics(this, 22867); + VersionChecker.checkPluginVersion(); + } + + @Override + public void onLoad(){ + MagmaCore.createInstance(this); } @Override public void onDisable() { Logger.info("Disabling ResourcePackManager"); + HandlerList.unregisterAll(this); AutoHost.shutdown(); } } \ No newline at end of file diff --git a/src/main/java/com/magmaguy/resourcepackmanager/api/ResourcePackManagerAPI.java b/src/main/java/com/magmaguy/resourcepackmanager/api/ResourcePackManagerAPI.java new file mode 100644 index 0000000..d1723bc --- /dev/null +++ b/src/main/java/com/magmaguy/resourcepackmanager/api/ResourcePackManagerAPI.java @@ -0,0 +1,41 @@ +package com.magmaguy.resourcepackmanager.api; + +import com.magmaguy.magmacore.command.CommandManager; +import com.magmaguy.resourcepackmanager.commands.ReloadCommand; +import com.magmaguy.resourcepackmanager.thirdparty.ThirdPartyResourcePack; +import org.bukkit.Bukkit; +import org.bukkit.command.CommandSender; + +import java.util.HashMap; + +public class ResourcePackManagerAPI { + public static HashMap thirdPartyResourcePackHashMap = new HashMap<>(); + + /** + * Please read and follow the parameters carefully. + * @param pluginName The name of the plugin as it appears in the plugin list. Case-sensitive. + * @param path The absolute path to the resource pack file (zipped or folder), or the URL to the resource pack. Zipped, local resource packs are strongly recommended. + * @param encrypts Whether the pack can be encrypted by the plugin. Currently does nothing. + * @param distributes Whether the plugin can distribute the pack. Currently does nothing. + * @param zips Whether the resource pack linked to is zipped. + * @param local Whether the resource pack is local or not, meaning whether it appears in the directory of the server or is provided as a download link. Local is strongly recommended. + * @param reloadCommand The reload command of the plugin adding a pack. Currently does nothing. + */ + public static void registerResourcePack(String pluginName, + String path, + boolean encrypts, + boolean distributes, + boolean zips, + boolean local, + String reloadCommand) { + thirdPartyResourcePackHashMap.put(pluginName, + new ThirdPartyResourcePack(pluginName, path, encrypts, distributes, zips, local, reloadCommand)); + } + + /** + * Reloads the plugin, thereby redoing everything necessary to merge and host the resource pack + */ + public static void reloadResourcePack(){ + ReloadCommand.reloadPlugin(Bukkit.getConsoleSender()); + } +} diff --git a/src/main/java/com/magmaguy/resourcepackmanager/autohost/AutoHost.java b/src/main/java/com/magmaguy/resourcepackmanager/autohost/AutoHost.java index a520e44..5cdeaaf 100644 --- a/src/main/java/com/magmaguy/resourcepackmanager/autohost/AutoHost.java +++ b/src/main/java/com/magmaguy/resourcepackmanager/autohost/AutoHost.java @@ -1,99 +1,212 @@ package com.magmaguy.resourcepackmanager.autohost; -import com.magmaguy.resourcepackmanager.Logger; +import com.magmaguy.magmacore.util.Logger; import com.magmaguy.resourcepackmanager.ResourcePackManager; +import com.magmaguy.resourcepackmanager.config.DataConfig; import com.magmaguy.resourcepackmanager.config.DefaultConfig; import com.magmaguy.resourcepackmanager.mixer.Mix; +import lombok.Getter; import org.apache.hc.client5.http.classic.methods.HttpPost; import org.apache.hc.client5.http.entity.mime.MultipartEntityBuilder; import org.apache.hc.client5.http.impl.classic.CloseableHttpClient; import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse; import org.apache.hc.client5.http.impl.classic.HttpClients; import org.apache.hc.core5.http.ContentType; +import org.apache.hc.core5.http.HttpEntity; import org.apache.hc.core5.http.io.entity.EntityUtils; -import org.apache.hc.core5.http.io.entity.FileEntity; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; import org.bukkit.scheduler.BukkitRunnable; import org.bukkit.scheduler.BukkitTask; import java.io.*; import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.StandardCopyOption; +import java.util.UUID; public class AutoHost { - private static final String hostURL = "http://localhost:3000/sha1"; - private static final String stillAliveURL = "http://localhost:3000/still_alive"; - private static final String rspURL = "http://localhost:3000/upload"; + private static final String finalURL = "http://magmaguy.com:50000/"; + private static final UUID pluginRSPUUID = UUID.randomUUID(); private static BukkitTask keepAlive = null; + @Getter + private static String rspUUID = null; + private static boolean firstUpload = true; private AutoHost() { } + public static void sendResourcePack(Player player) { + if (rspUUID == null) return; + Logger.info("Sending resource pack to " + player.getName()); + player.setResourcePack(finalURL + "rsp_" + rspUUID, Mix.getFinalSHA1Bytes(), DefaultConfig.getResourcePackPrompt(), DefaultConfig.isForceResourcePack()); + } + public static void initialize() { if (!DefaultConfig.isAutoHost()) return; if (Mix.getFinalResourcePack() == null) return; - keepAlive = new BukkitRunnable() { + Logger.info("Starting autohost!"); + firstUpload = true; + new BukkitRunnable() { @Override public void run() { - try { - if (!sendSHA1(Mix.getFinalSHA1(), hostURL)) { - uploadFile(Mix.getFinalResourcePack(), rspURL); + checkFileExistence(); + keepAlive = new BukkitRunnable() { + int counter = 0; + + @Override + public void run() { + if (rspUUID != null) { + counter = 0; + try { + sendStillAlive(); + } catch (Exception e) { + rspUUID = null; + Logger.warn("Failed to autohost resource pack!"); + e.printStackTrace(); + } + } else { + checkFileExistence(); + if (rspUUID == null && counter % 10 == 0) { + Logger.warn("Failed to connect to remote server to autohost the resource pack!"); + } + counter++; + } } - sendStillAlive(stillAliveURL); - } catch (Exception e) { - Logger.warn("Failed to autohost resource pack!"); - e.printStackTrace(); - } + }.runTaskTimerAsynchronously(ResourcePackManager.plugin, 0, 6 * 60 * 60 * 20L); } - }.runTaskTimerAsynchronously(ResourcePackManager.plugin, 0, 3 * 24 * 60 * 60 * 20L); + }.runTaskAsynchronously(ResourcePackManager.plugin); + } + + private static void checkFileExistence() { + initializeLink(); + if (rspUUID == null) return; + if (!sendSHA1()) uploadFile(); } - public static void uploadFile(File file, String url) throws IOException { + public static void initializeLink() { try (CloseableHttpClient httpClient = HttpClients.createDefault()) { - HttpPost uploadFile = new HttpPost(url); + HttpPost httpPost = new HttpPost(finalURL + "initialize"); + MultipartEntityBuilder builder = MultipartEntityBuilder.create(); + builder.addTextBody("uuid", DataConfig.getRspUUID(), ContentType.TEXT_PLAIN.withCharset(StandardCharsets.UTF_8)); + httpPost.setEntity(builder.build()); - // Use FileEntity for streaming large files - FileEntity fileEntity = new FileEntity(file, ContentType.APPLICATION_OCTET_STREAM); - uploadFile.setEntity(fileEntity); + try (CloseableHttpResponse response = httpClient.execute(httpPost)) { + String responseString = EntityUtils.toString(response.getEntity()); + rspUUID = responseString.trim(); + DataConfig.setRspUUID(rspUUID); + } catch (Exception e) { + Logger.warn("Failed to communicate with remote server!"); + e.printStackTrace(); + } + } catch (Exception e) { + rspUUID = null; + Logger.warn("Failed remote server initialization."); + e.printStackTrace(); + } + } + + public static void uploadFile() { + Logger.info("Uploading resource!"); + + try (CloseableHttpClient httpClient = HttpClients.createDefault()) { + HttpPost uploadFile = new HttpPost(finalURL + "upload"); + + MultipartEntityBuilder builder = MultipartEntityBuilder.create(); + builder.addTextBody("uuid", rspUUID, ContentType.TEXT_PLAIN.withCharset(StandardCharsets.UTF_8)); + builder.addBinaryBody("file", Mix.getFinalResourcePack(), ContentType.APPLICATION_OCTET_STREAM, Mix.getFinalResourcePack().getName()); + + uploadFile.setEntity(builder.build()); try (CloseableHttpResponse response = httpClient.execute(uploadFile)) { + } catch (Exception e) { + Logger.warn("Failed to communicate with remote server!"); + e.printStackTrace(); + return; + } + Logger.info("Uploaded resource pack for automatic hosting!"); + if (firstUpload) + //Recover from a reload by sending the pack to online players + for (Player player : Bukkit.getOnlinePlayers()) + AutoHost.sendResourcePack(player); + firstUpload = false; + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + private static boolean sendSHA1() { + try (CloseableHttpClient httpClient = HttpClients.createDefault()) { + HttpPost httpPost = new HttpPost(finalURL + "sha1"); + + MultipartEntityBuilder builder = MultipartEntityBuilder.create(); + builder.addTextBody("uuid", rspUUID, ContentType.TEXT_PLAIN.withCharset(StandardCharsets.UTF_8)); + builder.addTextBody("sha1", Mix.getFinalSHA1(), ContentType.TEXT_PLAIN.withCharset(StandardCharsets.UTF_8)); + + HttpEntity entity = builder.build(); + httpPost.setEntity(entity); + + // Convert the entity to a string for logging + ByteArrayOutputStream out = new ByteArrayOutputStream(); + entity.writeTo(out); + + try (CloseableHttpResponse response = httpClient.execute(httpPost)) { String responseString = EntityUtils.toString(response.getEntity()); - System.out.println("Response from server: " + responseString); + return Boolean.valueOf(responseString); } catch (Exception e) { - throw new RuntimeException(e); + Logger.warn("Failed to communicate with remote server!"); + e.printStackTrace(); } + } catch (Exception e) { + e.printStackTrace(); } + return false; } - private static Boolean sendSHA1(String stringData, String url) throws IOException { + private static void sendStillAlive() throws IOException { try (CloseableHttpClient httpClient = HttpClients.createDefault()) { - HttpPost httpPost = new HttpPost(url); + HttpPost httpPost = new HttpPost(finalURL + "still_alive"); MultipartEntityBuilder builder = MultipartEntityBuilder.create(); - builder.addTextBody("stringData", stringData, ContentType.TEXT_PLAIN.withCharset(StandardCharsets.UTF_8)); + builder.addTextBody("uuid", rspUUID); httpPost.setEntity(builder.build()); try (CloseableHttpResponse response = httpClient.execute(httpPost)) { - String responseString = EntityUtils.toString(response.getEntity()); - System.out.println("Response from server: " + responseString); - return Boolean.parseBoolean(responseString.trim()); } catch (Exception e) { Logger.warn("Failed to communicate with remote server!"); e.printStackTrace(); - return null; } } } - private static void sendStillAlive(String url) throws IOException { + public static void dataComplianceRequest() throws IOException { try (CloseableHttpClient httpClient = HttpClients.createDefault()) { - HttpPost httpPost = new HttpPost(url); + HttpPost httpPost = new HttpPost(finalURL + "data_compliance"); MultipartEntityBuilder builder = MultipartEntityBuilder.create(); - builder.addTextBody("status", "alive", ContentType.TEXT_PLAIN.withCharset(StandardCharsets.UTF_8)); + builder.addTextBody("uuid", rspUUID); httpPost.setEntity(builder.build()); try (CloseableHttpResponse response = httpClient.execute(httpPost)) { - String responseString = EntityUtils.toString(response.getEntity()); - System.out.println("Response from server: " + responseString); + HttpEntity responseEntity = response.getEntity(); + + if (responseEntity != null) { + // Save the response as a zip file + File zipFile = new File(ResourcePackManager.plugin.getDataFolder().getAbsolutePath() + File.separatorChar + "data_compliance" + File.separatorChar + "data.zip"); + if (!zipFile.getParentFile().exists()) zipFile.mkdirs(); + if (zipFile.exists()) zipFile.delete(); + zipFile.createNewFile(); + try (FileOutputStream outStream = new FileOutputStream(zipFile)) { + responseEntity.writeTo(outStream); + } + InputStream inputStream = ResourcePackManager.plugin.getResource("ReadMe.md"); + + File readMe = new File(ResourcePackManager.plugin.getDataFolder().getAbsolutePath() + File.separatorChar + "data_compliance" + File.separatorChar + "ReadMe.md"); + if (!readMe.exists()) readMe.createNewFile(); + + // Copy the InputStream to the file + Files.copy(inputStream, readMe.toPath(), StandardCopyOption.REPLACE_EXISTING); + } } catch (Exception e) { Logger.warn("Failed to communicate with remote server!"); e.printStackTrace(); diff --git a/src/main/java/com/magmaguy/resourcepackmanager/commands/AdvancedCommand.java b/src/main/java/com/magmaguy/resourcepackmanager/commands/AdvancedCommand.java deleted file mode 100644 index a6a651a..0000000 --- a/src/main/java/com/magmaguy/resourcepackmanager/commands/AdvancedCommand.java +++ /dev/null @@ -1,36 +0,0 @@ -package com.magmaguy.resourcepackmanager.commands; - -import org.bukkit.command.CommandSender; - -import java.util.ArrayList; -import java.util.List; - -public abstract class AdvancedCommand { - public final List aliases; - public final String description; - public final String permission; - public final boolean onlyForPlayers; - public final boolean enabled = true; - public final String usage; - - public AdvancedCommand(List aliases, String description, String permission, boolean onlyForPlayers, String usage) { - this.aliases = aliases; - this.description = description; - this.permission = permission; - this.onlyForPlayers = onlyForPlayers; - this.usage = usage; - } - - public abstract void execute(CommandSender sender, String[] arguments); - - public abstract List onTabComplete(CommandSender commandSender, org.bukkit.command.Command command, String label, String[] args); - - protected List trimSuggestions(List suggestions, String input) { - if (input.isEmpty()) return suggestions; - List newList = new ArrayList<>(); - for (String suggestion : suggestions) - if (suggestion.contains(input)) - newList.add(suggestion); - return newList; - } -} diff --git a/src/main/java/com/magmaguy/resourcepackmanager/commands/CommandManager.java b/src/main/java/com/magmaguy/resourcepackmanager/commands/CommandManager.java deleted file mode 100644 index 520ffff..0000000 --- a/src/main/java/com/magmaguy/resourcepackmanager/commands/CommandManager.java +++ /dev/null @@ -1,103 +0,0 @@ -package com.magmaguy.resourcepackmanager.commands; - -import org.bukkit.command.Command; -import org.bukkit.command.CommandExecutor; -import org.bukkit.command.CommandSender; -import org.bukkit.command.TabCompleter; -import org.bukkit.entity.Player; -import org.bukkit.plugin.java.JavaPlugin; - -import java.util.ArrayList; -import java.util.List; - -public class CommandManager implements CommandExecutor, TabCompleter { - public final List commands = new ArrayList<>(); - - public CommandManager(JavaPlugin javaPlugin) { - javaPlugin.getCommand("resourcepackmanager").setExecutor(this); - registerCommands(); - } - - private void registerCommands() { - registerCommand(new ReloadCommand()); - } - - public void registerCommand(AdvancedCommand command) { - commands.add(command); - } - - public void unregisterCommand(Command command) { - commands.remove(command); - } - - - private void sendMessage(CommandSender commandSender, String message) { - commandSender.sendMessage("[ResourcePackManager] " + message); - } - - @Override - public boolean onCommand(CommandSender commandSender, Command cmd, String label, String[] args) { - if (args.length == 0) { - sendMessage(commandSender, "Valid commands:"); - commands.forEach(command -> commandSender.sendMessage(command.usage)); - return true; - } - - for (AdvancedCommand command : commands) { - // We don't want to execute other commands or ones that are disabled - if (!(command.aliases.contains(args[0]) && command.enabled)) { - continue; - } - - if (command.onlyForPlayers && !(commandSender instanceof Player)) { - // Must be a player - commandSender.sendMessage("[ResourcePackManager] This command must be run as a player!"); - return false; - } - - if (!((commandSender.hasPermission(command.permission) || - command.permission.equalsIgnoreCase("") || - command.permission.equalsIgnoreCase("resourcepackmanager.")) && - command.enabled)) { - // No permissions - commandSender.sendMessage("[ResourcePackManager] You do not have the permission to run this command!"); - return false; - } - - command.execute(commandSender, args); - return true; - } - // Unknown command message - commandSender.sendMessage("[ResourcePackManager] Unknown command!"); - return false; - } - - @Override - public List onTabComplete(CommandSender commandSender, Command cmd, String label, String[] args) { - // Handle the tab completion if it's a sub-command. - if (args.length == 1) { - List result = new ArrayList<>(); - for (AdvancedCommand command : commands) { - for (String alias : command.aliases) { - if (alias.toLowerCase().startsWith(args[0].toLowerCase()) && ( - command.enabled && (commandSender.hasPermission(command.permission) - || command.permission.equalsIgnoreCase("") || command.permission - .equalsIgnoreCase("resourcepackmanager.")))) { - result.add(alias); - } - } - } - return result; - } - - // Let the sub-command handle the tab completion - for (AdvancedCommand command : commands) { - if (command.aliases.contains(args[0]) && (command.enabled && ( - commandSender.hasPermission(command.permission) || command.permission.equalsIgnoreCase("") - || command.permission.equalsIgnoreCase("resourcepackmanager.")))) { - return command.onTabComplete(commandSender, cmd, label, args); - } - } - return null; - } -} diff --git a/src/main/java/com/magmaguy/resourcepackmanager/commands/DataComplianceRequestCommand.java b/src/main/java/com/magmaguy/resourcepackmanager/commands/DataComplianceRequestCommand.java new file mode 100644 index 0000000..b736562 --- /dev/null +++ b/src/main/java/com/magmaguy/resourcepackmanager/commands/DataComplianceRequestCommand.java @@ -0,0 +1,43 @@ +package com.magmaguy.resourcepackmanager.commands; + +import com.magmaguy.magmacore.command.AdvancedCommand; +import com.magmaguy.magmacore.command.CommandData; +import com.magmaguy.magmacore.util.Logger; +import com.magmaguy.resourcepackmanager.ResourcePackManager; +import com.magmaguy.resourcepackmanager.autohost.AutoHost; +import org.bukkit.command.Command; +import org.bukkit.command.CommandSender; +import org.bukkit.scheduler.BukkitRunnable; + +import java.util.List; + +public class DataComplianceRequestCommand extends AdvancedCommand { + + public DataComplianceRequestCommand() { + super(List.of("data_compliance_request")); + setDescription("Downloads a copy of all data associated to this server from the autohoster"); + setPermission("resourcepackmanager.*"); + setUsage("/fmm data_compliance_request"); + } + + @Override + public void execute(CommandData commandData) { + if (AutoHost.getRspUUID() == null) { + Logger.sendMessage(commandData.getCommandSender(), "Seems like the auto-hoster is either disabled or not working, no data is stored in remote servers because no connection to remote servers is established"); + return; + } + + new BukkitRunnable() { + @Override + public void run() { + try { + AutoHost.dataComplianceRequest(); + Logger.sendMessage(commandData.getCommandSender(), "Data compliance request completed, check ~/plugins/ResourcePackManager/data_compliance to see all data the remote server has stored for this server."); + } catch (Exception e) { + Logger.sendMessage(commandData.getCommandSender(), "Failed to request data, check console for error logs!"); + e.printStackTrace(); + } + } + }.runTaskAsynchronously(ResourcePackManager.plugin); + } +} diff --git a/src/main/java/com/magmaguy/resourcepackmanager/commands/ReloadCommand.java b/src/main/java/com/magmaguy/resourcepackmanager/commands/ReloadCommand.java index 7da4f08..51dfa2e 100644 --- a/src/main/java/com/magmaguy/resourcepackmanager/commands/ReloadCommand.java +++ b/src/main/java/com/magmaguy/resourcepackmanager/commands/ReloadCommand.java @@ -1,7 +1,10 @@ package com.magmaguy.resourcepackmanager.commands; -import com.magmaguy.resourcepackmanager.Logger; +import com.magmaguy.magmacore.command.AdvancedCommand; +import com.magmaguy.magmacore.command.CommandData; +import com.magmaguy.magmacore.util.Logger; import com.magmaguy.resourcepackmanager.ResourcePackManager; +import java.util.Collections; import org.bukkit.command.Command; import org.bukkit.command.CommandSender; @@ -9,22 +12,22 @@ public class ReloadCommand extends AdvancedCommand { public ReloadCommand() { - super(List.of("reload"), "Reloads the plugin", "*", false, "/fmm reload"); + super(List.of("reload")); + setDescription("Reloads the plugin"); + setPermission("resourcepackmanager.*"); + setUsage("/fmm reload"); } public static void reloadPlugin(CommandSender sender) { ResourcePackManager.plugin.onDisable(); ResourcePackManager.plugin.onEnable(); - sender.sendMessage("[ResourcePackManager] Reloaded plugin!"); + Logger.sendMessage(sender, "Reloaded the plugin!"); } @Override - public void execute(CommandSender sender, String[] arguments) { - reloadPlugin(sender); - } - - @Override - public List onTabComplete(CommandSender commandSender, Command command, String label, String[] args) { - return null; + public void execute(CommandData commandData) { + ResourcePackManager.plugin.onDisable(); + ResourcePackManager.plugin.onEnable(); + Logger.sendMessage(commandData.getCommandSender(), "Reloaded the plugin!"); } } \ No newline at end of file diff --git a/src/main/java/com/magmaguy/resourcepackmanager/config/BlueprintFolder.java b/src/main/java/com/magmaguy/resourcepackmanager/config/BlueprintFolder.java new file mode 100644 index 0000000..3a8c9f4 --- /dev/null +++ b/src/main/java/com/magmaguy/resourcepackmanager/config/BlueprintFolder.java @@ -0,0 +1,47 @@ +package com.magmaguy.resourcepackmanager.config; + +import com.magmaguy.magmacore.util.Logger; +import com.magmaguy.magmacore.util.ZipFile; +import com.magmaguy.resourcepackmanager.ResourcePackManager; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; + +public class BlueprintFolder { + private BlueprintFolder() { + } + + public static void initialize() { + Logger.info("Creating blueprint folder"); + File blueprintDirectory = new File(ResourcePackManager.plugin.getDataFolder().getAbsolutePath() + File.separatorChar + "blueprint"); + if (!blueprintDirectory.exists()) blueprintDirectory.mkdir(); + Logger.info("Copying image"); + File imageFile = new File(blueprintDirectory.getAbsolutePath() + File.separatorChar + "pack.png"); + if (!imageFile.exists()) { + try { + InputStream inputStream = ResourcePackManager.plugin.getResource("pack.png"); + Files.copy(inputStream, imageFile.toPath()); + } catch (IOException e) { + e.printStackTrace(); + } + } + Logger.info("Copying mcmeta"); + File mcmetaFile = new File(blueprintDirectory.getAbsolutePath() + File.separatorChar + "pack.mcmeta"); + if (!mcmetaFile.exists()) { + try { + InputStream inputStream = ResourcePackManager.plugin.getResource("pack.mcmeta"); + Files.copy(inputStream, mcmetaFile.toPath()); + inputStream.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + try { + ZipFile.ZipUtility.zip(blueprintDirectory, blueprintDirectory.getAbsolutePath() + File.separatorChar + "blueprint.zip"); + } catch (Exception e) { + Logger.warn("Failed to zip blueprint resource pack!"); + } + } +} diff --git a/src/main/java/com/magmaguy/resourcepackmanager/config/ConfigurationEngine.java b/src/main/java/com/magmaguy/resourcepackmanager/config/ConfigurationEngine.java deleted file mode 100644 index 7e6c8a0..0000000 --- a/src/main/java/com/magmaguy/resourcepackmanager/config/ConfigurationEngine.java +++ /dev/null @@ -1,139 +0,0 @@ -package com.magmaguy.resourcepackmanager.config; - -import com.magmaguy.resourcepackmanager.Logger; -import com.magmaguy.resourcepackmanager.ResourcePackManager; -import org.bukkit.Bukkit; -import org.bukkit.configuration.file.FileConfiguration; -import org.bukkit.configuration.file.YamlConfiguration; - -import java.io.File; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStreamReader; -import java.nio.charset.StandardCharsets; -import java.util.List; - -public class ConfigurationEngine { - - public static File fileCreator(String path, String fileName) { - File file = new File(ResourcePackManager.plugin.getDataFolder().getPath() + "/" + path + "/", fileName); - return fileCreator(file); - } - - public static File fileCreator(String fileName) { - File file = new File(ResourcePackManager.plugin.getDataFolder().getPath(), fileName); - return fileCreator(file); - } - - public static File fileCreator(File file) { - - if (!file.exists()) - try { - file.getParentFile().mkdirs(); - file.createNewFile(); - } catch (IOException ex) { - Bukkit.getLogger().warning("[EliteMobs] Error generating the plugin file: " + file.getName()); - } - - return file; - - } - - public static FileConfiguration fileConfigurationCreator(File file) { - try { - return YamlConfiguration.loadConfiguration(new InputStreamReader(new FileInputStream(file), StandardCharsets.UTF_8)); - } catch (Exception exception) { - Logger.warn("Failed to read configuration from file " + file.getName()); - return null; - } - } - - public static void fileSaverCustomValues(FileConfiguration fileConfiguration, File file) { - fileConfiguration.options().copyDefaults(true); - - try { - fileConfiguration.save(file); - } catch (IOException e) { - e.printStackTrace(); - } - - } - - public static void fileSaverOnlyDefaults(FileConfiguration fileConfiguration, File file) { - fileConfiguration.options().copyDefaults(true); - UnusedNodeHandler.clearNodes(fileConfiguration); - - try { - fileConfiguration.save(file); - } catch (IOException e) { - e.printStackTrace(); - } - - } - - private static void setComments(FileConfiguration fileConfiguration, String key, List comments) { - fileConfiguration.setComments(key, comments); - } - - public static Boolean setBoolean(FileConfiguration fileConfiguration, String key, boolean defaultValue) { - fileConfiguration.addDefault(key, defaultValue); - return fileConfiguration.getBoolean(key); - } - - public static Boolean setBoolean(List comments, FileConfiguration fileConfiguration, String key, boolean defaultValue) { - boolean value = setBoolean(fileConfiguration, key, defaultValue); - setComments(fileConfiguration, key, comments); - return value; - } - - - public static int setInt(FileConfiguration fileConfiguration, String key, int defaultValue) { - fileConfiguration.addDefault(key, defaultValue); - return fileConfiguration.getInt(key); - } - - public static int setInt(List comments, FileConfiguration fileConfiguration, String key, int defaultValue) { - int value = setInt(fileConfiguration, key, defaultValue); - setComments(fileConfiguration, key, comments); - return value; - } - - public static double setDouble(FileConfiguration fileConfiguration, String key, double defaultValue) { - fileConfiguration.addDefault(key, defaultValue); - return fileConfiguration.getDouble(key); - } - - public static double setDouble(List comments, FileConfiguration fileConfiguration, String key, double defaultValue) { - double value = setDouble(fileConfiguration, key, defaultValue); - setComments(fileConfiguration, key, comments); - return value; - } - - public static boolean writeValue(Object value, File file, FileConfiguration fileConfiguration, String path) { - fileConfiguration.set(path, value); - try { - fileSaverCustomValues(fileConfiguration, file); - } catch (Exception exception) { - Logger.warn("Failed to write value for " + path + " in file " + file.getName()); - return false; - } - return true; - } - - public static void removeValue(File file, FileConfiguration fileConfiguration, String path) { - writeValue(null, file, fileConfiguration, path); - } - - public static List setList(File file, FileConfiguration fileConfiguration, String key, List defaultValue) { - fileConfiguration.addDefault(key, defaultValue); - return fileConfiguration.getList(key); - } - - public static List setList(List comment, File file, FileConfiguration fileConfiguration, String key, List defaultValue) { - List value = setList(file, fileConfiguration, key, defaultValue); - setComments(fileConfiguration, key, comment); - return value; - } - - -} diff --git a/src/main/java/com/magmaguy/resourcepackmanager/config/DataConfig.java b/src/main/java/com/magmaguy/resourcepackmanager/config/DataConfig.java new file mode 100644 index 0000000..919d8e0 --- /dev/null +++ b/src/main/java/com/magmaguy/resourcepackmanager/config/DataConfig.java @@ -0,0 +1,34 @@ +package com.magmaguy.resourcepackmanager.config; + +import com.magmaguy.magmacore.config.ConfigurationFile; +import com.magmaguy.magmacore.util.Logger; + +public class DataConfig extends ConfigurationFile { + private static DataConfig instance = null; + + public DataConfig() { + super("data.yml"); + instance = this; + } + + public static String getRspUUID() { + String uuid = instance.getFileConfiguration().getString("uuid"); + if (uuid == null) uuid = ""; + return uuid; + } + + public static void setRspUUID(String rspUUID) { + instance.getFileConfiguration().set("uuid", rspUUID); + try { + instance.getFileConfiguration().save(instance.file); + } catch (Exception e) { + Logger.warn("Failed to save uuid!"); + e.printStackTrace(); + } + } + + @Override + public void initializeValues() { + + } +} diff --git a/src/main/java/com/magmaguy/resourcepackmanager/config/DefaultConfig.java b/src/main/java/com/magmaguy/resourcepackmanager/config/DefaultConfig.java index 702aea3..f46df68 100644 --- a/src/main/java/com/magmaguy/resourcepackmanager/config/DefaultConfig.java +++ b/src/main/java/com/magmaguy/resourcepackmanager/config/DefaultConfig.java @@ -1,38 +1,71 @@ package com.magmaguy.resourcepackmanager.config; +import com.magmaguy.magmacore.config.ConfigurationEngine; +import com.magmaguy.magmacore.config.ConfigurationFile; import lombok.Getter; -import org.bukkit.configuration.file.FileConfiguration; -import java.io.File; import java.util.List; -public class DefaultConfig { - private static File file = null; - private static FileConfiguration fileConfiguration = null; +public class DefaultConfig extends ConfigurationFile { + @Getter private static List priorityOrder; @Getter private static boolean autoHost; + @Getter + private static boolean forceResourcePack; + @Getter + private static String resourcePackPrompt; + @Getter + private static String resourcePackRerouting; + - public static void initializeConfig() { - file = ConfigurationEngine.fileCreator("config.yml"); - fileConfiguration = ConfigurationEngine.fileConfigurationCreator(file); + public DefaultConfig() { + super("config.yml"); + } + @Override + public void initializeValues() { priorityOrder = ConfigurationEngine.setList( List.of( "Sets the list, from highest priority (top) to lowest priority (bottom), in which the resource" + " packs will automatically resolve merge conflicts.", "The defaults use plugin names. If you manually added your own resource pack in the mixer folder to be merged in, add its exact filename, including .zip in the name"), - file, fileConfiguration, "priorityOrder", - List.of("ResourcePackManager", "EliteMobs", "FreeMinecraftModels", "ModelEngine", "ItemsAdder", "Nova", "Oraxen")); + fileConfiguration, "priorityOrder", + List.of( + "ResourcePackManager", + "EliteMobs", + "FreeMinecraftModels", + "ModelEngine", + "Nova", + "ItemsAdder", + "Oraxen", + "Nexo", + "BetterHUD", + "ValhallaMMO", + "MMOInventory", + "vane-core", + "RealisticSurvival")); autoHost = ConfigurationEngine.setBoolean( List.of("Automatically host the resource pack on MagmaGuy's servers", "These servers cost money to keep running. There is no guarantee this will be an option forever."), fileConfiguration, "autoHost", true); - ConfigurationEngine.fileSaverOnlyDefaults(fileConfiguration, file); + forceResourcePack = ConfigurationEngine.setBoolean( + List.of("Sets whether the resource pack use will be forced to clients"), + fileConfiguration, "forceResourcePack", false); + resourcePackPrompt = ConfigurationEngine.setString( + List.of("Sets whether the resource pack use will be forced to clients"), + fileConfiguration, "resourcePackPrompt", "Use recommended resource pack?"); + resourcePackRerouting = ConfigurationEngine.setString( + List.of( + "OPTIONAL: Copy the merged directory to a custom directory location. Useful for unusual setups, like people trying to host with a different plugin.", + "If you are hosting with a different plugin make sure to disable Auto-hosting here!", + "This will use the plugin directory as the base directory.", + "As an example, if you wanted to target ResourcePackManager's output folder, you'd do:", + "ResourcePackManage/output", + "If you don't know what any of what is written here means, just don't touch this setting!"), + fileConfiguration, "resourcePackRerouting", ""); } - - } diff --git a/src/main/java/com/magmaguy/resourcepackmanager/config/UnusedNodeHandler.java b/src/main/java/com/magmaguy/resourcepackmanager/config/UnusedNodeHandler.java deleted file mode 100644 index e05eb13..0000000 --- a/src/main/java/com/magmaguy/resourcepackmanager/config/UnusedNodeHandler.java +++ /dev/null @@ -1,31 +0,0 @@ -package com.magmaguy.resourcepackmanager.config; - -import com.magmaguy.resourcepackmanager.Logger; -import org.bukkit.Bukkit; -import org.bukkit.configuration.Configuration; -import org.bukkit.configuration.file.FileConfiguration; - -public class UnusedNodeHandler { - - private UnusedNodeHandler() { - } - - public static Configuration clearNodes(FileConfiguration configuration) { - - for (String actual : configuration.getKeys(false)) { - boolean keyExists = false; - for (String defaults : configuration.getDefaults().getKeys(true)) - if (actual.equals(defaults)) { - keyExists = true; - break; - } - - if (!keyExists) { - configuration.set(actual, null); - Bukkit.getLogger().warning(actual); - Logger.warn("Deleting unused config values."); - } - } - return configuration; - } -} diff --git a/src/main/java/com/magmaguy/resourcepackmanager/datacompliance/DataCompliance.java b/src/main/java/com/magmaguy/resourcepackmanager/datacompliance/DataCompliance.java new file mode 100644 index 0000000..bdd04bb --- /dev/null +++ b/src/main/java/com/magmaguy/resourcepackmanager/datacompliance/DataCompliance.java @@ -0,0 +1,4 @@ +package com.magmaguy.resourcepackmanager.datacompliance; + +public class DataCompliance { +} diff --git a/src/main/java/com/magmaguy/resourcepackmanager/listeners/ResourcePackGeneratedEvent.java b/src/main/java/com/magmaguy/resourcepackmanager/listeners/ResourcePackGeneratedEvent.java new file mode 100644 index 0000000..07a5d6b --- /dev/null +++ b/src/main/java/com/magmaguy/resourcepackmanager/listeners/ResourcePackGeneratedEvent.java @@ -0,0 +1,14 @@ +package com.magmaguy.resourcepackmanager.listeners; + +import com.magmaguy.freeminecraftmodels.events.ResourcePackGenerationEvent; +import com.magmaguy.resourcepackmanager.commands.ReloadCommand; +import org.bukkit.Bukkit; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; + +public class ResourcePackGeneratedEvent implements Listener { + @EventHandler + public void onResourcePackGenerated(ResourcePackGenerationEvent event) { + ReloadCommand.reloadPlugin(Bukkit.getConsoleSender()); + } +} diff --git a/src/main/java/com/magmaguy/resourcepackmanager/mixer/Mix.java b/src/main/java/com/magmaguy/resourcepackmanager/mixer/Mix.java index 608d64e..c050e9c 100644 --- a/src/main/java/com/magmaguy/resourcepackmanager/mixer/Mix.java +++ b/src/main/java/com/magmaguy/resourcepackmanager/mixer/Mix.java @@ -2,15 +2,15 @@ import com.google.gson.*; import com.google.gson.stream.JsonReader; -import com.magmaguy.resourcepackmanager.Logger; +import com.magmaguy.magmacore.util.Logger; +import com.magmaguy.magmacore.util.ZipFile; import com.magmaguy.resourcepackmanager.ResourcePackManager; -import com.magmaguy.resourcepackmanager.thirdparty.EliteMobs; -import com.magmaguy.resourcepackmanager.thirdparty.FreeMinecraftModels; -import com.magmaguy.resourcepackmanager.thirdparty.ModelEngine; -import com.magmaguy.resourcepackmanager.thirdparty.ThirdPartyResourcePack; +import com.magmaguy.resourcepackmanager.api.ResourcePackManagerAPI; +import com.magmaguy.resourcepackmanager.config.DefaultConfig; +import com.magmaguy.resourcepackmanager.thirdparty.*; import com.magmaguy.resourcepackmanager.utils.SHA1Generator; -import com.magmaguy.resourcepackmanager.utils.ZipFile; import lombok.Getter; +import org.bukkit.Bukkit; import java.io.File; import java.io.FileReader; @@ -18,20 +18,20 @@ import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.attribute.BasicFileAttributeView; -import java.nio.file.attribute.BasicFileAttributes; -import java.nio.file.attribute.FileTime; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.TimeUnit; +import java.util.*; public class Mix { private static final String resourcePackName = "ResourcePackManager_RSP"; - private static List thirdPartyResourcePacks; + private static HashMap priorities; + private static List resourcePacks; + private static List orderedResourcePacks; @Getter private static File finalResourcePack; @Getter private static String finalSHA1; + @Getter + private static byte[] finalSHA1Bytes; + private static File mixerFolder; private Mix() { } @@ -39,13 +39,13 @@ private Mix() { public static void initialize() { if (!initializeDefaultPluginFolders()) return; initializeThirdPartyResourcePacks(); - cloneToOutPutAndUnzip(); + cloneToOutputAndUnzip(); createOutputDefaultElements(); } private static boolean initializeDefaultPluginFolders() { try { - File mixerFolder = new File(ResourcePackManager.plugin.getDataFolder().getAbsolutePath() + File.separatorChar + "mixer"); + mixerFolder = new File(ResourcePackManager.plugin.getDataFolder().getAbsolutePath() + File.separatorChar + "mixer"); if (!mixerFolder.exists()) mixerFolder.mkdir(); File outputFolder = getOutputFolder(); @@ -59,38 +59,120 @@ private static boolean initializeDefaultPluginFolders() { } private static void initializeThirdPartyResourcePacks() { - ArrayList tempList = new ArrayList<>(); - EliteMobs eliteMobs = new EliteMobs(); - if (eliteMobs.isEnabled()) - tempList.add(eliteMobs); - FreeMinecraftModels freeMinecraftModels = new FreeMinecraftModels(); - if (freeMinecraftModels.isEnabled()) - tempList.add(freeMinecraftModels); - ModelEngine modelEngine = new ModelEngine(); - if (modelEngine.isEnabled()) - tempList.add(modelEngine); - //todo: add the rest - thirdPartyResourcePacks = new ArrayList<>(); - for (int i = 0; i < tempList.size(); i++) { - for (ThirdPartyResourcePack thirdPartyResourcePack : tempList) { - if (thirdPartyResourcePack.getPriority() == i) { - thirdPartyResourcePacks.add(thirdPartyResourcePack); - tempList.remove(thirdPartyResourcePack); + orderedResourcePacks = new ArrayList<>(); + priorities = new HashMap(); + List tempList = new ArrayList<>(); + List resourcePackManagers = Arrays.asList( + new com.magmaguy.resourcepackmanager.thirdparty.ResourcePackManager(), + new EliteMobs(), + new FreeMinecraftModels(), + new ModelEngine(), + new ItemsAdder(), + new Nova(), + new Oraxen(), + new Nexo(), + new BetterHUD(), + new ValhallaMMO(), + new VaneCore(), + new BackpackPlus(), + new RealisticSurvival() + ); + + //API resource packs + resourcePackManagers.addAll(ResourcePackManagerAPI.thirdPartyResourcePackHashMap.values()); + + resourcePackManagers.stream() + .filter(ThirdPartyResourcePack::isEnabled) + .forEach(tempList::add); + + resourcePacks = new ArrayList<>(); + List customFiles = new ArrayList<>(); + List thirdPartyFiles = new ArrayList<>(); + + tempList.forEach(rsp -> { + if (rsp.getMixerResourcePack() != null) { + thirdPartyFiles.add(rsp.getMixerResourcePack()); + } + }); + + for (File file : mixerFolder.listFiles()) { + boolean isThirdParty = false; + for (File thirdPartyFile : thirdPartyFiles) { + if (file.getName().equals(thirdPartyFile.getName())) { + isThirdParty = true; break; } } + if (!isThirdParty) { + customFiles.add(file); + } } - thirdPartyResourcePacks.addAll(tempList); + + for (int i = 0; i < DefaultConfig.getPriorityOrder().size(); i++) { + boolean foundFileAtPriority = false; + Iterator iterator = tempList.iterator(); + + while (iterator.hasNext()) { + ThirdPartyResourcePack thirdPartyResourcePack = iterator.next(); + if (thirdPartyResourcePack.getPriority() == i) { + File resourcePackFile = thirdPartyResourcePack.getMixerResourcePack(); + if (resourcePackFile != null) { + resourcePacks.add(resourcePackFile); + orderedResourcePacks.add(resourcePackFile.getName().replace(".zip", "")); + iterator.remove(); + foundFileAtPriority = true; + break; + } + } + } + + if (!foundFileAtPriority) { + Iterator fileIterator = customFiles.iterator(); + while (fileIterator.hasNext()) { + File file = fileIterator.next(); + int priority = DefaultConfig.getPriorityOrder().indexOf(file.getName()); + if (priority == i) { + resourcePacks.add(file); + orderedResourcePacks.add(file.getName().replace(".zip", "")); + fileIterator.remove(); + Logger.info("Added custom resource pack " + file.getName() + " at priority " + i); + } + } + } + } + + tempList.stream() + .map(ThirdPartyResourcePack::getMixerResourcePack) + .filter(Objects::nonNull) + .forEach(resourcePack -> { + resourcePacks.add(resourcePack); + orderedResourcePacks.add(resourcePack.getName().replace(".zip", "")); + Logger.info("Added supported resource pack " + resourcePack.getName() + " without a priority!"); + }); + + customFiles.forEach(customFile -> { + resourcePacks.add(customFile); + orderedResourcePacks.add(customFile.getName().replace(".zip", "")); + Logger.info("Added custom resource pack " + customFile.getName() + " without a priority!"); + }); } - private static void cloneToOutPutAndUnzip() { - thirdPartyResourcePacks.forEach(thirdPartyResourcePack -> { + + private static void cloneToOutputAndUnzip() { + resourcePacks.forEach(resourcePack -> { try { - File file = new File(ResourcePackManager.plugin.getDataFolder().getAbsolutePath() + File.separatorChar + "output" + File.separatorChar + thirdPartyResourcePack.getMixerResourcePack().getName().replace(".zip", "")); - ZipFile.unzip(thirdPartyResourcePack.getMixerResourcePack(), file); + if (resourcePack == null) { + Logger.warn("A resource pack was null by the time it was meant to be unzipped!"); + return; + } + File file = new File(ResourcePackManager.plugin.getDataFolder().getAbsolutePath() + File.separatorChar + "output" + File.separatorChar + resourcePack.getName().replace(".zip", "")); + ZipFile.unzip(resourcePack, file); stripDirectoryMetadata(file); } catch (Exception e) { - Logger.warn("Failed to extract file " + thirdPartyResourcePack.getMixerResourcePack().getAbsolutePath() + " ! The file might be encrypted."); + if (resourcePack == null) + Logger.warn("Failed to extract resource pack! A file might be encrypted."); + else + Logger.warn("Failed to extract resource pack " + resourcePack.getName() + " ! The file might be encrypted."); e.printStackTrace(); } }); @@ -107,8 +189,13 @@ private static void createOutputDefaultElements() { throw new RuntimeException(e); } - for (File file : getOutputFolder().listFiles()) { - if (file.getName().equals(resourcePackName)) continue; + List orderedFiles = new ArrayList<>(); + for (String filename : orderedResourcePacks){ + orderedFiles.add(new File(getOutputFolder().getPath() + File.separatorChar + filename)); + } + + for (File file : orderedFiles) { + if (file.getName().equals(resourcePackName + ".zip")) continue; if (!file.isDirectory()) { if (file.getName().endsWith(".zip")) continue; Logger.warn("Somehow a non-folder file made its way to the output folder! This isn't good. File: " + file.getAbsolutePath()); @@ -122,11 +209,27 @@ private static void createOutputDefaultElements() { Logger.warn("Failed to zip merged resource pack!"); return; } + if (!DefaultConfig.getResourcePackRerouting().isEmpty() && !DefaultConfig.getResourcePackRerouting().isBlank()){ + try{ + File rerouteFolder = new File(ResourcePackManager.plugin.getDataFolder().getParentFile().getAbsolutePath() + File.separatorChar + DefaultConfig.getResourcePackRerouting()); + if (!rerouteFolder.exists()) { + Logger.warn("Failed to reroute zipped file to " + rerouteFolder.getAbsolutePath() + " because that folder does not exist!"); + } else if (!rerouteFolder.isDirectory()){ + Logger.warn("Failed to reroute zipped file to " + rerouteFolder.getAbsolutePath() + " because that is a file and not a folder!"); + } else if (!ZipFile.zip(getOutputResourcePackFolder(), rerouteFolder.getPath() + ".zip")) { + Logger.warn("Failed to zip merged resource pack into reroute directory!"); + return; + } + } catch (Exception e){ + Logger.warn("Failed to reroute zipped file to " + DefaultConfig.getResourcePackRerouting()); + } + } for (File file : getOutputFolder().listFiles()) { if (file.getName().equals(resourcePackName + ".zip")) { finalResourcePack = file; try { finalSHA1 = SHA1Generator.sha1CodeString(finalResourcePack); + finalSHA1Bytes = SHA1Generator.sha1CodeByteArray(finalResourcePack); } catch (Exception e) { Logger.warn("Failed to get SHA1 from zipped resource pack!"); finalResourcePack = null; @@ -154,14 +257,12 @@ private static void recursivelyDeleteDirectory(File directory) { Files.delete(directory.toPath()); } catch (Exception e) { Logger.warn("Failed to delete directory " + directory.getPath()); -// e.printStackTrace(); } } else { try { Files.delete(directory.toPath()); } catch (IOException e) { Logger.warn("Failed to delete file " + directory.getPath()); -// e.printStackTrace(); } } } diff --git a/src/main/java/com/magmaguy/resourcepackmanager/playermanager/PlayerManager.java b/src/main/java/com/magmaguy/resourcepackmanager/playermanager/PlayerManager.java new file mode 100644 index 0000000..3cfe328 --- /dev/null +++ b/src/main/java/com/magmaguy/resourcepackmanager/playermanager/PlayerManager.java @@ -0,0 +1,15 @@ +package com.magmaguy.resourcepackmanager.playermanager; + +import com.magmaguy.magmacore.util.Logger; +import com.magmaguy.resourcepackmanager.autohost.AutoHost; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerJoinEvent; + +public class PlayerManager implements Listener { + + @EventHandler + public void onPlayerJoin(PlayerJoinEvent event) { + AutoHost.sendResourcePack(event.getPlayer()); + } +} diff --git a/src/main/java/com/magmaguy/resourcepackmanager/thirdparty/BackpackPlus.java b/src/main/java/com/magmaguy/resourcepackmanager/thirdparty/BackpackPlus.java new file mode 100644 index 0000000..95f41e1 --- /dev/null +++ b/src/main/java/com/magmaguy/resourcepackmanager/thirdparty/BackpackPlus.java @@ -0,0 +1,15 @@ +package com.magmaguy.resourcepackmanager.thirdparty; + +import java.io.File; + +public class BackpackPlus extends ThirdPartyResourcePack { + public BackpackPlus() { + super("BackpackPlus", + "BackpackPlus" +File.separatorChar+ "pack" +File.separatorChar + "resourcepack.zip", + false, + false, + true, + true, + ""); + } +} diff --git a/src/main/java/com/magmaguy/resourcepackmanager/thirdparty/BetterHUD.java b/src/main/java/com/magmaguy/resourcepackmanager/thirdparty/BetterHUD.java new file mode 100644 index 0000000..b1b19d8 --- /dev/null +++ b/src/main/java/com/magmaguy/resourcepackmanager/thirdparty/BetterHUD.java @@ -0,0 +1,15 @@ +package com.magmaguy.resourcepackmanager.thirdparty; + +import java.io.File; + +public class BetterHUD extends ThirdPartyResourcePack { + public BetterHUD() { + super("BetterHUD", + "BetterHud" + File.separatorChar + "build.zip", + true, + false, + true, + true, + "betterhud reload"); + } +} diff --git a/src/main/java/com/magmaguy/resourcepackmanager/thirdparty/EliteMobs.java b/src/main/java/com/magmaguy/resourcepackmanager/thirdparty/EliteMobs.java index 6a69bb7..f4ca084 100644 --- a/src/main/java/com/magmaguy/resourcepackmanager/thirdparty/EliteMobs.java +++ b/src/main/java/com/magmaguy/resourcepackmanager/thirdparty/EliteMobs.java @@ -10,6 +10,8 @@ public EliteMobs() { "EliteMobs" + File.separatorChar + "exports" + File.separatorChar + "elitemobs_resource_pack.zip", false, false, + true, + true, "elitemobs reload"); } } diff --git a/src/main/java/com/magmaguy/resourcepackmanager/thirdparty/FreeMinecraftModels.java b/src/main/java/com/magmaguy/resourcepackmanager/thirdparty/FreeMinecraftModels.java index 7697c26..6b790a8 100644 --- a/src/main/java/com/magmaguy/resourcepackmanager/thirdparty/FreeMinecraftModels.java +++ b/src/main/java/com/magmaguy/resourcepackmanager/thirdparty/FreeMinecraftModels.java @@ -8,6 +8,8 @@ public FreeMinecraftModels() { "FreeMinecraftModels" + File.separatorChar + "output" + File.separatorChar + "FreeMinecraftModels.zip", false, false, + true, + true, "freeminecraftmodels reload"); } } diff --git a/src/main/java/com/magmaguy/resourcepackmanager/thirdparty/ItemsAdder.java b/src/main/java/com/magmaguy/resourcepackmanager/thirdparty/ItemsAdder.java index 3edad18..a4b21e5 100644 --- a/src/main/java/com/magmaguy/resourcepackmanager/thirdparty/ItemsAdder.java +++ b/src/main/java/com/magmaguy/resourcepackmanager/thirdparty/ItemsAdder.java @@ -1,4 +1,15 @@ package com.magmaguy.resourcepackmanager.thirdparty; -public class ItemsAdder { +import java.io.File; + +public class ItemsAdder extends ThirdPartyResourcePack { + public ItemsAdder() { + super("ItemsAdder", + "ItemsAdder" + File.separatorChar + "output" + File.separatorChar + "generated.zip", + false, + false, + true, + true, + ""); + } } diff --git a/src/main/java/com/magmaguy/resourcepackmanager/thirdparty/MMOInventory.java b/src/main/java/com/magmaguy/resourcepackmanager/thirdparty/MMOInventory.java new file mode 100644 index 0000000..505dc3b --- /dev/null +++ b/src/main/java/com/magmaguy/resourcepackmanager/thirdparty/MMOInventory.java @@ -0,0 +1,15 @@ +package com.magmaguy.resourcepackmanager.thirdparty; + +import java.io.File; + +public class MMOInventory extends ThirdPartyResourcePack { + public MMOInventory() { + super("MMOInventory", + "https://www.dropbox.com/s/1lftxmzh0q4b5yu/mmoinv_rp_3.zip?dl=1", + false, + false, + true, + false, + ""); + } +} \ No newline at end of file diff --git a/src/main/java/com/magmaguy/resourcepackmanager/thirdparty/ModelEngine.java b/src/main/java/com/magmaguy/resourcepackmanager/thirdparty/ModelEngine.java index e3125e9..1760ba1 100644 --- a/src/main/java/com/magmaguy/resourcepackmanager/thirdparty/ModelEngine.java +++ b/src/main/java/com/magmaguy/resourcepackmanager/thirdparty/ModelEngine.java @@ -8,6 +8,8 @@ public ModelEngine() { "ModelEngine" + File.separatorChar + "resource pack.zip", false, false, + true, + true, "meg reload"); } } \ No newline at end of file diff --git a/src/main/java/com/magmaguy/resourcepackmanager/thirdparty/Nexo.java b/src/main/java/com/magmaguy/resourcepackmanager/thirdparty/Nexo.java new file mode 100644 index 0000000..4b95059 --- /dev/null +++ b/src/main/java/com/magmaguy/resourcepackmanager/thirdparty/Nexo.java @@ -0,0 +1,15 @@ +package com.magmaguy.resourcepackmanager.thirdparty; + +import java.io.File; + +public class Nexo extends ThirdPartyResourcePack { + public Nexo() { + super("Nexo", + "Nexo" + File.separatorChar + "pack" + File.separatorChar + "pack.zip", + false, + false, + true, + true, + "n reload pack"); + } +} diff --git a/src/main/java/com/magmaguy/resourcepackmanager/thirdparty/Nova.java b/src/main/java/com/magmaguy/resourcepackmanager/thirdparty/Nova.java index 0494ff6..13a017c 100644 --- a/src/main/java/com/magmaguy/resourcepackmanager/thirdparty/Nova.java +++ b/src/main/java/com/magmaguy/resourcepackmanager/thirdparty/Nova.java @@ -1,4 +1,15 @@ package com.magmaguy.resourcepackmanager.thirdparty; -public class Nova { +import java.io.File; + +public class Nova extends ThirdPartyResourcePack { + public Nova() { + super("Nova", + "Nova" + File.separatorChar + "resource_pack" + File.separatorChar + "ResourcePack.zip", + false, + false, + true, + true, + ""); + } } diff --git a/src/main/java/com/magmaguy/resourcepackmanager/thirdparty/Oraxen.java b/src/main/java/com/magmaguy/resourcepackmanager/thirdparty/Oraxen.java index 3d409ac..b828c09 100644 --- a/src/main/java/com/magmaguy/resourcepackmanager/thirdparty/Oraxen.java +++ b/src/main/java/com/magmaguy/resourcepackmanager/thirdparty/Oraxen.java @@ -1,4 +1,15 @@ package com.magmaguy.resourcepackmanager.thirdparty; -public class Oraxen { -} +import java.io.File; + +public class Oraxen extends ThirdPartyResourcePack { + public Oraxen() { + super("Oraxen", + "Oraxen" + File.separatorChar + "pack" + File.separatorChar + "pack.zip", + false, + false, + true, + true, + ""); + } +} \ No newline at end of file diff --git a/src/main/java/com/magmaguy/resourcepackmanager/thirdparty/RealisticSurvival.java b/src/main/java/com/magmaguy/resourcepackmanager/thirdparty/RealisticSurvival.java new file mode 100644 index 0000000..c69eb94 --- /dev/null +++ b/src/main/java/com/magmaguy/resourcepackmanager/thirdparty/RealisticSurvival.java @@ -0,0 +1,13 @@ +package com.magmaguy.resourcepackmanager.thirdparty; + +public class RealisticSurvival extends ThirdPartyResourcePack { + public RealisticSurvival() { + super("RealisticSurvival", + "https://www.dropbox.com/scl/fi/5ggc7t20bfxmrzsbb1kok/Realistic-Survival-RP-1.2.8-RELEASE.zip?rlkey=55llpn4zj146usfmm8okf1ier&dl=1", + false, + false, + true, + false, + ""); + } +} diff --git a/src/main/java/com/magmaguy/resourcepackmanager/thirdparty/ResourcePackManager.java b/src/main/java/com/magmaguy/resourcepackmanager/thirdparty/ResourcePackManager.java new file mode 100644 index 0000000..a15d979 --- /dev/null +++ b/src/main/java/com/magmaguy/resourcepackmanager/thirdparty/ResourcePackManager.java @@ -0,0 +1,15 @@ +package com.magmaguy.resourcepackmanager.thirdparty; + +import java.io.File; + +public class ResourcePackManager extends ThirdPartyResourcePack { + public ResourcePackManager() { + super("ResourcePackManager", + "ResourcePackManager" + File.separatorChar + "blueprint" + File.separatorChar + "blueprint.zip", + false, + false, + true, + true, + ""); + } +} diff --git a/src/main/java/com/magmaguy/resourcepackmanager/thirdparty/ThirdPartyResourcePack.java b/src/main/java/com/magmaguy/resourcepackmanager/thirdparty/ThirdPartyResourcePack.java index 59e6c2f..20eb936 100644 --- a/src/main/java/com/magmaguy/resourcepackmanager/thirdparty/ThirdPartyResourcePack.java +++ b/src/main/java/com/magmaguy/resourcepackmanager/thirdparty/ThirdPartyResourcePack.java @@ -1,23 +1,38 @@ package com.magmaguy.resourcepackmanager.thirdparty; -import com.magmaguy.resourcepackmanager.Logger; +import com.magmaguy.magmacore.util.Logger; +import com.magmaguy.magmacore.util.ZipFile; import com.magmaguy.resourcepackmanager.ResourcePackManager; import com.magmaguy.resourcepackmanager.config.DefaultConfig; import com.magmaguy.resourcepackmanager.utils.SHA1Generator; import lombok.Getter; +import org.apache.hc.client5.http.classic.methods.HttpGet; +import org.apache.hc.client5.http.classic.methods.HttpPost; +import org.apache.hc.client5.http.impl.classic.CloseableHttpClient; +import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse; +import org.apache.hc.client5.http.impl.classic.HttpClients; +import org.apache.hc.core5.http.HttpEntity; import org.bukkit.Bukkit; +import java.io.BufferedInputStream; import java.io.File; +import java.io.FileOutputStream; +import java.io.InputStream; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.StandardCopyOption; public class ThirdPartyResourcePack implements GeneratorInterface { @Getter - private final File file; - private final boolean encrypts; - private final boolean distributes; - private final String reloadCommand; + private final String pluginName; + @Getter + private File file = null; + private String url; + private boolean encrypts; + private boolean distributes; + private boolean zips; + private boolean local; + private String reloadCommand; @Getter private boolean isEnabled; private String SHA1; @@ -25,21 +40,38 @@ public class ThirdPartyResourcePack implements GeneratorInterface { @Getter private File mixerResourcePack = null; @Getter + private String mixerFilename; + @Getter private int priority = -1; - public ThirdPartyResourcePack(String pluginName, String path, boolean encrypts, boolean distributes, String reloadCommand) { + public ThirdPartyResourcePack(String pluginName, String path, boolean encrypts, boolean distributes, boolean zips, boolean local, String reloadCommand) { + this.pluginName = pluginName; + this.mixerFilename = pluginName + "_resource_pack.zip"; isEnabled = Bukkit.getPluginManager().isPluginEnabled(pluginName); if (isEnabled) Logger.info("Initializing " + pluginName + "'s resource pack"); - this.file = new File(ResourcePackManager.plugin.getDataFolder().getParentFile().toPath().toString() + File.separatorChar + path); - if (!file.exists()) { + else return; + this.local = local; + if (local) + this.file = new File(ResourcePackManager.plugin.getDataFolder().getParentFile().toPath().toString() + File.separatorChar + path); + else + this.url = path; + if (file != null && !file.exists()) { Logger.warn("Found " + pluginName + " but could not find resource pack at location " + file.getPath() + " ! ResourcePackManager will not be able to merge the resource pack from this plugin."); isEnabled = false; + return; } this.encrypts = encrypts; this.distributes = distributes; this.reloadCommand = reloadCommand; - if (isEnabled) SHA1 = getSHA1(file); + this.zips = zips; + if (!zips) { + ZipFile.zip(file, getTarget().toString()); + file = new File(getTarget().toUri()); + resourcePackUpdated = true; + mixerResourcePack = file; + } + if (isEnabled && local) SHA1 = getSHA1(file); process(); if (DefaultConfig.getPriorityOrder().contains(pluginName)) priority = DefaultConfig.getPriorityOrder().indexOf(pluginName); @@ -47,18 +79,21 @@ public ThirdPartyResourcePack(String pluginName, String path, boolean encrypts, public void process() { if (!isEnabled) return; - if (mixerCloneExists()) { - if (getSHA1(new File(getTarget().toUri())).equals(SHA1)) { - mixerResourcePack = getTarget().toFile(); - return; - } else { - Logger.info("Clearing outdated resource pack in " + getTarget()); - getTarget().toFile().delete(); + if (local && zips) { + if (mixerCloneExists()) { + if (getSHA1(new File(getTarget().toUri())).equals(SHA1)) { + mixerResourcePack = getTarget().toFile(); + return; + } else { + Logger.info("Clearing outdated resource pack in " + getTarget()); + getTarget().toFile().delete(); + } } } if (encrypts) decrypt(); if (distributes) unpublish(); - cloneResourcePackFile(); + if (zips) + cloneResourcePackFile(); } private String getSHA1(File file) { @@ -82,15 +117,67 @@ public void unpublish() { @Override public void cloneResourcePackFile() { + if (local) cloneLocalRSP(); + else cloneRemoteRSP(); + resourcePackUpdated = true; + } + + private void cloneLocalRSP() { try { - Logger.info("Cloning resource pack from " + file.toPath()); - mixerResourcePack = Files.copy(Path.of(file.getAbsolutePath()), Path.of(getTarget().toAbsolutePath().toString()), StandardCopyOption.REPLACE_EXISTING).toFile(); + if (zips) { + Logger.info("Cloning resource pack from " + file.toPath()); + mixerResourcePack = Files.copy(Path.of(file.getAbsolutePath()), Path.of(getTarget().toAbsolutePath().toString()), StandardCopyOption.REPLACE_EXISTING).toFile(); + } } catch (Exception e) { Logger.warn("Failed to clone resource pack from " + file.getPath() + " to the mixer folder!"); e.printStackTrace(); } + } - resourcePackUpdated = true; + public void cloneRemoteRSP() { + Logger.info("Getting resource pack from remote URL! This is not ideal but not optional for some plugins. URL: " + url); + try (CloseableHttpClient httpClient = HttpClients.createDefault()) { + HttpGet httpGet = new HttpGet(url); + try (CloseableHttpResponse response = httpClient.execute(httpGet)) { + int statusCode = response.getCode(); + Logger.info("Response status code: " + statusCode); + + if (statusCode == 200) { + HttpEntity responseEntity = response.getEntity(); + if (responseEntity != null) { + // Save the response as a zip file + File zipFile = getTarget().toFile(); + if (zipFile.exists()) { + Logger.info("Target file exists, deleting it: " + zipFile.getAbsolutePath()); + zipFile.delete(); + } + zipFile.createNewFile(); + + try (InputStream inStream = new BufferedInputStream(responseEntity.getContent()); + FileOutputStream outStream = new FileOutputStream(zipFile)) { + + byte[] buffer = new byte[4096]; + int bytesRead; + while ((bytesRead = inStream.read(buffer)) != -1) { + outStream.write(buffer, 0, bytesRead); + } + + Logger.info("Successfully downloaded the resource pack to " + zipFile.getAbsolutePath()); + } catch (Exception e) { + Logger.warn("Failed to write resource pack from remote!"); + } + } else { + Logger.warn("Response entity is null"); + } + } else { + Logger.warn("Unexpected response status: " + statusCode); + } + } catch (Exception e) { + Logger.warn("Failed to communicate with remote server when downloading resource pack for plugin " + pluginName + "!"); + } + } catch (Exception e) { + Logger.warn("Failed to connect to url " + url + " to download resource pack for plugin " + pluginName); + } } @Override @@ -103,6 +190,6 @@ private boolean mixerCloneExists() { } private Path getTarget() { - return Path.of(ResourcePackManager.plugin.getDataFolder().toString(), "mixer", file.getName()); + return Path.of(ResourcePackManager.plugin.getDataFolder().toString(), "mixer", mixerFilename); } } diff --git a/src/main/java/com/magmaguy/resourcepackmanager/thirdparty/ValhallaMMO.java b/src/main/java/com/magmaguy/resourcepackmanager/thirdparty/ValhallaMMO.java new file mode 100644 index 0000000..b7abf4d --- /dev/null +++ b/src/main/java/com/magmaguy/resourcepackmanager/thirdparty/ValhallaMMO.java @@ -0,0 +1,15 @@ +package com.magmaguy.resourcepackmanager.thirdparty; + +import java.io.File; + +public class ValhallaMMO extends ThirdPartyResourcePack { + public ValhallaMMO() { + super("ValhallaMMO", + "ValhallaMMO" + File.separatorChar + "resourcepack", + false, + false, + false, + true, + ""); + } +} \ No newline at end of file diff --git a/src/main/java/com/magmaguy/resourcepackmanager/thirdparty/VaneCore.java b/src/main/java/com/magmaguy/resourcepackmanager/thirdparty/VaneCore.java new file mode 100644 index 0000000..54b69bb --- /dev/null +++ b/src/main/java/com/magmaguy/resourcepackmanager/thirdparty/VaneCore.java @@ -0,0 +1,13 @@ +package com.magmaguy.resourcepackmanager.thirdparty; + +public class VaneCore extends ThirdPartyResourcePack { + public VaneCore() { + super("vane-core", + "vane-resource-pack.zip", + false, + true, + true, + true, + ""); + } +} \ No newline at end of file diff --git a/src/main/java/com/magmaguy/resourcepackmanager/utils/ChatColorConverter.java b/src/main/java/com/magmaguy/resourcepackmanager/utils/ChatColorConverter.java new file mode 100644 index 0000000..cfcae6d --- /dev/null +++ b/src/main/java/com/magmaguy/resourcepackmanager/utils/ChatColorConverter.java @@ -0,0 +1,24 @@ +package com.magmaguy.resourcepackmanager.utils; + +import org.bukkit.ChatColor; + +import java.util.ArrayList; +import java.util.List; + +public class ChatColorConverter { + private ChatColorConverter() { + } + + public static String convert(String string) { + if (string == null) return ""; + return ChatColor.translateAlternateColorCodes('&', string); + } + + public static List convert(List list) { + if (list == null) return new ArrayList<>(); + List convertedList = new ArrayList<>(); + for (Object value : list) + convertedList.add(convert(value + "")); + return convertedList; + } +} diff --git a/src/main/java/com/magmaguy/resourcepackmanager/utils/SHA1Generator.java b/src/main/java/com/magmaguy/resourcepackmanager/utils/SHA1Generator.java index c1d4edb..5cd8649 100644 --- a/src/main/java/com/magmaguy/resourcepackmanager/utils/SHA1Generator.java +++ b/src/main/java/com/magmaguy/resourcepackmanager/utils/SHA1Generator.java @@ -1,8 +1,11 @@ package com.magmaguy.resourcepackmanager.utils; +import com.magmaguy.magmacore.util.Logger; + import java.io.File; import java.io.FileInputStream; import java.io.IOException; +import java.nio.charset.StandardCharsets; import java.security.DigestInputStream; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; @@ -21,6 +24,28 @@ public static String sha1CodeString(File file) throws IOException, NoSuchAlgorit } } + public static String sha1CodeString(String text) { + try { + MessageDigest digest = MessageDigest.getInstance("SHA-1"); + byte[] bytes = text.getBytes(StandardCharsets.UTF_8); + byte[] resultByteArry = digest.digest(bytes); + return bytesToHexString(resultByteArry); + } catch (NoSuchAlgorithmException e) { + Logger.warn("Failed to find SHA-1 algorithm."); + } + return null; + } + + public static byte[] sha1CodeByteArray(File file) throws IOException, NoSuchAlgorithmException { + FileInputStream fileInputStream = new FileInputStream(file); + MessageDigest digest = MessageDigest.getInstance("SHA-1"); + DigestInputStream digestInputStream = new DigestInputStream(fileInputStream, digest); + byte[] bytes = new byte[1024]; + // read all file content + while (digestInputStream.read(bytes) > 0) digest = digestInputStream.getMessageDigest(); + return digest.digest(); + } + public static String bytesToHexString(byte[] bytes) { StringBuilder sb = new StringBuilder(); for (byte b : bytes) { diff --git a/src/main/java/com/magmaguy/resourcepackmanager/utils/VersionChecker.java b/src/main/java/com/magmaguy/resourcepackmanager/utils/VersionChecker.java new file mode 100644 index 0000000..5341e96 --- /dev/null +++ b/src/main/java/com/magmaguy/resourcepackmanager/utils/VersionChecker.java @@ -0,0 +1,106 @@ +package com.magmaguy.resourcepackmanager.utils; + +import com.magmaguy.magmacore.util.Logger; +import com.magmaguy.resourcepackmanager.ResourcePackManager; +import org.bukkit.event.EventHandler; +import org.bukkit.event.Listener; +import org.bukkit.event.player.PlayerJoinEvent; +import org.bukkit.scheduler.BukkitRunnable; + +import java.io.IOException; +import java.net.URL; +import java.nio.charset.StandardCharsets; +import java.util.Scanner; + +public class VersionChecker { + private static boolean pluginIsUpToDate = true; + + private VersionChecker() { + } + + public static void checkPluginVersion() { + new BukkitRunnable() { + @Override + public void run() { + String currentVersion = ResourcePackManager.plugin.getDescription().getVersion(); + boolean snapshot = false; + if (currentVersion.contains("SNAPSHOT")) { + snapshot = true; + currentVersion = currentVersion.split("-")[0]; + } + String publicVersion = ""; + + try { + Logger.info("Latest public release is " + VersionChecker.readStringFromURL("https://api.spigotmc.org/legacy/update.php?resource=118574")); + Logger.info("Your version is " + ResourcePackManager.plugin.getDescription().getVersion()); + publicVersion = VersionChecker.readStringFromURL("https://api.spigotmc.org/legacy/update.php?resource=118574"); + } catch (IOException e) { + Logger.warn("Couldn't check latest version"); + return; + } + + if (Double.parseDouble(currentVersion.split("\\.")[0]) < Double.parseDouble(publicVersion.split("\\.")[0])) { + outOfDateHandler(); + return; + } + + if (Double.parseDouble(currentVersion.split("\\.")[0]) == Double.parseDouble(publicVersion.split("\\.")[0])) { + + if (Double.parseDouble(currentVersion.split("\\.")[1]) < Double.parseDouble(publicVersion.split("\\.")[1])) { + outOfDateHandler(); + return; + } + + if (Double.parseDouble(currentVersion.split("\\.")[1]) == Double.parseDouble(publicVersion.split("\\.")[1])) { + if (Double.parseDouble(currentVersion.split("\\.")[2]) < Double.parseDouble(publicVersion.split("\\.")[2])) { + outOfDateHandler(); + return; + } + } + } + + if (!snapshot) + Logger.info("You are running the latest version!"); + else + Logger.info("You are running a snapshot version! You can check for updates in the #releases channel on the Nightbreak Discord!"); + + pluginIsUpToDate = true; + } + }.runTaskAsynchronously(ResourcePackManager.plugin); + } + + private static String readStringFromURL(String url) throws IOException { + + try (Scanner scanner = new Scanner(new URL(url).openStream(), + StandardCharsets.UTF_8)) { + scanner.useDelimiter("\\A"); + return scanner.hasNext() ? scanner.next() : ""; + } + + } + + private static void outOfDateHandler() { + Logger.warn("A newer version of this plugin is available for download!"); + pluginIsUpToDate = false; + } + + public static class VersionCheckerEvents implements Listener { + @EventHandler + public void onPlayerLogin(PlayerJoinEvent event) { + + if (!event.getPlayer().hasPermission("elitemobs.versionnotification")) return; + + new BukkitRunnable() { + @Override + public void run() { + if (!event.getPlayer().isOnline()) return; + if (!pluginIsUpToDate) + event.getPlayer().sendMessage(com.magmaguy.magmacore.util.ChatColorConverter.convert("&cYour version of ResourcePackManager is outdated." + + " &aYou can download the latest version from &3&n&ohttps://www.spigotmc.org/resources/resource-pack-manager.118574/")); + } + }.runTaskLater(ResourcePackManager.plugin, 20L * 3); + + } + } + +} diff --git a/src/main/java/com/magmaguy/resourcepackmanager/utils/ZipFile.java b/src/main/java/com/magmaguy/resourcepackmanager/utils/ZipFile.java deleted file mode 100644 index 757dee4..0000000 --- a/src/main/java/com/magmaguy/resourcepackmanager/utils/ZipFile.java +++ /dev/null @@ -1,155 +0,0 @@ -package com.magmaguy.resourcepackmanager.utils; - -import com.magmaguy.resourcepackmanager.Logger; - -import java.io.*; -import java.util.zip.ZipEntry; -import java.util.zip.ZipInputStream; -import java.util.zip.ZipOutputStream; - -public class ZipFile { - private ZipFile() { - } - - public static boolean zip(File directory, String targetZipPath) { - if (!directory.exists()) { - Logger.warn("Failed to zip directory " + directory.getPath() + " because it does not exist!"); - return false; - } - - try { - ZipUtility.zip(directory, targetZipPath); - return true; - } catch (IOException e) { - e.printStackTrace(); - return false; - } - } - - public static File unzip(File zippedFile, File destinationUnzippedFile) throws IOException { - byte[] buffer = new byte[1024]; - ZipInputStream zipInputStream = new ZipInputStream(new FileInputStream(zippedFile)); - ZipEntry zipEntry = zipInputStream.getNextEntry(); - while (zipEntry != null) { - File newFile = newFile(destinationUnzippedFile, zipEntry); - if (zipEntry.isDirectory()) { - if (!newFile.isDirectory() && !newFile.mkdirs()) { - throw new IOException("Failed to create directory " + newFile); - } - } else { - // Fix for Windows-created archives - File parent = newFile.getParentFile(); - if (!parent.isDirectory() && !parent.mkdirs()) { - throw new IOException("Failed to create directory " + parent); - } - - // Write file content - FileOutputStream fileOutputStream = new FileOutputStream(newFile); - int len; - while ((len = zipInputStream.read(buffer)) > 0) { - fileOutputStream.write(buffer, 0, len); - } - fileOutputStream.close(); - } - newFile.setLastModified(zipEntry.getTime()); - zipEntry = zipInputStream.getNextEntry(); - } - zipInputStream.closeEntry(); - zipInputStream.close(); - return destinationUnzippedFile; - } - - private static File newFile(File destinationDir, ZipEntry zipEntry) throws IOException { - File destFile = new File(destinationDir, zipEntry.getName()); - - String destDirPath = destinationDir.getCanonicalPath(); - String destFilePath = destFile.getCanonicalPath(); - - if (!destFilePath.startsWith(destDirPath + File.separatorChar)) { - throw new IOException("Entry is outside of the target dir: " + zipEntry.getName()); - } - - return destFile; - } - - public static class ZipUtility { - /** - * A constant for buffer size used to read/write data - */ - private static final int BUFFER_SIZE = 4096; - - /** - * Compresses a list of files to a destination zip file - * - * @param file File to zip - * @param destZipFile The path of the destination zip file - * @throws FileNotFoundException - * @throws IOException - */ - public static void zip(File file, String destZipFile) throws FileNotFoundException, IOException { - FileOutputStream fileOutputStream = new FileOutputStream(destZipFile); - ZipOutputStream zos = new ZipOutputStream(fileOutputStream); - // This slight tweak avoids making the directory zipped be in the zipped file when what we are looking for is to - // zip the contents of the directory, outside of the directory itself - if (file.isDirectory()) { - for (File file1 : file.listFiles()) { - if (file1.isDirectory()) - zipDirectory(file1, file1.getName(), zos); - else - zipFile(file1, zos); - } - } else { - zipFile(file, zos); - } - zos.flush(); - zos.close(); - fileOutputStream.close(); - } - - /** - * Adds a directory to the current zip output stream - * - * @param folder the directory to be added - * @param parentFolder the path of parent directory - * @param zos the current zip output stream - * @throws FileNotFoundException - * @throws IOException - */ - private static void zipDirectory(File folder, String parentFolder, ZipOutputStream zos) throws FileNotFoundException, IOException { - for (File file : folder.listFiles()) { - if (file.isDirectory()) { - zipDirectory(file, parentFolder + "/" + file.getName(), zos); - continue; - } - ZipEntry zipEntry = new ZipEntry(parentFolder + "/" + file.getName()); - zippedySplit(zos, file, zipEntry); - } - } - - /** - * Adds a file to the current zip output stream - * - * @param file the file to be added - * @param zos the current zip output stream - * @throws FileNotFoundException - * @throws IOException - */ - private static void zipFile(File file, ZipOutputStream zos) throws FileNotFoundException, IOException { - ZipEntry zipEntry = new ZipEntry(file.getName()); - zippedySplit(zos, file, zipEntry); - } - - private static void zippedySplit(ZipOutputStream zos, File file, ZipEntry zipEntry) throws IOException { - zipEntry.setTime(0L); - zos.putNextEntry(zipEntry); - BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file)); - byte[] bytesIn = new byte[BUFFER_SIZE]; - int read; - while ((read = bis.read(bytesIn)) != -1) { - zos.write(bytesIn, 0, read); - } - zos.closeEntry(); - bis.close(); - } - } -} diff --git a/src/main/resources/ReadMe.md b/src/main/resources/ReadMe.md new file mode 100644 index 0000000..b7ca72c --- /dev/null +++ b/src/main/resources/ReadMe.md @@ -0,0 +1,51 @@ +### ResourcePackManager Data Policy and Compliance + +**ResourcePackManager**, developed by MagmaGuy for the Nightbreak game studio, includes an optional auto-host feature that temporarily hosts resource pack data on a remote server. + +As of this writing, the hosted data is fully anonymous and serves the sole purpose of simplifying the distribution of resource packs to clients of servers utilizing this service. Future versions of this document may be updated to reflect any changes in data policy and other related matters. + +This system complies with: +- **Directive 2000/31/EC** of the European Parliament and of the Council of 8 June 2000 +- **Regulation (EU) 2022/2065** of the European Parliament and of the Council of 19 October 2022 + +For data hosting transparency and compliance with these and other European norms, it is possible to obtain all data related to a server via the `/resourcepackmanager data_compliance_request` command. This command packages a full copy of all files and data associated with the requesting server. + +To request the takedown of your server's data, contact MagmaGuy at `magmaguy/at\nightbreak.io` (replace `/at\ ` with `@`). However, due to the system's design, data is only retained for up to 24h after a server using ResourcePackManager shuts down, making email requests largely unnecessary. Nonetheless, the option remains available to ensure full compliance with European norms. + +### Data Handling by ResourcePackManager and Nightbreak Servers + +1. **Resource Pack Creation** + - ResourcePackManager aggregates resource packs on your server into a single zipped file containing all custom content. + +2. **Initialization Request** + - An initialization request is sent to remote servers, creating a `.txt` file with a random UUID. This file can be obtained via the `/resourcepackmanager data_compliance_request`. + +3. **SHA1 Request** + - ResourcePackManager transmits the SHA1 code of your resource pack to the remote server, which is saved in the `.txt` file. + +4. **File Transmission** + - The zipped resource pack file is sent to the remote server, assigned the same UUID as the `.txt` file. This file can be obtained through `/resourcepackmanager data_compliance_request` and verified to be identical to the original in your output folder, as it is not modified by the Nightbreak servers. + +5. **"Still Alive" Ping** + - ResourcePackManager sends a "still alive" ping every 6 hours, transmitting the UUID to the server, which updates the timestamp in the `.txt` file. + - If no "still alive" ping is received for over 24 hours, all data associated with that UUID (the `.txt` file and the resource pack) is deleted from the Nightbreak servers. + +### Data Policy + +- **Pseudonymous Identification:** Nightbreak assigns a random UUID to your server's files each time the server reboots, ensuring no IP address or identifiable information is stored unless users manually add such information to their resource packs. +- **No Download Logging:** Nightbreak does not log any data related to download requests by Minecraft clients. +- **No Data Sales:** Data uploaded to Nightbreak is not, has never been, and will never be sold. +- **Compliance with Takedown Requests:** Nightbreak will comply with takedown requests from both server administrators and law enforcement agencies. +- **Automatic Data Removal:** All data associated with your server is automatically removed 24 hours after your server shuts down and is reuploaded on every restart for as long as ResourcePackManager is in use and using the auto-host feature. + +### Terms of service + +As of writing this, the hosting service is provided for free for all users of ResourcePackManager. + +It is the user's responsibility to ensure that the data uploaded to servers is not illegal and complies with any Mojang TOS as defined in their EULA. + +Abusing the service to host material other than resource packages may result in a permanent denial of service for the offending IP. + +The service may, at any time, cease or be modified in such a way that makes old versions unable to connect to it. + +We reserve the right to unilaterally terminate this service at any time and for any reason. \ No newline at end of file diff --git a/src/main/resources/pack.mcmeta b/src/main/resources/pack.mcmeta new file mode 100644 index 0000000..31d8f2e --- /dev/null +++ b/src/main/resources/pack.mcmeta @@ -0,0 +1,6 @@ +{ + "pack": { + "pack_format": 34, + "description": "= ResourcePackManagerRSP =" + } +} \ No newline at end of file diff --git a/src/main/resources/pack.png b/src/main/resources/pack.png new file mode 100644 index 0000000..485d0af Binary files /dev/null and b/src/main/resources/pack.png differ diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml index b02ba46..a4168fb 100644 --- a/src/main/resources/plugin.yml +++ b/src/main/resources/plugin.yml @@ -1,7 +1,8 @@ name: ResourcePackManager main: com.magmaguy.resourcepackmanager.ResourcePackManager -version: 1.0.0-SNAPSHOT +version: 1.2.1 api-version: 1.14 +author: MagmaGuy softdepend: - EliteMobs - FreeMinecraftModels @@ -9,6 +10,9 @@ softdepend: - Nova - Oraxen - ItemsAdder +- BackpackPlus +- vane-core +- RealisticSurvival commands: resourcepackmanager: