mirror of
https://github.com/GeyserMC/Geyser.git
synced 2024-12-22 14:34:59 +01:00
Update to latest MCProtocolLib
This commit is contained in:
parent
3528b1d692
commit
be04ff2a13
29 changed files with 135 additions and 96 deletions
|
@ -220,7 +220,7 @@ public class SessionPlayerEntity extends PlayerEntity {
|
|||
public void setLastDeathPosition(@Nullable GlobalPos pos) {
|
||||
if (pos != null) {
|
||||
dirtyMetadata.put(EntityDataTypes.PLAYER_LAST_DEATH_POS, pos.getPosition());
|
||||
dirtyMetadata.put(EntityDataTypes.PLAYER_LAST_DEATH_DIMENSION, DimensionUtils.javaToBedrock(pos.getDimension()));
|
||||
dirtyMetadata.put(EntityDataTypes.PLAYER_LAST_DEATH_DIMENSION, DimensionUtils.javaToBedrock(pos.getDimension().asString()));
|
||||
dirtyMetadata.put(EntityDataTypes.PLAYER_HAS_DIED, true);
|
||||
} else {
|
||||
dirtyMetadata.put(EntityDataTypes.PLAYER_HAS_DIED, false);
|
||||
|
|
|
@ -26,7 +26,9 @@
|
|||
package org.geysermc.geyser.inventory.item;
|
||||
|
||||
import lombok.Getter;
|
||||
import net.kyori.adventure.key.Key;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
import org.geysermc.geyser.util.MinecraftKey;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
|
@ -78,17 +80,17 @@ public enum BannerPattern {
|
|||
|
||||
private static final BannerPattern[] VALUES = values();
|
||||
|
||||
private final String javaIdentifier;
|
||||
private final Key javaIdentifier;
|
||||
private final String bedrockIdentifier;
|
||||
|
||||
BannerPattern(String bedrockIdentifier) {
|
||||
this.javaIdentifier = "minecraft:" + this.name().toLowerCase(Locale.ROOT);
|
||||
this.javaIdentifier = MinecraftKey.key(this.name().toLowerCase(Locale.ROOT));
|
||||
this.bedrockIdentifier = bedrockIdentifier;
|
||||
}
|
||||
|
||||
public static @Nullable BannerPattern getByJavaIdentifier(String javaIdentifier) {
|
||||
public static @Nullable BannerPattern getByJavaIdentifier(Key key) {
|
||||
for (BannerPattern bannerPattern : VALUES) {
|
||||
if (bannerPattern.javaIdentifier.equals(javaIdentifier)) {
|
||||
if (bannerPattern.javaIdentifier.equals(key)) {
|
||||
return bannerPattern;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -47,7 +47,7 @@ public final class TrimRecipe {
|
|||
public static final ItemDescriptorWithCount TEMPLATE = tagDescriptor("minecraft:trim_templates");
|
||||
|
||||
public static TrimMaterial readTrimMaterial(GeyserSession session, RegistryEntry entry) {
|
||||
String key = stripMinecraftNamespace(entry.getId());
|
||||
String key = entry.getId().asMinimalString();
|
||||
|
||||
// Color is used when hovering over the item
|
||||
// Find the nearest legacy color from the RGB Java gives us to work with
|
||||
|
@ -67,7 +67,7 @@ public final class TrimRecipe {
|
|||
}
|
||||
|
||||
public static TrimPattern readTrimPattern(GeyserSession session, RegistryEntry entry) {
|
||||
String key = stripMinecraftNamespace(entry.getId());
|
||||
String key = entry.getId().asMinimalString();
|
||||
|
||||
String itemIdentifier = entry.getData().getString("template_item");
|
||||
ItemMapping itemMapping = session.getItemMappings().getMapping(itemIdentifier);
|
||||
|
@ -78,19 +78,6 @@ public final class TrimRecipe {
|
|||
return new TrimPattern(itemMapping.getBedrockIdentifier(), key);
|
||||
}
|
||||
|
||||
// TODO find a good place for a stripNamespace util method
|
||||
private static String stripMinecraftNamespace(String identifier) {
|
||||
int i = identifier.indexOf(':');
|
||||
if (i >= 0) {
|
||||
String namespace = identifier.substring(0, i);
|
||||
// Only strip minecraft namespace
|
||||
if (namespace.equals("minecraft")) {
|
||||
return identifier.substring(i + 1);
|
||||
}
|
||||
}
|
||||
return identifier;
|
||||
}
|
||||
|
||||
private TrimRecipe() {
|
||||
//no-op
|
||||
}
|
||||
|
|
|
@ -31,6 +31,7 @@ import org.geysermc.geyser.inventory.item.BedrockEnchantment;
|
|||
import org.geysermc.geyser.session.cache.tags.EnchantmentTag;
|
||||
import org.geysermc.geyser.session.cache.tags.ItemTag;
|
||||
import org.geysermc.geyser.translator.text.MessageTranslator;
|
||||
import org.geysermc.geyser.util.MinecraftKey;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.RegistryEntry;
|
||||
|
||||
import java.util.HashSet;
|
||||
|
@ -59,11 +60,11 @@ public record Enchantment(String identifier,
|
|||
int maxLevel = data.getInt("max_level");
|
||||
int anvilCost = data.getInt("anvil_cost");
|
||||
String exclusiveSet = data.getString("exclusive_set", null);
|
||||
EnchantmentTag exclusiveSetTag = exclusiveSet == null ? null : EnchantmentTag.ALL_ENCHANTMENT_TAGS.get(exclusiveSet.substring(1));
|
||||
BedrockEnchantment bedrockEnchantment = BedrockEnchantment.getByJavaIdentifier(entry.getId());
|
||||
EnchantmentTag exclusiveSetTag = exclusiveSet == null ? null : EnchantmentTag.ALL_ENCHANTMENT_TAGS.get(MinecraftKey.key(exclusiveSet.substring(1)));
|
||||
BedrockEnchantment bedrockEnchantment = BedrockEnchantment.getByJavaIdentifier(entry.getId().asString());
|
||||
String description = bedrockEnchantment == null ? MessageTranslator.deserializeDescription(data) : null;
|
||||
|
||||
return new Enchantment(entry.getId(), effects, ItemTag.ALL_ITEM_TAGS.get(supportedItems), maxLevel,
|
||||
return new Enchantment(entry.getId().asString(), effects, ItemTag.ALL_ITEM_TAGS.get(MinecraftKey.key(supportedItems)), maxLevel,
|
||||
description, anvilCost, exclusiveSetTag, bedrockEnchantment);
|
||||
}
|
||||
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
package org.geysermc.geyser.item.type;
|
||||
|
||||
import it.unimi.dsi.fastutil.Pair;
|
||||
import net.kyori.adventure.key.Key;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.format.Style;
|
||||
import net.kyori.adventure.text.format.TextColor;
|
||||
|
@ -40,8 +41,8 @@ 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.geyser.util.MinecraftKey;
|
||||
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;
|
||||
|
@ -106,7 +107,7 @@ public class BannerItem extends BlockItem {
|
|||
if (color != pair.right()) {
|
||||
return false;
|
||||
}
|
||||
String id = Identifier.formalize(patternLayer.getString("pattern")); // Ouch
|
||||
Key id = MinecraftKey.key(patternLayer.getString("pattern")); // Ouch
|
||||
BannerPattern bannerPattern = BannerPattern.getByJavaIdentifier(id);
|
||||
if (bannerPattern != pair.left()) {
|
||||
return false;
|
||||
|
@ -166,7 +167,7 @@ public class BannerItem extends BlockItem {
|
|||
*/
|
||||
private static NbtMap getBedrockBannerPattern(NbtMap pattern) {
|
||||
// ViaVersion 1.20.4 -> 1.20.5 can send without the namespace
|
||||
BannerPattern bannerPattern = BannerPattern.getByJavaIdentifier(Identifier.formalize(pattern.getString("pattern")));
|
||||
BannerPattern bannerPattern = BannerPattern.getByJavaIdentifier(MinecraftKey.key(pattern.getString("pattern")));
|
||||
DyeColor dyeColor = DyeColor.getByJavaIdentifier(pattern.getString("color"));
|
||||
if (bannerPattern == null || dyeColor == null) {
|
||||
return null;
|
||||
|
|
|
@ -45,7 +45,7 @@ import org.geysermc.geyser.text.MinecraftLocale;
|
|||
import org.geysermc.geyser.translator.item.BedrockItemBuilder;
|
||||
import org.geysermc.geyser.translator.item.ItemTranslator;
|
||||
import org.geysermc.geyser.translator.text.MessageTranslator;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.Identifier;
|
||||
import org.geysermc.geyser.util.MinecraftKey;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.item.component.DyedItemColor;
|
||||
|
@ -65,7 +65,7 @@ public class Item {
|
|||
private final int maxDamage;
|
||||
|
||||
public Item(String javaIdentifier, Builder builder) {
|
||||
this.javaIdentifier = Identifier.formalize(javaIdentifier).intern();
|
||||
this.javaIdentifier = MinecraftKey.key(javaIdentifier).asString().intern();
|
||||
this.stackSize = builder.stackSize;
|
||||
this.maxDamage = builder.maxDamage;
|
||||
this.attackDamage = builder.attackDamage;
|
||||
|
|
|
@ -28,6 +28,7 @@ package org.geysermc.geyser.level;
|
|||
import lombok.AccessLevel;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
import net.kyori.adventure.key.Key;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
|
@ -90,9 +91,12 @@ public enum PaintingType {
|
|||
private final int width;
|
||||
private final int height;
|
||||
|
||||
public static PaintingType getByName(String javaName) {
|
||||
public static PaintingType getByName(Key key) {
|
||||
if (!key.namespace().equals("minecraft")) {
|
||||
return null;
|
||||
}
|
||||
for (PaintingType paintingName : VALUES) {
|
||||
if (("minecraft:" + paintingName.name().toLowerCase(Locale.ROOT)).equals(javaName)) return paintingName;
|
||||
if (paintingName.name().toLowerCase(Locale.ROOT).equals(key.value())) return paintingName;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
|
|
@ -27,7 +27,6 @@ package org.geysermc.geyser.registry.mappings.versions;
|
|||
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import com.fasterxml.jackson.databind.node.ArrayNode;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.Identifier;
|
||||
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
|
||||
import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
|
@ -35,14 +34,9 @@ import org.geysermc.geyser.GeyserImpl;
|
|||
import org.geysermc.geyser.api.block.custom.CustomBlockData;
|
||||
import org.geysermc.geyser.api.block.custom.CustomBlockPermutation;
|
||||
import org.geysermc.geyser.api.block.custom.CustomBlockState;
|
||||
import org.geysermc.geyser.api.block.custom.component.BoxComponent;
|
||||
import org.geysermc.geyser.api.block.custom.component.CustomBlockComponents;
|
||||
import org.geysermc.geyser.api.block.custom.component.GeometryComponent;
|
||||
import org.geysermc.geyser.api.block.custom.component.MaterialInstance;
|
||||
import org.geysermc.geyser.api.block.custom.component.PlacementConditions;
|
||||
import org.geysermc.geyser.api.block.custom.component.*;
|
||||
import org.geysermc.geyser.api.block.custom.component.PlacementConditions.BlockFilterType;
|
||||
import org.geysermc.geyser.api.block.custom.component.PlacementConditions.Face;
|
||||
import org.geysermc.geyser.api.block.custom.component.TransformationComponent;
|
||||
import org.geysermc.geyser.api.item.custom.CustomItemData;
|
||||
import org.geysermc.geyser.api.item.custom.CustomItemOptions;
|
||||
import org.geysermc.geyser.api.util.CreativeCategory;
|
||||
|
@ -60,16 +54,10 @@ import org.geysermc.geyser.registry.mappings.util.CustomBlockStateMapping;
|
|||
import org.geysermc.geyser.translator.collision.BlockCollision;
|
||||
import org.geysermc.geyser.util.BlockUtils;
|
||||
import org.geysermc.geyser.util.MathUtils;
|
||||
import org.geysermc.geyser.util.MinecraftKey;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.util.ArrayList;
|
||||
import java.util.EnumSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.LinkedHashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.*;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Predicate;
|
||||
|
@ -131,7 +119,7 @@ public class MappingsReader_v1 extends MappingsReader {
|
|||
blocksNode.fields().forEachRemaining(entry -> {
|
||||
if (entry.getValue().isObject()) {
|
||||
try {
|
||||
String identifier = Identifier.formalize(entry.getKey());
|
||||
String identifier = MinecraftKey.key(entry.getKey()).asString();
|
||||
CustomBlockMapping customBlockMapping = this.readBlockMappingEntry(identifier, entry.getValue());
|
||||
consumer.accept(identifier, customBlockMapping);
|
||||
} catch (Exception e) {
|
||||
|
|
|
@ -40,6 +40,7 @@ import lombok.AccessLevel;
|
|||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import lombok.experimental.Accessors;
|
||||
import net.kyori.adventure.key.Key;
|
||||
import org.checkerframework.checker.index.qual.NonNegative;
|
||||
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
|
@ -290,7 +291,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource {
|
|||
* Keeps track of the world name for respawning.
|
||||
*/
|
||||
@Setter
|
||||
private String worldName = null;
|
||||
private Key worldName = null;
|
||||
/**
|
||||
* As of Java 1.19.3, the client only uses these for commands.
|
||||
*/
|
||||
|
|
|
@ -27,6 +27,7 @@ package org.geysermc.geyser.session.cache;
|
|||
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectMap;
|
||||
import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap;
|
||||
import net.kyori.adventure.key.Key;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
import org.geysermc.geyser.inventory.GeyserItemStack;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.GlobalPos;
|
||||
|
@ -64,7 +65,7 @@ public final class LodestoneCache {
|
|||
int x = position.getX();
|
||||
int y = position.getY();
|
||||
int z = position.getZ();
|
||||
String dim = position.getDimension();
|
||||
Key dim = position.getDimension();
|
||||
|
||||
for (LodestonePos pos : this.activeLodestones.values()) {
|
||||
if (pos.equals(x, y, z, dim)) {
|
||||
|
@ -98,7 +99,7 @@ public final class LodestoneCache {
|
|||
int x = position.getX();
|
||||
int y = position.getY();
|
||||
int z = position.getZ();
|
||||
String dim = position.getDimension();
|
||||
Key dim = position.getDimension();
|
||||
|
||||
for (LodestonePos pos : this.activeLodestones.values()) {
|
||||
if (pos.equals(x, y, z, dim)) {
|
||||
|
@ -138,8 +139,8 @@ public final class LodestoneCache {
|
|||
this.lodestones.clear();
|
||||
}
|
||||
|
||||
public record LodestonePos(int id, int x, int y, int z, String dimension) {
|
||||
boolean equals(int x, int y, int z, String dimension) {
|
||||
public record LodestonePos(int id, int x, int y, int z, Key dimension) {
|
||||
boolean equals(int x, int y, int z, Key dimension) {
|
||||
return this.x == x && this.y == y && this.z == z && this.dimension.equals(dimension);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -30,6 +30,7 @@ import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap;
|
|||
import lombok.AccessLevel;
|
||||
import lombok.Getter;
|
||||
import lombok.experimental.Accessors;
|
||||
import net.kyori.adventure.key.Key;
|
||||
import org.cloudburstmc.nbt.NbtMap;
|
||||
import org.cloudburstmc.nbt.NbtType;
|
||||
import org.cloudburstmc.protocol.bedrock.data.TrimMaterial;
|
||||
|
@ -47,6 +48,7 @@ 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.geyser.util.MinecraftKey;
|
||||
import org.geysermc.mcprotocollib.protocol.MinecraftProtocol;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.RegistryEntry;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.chat.ChatType;
|
||||
|
@ -70,8 +72,8 @@ import java.util.function.ToIntFunction;
|
|||
@Accessors(fluent = true)
|
||||
@Getter
|
||||
public final class RegistryCache {
|
||||
private static final Map<String, Map<String, NbtMap>> DEFAULTS;
|
||||
private static final Map<String, BiConsumer<RegistryCache, List<RegistryEntry>>> REGISTRIES = new HashMap<>();
|
||||
private static final Map<Key, Map<String, NbtMap>> DEFAULTS;
|
||||
private static final Map<Key, BiConsumer<RegistryCache, List<RegistryEntry>>> REGISTRIES = new HashMap<>();
|
||||
|
||||
static {
|
||||
register("chat_type", cache -> cache.chatTypes, ($, entry) -> TextDecoration.readChatType(entry));
|
||||
|
@ -83,14 +85,14 @@ public final class RegistryCache {
|
|||
register("trim_pattern", cache -> cache.trimPatterns, TrimRecipe::readTrimPattern);
|
||||
register("worldgen/biome", (cache, array) -> cache.biomeTranslations = array, BiomeTranslator::loadServerBiome);
|
||||
register("banner_pattern", cache -> cache.bannerPatterns, ($, entry) -> BannerPattern.getByJavaIdentifier(entry.getId()));
|
||||
register("wolf_variant", cache -> cache.wolfVariants, ($, entry) -> WolfEntity.BuiltInWolfVariant.getByJavaIdentifier(entry.getId()));
|
||||
register("wolf_variant", cache -> cache.wolfVariants, ($, entry) -> WolfEntity.BuiltInWolfVariant.getByJavaIdentifier(entry.getId().asString()));
|
||||
|
||||
// Load from MCProtocolLib's classloader
|
||||
NbtMap tag = MinecraftProtocol.loadNetworkCodec();
|
||||
Map<String, Map<String, NbtMap>> defaults = new HashMap<>();
|
||||
Map<Key, Map<String, NbtMap>> defaults = new HashMap<>();
|
||||
// Don't create a keySet - no need to create the cached object in HashMap if we don't use it again
|
||||
REGISTRIES.forEach((key, $) -> {
|
||||
List<NbtMap> rawValues = tag.getCompound(key)
|
||||
List<NbtMap> rawValues = tag.getCompound(key.asString())
|
||||
.getList("value", NbtType.COMPOUND);
|
||||
Map<String, NbtMap> values = new HashMap<>();
|
||||
for (NbtMap value : rawValues) {
|
||||
|
@ -148,7 +150,7 @@ public final class RegistryCache {
|
|||
* @param <T> the class that represents these entries.
|
||||
*/
|
||||
private static <T> void register(String registry, Function<RegistryCache, JavaRegistry<T>> localCacheFunction, BiFunction<GeyserSession, RegistryEntry, T> reader) {
|
||||
String key = "minecraft:" + registry;
|
||||
Key key = MinecraftKey.key(registry);
|
||||
REGISTRIES.put(key, (registryCache, entries) -> {
|
||||
Map<String, NbtMap> localRegistry = null;
|
||||
JavaRegistry<T> localCache = localCacheFunction.apply(registryCache);
|
||||
|
@ -176,7 +178,7 @@ public final class RegistryCache {
|
|||
* @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) -> {
|
||||
REGISTRIES.put(MinecraftKey.key(registry), (registryCache, entries) -> {
|
||||
Int2IntMap temp = new Int2IntOpenHashMap();
|
||||
int greatestId = 0;
|
||||
for (int i = 0; i < entries.size(); i++) {
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
package org.geysermc.geyser.session.cache;
|
||||
|
||||
import it.unimi.dsi.fastutil.ints.IntArrays;
|
||||
import net.kyori.adventure.key.Key;
|
||||
import org.checkerframework.checker.nullness.qual.Nullable;
|
||||
import org.geysermc.geyser.GeyserImpl;
|
||||
import org.geysermc.geyser.GeyserLogger;
|
||||
|
@ -36,6 +37,7 @@ import org.geysermc.geyser.session.GeyserSession;
|
|||
import org.geysermc.geyser.session.cache.tags.BlockTag;
|
||||
import org.geysermc.geyser.session.cache.tags.EnchantmentTag;
|
||||
import org.geysermc.geyser.session.cache.tags.ItemTag;
|
||||
import org.geysermc.geyser.util.MinecraftKey;
|
||||
import org.geysermc.geyser.util.Ordered;
|
||||
import org.geysermc.mcprotocollib.protocol.packet.common.clientbound.ClientboundUpdateTagsPacket;
|
||||
|
||||
|
@ -58,33 +60,33 @@ public final class TagCache {
|
|||
private final int[][] enchantments = new int[ALL_ENCHANTMENT_TAGS.size()][];
|
||||
|
||||
public void loadPacket(GeyserSession session, ClientboundUpdateTagsPacket packet) {
|
||||
Map<String, int[]> blockTags = packet.getTags().get("minecraft:block");
|
||||
Map<Key, int[]> blockTags = packet.getTags().get(MinecraftKey.key("block"));
|
||||
loadTags("Block", blockTags, ALL_BLOCK_TAGS, this.blocks);
|
||||
|
||||
// Hack btw
|
||||
GeyserLogger logger = session.getGeyser().getLogger();
|
||||
int[] convertableToMud = blockTags.get("minecraft:convertable_to_mud");
|
||||
int[] convertableToMud = blockTags.get(MinecraftKey.key("convertable_to_mud"));
|
||||
boolean emulatePost1_18Logic = convertableToMud != null && convertableToMud.length != 0;
|
||||
session.setEmulatePost1_18Logic(emulatePost1_18Logic);
|
||||
if (logger.isDebug()) {
|
||||
logger.debug("Emulating post 1.18 block predication logic for " + session.bedrockUsername() + "? " + emulatePost1_18Logic);
|
||||
}
|
||||
|
||||
Map<String, int[]> itemTags = packet.getTags().get("minecraft:item");
|
||||
Map<Key, int[]> itemTags = packet.getTags().get(MinecraftKey.key("item"));
|
||||
loadTags("Item", itemTags, ALL_ITEM_TAGS, this.items);
|
||||
|
||||
// Hack btw
|
||||
boolean emulatePost1_13Logic = itemTags.get("minecraft:signs").length > 1;
|
||||
boolean emulatePost1_13Logic = itemTags.get(MinecraftKey.key("signs")).length > 1;
|
||||
session.setEmulatePost1_13Logic(emulatePost1_13Logic);
|
||||
if (logger.isDebug()) {
|
||||
logger.debug("Emulating post 1.13 villager logic for " + session.bedrockUsername() + "? " + emulatePost1_13Logic);
|
||||
}
|
||||
|
||||
Map<String, int[]> enchantmentTags = packet.getTags().get("minecraft:enchantment");
|
||||
Map<Key, int[]> enchantmentTags = packet.getTags().get(MinecraftKey.key("enchantment"));
|
||||
loadTags("Enchantment", enchantmentTags, ALL_ENCHANTMENT_TAGS, this.enchantments);
|
||||
}
|
||||
|
||||
private <T extends Ordered> void loadTags(String type, @Nullable Map<String, int[]> packetTags, Map<String, T> allTags, int[][] localValues) {
|
||||
private <T extends Ordered> void loadTags(String type, @Nullable Map<Key, int[]> packetTags, Map<Key, T> allTags, int[][] localValues) {
|
||||
if (packetTags == null) {
|
||||
Arrays.fill(localValues, IntArrays.EMPTY_ARRAY);
|
||||
GeyserImpl.getInstance().getLogger().debug("Not loading " + type + " tags; they do not exist here.");
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
|
||||
package org.geysermc.geyser.session.cache.tags;
|
||||
|
||||
import net.kyori.adventure.key.Key;
|
||||
import org.geysermc.geyser.util.Ordered;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
@ -32,7 +33,7 @@ import java.util.Map;
|
|||
|
||||
@SuppressWarnings("unused")
|
||||
public final class BlockTag implements Ordered {
|
||||
public static final Map<String, BlockTag> ALL_BLOCK_TAGS = new HashMap<>();
|
||||
public static final Map<Key, BlockTag> ALL_BLOCK_TAGS = new HashMap<>();
|
||||
|
||||
public static final BlockTag WOOL = new BlockTag("wool");
|
||||
public static final BlockTag PLANKS = new BlockTag("planks");
|
||||
|
@ -232,6 +233,6 @@ public final class BlockTag implements Ordered {
|
|||
}
|
||||
|
||||
private static void register(String name, BlockTag tag) {
|
||||
ALL_BLOCK_TAGS.put(("minecraft:" + name).intern(), tag);
|
||||
ALL_BLOCK_TAGS.put(Key.key(name), tag);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,6 +25,8 @@
|
|||
|
||||
package org.geysermc.geyser.session.cache.tags;
|
||||
|
||||
import net.kyori.adventure.key.Key;
|
||||
import org.geysermc.geyser.util.MinecraftKey;
|
||||
import org.geysermc.geyser.util.Ordered;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
@ -32,7 +34,7 @@ import java.util.Map;
|
|||
|
||||
@SuppressWarnings("unused")
|
||||
public final class EnchantmentTag implements Ordered {
|
||||
public static final Map<String, EnchantmentTag> ALL_ENCHANTMENT_TAGS = new HashMap<>();
|
||||
public static final Map<Key, EnchantmentTag> ALL_ENCHANTMENT_TAGS = new HashMap<>();
|
||||
|
||||
public static final EnchantmentTag TOOLTIP_ORDER = new EnchantmentTag("tooltip_order");
|
||||
public static final EnchantmentTag EXCLUSIVE_SET_ARMOR = new EnchantmentTag("exclusive_set/armor");
|
||||
|
@ -84,6 +86,6 @@ public final class EnchantmentTag implements Ordered {
|
|||
}
|
||||
|
||||
private static void register(String name, EnchantmentTag tag) {
|
||||
ALL_ENCHANTMENT_TAGS.put(("minecraft:" + name).intern(), tag);
|
||||
ALL_ENCHANTMENT_TAGS.put(MinecraftKey.key(name), tag);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,6 +25,8 @@
|
|||
|
||||
package org.geysermc.geyser.session.cache.tags;
|
||||
|
||||
import net.kyori.adventure.key.Key;
|
||||
import org.geysermc.geyser.util.MinecraftKey;
|
||||
import org.geysermc.geyser.util.Ordered;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
@ -32,7 +34,7 @@ import java.util.Map;
|
|||
|
||||
@SuppressWarnings("unused")
|
||||
public final class ItemTag implements Ordered {
|
||||
public static final Map<String, ItemTag> ALL_ITEM_TAGS = new HashMap<>();
|
||||
public static final Map<Key, ItemTag> ALL_ITEM_TAGS = new HashMap<>();
|
||||
|
||||
public static final ItemTag WOOL = new ItemTag("wool");
|
||||
public static final ItemTag PLANKS = new ItemTag("planks");
|
||||
|
@ -195,6 +197,6 @@ public final class ItemTag implements Ordered {
|
|||
}
|
||||
|
||||
private static void register(String name, ItemTag tag) {
|
||||
ALL_ITEM_TAGS.put(("minecraft:" + name).intern(), tag);
|
||||
ALL_ITEM_TAGS.put(MinecraftKey.key(name), tag);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -45,7 +45,7 @@ import org.geysermc.geyser.session.GeyserSession;
|
|||
public class BiomeTranslator {
|
||||
|
||||
public static int loadServerBiome(RegistryEntry entry) {
|
||||
String javaIdentifier = entry.getId();
|
||||
String javaIdentifier = entry.getId().asString();
|
||||
return Registries.BIOME_IDENTIFIERS.get().getOrDefault(javaIdentifier, 0);
|
||||
}
|
||||
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
|
||||
package org.geysermc.geyser.translator.protocol.bedrock;
|
||||
|
||||
import org.geysermc.geyser.util.MinecraftKey;
|
||||
import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.inventory.ServerboundSetJigsawBlockPacket;
|
||||
import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.level.ServerboundSignUpdatePacket;
|
||||
import org.cloudburstmc.math.vector.Vector3i;
|
||||
|
@ -119,7 +120,8 @@ public class BedrockBlockEntityDataTranslator extends PacketTranslator<BlockEnti
|
|||
String finalState = tag.getString("final_state");
|
||||
String joint = tag.getString("joint");
|
||||
// last two parameters are priority values that Bedrock doesn't have (yet?)
|
||||
ServerboundSetJigsawBlockPacket jigsawPacket = new ServerboundSetJigsawBlockPacket(pos, name, target, pool,
|
||||
ServerboundSetJigsawBlockPacket jigsawPacket = new ServerboundSetJigsawBlockPacket(pos,
|
||||
MinecraftKey.key(name), MinecraftKey.key(target), MinecraftKey.key(pool),
|
||||
finalState, joint, 0, 0);
|
||||
session.sendDownstreamGamePacket(jigsawPacket);
|
||||
}
|
||||
|
|
|
@ -58,7 +58,7 @@ public class BedrockPositionTrackingDBClientRequestTranslator extends PacketTran
|
|||
|
||||
// Build the NBT data for the update
|
||||
NbtMapBuilder builder = NbtMap.builder();
|
||||
builder.putInt("dim", DimensionUtils.javaToBedrock(pos.dimension()));
|
||||
builder.putInt("dim", DimensionUtils.javaToBedrock(pos.dimension().asString()));
|
||||
builder.putString("id", "0x" + String.format("%08X", packet.getTrackingId()));
|
||||
|
||||
builder.putByte("version", (byte) 1); // Not sure what this is for
|
||||
|
|
|
@ -39,6 +39,7 @@ public class JavaClientboundRecipesTranslator extends PacketTranslator<Clientbou
|
|||
|
||||
@Override
|
||||
public void translate(GeyserSession session, ClientboundRecipePacket packet) {
|
||||
System.out.println(packet);
|
||||
UnlockedRecipesPacket recipesPacket = new UnlockedRecipesPacket();
|
||||
switch (packet.getAction()) {
|
||||
case INIT -> {
|
||||
|
|
|
@ -34,6 +34,7 @@ import it.unimi.dsi.fastutil.ints.IntSet;
|
|||
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenCustomHashMap;
|
||||
import lombok.Getter;
|
||||
import lombok.ToString;
|
||||
import net.kyori.adventure.key.Key;
|
||||
import net.kyori.adventure.text.format.NamedTextColor;
|
||||
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
import org.cloudburstmc.protocol.bedrock.data.command.*;
|
||||
|
@ -66,7 +67,7 @@ public class JavaCommandsTranslator extends PacketTranslator<ClientboundCommands
|
|||
*/
|
||||
private static final Supplier<String[]> ALL_BLOCK_NAMES = Suppliers.memoize(() -> BlockRegistries.JAVA_BLOCKS.get().stream().map(block -> block.javaIdentifier().toString()).toArray(String[]::new));
|
||||
private static final String[] ALL_EFFECT_IDENTIFIERS = EntityUtils.getAllEffectIdentifiers();
|
||||
private static final String[] ATTRIBUTES = AttributeType.Builtin.BUILTIN.values().stream().map(AttributeType::getIdentifier).toList().toArray(new String[0]);
|
||||
private static final String[] ATTRIBUTES = AttributeType.Builtin.BUILTIN.values().stream().map(type -> type.getIdentifier().asString()).toList().toArray(new String[0]);
|
||||
private static final String[] ENUM_BOOLEAN = {"true", "false"};
|
||||
private static final String[] VALID_COLORS;
|
||||
private static final String[] VALID_SCOREBOARD_SLOTS;
|
||||
|
@ -264,8 +265,8 @@ public class JavaCommandsTranslator extends PacketTranslator<ClientboundCommands
|
|||
};
|
||||
}
|
||||
|
||||
private static Object handleResource(CommandBuilderContext context, String resource, boolean tags) {
|
||||
return switch (resource) {
|
||||
private static Object handleResource(CommandBuilderContext context, Key resource, boolean tags) {
|
||||
return switch (resource.asString()) {
|
||||
case "minecraft:attribute" -> ATTRIBUTES;
|
||||
case "minecraft:enchantment" -> context.getEnchantments();
|
||||
case "minecraft:entity_type" -> context.getEntityTypes();
|
||||
|
@ -476,12 +477,8 @@ public class JavaCommandsTranslator extends PacketTranslator<ClientboundCommands
|
|||
*/
|
||||
private static String getEnumDataName(CommandNode node) {
|
||||
if (node.getProperties() instanceof ResourceProperties properties) {
|
||||
String registryKey = properties.getRegistryKey();
|
||||
int identifierSplit = registryKey.indexOf(':');
|
||||
if (identifierSplit != -1) {
|
||||
return registryKey.substring(identifierSplit);
|
||||
}
|
||||
return registryKey;
|
||||
Key registryKey = properties.getRegistryKey();
|
||||
return registryKey.value();
|
||||
}
|
||||
return node.getParser().name();
|
||||
}
|
||||
|
|
|
@ -54,7 +54,7 @@ public class JavaCustomPayloadTranslator extends PacketTranslator<ClientboundCus
|
|||
|
||||
@Override
|
||||
public void translate(GeyserSession session, ClientboundCustomPayloadPacket packet) {
|
||||
String channel = packet.getChannel();
|
||||
String channel = packet.getChannel().asString();
|
||||
|
||||
if (channel.equals(Constants.PLUGIN_MESSAGE)) {
|
||||
ByteBuf buf = Unpooled.wrappedBuffer(packet.getData());
|
||||
|
@ -92,7 +92,7 @@ public class JavaCustomPayloadTranslator extends PacketTranslator<ClientboundCus
|
|||
System.arraycopy(raw, 0, finalData, 2, raw.length);
|
||||
}
|
||||
|
||||
session.sendDownstreamPacket(new ServerboundCustomPayloadPacket(channel, finalData));
|
||||
session.sendDownstreamPacket(new ServerboundCustomPayloadPacket(packet.getChannel(), finalData));
|
||||
});
|
||||
session.sendForm(form);
|
||||
});
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
package org.geysermc.geyser.translator.protocol.java;
|
||||
|
||||
import com.github.steveice10.mc.auth.data.GameProfile;
|
||||
import net.kyori.adventure.key.Key;
|
||||
import org.geysermc.geyser.api.network.AuthType;
|
||||
import org.geysermc.geyser.entity.type.player.PlayerEntity;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
|
@ -72,7 +73,7 @@ public class JavaGameProfileTranslator extends PacketTranslator<ClientboundGameP
|
|||
session.getClientData().setOriginalString(null);
|
||||
|
||||
// configuration phase stuff that the vanilla client replies with after receiving the GameProfilePacket
|
||||
session.sendDownstreamPacket(new ServerboundCustomPayloadPacket("minecraft:brand", PluginMessageUtils.getGeyserBrandData()));
|
||||
session.sendDownstreamPacket(new ServerboundCustomPayloadPacket(Key.key("brand"), PluginMessageUtils.getGeyserBrandData()));
|
||||
session.sendJavaClientSettings();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -25,7 +25,9 @@
|
|||
|
||||
package org.geysermc.geyser.translator.protocol.java;
|
||||
|
||||
import net.kyori.adventure.key.Key;
|
||||
import org.geysermc.erosion.Constants;
|
||||
import org.geysermc.geyser.util.MinecraftKey;
|
||||
import org.geysermc.mcprotocollib.protocol.data.game.entity.player.PlayerSpawnInfo;
|
||||
import org.geysermc.mcprotocollib.protocol.packet.common.serverbound.ServerboundCustomPayloadPacket;
|
||||
import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.ClientboundLoginPacket;
|
||||
|
@ -47,6 +49,7 @@ import org.geysermc.geyser.util.DimensionUtils;
|
|||
import org.geysermc.geyser.util.EntityUtils;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Arrays;
|
||||
|
||||
@Translator(packet = ClientboundLoginPacket.class)
|
||||
public class JavaLoginTranslator extends PacketTranslator<ClientboundLoginPacket> {
|
||||
|
@ -98,7 +101,7 @@ public class JavaLoginTranslator extends PacketTranslator<ClientboundLoginPacket
|
|||
}
|
||||
|
||||
session.setWorldName(spawnInfo.getWorldName());
|
||||
session.setLevels(packet.getWorldNames());
|
||||
session.setLevels(Arrays.stream(packet.getWorldNames()).map(Key::asString).toArray(String[]::new));
|
||||
session.setGameMode(spawnInfo.getGameMode());
|
||||
int newDimension = spawnInfo.getDimension();
|
||||
|
||||
|
@ -134,10 +137,11 @@ public class JavaLoginTranslator extends PacketTranslator<ClientboundLoginPacket
|
|||
// as the bedrock client isn't required to send a render distance
|
||||
session.sendJavaClientSettings();
|
||||
|
||||
Key register = MinecraftKey.key("register");
|
||||
if (session.remoteServer().authType() == AuthType.FLOODGATE) {
|
||||
session.sendDownstreamPacket(new ServerboundCustomPayloadPacket("minecraft:register", PluginMessageChannels.getFloodgateRegisterData()));
|
||||
session.sendDownstreamPacket(new ServerboundCustomPayloadPacket(register, PluginMessageChannels.getFloodgateRegisterData()));
|
||||
}
|
||||
session.sendDownstreamPacket(new ServerboundCustomPayloadPacket("minecraft:register", Constants.PLUGIN_MESSAGE.getBytes(StandardCharsets.UTF_8)));
|
||||
session.sendDownstreamPacket(new ServerboundCustomPayloadPacket(register, Constants.PLUGIN_MESSAGE.getBytes(StandardCharsets.UTF_8)));
|
||||
|
||||
if (newDimension != session.getDimension()) {
|
||||
DimensionUtils.switchDimension(session, newDimension);
|
||||
|
|
|
@ -119,14 +119,14 @@ public class JavaUpdateRecipesTranslator extends PacketTranslator<ClientboundUpd
|
|||
ShapelessRecipeData shapelessRecipeData = (ShapelessRecipeData) recipe.getData();
|
||||
List<String> bedrockRecipeIDs = context.translateShapelessRecipe(new GeyserShapelessRecipe(shapelessRecipeData));
|
||||
if (bedrockRecipeIDs != null) {
|
||||
context.addRecipeIdentifier(session, recipe.getIdentifier(), bedrockRecipeIDs);
|
||||
context.addRecipeIdentifier(session, recipe.getIdentifier().asString(), bedrockRecipeIDs);
|
||||
}
|
||||
}
|
||||
case CRAFTING_SHAPED -> {
|
||||
ShapedRecipeData shapedRecipeData = (ShapedRecipeData) recipe.getData();
|
||||
List<String> bedrockRecipeIDs = context.translateShapedRecipe(new GeyserShapedRecipe(shapedRecipeData));
|
||||
if (bedrockRecipeIDs != null) {
|
||||
context.addRecipeIdentifier(session, recipe.getIdentifier(), bedrockRecipeIDs);
|
||||
context.addRecipeIdentifier(session, recipe.getIdentifier().asString(), bedrockRecipeIDs);
|
||||
}
|
||||
}
|
||||
case STONECUTTING -> {
|
||||
|
@ -160,7 +160,7 @@ public class JavaUpdateRecipesTranslator extends PacketTranslator<ClientboundUpd
|
|||
for (ItemStack addition : data.getAddition().getOptions()) {
|
||||
ItemDescriptorWithCount bedrockAddition = ItemDescriptorWithCount.fromItem(ItemTranslator.translateToBedrock(session, addition));
|
||||
|
||||
String id = recipe.getIdentifier();
|
||||
String id = recipe.getIdentifier().asString();
|
||||
// Note: vanilla inputs use aux value of Short.MAX_VALUE
|
||||
craftingDataPacket.getCraftingData().add(org.cloudburstmc.protocol.bedrock.data.inventory.crafting.recipe.SmithingTransformRecipeData.of(id,
|
||||
bedrockTemplate, bedrockBase, bedrockAddition, output, "smithing_table", context.getAndIncrementNetId()));
|
||||
|
@ -501,7 +501,7 @@ public class JavaUpdateRecipesTranslator extends PacketTranslator<ClientboundUpd
|
|||
case CRAFTING_SPECIAL_TIPPEDARROW ->
|
||||
// similar as above
|
||||
"minecraft:arrow";
|
||||
default -> recipe.getIdentifier();
|
||||
default -> recipe.getIdentifier().asString();
|
||||
};
|
||||
|
||||
addRecipeIdentifier(session, javaRecipeID, identifiers);
|
||||
|
|
|
@ -35,6 +35,6 @@ public class JavaStoreCookieTranslator extends PacketTranslator<ClientboundStore
|
|||
|
||||
@Override
|
||||
public void translate(GeyserSession session, ClientboundStoreCookiePacket packet) {
|
||||
session.getCookies().put(packet.getKey(), packet.getPayload());
|
||||
session.getCookies().put(packet.getKey().asString(), packet.getPayload());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -47,7 +47,7 @@ public class JavaStopSoundTranslator extends PacketTranslator<ClientboundStopSou
|
|||
}
|
||||
|
||||
StopSoundPacket stopSoundPacket = new StopSoundPacket();
|
||||
stopSoundPacket.setSoundName(SoundUtils.translatePlaySound(packet.getSound()));
|
||||
stopSoundPacket.setSoundName(SoundUtils.translatePlaySound(packet.getSound().asString()));
|
||||
stopSoundPacket.setStoppingAllSound(false);
|
||||
|
||||
session.sendUpstreamPacket(stopSoundPacket);
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* 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.util;
|
||||
|
||||
import net.kyori.adventure.key.Key;
|
||||
import org.intellij.lang.annotations.Subst;
|
||||
|
||||
public final class MinecraftKey {
|
||||
|
||||
/**
|
||||
* To prevent constant warnings from invalid regex.
|
||||
*/
|
||||
public static Key key(@Subst("empty") String s) {
|
||||
return Key.key(s);
|
||||
}
|
||||
}
|
|
@ -26,6 +26,7 @@
|
|||
package org.geysermc.geyser.util;
|
||||
|
||||
import com.google.common.base.Charsets;
|
||||
import net.kyori.adventure.key.Key;
|
||||
import org.geysermc.geyser.GeyserImpl;
|
||||
import org.geysermc.geyser.session.GeyserSession;
|
||||
import org.geysermc.mcprotocollib.protocol.packet.common.serverbound.ServerboundCustomPayloadPacket;
|
||||
|
@ -54,7 +55,7 @@ public class PluginMessageUtils {
|
|||
}
|
||||
|
||||
public static void sendMessage(GeyserSession session, String channel, byte[] data) {
|
||||
session.sendDownstreamPacket(new ServerboundCustomPayloadPacket(channel, data));
|
||||
session.sendDownstreamPacket(new ServerboundCustomPayloadPacket(Key.key(channel), data));
|
||||
}
|
||||
|
||||
private static byte[] writeVarInt(int value) {
|
||||
|
|
|
@ -13,7 +13,7 @@ websocket = "1.5.1"
|
|||
protocol = "3.0.0.Beta2-20240606.172607-7"
|
||||
raknet = "1.0.0.CR3-20240416.144209-1"
|
||||
mcauthlib = "e5b0bcc"
|
||||
mcprotocollib = "784e91c"
|
||||
mcprotocollib = "f9cc9ee6"
|
||||
adventure = "4.14.0"
|
||||
adventure-platform = "4.3.0"
|
||||
junit = "5.9.2"
|
||||
|
|
Loading…
Reference in a new issue