3
0
Mirror von https://github.com/GeyserMC/Geyser.git synchronisiert 2024-11-20 15:00:11 +01:00

smol cleanup: don't register packs if their options failed to register; clean up holders, fluent accessors

Dieser Commit ist enthalten in:
onebeastchris 2024-09-18 20:55:19 +08:00
Ursprung 19954a201c
Commit 3bf5da1476
6 geänderte Dateien mit 94 neuen und 86 gelöschten Zeilen

Datei anzeigen

@ -32,6 +32,7 @@ import org.geysermc.geyser.api.GeyserApi;
* When a Bedrock client is unable to download a resource pack from a URL, Geyser will, by default, * 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 org.geysermc.geyser.api.pack.PathPackCodec}). * serve the resource pack over raknet (as packs are served with the {@link org.geysermc.geyser.api.pack.PathPackCodec}).
* This option can be used to disable that behavior, and disconnect the player instead. * This option can be used to disable that behavior, and disconnect the player instead.
* By default, {@link UrlFallbackOption#TRUE} is set.
*/ */
public interface UrlFallbackOption extends ResourcePackOption<Boolean> { public interface UrlFallbackOption extends ResourcePackOption<Boolean> {

Datei anzeigen

@ -63,10 +63,8 @@ public class GeyserDefineResourcePacksEventImpl extends GeyserDefineResourcePack
} }
ResourcePackHolder holder = ResourcePackHolder.of(pack); ResourcePackHolder holder = ResourcePackHolder.of(pack);
packs.put(uuid, holder);
// register options
registerOption(holder, options); registerOption(holder, options);
packs.put(uuid, holder);
return true; return true;
} }
@ -75,12 +73,12 @@ public class GeyserDefineResourcePacksEventImpl extends GeyserDefineResourcePack
Objects.requireNonNull(uuid); Objects.requireNonNull(uuid);
Objects.requireNonNull(options); Objects.requireNonNull(options);
ResourcePackHolder packHolder = packs.get(uuid); ResourcePackHolder holder = packs.get(uuid);
if (packHolder == null) { if (holder == null) {
throw new IllegalArgumentException("ResourcePack with " + uuid + " not found, unable to provide options"); throw new IllegalArgumentException("resource pack with uuid " + uuid + " not found, unable to register options");
} }
registerOption(packHolder, options); registerOption(holder, options);
} }
@Override @Override
@ -88,7 +86,7 @@ public class GeyserDefineResourcePacksEventImpl extends GeyserDefineResourcePack
Objects.requireNonNull(uuid); Objects.requireNonNull(uuid);
ResourcePackHolder packHolder = packs.get(uuid); ResourcePackHolder packHolder = packs.get(uuid);
if (packHolder == null) { if (packHolder == null) {
throw new IllegalArgumentException("ResourcePack with " + uuid + " not found, unable to provide options"); throw new IllegalArgumentException("resource pack with uuid " + uuid + " not found, unable to provide options");
} }
return packHolder.optionHolder().immutableValues(); return packHolder.optionHolder().immutableValues();
@ -101,7 +99,7 @@ public class GeyserDefineResourcePacksEventImpl extends GeyserDefineResourcePack
ResourcePackHolder packHolder = packs.get(uuid); ResourcePackHolder packHolder = packs.get(uuid);
if (packHolder == null) { if (packHolder == null) {
throw new IllegalArgumentException("ResourcePack with " + uuid + " not found, unable to provide options"); throw new IllegalArgumentException("resource pack with uuid " + uuid + " not found, unable to provide option");
} }
return packHolder.optionHolder().get(type); return packHolder.optionHolder().get(type);
@ -117,8 +115,7 @@ public class GeyserDefineResourcePacksEventImpl extends GeyserDefineResourcePack
return; return;
} }
holder.optionHolder().add(options); holder.optionHolder().validateAndAdd(holder.pack(), options);
holder.optionHolder().validateOptions(holder.pack());
} }
private GeyserResourcePack validate(@NonNull ResourcePack resourcePack) { private GeyserResourcePack validate(@NonNull ResourcePack resourcePack) {
@ -126,7 +123,7 @@ public class GeyserDefineResourcePacksEventImpl extends GeyserDefineResourcePack
if (resourcePack instanceof GeyserResourcePack geyserResourcePack) { if (resourcePack instanceof GeyserResourcePack geyserResourcePack) {
return geyserResourcePack; return geyserResourcePack;
} else { } else {
throw new IllegalArgumentException("Unknown resource pack implementation: %s". throw new IllegalArgumentException("unknown resource pack implementation: %s".
formatted(resourcePack.getClass().getSuperclass().getName())); formatted(resourcePack.getClass().getSuperclass().getName()));
} }
} }

Datei anzeigen

