Mirror von
https://github.com/GeyserMC/Geyser.git
synchronisiert 2024-11-20 15:00:11 +01:00
Ensure we don't modify default options
Dieser Commit ist enthalten in:
Ursprung
250a9b43d1
Commit
fb4e42de6c
@ -26,6 +26,7 @@
|
|||||||
package org.geysermc.geyser.api.event.bedrock;
|
package org.geysermc.geyser.api.event.bedrock;
|
||||||
|
|
||||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
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.connection.GeyserConnection;
|
||||||
import org.geysermc.geyser.api.event.connection.ConnectionEvent;
|
import org.geysermc.geyser.api.event.connection.ConnectionEvent;
|
||||||
import org.geysermc.geyser.api.pack.ResourcePack;
|
import org.geysermc.geyser.api.pack.ResourcePack;
|
||||||
@ -64,11 +65,29 @@ public abstract class SessionLoadResourcePacksEvent extends ConnectionEvent {
|
|||||||
* specific options.
|
* specific options.
|
||||||
*
|
*
|
||||||
* @param resourcePack a resource pack that will be sent to the client.
|
* @param resourcePack a resource pack that will be sent to the client.
|
||||||
* @param resourcePackOptions {@link ResourcePackOption}'s that specify how clients load the pack
|
* @param options {@link ResourcePackOption}'s that specify how clients load the pack
|
||||||
* @return true if the resource pack was added successfully,
|
* @return true if the resource pack was added successfully,
|
||||||
* or false if already present
|
* or false if already present
|
||||||
*/
|
*/
|
||||||
public abstract boolean register(@NonNull ResourcePack resourcePack, ResourcePackOption... resourcePackOptions);
|
public abstract boolean register(@NonNull ResourcePack resourcePack, @Nullable ResourcePackOption... options);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets {@link ResourcePackOption}'s for a resource pack
|
||||||
|
*
|
||||||
|
* @param resourcePack the resource pack to register the options for
|
||||||
|
* @param options the options to register for the pack
|
||||||
|
* @throws IllegalArgumentException if the pack is not registered.
|
||||||
|
*/
|
||||||
|
public abstract void registerOptions(@NonNull ResourcePack resourcePack, @NonNull ResourcePackOption... options);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets {@link ResourcePackOption}'s for a resource pack
|
||||||
|
*
|
||||||
|
* @param uuid the resource pack uuid to register the options for
|
||||||
|
* @param options the options to register for the pack
|
||||||
|
* @throws IllegalArgumentException if the pack is not registered.
|
||||||
|
*/
|
||||||
|
public abstract void registerOptions(@NonNull UUID uuid, @NonNull ResourcePackOption... options);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the subpack options set for a specific resource pack.
|
* Returns the subpack options set for a specific resource pack.
|
||||||
@ -76,9 +95,7 @@ public abstract class SessionLoadResourcePacksEvent extends ConnectionEvent {
|
|||||||
* @param resourcePack the resourcePack for which the options are set
|
* @param resourcePack the resourcePack for which the options are set
|
||||||
* @return a list of {@link ResourcePackOption}
|
* @return a list of {@link ResourcePackOption}
|
||||||
*/
|
*/
|
||||||
Collection<ResourcePackOption> options(ResourcePack resourcePack) {
|
public abstract Collection<ResourcePackOption> options(ResourcePack resourcePack);
|
||||||
return options(resourcePack.manifest().header().uuid());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the subpack options set for a specific resource pack uuid.
|
* Returns the subpack options set for a specific resource pack uuid.
|
||||||
|
@ -30,6 +30,7 @@ import org.geysermc.geyser.api.GeyserApi;
|
|||||||
import org.geysermc.geyser.api.pack.option.ResourcePackOption;
|
import org.geysermc.geyser.api.pack.option.ResourcePackOption;
|
||||||
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a resource pack sent to Bedrock clients
|
* Represents a resource pack sent to Bedrock clients
|
||||||
@ -63,6 +64,14 @@ public interface ResourcePack {
|
|||||||
@NonNull
|
@NonNull
|
||||||
String contentKey();
|
String contentKey();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the resource pack uuid. Shortcut for getting the UUID from the header.
|
||||||
|
*/
|
||||||
|
@NonNull
|
||||||
|
default UUID uuid() {
|
||||||
|
return manifest().header().uuid();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets the currently set default options of this resource pack.
|
* Gets the currently set default options of this resource pack.
|
||||||
* These can be a priority defining how the Bedrock client applies multiple packs,
|
* These can be a priority defining how the Bedrock client applies multiple packs,
|
||||||
|
@ -28,6 +28,7 @@ package org.geysermc.geyser.event.type;
|
|||||||
import it.unimi.dsi.fastutil.objects.Object2ObjectLinkedOpenHashMap;
|
import it.unimi.dsi.fastutil.objects.Object2ObjectLinkedOpenHashMap;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||||
|
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||||
import org.cloudburstmc.protocol.bedrock.packet.ResourcePackStackPacket;
|
import org.cloudburstmc.protocol.bedrock.packet.ResourcePackStackPacket;
|
||||||
import org.cloudburstmc.protocol.bedrock.packet.ResourcePacksInfoPacket;
|
import org.cloudburstmc.protocol.bedrock.packet.ResourcePacksInfoPacket;
|
||||||
import org.geysermc.geyser.api.event.bedrock.SessionLoadResourcePacksEvent;
|
import org.geysermc.geyser.api.event.bedrock.SessionLoadResourcePacksEvent;
|
||||||
@ -36,20 +37,21 @@ import org.geysermc.geyser.api.pack.ResourcePackManifest;
|
|||||||
import org.geysermc.geyser.api.pack.option.PriorityOption;
|
import org.geysermc.geyser.api.pack.option.PriorityOption;
|
||||||
import org.geysermc.geyser.api.pack.option.ResourcePackOption;
|
import org.geysermc.geyser.api.pack.option.ResourcePackOption;
|
||||||
import org.geysermc.geyser.api.pack.option.SubpackOption;
|
import org.geysermc.geyser.api.pack.option.SubpackOption;
|
||||||
|
import org.geysermc.geyser.pack.GeyserResourcePack;
|
||||||
|
import org.geysermc.geyser.pack.option.GeyserSubpackOption;
|
||||||
|
import org.geysermc.geyser.pack.option.OptionHolder;
|
||||||
import org.geysermc.geyser.registry.Registries;
|
import org.geysermc.geyser.registry.Registries;
|
||||||
import org.geysermc.geyser.session.GeyserSession;
|
import org.geysermc.geyser.session.GeyserSession;
|
||||||
|
|
||||||
import java.util.AbstractMap;
|
import java.util.AbstractMap;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Objects;
|
||||||
import java.util.TreeSet;
|
import java.util.TreeSet;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
@ -57,22 +59,19 @@ import java.util.stream.Collectors;
|
|||||||
public class SessionLoadResourcePacksEventImpl extends SessionLoadResourcePacksEvent {
|
public class SessionLoadResourcePacksEventImpl extends SessionLoadResourcePacksEvent {
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
private final Map<UUID, ResourcePack> packs;
|
private final Map<UUID, GeyserResourcePack> packs;
|
||||||
private final Map<UUID, Collection<ResourcePackOption>> options = new HashMap<>();
|
private final Map<UUID, OptionHolder> options = new HashMap<>();
|
||||||
|
|
||||||
public SessionLoadResourcePacksEventImpl(GeyserSession session) {
|
public SessionLoadResourcePacksEventImpl(GeyserSession session) {
|
||||||
super(session);
|
super(session);
|
||||||
this.packs = new Object2ObjectLinkedOpenHashMap<>(Registries.RESOURCE_PACKS.get());
|
this.packs = new Object2ObjectLinkedOpenHashMap<>(Registries.RESOURCE_PACKS.get());
|
||||||
this.packs.values().forEach(
|
|
||||||
pack -> options.put(pack.manifest().header().uuid(), pack.defaultOptions())
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public LinkedList<ResourcePackStackPacket.Entry> orderedPacks() {
|
public LinkedList<ResourcePackStackPacket.Entry> orderedPacks() {
|
||||||
TreeSet<Map.Entry<ResourcePack, Integer>> sortedPacks = packs.values().stream()
|
TreeSet<Map.Entry<GeyserResourcePack, Integer>> sortedPacks = packs.values().stream()
|
||||||
// Map each ResourcePack to a pair of (ResourcePack, Priority)
|
// Map each ResourcePack to a pair of (ResourcePack, Priority)
|
||||||
.map(pack -> new AbstractMap.SimpleEntry<>(pack, getPriority(pack)))
|
.map(pack -> new AbstractMap.SimpleEntry<>(pack, getPriority(pack)))
|
||||||
// Sort by priority in descending order
|
// Sort by priority in ascending order
|
||||||
.collect(Collectors.toCollection(() -> new TreeSet<>(Map.Entry.comparingByValue(Comparator.naturalOrder()))));
|
.collect(Collectors.toCollection(() -> new TreeSet<>(Map.Entry.comparingByValue(Comparator.naturalOrder()))));
|
||||||
|
|
||||||
// Convert the sorted entries to a LinkedList of ResourcePackStackPacket.Entry
|
// Convert the sorted entries to a LinkedList of ResourcePackStackPacket.Entry
|
||||||
@ -82,42 +81,52 @@ public class SessionLoadResourcePacksEventImpl extends SessionLoadResourcePacksE
|
|||||||
return new ResourcePackStackPacket.Entry(
|
return new ResourcePackStackPacket.Entry(
|
||||||
header.uuid().toString(),
|
header.uuid().toString(),
|
||||||
header.version().toString(),
|
header.version().toString(),
|
||||||
getSubpackName(header.uuid())
|
getSubpackName(entry.getKey())
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
.collect(Collectors.toCollection(LinkedList::new));
|
.collect(Collectors.toCollection(LinkedList::new));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Helper method to get the priority of a ResourcePack
|
// Helper method to get the priority of a ResourcePack
|
||||||
private int getPriority(ResourcePack pack) {
|
private int getPriority(GeyserResourcePack pack) {
|
||||||
return options.get(pack.manifest().header().uuid()).stream()
|
ResourcePackOption option;
|
||||||
.filter(option -> option instanceof PriorityOption)
|
OptionHolder holder = options.get(pack.uuid());
|
||||||
.mapToInt(option -> ((PriorityOption) option).priority())
|
|
||||||
.max()
|
if (holder == null) {
|
||||||
.orElse(PriorityOption.NORMAL.priority());
|
option = pack.options().get(ResourcePackOption.Type.PRIORITY);
|
||||||
|
} else {
|
||||||
|
option = options.get(pack.uuid())
|
||||||
|
.getOrDefault(ResourcePackOption.Type.PRIORITY, pack, PriorityOption.NORMAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return ((PriorityOption) option).priority();
|
||||||
|
}
|
||||||
|
|
||||||
public List<ResourcePacksInfoPacket.Entry> infoPacketEntries() {
|
public List<ResourcePacksInfoPacket.Entry> infoPacketEntries() {
|
||||||
List<ResourcePacksInfoPacket.Entry> entries = new ArrayList<>();
|
List<ResourcePacksInfoPacket.Entry> entries = new ArrayList<>();
|
||||||
|
|
||||||
for (ResourcePack pack : packs.values()) {
|
for (GeyserResourcePack pack : packs.values()) {
|
||||||
ResourcePackManifest.Header header = pack.manifest().header();
|
ResourcePackManifest.Header header = pack.manifest().header();
|
||||||
entries.add(new ResourcePacksInfoPacket.Entry(
|
entries.add(new ResourcePacksInfoPacket.Entry(
|
||||||
header.uuid().toString(), header.version().toString(), pack.codec().size(), pack.contentKey(),
|
header.uuid().toString(), header.version().toString(), pack.codec().size(), pack.contentKey(),
|
||||||
getSubpackName(header.uuid()), header.uuid().toString(), false, false)
|
getSubpackName(pack), header.uuid().toString(), false, false)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return entries;
|
return entries;
|
||||||
}
|
}
|
||||||
|
|
||||||
private String getSubpackName(UUID uuid) {
|
private String getSubpackName(GeyserResourcePack pack) {
|
||||||
return options.get(uuid).stream()
|
OptionHolder holder = options.get(pack.uuid());
|
||||||
.filter(option -> option instanceof SubpackOption)
|
ResourcePackOption option;
|
||||||
.map(option -> ((SubpackOption) option).subpackName())
|
if (holder == null) {
|
||||||
.findFirst()
|
option = pack.options().getOrDefault(ResourcePackOption.Type.PRIORITY, GeyserSubpackOption.EMPTY);
|
||||||
.orElse(""); // Return an empty string if none is found
|
} else {
|
||||||
|
option = options.get(pack.uuid())
|
||||||
|
.getOrDefault(ResourcePackOption.Type.PRIORITY, pack, GeyserSubpackOption.EMPTY);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ((SubpackOption) option).subpackName();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -127,35 +136,73 @@ public class SessionLoadResourcePacksEventImpl extends SessionLoadResourcePacksE
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean register(@NonNull ResourcePack resourcePack) {
|
public boolean register(@NonNull ResourcePack resourcePack) {
|
||||||
|
validate(resourcePack);
|
||||||
return register(resourcePack, PriorityOption.NORMAL);
|
return register(resourcePack, PriorityOption.NORMAL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void registerOption(@NonNull ResourcePack resourcePack, @NonNull ResourcePackOption option) {
|
||||||
|
GeyserResourcePack pack = validate(resourcePack);
|
||||||
|
|
||||||
|
OptionHolder holder = this.options.computeIfAbsent(pack.uuid(), $ -> new OptionHolder());
|
||||||
|
holder.add(option);
|
||||||
|
holder.validateOptions(pack);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean register(@NonNull ResourcePack resourcePack, ResourcePackOption... resourcePackOptions) {
|
public boolean register(@NonNull ResourcePack resourcePack, @Nullable ResourcePackOption... options) {
|
||||||
|
GeyserResourcePack pack = validate(resourcePack);
|
||||||
|
|
||||||
// Validate options, check for duplicates
|
UUID uuid = resourcePack.uuid();
|
||||||
Set<ResourcePackOption.Type> types = new HashSet<>();
|
if (packs.containsValue(pack) || packs.containsKey(uuid)) {
|
||||||
for (ResourcePackOption option : resourcePackOptions) {
|
|
||||||
option.validate(resourcePack);
|
|
||||||
if (!types.add(option.type())) {
|
|
||||||
throw new IllegalArgumentException("Duplicate resource pack option " + option + "!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
types.clear();
|
|
||||||
|
|
||||||
UUID uuid = resourcePack.manifest().header().uuid();
|
|
||||||
if (packs.containsValue(resourcePack) || packs.containsKey(uuid)) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
packs.put(uuid, resourcePack);
|
packs.put(uuid, pack);
|
||||||
options.put(uuid, List.of(resourcePackOptions));
|
|
||||||
|
// register options
|
||||||
|
OptionHolder holder = new OptionHolder();
|
||||||
|
holder.add(options);
|
||||||
|
holder.validateOptions(pack);
|
||||||
|
this.options.put(uuid, holder);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Collection<ResourcePackOption> options(UUID uuid) {
|
public void registerOptions(@NonNull ResourcePack resourcePack, @NonNull ResourcePackOption... options) {
|
||||||
return Collections.unmodifiableCollection(options.get(uuid));
|
validate(resourcePack);
|
||||||
|
registerOptions(resourcePack.uuid());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void registerOptions(@NonNull UUID uuid, @NonNull ResourcePackOption... options) {
|
||||||
|
Objects.requireNonNull(uuid);
|
||||||
|
GeyserResourcePack resourcePack = packs.get(uuid);
|
||||||
|
if (resourcePack == null) {
|
||||||
|
throw new IllegalArgumentException("Pack with uuid %s not registered yet!".formatted(uuid));
|
||||||
|
}
|
||||||
|
|
||||||
|
OptionHolder holder = this.options.computeIfAbsent(uuid, $ -> new OptionHolder());
|
||||||
|
holder.add(options);
|
||||||
|
holder.validateOptions(resourcePack);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Collection<ResourcePackOption> options(@NonNull ResourcePack resourcePack) {
|
||||||
|
validate(resourcePack);
|
||||||
|
return options(resourcePack.uuid());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Collection<ResourcePackOption> options(@NonNull UUID uuid) {
|
||||||
|
Objects.requireNonNull(uuid);
|
||||||
|
GeyserResourcePack pack = packs.get(uuid);
|
||||||
|
if (pack == null) {
|
||||||
|
throw new IllegalArgumentException("ResourcePack with " + uuid + " not found, unable to provide options");
|
||||||
|
}
|
||||||
|
|
||||||
|
OptionHolder holder = options.getOrDefault(uuid, new OptionHolder());
|
||||||
|
return holder.immutableValues(pack);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -163,4 +210,14 @@ public class SessionLoadResourcePacksEventImpl extends SessionLoadResourcePacksE
|
|||||||
options.remove(uuid);
|
options.remove(uuid);
|
||||||
return packs.remove(uuid) != null;
|
return packs.remove(uuid) != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private GeyserResourcePack validate(@NonNull ResourcePack resourcePack) {
|
||||||
|
Objects.requireNonNull(resourcePack);
|
||||||
|
if (resourcePack instanceof GeyserResourcePack geyserResourcePack) {
|
||||||
|
return geyserResourcePack;
|
||||||
|
} else {
|
||||||
|
throw new IllegalArgumentException("Unknown resource pack implementation: %s".
|
||||||
|
formatted(resourcePack.getClass().getSuperclass().getName()));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -29,23 +29,17 @@ import org.checkerframework.checker.nullness.qual.NonNull;
|
|||||||
import org.geysermc.geyser.api.pack.PackCodec;
|
import org.geysermc.geyser.api.pack.PackCodec;
|
||||||
import org.geysermc.geyser.api.pack.ResourcePack;
|
import org.geysermc.geyser.api.pack.ResourcePack;
|
||||||
import org.geysermc.geyser.api.pack.ResourcePackManifest;
|
import org.geysermc.geyser.api.pack.ResourcePackManifest;
|
||||||
import org.geysermc.geyser.api.pack.option.PriorityOption;
|
|
||||||
import org.geysermc.geyser.api.pack.option.ResourcePackOption;
|
import org.geysermc.geyser.api.pack.option.ResourcePackOption;
|
||||||
|
import org.geysermc.geyser.pack.option.OptionHolder;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
public record GeyserResourcePack(
|
public record GeyserResourcePack(
|
||||||
PackCodec codec,
|
PackCodec codec,
|
||||||
ResourcePackManifest manifest,
|
ResourcePackManifest manifest,
|
||||||
String contentKey,
|
String contentKey,
|
||||||
Collection<ResourcePackOption> defaultOptions
|
OptionHolder options
|
||||||
) implements ResourcePack {
|
) implements ResourcePack {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -53,8 +47,13 @@ public record GeyserResourcePack(
|
|||||||
*/
|
*/
|
||||||
public static final int CHUNK_SIZE = 102400;
|
public static final int CHUNK_SIZE = 102400;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Collection<ResourcePackOption> defaultOptions() {
|
||||||
|
return options.immutableValues();
|
||||||
|
}
|
||||||
|
|
||||||
public GeyserResourcePack(PackCodec codec, ResourcePackManifest manifest, String contentKey) {
|
public GeyserResourcePack(PackCodec codec, ResourcePackManifest manifest, String contentKey) {
|
||||||
this(codec, manifest, contentKey, new ArrayList<>(List.of(PriorityOption.NORMAL)));
|
this(codec, manifest, contentKey, new OptionHolder());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class Builder implements ResourcePack.Builder {
|
public static class Builder implements ResourcePack.Builder {
|
||||||
@ -73,7 +72,7 @@ public record GeyserResourcePack(
|
|||||||
private final PackCodec codec;
|
private final PackCodec codec;
|
||||||
private final ResourcePackManifest manifest;
|
private final ResourcePackManifest manifest;
|
||||||
private String contentKey = "";
|
private String contentKey = "";
|
||||||
private final Collection<ResourcePackOption> defaultOptions = new ArrayList<>(List.of(PriorityOption.NORMAL));
|
private final OptionHolder optionHolder = new OptionHolder();
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ResourcePackManifest manifest() {
|
public ResourcePackManifest manifest() {
|
||||||
@ -92,7 +91,7 @@ public record GeyserResourcePack(
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Collection<ResourcePackOption> defaultOptions() {
|
public Collection<ResourcePackOption> defaultOptions() {
|
||||||
return Collections.unmodifiableCollection(defaultOptions);
|
return optionHolder.immutableValues();
|
||||||
}
|
}
|
||||||
|
|
||||||
public Builder contentKey(@NonNull String contentKey) {
|
public Builder contentKey(@NonNull String contentKey) {
|
||||||
@ -101,23 +100,15 @@ public record GeyserResourcePack(
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Builder defaultOptions(ResourcePackOption... defaultOptions) {
|
public Builder defaultOptions(@NonNull ResourcePackOption... defaultOptions) {
|
||||||
this.defaultOptions.addAll(Arrays.stream(defaultOptions).toList());
|
Objects.requireNonNull(defaultOptions);
|
||||||
|
this.optionHolder.add(defaultOptions);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public GeyserResourcePack build() {
|
public GeyserResourcePack build() {
|
||||||
// Check for duplicates
|
GeyserResourcePack pack = new GeyserResourcePack(codec, manifest, contentKey, optionHolder);
|
||||||
Set<ResourcePackOption.Type> types = new HashSet<>();
|
optionHolder.validateOptions(pack);
|
||||||
for (ResourcePackOption option : defaultOptions) {
|
|
||||||
if (!types.add(option.type())) {
|
|
||||||
throw new IllegalArgumentException("Duplicate resource pack option " + option + "!");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
types.clear();
|
|
||||||
|
|
||||||
GeyserResourcePack pack = new GeyserResourcePack(codec, manifest, contentKey, defaultOptions);
|
|
||||||
defaultOptions.forEach(option -> option.validate(pack));
|
|
||||||
return pack;
|
return pack;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -38,6 +38,8 @@ import java.util.Objects;
|
|||||||
*/
|
*/
|
||||||
public record GeyserSubpackOption(String subpackName) implements SubpackOption {
|
public record GeyserSubpackOption(String subpackName) implements SubpackOption {
|
||||||
|
|
||||||
|
public static final GeyserSubpackOption EMPTY = new GeyserSubpackOption("");
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @NonNull Type type() {
|
public @NonNull Type type() {
|
||||||
return Type.SUBPACK;
|
return Type.SUBPACK;
|
||||||
|
108
core/src/main/java/org/geysermc/geyser/pack/option/OptionHolder.java
Normale Datei
108
core/src/main/java/org/geysermc/geyser/pack/option/OptionHolder.java
Normale Datei
@ -0,0 +1,108 @@
|
|||||||
|
/*
|
||||||
|
* 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;
|
||||||
|
import org.geysermc.geyser.api.pack.option.ResourcePackOption;
|
||||||
|
import org.geysermc.geyser.pack.GeyserResourcePack;
|
||||||
|
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
public class OptionHolder extends HashMap<ResourcePackOption.Type, ResourcePackOption> {
|
||||||
|
|
||||||
|
public void add(ResourcePackOption option) {
|
||||||
|
if (super.containsKey(option.type())) {
|
||||||
|
super.replace(option.type(), option);
|
||||||
|
} else {
|
||||||
|
super.put(option.type(), option);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void add(ResourcePackOption... options) {
|
||||||
|
for (ResourcePackOption option : options) {
|
||||||
|
add(option);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public ResourcePackOption getOrDefault(ResourcePackOption.Type type,
|
||||||
|
GeyserResourcePack pack,
|
||||||
|
ResourcePackOption defaultValue) {
|
||||||
|
ResourcePackOption option = super.get(type);
|
||||||
|
if (option != null) {
|
||||||
|
return option;
|
||||||
|
}
|
||||||
|
|
||||||
|
ResourcePackOption packOption = pack.options().get(type);
|
||||||
|
if (packOption != null) {
|
||||||
|
return packOption;
|
||||||
|
}
|
||||||
|
|
||||||
|
return defaultValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void remove(ResourcePackOption option) {
|
||||||
|
super.remove(option.type());
|
||||||
|
}
|
||||||
|
|
||||||
|
public OptionHolder() {
|
||||||
|
super();
|
||||||
|
add(PriorityOption.NORMAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void validateOptions(ResourcePack pack) {
|
||||||
|
values().forEach(option -> option.validate(pack));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the options of this option holder in an immutable collection
|
||||||
|
*/
|
||||||
|
public Collection<ResourcePackOption> immutableValues() {
|
||||||
|
return Collections.unmodifiableCollection(values());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return the options of this option holder, with fallbacks to options of a {@link GeyserResourcePack}
|
||||||
|
* if they're not already overridden here
|
||||||
|
*/
|
||||||
|
public Collection<ResourcePackOption> immutableValues(GeyserResourcePack pack) {
|
||||||
|
if (pack.options().isEmpty()) {
|
||||||
|
return immutableValues();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a map to hold the combined values
|
||||||
|
Map<ResourcePackOption.Type, ResourcePackOption> combinedOptions = new HashMap<>(this);
|
||||||
|
|
||||||
|
// Add options from the pack if not already overridden by this OptionHolder
|
||||||
|
pack.options().forEach(combinedOptions::putIfAbsent);
|
||||||
|
|
||||||
|
// Return an immutable collection of the combined options
|
||||||
|
return Collections.unmodifiableCollection(combinedOptions.values());
|
||||||
|
}
|
||||||
|
}
|
@ -33,14 +33,22 @@ import org.cloudburstmc.nbt.NbtMapBuilder;
|
|||||||
import org.cloudburstmc.protocol.bedrock.data.inventory.crafting.PotionMixData;
|
import org.cloudburstmc.protocol.bedrock.data.inventory.crafting.PotionMixData;
|
||||||
import org.cloudburstmc.protocol.bedrock.packet.BedrockPacket;
|
import org.cloudburstmc.protocol.bedrock.packet.BedrockPacket;
|
||||||
import org.geysermc.geyser.GeyserImpl;
|
import org.geysermc.geyser.GeyserImpl;
|
||||||
import org.geysermc.geyser.api.pack.ResourcePack;
|
|
||||||
import org.geysermc.geyser.entity.EntityDefinition;
|
import org.geysermc.geyser.entity.EntityDefinition;
|
||||||
import org.geysermc.geyser.inventory.recipe.GeyserRecipe;
|
import org.geysermc.geyser.inventory.recipe.GeyserRecipe;
|
||||||
import org.geysermc.geyser.item.type.Item;
|
import org.geysermc.geyser.item.type.Item;
|
||||||
import org.geysermc.geyser.registry.loader.*;
|
import org.geysermc.geyser.pack.GeyserResourcePack;
|
||||||
|
import org.geysermc.geyser.registry.loader.BiomeIdentifierRegistryLoader;
|
||||||
|
import org.geysermc.geyser.registry.loader.BlockEntityRegistryLoader;
|
||||||
|
import org.geysermc.geyser.registry.loader.ParticleTypesRegistryLoader;
|
||||||
|
import org.geysermc.geyser.registry.loader.PotionMixRegistryLoader;
|
||||||
|
import org.geysermc.geyser.registry.loader.ProviderRegistryLoader;
|
||||||
|
import org.geysermc.geyser.registry.loader.RecipeRegistryLoader;
|
||||||
|
import org.geysermc.geyser.registry.loader.RegistryLoaders;
|
||||||
|
import org.geysermc.geyser.registry.loader.SoundEventsRegistryLoader;
|
||||||
|
import org.geysermc.geyser.registry.loader.SoundRegistryLoader;
|
||||||
|
import org.geysermc.geyser.registry.loader.SoundTranslatorRegistryLoader;
|
||||||
import org.geysermc.geyser.registry.populator.ItemRegistryPopulator;
|
import org.geysermc.geyser.registry.populator.ItemRegistryPopulator;
|
||||||
import org.geysermc.geyser.registry.populator.PacketRegistryPopulator;
|
import org.geysermc.geyser.registry.populator.PacketRegistryPopulator;
|
||||||
import org.geysermc.geyser.registry.loader.RecipeRegistryLoader;
|
|
||||||
import org.geysermc.geyser.registry.provider.ProviderSupplier;
|
import org.geysermc.geyser.registry.provider.ProviderSupplier;
|
||||||
import org.geysermc.geyser.registry.type.ItemMappings;
|
import org.geysermc.geyser.registry.type.ItemMappings;
|
||||||
import org.geysermc.geyser.registry.type.ParticleMapping;
|
import org.geysermc.geyser.registry.type.ParticleMapping;
|
||||||
@ -56,7 +64,14 @@ import org.geysermc.mcprotocollib.protocol.data.game.level.event.LevelEvent;
|
|||||||
import org.geysermc.mcprotocollib.protocol.data.game.level.particle.ParticleType;
|
import org.geysermc.mcprotocollib.protocol.data.game.level.particle.ParticleType;
|
||||||
import org.geysermc.mcprotocollib.protocol.data.game.recipe.RecipeType;
|
import org.geysermc.mcprotocollib.protocol.data.game.recipe.RecipeType;
|
||||||
|
|
||||||
import java.util.*;
|
import java.util.ArrayList;
|
||||||
|
import java.util.EnumMap;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.IdentityHashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Holds all the common registries in Geyser.
|
* Holds all the common registries in Geyser.
|
||||||
@ -143,9 +158,9 @@ public final class Registries {
|
|||||||
public static final SimpleMappedRegistry<RecipeType, List<GeyserRecipe>> RECIPES = SimpleMappedRegistry.create("mappings/recipes.nbt", RecipeRegistryLoader::new);
|
public static final SimpleMappedRegistry<RecipeType, List<GeyserRecipe>> RECIPES = SimpleMappedRegistry.create("mappings/recipes.nbt", RecipeRegistryLoader::new);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A mapped registry holding {@link ResourcePack}'s with the pack uuid as keys.
|
* A mapped registry holding {@link GeyserResourcePack}'s with the pack uuid as keys.
|
||||||
*/
|
*/
|
||||||
public static final DeferredRegistry<Map<UUID, ResourcePack>> RESOURCE_PACKS = DeferredRegistry.create(GeyserImpl.getInstance().packDirectory(), SimpleMappedRegistry::create, RegistryLoaders.RESOURCE_PACKS);
|
public static final DeferredRegistry<Map<UUID, GeyserResourcePack>> RESOURCE_PACKS = DeferredRegistry.create(GeyserImpl.getInstance().packDirectory(), SimpleMappedRegistry::create, RegistryLoaders.RESOURCE_PACKS);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A mapped registry holding sound identifiers to their corresponding {@link SoundMapping}.
|
* A mapped registry holding sound identifiers to their corresponding {@link SoundMapping}.
|
||||||
|
@ -55,7 +55,7 @@ import java.util.zip.ZipFile;
|
|||||||
/**
|
/**
|
||||||
* Loads {@link ResourcePack}s within a {@link Path} directory, firing the {@link GeyserLoadResourcePacksEvent}.
|
* Loads {@link ResourcePack}s within a {@link Path} directory, firing the {@link GeyserLoadResourcePacksEvent}.
|
||||||
*/
|
*/
|
||||||
public class ResourcePackLoader implements RegistryLoader<Path, Map<UUID, ResourcePack>> {
|
public class ResourcePackLoader implements RegistryLoader<Path, Map<UUID, GeyserResourcePack>> {
|
||||||
|
|
||||||
static final PathMatcher PACK_MATCHER = FileSystems.getDefault().getPathMatcher("glob:**.{zip,mcpack}");
|
static final PathMatcher PACK_MATCHER = FileSystems.getDefault().getPathMatcher("glob:**.{zip,mcpack}");
|
||||||
|
|
||||||
@ -65,8 +65,8 @@ public class ResourcePackLoader implements RegistryLoader<Path, Map<UUID, Resour
|
|||||||
* Loop through the packs directory and locate valid resource pack files
|
* Loop through the packs directory and locate valid resource pack files
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public Map<UUID, ResourcePack> load(Path directory) {
|
public Map<UUID, GeyserResourcePack> load(Path directory) {
|
||||||
Map<UUID, ResourcePack> packMap = new HashMap<>();
|
Map<UUID, GeyserResourcePack> packMap = new HashMap<>();
|
||||||
|
|
||||||
if (!Files.exists(directory)) {
|
if (!Files.exists(directory)) {
|
||||||
try {
|
try {
|
||||||
@ -101,7 +101,7 @@ public class ResourcePackLoader implements RegistryLoader<Path, Map<UUID, Resour
|
|||||||
for (Path path : event.resourcePacks()) {
|
for (Path path : event.resourcePacks()) {
|
||||||
try {
|
try {
|
||||||
GeyserResourcePack pack = readPack(path).build();
|
GeyserResourcePack pack = readPack(path).build();
|
||||||
packMap.put(pack.manifest().header().uuid(), pack);
|
packMap.put(pack.uuid(), pack);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
e.printStackTrace();
|
e.printStackTrace();
|
||||||
}
|
}
|
||||||
|
Laden…
In neuem Issue referenzieren
Einen Benutzer sperren