Refactor Java registry storage; implement trim support

This commit is contained in:
Camotoy 2024-04-22 19:40:50 -04:00
parent 6a5efa3c9d
commit 11f79d4e2c
No known key found for this signature in database
GPG key ID: 7EEFB66FE798081F
11 changed files with 253 additions and 172 deletions

View file

@ -25,63 +25,68 @@
package org.geysermc.geyser.inventory.recipe;
import com.github.steveice10.mc.protocol.data.game.RegistryEntry;
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
import com.github.steveice10.opennbt.tag.builtin.StringTag;
import net.kyori.adventure.text.Component;
import net.kyori.adventure.text.format.TextColor;
import org.cloudburstmc.protocol.bedrock.data.TrimMaterial;
import org.cloudburstmc.protocol.bedrock.data.TrimPattern;
import org.cloudburstmc.protocol.bedrock.data.inventory.descriptor.ItemDescriptorWithCount;
import org.cloudburstmc.protocol.bedrock.data.inventory.descriptor.ItemTagDescriptor;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.geysermc.geyser.registry.type.ItemMapping;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.translator.text.MessageTranslator;
/**
* Hardcoded recipe information about armor trims until further improvements can be made. This information was scraped
* from BDS 1.19.81 with a world with the next_major_update and sniffer features enabled, using ProxyPass.
* Stores information on trim materials and patterns, including smithing armor hacks for pre-1.20.
*/
public class TrimRecipe {
// For TrimDataPacket, which BDS sends just before the CraftingDataPacket
public static final List<TrimPattern> PATTERNS;
public static final List<TrimMaterial> MATERIALS;
public final class TrimRecipe {
// For CraftingDataPacket
public static final String ID = "minecraft:smithing_armor_trim";
public static final ItemDescriptorWithCount BASE = tagDescriptor("minecraft:trimmable_armors");
public static final ItemDescriptorWithCount ADDITION = tagDescriptor("minecraft:trim_materials");
public static final ItemDescriptorWithCount TEMPLATE = tagDescriptor("minecraft:trim_templates");
static {
List<TrimPattern> patterns = new ArrayList<>(16);
patterns.add(new TrimPattern("minecraft:ward_armor_trim_smithing_template", "ward"));
patterns.add(new TrimPattern("minecraft:sentry_armor_trim_smithing_template", "sentry"));
patterns.add(new TrimPattern("minecraft:snout_armor_trim_smithing_template", "snout"));
patterns.add(new TrimPattern("minecraft:dune_armor_trim_smithing_template", "dune"));
patterns.add(new TrimPattern("minecraft:spire_armor_trim_smithing_template", "spire"));
patterns.add(new TrimPattern("minecraft:tide_armor_trim_smithing_template", "tide"));
patterns.add(new TrimPattern("minecraft:wild_armor_trim_smithing_template", "wild"));
patterns.add(new TrimPattern("minecraft:rib_armor_trim_smithing_template", "rib"));
patterns.add(new TrimPattern("minecraft:coast_armor_trim_smithing_template", "coast"));
patterns.add(new TrimPattern("minecraft:shaper_armor_trim_smithing_template", "shaper"));
patterns.add(new TrimPattern("minecraft:eye_armor_trim_smithing_template", "eye"));
patterns.add(new TrimPattern("minecraft:vex_armor_trim_smithing_template", "vex"));
patterns.add(new TrimPattern("minecraft:silence_armor_trim_smithing_template", "silence"));
patterns.add(new TrimPattern("minecraft:wayfinder_armor_trim_smithing_template", "wayfinder"));
patterns.add(new TrimPattern("minecraft:raiser_armor_trim_smithing_template", "raiser"));
patterns.add(new TrimPattern("minecraft:host_armor_trim_smithing_template", "host"));
PATTERNS = Collections.unmodifiableList(patterns);
public static TrimMaterial readTrimMaterial(GeyserSession session, RegistryEntry entry) {
String key = stripNamespace(entry.getId());
List<TrimMaterial> materials = new ArrayList<>(10);
materials.add(new TrimMaterial("quartz", "§h", "minecraft:quartz"));
materials.add(new TrimMaterial("iron", "§i", "minecraft:iron_ingot"));
materials.add(new TrimMaterial("netherite", "§j", "minecraft:netherite_ingot"));
materials.add(new TrimMaterial("redstone", "§m", "minecraft:redstone"));
materials.add(new TrimMaterial("copper", "§n", "minecraft:copper_ingot"));
materials.add(new TrimMaterial("gold", "§p", "minecraft:gold_ingot"));
materials.add(new TrimMaterial("emerald", "§q", "minecraft:emerald"));
materials.add(new TrimMaterial("diamond", "§s", "minecraft:diamond"));
materials.add(new TrimMaterial("lapis", "§t", "minecraft:lapis_lazuli"));
materials.add(new TrimMaterial("amethyst", "§u", "minecraft:amethyst_shard"));
MATERIALS = Collections.unmodifiableList(materials);
// Color is used when hovering over the item
// Find the nearest legacy color from the RGB Java gives us to work with
// Also yes this is a COMPLETE hack but it works ok!!!!!
StringTag colorTag = ((CompoundTag) entry.getData().get("description")).get("color");
TextColor color = TextColor.fromHexString(colorTag.getValue());
String legacy = MessageTranslator.convertMessage(Component.space().color(color));
String itemIdentifier = ((StringTag) entry.getData().get("ingredient")).getValue();
ItemMapping itemMapping = session.getItemMappings().getMapping(itemIdentifier);
if (itemMapping == null) {
// This should never happen so not sure what to do here.
itemMapping = ItemMapping.AIR;
}
// Just pick out the resulting color code, without RESET in front.
return new TrimMaterial(key, legacy.substring(2).trim(), itemMapping.getBedrockIdentifier());
}
public static TrimPattern readTrimPattern(GeyserSession session, RegistryEntry entry) {
String key = stripNamespace(entry.getId());
String itemIdentifier = ((StringTag) entry.getData().get("template_item")).getValue();
ItemMapping itemMapping = session.getItemMappings().getMapping(itemIdentifier);
if (itemMapping == null) {
// This should never happen so not sure what to do here.
itemMapping = ItemMapping.AIR;
}
return new TrimPattern(itemMapping.getBedrockIdentifier(), key);
}
// TODO find a good place for a stripNamespace util method
private static String stripNamespace(String identifier) {
int i = identifier.indexOf(':');
if (i >= 0) {
return identifier.substring(i + 1);
}
return identifier;
}
private TrimRecipe() {

View file

@ -33,6 +33,8 @@ import com.github.steveice10.opennbt.tag.builtin.StringTag;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.cloudburstmc.nbt.NbtMap;
import org.cloudburstmc.nbt.NbtMapBuilder;
import org.cloudburstmc.protocol.bedrock.data.TrimMaterial;
import org.cloudburstmc.protocol.bedrock.data.TrimPattern;
import org.geysermc.geyser.item.ArmorMaterial;
import org.geysermc.geyser.registry.type.ItemMapping;
import org.geysermc.geyser.session.GeyserSession;
@ -57,14 +59,13 @@ public class ArmorItem extends Item {
return;
}
// TODO material IDs
String material = trim.material().custom().assetName();
String pattern = trim.pattern().custom().assetId();
TrimMaterial material = session.getRegistryCache().trimMaterials().get(trim.material().id());
TrimPattern pattern = session.getRegistryCache().trimPatterns().get(trim.pattern().id());
NbtMapBuilder trimBuilder = NbtMap.builder();
// bedrock has an uppercase first letter key, and the value is not namespaced
trimBuilder.put("Material", stripNamespace(material));
trimBuilder.put("Pattern", stripNamespace(pattern));
trimBuilder.put("Material", material.getMaterialId());
trimBuilder.put("Pattern", pattern.getPatternId());
builder.putCompound("Trim", trimBuilder.build());
}
}
@ -86,12 +87,4 @@ public class ArmorItem extends Item {
public boolean isValidRepairItem(Item other) {
return material.getRepairIngredient() == other;
}
private static String stripNamespace(String identifier) {
int i = identifier.indexOf(':');
if (i >= 0) {
return identifier.substring(i + 1);
}
return identifier;
}
}

View file

@ -55,4 +55,18 @@ public record JavaDimension(int minY, int maxY, boolean piglinSafe, double world
map.put(i, new JavaDimension(minY, maxY, piglinSafe, coordinateScale));
}
}
public static JavaDimension read(RegistryEntry entry) {
CompoundTag dimension = entry.getData();
int minY = ((IntTag) dimension.get("min_y")).getValue();
int maxY = ((IntTag) dimension.get("height")).getValue();
// Logical height can be ignored probably - seems to be for artificial limits like the Nether.
// Set if piglins/hoglins should shake
boolean piglinSafe = ((Number) dimension.get("piglin_safe").getValue()).byteValue() != (byte) 0;
// Load world coordinate scale for the world border
double coordinateScale = ((Number) dimension.get("coordinate_scale").getValue()).doubleValue();
return new JavaDimension(minY, maxY, piglinSafe, coordinateScale);
}
}

