diff --git a/core/src/main/java/org/geysermc/geyser/network/UpstreamPacketHandler.java b/core/src/main/java/org/geysermc/geyser/network/UpstreamPacketHandler.java index a775399c1..2e94993e7 100644 --- a/core/src/main/java/org/geysermc/geyser/network/UpstreamPacketHandler.java +++ b/core/src/main/java/org/geysermc/geyser/network/UpstreamPacketHandler.java @@ -282,7 +282,7 @@ public class UpstreamPacketHandler extends LoggingPacketHandler { // TODO: Proper pack checking - could be that the remote url is offline, the pack changed, or.. something? GeyserImpl.getInstance().getLogger().warning("Received ResourcePackChunkRequestPacket for URL pack " + urlPackCodec.url()); - WebUtils.checkRemotePackUrl(urlPackCodec.url()); + WebUtils.checkUrlAndDownloadRemotePack(urlPackCodec.url()); } } diff --git a/core/src/main/java/org/geysermc/geyser/pack/url/GeyserUrlPackCodec.java b/core/src/main/java/org/geysermc/geyser/pack/url/GeyserUrlPackCodec.java index 4335187be..1f40408eb 100644 --- a/core/src/main/java/org/geysermc/geyser/pack/url/GeyserUrlPackCodec.java +++ b/core/src/main/java/org/geysermc/geyser/pack/url/GeyserUrlPackCodec.java @@ -27,6 +27,7 @@ package org.geysermc.geyser.pack.url; import lombok.Getter; import org.checkerframework.checker.nullness.qual.NonNull; +import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.api.pack.ResourcePack; import org.geysermc.geyser.api.pack.UrlPackCodec; import org.geysermc.geyser.pack.path.GeyserPathPackCodec; @@ -39,7 +40,7 @@ public class GeyserUrlPackCodec extends UrlPackCodec { private final String url; private final String contentKey; @Getter - private final GeyserPathPackCodec fallback; + private GeyserPathPackCodec fallback; public GeyserUrlPackCodec(String url) throws IllegalArgumentException { this(url, ""); @@ -48,31 +49,49 @@ public class GeyserUrlPackCodec extends UrlPackCodec { public GeyserUrlPackCodec(String url, String contentKey) throws IllegalArgumentException { this.url = url; this.contentKey = contentKey; - try { - this.fallback = new GeyserPathPackCodec(ResourcePackLoader.downloadPack(url).get()); - } catch (Exception e) { - throw new IllegalArgumentException("Unable to download pack from " + url, e); - } } @Override public byte @NonNull [] sha256() { + if (this.fallback == null) { + throw new IllegalStateException("Fallback pack not initialized! Needs to be created first."); + } return fallback.sha256(); } @Override public long size() { + if (this.fallback == null) { + throw new IllegalStateException("Fallback pack not initialized! Needs to be created first."); + } return fallback.size(); } @Override public @NonNull SeekableByteChannel serialize(@NonNull ResourcePack resourcePack) throws IOException { + if (this.fallback == null) { + throw new IllegalStateException("Fallback pack not initialized! Needs to be created first."); + } return fallback.serialize(resourcePack); } @Override @NonNull public ResourcePack create() { + if (this.fallback == null) { + try { + this.fallback = new GeyserPathPackCodec(ResourcePackLoader.downloadPack(url).whenComplete((pack, throwable) -> { + if (throwable != null) { + GeyserImpl.getInstance().getLogger().error("Failed to download pack from " + url, throwable); + if (GeyserImpl.getInstance().getConfig().isDebugMode()) { + throwable.printStackTrace(); + } + } + }).join()); + } catch (Exception e) { + throw new IllegalArgumentException("Unable to download pack from " + url, e); + } + } return ResourcePackLoader.loadDownloadedPack(this); } diff --git a/core/src/main/java/org/geysermc/geyser/registry/loader/ResourcePackLoader.java b/core/src/main/java/org/geysermc/geyser/registry/loader/ResourcePackLoader.java index 0dcb2ab5f..3e92bd34f 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/loader/ResourcePackLoader.java +++ b/core/src/main/java/org/geysermc/geyser/registry/loader/ResourcePackLoader.java @@ -230,16 +230,20 @@ public class ResourcePackLoader implements RegistryLoader downloadPack(String url) throws IllegalArgumentException { - CompletableFuture future = WebUtils.checkRemotePackUrl(url); - AtomicReference pathAtomicReference = new AtomicReference<>(); + CompletableFuture future = WebUtils.checkUrlAndDownloadRemotePack(url); future.whenCompleteAsync((cachedPath, throwable) -> { - if (cachedPath == null || throwable != null) { + if (cachedPath == null) { + return; + } + + if (throwable != null) { + GeyserImpl.getInstance().getLogger().error("Failed to download resource pack " + url, throwable); return; } // Check if the pack is a .zip or .mcpack file if (!PACK_MATCHER.matches(cachedPath)) { - throw new IllegalArgumentException("Invalid pack! Not a .zip or .mcpack file."); + throw new IllegalArgumentException("Invalid pack format! Not a .zip or .mcpack file."); } try { @@ -258,10 +262,7 @@ public class ResourcePackLoader implements RegistryLoader pathAtomicReference.get()); + return future; } } diff --git a/core/src/main/java/org/geysermc/geyser/util/WebUtils.java b/core/src/main/java/org/geysermc/geyser/util/WebUtils.java index a0351e92a..96372d90c 100644 --- a/core/src/main/java/org/geysermc/geyser/util/WebUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/WebUtils.java @@ -105,19 +105,25 @@ public class WebUtils { * @param url The URL to check * @return Path to the downloaded pack file */ - public static CompletableFuture<@Nullable Path> checkRemotePackUrl(String url) { + public static CompletableFuture<@Nullable Path> checkUrlAndDownloadRemotePack(String url) { return CompletableFuture.supplyAsync(() -> { try { HttpURLConnection con = (HttpURLConnection) new URL(url).openConnection(); con.setRequestProperty("User-Agent", "Geyser-" + GeyserImpl.getInstance().getPlatformType().toString() + "/" + GeyserImpl.VERSION); int size = con.getContentLength(); String type = con.getContentType(); - InputStream in = con.getInputStream(); - if (size < 1 || !type.equals("application/zip")) { - GeyserImpl.getInstance().getLogger().error("Invalid resource pack: " + url + " (" + type + ", " + size + " bytes)"); - //return null; + if (size <= 0) { + GeyserImpl.getInstance().getLogger().error(String.format("Invalid size from remote pack URL: %s (size: %d)", url, size)); + return null; } + + if (type == null || !type.equals("application/zip")) { + GeyserImpl.getInstance().getLogger().error(String.format("Invalid application type from remote pack URL: %s (type: %s)", url, type)); + return null; + } + + InputStream in = con.getInputStream(); Path fileLocation = GeyserImpl.getInstance().getBootstrap().getConfigFolder().resolve("cache").resolve("remote_packs").resolve(url.hashCode() + ".zip"); Files.copy(in, fileLocation, StandardCopyOption.REPLACE_EXISTING);