@ -55,14 +55,24 @@ import java.util.UUID;
public class SessionLoadResourcePacksEventImpl extends SessionLoadResourcePacksEvent { public class SessionLoadResourcePacksEventImpl extends SessionLoadResourcePacksEvent {
/**
* The packs for this Session. A {@link ResourcePackHolder} may contain resource pack options registered
* during the {@link org.geysermc.geyser.api.event.lifecycle.GeyserDefineResourcePacksEvent}.
*/
@Getter @Getter
private final Map<UUID, ResourcePackHolder> packs; private final Map<UUID, ResourcePackHolder> packs;
private final Map<UUID, OptionHolder> options;
/**
* The additional, per-session options for the resource packs of this session.
* These options are prioritized over the "default" options registered
* in the {@link org.geysermc.geyser.api.event.lifecycle.GeyserDefineResourcePacksEvent}
*/
private final Map<UUID, OptionHolder> sessionPackOptionOverrides;
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.options = new Object2ObjectOpenHashMap<>(); this.sessionPackOptionOverrides = new Object2ObjectOpenHashMap<>();
} }
@Override @Override
@ -84,20 +94,18 @@ public class SessionLoadResourcePacksEventImpl extends SessionLoadResourcePacksE
return false; return false;
} }
registerOption(pack, options);
packs.put(uuid, ResourcePackHolder.of(pack)); packs.put(uuid, ResourcePackHolder.of(pack));
// register options
registerOption(resourcePack, options);
return true; return true;
} }
@Override @Override
public void registerOptions(@NonNull UUID uuid, @NonNull ResourcePackOption<?>... options) { public void registerOptions(@NonNull UUID uuid, @NonNull ResourcePackOption<?>... options) {
Objects.requireNonNull(uuid); Objects.requireNonNull(uuid, "uuid cannot be null");
Objects.requireNonNull(options); Objects.requireNonNull(options, "options cannot be null");
ResourcePackHolder holder = packs.get(uuid); ResourcePackHolder holder = packs.get(uuid);
if (holder == null) { if (holder == null) {
throw new IllegalArgumentException("ResourcePack with " + uuid + " not found, unable to provide options"); throw new IllegalArgumentException("resource pack with uuid " + uuid + " not found, unable to register options");
} }
registerOption(holder.pack(), options); registerOption(holder.pack(), options);
@ -108,10 +116,16 @@ public class SessionLoadResourcePacksEventImpl extends SessionLoadResourcePacksE
Objects.requireNonNull(uuid); Objects.requireNonNull(uuid);
ResourcePackHolder packHolder = packs.get(uuid); ResourcePackHolder packHolder = packs.get(uuid);
if (packHolder == null) { if (packHolder == null) {
throw new IllegalArgumentException("ResourcePack with " + uuid + " not found, unable to provide options"); throw new IllegalArgumentException("resource pack with uuid " + uuid + " not found, unable to provide options");
}
OptionHolder optionHolder = sessionPackOptionOverrides.get(uuid);
if (optionHolder == null) {
// Not creating a new option holder here since it would
// override the default priority option
return packHolder.optionHolder().immutableValues();
} }
OptionHolder optionHolder = options.getOrDefault(uuid, new OptionHolder());
return optionHolder.immutableValues(packHolder.optionHolder()); return optionHolder.immutableValues(packHolder.optionHolder());
} }
@ -122,32 +136,29 @@ public class SessionLoadResourcePacksEventImpl extends SessionLoadResourcePacksE
ResourcePackHolder packHolder = packs.get(uuid); ResourcePackHolder packHolder = packs.get(uuid);
if (packHolder == null) { if (packHolder == null) {
throw new IllegalArgumentException("ResourcePack with " + uuid + " not found, unable to provide options"); throw new IllegalArgumentException("resource pack with uuid " + uuid + " not found, unable to provide option");
} }
OptionHolder holder = options.get(uuid); @Nullable OptionHolder additionalOptions = sessionPackOptionOverrides.get(uuid);
OptionHolder defaultHolder = packHolder.optionHolder(); OptionHolder defaultHolder = packHolder.optionHolder();
Objects.requireNonNull(defaultHolder); // should never be null Objects.requireNonNull(defaultHolder); // should never be null
return OptionHolder.getOptionByType(type, holder, defaultHolder); return OptionHolder.optionByType(type, additionalOptions, defaultHolder);
} }
@Override @Override
public boolean unregister(@NonNull UUID uuid) { public boolean unregister(@NonNull UUID uuid) {
options.remove(uuid); sessionPackOptionOverrides.remove(uuid);
return packs.remove(uuid) != null; return packs.remove(uuid) != null;
} }
private void registerOption(@NonNull ResourcePack resourcePack, @Nullable ResourcePackOption<?>... options) { private void registerOption(@NonNull GeyserResourcePack pack, @Nullable ResourcePackOption<?>... options) {
if (options == null) { if (options == null) {
return; return;
} }
GeyserResourcePack pack = validate(resourcePack); OptionHolder holder = this.sessionPackOptionOverrides.computeIfAbsent(pack.uuid(), $ -> new OptionHolder());
holder.validateAndAdd(pack, options);
OptionHolder holder = this.options.computeIfAbsent(pack.uuid(), $ -> new OptionHolder());
holder.add(options);
holder.validateOptions(pack);
} }
// Methods used internally for e.g. ordered packs, or resource pack entries // Methods used internally for e.g. ordered packs, or resource pack entries
@ -190,10 +201,11 @@ public class SessionLoadResourcePacksEventImpl extends SessionLoadResourcePacksE
for (ResourcePackHolder holder : this.packs.values()) { for (ResourcePackHolder holder : this.packs.values()) {
GeyserResourcePack pack = holder.pack(); GeyserResourcePack pack = holder.pack();
ResourcePackManifest.Header header = pack.manifest().header();
if (pack.codec() instanceof UrlPackCodec urlPackCodec) { if (pack.codec() instanceof UrlPackCodec urlPackCodec) {
ResourcePackManifest.Header header = pack.manifest().header();
entries.add(new ResourcePacksInfoPacket.CDNEntry( entries.add(new ResourcePacksInfoPacket.CDNEntry(
header.uuid() + "_" + header.version(), urlPackCodec.url())); header.uuid() + "_" + header.version(), urlPackCodec.url())
);
} }
} }
@ -202,20 +214,20 @@ public class SessionLoadResourcePacksEventImpl extends SessionLoadResourcePacksE
// Helper methods to get the options for a ResourcePack // Helper methods to get the options for a ResourcePack
public <T> T getValue(UUID uuid, ResourcePackOption.Type type, T defaultValue) { public <T> T value(UUID uuid, ResourcePackOption.Type type, T defaultValue) {
OptionHolder holder = options.get(uuid); OptionHolder holder = sessionPackOptionOverrides.get(uuid);
OptionHolder defaultHolder = packs.get(uuid).optionHolder(); OptionHolder defaultHolder = packs.get(uuid).optionHolder();
Objects.requireNonNull(defaultHolder); // should never be null Objects.requireNonNull(defaultHolder); // should never be null
return OptionHolder.getWithFallbacks(type, holder, defaultHolder, defaultValue); return OptionHolder.valueOrFallback(type, holder, defaultHolder, defaultValue);
} }
private double priority(GeyserResourcePack pack) { private double priority(GeyserResourcePack pack) {
return getValue(pack.uuid(), ResourcePackOption.Type.PRIORITY, 5); return value(pack.uuid(), ResourcePackOption.Type.PRIORITY, PriorityOption.NORMAL.value());
} }
private String subpackName(GeyserResourcePack pack) { private String subpackName(GeyserResourcePack pack) {
return getValue(pack.uuid(), ResourcePackOption.Type.SUBPACK, ""); return value(pack.uuid(), ResourcePackOption.Type.SUBPACK, "");
} }
// Helper method to validate a pack // Helper method to validate a pack

