mirror of
https://github.com/GeyserMC/Geyser.git
synced 2024-12-22 22:45:04 +01:00
Different registry implementation; fix banner blocks with ViaVersion
This commit is contained in:
parent
abb1d7d9e9
commit
1e8d6b23cf
8 changed files with 166 additions and 63 deletions
|
@ -113,7 +113,7 @@ public class WolfEntity extends TameableEntity {
|
|||
|
||||
// 1.20.5+
|
||||
public void setWolfVariant(IntEntityMetadata entityMetadata) {
|
||||
WolfVariant wolfVariant = session.getRegistryCache().wolfVariants().get(entityMetadata.getPrimitiveValue());
|
||||
WolfVariant wolfVariant = session.getRegistryCache().wolfVariants().byId(entityMetadata.getPrimitiveValue());
|
||||
if (wolfVariant == null) {
|
||||
wolfVariant = WolfVariant.PALE;
|
||||
}
|
||||
|
|
|
@ -56,8 +56,8 @@ public class ArmorItem extends Item {
|
|||
return;
|
||||
}
|
||||
|
||||
TrimMaterial material = session.getRegistryCache().trimMaterials().get(trim.material().id());
|
||||
TrimPattern pattern = session.getRegistryCache().trimPatterns().get(trim.pattern().id());
|
||||
TrimMaterial material = session.getRegistryCache().trimMaterials().byId(trim.material().id());
|
||||
TrimPattern pattern = session.getRegistryCache().trimPatterns().byId(trim.pattern().id());
|
||||
|
||||
NbtMapBuilder trimBuilder = NbtMap.builder();
|
||||
// bedrock has an uppercase first letter key, and the value is not namespaced
|
||||
|
|
|
@ -33,13 +33,14 @@ import org.checkerframework.checker.nullness.qual.NonNull;
|
|||
import org.cloudburstmc.nbt.NbtList;
|
||||
import org.cloudburstmc.nbt.NbtMap;
|
||||
import org.cloudburstmc.nbt.NbtType;
|
||||
import org.cloudburstmc.protocol.common.util.Int2ObjectBiMap;
|
||||
import org.geysermc.geyser.inventory.item.BannerPattern;
|
||||
import org.geysermc.geyser.inventory.item.DyeColor;
|
||||
import org.geysermc.geyser.registry.type.ItemMapping;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.session.cache.registry.JavaRegistry;
|
||||
import org.geysermc.geyser.translator.item.BedrockItemBuilder;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.Holder;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.Identifier;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.item.component.BannerPatternLayer;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents;
|
||||
|
@ -57,7 +58,6 @@ public class BannerItem extends BlockItem {
|
|||
* the correct ominous banner pattern if Bedrock pulls the item from creative.
|
||||
*/
|
||||
private static final List<Pair<BannerPattern, DyeColor>> OMINOUS_BANNER_PATTERN;
|
||||
private static final List<NbtMap> OMINOUS_BANNER_PATTERN_BLOCK;
|
||||
|
||||
// TODO fix - we somehow need to be able to get the sessions banner pattern registry, which we don't have where we need this :/
|
||||
private static final int[] ominousBannerPattern = new int[] { 21, 29, 30, 1, 34, 15, 3, 1 };
|
||||
|
@ -74,11 +74,6 @@ public class BannerItem extends BlockItem {
|
|||
Pair.of(BannerPattern.CIRCLE, DyeColor.LIGHT_GRAY),
|
||||
Pair.of(BannerPattern.BORDER, DyeColor.BLACK)
|
||||
);
|
||||
|
||||
OMINOUS_BANNER_PATTERN_BLOCK = new ArrayList<>();
|
||||
for (Pair<BannerPattern, DyeColor> pair : OMINOUS_BANNER_PATTERN) {
|
||||
OMINOUS_BANNER_PATTERN_BLOCK.add(getJavaBannerPatternTag(pair.left(), pair.right()));
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isOminous(GeyserSession session, List<BannerPatternLayer> patternLayers) {
|
||||
|
@ -92,7 +87,7 @@ public class BannerItem extends BlockItem {
|
|||
!patternLayer.getPattern().isId()) {
|
||||
return false;
|
||||
}
|
||||
BannerPattern bannerPattern = session.getRegistryCache().bannerPatterns().get(patternLayer.getPattern().id());
|
||||
BannerPattern bannerPattern = session.getRegistryCache().bannerPatterns().byId(patternLayer.getPattern().id());
|
||||
if (bannerPattern != pair.left()) {
|
||||
return false;
|
||||
}
|
||||
|
@ -101,7 +96,25 @@ public class BannerItem extends BlockItem {
|
|||
}
|
||||
|
||||
public static boolean isOminous(List<NbtMap> blockEntityPatterns) {
|
||||
return OMINOUS_BANNER_PATTERN_BLOCK.equals(blockEntityPatterns);
|
||||
// Cannot do a simple NBT equals check here because the IDs may not be full resource locations
|
||||
// ViaVersion's fault, 1.20.4 -> 1.20.5, but it works on Java so we need to support it.
|
||||
if (OMINOUS_BANNER_PATTERN.size() != blockEntityPatterns.size()) {
|
||||
return false;
|
||||
}
|
||||
for (int i = 0; i < OMINOUS_BANNER_PATTERN.size(); i++) {
|
||||
NbtMap patternLayer = blockEntityPatterns.get(i);
|
||||
Pair<BannerPattern, DyeColor> pair = OMINOUS_BANNER_PATTERN.get(i);
|
||||
DyeColor color = DyeColor.getByJavaIdentifier(patternLayer.getString("color"));
|
||||
if (color != pair.right()) {
|
||||
return false;
|
||||
}
|
||||
String id = Identifier.formalize(patternLayer.getString("pattern")); // Ouch
|
||||
BannerPattern bannerPattern = BannerPattern.getByJavaIdentifier(id);
|
||||
if (bannerPattern != pair.left()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -133,7 +146,7 @@ public class BannerItem extends BlockItem {
|
|||
List<NbtMap> patternList = new ArrayList<>(patterns.size());
|
||||
for (BannerPatternLayer patternLayer : patterns) {
|
||||
patternLayer.getPattern().ifId(holder -> {
|
||||
BannerPattern bannerPattern = session.getRegistryCache().bannerPatterns().get(holder.id());
|
||||
BannerPattern bannerPattern = session.getRegistryCache().bannerPatterns().byId(holder.id());
|
||||
if (bannerPattern != null) {
|
||||
NbtMap tag = NbtMap.builder()
|
||||
.putString("Pattern", bannerPattern.getBedrockIdentifier())
|
||||
|
@ -154,7 +167,8 @@ public class BannerItem extends BlockItem {
|
|||
* @return The Bedrock edition format pattern nbt
|
||||
*/
|
||||
private static NbtMap getBedrockBannerPattern(NbtMap pattern) {
|
||||
BannerPattern bannerPattern = BannerPattern.getByJavaIdentifier(pattern.getString("pattern"));
|
||||
// ViaVersion 1.20.4 -> 1.20.5 can send without the namespace
|
||||
BannerPattern bannerPattern = BannerPattern.getByJavaIdentifier(Identifier.formalize(pattern.getString("pattern")));
|
||||
DyeColor dyeColor = DyeColor.getByJavaIdentifier(pattern.getString("color"));
|
||||
if (bannerPattern == null || dyeColor == null) {
|
||||
return null;
|
||||
|
@ -166,13 +180,6 @@ public class BannerItem extends BlockItem {
|
|||
.build();
|
||||
}
|
||||
|
||||
public static NbtMap getJavaBannerPatternTag(BannerPattern bannerPattern, DyeColor dyeColor) {
|
||||
return NbtMap.builder()
|
||||
.putString("pattern", bannerPattern.getJavaIdentifier())
|
||||
.putString("color", dyeColor.getJavaIdentifier())
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the Bedrock edition banner pattern nbt to Java edition
|
||||
*
|
||||
|
@ -180,11 +187,14 @@ public class BannerItem extends BlockItem {
|
|||
* @return The Java edition format pattern layer
|
||||
*/
|
||||
public static BannerPatternLayer getJavaBannerPattern(GeyserSession session, NbtMap pattern) {
|
||||
Int2ObjectBiMap<BannerPattern> registry = session.getRegistryCache().bannerPatterns();
|
||||
JavaRegistry<BannerPattern> registry = session.getRegistryCache().bannerPatterns();
|
||||
BannerPattern bannerPattern = BannerPattern.getByBedrockIdentifier(pattern.getString("Pattern"));
|
||||
DyeColor dyeColor = DyeColor.getById(15 - pattern.getInt("Color"));
|
||||
if (bannerPattern != null && dyeColor != null && registry.containsValue(bannerPattern)) {
|
||||
return new BannerPatternLayer(Holder.ofId(registry.get(bannerPattern)), dyeColor.ordinal());
|
||||
if (bannerPattern != null && dyeColor != null) {
|
||||
int id = registry.byValue(bannerPattern);
|
||||
if (id != -1) {
|
||||
return new BannerPatternLayer(Holder.ofId(id), dyeColor.ordinal());
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -27,25 +27,25 @@ package org.geysermc.geyser.session.cache;
|
|||
|
||||
import it.unimi.dsi.fastutil.ints.Int2IntMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||
import lombok.AccessLevel;
|
||||
import lombok.Getter;
|
||||
import lombok.experimental.Accessors;
|
||||
import org.cloudburstmc.protocol.bedrock.data.TrimMaterial;
|
||||
import org.cloudburstmc.protocol.bedrock.data.TrimPattern;
|
||||
import org.cloudburstmc.protocol.common.util.Int2ObjectBiMap;
|
||||
import org.geysermc.geyser.GeyserImpl;
|
||||
import org.geysermc.geyser.entity.type.living.animal.tameable.WolfEntity;
|
||||
import org.geysermc.geyser.inventory.item.BannerPattern;
|
||||
import org.geysermc.geyser.inventory.recipe.TrimRecipe;
|
||||
import org.geysermc.geyser.level.JavaDimension;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.geyser.session.cache.registry.JavaRegistry;
|
||||
import org.geysermc.geyser.session.cache.registry.SimpleJavaRegistry;
|
||||
import org.geysermc.geyser.text.TextDecoration;
|
||||
import org.geysermc.geyser.translator.level.BiomeTranslator;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.RegistryEntry;
|
||||
import org.geysermc.mcprotocollib.protocol.packet.configuration.clientbound.ClientboundRegistryDataPacket;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
@ -71,7 +71,7 @@ public final class RegistryCache {
|
|||
register("trim_material", cache -> cache.trimMaterials, TrimRecipe::readTrimMaterial);
|
||||
register("trim_pattern", cache -> cache.trimPatterns, TrimRecipe::readTrimPattern);
|
||||
register("worldgen/biome", (cache, array) -> cache.biomeTranslations = array, BiomeTranslator::loadServerBiome);
|
||||
registerBannerRegistry(($, entry) -> BannerPattern.getByJavaIdentifier(entry.getId()));
|
||||
register("banner_pattern", cache -> cache.bannerPatterns, ($, entry) -> BannerPattern.getByJavaIdentifier(entry.getId()));
|
||||
register("wolf_variant", cache -> cache.wolfVariants, ($, entry) -> WolfEntity.WolfVariant.getByJavaIdentifier(entry.getId()));
|
||||
}
|
||||
|
||||
|
@ -82,16 +82,16 @@ public final class RegistryCache {
|
|||
* Java -> Bedrock biome network IDs.
|
||||
*/
|
||||
private int[] biomeTranslations;
|
||||
private final Int2ObjectMap<TextDecoration> chatTypes = new Int2ObjectOpenHashMap<>(7);
|
||||
private final JavaRegistry<TextDecoration> chatTypes = new SimpleJavaRegistry<>();
|
||||
/**
|
||||
* All dimensions that the client could possibly connect to.
|
||||
*/
|
||||
private final Int2ObjectMap<JavaDimension> dimensions = new Int2ObjectOpenHashMap<>(4);
|
||||
private final Int2ObjectMap<TrimMaterial> trimMaterials = new Int2ObjectOpenHashMap<>();
|
||||
private final Int2ObjectMap<TrimPattern> trimPatterns = new Int2ObjectOpenHashMap<>();
|
||||
private final JavaRegistry<JavaDimension> dimensions = new SimpleJavaRegistry<>();
|
||||
private final JavaRegistry<TrimMaterial> trimMaterials = new SimpleJavaRegistry<>();
|
||||
private final JavaRegistry<TrimPattern> trimPatterns = new SimpleJavaRegistry<>();
|
||||
|
||||
private Int2ObjectBiMap<BannerPattern> bannerPatterns = new Int2ObjectBiMap<>();
|
||||
private final Int2ObjectMap<WolfEntity.WolfVariant> wolfVariants = new Int2ObjectOpenHashMap<>();
|
||||
private final JavaRegistry<BannerPattern> bannerPatterns = new SimpleJavaRegistry<>();
|
||||
private final JavaRegistry<WolfEntity.WolfVariant> wolfVariants = new SimpleJavaRegistry<>();
|
||||
|
||||
public RegistryCache(GeyserSession session) {
|
||||
this.session = session;
|
||||
|
@ -109,47 +109,25 @@ public final class RegistryCache {
|
|||
}
|
||||
}
|
||||
|
||||
private static <T> void registerBannerRegistry(BiFunction<GeyserSession, RegistryEntry, T> reader) {
|
||||
REGISTRIES.put("minecraft:banner_pattern", ((registryCache, entries) -> {
|
||||
// Clear each local cache every time a new registry entry is given to us
|
||||
// (e.g. proxy server switches)
|
||||
registryCache.bannerPatterns = new Int2ObjectBiMap<>(); // Cannot clear it, must re-create :(
|
||||
for (int i = 0; i < entries.size(); i++) {
|
||||
RegistryEntry entry = entries.get(i);
|
||||
// This is what Geyser wants to keep as a value for this registry.
|
||||
T cacheEntry = reader.apply(registryCache.session, entry);
|
||||
if (cacheEntry != null) {
|
||||
registryCache.bannerPatterns.put(i, (BannerPattern) cacheEntry);
|
||||
} else {
|
||||
// TODO - seems to be possible with viaversion :/
|
||||
GeyserImpl.getInstance().getLogger().warning("Was not able to translate entry: ");
|
||||
}
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
/**
|
||||
* @param registry the Java registry resource location, without the "minecraft:" prefix.
|
||||
* @param localCacheFunction which local field in RegistryCache are we caching entries for this registry?
|
||||
* @param reader converts the RegistryEntry NBT into a class file
|
||||
* @param <T> the class that represents these entries.
|
||||
*/
|
||||
private static <T> void register(String registry, Function<RegistryCache, Int2ObjectMap<T>> localCacheFunction, BiFunction<GeyserSession, RegistryEntry, T> reader) {
|
||||
private static <T> void register(String registry, Function<RegistryCache, JavaRegistry<T>> localCacheFunction, BiFunction<GeyserSession, RegistryEntry, T> reader) {
|
||||
REGISTRIES.put("minecraft:" + registry, (registryCache, entries) -> {
|
||||
Int2ObjectMap<T> localCache = localCacheFunction.apply(registryCache);
|
||||
JavaRegistry<T> localCache = localCacheFunction.apply(registryCache);
|
||||
// Clear each local cache every time a new registry entry is given to us
|
||||
// (e.g. proxy server switches)
|
||||
localCache.clear();
|
||||
List<T> builder = new ArrayList<>(entries.size());
|
||||
for (int i = 0; i < entries.size(); i++) {
|
||||
RegistryEntry entry = entries.get(i);
|
||||
// This is what Geyser wants to keep as a value for this registry.
|
||||
T cacheEntry = reader.apply(registryCache.session, entry);
|
||||
localCache.put(i, cacheEntry);
|
||||
}
|
||||
// Trim registry down to needed size
|
||||
if (localCache instanceof Int2ObjectOpenHashMap<T> hashMap) {
|
||||
hashMap.trim();
|
||||
builder.add(i, cacheEntry);
|
||||
}
|
||||
localCache.reset(builder);
|
||||
});
|
||||
}
|
||||
|
||||
|
|
56
core/src/main/java/org/geysermc/geyser/session/cache/registry/JavaRegistry.java
vendored
Normal file
56
core/src/main/java/org/geysermc/geyser/session/cache/registry/JavaRegistry.java
vendored
Normal file
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* Copyright (c) 2019-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.session.cache.registry;
|
||||
|
||||
import org.checkerframework.checker.index.qual.NonNegative;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* A wrapper for a list, holding Java registry values.
|
||||
*/
|
||||
public interface JavaRegistry<T> {
|
||||
|
||||
/**
|
||||
* Looks up a registry entry by its ID. The object can be null, or not present.
|
||||
*/
|
||||
T byId(@NonNegative int id);
|
||||
|
||||
/**
|
||||
* Reverse looks-up an object to return its network ID, or -1.
|
||||
*/
|
||||
int byValue(T value);
|
||||
|
||||
/**
|
||||
* Resets the objects by these IDs.
|
||||
*/
|
||||
void reset(List<T> values);
|
||||
|
||||
/**
|
||||
* All values of this registry, as a list.
|
||||
*/
|
||||
List<T> values();
|
||||
}
|
59
core/src/main/java/org/geysermc/geyser/session/cache/registry/SimpleJavaRegistry.java
vendored
Normal file
59
core/src/main/java/org/geysermc/geyser/session/cache/registry/SimpleJavaRegistry.java
vendored
Normal file
|
@ -0,0 +1,59 @@
|
|||
/*
|
||||
* Copyright (c) 2019-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.session.cache.registry;
|
||||
|
||||
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
|
||||
import org.checkerframework.checker.index.qual.NonNegative;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class SimpleJavaRegistry<T> implements JavaRegistry<T> {
|
||||
protected final ObjectArrayList<T> values = new ObjectArrayList<>();
|
||||
|
||||
@Override
|
||||
public T byId(@NonNegative int id) {
|
||||
if (id < 0 || id >= this.values.size()) {
|
||||
return null;
|
||||
}
|
||||
return this.values.get(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int byValue(T value) {
|
||||
return this.values.indexOf(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset(List<T> values) {
|
||||
this.values.addAll(values);
|
||||
this.values.trim();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<T> values() {
|
||||
return this.values;
|
||||
}
|
||||
}
|
|
@ -330,7 +330,7 @@ public class MessageTranslator {
|
|||
|
||||
textPacket.setNeedsTranslation(false);
|
||||
|
||||
TextDecoration decoration = session.getRegistryCache().chatTypes().get(chatType);
|
||||
TextDecoration decoration = session.getRegistryCache().chatTypes().byId(chatType);
|
||||
if (decoration != null) {
|
||||
// As of 1.19 - do this to apply all the styling for signed messages
|
||||
// Though, Bedrock cannot care about the signed stuff.
|
||||
|
|
|
@ -280,7 +280,7 @@ public class ChunkUtils {
|
|||
* This must be done after the player has switched dimensions so we know what their dimension is
|
||||
*/
|
||||
public static void loadDimension(GeyserSession session) {
|
||||
JavaDimension dimension = session.getRegistryCache().dimensions().get(session.getDimension());
|
||||
JavaDimension dimension = session.getRegistryCache().dimensions().byId(session.getDimension());
|
||||
session.setDimensionType(dimension);
|
||||
int minY = dimension.minY();
|
||||
int maxY = dimension.maxY();
|
||||
|
|
Loading…
Reference in a new issue