From ef36d28381ac56e7b8fcca6b81acb8c4d12c93ca Mon Sep 17 00:00:00 2001 From: XiaoMoMi Date: Fri, 18 Apr 2025 18:15:20 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E6=94=B9=E9=85=8D=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- bukkit/loader/src/main/resources/config.yml | 14 ++- .../item/recipe/BukkitRecipeManager.java | 2 +- .../item/recipe/RecipeEventListener.java | 2 +- .../bukkit/pack/BukkitPackManager.java | 6 +- .../core/pack/AbstractPackManager.java | 2 +- .../core/pack/host/ResourcePackHost.java | 6 - .../core/pack/host/ResourcePackHosts.java | 26 ++-- .../core/pack/host/impl/AlistHost.java | 14 +-- .../core/pack/host/impl/CustomApiHost.java | 119 ------------------ .../core/pack/host/impl/DropboxHost.java | 25 ++-- .../core/pack/host/impl/LobFileHost.java | 15 +-- .../core/pack/host/impl/OneDriveHost.java | 12 +- .../core/pack/host/impl/S3Host.java | 59 ++++----- .../core/pack/host/impl/SelfHost.java | 6 +- .../pack/host/impl/SelfHostHttpServer.java | 6 - .../core/plugin/config/Config.java | 39 ++++-- .../gui/category/ItemBrowserManagerImpl.java | 2 +- .../craftengine/core/util/MiscUtils.java | 3 +- 18 files changed, 102 insertions(+), 256 deletions(-) delete mode 100644 core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/CustomApiHost.java diff --git a/bukkit/loader/src/main/resources/config.yml b/bukkit/loader/src/main/resources/config.yml index 884d642cc..d4eb04482 100644 --- a/bukkit/loader/src/main/resources/config.yml +++ b/bukkit/loader/src/main/resources/config.yml @@ -65,24 +65,30 @@ resource-pack: - CustomNameplates/ResourcePack - BetterModel/build - BetterHud/build - send: + delivery: + # Send the resource pack on joining the server send-on-join: true - send-on-reload: true kick-if-declined: true prompt: "To fully experience our server, please accept our custom resource pack." # If you are hosting the resource pack by yourself, replace `localhost` with your server ip otherwise it would only work on your local pc # If using BungeeCord or Velocity, consider using a proxy-side plugin to handle resource pack delivery. # Read this page for more host types: https://mo-mi.gitbook.io/xiaomomi-plugins/craftengine/plugin-wiki/craftengine/resource-pack/host - host: + hosting: - type: "self_host" ip: "localhost" port: 8163 protocol: "http" deny-non-minecraft-request: true - local-file-path: "./generated/resource_pack.zip" rate-limit: max-requests: 3 reset-interval: 20 + # Upload the resource pack automatically on generation + # When disabled, you must manually trigger uploads using the /ce upload command + auto-upload: true + # The file to upload + file-to-upload: "./generated/resource_pack.zip" + # Resend the resource pack to players upon successful upload + resend-on-upload: true duplicated-files-handler: - term: type: any_of diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/BukkitRecipeManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/BukkitRecipeManager.java index 663ec5371..562f795a2 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/BukkitRecipeManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/BukkitRecipeManager.java @@ -14,8 +14,8 @@ import net.momirealms.craftengine.bukkit.util.RecipeUtils; import net.momirealms.craftengine.bukkit.util.Reflections; import net.momirealms.craftengine.core.item.CustomItem; import net.momirealms.craftengine.core.item.ItemBuildContext; -import net.momirealms.craftengine.core.item.recipe.Recipe; import net.momirealms.craftengine.core.item.recipe.*; +import net.momirealms.craftengine.core.item.recipe.Recipe; import net.momirealms.craftengine.core.item.recipe.vanilla.*; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.config.Config; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/RecipeEventListener.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/RecipeEventListener.java index 5d4bd2632..918f68fec 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/RecipeEventListener.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/item/recipe/RecipeEventListener.java @@ -12,8 +12,8 @@ import net.momirealms.craftengine.bukkit.util.ItemUtils; import net.momirealms.craftengine.bukkit.util.LegacyInventoryUtils; import net.momirealms.craftengine.bukkit.util.Reflections; import net.momirealms.craftengine.core.item.*; -import net.momirealms.craftengine.core.item.recipe.Recipe; import net.momirealms.craftengine.core.item.recipe.*; +import net.momirealms.craftengine.core.item.recipe.Recipe; import net.momirealms.craftengine.core.item.recipe.input.CraftingInput; import net.momirealms.craftengine.core.item.recipe.input.SingleItemInput; import net.momirealms.craftengine.core.item.recipe.input.SmithingInput; diff --git a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/pack/BukkitPackManager.java b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/pack/BukkitPackManager.java index 48cd579e6..d0134f042 100644 --- a/bukkit/src/main/java/net/momirealms/craftengine/bukkit/pack/BukkitPackManager.java +++ b/bukkit/src/main/java/net/momirealms/craftengine/bukkit/pack/BukkitPackManager.java @@ -1,7 +1,6 @@ package net.momirealms.craftengine.bukkit.pack; import net.momirealms.craftengine.bukkit.api.event.AsyncResourcePackGenerateEvent; -import net.momirealms.craftengine.bukkit.nms.FastNMS; import net.momirealms.craftengine.bukkit.plugin.BukkitCraftEngine; import net.momirealms.craftengine.bukkit.plugin.command.feature.ReloadCommand; import net.momirealms.craftengine.bukkit.plugin.user.BukkitServerPlayer; @@ -121,12 +120,13 @@ public class BukkitPackManager extends AbstractPackManager implements Listener { @EventHandler(priority = EventPriority.MONITOR) public void onAsyncResourcePackGenerate(AsyncResourcePackGenerateEvent event) { - resourcePackHost().upload(event.zipFilePath()).whenComplete((d, e) -> { + if (!Config.autoUpload()) return; + resourcePackHost().upload(Config.fileToUpload()).whenComplete((d, e) -> { if (e != null) { CraftEngine.instance().logger().warn("Failed to upload resource pack", e); return; } - if (!Config.sendPackOnReload()) return; + if (!Config.sendPackOnUpload()) return; for (BukkitServerPlayer player : this.plugin.networkManager().onlineUsers()) { sendResourcePack(player); } diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/AbstractPackManager.java b/core/src/main/java/net/momirealms/craftengine/core/pack/AbstractPackManager.java index d47cea0d8..d63079b13 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/AbstractPackManager.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/AbstractPackManager.java @@ -147,7 +147,7 @@ public abstract class AbstractPackManager implements PackManager { @Override public void load() { - List> list = Config.instance().settings().getMapList("resource-pack.send.host"); + List> list = Config.instance().settings().getMapList("resource-pack.delivery.hosting"); if (list == null || list.isEmpty()) { this.resourcePackHost = NoneHost.INSTANCE; } else { diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/host/ResourcePackHost.java b/core/src/main/java/net/momirealms/craftengine/core/pack/host/ResourcePackHost.java index ced5a92c6..1da990f1d 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/host/ResourcePackHost.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/host/ResourcePackHost.java @@ -1,7 +1,5 @@ package net.momirealms.craftengine.core.pack.host; -import net.momirealms.craftengine.core.plugin.CraftEngine; - import java.nio.file.Path; import java.util.List; import java.util.UUID; @@ -12,8 +10,4 @@ public interface ResourcePackHost { CompletableFuture> requestResourcePackDownloadLink(UUID player); CompletableFuture upload(Path resourcePackPath); - - static Path customPackPath(String path) { - return path.startsWith(".") ? CraftEngine.instance().dataFolderPath().resolve(path) : Path.of(path); - } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/host/ResourcePackHosts.java b/core/src/main/java/net/momirealms/craftengine/core/pack/host/ResourcePackHosts.java index 34ad5a5a1..c6207c254 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/host/ResourcePackHosts.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/host/ResourcePackHosts.java @@ -12,25 +12,23 @@ import java.util.Map; public class ResourcePackHosts { public static final Key NONE = Key.of("craftengine:none"); - public static final Key SELF_HOST = Key.of("craftengine:self_host"); - public static final Key EXTERNAL_HOST = Key.of("craftengine:external_host"); + public static final Key SELF = Key.of("craftengine:self"); + public static final Key EXTERNAL = Key.of("craftengine:external"); public static final Key LOBFILE = Key.of("craftengine:lobfile"); - public static final Key S3_HOST = Key.of("craftengine:s3_host"); - public static final Key CUSTOM_API_HOST = Key.of("craftengine:custom_api_host"); - public static final Key ALIST_HOST = Key.of("craftengine:alist_host"); - public static final Key DROPBOX_HOST = Key.of("craftengine:dropbox_host"); - public static final Key ONEDRIVE_HOST = Key.of("craftengine:onedrive_host"); + public static final Key S3 = Key.of("craftengine:s3"); + public static final Key ALIST = Key.of("craftengine:alist"); + public static final Key DROPBOX = Key.of("craftengine:dropbox"); + public static final Key ONEDRIVE = Key.of("craftengine:onedrive"); static { register(NONE, NoneHost.FACTORY); - register(SELF_HOST, SelfHost.FACTORY); - register(EXTERNAL_HOST, ExternalHost.FACTORY); + register(SELF, SelfHost.FACTORY); + register(EXTERNAL, ExternalHost.FACTORY); register(LOBFILE, LobFileHost.FACTORY); - register(S3_HOST, S3Host.FACTORY); - register(CUSTOM_API_HOST, CustomApiHost.FACTORY); - register(ALIST_HOST, AlistHost.FACTORY); - register(DROPBOX_HOST, DropboxHost.FACTORY); - register(ONEDRIVE_HOST, OneDriveHost.FACTORY); + register(S3, S3Host.FACTORY); + register(ALIST, AlistHost.FACTORY); + register(DROPBOX, DropboxHost.FACTORY); + register(ONEDRIVE, OneDriveHost.FACTORY); } public static void register(Key key, ResourcePackHostFactory factory) { diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/AlistHost.java b/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/AlistHost.java index 4bebf88ae..1f27a3bb5 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/AlistHost.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/AlistHost.java @@ -39,7 +39,6 @@ public class AlistHost implements ResourcePackHost { private final Duration jwtTokenExpiration; private final String filePath; private final boolean disabledUpload; - private final Path localFilePath; private final ProxySelector proxy; private Pair jwtToken; private String cacheSha1; @@ -52,7 +51,6 @@ public class AlistHost implements ResourcePackHost { Duration jwtTokenExpiration, String filePath, boolean disabledUpload, - String localFilePath, ProxySelector proxy) { this.apiUrl = apiUrl; this.userName = userName; @@ -62,7 +60,6 @@ public class AlistHost implements ResourcePackHost { this.jwtTokenExpiration = jwtTokenExpiration; this.filePath = filePath; this.disabledUpload = disabledUpload; - this.localFilePath = localFilePath == null ? null : Path.of(localFilePath); this.proxy = proxy; this.readCacheFromDisk(); } @@ -117,8 +114,6 @@ public class AlistHost implements ResourcePackHost { return CompletableFuture.completedFuture(null); } CompletableFuture future = new CompletableFuture<>(); - if (this.localFilePath != null) resourcePackPath = this.localFilePath; - Path finalResourcePackPath = resourcePackPath; CraftEngine.instance().scheduler().executeAsync(() -> { try (HttpClient client = HttpClient.newBuilder().proxy(proxy).build()) { HttpRequest request = HttpRequest.newBuilder() @@ -129,7 +124,7 @@ public class AlistHost implements ResourcePackHost { .header("overwrite", "true") .header("password", filePassword) .header("Content-Type", "application/x-zip-compressed") - .PUT(HttpRequest.BodyPublishers.ofFile(finalResourcePackPath)) + .PUT(HttpRequest.BodyPublishers.ofFile(resourcePackPath)) .build(); long requestStart = System.currentTimeMillis(); CraftEngine.instance().logger().info("[Alist] Starting file upload..."); @@ -137,9 +132,9 @@ public class AlistHost implements ResourcePackHost { .thenAccept(response -> { long uploadTime = System.currentTimeMillis() - requestStart; if (response.statusCode() == 200) { - cacheSha1 = HashUtils.calculateLocalFileSha1(finalResourcePackPath); + cacheSha1 = HashUtils.calculateLocalFileSha1(resourcePackPath); saveCacheToDisk(); - CraftEngine.instance().logger().info("[Alist] Upload resource pack success after " + uploadTime + "ms"); + CraftEngine.instance().logger().info("[Alist] Upload resource pack successfully in " + uploadTime + "ms"); future.complete(null); } else { future.completeExceptionally(new RuntimeException("Upload failed with status code: " + response.statusCode())); @@ -286,9 +281,8 @@ public class AlistHost implements ResourcePackHost { throw new IllegalArgumentException("'file-path' cannot be empty for Alist host"); } boolean disabledUpload = (boolean) arguments.getOrDefault("disabled-upload", false); - String localFilePath = (String) arguments.get("local-file-path"); ProxySelector proxy = MiscUtils.getProxySelector(arguments.get("proxy")); - return new AlistHost(apiUrl, userName, password, filePassword, otpCode, jwtTokenExpiration, filePath, disabledUpload, localFilePath, proxy); + return new AlistHost(apiUrl, userName, password, filePassword, otpCode, jwtTokenExpiration, filePath, disabledUpload, proxy); } } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/CustomApiHost.java b/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/CustomApiHost.java deleted file mode 100644 index e5b45e71f..000000000 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/CustomApiHost.java +++ /dev/null @@ -1,119 +0,0 @@ -package net.momirealms.craftengine.core.pack.host.impl; - -import net.momirealms.craftengine.core.pack.host.ResourcePackDownloadData; -import net.momirealms.craftengine.core.pack.host.ResourcePackHost; -import net.momirealms.craftengine.core.pack.host.ResourcePackHostFactory; -import net.momirealms.craftengine.core.plugin.CraftEngine; -import net.momirealms.craftengine.core.util.GsonHelper; -import net.momirealms.craftengine.core.util.MiscUtils; - -import java.io.FileNotFoundException; -import java.net.ProxySelector; -import java.net.URI; -import java.net.http.HttpClient; -import java.net.http.HttpRequest; -import java.net.http.HttpResponse; -import java.nio.file.Path; -import java.util.List; -import java.util.Map; -import java.util.UUID; -import java.util.concurrent.CompletableFuture; - -public class CustomApiHost implements ResourcePackHost { - public static final Factory FACTORY = new Factory(); - private final String apiUrl; - private final String authKey; - private final Path localFilePath; - private final ProxySelector proxy; - - public CustomApiHost(String apiUrl, String authKey, String localFilePath, ProxySelector proxy) { - this.apiUrl = apiUrl; - this.authKey = authKey; - this.localFilePath = localFilePath == null ? null : Path.of(localFilePath); - this.proxy = proxy; - } - - @Override - public CompletableFuture> requestResourcePackDownloadLink(UUID player) { - CompletableFuture> future = new CompletableFuture<>(); - CraftEngine.instance().scheduler().executeAsync(() -> { - try (HttpClient client = HttpClient.newBuilder().proxy(proxy).build()) { - HttpRequest request = HttpRequest.newBuilder() - .uri(URI.create(apiUrl + "/api/v1/get-download-link?uuid=" + player)) - .header("Authorization", authKey) - .GET() - .build(); - client.sendAsync(request, HttpResponse.BodyHandlers.ofString()) - .thenAccept(response -> { - if (response.statusCode() == 200) { - Map jsonData = GsonHelper.parseJsonToMap(response.body()); - String url = (String) jsonData.get("url"); - String sha1 = (String) jsonData.get("sha1"); - UUID uuid = UUID.fromString(sha1); - future.complete(List.of(new ResourcePackDownloadData(url, uuid, sha1))); - } - }) - .exceptionally(ex -> { - CraftEngine.instance().logger().warn("[CustomApi] Get resource pack download link failed", ex); - future.completeExceptionally(ex); - return null; - }); - } - }); - return future; - } - - @Override - public CompletableFuture upload(Path resourcePackPath) { - CompletableFuture future = new CompletableFuture<>(); - if (this.localFilePath != null) resourcePackPath = this.localFilePath; - Path finalResourcePackPath = resourcePackPath; - CraftEngine.instance().scheduler().executeAsync(() -> { - try (HttpClient client = HttpClient.newBuilder().proxy(proxy).build()) { - HttpRequest request = HttpRequest.newBuilder() - .uri(URI.create(apiUrl + "/api/v1/upload-resource-pack")) - .header("Authorization", authKey) - .header("Content-Type", "application/octet-stream") - .PUT(HttpRequest.BodyPublishers.ofFile(finalResourcePackPath)) - .build(); - long uploadStart = System.currentTimeMillis(); - CraftEngine.instance().logger().info("[CustomApi] Starting file upload..."); - client.sendAsync(request, HttpResponse.BodyHandlers.ofString()) - .thenAccept(response -> { - long uploadTime = System.currentTimeMillis() - uploadStart; - CraftEngine.instance().logger().info( - "[CustomApi] Upload request completed in " + uploadTime + "ms"); - if (response.statusCode() == 200) { - future.complete(null); - } else { - future.completeExceptionally(new RuntimeException("Upload failed with status code: " + response.statusCode())); - } - }) - .exceptionally(ex -> { - CraftEngine.instance().logger().warn("[CustomApi] Upload resource pack failed", ex); - future.completeExceptionally(ex); - return null; - }); - } catch (FileNotFoundException e) { - CraftEngine.instance().logger().warn("[CustomApi] Resource pack not found: " + finalResourcePackPath); - future.completeExceptionally(e); - } - }); - return future; - } - - public static class Factory implements ResourcePackHostFactory { - - @Override - public ResourcePackHost create(Map arguments) { - String apiUrl = (String) arguments.get("api-url"); - String authKey = (String) arguments.getOrDefault("auth-key", ""); - if (apiUrl == null || apiUrl.isEmpty()) { - throw new IllegalArgumentException("'api-url' cannot be empty for custom api host"); - } - String localFilePath = (String) arguments.get("local-file-path"); - ProxySelector proxy = MiscUtils.getProxySelector(arguments.get("proxy")); - return new CustomApiHost(apiUrl, authKey, localFilePath, proxy); - } - } -} diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/DropboxHost.java b/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/DropboxHost.java index 43784ad8f..1d9252667 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/DropboxHost.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/DropboxHost.java @@ -32,17 +32,15 @@ public class DropboxHost implements ResourcePackHost { private final String accessToken; private final String uploadPath; private final ProxySelector proxy; - private final Path localFilePath; private String url; private String sha1; private UUID uuid; - public DropboxHost(String accessToken, String uploadPath, ProxySelector proxy, String localFilePath) { + public DropboxHost(String accessToken, String uploadPath, ProxySelector proxy) { this.accessToken = accessToken; this.uploadPath = uploadPath; this.proxy = proxy; - this.localFilePath = localFilePath == null ? null : Path.of(localFilePath); readCacheFromDisk(); } @@ -100,12 +98,8 @@ public class DropboxHost implements ResourcePackHost { @Override public CompletableFuture upload(Path resourcePackPath) { CompletableFuture future = new CompletableFuture<>(); - if (this.localFilePath != null) resourcePackPath = this.localFilePath; - - Path finalResourcePackPath = resourcePackPath; - CraftEngine.instance().scheduler().executeAsync(() -> { - String sha1 = HashUtils.calculateLocalFileSha1(finalResourcePackPath); + String sha1 = HashUtils.calculateLocalFileSha1(resourcePackPath); try (HttpClient client = HttpClient.newBuilder().proxy(proxy).build()) { JsonObject apiArg = new JsonObject(); apiArg.addProperty("path", uploadPath); @@ -115,7 +109,7 @@ public class DropboxHost implements ResourcePackHost { .header("Authorization", "Bearer " + accessToken) .header("Content-Type", "application/octet-stream") .header("Dropbox-API-Arg", apiArg.toString()) - .POST(HttpRequest.BodyPublishers.ofFile(finalResourcePackPath)) + .POST(HttpRequest.BodyPublishers.ofFile(resourcePackPath)) .build(); long uploadStart = System.currentTimeMillis(); @@ -152,26 +146,26 @@ public class DropboxHost implements ResourcePackHost { } private String getDownloadUrl() { - try (HttpClient client = HttpClient.newBuilder().proxy(proxy).build()) { + try (HttpClient client = HttpClient.newBuilder().proxy(this.proxy).build()) { try { JsonObject requestJson = new JsonObject(); - requestJson.addProperty("path", uploadPath); + requestJson.addProperty("path", this.uploadPath); JsonObject settingsJson = new JsonObject(); settingsJson.addProperty("requested_visibility", "public"); requestJson.add("settings", settingsJson); HttpRequest request = HttpRequest.newBuilder() .uri(URI.create("https://api.dropboxapi.com/2/sharing/create_shared_link_with_settings")) - .header("Authorization", "Bearer " + accessToken) + .header("Authorization", "Bearer " + this.accessToken) .header("Content-Type", "application/json") .POST(HttpRequest.BodyPublishers.ofString(requestJson.toString())) .build(); HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString()); if (response.statusCode() == 409) { JsonObject listJson = new JsonObject(); - listJson.addProperty("path", uploadPath); + listJson.addProperty("path", this.uploadPath); HttpRequest listLinksRequest = HttpRequest.newBuilder() .uri(URI.create("https://api.dropboxapi.com/2/sharing/list_shared_links")) - .header("Authorization", "Bearer " + accessToken) + .header("Authorization", "Bearer " + this.accessToken) .header("Content-Type", "application/json") .POST(HttpRequest.BodyPublishers.ofString(listJson.toString())) .build(); @@ -200,14 +194,13 @@ public class DropboxHost implements ResourcePackHost { @Override public ResourcePackHost create(Map arguments) { - String localFilePath = (String) arguments.get("local-file-path"); String accessToken = (String) arguments.get("access-token"); if (accessToken == null || accessToken.isEmpty()) { throw new RuntimeException("Missing 'access-token' for DropboxHost"); } String uploadPath = (String) arguments.getOrDefault("upload-path", "/resource_pack.zip"); ProxySelector proxy = MiscUtils.getProxySelector(arguments.get("proxy")); - return new DropboxHost(accessToken, uploadPath, proxy, localFilePath); + return new DropboxHost(accessToken, uploadPath, proxy); } } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/LobFileHost.java b/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/LobFileHost.java index 3b9c6d950..e1415dca1 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/LobFileHost.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/LobFileHost.java @@ -27,7 +27,6 @@ import java.util.concurrent.CompletableFuture; public class LobFileHost implements ResourcePackHost { public static final Factory FACTORY = new Factory(); - private final Path forcedPackPath; private final String apiKey; private final ProxySelector proxy; private AccountInfo accountInfo; @@ -36,8 +35,7 @@ public class LobFileHost implements ResourcePackHost { private String sha1; private UUID uuid; - public LobFileHost(String localFile, String apiKey, ProxySelector proxy) { - this.forcedPackPath = localFile == null ? null : ResourcePackHost.customPackPath(localFile); + public LobFileHost(String apiKey, ProxySelector proxy) { this.apiKey = apiKey; this.proxy = proxy; this.readCacheFromDisk(); @@ -107,13 +105,9 @@ public class LobFileHost implements ResourcePackHost { public CompletableFuture upload(Path resourcePackPath) { CompletableFuture future = new CompletableFuture<>(); long totalStartTime = System.currentTimeMillis(); - - if (this.forcedPackPath != null) resourcePackPath = forcedPackPath; - Path finalResourcePackPath = resourcePackPath; - CraftEngine.instance().scheduler().executeAsync(() -> { try { - Map hashes = calculateHashes(finalResourcePackPath); + Map hashes = calculateHashes(resourcePackPath); String sha1Hash = hashes.get("SHA-1"); String sha256Hash = hashes.get("SHA-256"); @@ -124,7 +118,7 @@ public class LobFileHost implements ResourcePackHost { .uri(URI.create("https://lobfile.com/api/v3/upload.php")) .header("X-API-Key", apiKey) .header("Content-Type", "multipart/form-data; boundary=" + boundary) - .POST(buildMultipartBody(finalResourcePackPath, sha256Hash, boundary)) + .POST(buildMultipartBody(resourcePackPath, sha256Hash, boundary)) .build(); long uploadStart = System.currentTimeMillis(); @@ -263,13 +257,12 @@ public class LobFileHost implements ResourcePackHost { @Override public ResourcePackHost create(Map arguments) { - String localFilePath = (String) arguments.get("local-file-path"); String apiKey = (String) arguments.get("api-key"); if (apiKey == null || apiKey.isEmpty()) { throw new RuntimeException("Missing 'api-key' for LobFileHost"); } ProxySelector proxy = MiscUtils.getProxySelector(arguments.get("proxy")); - return new LobFileHost(localFilePath, apiKey, proxy); + return new LobFileHost(apiKey, proxy); } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/OneDriveHost.java b/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/OneDriveHost.java index 5228bdde6..e3613d6d5 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/OneDriveHost.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/OneDriveHost.java @@ -34,7 +34,6 @@ public class OneDriveHost implements ResourcePackHost { private final String clientSecret; private final ProxySelector proxy; private final String filePath; - private final Path localFilePath; private Tuple refreshToken; private String sha1; private String fileId; @@ -43,13 +42,11 @@ public class OneDriveHost implements ResourcePackHost { String clientSecret, String refreshToken, String filePath, - String localFilePath, ProxySelector proxy) { this.clientId = clientId; this.clientSecret = clientSecret; this.proxy = proxy; this.filePath = filePath; - this.localFilePath = localFilePath == null ? null : Path.of(localFilePath); this.refreshToken = Tuple.of(refreshToken, "", new Date()); readCacheFromDisk(); } @@ -140,17 +137,15 @@ public class OneDriveHost implements ResourcePackHost { @Override public CompletableFuture upload(Path resourcePackPath) { CompletableFuture future = new CompletableFuture<>(); - if (this.localFilePath != null) resourcePackPath = this.localFilePath; - Path finalResourcePackPath = resourcePackPath; CraftEngine.instance().scheduler().executeAsync(() -> { - sha1 = HashUtils.calculateLocalFileSha1(finalResourcePackPath); + sha1 = HashUtils.calculateLocalFileSha1(resourcePackPath); String accessToken = getOrRefreshJwtToken(); try (HttpClient client = HttpClient.newBuilder().proxy(proxy).build()) { HttpRequest request = HttpRequest.newBuilder() .uri(URI.create("https://graph.microsoft.com/v1.0/drive/root:/" + filePath + ":/content")) .header("Authorization", "Bearer " + accessToken) .header("Content-Type", "application/octet-stream") - .PUT(HttpRequest.BodyPublishers.ofFile(finalResourcePackPath)) + .PUT(HttpRequest.BodyPublishers.ofFile(resourcePackPath)) .build(); long uploadStart = System.currentTimeMillis(); CraftEngine.instance().logger().info("[OneDrive] Starting file upload..."); @@ -242,9 +237,8 @@ public class OneDriveHost implements ResourcePackHost { if (filePath == null || filePath.isEmpty()) { throw new RuntimeException("Missing 'file-path' for OneDriveHost"); } - String localFilePath = (String) arguments.get("local-file-path"); ProxySelector proxy = MiscUtils.getProxySelector(arguments.get("proxy")); - return new OneDriveHost(clientId, clientSecret, refreshToken, filePath, localFilePath, proxy); + return new OneDriveHost(clientId, clientSecret, refreshToken, filePath, proxy); } } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/S3Host.java b/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/S3Host.java index fc55dfb17..97d04f4cd 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/S3Host.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/S3Host.java @@ -38,41 +38,36 @@ import java.util.concurrent.CompletionException; public class S3Host implements ResourcePackHost { public static final Factory FACTORY = new Factory(); private final S3AsyncClient s3AsyncClient; - private final S3Presigner presigner; + private final S3Presigner preSigner; private final String bucket; private final String uploadPath; private final String cdnDomain; private final String cdnProtocol; private final Duration validity; - private final Path localFilePath; public S3Host( S3AsyncClient s3AsyncClient, - S3Presigner presigner, + S3Presigner preSigner, String bucket, String uploadPath, String cdnDomain, String cdnProtocol, - Duration validity, - String localFilePath + Duration validity ) { this.s3AsyncClient = s3AsyncClient; - this.presigner = presigner; + this.preSigner = preSigner; this.bucket = bucket; this.uploadPath = uploadPath; this.cdnDomain = cdnDomain; this.cdnProtocol = cdnProtocol; this.validity = validity; - this.localFilePath = localFilePath == null ? null : ResourcePackHost.customPackPath(localFilePath); } @Override public CompletableFuture> requestResourcePackDownloadLink(UUID player) { - String objectKey = uploadPath; - - return s3AsyncClient.headObject(HeadObjectRequest.builder() - .bucket(bucket) - .key(objectKey) + return this.s3AsyncClient.headObject(HeadObjectRequest.builder() + .bucket(this.bucket) + .key(this.uploadPath) .build()) .handle((headResponse, exception) -> { if (exception != null) { @@ -90,16 +85,16 @@ public class S3Host implements ResourcePackHost { } String sha1 = headResponse.metadata().get("sha1"); if (sha1 == null) { - CraftEngine.instance().logger().warn("[S3] SHA1 metadata missing for object: " + objectKey); - throw new CompletionException(new IllegalStateException("SHA1 metadata missing for object: " + objectKey)); + CraftEngine.instance().logger().warn("[S3] SHA1 metadata missing for object: " + this.uploadPath); + throw new CompletionException(new IllegalStateException("SHA1 metadata missing for object: " + this.uploadPath)); } GetObjectPresignRequest presignRequest = GetObjectPresignRequest.builder() - .signatureDuration(validity) - .getObjectRequest(b -> b.bucket(bucket).key(objectKey)) + .signatureDuration(this.validity) + .getObjectRequest(b -> b.bucket(this.bucket).key(this.uploadPath)) .build(); return Collections.singletonList( ResourcePackDownloadData.of( - replaceWithCdnUrl(presigner.presignGetObject(presignRequest).url()), + replaceWithCdnUrl(this.preSigner.presignGetObject(presignRequest).url()), UUID.nameUUIDFromBytes(sha1.getBytes(StandardCharsets.UTF_8)), sha1 ) @@ -109,30 +104,28 @@ public class S3Host implements ResourcePackHost { @Override public CompletableFuture upload(Path resourcePackPath) { - if (this.localFilePath != null) resourcePackPath = this.localFilePath; - String objectKey = uploadPath; String sha1 = HashUtils.calculateLocalFileSha1(resourcePackPath); PutObjectRequest putObjectRequest = PutObjectRequest.builder() - .bucket(bucket) - .key(objectKey) + .bucket(this.bucket) + .key(this.uploadPath) .metadata(Map.of("sha1", sha1)) .build(); long uploadStart = System.currentTimeMillis(); CraftEngine.instance().logger().info("[S3] Starting file upload..."); - return s3AsyncClient.putObject(putObjectRequest, AsyncRequestBody.fromFile(resourcePackPath)) + return this.s3AsyncClient.putObject(putObjectRequest, AsyncRequestBody.fromFile(resourcePackPath)) .handle((response, exception) -> { if (exception != null) { Throwable cause = exception instanceof CompletionException ? exception.getCause() : exception; CraftEngine.instance().logger().warn( - "[S3] Upload to " + objectKey + " failed! Reason: " + + "[S3] Upload to " + this.uploadPath + " failed! Reason: " + cause.getClass().getSimpleName() + " - " + cause.getMessage() ); throw new CompletionException("Resource pack upload failed", cause); } CraftEngine.instance().logger().info( - "[S3] Upload to " + objectKey + " complete! Took " + + "[S3] Upload to " + this.uploadPath + " complete! Took " + (System.currentTimeMillis() - uploadStart) + "ms" ); return null; @@ -140,8 +133,8 @@ public class S3Host implements ResourcePackHost { } private String replaceWithCdnUrl(URL originalUrl) { - if (cdnDomain == null) return originalUrl.toString(); - return cdnProtocol + "://" + cdnDomain + if (this.cdnDomain == null) return originalUrl.toString(); + return this.cdnProtocol + "://" + this.cdnDomain + originalUrl.getPath() + (originalUrl.getQuery() != null ? "?" + originalUrl.getQuery() : ""); } @@ -174,7 +167,6 @@ public class S3Host implements ResourcePackHost { if (uploadPath == null || uploadPath.isEmpty()) { throw new IllegalArgumentException("'upload-path' cannot be empty for S3 host"); } - String localFilePath = (String) arguments.get("local-file-path"); boolean useLegacySignature = (boolean) arguments.getOrDefault("use-legacy-signature", true); Duration validity = Duration.ofSeconds((int) arguments.getOrDefault("validity", 10)); @@ -219,22 +211,13 @@ public class S3Host implements ResourcePackHost { S3AsyncClient s3AsyncClient = s3AsyncClientBuilder.build(); - S3Presigner presigner = S3Presigner.builder() + S3Presigner preSigner = S3Presigner.builder() .endpointOverride(URI.create(protocol + "://" + endpoint)) .region(Region.of(region)) .credentialsProvider(StaticCredentialsProvider.create(credentials)) .build(); - return new S3Host( - s3AsyncClient, - presigner, - bucket, - uploadPath, - cdnDomain, - cdnProtocol, - validity, - localFilePath - ); + return new S3Host(s3AsyncClient, preSigner, bucket, uploadPath, cdnDomain, cdnProtocol, validity); } } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/SelfHost.java b/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/SelfHost.java index b50b1d34d..ce881c3bb 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/SelfHost.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/SelfHost.java @@ -4,6 +4,7 @@ import net.momirealms.craftengine.core.pack.host.ResourcePackDownloadData; import net.momirealms.craftengine.core.pack.host.ResourcePackHost; import net.momirealms.craftengine.core.pack.host.ResourcePackHostFactory; import net.momirealms.craftengine.core.plugin.CraftEngine; +import net.momirealms.craftengine.core.plugin.config.Config; import net.momirealms.craftengine.core.util.MiscUtils; import java.nio.file.Path; @@ -17,7 +18,7 @@ public class SelfHost implements ResourcePackHost { private static final SelfHost INSTANCE = new SelfHost(); public SelfHost() { - SelfHostHttpServer.instance().readResourcePack(CraftEngine.instance().packManager().resourcePackPath()); + SelfHostHttpServer.instance().readResourcePack(Config.fileToUpload()); } @Override @@ -56,7 +57,6 @@ public class SelfHost implements ResourcePackHost { } String protocol = (String) arguments.getOrDefault("protocol", "http"); boolean denyNonMinecraftRequest = (boolean) arguments.getOrDefault("deny-non-minecraft-request", true); - String localFilePath = (String) arguments.get("local-file-path"); Map rateMap = MiscUtils.castToMap(arguments.get("rate-map"), true); int maxRequests = 5; int resetInterval = 20_000; @@ -64,7 +64,7 @@ public class SelfHost implements ResourcePackHost { maxRequests = (int) rateMap.getOrDefault("max-requests", 5); resetInterval = (int) rateMap.getOrDefault("reset-interval", 20) * 1000; } - selfHostHttpServer.updateProperties(ip, port, denyNonMinecraftRequest, protocol, localFilePath, maxRequests, resetInterval); + selfHostHttpServer.updateProperties(ip, port, denyNonMinecraftRequest, protocol, maxRequests, resetInterval); return INSTANCE; } } diff --git a/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/SelfHostHttpServer.java b/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/SelfHostHttpServer.java index 48b2ad634..67685b733 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/SelfHostHttpServer.java +++ b/core/src/main/java/net/momirealms/craftengine/core/pack/host/impl/SelfHostHttpServer.java @@ -6,9 +6,7 @@ import com.sun.net.httpserver.HttpExchange; import com.sun.net.httpserver.HttpHandler; import com.sun.net.httpserver.HttpServer; import net.momirealms.craftengine.core.pack.host.ResourcePackDownloadData; -import net.momirealms.craftengine.core.pack.host.ResourcePackHost; import net.momirealms.craftengine.core.plugin.CraftEngine; -import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import java.io.IOException; @@ -55,18 +53,15 @@ public class SelfHostHttpServer { private volatile byte[] resourcePackBytes; private String packHash; private UUID packUUID; - private Path localFilePath = null; public void updateProperties(String ip, int port, boolean denyNonMinecraft, String protocol, - String localFile, int maxRequests, int resetInternal) { this.ip = ip; this.port = port; - this.localFilePath = localFile == null ? null : ResourcePackHost.customPackPath(localFile); this.denyNonMinecraft = denyNonMinecraft; this.protocol = protocol; this.rateLimit = maxRequests; @@ -116,7 +111,6 @@ public class SelfHostHttpServer { } public void readResourcePack(Path path) { - if (this.localFilePath != null) path = this.localFilePath; try { if (Files.exists(path)) { this.resourcePackBytes = Files.readAllBytes(path); diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/config/Config.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/config/Config.java index cd862445c..98a3275e6 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/config/Config.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/config/Config.java @@ -79,9 +79,11 @@ public class Config { protected float resource_pack$supported_version$min; protected float resource_pack$supported_version$max; - protected boolean resource_pack$send$kick_if_declined; - protected boolean resource_pack$send$send_on_join; - protected boolean resource_pack$send$send_on_reload; + protected boolean resource_pack$delivery$kick_if_declined; + protected boolean resource_pack$delivery$send_on_join; + protected boolean resource_pack$delivery$resend_on_upload; + protected boolean resource_pack$delivery$auto_upload; + protected Path resource_pack$delivery$file_to_upload; protected Component resource_pack$send$prompt; protected int performance$max_block_chain_update_limit; @@ -202,11 +204,12 @@ public class Config { resource_pack$supported_version$min = getVersion(config.get("resource-pack.supported-version.min", "1.20").toString()); resource_pack$supported_version$max = getVersion(config.get("resource-pack.supported-version.max", "LATEST").toString()); resource_pack$merge_external_folders = config.getStringList("resource-pack.merge-external-folders"); - //resource_pack$send$mode = HostMode.valueOf(config.getString("resource-pack.send.mode", "self-host").replace("-", "_").toUpperCase(Locale.ENGLISH)); - resource_pack$send$send_on_join = config.getBoolean("resource-pack.send.send-on-join", true); - resource_pack$send$send_on_reload = config.getBoolean("resource-pack.send.send-on-reload", true); - resource_pack$send$kick_if_declined = config.getBoolean("resource-pack.send.kick-if-declined", true); - resource_pack$send$prompt = AdventureHelper.miniMessage().deserialize(config.getString("resource-pack.send.prompt", "To fully experience our server, please accept our custom resource pack.")); + resource_pack$delivery$send_on_join = config.getBoolean("resource-pack.delivery.send-on-join", true); + resource_pack$delivery$resend_on_upload = config.getBoolean("resource-pack.delivery.resend-on-upload", true); + resource_pack$delivery$kick_if_declined = config.getBoolean("resource-pack.delivery.kick-if-declined", true); + resource_pack$delivery$auto_upload = config.getBoolean("resource-pack.delivery.auto-upload", true); + resource_pack$delivery$file_to_upload = resolvePath(config.getString("resource-pack.delivery.file-to-upload", "./generated/resource_pack.zip")); + resource_pack$send$prompt = AdventureHelper.miniMessage().deserialize(config.getString("resource-pack.delivery.prompt", "To fully experience our server, please accept our custom resource pack.")); resource_pack$protection$crash_tools$method_1 = config.getBoolean("resource-pack.protection.crash-tools.method-1", false); resource_pack$protection$crash_tools$method_2 = config.getBoolean("resource-pack.protection.crash-tools.method-2", false); resource_pack$protection$crash_tools$method_3 = config.getBoolean("resource-pack.protection.crash-tools.method-3", false); @@ -430,7 +433,7 @@ public class Config { } public static boolean kickOnDeclined() { - return instance.resource_pack$send$kick_if_declined; + return instance.resource_pack$delivery$kick_if_declined; } public static Component resourcePackPrompt() { @@ -438,11 +441,19 @@ public class Config { } public static boolean sendPackOnJoin() { - return instance.resource_pack$send$send_on_join; + return instance.resource_pack$delivery$send_on_join; } - public static boolean sendPackOnReload() { - return instance.resource_pack$send$send_on_reload; + public static boolean sendPackOnUpload() { + return instance.resource_pack$delivery$resend_on_upload; + } + + public static boolean autoUpload() { + return instance.resource_pack$delivery$auto_upload; + } + + public static Path fileToUpload() { + return instance.resource_pack$delivery$file_to_upload; } public static List resolutions() { @@ -687,6 +698,10 @@ public class Config { return configFile; } + private Path resolvePath(String path) { + return path.startsWith(".") ? CraftEngine.instance().dataFolderPath().resolve(path) : Path.of(path); + } + public YamlDocument settings() { if (config == null) { throw new IllegalStateException("Main config not loaded"); diff --git a/core/src/main/java/net/momirealms/craftengine/core/plugin/gui/category/ItemBrowserManagerImpl.java b/core/src/main/java/net/momirealms/craftengine/core/plugin/gui/category/ItemBrowserManagerImpl.java index aacfc4f47..c457cac1c 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/plugin/gui/category/ItemBrowserManagerImpl.java +++ b/core/src/main/java/net/momirealms/craftengine/core/plugin/gui/category/ItemBrowserManagerImpl.java @@ -9,8 +9,8 @@ import net.momirealms.craftengine.core.pack.LoadingSequence; import net.momirealms.craftengine.core.pack.Pack; import net.momirealms.craftengine.core.plugin.CraftEngine; import net.momirealms.craftengine.core.plugin.config.ConfigSectionParser; -import net.momirealms.craftengine.core.plugin.gui.Ingredient; import net.momirealms.craftengine.core.plugin.gui.*; +import net.momirealms.craftengine.core.plugin.gui.Ingredient; import net.momirealms.craftengine.core.registry.Holder; import net.momirealms.craftengine.core.util.AdventureHelper; import net.momirealms.craftengine.core.util.Key; diff --git a/core/src/main/java/net/momirealms/craftengine/core/util/MiscUtils.java b/core/src/main/java/net/momirealms/craftengine/core/util/MiscUtils.java index 277bc4607..12e27e285 100644 --- a/core/src/main/java/net/momirealms/craftengine/core/util/MiscUtils.java +++ b/core/src/main/java/net/momirealms/craftengine/core/util/MiscUtils.java @@ -4,7 +4,8 @@ import org.joml.Quaternionf; import org.joml.Vector3d; import org.joml.Vector3f; -import java.net.*; +import java.net.InetSocketAddress; +import java.net.ProxySelector; import java.util.ArrayList; import java.util.List; import java.util.Map;