diff --git a/api/src/main/java/org/geysermc/geyser/api/pack/ResourcePack.java b/api/src/main/java/org/geysermc/geyser/api/pack/ResourcePack.java index de1beaf65..54971d402 100644 --- a/api/src/main/java/org/geysermc/geyser/api/pack/ResourcePack.java +++ b/api/src/main/java/org/geysermc/geyser/api/pack/ResourcePack.java @@ -26,12 +26,15 @@ package org.geysermc.geyser.api.pack; import org.checkerframework.checker.nullness.qual.NonNull; +import org.checkerframework.checker.nullness.qual.Nullable; /** * Represents a resource pack sent to Bedrock clients *
* This representation of a resource pack only contains what * Geyser requires to send it to the client. + *
+ * Optionally, a content key and/or a subpack name to load can be provided.
*/
public interface ResourcePack {
@@ -59,6 +62,25 @@ public interface ResourcePack {
@NonNull
String contentKey();
+ /**
+ * Sets the content key of the resource pack. Lack of a content key can be represented by an empty string.
+ */
+ void contentKey(@NonNull String contentKey);
+
+ /**
+ * The subpack to tell Bedrock clients to load. Lack of a subpack to load is represented by an empty string.
+ *
+ * @return the subpack name, or an empty string if not set.
+ */
+ @NonNull
+ String subpackName();
+
+ /**
+ * Sets the subpack name that clients should load.
+ * It must match one of the subpacks that can be found in the manifest.
+ */
+ void subpackName(@Nullable String subpackName);
+
/**
* Creates a resource pack with the given {@link PackCodec}.
*
diff --git a/api/src/main/java/org/geysermc/geyser/api/pack/ResourcePackManifest.java b/api/src/main/java/org/geysermc/geyser/api/pack/ResourcePackManifest.java
index c9ccdd6c5..06a1c5278 100644
--- a/api/src/main/java/org/geysermc/geyser/api/pack/ResourcePackManifest.java
+++ b/api/src/main/java/org/geysermc/geyser/api/pack/ResourcePackManifest.java
@@ -66,6 +66,14 @@ public interface ResourcePackManifest {
@NonNull
Collection extends Dependency> dependencies();
+ /**
+ * Gets the subpacks of the resource pack.
+ *
+ * @return the subpacks
+ */
+ @NonNull
+ Collection extends Subpack> subpacks();
+
/**
* Represents the header of a resource pack.
*/
@@ -172,6 +180,36 @@ public interface ResourcePackManifest {
Version version();
}
+ /**
+ * Represents a subpack of a resource pack
+ */
+ interface Subpack {
+
+ /**
+ * Gets the folder name of the subpack.
+ *
+ * @return the folder name
+ */
+ String folderName();
+
+ /**
+ * Gets the name of the subpack.
+ * It can be sent to the Bedrock client alongside the pack
+ * to load a particular subpack within a resource pack.
+ *
+ * @return the subpack name
+ */
+ String name();
+
+ /**
+ * Gets the memory tier of the subpack.
+ *
+ * @return the memory tier
+ */
+
+ Float memoryTier();
+ }
+
/**
* Represents a version of a resource pack.
*/
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 f56a8a43f..9d5724998 100644
--- a/core/src/main/java/org/geysermc/geyser/network/UpstreamPacketHandler.java
+++ b/core/src/main/java/org/geysermc/geyser/network/UpstreamPacketHandler.java
@@ -205,11 +205,10 @@ public class UpstreamPacketHandler extends LoggingPacketHandler {
ResourcePacksInfoPacket resourcePacksInfo = new ResourcePacksInfoPacket();
for (ResourcePack pack : this.resourcePackLoadEvent.resourcePacks()) {
- PackCodec codec = pack.codec();
ResourcePackManifest.Header header = pack.manifest().header();
resourcePacksInfo.getResourcePackInfos().add(new ResourcePacksInfoPacket.Entry(
- header.uuid().toString(), header.version().toString(), codec.size(), pack.contentKey(),
- "", header.uuid().toString(), false, false));
+ header.uuid().toString(), header.version().toString(), pack.codec().size(), pack.contentKey(),
+ pack.subpackName(), header.uuid().toString(), false, false));
}
resourcePacksInfo.setForcedToAccept(GeyserImpl.getInstance().getConfig().isForceResourcePacks());
session.sendUpstreamPacket(resourcePacksInfo);
diff --git a/core/src/main/java/org/geysermc/geyser/pack/GeyserResourcePack.java b/core/src/main/java/org/geysermc/geyser/pack/GeyserResourcePack.java
index 82408b6e7..64b9fdd81 100644
--- a/core/src/main/java/org/geysermc/geyser/pack/GeyserResourcePack.java
+++ b/core/src/main/java/org/geysermc/geyser/pack/GeyserResourcePack.java
@@ -25,14 +25,62 @@
package org.geysermc.geyser.pack;
+import lombok.RequiredArgsConstructor;
+import org.checkerframework.checker.nullness.qual.NonNull;
+import org.checkerframework.checker.nullness.qual.Nullable;
import org.geysermc.geyser.api.pack.PackCodec;
import org.geysermc.geyser.api.pack.ResourcePack;
import org.geysermc.geyser.api.pack.ResourcePackManifest;
-public record GeyserResourcePack(PackCodec codec, ResourcePackManifest manifest, String contentKey) implements ResourcePack {
+@RequiredArgsConstructor
+public class GeyserResourcePack implements ResourcePack {
/**
* The size of each chunk to use when sending the resource packs to clients in bytes
*/
public static final int CHUNK_SIZE = 102400;
+
+ private final PackCodec codec;
+ private final ResourcePackManifest manifest;
+ private String contentKey;
+ private String subpackName;
+
+ public GeyserResourcePack(PackCodec codec, ResourcePackManifest manifest, String contentKey) {
+ this(codec, manifest);
+ this.contentKey = contentKey;
+ }
+
+ @Override
+ public @NonNull PackCodec codec() {
+ return this.codec;
+ }
+
+ @Override
+ public @NonNull ResourcePackManifest manifest() {
+ return this.manifest;
+ }
+
+ @Override
+ public @NonNull String contentKey() {
+ return this.contentKey == null ? "" : this.contentKey;
+ }
+
+ @Override
+ public void contentKey(@Nullable String contentKey) {
+ this.contentKey = contentKey;
+ }
+
+ @Override
+ public @NonNull String subpackName() {
+ return this.subpackName == null ? "" : this.subpackName;
+ }
+
+ @Override
+ public void subpackName(@Nullable String subpackName) {
+ if (manifest.subpacks().stream().anyMatch(subpack -> subpack.name().equals(subpackName))) {
+ this.subpackName = subpackName;
+ } else {
+ throw new IllegalArgumentException("A subpack with the name '" + subpackName + "' does not exist!");
+ }
+ }
}
diff --git a/core/src/main/java/org/geysermc/geyser/pack/GeyserResourcePackManifest.java b/core/src/main/java/org/geysermc/geyser/pack/GeyserResourcePackManifest.java
index 25a0f0ee0..1807c63bb 100644
--- a/core/src/main/java/org/geysermc/geyser/pack/GeyserResourcePackManifest.java
+++ b/core/src/main/java/org/geysermc/geyser/pack/GeyserResourcePackManifest.java
@@ -37,7 +37,13 @@ import java.io.IOException;
import java.util.Collection;
import java.util.UUID;
-public record GeyserResourcePackManifest(@JsonProperty("format_version") int formatVersion, Header header, Collection