1
0
mirror of https://github.com/GeyserMC/Geyser.git synced 2026-01-06 15:41:50 +00:00

Feature: Resource Pack API additions - ResourcePackOptions and a GeyserDefineResourcePacksEvent (#4978)

This commit is contained in:
chris
2025-03-25 15:49:18 +01:00
committed by GitHub
parent 512c68a883
commit 69329f2cad
45 changed files with 2213 additions and 138 deletions

View File

@@ -31,6 +31,7 @@ import org.geysermc.geyser.api.event.connection.ConnectionEvent;
/**
* Called when Geyser session connected to a Java remote server and is in a play-ready state.
* @since 2.1.1
*/
public final class SessionJoinEvent extends ConnectionEvent {
public SessionJoinEvent(@NonNull GeyserConnection connection) {

View File

@@ -26,15 +26,20 @@
package org.geysermc.geyser.api.event.bedrock;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.geysermc.geyser.api.connection.GeyserConnection;
import org.geysermc.geyser.api.event.connection.ConnectionEvent;
import org.geysermc.geyser.api.pack.ResourcePack;
import org.geysermc.geyser.api.pack.exception.ResourcePackException;
import org.geysermc.geyser.api.pack.option.ResourcePackOption;
import java.util.Collection;
import java.util.List;
import java.util.UUID;
/**
* Called when Geyser initializes a session for a new Bedrock client and is in the process of sending resource packs.
* Called when Geyser initializes a session for a new Bedrock client and is in the process of sending {@link ResourcePack}'s.
* @since 2.1.1
*/
public abstract class SessionLoadResourcePacksEvent extends ConnectionEvent {
public SessionLoadResourcePacksEvent(@NonNull GeyserConnection connection) {
@@ -42,26 +47,70 @@ public abstract class SessionLoadResourcePacksEvent extends ConnectionEvent {
}
/**
* Gets an unmodifiable list of {@link ResourcePack}s that will be sent to the client.
* Gets the {@link ResourcePack}'s that will be sent to this {@link GeyserConnection}.
* To remove packs, use {@link #unregister(UUID)}, as the list returned
* by this method is unmodifiable.
*
* @return an unmodifiable list of resource packs that will be sent to the client.
* @return an unmodifiable list of {@link ResourcePack}'s
* @since 2.1.1
*/
public abstract @NonNull List<ResourcePack> resourcePacks();
/**
* Registers a {@link ResourcePack} to be sent to the client.
*
* @param resourcePack a resource pack that will be sent to the client.
* @return true if the resource pack was added successfully,
* or false if already present
* @deprecated Use {{@link #register(ResourcePack, ResourcePackOption[])}} instead
*/
public abstract boolean register(@NonNull ResourcePack resourcePack);
@Deprecated
public abstract boolean register(@NonNull ResourcePack pack);
/**
* Unregisters a resource pack from being sent to the client.
* Registers a {@link ResourcePack} to be sent to the client, optionally alongside
* specific {@link ResourcePackOption}'s specifying how it will be applied by the client.
*
* @param uuid the UUID of the resource pack
* @return true whether the resource pack was removed from the list of resource packs.
* @param pack the {@link ResourcePack} that will be sent to the client
* @param options {@link ResourcePackOption}'s that specify how the client loads the pack
* @throws ResourcePackException if an issue occurred during pack registration
* @since 2.6.2
*/
public abstract void register(@NonNull ResourcePack pack, @Nullable ResourcePackOption<?>... options);
/**
* Sets {@link ResourcePackOption}'s for a {@link ResourcePack}.
* This method can also be used to override options for resource packs already registered in the
* {@link org.geysermc.geyser.api.event.lifecycle.GeyserDefineResourcePacksEvent}.
*
* @param uuid the uuid of the resource pack to register the options for
* @param options the {@link ResourcePackOption}'s to register for the resource pack
* @throws ResourcePackException if an issue occurred during {@link ResourcePackOption} registration
* @since 2.6.2
*/
public abstract void registerOptions(@NonNull UUID uuid, @NonNull ResourcePackOption<?>... options);
/**
* Returns a collection of {@link ResourcePackOption}'s for a registered {@link ResourcePack}.
* The collection returned here is not modifiable.
*
* @param uuid the {@link ResourcePack} for which the options are set
* @return a collection of {@link ResourcePackOption}'s
* @throws ResourcePackException if the pack was not registered
* @since 2.6.2
*/
public abstract Collection<ResourcePackOption<?>> options(@NonNull UUID uuid);
/**
* Returns the current {@link ResourcePackOption}, or null, for a given {@link ResourcePackOption.Type}.
*
* @param uuid the {@link ResourcePack} for which to query this option type
* @param type the {@link ResourcePackOption.Type} of the option to query
* @throws ResourcePackException if the queried option is invalid or not present on the resource pack
* @since 2.6.2
*/
public abstract @Nullable ResourcePackOption<?> option(@NonNull UUID uuid, ResourcePackOption.@NonNull Type type);
/**
* Unregisters a {@link ResourcePack} from the list of packs sent to this {@link GeyserConnection}.
*
* @param uuid the UUID of the {@link ResourcePack} to be removed
* @since 2.1.1
*/
public abstract boolean unregister(@NonNull UUID uuid);
}

View File

@@ -0,0 +1,104 @@
/*
* Copyright (c) 2019-2025 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.geyser.api.event.lifecycle;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.geysermc.event.Event;
import org.geysermc.geyser.api.pack.ResourcePack;
import org.geysermc.geyser.api.pack.exception.ResourcePackException;
import org.geysermc.geyser.api.pack.option.ResourcePackOption;
import java.util.Collection;
import java.util.List;
import java.util.UUID;
/**
* Called when {@link ResourcePack}'s are loaded within Geyser.
* @since 2.6.2
*/
public abstract class GeyserDefineResourcePacksEvent implements Event {
/**
* Gets the {@link ResourcePack}'s that will be sent to connecting Bedrock clients.
* To remove packs, use {@link #unregister(UUID)}, as the list returned
* by this method is unmodifiable.
*
* @return an unmodifiable list of {@link ResourcePack}'s
* @since 2.6.2
*/
public abstract @NonNull List<ResourcePack> resourcePacks();
/**
* Registers a {@link ResourcePack} to be sent to the client, optionally alongside
* {@link ResourcePackOption}'s specifying how it will be applied on clients.
*
* @param pack a resource pack that will be sent to the client
* @param options {@link ResourcePackOption}'s that specify how clients load the pack
* @throws ResourcePackException if an issue occurred during pack registration
* @since 2.6.2
*/
public abstract void register(@NonNull ResourcePack pack, @Nullable ResourcePackOption<?>... options);
/**
* Sets {@link ResourcePackOption}'s for a {@link ResourcePack}.
*
* @param uuid the uuid of the resource pack to register the options for
* @param options the {@link ResourcePackOption}'s to register for the resource pack
* @throws ResourcePackException if an issue occurred during {@link ResourcePackOption} registration
* @since 2.6.2
*/
public abstract void registerOptions(@NonNull UUID uuid, @NonNull ResourcePackOption<?>... options);
/**
* Returns a collection of {@link ResourcePackOption}'s for a registered {@link ResourcePack}.
* The collection returned here is not modifiable.
*
* @param uuid the uuid of the {@link ResourcePack} for which the options are set
* @return a collection of {@link ResourcePackOption}'s
* @throws ResourcePackException if the pack was not registered
* @since 2.6.2
*/
public abstract Collection<ResourcePackOption<?>> options(@NonNull UUID uuid);
/**
* Returns the current option, or null, for a given {@link ResourcePackOption.Type}.
*
* @param uuid the {@link ResourcePack} for which to query this option type
* @param type the {@link ResourcePackOption.Type} of the option to query
* @throws ResourcePackException if the queried option is invalid or not present on the resource pack
* @since 2.6.2
*/
public abstract @Nullable ResourcePackOption<?> option(@NonNull UUID uuid, ResourcePackOption.@NonNull Type type);
/**
* Unregisters a {@link ResourcePack} from the list of packs sent to connecting Bedrock clients.
*
* @param uuid the UUID of the {@link ResourcePack} to be removed
* @since 2.6.2
*/
public abstract void unregister(@NonNull UUID uuid);
}

View File

@@ -32,9 +32,8 @@ import java.nio.file.Path;
import java.util.List;
/**
* Called when resource packs are loaded within Geyser.
*
* @param resourcePacks a mutable list of the currently listed resource packs
* @deprecated Use the {@link GeyserDefineResourcePacksEvent} instead.
*/
@Deprecated
public record GeyserLoadResourcePacksEvent(@NonNull List<Path> resourcePacks) implements Event {
}

View File

@@ -33,7 +33,7 @@ import org.geysermc.geyser.api.extension.ExtensionManager;
/**
* Called when Geyser is about to reload. Primarily aimed at extensions, so they can decide on their own what to reload.
* After this event is fired, some lifecycle events can be fired again - such as the {@link GeyserLoadResourcePacksEvent}.
* After this event is fired, some lifecycle events can be fired again - such as the {@link GeyserDefineResourcePacksEvent}.
*
* @param extensionManager the extension manager
* @param eventBus the event bus

View File

@@ -35,6 +35,7 @@ import java.nio.file.Path;
/**
* Represents a pack codec that can be used
* to provide resource packs to clients.
* @since 2.1.1
*/
public abstract class PackCodec {
@@ -42,6 +43,7 @@ public abstract class PackCodec {
* Gets the sha256 hash of the resource pack.
*
* @return the hash of the resource pack
* @since 2.1.1
*/
public abstract byte @NonNull [] sha256();
@@ -49,34 +51,66 @@ public abstract class PackCodec {
* Gets the resource pack size.
*
* @return the resource pack file size
* @since 2.1.1
*/
public abstract long size();
/**
* Serializes the given resource pack into a byte buffer.
* @deprecated use {@link #serialize()} instead.
*/
@Deprecated
@NonNull
public SeekableByteChannel serialize(@NonNull ResourcePack resourcePack) throws IOException {
return serialize();
};
/**
* Serializes the given codec into a byte buffer.
*
* @param resourcePack the resource pack to serialize
* @return the serialized resource pack
* @since 2.6.2
*/
@NonNull
public abstract SeekableByteChannel serialize(@NonNull ResourcePack resourcePack) throws IOException;
public abstract SeekableByteChannel serialize() throws IOException;
/**
* Creates a new resource pack from this codec.
*
* @return the new resource pack
* @since 2.1.1
*/
@NonNull
protected abstract ResourcePack create();
/**
* Creates a new resource pack builder from this codec.
*
* @return the new resource pack builder
* @since 2.6.2
*/
protected abstract ResourcePack.@NonNull Builder createBuilder();
/**
* Creates a new pack provider from the given path.
*
* @param path the path to create the pack provider from
* @return the new pack provider
* @since 2.1.1
*/
@NonNull
public static PackCodec path(@NonNull Path path) {
public static PathPackCodec path(@NonNull Path path) {
return GeyserApi.api().provider(PathPackCodec.class, path);
}
/**
* Creates a new pack provider from the given url.
*
* @param url the url to create the pack provider from
* @return the new pack provider
* @since 2.6.2
*/
@NonNull
public static UrlPackCodec url(@NonNull String url) {
return GeyserApi.api().provider(UrlPackCodec.class, url);
}
}

View File

@@ -32,6 +32,7 @@ import java.nio.file.Path;
/**
* Represents a pack codec that creates a resource
* pack from a path on the filesystem.
* @since 2.1.1
*/
public abstract class PathPackCodec extends PackCodec {
@@ -39,7 +40,8 @@ public abstract class PathPackCodec extends PackCodec {
* Gets the path of the resource pack.
*
* @return the path of the resource pack
* @since 2.1.1
*/
@NonNull
public abstract Path path();
}
}

View File

@@ -26,12 +26,17 @@
package org.geysermc.geyser.api.pack;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.common.returnsreceiver.qual.This;
import org.geysermc.geyser.api.GeyserApi;
import java.util.UUID;
/**
* Represents a resource pack sent to Bedrock clients
* <p>
* This representation of a resource pack only contains what
* Geyser requires to send it to the client.
* @since 2.1.1
*/
public interface ResourcePack {
@@ -39,6 +44,7 @@ public interface ResourcePack {
* The {@link PackCodec codec} for this pack.
*
* @return the codec for this pack
* @since 2.1.1
*/
@NonNull
PackCodec codec();
@@ -47,6 +53,7 @@ public interface ResourcePack {
* Gets the resource pack manifest.
*
* @return the resource pack manifest
* @since 2.1.1
*/
@NonNull
ResourcePackManifest manifest();
@@ -55,18 +62,83 @@ public interface ResourcePack {
* Gets the content key of the resource pack. Lack of a content key is represented by an empty String.
*
* @return the content key of the resource pack
* @since 2.1.1
*/
@NonNull
String contentKey();
/**
* Shortcut for getting the UUID from the {@link ResourcePackManifest}.
*
* @return the resource pack uuid
* @since 2.6.2
*/
@NonNull
default UUID uuid() {
return manifest().header().uuid();
}
/**
* Creates a resource pack with the given {@link PackCodec}.
*
* @param codec the pack codec
* @return the resource pack
* @since 2.1.1
*/
@NonNull
static ResourcePack create(@NonNull PackCodec codec) {
return codec.create();
}
/**
* Returns a {@link Builder} for a resource pack.
* It can be used to set a content key.
*
* @param codec the {@link PackCodec} to base the builder on
* @return a {@link Builder} to build a resource pack
* @since 2.6.2
*/
static Builder builder(@NonNull PackCodec codec) {
return GeyserApi.api().provider(Builder.class, codec);
}
/**
* A builder for a resource pack. It allows providing a content key manually.
* @since 2.6.2
*/
interface Builder {
/**
* @return the {@link ResourcePackManifest} of this resource pack
* @since 2.6.2
*/
ResourcePackManifest manifest();
/**
* @return the {@link PackCodec} of this resource pack
* @since 2.6.2
*/
PackCodec codec();
/**
* @return the current content key, or an empty string if not set
* @since 2.6.2
*/
String contentKey();
/**
* Sets a content key for this resource pack.
*
* @param contentKey the content key
* @return this builder
* @since 2.6.2
*/
@This Builder contentKey(@NonNull String contentKey);
/**
* @return the resource pack
* @since 2.6.2
*/
ResourcePack build();
}
}

View File

@@ -26,55 +26,99 @@
package org.geysermc.geyser.api.pack;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.geysermc.geyser.api.event.bedrock.SessionLoadResourcePacksEvent;
import org.geysermc.geyser.api.event.lifecycle.GeyserDefineResourcePacksEvent;
import org.geysermc.geyser.api.pack.option.SubpackOption;
import java.util.Collection;
import java.util.UUID;
/**
* Represents a resource pack manifest.
* Represents a Bedrock edition resource pack manifest (manifest.json).
* All resource packs are required to have such a file as it identifies the resource pack.
* See <a href="https://learn.microsoft.com/en-us/minecraft/creator/reference/content/addonsreference/examples/addonmanifest?view=minecraft-bedrock-stable">
* Microsoft's docs for more info</a>.
* @since 2.1.1
*/
public interface ResourcePackManifest {
/**
* Gets the format version of the resource pack.
* <p>
* "1" is used for skin packs,
* "2" is used for resource and behavior packs, and world templates.
*
* @return the format version
* @since 2.1.1
*/
int formatVersion();
/**
* Gets the header of the resource pack.
* Gets the {@link Header} of the resource pack.
*
* @return the header
* @return the {@link Header}
* @since 2.1.1
*/
@NonNull
Header header();
/**
* Gets the modules of the resource pack.
* Gets the {@link Module}'s of the resource pack.
*
* @return the modules
* @return a collection of modules
* @since 2.1.1
*/
@NonNull
Collection<? extends Module> modules();
/**
* Gets the dependencies of the resource pack.
* Gets the {@link Dependency}'s of the resource pack.
*
* @return the dependencies
* @return a collection of dependencies
* @since 2.6.2
*/
@NonNull
Collection<? extends Dependency> dependencies();
/**
* Gets the {@link Subpack}'s of the resource pack.
* See <a href="https://learn.microsoft.com/en-us/minecraft/creator/documents/utilizingsubpacks">Microsoft's docs on subpacks
* </a> for more information.
*
* @return a collection of subpacks
* @since 2.6.2
*/
@NonNull
Collection<? extends Subpack> subpacks();
/**
* Gets the {@link Setting}'s of the resource pack.
* These are shown to Bedrock client's in the resource pack settings menu (<a href="https://learn.microsoft.com/en-us/minecraft/creator/documents/media/utilizingsubpacks/subpackgif.gif?view=minecraft-bedrock-stable">see here</a>)
* to inform users about what the resource pack and sub-packs include.
*
* @return a collection of settings
* @since 2.6.2
*/
@NonNull
Collection<? extends Setting> settings();
/**
* Represents the header of a resource pack.
* It contains the main information about the resource pack, such as
* the name, description, or uuid.
* See <a href="https://learn.microsoft.com/en-us/minecraft/creator/reference/content/addonsreference/examples/addonmanifest?view=minecraft-bedrock-stable#header">
* Microsoft's docs for further details on headers.</a>
* @since 2.1.1
*/
interface Header {
/**
* Gets the UUID of the resource pack.
* Gets the UUID of the resource pack. It is a unique identifier that differentiates this resource pack from any other resource pack.
* Bedrock clients will cache resource packs, and download resource packs when the uuid is new (or the version changes).
*
* @return the UUID
* @since 2.1.1
*/
@NonNull
UUID uuid();
@@ -83,6 +127,7 @@ public interface ResourcePackManifest {
* Gets the version of the resource pack.
*
* @return the version
* @since 2.1.1
*/
@NonNull
Version version();
@@ -91,6 +136,7 @@ public interface ResourcePackManifest {
* Gets the name of the resource pack.
*
* @return the name
* @since 2.1.1
*/
@NonNull
String name();
@@ -99,6 +145,7 @@ public interface ResourcePackManifest {
* Gets the description of the resource pack.
*
* @return the description
* @since 2.1.1
*/
@NonNull
String description();
@@ -107,6 +154,7 @@ public interface ResourcePackManifest {
* Gets the minimum supported Minecraft version of the resource pack.
*
* @return the minimum supported Minecraft version
* @since 2.1.1
*/
@NonNull
Version minimumSupportedMinecraftVersion();
@@ -114,21 +162,29 @@ public interface ResourcePackManifest {
/**
* Represents a module of a resource pack.
* It contains information about the content type that is
* offered by this resource pack.
* See <a href="https://learn.microsoft.com/en-us/minecraft/creator/reference/content/addonsreference/examples/addonmanifest?view=minecraft-bedrock-stable#modules">
* Microsoft's docs for further details on modules.</a>
* @since 2.1.1
*/
interface Module {
/**
* Gets the UUID of the module.
* This should usually be different from the UUID in the {@link Header}.
*
* @return the UUID
* @since 2.1.1
*/
@NonNull
UUID uuid();
/**
* Gets the version of the module.
* Gets the {@link Version} of the module.
*
* @return the version
* @return the {@link Version}
* @since 2.1.1
*/
@NonNull
Version version();
@@ -137,6 +193,7 @@ public interface ResourcePackManifest {
* Gets the type of the module.
*
* @return the type
* @since 2.1.1
*/
@NonNull
String type();
@@ -145,6 +202,7 @@ public interface ResourcePackManifest {
* Gets the description of the module.
*
* @return the description
* @since 2.1.1
*/
@NonNull
String description();
@@ -152,28 +210,102 @@ public interface ResourcePackManifest {
/**
* Represents a dependency of a resource pack.
* These are references to other resource packs that must be
* present in order for this resource pack to apply.
* See <a href="https://learn.microsoft.com/en-us/minecraft/creator/reference/content/addonsreference/examples/addonmanifest?view=minecraft-bedrock-stable#dependencies">
* Microsoft's docs for further details on dependencies.</a>
* @since 2.1.1
*/
interface Dependency {
/**
* Gets the UUID of the dependency.
* Gets the UUID of the resource pack dependency.
*
* @return the uuid
* @since 2.1.1
*/
@NonNull
UUID uuid();
/**
* Gets the version of the dependency.
* Gets the {@link Version} of the dependency.
*
* @return the version
* @return the {@link Version}
* @since 2.1.1
*/
@NonNull
Version version();
}
/**
* Represents a subpack of a resource pack. These are often used for "variants" of the resource pack,
* such as lesser details, or additional features either to be determined by player's taste or adapted to the player device's performance.
* See <a href="https://learn.microsoft.com/en-us/minecraft/creator/documents/utilizingsubpacks">Micoroft's docs</a> for more information.
*/
interface Subpack {
/**
* Gets the folder name where this sub-pack is placed in.
*
* @return the folder name
* @since 2.6.2
*/
@NonNull
String folderName();
/**
* Gets the name of this subpack. Required for each subpack to be valid.
* To make a Bedrock client load any subpack, register the resource pack
* in the {@link SessionLoadResourcePacksEvent} or {@link GeyserDefineResourcePacksEvent} and specify a
* {@link SubpackOption} with the name of the subpack to load.
*
* @return the subpack name
* @since 2.6.2
*/
@NonNull
String name();
/**
* Gets the memory tier of this Subpack, representing how much RAM a device must have to run it.
* Each memory tier requires 0.25 GB of RAM. For example, a memory tier of 0 is no requirement,
* and a memory tier of 4 requires 1GB of RAM.
*
* @return the memory tier
* @since 2.6.2
*/
@Nullable
Float memoryTier();
}
/**
* Represents a setting that is shown client-side that describe what a pack does.
* Multiple setting entries are shown in separate paragraphs.
* @since 2.6.2
*/
interface Setting {
/**
* The type of the setting. Usually just "label".
*
* @return the type
* @since 2.6.2
*/
@NonNull
String type();
/**
* The text shown for the setting.
*
* @return the text content
* @since 2.6.2
*/
@NonNull
String text();
}
/**
* Represents a version of a resource pack.
* @since 2.1.1
*/
interface Version {
@@ -181,6 +313,7 @@ public interface ResourcePackManifest {
* Gets the major version.
*
* @return the major version
* @since 2.1.1
*/
int major();
@@ -188,6 +321,7 @@ public interface ResourcePackManifest {
* Gets the minor version.
*
* @return the minor version
* @since 2.1.1
*/
int minor();
@@ -195,6 +329,7 @@ public interface ResourcePackManifest {
* Gets the patch version.
*
* @return the patch version
* @since 2.1.1
*/
int patch();
@@ -202,6 +337,7 @@ public interface ResourcePackManifest {
* Gets the version formatted as a String.
*
* @return the version string
* @since 2.1.1
*/
@NonNull String toString();
}

View File

@@ -0,0 +1,51 @@
/*
* Copyright (c) 2019-2023 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.geyser.api.pack;
import org.checkerframework.checker.nullness.qual.NonNull;
/**
* Represents a pack codec that creates a resource
* pack from a URL.
* <p>
* Due to Bedrock limitations, the URL must:
* <ul>
* <li>be a direct download link to a .zip or .mcpack resource pack</li>
* <li>use the application type `application/zip` and set a correct content length</li>
* </ul>
* @since 2.6.2
*/
public abstract class UrlPackCodec extends PackCodec {
/**
* Gets the URL to the resource pack location.
*
* @return the URL of the resource pack
* @since 2.6.2
*/
@NonNull
public abstract String url();
}

View File

@@ -0,0 +1,97 @@
/*
* Copyright (c) 2025 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.geyser.api.pack.exception;
import java.io.Serial;
/**
* Used to indicate an exception that occurred while handling resource pack registration,
* or during resource pack option validation.
* @since 2.6.2
*/
public class ResourcePackException extends IllegalArgumentException {
@Serial
private static final long serialVersionUID = 1L;
/**
* The {@link Cause} of this exception.
*/
private final Cause cause;
/**
* @param cause the cause of this exception
* @since 2.6.2
*/
public ResourcePackException(Cause cause) {
super(cause.message());
this.cause = cause;
}
/**
* @param cause the cause of this exception
* @param message an additional, more in-depth message about the issue.
* @since 2.6.2
*/
public ResourcePackException(Cause cause, String message) {
super(message);
this.cause = cause;
}
/**
* @return the cause of this exception
* @since 2.6.2
*/
public Cause cause() {
return cause;
}
/**
* Represents different causes with explanatory messages stating which issue occurred.
* @since 2.6.2
*/
public enum Cause {
DUPLICATE("A resource pack with this UUID was already registered!"),
INVALID_PACK("This resource pack is not a valid Bedrock edition resource pack!"),
INVALID_PACK_OPTION("Attempted to register an invalid resource pack option!"),
PACK_NOT_FOUND("No resource pack was found!"),
UNKNOWN_IMPLEMENTATION("Use the resource pack codecs to create resource packs.");
private final String message;
/**
* @return the message of this cause
* @since 2.6.2
*/
public String message() {
return message;
}
Cause(String message) {
this.message = message;
}
}
}

View File

@@ -0,0 +1,59 @@
/*
* Copyright (c) 2024 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.geyser.api.pack.option;
import org.geysermc.geyser.api.GeyserApi;
/**
* Allows specifying a pack priority that decides the order on how packs are sent to the client.
* If two resource packs modify the same texture - for example if one removes the pumpkin overlay and
* the other is just making it translucent, one of the packs will override the other.
* Specifically, the pack with the higher priority will override the pack changes of the lower priority.
* @since 2.6.2
*/
public interface PriorityOption extends ResourcePackOption<Integer> {
PriorityOption HIGHEST = PriorityOption.priority(100);
PriorityOption HIGH = PriorityOption.priority(50);
PriorityOption NORMAL = PriorityOption.priority(0);
PriorityOption LOW = PriorityOption.priority(-50);
PriorityOption LOWEST = PriorityOption.priority(-100);
/**
* Constructs a priority option based on a value between 0 and 10.
* The higher the number, the higher will this pack appear in the resource pack stack.
*
* @param priority an integer that is above 0, but smaller than 10
* @return the priority option
* @since 2.6.2
*/
static PriorityOption priority(int priority) {
if (priority < -100 || priority > 100) {
throw new IllegalArgumentException("Priority must be between 0 and 10 inclusive!");
}
return GeyserApi.api().provider(PriorityOption.class, priority);
}
}

View File

@@ -0,0 +1,76 @@
/*
* Copyright (c) 2024 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.geyser.api.pack.option;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.geysermc.geyser.api.pack.ResourcePack;
import org.geysermc.geyser.api.pack.exception.ResourcePackException;
/**
* Represents a resource pack option that can be used to specify how a resource
* pack is sent to Bedrock clients.
* <p>
* Not all options can be applied to all resource packs. For example, you cannot specify
* a specific subpack to be loaded on resource packs that do not have subpacks.
* To see which limitations apply to specific resource pack options, check the javadocs
* or see the {@link #validate(ResourcePack)} method.
* @since 2.6.2
*/
public interface ResourcePackOption<T> {
/**
* @return the option type
* @since 2.6.2
*/
@NonNull Type type();
/**
* @return the value of the option
* @since 2.6.2
*/
@NonNull T value();
/**
* Used to validate a specific options for a pack.
* Some options are not applicable to some packs.
*
* @param pack the resource pack to validate the option for
* @throws ResourcePackException with the {@link ResourcePackException.Cause#INVALID_PACK_OPTION} cause
* @since 2.6.2
*/
void validate(@NonNull ResourcePack pack);
/**
* Represents the different types of resource pack options.
* @since 2.6.2
*/
enum Type {
SUBPACK,
PRIORITY,
FALLBACK
}
}

View File

@@ -0,0 +1,71 @@
/*
* Copyright (c) 2024 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.geyser.api.pack.option;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.geysermc.geyser.api.GeyserApi;
import org.geysermc.geyser.api.pack.ResourcePackManifest;
/**
* Can be used to specify which subpack from a resource pack a player should load.
* Available subpacks can be seen in a resource pack manifest {@link ResourcePackManifest#subpacks()}.
* @since 2.6.2
*/
public interface SubpackOption extends ResourcePackOption<String> {
/**
* Creates a subpack option based on a {@link ResourcePackManifest.Subpack}.
*
* @param subpack the chosen subpack
* @return a subpack option specifying that subpack
* @since 2.6.2
*/
static SubpackOption subpack(ResourcePackManifest.@NonNull Subpack subpack) {
return named(subpack.name());
}
/**
* Creates a subpack option based on a subpack name.
*
* @param subpackName the name of the subpack
* @return a subpack option specifying a subpack with that name
* @since 2.6.2
*/
static SubpackOption named(@NonNull String subpackName) {
return GeyserApi.api().provider(SubpackOption.class, subpackName);
}
/**
* Creates a subpack option with no subpack specified.
*
* @return a subpack option specifying no subpack
* @since 2.6.2
*/
static SubpackOption empty() {
return GeyserApi.api().provider(SubpackOption.class, "");
}
}

View File

@@ -0,0 +1,56 @@
/*
* Copyright (c) 2024 GeyserMC. http://geysermc.org
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @author GeyserMC
* @link https://github.com/GeyserMC/Geyser
*/
package org.geysermc.geyser.api.pack.option;
import org.geysermc.geyser.api.GeyserApi;
import org.geysermc.geyser.api.pack.PathPackCodec;
import org.geysermc.geyser.api.pack.UrlPackCodec;
/**
* Can be used for resource packs created with the {@link UrlPackCodec}.
* When a Bedrock client is unable to download a resource pack from a URL, Geyser will, by default,
* serve the resource pack over raknet (as packs are served with the {@link PathPackCodec}).
* This option can be used to disable that behavior, and disconnect the player instead.
* By default, the {@link UrlFallbackOption#TRUE} option is set.
* @since 2.6.2
*/
public interface UrlFallbackOption extends ResourcePackOption<Boolean> {
UrlFallbackOption TRUE = fallback(true);
UrlFallbackOption FALSE = fallback(false);
/**
* Whether to fall back to serving packs over the raknet connection
*
* @param fallback whether to fall back
* @return a UrlFallbackOption with the specified behavior
* @since 2.6.2
*/
static UrlFallbackOption fallback(boolean fallback) {
return GeyserApi.api().provider(UrlFallbackOption.class, fallback);
}
}