View file

@ -44,7 +44,6 @@ import com.github.steveice10.mc.protocol.data.game.statistic.CustomStatistic;
import com.github.steveice10.mc.protocol.data.game.statistic.Statistic;
import com.github.steveice10.mc.protocol.packet.common.serverbound.ServerboundClientInformationPacket;
import com.github.steveice10.mc.protocol.packet.handshake.serverbound.ClientIntentionPacket;
import com.github.steveice10.mc.protocol.packet.ingame.serverbound.ServerboundChatCommandPacket;
import com.github.steveice10.mc.protocol.packet.ingame.serverbound.ServerboundChatCommandSignedPacket;
import com.github.steveice10.mc.protocol.packet.ingame.serverbound.ServerboundChatPacket;
import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.ServerboundMovePlayerPosPacket;
@ -54,11 +53,7 @@ import com.github.steveice10.mc.protocol.packet.ingame.serverbound.player.Server
import com.github.steveice10.mc.protocol.packet.login.serverbound.ServerboundCustomQueryAnswerPacket;
import com.github.steveice10.packetlib.BuiltinFlags;
import com.github.steveice10.packetlib.Session;
import com.github.steveice10.packetlib.event.session.ConnectedEvent;
import com.github.steveice10.packetlib.event.session.DisconnectedEvent;
import com.github.steveice10.packetlib.event.session.PacketErrorEvent;
import com.github.steveice10.packetlib.event.session.PacketSendingEvent;
import com.github.steveice10.packetlib.event.session.SessionAdapter;
import com.github.steveice10.packetlib.event.session.*;
import com.github.steveice10.packetlib.packet.Packet;
import com.github.steveice10.packetlib.tcp.TcpClientSession;
import com.github.steveice10.packetlib.tcp.TcpSession;
@ -66,8 +61,6 @@ import io.netty.channel.Channel;
import io.netty.channel.EventLoop;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
import it.unimi.dsi.fastutil.longs.Long2ObjectMap;
import it.unimi.dsi.fastutil.longs.Long2ObjectOpenHashMap;
import it.unimi.dsi.fastutil.objects.Object2IntMap;
import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
@ -146,7 +139,6 @@ import org.geysermc.geyser.session.cache.*;
import org.geysermc.geyser.skin.FloodgateSkinUploader;
import org.geysermc.geyser.text.GeyserLocale;
import org.geysermc.geyser.text.MinecraftLocale;
import org.geysermc.geyser.text.TextDecoration;
import org.geysermc.geyser.translator.inventory.InventoryTranslator;
import org.geysermc.geyser.translator.text.MessageTranslator;
import org.geysermc.geyser.util.ChunkUtils;
@ -158,16 +150,7 @@ import java.net.ConnectException;
import java.net.InetSocketAddress;
import java.nio.charset.StandardCharsets;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.BitSet;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Queue;
import java.util.Set;
import java.util.UUID;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.ScheduledFuture;
@ -214,6 +197,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
private final LodestoneCache lodestoneCache;
private final PistonCache pistonCache;
private final PreferencesCache preferencesCache;
private final RegistryCache registryCache;
private final SkullCache skullCache;
private final StructureBlockCache structureBlockCache;
private final TagCache tagCache;
@ -263,12 +247,6 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
@Setter
private ItemMappings itemMappings;
/**
* Stores the map between Java and Bedrock biome network IDs.
*/
@Setter
private int[] biomeTranslations = null;
/**
* A map of Vector3i positions to Java entities.
* Used for translating Bedrock block actions to Java entity actions.
@ -360,12 +338,6 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
@MonotonicNonNull
@Setter
private JavaDimension dimensionType = null;
/**
* All dimensions that the client could possibly connect to.
*/
private final Int2ObjectMap<JavaDimension> dimensions = new Int2ObjectOpenHashMap<>(4);
private final Int2ObjectMap<TextDecoration> chatTypes = new Int2ObjectOpenHashMap<>(7);
@Setter
private int breakingBlock;
@ -619,6 +591,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
this.lodestoneCache = new LodestoneCache();
this.pistonCache = new PistonCache(this);
this.preferencesCache = new PreferencesCache(this);
this.registryCache = new RegistryCache(this);
this.skullCache = new SkullCache(this);
this.structureBlockCache = new StructureBlockCache();
this.tagCache = new TagCache();

