Mirror von
https://github.com/GeyserMC/Geyser.git
synchronisiert 2024-11-20 15:00:11 +01:00
Attempt at making a proper builder for resource pack options (content key, default subpack), and a ResourcePackOption system to register packs with further options
Dieser Commit ist enthalten in:
Ursprung
87829c9d0a
Commit
033d2d6d8c
@ -29,7 +29,9 @@ import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
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.option.ResourcePackOption;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
@ -57,6 +59,34 @@ public abstract class SessionLoadResourcePacksEvent extends ConnectionEvent {
|
||||
*/
|
||||
public abstract boolean register(@NonNull ResourcePack resourcePack);
|
||||
|
||||
/**
|
||||
* Registers a {@link ResourcePack} to be sent to the client, but alongside
|
||||
* specific options.
|
||||
*
|
||||
* @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
|
||||
*/
|
||||
public abstract boolean register(@NonNull ResourcePack resourcePack, ResourcePackOption... resourcePackOptions);
|
||||
|
||||
/**
|
||||
* Returns the subpack options set for a specific resource pack.
|
||||
*
|
||||
* @param resourcePack the resourcePack for which the options are set
|
||||
* @return a list of {@link ResourcePackOption}
|
||||
*/
|
||||
Collection<ResourcePackOption> options(ResourcePack resourcePack) {
|
||||
return options(resourcePack.manifest().header().uuid());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the subpack options set for a specific resource pack uuid.
|
||||
*
|
||||
* @param resourcePack the resourcePack for which the options are set
|
||||
* @return a list of {@link ResourcePackOption}
|
||||
*/
|
||||
public abstract Collection<ResourcePackOption> options(UUID resourcePack);
|
||||
|
||||
/**
|
||||
* Unregisters a resource pack from being sent to the client.
|
||||
*
|
||||
@ -64,4 +94,5 @@ public abstract class SessionLoadResourcePacksEvent extends ConnectionEvent {
|
||||
* @return true whether the resource pack was removed from the list of resource packs.
|
||||
*/
|
||||
public abstract boolean unregister(@NonNull UUID uuid);
|
||||
|
||||
}
|
||||
|
@ -53,13 +53,21 @@ public abstract class PackCodec {
|
||||
public abstract long size();
|
||||
|
||||
/**
|
||||
* Serializes the given resource pack into a byte buffer.
|
||||
* 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
|
||||
*/
|
||||
@NonNull
|
||||
public abstract SeekableByteChannel serialize(@NonNull ResourcePack resourcePack) throws IOException;
|
||||
public abstract SeekableByteChannel serialize() throws IOException;
|
||||
|
||||
/**
|
||||
* Creates a new resource pack from this codec.
|
||||
@ -69,6 +77,13 @@ public abstract class PackCodec {
|
||||
@NonNull
|
||||
protected abstract ResourcePack create();
|
||||
|
||||
/**
|
||||
* Creates a new resource pack builder from this codec.
|
||||
*
|
||||
* @return the new resource pack builder
|
||||
*/
|
||||
protected abstract ResourcePack.@NonNull Builder createBuilder();
|
||||
|
||||
/**
|
||||
* Creates a new pack provider from the given path.
|
||||
*
|
||||
|
@ -26,7 +26,7 @@
|
||||
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.GeyserApi;
|
||||
|
||||
/**
|
||||
* Represents a resource pack sent to Bedrock clients
|
||||
@ -63,23 +63,12 @@ public interface ResourcePack {
|
||||
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.
|
||||
* The default 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);
|
||||
String defaultSubpackName();
|
||||
|
||||
/**
|
||||
* Creates a resource pack with the given {@link PackCodec}.
|
||||
@ -91,4 +80,36 @@ public interface ResourcePack {
|
||||
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, or a default subpack.
|
||||
*
|
||||
* @param codec the {@link PackCodec} to base the builder on
|
||||
* @return a {@link Builder} to build a resource pack.
|
||||
*/
|
||||
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, or
|
||||
* setting a default subpack.
|
||||
*/
|
||||
interface Builder {
|
||||
|
||||
ResourcePackManifest manifest();
|
||||
|
||||
PackCodec codec();
|
||||
|
||||
String contentKey();
|
||||
|
||||
String defaultSubpackName();
|
||||
|
||||
Builder contentKey(@NonNull String contentKey);
|
||||
|
||||
Builder defaultSubpackName(@NonNull String subpackName);
|
||||
|
||||
ResourcePack build();
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,44 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
public interface PriorityOption extends ResourcePackOption {
|
||||
|
||||
PriorityOption HIGH = PriorityOption.priority(10);
|
||||
PriorityOption NORMAL = PriorityOption.priority(5);
|
||||
PriorityOption LOW = PriorityOption.priority(0);
|
||||
|
||||
int priority();
|
||||
|
||||
static PriorityOption priority(int priority) {
|
||||
if (priority < 0 || priority > 10) {
|
||||
throw new IllegalArgumentException("Priority must be between 0 and 10 inclusive!");
|
||||
}
|
||||
return GeyserApi.api().provider(PriorityOption.class, priority);
|
||||
}
|
||||
}
|
@ -0,0 +1,48 @@
|
||||
/*
|
||||
* 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.pack.ResourcePack;
|
||||
|
||||
/**
|
||||
* Represents a resource pack option that can be used to specify how a resource
|
||||
* pack is sent to Bedrock clients.
|
||||
*/
|
||||
public interface ResourcePackOption {
|
||||
|
||||
Type type();
|
||||
|
||||
void validate(ResourcePack pack);
|
||||
|
||||
enum Type {
|
||||
SUBPACK("subpack"),
|
||||
PRIORITY("priority");
|
||||
|
||||
Type(String name) {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,61 @@
|
||||
/*
|
||||
* 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.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()}
|
||||
*/
|
||||
public interface SubpackOption extends ResourcePackOption {
|
||||
|
||||
/**
|
||||
* Creates a subpack option based on a {@link ResourcePackManifest.Subpack}
|
||||
*
|
||||
* @param subpack the chosen subpack
|
||||
* @return a subpack option specifying that subpack
|
||||
*/
|
||||
static SubpackOption subpack(ResourcePackManifest.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
|
||||
*/
|
||||
static SubpackOption named(String subpackName) {
|
||||
return GeyserApi.api().provider(SubpackOption.class, subpackName);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the subpack name of the chosen subpack.
|
||||
*/
|
||||
String subpackName();
|
||||
}
|
@ -25,11 +25,18 @@
|
||||
|
||||
package org.geysermc.geyser.event.type;
|
||||
|
||||
import it.unimi.dsi.fastutil.objects.Object2ObjectLinkedOpenHashMap;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.geysermc.geyser.api.event.bedrock.SessionLoadResourcePacksEvent;
|
||||
import org.geysermc.geyser.api.pack.ResourcePack;
|
||||
import org.geysermc.geyser.api.pack.option.PriorityOption;
|
||||
import org.geysermc.geyser.api.pack.option.ResourcePackOption;
|
||||
import org.geysermc.geyser.registry.Registries;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
@ -37,10 +44,12 @@ import java.util.UUID;
|
||||
public class SessionLoadResourcePacksEventImpl extends SessionLoadResourcePacksEvent {
|
||||
|
||||
private final Map<String, ResourcePack> packs;
|
||||
private final Map<String, Collection<ResourcePackOption>> options;
|
||||
|
||||
public SessionLoadResourcePacksEventImpl(GeyserSession session, Map<String, ResourcePack> packMap) {
|
||||
public SessionLoadResourcePacksEventImpl(GeyserSession session) {
|
||||
super(session);
|
||||
this.packs = packMap;
|
||||
this.packs = new Object2ObjectLinkedOpenHashMap<>(Registries.RESOURCE_PACKS.get());
|
||||
this.options = new HashMap<>();
|
||||
}
|
||||
|
||||
public @NonNull Map<String, ResourcePack> getPacks() {
|
||||
@ -54,16 +63,35 @@ public class SessionLoadResourcePacksEventImpl extends SessionLoadResourcePacksE
|
||||
|
||||
@Override
|
||||
public boolean register(@NonNull ResourcePack resourcePack) {
|
||||
return register(resourcePack, PriorityOption.NORMAL);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean register(@NonNull ResourcePack resourcePack, ResourcePackOption... resourcePackOptions) {
|
||||
for (ResourcePackOption option : resourcePackOptions) {
|
||||
option.validate(resourcePack);
|
||||
}
|
||||
|
||||
String packID = resourcePack.manifest().header().uuid().toString();
|
||||
if (packs.containsValue(resourcePack) || packs.containsKey(packID)) {
|
||||
return false;
|
||||
}
|
||||
packs.put(resourcePack.manifest().header().uuid().toString(), resourcePack);
|
||||
|
||||
String uuid = resourcePack.manifest().header().uuid().toString();
|
||||
packs.put(uuid, resourcePack);
|
||||
options.put(uuid, List.of(resourcePackOptions));
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<ResourcePackOption> options(UUID resourcePack) {
|
||||
Collection<ResourcePackOption> packOptions = options.get(resourcePack.toString());
|
||||
return packOptions == null ? List.of() : Collections.unmodifiableCollection(packOptions);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean unregister(@NonNull UUID uuid) {
|
||||
options.remove(uuid.toString());
|
||||
return packs.remove(uuid.toString()) != null;
|
||||
}
|
||||
}
|
||||
|
@ -75,7 +75,6 @@ import java.nio.ByteBuffer;
|
||||
import java.nio.channels.SeekableByteChannel;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.Deque;
|
||||
import java.util.HashMap;
|
||||
import java.util.OptionalInt;
|
||||
|
||||
public class UpstreamPacketHandler extends LoggingPacketHandler {
|
||||
@ -200,7 +199,7 @@ public class UpstreamPacketHandler extends LoggingPacketHandler {
|
||||
|
||||
geyser.getSessionManager().addPendingSession(session);
|
||||
|
||||
this.resourcePackLoadEvent = new SessionLoadResourcePacksEventImpl(session, new HashMap<>(Registries.RESOURCE_PACKS.get()));
|
||||
this.resourcePackLoadEvent = new SessionLoadResourcePacksEventImpl(session);
|
||||
this.geyser.eventBus().fire(this.resourcePackLoadEvent);
|
||||
|
||||
ResourcePacksInfoPacket resourcePacksInfo = new ResourcePacksInfoPacket();
|
||||
@ -208,7 +207,7 @@ public class UpstreamPacketHandler extends LoggingPacketHandler {
|
||||
ResourcePackManifest.Header header = pack.manifest().header();
|
||||
resourcePacksInfo.getResourcePackInfos().add(new ResourcePacksInfoPacket.Entry(
|
||||
header.uuid().toString(), header.version().toString(), pack.codec().size(), pack.contentKey(),
|
||||
pack.subpackName(), header.uuid().toString(), false, false));
|
||||
pack.defaultSubpackName(), header.uuid().toString(), false, false));
|
||||
}
|
||||
resourcePacksInfo.setForcedToAccept(GeyserImpl.getInstance().getConfig().isForceResourcePacks());
|
||||
session.sendUpstreamPacket(resourcePacksInfo);
|
||||
|
@ -25,62 +25,90 @@
|
||||
|
||||
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;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public class GeyserResourcePack implements ResourcePack {
|
||||
public record GeyserResourcePack(
|
||||
PackCodec codec,
|
||||
ResourcePackManifest manifest,
|
||||
String contentKey,
|
||||
String defaultSubpackName
|
||||
) 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;
|
||||
this(codec, manifest, contentKey, "");
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull PackCodec codec() {
|
||||
return this.codec;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull ResourcePackManifest manifest() {
|
||||
return this.manifest;
|
||||
}
|
||||
public static class Builder implements ResourcePack.Builder {
|
||||
|
||||
@Override
|
||||
public @NonNull String contentKey() {
|
||||
return this.contentKey == null ? "" : this.contentKey;
|
||||
}
|
||||
public Builder(PackCodec codec, ResourcePackManifest manifest) {
|
||||
this.codec = codec;
|
||||
this.manifest = manifest;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void contentKey(@Nullable String contentKey) {
|
||||
this.contentKey = contentKey;
|
||||
}
|
||||
public Builder(PackCodec codec, ResourcePackManifest manifest, String contentKey) {
|
||||
this.codec = codec;
|
||||
this.manifest = manifest;
|
||||
this.contentKey = contentKey;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull String subpackName() {
|
||||
return this.subpackName == null ? "" : this.subpackName;
|
||||
}
|
||||
private final PackCodec codec;
|
||||
private final ResourcePackManifest manifest;
|
||||
private String contentKey;
|
||||
private String defaultSubpackName;
|
||||
|
||||
@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!");
|
||||
@Override
|
||||
public ResourcePackManifest manifest() {
|
||||
return manifest;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PackCodec codec() {
|
||||
return codec;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String contentKey() {
|
||||
return this.contentKey == null ? "" : this.contentKey;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String defaultSubpackName() {
|
||||
return this.defaultSubpackName == null ? "" : this.defaultSubpackName;
|
||||
}
|
||||
|
||||
public Builder contentKey(@Nullable String contentKey) {
|
||||
this.contentKey = contentKey;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder defaultSubpackName(@Nullable String subpackName) {
|
||||
if (manifest.subpacks().stream().anyMatch(subpack -> subpack.name().equals(subpackName))) {
|
||||
this.defaultSubpackName = subpackName;
|
||||
} else {
|
||||
throw new IllegalArgumentException("A subpack with the name '" + subpackName + "' does not exist!");
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
public GeyserResourcePack build() {
|
||||
if (contentKey == null) {
|
||||
contentKey = "";
|
||||
}
|
||||
if (defaultSubpackName == null) {
|
||||
defaultSubpackName = "";
|
||||
}
|
||||
|
||||
return new GeyserResourcePack(codec, manifest, contentKey, defaultSubpackName);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -0,0 +1,57 @@
|
||||
/*
|
||||
* 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.pack.option;
|
||||
|
||||
import org.geysermc.geyser.api.pack.ResourcePack;
|
||||
import org.geysermc.geyser.api.pack.option.PriorityOption;
|
||||
|
||||
public class GeyserPriorityOption implements PriorityOption {
|
||||
|
||||
private final int priority;
|
||||
|
||||
public int priority() {
|
||||
return priority;
|
||||
}
|
||||
|
||||
public GeyserPriorityOption(int priority) {
|
||||
if (priority < 0 || priority > 10) {
|
||||
throw new IllegalArgumentException("Priority must be between 0 and 10 inclusive!");
|
||||
}
|
||||
this.priority = priority;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type type() {
|
||||
return Type.PRIORITY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validate(ResourcePack pack) {
|
||||
if (priority <= 10 && priority > 0) {
|
||||
throw new IllegalArgumentException("Priority must be between 0 and 10 inclusive!");
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,60 @@
|
||||
/*
|
||||
* 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.pack.option;
|
||||
|
||||
import org.geysermc.geyser.api.pack.ResourcePack;
|
||||
import org.geysermc.geyser.api.pack.ResourcePackManifest;
|
||||
import org.geysermc.geyser.api.pack.option.SubpackOption;
|
||||
|
||||
/**
|
||||
* 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()}
|
||||
*/
|
||||
public class GeyserSubpackOption implements SubpackOption {
|
||||
|
||||
private final String subpackName;
|
||||
|
||||
public GeyserSubpackOption(String subpackName) {
|
||||
this.subpackName = subpackName;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Type type() {
|
||||
return Type.SUBPACK;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void validate(ResourcePack pack) {
|
||||
if (pack.manifest().subpacks().stream().noneMatch(subpack -> subpack.name().equals(subpackName))) {
|
||||
throw new IllegalArgumentException("No subpack with the name %s found!".formatted(subpackName));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String subpackName() {
|
||||
return subpackName;
|
||||
}
|
||||
}
|
@ -79,15 +79,20 @@ public class GeyserPathPackCodec extends PathPackCodec {
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull SeekableByteChannel serialize(@NonNull ResourcePack resourcePack) throws IOException {
|
||||
public @NonNull SeekableByteChannel serialize() throws IOException {
|
||||
return FileChannel.open(this.path);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @NonNull ResourcePack create() {
|
||||
protected ResourcePack.@NonNull Builder createBuilder() {
|
||||
return ResourcePackLoader.readPack(this.path);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @NonNull ResourcePack create() {
|
||||
return createBuilder().build();
|
||||
}
|
||||
|
||||
private void checkLastModified() {
|
||||
try {
|
||||
FileTime lastModified = Files.getLastModifiedTime(this.path);
|
||||
|
@ -40,10 +40,12 @@ import org.geysermc.geyser.api.item.custom.CustomItemData;
|
||||
import org.geysermc.geyser.api.item.custom.CustomItemOptions;
|
||||
import org.geysermc.geyser.api.item.custom.NonVanillaCustomItemData;
|
||||
import org.geysermc.geyser.api.pack.PathPackCodec;
|
||||
import org.geysermc.geyser.impl.camera.GeyserCameraFade;
|
||||
import org.geysermc.geyser.impl.camera.GeyserCameraPosition;
|
||||
import org.geysermc.geyser.api.pack.option.PriorityOption;
|
||||
import org.geysermc.geyser.api.pack.option.SubpackOption;
|
||||
import org.geysermc.geyser.event.GeyserEventRegistrar;
|
||||
import org.geysermc.geyser.extension.command.GeyserExtensionCommand;
|
||||
import org.geysermc.geyser.impl.camera.GeyserCameraFade;
|
||||
import org.geysermc.geyser.impl.camera.GeyserCameraPosition;
|
||||
import org.geysermc.geyser.item.GeyserCustomItemData;
|
||||
import org.geysermc.geyser.item.GeyserCustomItemOptions;
|
||||
import org.geysermc.geyser.item.GeyserNonVanillaCustomItemData;
|
||||
@ -53,6 +55,8 @@ import org.geysermc.geyser.level.block.GeyserGeometryComponent;
|
||||
import org.geysermc.geyser.level.block.GeyserJavaBlockState;
|
||||
import org.geysermc.geyser.level.block.GeyserMaterialInstance;
|
||||
import org.geysermc.geyser.level.block.GeyserNonVanillaCustomBlockData;
|
||||
import org.geysermc.geyser.pack.option.GeyserPriorityOption;
|
||||
import org.geysermc.geyser.pack.option.GeyserSubpackOption;
|
||||
import org.geysermc.geyser.pack.path.GeyserPathPackCodec;
|
||||
import org.geysermc.geyser.registry.provider.ProviderSupplier;
|
||||
|
||||
@ -66,9 +70,10 @@ public class ProviderRegistryLoader implements RegistryLoader<Map<Class<?>, Prov
|
||||
|
||||
@Override
|
||||
public Map<Class<?>, ProviderSupplier> load(Map<Class<?>, ProviderSupplier> providers) {
|
||||
// misc
|
||||
// commands
|
||||
providers.put(Command.Builder.class, args -> new GeyserExtensionCommand.Builder<>((Extension) args[0]));
|
||||
|
||||
// custom blocks
|
||||
providers.put(CustomBlockComponents.Builder.class, args -> new GeyserCustomBlockComponents.Builder());
|
||||
providers.put(CustomBlockData.Builder.class, args -> new GeyserCustomBlockData.Builder());
|
||||
providers.put(JavaBlockState.Builder.class, args -> new GeyserJavaBlockState.Builder());
|
||||
@ -76,8 +81,13 @@ public class ProviderRegistryLoader implements RegistryLoader<Map<Class<?>, Prov
|
||||
providers.put(MaterialInstance.Builder.class, args -> new GeyserMaterialInstance.Builder());
|
||||
providers.put(GeometryComponent.Builder.class, args -> new GeyserGeometryComponent.Builder());
|
||||
|
||||
// misc
|
||||
providers.put(EventRegistrar.class, args -> new GeyserEventRegistrar(args[0]));
|
||||
|
||||
// packs
|
||||
providers.put(PathPackCodec.class, args -> new GeyserPathPackCodec((Path) args[0]));
|
||||
providers.put(PriorityOption.class, args -> new GeyserPriorityOption((int) args[0]));
|
||||
providers.put(SubpackOption.class, args -> new GeyserSubpackOption((String) args[0]));
|
||||
|
||||
// items
|
||||
providers.put(CustomItemData.Builder.class, args -> new GeyserCustomItemData.Builder());
|
||||
|
@ -99,7 +99,7 @@ public class ResourcePackLoader implements RegistryLoader<Path, Map<String, Reso
|
||||
|
||||
for (Path path : event.resourcePacks()) {
|
||||
try {
|
||||
GeyserResourcePack pack = readPack(path);
|
||||
GeyserResourcePack pack = readPack(path).build();
|
||||
packMap.put(pack.manifest().header().uuid().toString(), pack);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
@ -113,10 +113,10 @@ public class ResourcePackLoader implements RegistryLoader<Path, Map<String, Reso
|
||||
* but suffixed by ".key", containing the content key. If such file does not exist, no content key is stored.
|
||||
*
|
||||
* @param path the file to read from, in ZIP format
|
||||
* @return a {@link ResourcePack} representation
|
||||
* @return a {@link ResourcePack.Builder} representation
|
||||
* @throws IllegalArgumentException if the pack manifest was invalid or there was any processing exception
|
||||
*/
|
||||
public static GeyserResourcePack readPack(Path path) throws IllegalArgumentException {
|
||||
public static GeyserResourcePack.Builder readPack(Path path) throws IllegalArgumentException {
|
||||
if (!path.getFileName().toString().endsWith(".mcpack") && !path.getFileName().toString().endsWith(".zip")) {
|
||||
throw new IllegalArgumentException("Resource pack " + path.getFileName() + " must be a .zip or .mcpack file!");
|
||||
}
|
||||
@ -155,7 +155,7 @@ public class ResourcePackLoader implements RegistryLoader<Path, Map<String, Reso
|
||||
Path keyFile = path.resolveSibling(path.getFileName().toString() + ".key");
|
||||
String contentKey = Files.exists(keyFile) ? Files.readString(keyFile, StandardCharsets.UTF_8) : "";
|
||||
|
||||
return new GeyserResourcePack(new GeyserPathPackCodec(path), manifest, contentKey);
|
||||
return new GeyserResourcePack.Builder(new GeyserPathPackCodec(path), manifest, contentKey);
|
||||
} catch (Exception e) {
|
||||
throw new IllegalArgumentException(GeyserLocale.getLocaleStringLog("geyser.resource_pack.broken", path.getFileName()), e);
|
||||
}
|
||||
|
@ -62,7 +62,7 @@ public class ResourcePackLoaderTest {
|
||||
public void testPack() throws Exception {
|
||||
// this mcpack only contains a folder, which the manifest is in
|
||||
Path path = getResource("empty_pack.mcpack");
|
||||
ResourcePack pack = ResourcePackLoader.readPack(path);
|
||||
ResourcePack pack = ResourcePackLoader.readPack(path).build();
|
||||
assertEquals("", pack.contentKey());
|
||||
// should probably add some more tests here related to the manifest
|
||||
}
|
||||
@ -71,7 +71,7 @@ public class ResourcePackLoaderTest {
|
||||
public void testEncryptedPack() throws Exception {
|
||||
// this zip only contains a contents.json and manifest.json at the root
|
||||
Path path = getResource("encrypted_pack.zip");
|
||||
ResourcePack pack = ResourcePackLoader.readPack(path);
|
||||
ResourcePack pack = ResourcePackLoader.readPack(path).build();
|
||||
assertEquals("JAGcSXcXwcODc1YS70GzeWAUKEO172UA", pack.contentKey());
|
||||
}
|
||||
|
||||
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren