mirror of
https://github.com/Xiao-MoMi/craft-engine.git
synced 2025-12-28 03:19:14 +00:00
修改配置
This commit is contained in:
@@ -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: "<yellow>To fully experience our server, please accept our custom resource pack.</yellow>"
|
||||
# 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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -147,7 +147,7 @@ public abstract class AbstractPackManager implements PackManager {
|
||||
|
||||
@Override
|
||||
public void load() {
|
||||
List<Map<?, ?>> list = Config.instance().settings().getMapList("resource-pack.send.host");
|
||||
List<Map<?, ?>> list = Config.instance().settings().getMapList("resource-pack.delivery.hosting");
|
||||
if (list == null || list.isEmpty()) {
|
||||
this.resourcePackHost = NoneHost.INSTANCE;
|
||||
} else {
|
||||
|
||||
@@ -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<List<ResourcePackDownloadData>> requestResourcePackDownloadLink(UUID player);
|
||||
|
||||
CompletableFuture<Void> upload(Path resourcePackPath);
|
||||
|
||||
static Path customPackPath(String path) {
|
||||
return path.startsWith(".") ? CraftEngine.instance().dataFolderPath().resolve(path) : Path.of(path);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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<String, Date> 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<Void> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<List<ResourcePackDownloadData>> requestResourcePackDownloadLink(UUID player) {
|
||||
CompletableFuture<List<ResourcePackDownloadData>> 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<String, Object> 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<Void> upload(Path resourcePackPath) {
|
||||
CompletableFuture<Void> 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<String, Object> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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<Void> upload(Path resourcePackPath) {
|
||||
CompletableFuture<Void> 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<String> 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<String, Object> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<Void> upload(Path resourcePackPath) {
|
||||
CompletableFuture<Void> future = new CompletableFuture<>();
|
||||
long totalStartTime = System.currentTimeMillis();
|
||||
|
||||
if (this.forcedPackPath != null) resourcePackPath = forcedPackPath;
|
||||
Path finalResourcePackPath = resourcePackPath;
|
||||
|
||||
CraftEngine.instance().scheduler().executeAsync(() -> {
|
||||
try {
|
||||
Map<String, String> hashes = calculateHashes(finalResourcePackPath);
|
||||
Map<String, String> 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<String, Object> 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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<String, String, Date> 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<Void> upload(Path resourcePackPath) {
|
||||
CompletableFuture<Void> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<List<ResourcePackDownloadData>> 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<Void> 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<String, Object> 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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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", "<yellow>To fully experience our server, please accept our custom resource pack.</yellow>"));
|
||||
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", "<yellow>To fully experience our server, please accept our custom resource pack.</yellow>"));
|
||||
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<ConditionalResolution> 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");
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user