View file

@ -0,0 +1,153 @@
/*
* 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;
import com.github.steveice10.mc.protocol.data.game.RegistryEntry;
import com.github.steveice10.mc.protocol.packet.configuration.clientbound.ClientboundRegistryDataPacket;
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.geysermc.geyser.GeyserImpl;
import org.geysermc.geyser.inventory.recipe.TrimRecipe;
import org.geysermc.geyser.level.JavaDimension;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.text.TextDecoration;
import org.geysermc.geyser.translator.level.BiomeTranslator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.util.function.ToIntFunction;
/**
* Stores any information sent via Java registries. May not contain all data in a given registry - we'll strip what's
* unneeded.
*
* Crafted as of 1.20.5 for easy "add new registry" in the future.
*/
@Accessors(fluent = true)
@Getter
public final class RegistryCache {
private static final Map<String, BiConsumer<RegistryCache, List<RegistryEntry>>> REGISTRIES = new HashMap<>();
static {
register("chat_type", cache -> cache.chatTypes, ($, entry) -> TextDecoration.readChatType(entry));
register("dimension_type", cache -> cache.dimensions, ($, entry) -> JavaDimension.read(entry));
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);
}
@Getter(AccessLevel.NONE)
private final GeyserSession session;
/**
* Java -> Bedrock biome network IDs.
*/
private int[] biomeTranslations;
private final Int2ObjectMap<TextDecoration> chatTypes = new Int2ObjectOpenHashMap<>(7);
/**
* 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<>();
public RegistryCache(GeyserSession session) {
this.session = session;
}
/**
* Loads a registry in, if we are tracking it.
*/
public void load(ClientboundRegistryDataPacket packet) {
var reader = REGISTRIES.get(packet.getRegistry());
if (reader != null) {
reader.accept(this, packet.getEntries());
} else {
GeyserImpl.getInstance().getLogger().debug("Ignoring registry of type " + packet.getRegistry());
}
}
/**
* @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) {
REGISTRIES.put("minecraft:" + registry, (registryCache, entries) -> {
Int2ObjectMap<T> localCache = localCacheFunction.apply(registryCache);
// Clear each local cache every time a new registry entry is given to us
localCache.clear();
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();
}
});
}
/**
* @param localCacheFunction the int array to set the final values to.
*/
private static void register(String registry, BiConsumer<RegistryCache, int[]> localCacheFunction, ToIntFunction<RegistryEntry> reader) {
REGISTRIES.put("minecraft:" + registry, (registryCache, entries) -> {
Int2IntMap temp = new Int2IntOpenHashMap();
int greatestId = 0;
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.
int cacheEntry = reader.applyAsInt(entry);
temp.put(i, cacheEntry);
if (i > greatestId) {
// Maximum registry ID, so far. Make sure the final array is at least this large.
greatestId = i;
}
}
int[] array = new int[greatestId + 1];
for (Int2IntMap.Entry entry : temp.int2IntEntrySet()) {
array[entry.getIntKey()] = entry.getIntValue();
}
localCacheFunction.accept(registryCache, array);
});
}
}