Datei anzeigen

@ -316,7 +316,7 @@ public class UpstreamPacketHandler extends LoggingPacketHandler {
if (codec instanceof UrlPackCodec urlPackCodec) { if (codec instanceof UrlPackCodec urlPackCodec) {
ResourcePackLoader.testRemotePack(session, urlPackCodec, packet.getPackId(), packet.getPackVersion()); ResourcePackLoader.testRemotePack(session, urlPackCodec, packet.getPackId(), packet.getPackVersion());
if (!resourcePackLoadEvent.getValue(pack.uuid(), ResourcePackOption.Type.FALLBACK, true)) { if (!resourcePackLoadEvent.value(pack.uuid(), ResourcePackOption.Type.FALLBACK, true)) {
session.disconnect("Unable to provide downloaded resource pack. Contact an administrator!"); session.disconnect("Unable to provide downloaded resource pack. Contact an administrator!");
return PacketSignal.HANDLED; return PacketSignal.HANDLED;
} }

Datei anzeigen

@ -27,6 +27,7 @@ package org.geysermc.geyser.pack;
import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.NonNull;
import org.geysermc.geyser.api.pack.ResourcePack; import org.geysermc.geyser.api.pack.ResourcePack;
import org.geysermc.geyser.api.pack.option.PriorityOption;
import org.geysermc.geyser.pack.option.OptionHolder; import org.geysermc.geyser.pack.option.OptionHolder;
public record ResourcePackHolder( public record ResourcePackHolder(
@ -35,7 +36,7 @@ public record ResourcePackHolder(
) { ) {
public static ResourcePackHolder of(GeyserResourcePack pack) { public static ResourcePackHolder of(GeyserResourcePack pack) {
return new ResourcePackHolder(pack, new OptionHolder()); return new ResourcePackHolder(pack, new OptionHolder(PriorityOption.NORMAL));
} }
public ResourcePack resourcePack() { public ResourcePack resourcePack() {

Datei anzeigen

@ -39,93 +39,90 @@ import java.util.Map;
public class OptionHolder extends HashMap<ResourcePackOption.Type, ResourcePackOption<?>> { public class OptionHolder extends HashMap<ResourcePackOption.Type, ResourcePackOption<?>> {
public void add(ResourcePackOption<?> option) { public OptionHolder() {
super();
}
// Used when adding resource packs initially to ensure that a priority option is always set
// It is however NOT used for session-options, as then the "normal" prio might override
// the resource pack option
public OptionHolder(PriorityOption option) {
super();
put(option.type(), option);
}
public void validateAndAdd(ResourcePack pack, ResourcePackOption<?>... options) {
for (ResourcePackOption<?> option : options) {
// Validate before adding
option.validate(pack);
// Ensure that we do not have duplicate types.
if (super.containsKey(option.type())) { if (super.containsKey(option.type())) {
super.replace(option.type(), option); super.replace(option.type(), option);
} else { } else {
super.put(option.type(), option); super.put(option.type(), option);
} }
} }
public void add(ResourcePackOption<?>... options) {
for (ResourcePackOption<?> option : options) {
add(option);
}
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public static <T> T getWithFallbacks(ResourcePackOption.@NonNull Type type, public static <T> T valueOrFallback(ResourcePackOption.@NonNull Type type,
@Nullable OptionHolder holder, @Nullable OptionHolder sessionPackOptions,
@NonNull OptionHolder defaultHolder, @NonNull OptionHolder resourcePackOptions,
@NonNull T defaultValue) { @NonNull T defaultValue) {
ResourcePackOption<?> option; ResourcePackOption<?> option;
// First: the optionHolder's option, if it exists // First: the session's options, if they exist
if (holder != null) { if (sessionPackOptions != null) {
option = holder.get(type); option = sessionPackOptions.get(type);
if (option != null) { if (option != null) {
return ((ResourcePackOption<T>) option).value(); return (T) option.value();
} }
} }
// Second: check the default optionHolder for the option, if it exists // Second: check the resource pack options
option = defaultHolder.get(type); option = resourcePackOptions.get(type);
if (option != null) { if (option != null) {
return ((ResourcePackOption<T>) option).value(); return (T) option.value();
} }
// Finally: Fallback to default // Finally: return default
return defaultValue; return defaultValue;
} }
public static ResourcePackOption<?> getOptionByType(ResourcePackOption.@NonNull Type type, public static @Nullable ResourcePackOption<?> optionByType(ResourcePackOption.@NonNull Type type,
@Nullable OptionHolder holder, @Nullable OptionHolder sessionPackOptions,
@NonNull OptionHolder defaultHolder) { @NonNull OptionHolder resourcePackOptions) {
ResourcePackOption<?> option;
// First: the optionHolder's option, if it exists // First: the session-specific options, if these exist
if (holder != null) { if (sessionPackOptions != null) {
option = holder.get(type); ResourcePackOption<?> option = sessionPackOptions.get(type);
if (option != null) { if (option != null) {
return option; return option;
} }
} }
// Second: check the default optionHolder for the option, if it exists; // Second: check the default holder for the option, if it exists;
// Or return null if the option isn't set. // Or return null if the option isn't set.
option = defaultHolder.get(type); return resourcePackOptions.get(type);
return option;
} }
public void remove(ResourcePackOption<?> option) { public void remove(ResourcePackOption<?> option) {
super.remove(option.type()); 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 optionHolder in an immutable collection * @return the options of this holder in an immutable collection
*/ */
public Collection<ResourcePackOption<?>> immutableValues() { public Collection<ResourcePackOption<?>> immutableValues() {
return Collections.unmodifiableCollection(values()); return Collections.unmodifiableCollection(values());
} }
/** /**
* @return the options of this option optionHolder, with fallbacks to options of a {@link GeyserResourcePack} * @return the options of this option holder, with fallbacks to options of a {@link GeyserResourcePack}
* if they're not already overridden here * if they're not already overridden here
*/ */
public Collection<ResourcePackOption<?>> immutableValues(OptionHolder defaultValues) { public Collection<ResourcePackOption<?>> immutableValues(OptionHolder defaultValues) {
if (defaultValues.isEmpty()) {
return immutableValues();
}
// Create a map to hold the combined values // Create a map to hold the combined values
Map<ResourcePackOption.Type, ResourcePackOption<?>> combinedOptions = new HashMap<>(this); Map<ResourcePackOption.Type, ResourcePackOption<?>> combinedOptions = new HashMap<>(this);