View file

@ -25,6 +25,7 @@
package org.geysermc.geyser.text;
import com.github.steveice10.mc.protocol.data.game.RegistryEntry;
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
import com.github.steveice10.opennbt.tag.builtin.ListTag;
import com.github.steveice10.opennbt.tag.builtin.StringTag;
@ -87,6 +88,17 @@ public final class TextDecoration {
'}';
}
public static TextDecoration readChatType(RegistryEntry entry) {
// Note: The ID is NOT ALWAYS THE SAME! ViaVersion as of 1.19 adds two registry entries that do NOT match vanilla.
CompoundTag tag = entry.getData();
CompoundTag chat = tag.get("chat");
TextDecoration textDecoration = null;
if (chat != null) {
textDecoration = new TextDecoration(chat);
}
return textDecoration;
}
public enum Parameter {
CONTENT,
SENDER,

View file

@ -31,7 +31,9 @@ import com.github.steveice10.mc.protocol.data.game.chunk.DataPalette;
import com.github.steveice10.mc.protocol.data.game.chunk.palette.GlobalPalette;
import com.github.steveice10.mc.protocol.data.game.chunk.palette.Palette;
import com.github.steveice10.mc.protocol.data.game.chunk.palette.SingletonPalette;
import it.unimi.dsi.fastutil.ints.*;
import it.unimi.dsi.fastutil.ints.IntArrayList;
import it.unimi.dsi.fastutil.ints.IntList;
import it.unimi.dsi.fastutil.ints.IntLists;
import org.geysermc.geyser.level.chunk.BlockStorage;
import org.geysermc.geyser.level.chunk.bitarray.BitArray;
import org.geysermc.geyser.level.chunk.bitarray.BitArrayVersion;
@ -39,58 +41,20 @@ import org.geysermc.geyser.level.chunk.bitarray.SingletonBitArray;
import org.geysermc.geyser.registry.Registries;
import org.geysermc.geyser.session.GeyserSession;
import java.util.List;
// Array index formula by https://wiki.vg/Chunk_Format
public class BiomeTranslator {
public static void loadServerBiomes(GeyserSession session, List<RegistryEntry> entries) {
Int2IntMap biomeTranslations = new Int2IntOpenHashMap();
int greatestBiomeId = 0;
for (int i = 0; i < entries.size(); i++) {
RegistryEntry entry = entries.get(i);
String javaIdentifier = entry.getId();
int bedrockId = Registries.BIOME_IDENTIFIERS.get().getOrDefault(javaIdentifier, 0);
int javaId = i;
if (javaId > greatestBiomeId) {
greatestBiomeId = javaId;
}
// TODO - the category tag no longer exists - find a better replacement option
// if (bedrockId == -1) {
// // There is no matching Bedrock variation for this biome; let's set the closest match based on biome category
// String category = ((StringTag) ((CompoundTag) biomeTag.get("element")).get("category")).getValue();
// String replacementBiome = switch (category) {
// case "extreme_hills" -> "minecraft:mountains";
// case "icy" -> "minecraft:ice_spikes";
// case "mesa" -> "minecraft:badlands";
// case "mushroom" -> "minecraft:mushroom_fields";
// case "nether" -> "minecraft:nether_wastes";
// default -> "minecraft:ocean"; // Typically ID 0 so a good default
// case "taiga", "jungle", "plains", "savanna", "the_end", "beach", "ocean", "desert", "river", "swamp" -> "minecraft:" + category;
// };
// bedrockId = Registries.BIOME_IDENTIFIERS.get().getInt(replacementBiome);
// }
// When we see the Java ID, we should instead apply the Bedrock ID
biomeTranslations.put(javaId, bedrockId);
if (javaId == 0) {
// Matches Java behavior when it sees an invalid biome - it just replaces it with ID 0
biomeTranslations.defaultReturnValue(bedrockId);
}
}
int[] biomes = new int[greatestBiomeId + 1];
for (Int2IntMap.Entry entry : biomeTranslations.int2IntEntrySet()) {
biomes[entry.getIntKey()] = entry.getIntValue();
}
session.setBiomeTranslations(biomes);
public static int loadServerBiome(RegistryEntry entry) {
String javaIdentifier = entry.getId();
return Registries.BIOME_IDENTIFIERS.get().getOrDefault(javaIdentifier, 0);
// if (javaId == 0) {
// // Matches Java behavior when it sees an invalid biome - it just replaces it with ID 0
// biomeTranslations.defaultReturnValue(bedrockId);
// }
}
public static BlockStorage toNewBedrockBiome(GeyserSession session, DataPalette biomeData) {
int[] biomeTranslations = session.getBiomeTranslations();
int[] biomeTranslations = session.getRegistryCache().biomeTranslations();
// As of 1.17.10: the client expects the same format as a chunk but filled with biomes
// As of 1.18 this is the same as Java Edition

View file

@ -25,49 +25,16 @@
package org.geysermc.geyser.translator.protocol.java;
import com.github.steveice10.mc.protocol.data.game.RegistryEntry;
import com.github.steveice10.mc.protocol.packet.configuration.clientbound.ClientboundRegistryDataPacket;
import com.github.steveice10.opennbt.tag.builtin.CompoundTag;
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
import org.geysermc.geyser.level.JavaDimension;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.text.TextDecoration;
import org.geysermc.geyser.translator.level.BiomeTranslator;
import org.geysermc.geyser.translator.protocol.PacketTranslator;
import org.geysermc.geyser.translator.protocol.Translator;
import java.util.List;
@Translator(packet = ClientboundRegistryDataPacket.class)
public class JavaRegistryDataTranslator extends PacketTranslator<ClientboundRegistryDataPacket> {
@Override
public void translate(GeyserSession session, ClientboundRegistryDataPacket packet) {
if (packet.getRegistry().equals("minecraft:dimension_type")) {
Int2ObjectMap<JavaDimension> dimensions = session.getDimensions();
dimensions.clear();
JavaDimension.load(packet.getEntries(), dimensions);
}
if (packet.getRegistry().equals("minecraft:chat_type")) {
Int2ObjectMap<TextDecoration> chatTypes = session.getChatTypes();
chatTypes.clear();
List<RegistryEntry> entries = packet.getEntries();
for (int i = 0; i < entries.size(); i++) {
// The ID is NOT ALWAYS THE SAME! ViaVersion as of 1.19 adds two registry entries that do NOT match vanilla.
RegistryEntry entry = entries.get(i);
CompoundTag tag = entry.getData();
CompoundTag chat = tag.get("chat");
TextDecoration textDecoration = null;
if (chat != null) {
textDecoration = new TextDecoration(chat);
}
chatTypes.put(i, textDecoration);
}
}
if (packet.getRegistry().equals("minecraft:worldgen/biome")) {
BiomeTranslator.loadServerBiomes(session, packet.getEntries());
}
session.getRegistryCache().load(packet);
}
}

View file

@ -269,8 +269,8 @@ public class JavaUpdateRecipesTranslator extends PacketTranslator<ClientboundUpd
if (sendTrimRecipes) {
// BDS sends armor trim templates and materials before the CraftingDataPacket
TrimDataPacket trimDataPacket = new TrimDataPacket();
trimDataPacket.getPatterns().addAll(TrimRecipe.PATTERNS);
trimDataPacket.getMaterials().addAll(TrimRecipe.MATERIALS);
trimDataPacket.getPatterns().addAll(session.getRegistryCache().trimPatterns().values());
trimDataPacket.getMaterials().addAll(session.getRegistryCache().trimMaterials().values());
session.sendUpstreamPacket(trimDataPacket);
// Identical smithing_trim recipe sent by BDS that uses tag-descriptors, as the client seems to ignore the

View file

@ -312,7 +312,7 @@ public class MessageTranslator {
textPacket.setNeedsTranslation(false);
TextDecoration decoration = session.getChatTypes().get(chatType);
TextDecoration decoration = session.getRegistryCache().chatTypes().get(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.

View file

@ -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.getDimensions().get(session.getDimension());
JavaDimension dimension = session.getRegistryCache().dimensions().get(session.getDimension());
session.setDimensionType(dimension);
int minY = dimension.minY();
int maxY = dimension.maxY();