From d94c6ffcb6df79359390b8a295acafd80c252b91 Mon Sep 17 00:00:00 2001 From: chris Date: Wed, 23 Oct 2024 03:49:04 +0800 Subject: [PATCH 01/10] API: Expose a GeyserConnection's protocol version (#5083) * Add protocolVersion() to GeyserConnection * specify which protocol --- .../org/geysermc/geyser/api/connection/GeyserConnection.java | 5 +++++ .../main/java/org/geysermc/geyser/session/GeyserSession.java | 5 +++++ gradle.properties | 2 +- 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/api/src/main/java/org/geysermc/geyser/api/connection/GeyserConnection.java b/api/src/main/java/org/geysermc/geyser/api/connection/GeyserConnection.java index 0a580f975..ede4c1bc4 100644 --- a/api/src/main/java/org/geysermc/geyser/api/connection/GeyserConnection.java +++ b/api/src/main/java/org/geysermc/geyser/api/connection/GeyserConnection.java @@ -70,6 +70,11 @@ public interface GeyserConnection extends Connection, CommandSource { */ void closeForm(); + /** + * Gets the Bedrock protocol version of the player. + */ + int protocolVersion(); + /** * @param javaId the Java entity ID to look up. * @return a {@link GeyserEntity} if present in this connection's entity tracker. diff --git a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java index 9c20e9909..b8a991013 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -2229,6 +2229,11 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { return (int) Math.floor(rakSessionCodec.getPing()); } + @Override + public int protocolVersion() { + return upstream.getProtocolVersion(); + } + @Override public void closeForm() { if (!GameProtocol.isPre1_21_2(this)) { diff --git a/gradle.properties b/gradle.properties index 1ee0e12cc..86cf4e922 100644 --- a/gradle.properties +++ b/gradle.properties @@ -8,5 +8,5 @@ org.gradle.vfs.watch=false group=org.geysermc id=geyser -version=2.4.3-SNAPSHOT +version=2.4.4-SNAPSHOT description=Allows for players from Minecraft: Bedrock Edition to join Minecraft: Java Edition servers. From e7ecb55f33abd6e951aeac9ce0b462205cbd3339 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Tue, 22 Oct 2024 18:10:27 -0400 Subject: [PATCH 02/10] Indicate support for Bedrock 1.21.41 --- README.md | 2 +- .../java/org/geysermc/geyser/network/GameProtocol.java | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 418bfcdeb..3e99a96a7 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ The ultimate goal of this project is to allow Minecraft: Bedrock Edition users t Special thanks to the DragonProxy project for being a trailblazer in protocol translation and for all the team members who have joined us here! ## Supported Versions -Geyser is currently supporting Minecraft Bedrock 1.20.80 - 1.21.40 and Minecraft Java 1.21/1.21.1. For more information, please see [here](https://geysermc.org/wiki/geyser/supported-versions/). +Geyser is currently supporting Minecraft Bedrock 1.20.80 - 1.21.41 and Minecraft Java 1.21/1.21.1. For more information, please see [here](https://geysermc.org/wiki/geyser/supported-versions/). ## Setting Up Take a look [here](https://geysermc.org/wiki/geyser/setup/) for how to set up Geyser. diff --git a/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java b/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java index c76958777..c39629917 100644 --- a/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java +++ b/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java @@ -52,7 +52,7 @@ public final class GameProtocol { * release of the game that Geyser supports. */ public static final BedrockCodec DEFAULT_BEDROCK_CODEC = CodecProcessor.processCodec(Bedrock_v748.CODEC.toBuilder() - .minecraftVersion("1.21.40") + .minecraftVersion("1.21.41") .build()); /** @@ -80,10 +80,10 @@ public final class GameProtocol { .minecraftVersion("1.21.20 - 1.21.23") .build())); SUPPORTED_BEDROCK_CODECS.add(CodecProcessor.processCodec(Bedrock_v729.CODEC.toBuilder() - .minecraftVersion("1.21.30/1.21.31") - .build())); + .minecraftVersion("1.21.30/1.21.31") + .build())); SUPPORTED_BEDROCK_CODECS.add(DEFAULT_BEDROCK_CODEC.toBuilder() - .minecraftVersion("1.21.40") + .minecraftVersion("1.21.40/1.21.41") .build()); } From 29fe033257d78e92cf7f3c957b809599d3f83b06 Mon Sep 17 00:00:00 2001 From: chris Date: Fri, 25 Oct 2024 00:55:19 +0800 Subject: [PATCH 03/10] Don't attempt to clear registry that hasn't been loaded yet (#5101) --- core/src/main/java/org/geysermc/geyser/GeyserImpl.java | 4 +++- .../org/geysermc/geyser/registry/DeferredRegistry.java | 7 +++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/core/src/main/java/org/geysermc/geyser/GeyserImpl.java b/core/src/main/java/org/geysermc/geyser/GeyserImpl.java index 9df1d2189..4672aef5b 100644 --- a/core/src/main/java/org/geysermc/geyser/GeyserImpl.java +++ b/core/src/main/java/org/geysermc/geyser/GeyserImpl.java @@ -723,7 +723,9 @@ public class GeyserImpl implements GeyserApi, EventRegistrar { runIfNonNull(newsHandler, NewsHandler::shutdown); runIfNonNull(erosionUnixListener, UnixSocketClientListener::close); - Registries.RESOURCE_PACKS.get().clear(); + if (Registries.RESOURCE_PACKS.loaded()) { + Registries.RESOURCE_PACKS.get().clear(); + } this.setEnabled(false); } diff --git a/core/src/main/java/org/geysermc/geyser/registry/DeferredRegistry.java b/core/src/main/java/org/geysermc/geyser/registry/DeferredRegistry.java index 6a2f2ae37..ce77261ae 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/DeferredRegistry.java +++ b/core/src/main/java/org/geysermc/geyser/registry/DeferredRegistry.java @@ -112,6 +112,13 @@ public final class DeferredRegistry implements IRegistry { this.loaded = true; } + /** + * Whether this registry was loaded. + */ + public boolean loaded() { + return this.loaded; + } + /** * Creates a new deferred registry. * From 6331cb6d586d1a19bf9d0daabb535d82c9a58e29 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Thu, 24 Oct 2024 19:52:18 -0400 Subject: [PATCH 04/10] Fix pulling skulls/heads from creative inventory --- .../populator/ItemRegistryPopulator.java | 32 ++++++++++++++++--- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java b/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java index 12b5ebb0e..0b61c7999 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java @@ -33,7 +33,13 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import it.unimi.dsi.fastutil.ints.IntOpenHashSet; import it.unimi.dsi.fastutil.ints.IntSet; -import it.unimi.dsi.fastutil.objects.*; +import it.unimi.dsi.fastutil.objects.Object2IntMap; +import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; +import it.unimi.dsi.fastutil.objects.Object2ObjectLinkedOpenHashMap; +import it.unimi.dsi.fastutil.objects.Object2ObjectMap; +import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; +import it.unimi.dsi.fastutil.objects.ObjectArrayList; +import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; import org.checkerframework.checker.nullness.qual.NonNull; import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMapBuilder; @@ -66,10 +72,22 @@ import org.geysermc.geyser.item.type.BlockItem; import org.geysermc.geyser.item.type.Item; import org.geysermc.geyser.registry.BlockRegistries; import org.geysermc.geyser.registry.Registries; -import org.geysermc.geyser.registry.type.*; +import org.geysermc.geyser.registry.type.BlockMappings; +import org.geysermc.geyser.registry.type.GeyserBedrockBlock; +import org.geysermc.geyser.registry.type.GeyserMappingItem; +import org.geysermc.geyser.registry.type.ItemMapping; +import org.geysermc.geyser.registry.type.ItemMappings; +import org.geysermc.geyser.registry.type.NonVanillaItemRegistration; +import org.geysermc.geyser.registry.type.PaletteItem; import java.io.InputStream; -import java.util.*; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; import java.util.concurrent.atomic.AtomicInteger; /** @@ -96,7 +114,13 @@ public class ItemRegistryPopulator { paletteVersions.add(new PaletteVersion("1_21_0", Bedrock_v685.CODEC.getProtocolVersion(), Collections.emptyMap(), Conversion712_685::remapItem)); paletteVersions.add(new PaletteVersion("1_21_20", Bedrock_v712.CODEC.getProtocolVersion(), Collections.emptyMap(), Conversion729_712::remapItem)); paletteVersions.add(new PaletteVersion("1_21_30", Bedrock_v729.CODEC.getProtocolVersion())); - paletteVersions.add(new PaletteVersion("1_21_40", Bedrock_v748.CODEC.getProtocolVersion())); + paletteVersions.add(new PaletteVersion("1_21_40", Bedrock_v748.CODEC.getProtocolVersion(), Collections.emptyMap(), (item, mapping) -> { + String identifier = item.javaIdentifier(); + if (identifier.endsWith("_head") || identifier.endsWith("_skull")) { + return mapping.withBedrockIdentifier(item.javaIdentifier()); + } + return mapping; + })); GeyserBootstrap bootstrap = GeyserImpl.getInstance().getBootstrap(); From d6d19b02b204ef21f74b203cf26badb36f42ec46 Mon Sep 17 00:00:00 2001 From: Tim203 Date: Sun, 27 Oct 2024 22:53:56 +0100 Subject: [PATCH 05/10] Fix #5089 and don't auto-load Registries (#5093) * Fix #5089 and made Registries instance based * Instead of using instance based Registries, manually initialize them * Address review * Commit this too pls --- .../geyser/entity/EntityDefinition.java | 8 +- .../geyser/entity/EntityDefinitions.java | 6 +- .../geyser/entity/GeyserDirtyMetadata.java | 10 +- .../entity/type/living/ArmorStandEntity.java | 8 + .../entity/type/player/PlayerEntity.java | 21 +- .../geysermc/geyser/registry/Registries.java | 41 ++- .../geysermc/geyser/registry/Registry.java | 20 +- .../loader/PotionMixRegistryLoader.java | 2 +- .../registry/loader/RegistryLoaderHolder.java | 33 ++ .../org/geysermc/geyser/scoreboard/Team.java | 11 + .../geyser/session/cache/EntityCache.java | 11 +- .../JavaPlayerInfoUpdateTranslator.java | 4 +- .../entity/spawn/JavaAddEntityTranslator.java | 28 +- .../JavaSetDisplayObjectiveTranslator.java | 2 +- .../org/geysermc/geyser/util/EntityUtils.java | 2 +- .../geyser/util/EnvironmentUtils.java | 2 +- .../network/NameVisibilityScoreboardTest.java | 42 +-- .../network/ScoreboardIssueTests.java | 170 +++++++++- .../BasicBelownameScoreboardTests.java | 36 +- .../BasicPlayerlistScoreboardTests.java | 31 +- .../server/CubecraftScoreboardTest.java | 313 +++++++----------- .../sidebar/BasicSidebarScoreboardTests.java | 35 +- .../OrderAndLimitSidebarScoreboardTests.java | 112 +++---- .../VanillaSidebarScoreboardTests.java | 52 +-- .../scoreboard/network/util/AssertUtils.java | 13 +- .../network/util/GeyserMockContext.java | 19 +- .../util/GeyserMockContextScoreboard.java | 18 +- 27 files changed, 626 insertions(+), 424 deletions(-) create mode 100644 core/src/main/java/org/geysermc/geyser/registry/loader/RegistryLoaderHolder.java diff --git a/core/src/main/java/org/geysermc/geyser/entity/EntityDefinition.java b/core/src/main/java/org/geysermc/geyser/entity/EntityDefinition.java index ea3950bd4..5b4dc0969 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/EntityDefinition.java +++ b/core/src/main/java/org/geysermc/geyser/entity/EntityDefinition.java @@ -37,7 +37,6 @@ import org.geysermc.geyser.entity.properties.GeyserEntityProperties; import org.geysermc.geyser.entity.type.Entity; import org.geysermc.geyser.registry.Registries; import org.geysermc.geyser.translator.entity.EntityMetadataTranslator; -import org.geysermc.geyser.util.EnvironmentUtils; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.EntityMetadata; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.MetadataType; import org.geysermc.mcprotocollib.protocol.data.game.entity.type.EntityType; @@ -146,13 +145,8 @@ public record EntityDefinition(EntityFactory factory, Entit return this; } - /** - * Build the given entity. If a testing environment has been discovered the entity is not registered, - * otherwise it is. This is to prevent all the registries from loading, which will fail (and should - * not be loaded) while testing - */ public EntityDefinition build() { - return build(!EnvironmentUtils.isUnitTesting); + return build(true); } /** diff --git a/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java b/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java index 39357eb60..391130146 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java +++ b/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java @@ -145,7 +145,6 @@ import org.geysermc.geyser.entity.type.living.monster.raid.VindicatorEntity; import org.geysermc.geyser.entity.type.player.PlayerEntity; import org.geysermc.geyser.registry.Registries; import org.geysermc.geyser.translator.text.MessageTranslator; -import org.geysermc.geyser.util.EnvironmentUtils; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.MetadataType; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.FloatEntityMetadata; @@ -1122,10 +1121,7 @@ public final class EntityDefinitions { .identifier("minecraft:armor_stand") // Emulated .build(false); // Never sent over the network - // causes the registries to load - if (!EnvironmentUtils.isUnitTesting) { - Registries.JAVA_ENTITY_IDENTIFIERS.get().put("minecraft:marker", null); // We don't need an entity definition for this as it is never sent over the network - } + Registries.JAVA_ENTITY_IDENTIFIERS.get().put("minecraft:marker", null); // We don't need an entity definition for this as it is never sent over the network } public static void init() { diff --git a/core/src/main/java/org/geysermc/geyser/entity/GeyserDirtyMetadata.java b/core/src/main/java/org/geysermc/geyser/entity/GeyserDirtyMetadata.java index bc567ab91..1ee84f4b5 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/GeyserDirtyMetadata.java +++ b/core/src/main/java/org/geysermc/geyser/entity/GeyserDirtyMetadata.java @@ -32,7 +32,7 @@ import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataType; import java.util.Map; /** - * A write-only wrapper for temporarily storing entity metadata that will be sent to Bedrock. + * A wrapper for temporarily storing entity metadata that will be sent to Bedrock. */ public final class GeyserDirtyMetadata { private final Map, Object> metadata = new Object2ObjectLinkedOpenHashMap<>(); @@ -53,6 +53,14 @@ public final class GeyserDirtyMetadata { return !metadata.isEmpty(); } + /** + * Intended for testing purposes only + */ + public T get(EntityDataType entityData) { + //noinspection unchecked + return (T) metadata.get(entityData); + } + @Override public String toString() { return metadata.toString(); diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/ArmorStandEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/ArmorStandEntity.java index d057f09c7..e1c82345f 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/ArmorStandEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/ArmorStandEntity.java @@ -27,6 +27,7 @@ package org.geysermc.geyser.entity.type.living; import lombok.Getter; import net.kyori.adventure.text.Component; +import org.checkerframework.checker.nullness.qual.Nullable; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataType; import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; @@ -36,6 +37,7 @@ import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.entity.EntityDefinitions; import org.geysermc.geyser.entity.type.LivingEntity; import org.geysermc.geyser.item.Items; +import org.geysermc.geyser.scoreboard.Team; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.util.InteractionResult; import org.geysermc.geyser.util.MathUtils; @@ -123,6 +125,12 @@ public class ArmorStandEntity extends LivingEntity { this.position = position; } + @Override + public void updateNametag(@Nullable Team team) { + // unlike all other LivingEntities, armor stands are not affected by team nametag visibility + super.updateNametag(team, true); + } + @Override public void setDisplayName(EntityMetadata, ?> entityMetadata) { super.setDisplayName(entityMetadata); diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/player/PlayerEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/player/PlayerEntity.java index 4e0de44ea..2abc34d2b 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/player/PlayerEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/player/PlayerEntity.java @@ -43,7 +43,6 @@ import org.cloudburstmc.protocol.bedrock.data.AbilityLayer; import org.cloudburstmc.protocol.bedrock.data.GameType; import org.cloudburstmc.protocol.bedrock.data.PlayerPermission; import org.cloudburstmc.protocol.bedrock.data.command.CommandPermission; -import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataMap; import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag; import org.cloudburstmc.protocol.bedrock.data.entity.EntityLinkData; @@ -112,20 +111,6 @@ public class PlayerEntity extends LivingEntity implements GeyserPlayerEntity { this.texturesProperty = texturesProperty; } - /** - * Do not use! For testing purposes only - */ - public PlayerEntity(GeyserSession session, long geyserId, UUID uuid, String username) { - super(session, -1, geyserId, uuid, EntityDefinitions.PLAYER, Vector3f.ZERO, Vector3f.ZERO, 0, 0, 0); - this.username = username; - this.nametag = username; - this.texturesProperty = null; - - // clear initial metadata - dirtyMetadata.apply(new EntityDataMap()); - setFlagsDirty(false); - } - @Override protected void initializeMetadata() { super.initializeMetadata(); @@ -193,11 +178,7 @@ public class PlayerEntity extends LivingEntity implements GeyserPlayerEntity { if (session.getEntityCache().getPlayerEntity(uuid) == null) return; - if (session.getEntityCache().getEntityByGeyserId(geyserId) == null) { - session.getEntityCache().spawnEntity(this); - } else { - spawnEntity(); - } + session.getEntityCache().spawnEntity(this); } @Override diff --git a/core/src/main/java/org/geysermc/geyser/registry/Registries.java b/core/src/main/java/org/geysermc/geyser/registry/Registries.java index 30d3c0763..e9ff837ab 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/Registries.java +++ b/core/src/main/java/org/geysermc/geyser/registry/Registries.java @@ -62,6 +62,8 @@ import java.util.*; * Holds all the common registries in Geyser. */ public final class Registries { + private static boolean initialized = false; + /** * A registry holding all the providers. * This has to be initialized first to allow extensions to access providers during other registry events. @@ -69,7 +71,7 @@ public final class Registries { public static final SimpleMappedRegistry, ProviderSupplier> PROVIDERS = SimpleMappedRegistry.create(new IdentityHashMap<>(), ProviderRegistryLoader::new); /** - * A registry holding a CompoundTag of the known entity identifiers. + * A registry holding a NbtMap of the known entity identifiers. */ public static final SimpleRegistry BEDROCK_ENTITY_IDENTIFIERS = SimpleRegistry.create("bedrock/entity_identifiers.dat", RegistryLoaders.NBT); @@ -79,7 +81,7 @@ public final class Registries { public static final PacketTranslatorRegistry BEDROCK_PACKET_TRANSLATORS = PacketTranslatorRegistry.create(); /** - * A registry holding a CompoundTag of all the known biomes. + * A registry holding a NbtMap of all the known biomes. */ public static final SimpleRegistry BIOMES_NBT = SimpleRegistry.create("bedrock/biome_definitions.dat", RegistryLoaders.NBT); @@ -118,6 +120,9 @@ public final class Registries { */ public static final ListRegistry JAVA_ITEMS = ListRegistry.create(RegistryLoaders.empty(ArrayList::new)); + /** + * A registry containing item identifiers. + */ public static final SimpleMappedRegistry JAVA_ITEM_IDENTIFIERS = SimpleMappedRegistry.create(RegistryLoaders.empty(Object2ObjectOpenHashMap::new)); /** @@ -135,7 +140,7 @@ public final class Registries { /** * A registry holding all the potion mixes. */ - public static final VersionedRegistry> POTION_MIXES; + public static final VersionedRegistry> POTION_MIXES = VersionedRegistry.create(PotionMixRegistryLoader::new); /** * A versioned registry holding all the recipes, with the net ID being the key, and {@link GeyserRecipe} as the value. @@ -163,15 +168,35 @@ public final class Registries { public static final SimpleMappedRegistry> SOUND_TRANSLATORS = SimpleMappedRegistry.create("org.geysermc.geyser.translator.sound.SoundTranslator", SoundTranslatorRegistryLoader::new); public static void init() { - // no-op - } + if (initialized) return; + initialized = true; + + PROVIDERS.load(); + BEDROCK_ENTITY_IDENTIFIERS.load(); + BEDROCK_PACKET_TRANSLATORS.load(); + BIOMES_NBT.load(); + BIOME_IDENTIFIERS.load(); + BLOCK_ENTITIES.load(); + ENTITY_DEFINITIONS.load(); + BEDROCK_ENTITY_PROPERTIES.load(); + JAVA_ENTITY_IDENTIFIERS.load(); + JAVA_PACKET_TRANSLATORS.load(); + JAVA_ITEMS.load(); + JAVA_ITEM_IDENTIFIERS.load(); + ITEMS.load(); + PARTICLES.load(); + // load potion mixes later + RECIPES.load(); + RESOURCE_PACKS.load(); + SOUNDS.load(); + SOUND_LEVEL_EVENTS.load(); + SOUND_TRANSLATORS.load(); - static { PacketRegistryPopulator.populate(); ItemRegistryPopulator.populate(); - // Create registries that require other registries to load first - POTION_MIXES = VersionedRegistry.create(PotionMixRegistryLoader::new); + // potion mixes depend on other registries + POTION_MIXES.load(); // Remove unneeded client generation data from NbtMapBuilder NbtMapBuilder biomesNbt = NbtMap.builder(); diff --git a/core/src/main/java/org/geysermc/geyser/registry/Registry.java b/core/src/main/java/org/geysermc/geyser/registry/Registry.java index 8836502b3..4e83a3c2e 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/Registry.java +++ b/core/src/main/java/org/geysermc/geyser/registry/Registry.java @@ -25,9 +25,9 @@ package org.geysermc.geyser.registry; -import org.geysermc.geyser.registry.loader.RegistryLoader; - import java.util.function.Consumer; +import org.geysermc.geyser.registry.loader.RegistryLoader; +import org.geysermc.geyser.registry.loader.RegistryLoaderHolder; /** * A wrapper around a value which is loaded based on the output from the provided @@ -63,7 +63,9 @@ import java.util.function.Consumer; * * @param the value being held by the registry */ +@SuppressWarnings("rawtypes") public abstract class Registry implements IRegistry { + protected RegistryLoaderHolder loaderHolder; protected M mappings; /** @@ -76,7 +78,17 @@ public abstract class Registry implements IRegistry { * @param the input type */ protected Registry(I input, RegistryLoader registryLoader) { - this.mappings = registryLoader.load(input); + this.loaderHolder = new RegistryLoaderHolder<>(input, registryLoader); + } + + public void load() { + // don't load twice + if (this.mappings != null) return; + + var holder = this.loaderHolder; + this.loaderHolder = null; + //noinspection unchecked + this.mappings = (M) holder.registryLoader().load(holder.input()); } /** @@ -111,4 +123,4 @@ public abstract class Registry implements IRegistry { public void register(Consumer consumer) { consumer.accept(this.mappings); } -} \ No newline at end of file +} diff --git a/core/src/main/java/org/geysermc/geyser/registry/loader/PotionMixRegistryLoader.java b/core/src/main/java/org/geysermc/geyser/registry/loader/PotionMixRegistryLoader.java index eae4e2bea..613df61aa 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/loader/PotionMixRegistryLoader.java +++ b/core/src/main/java/org/geysermc/geyser/registry/loader/PotionMixRegistryLoader.java @@ -125,4 +125,4 @@ public class PotionMixRegistryLoader implements RegistryLoader(I input, RegistryLoader registryLoader) { +} diff --git a/core/src/main/java/org/geysermc/geyser/scoreboard/Team.java b/core/src/main/java/org/geysermc/geyser/scoreboard/Team.java index d7c06ac4f..507523539 100644 --- a/core/src/main/java/org/geysermc/geyser/scoreboard/Team.java +++ b/core/src/main/java/org/geysermc/geyser/scoreboard/Team.java @@ -90,6 +90,8 @@ public final class Team { // Remove old team from this map, and from the set of players of the old team. // Java 1.19.3 Mojmap: Scoreboard#addPlayerToTeam calls #removePlayerFromTeam oldTeam.entities.remove(player); + // also remove the managed entity if there is one + removeManagedEntity(player); } return this; }); @@ -282,6 +284,15 @@ public final class Team { } } + /** + * Used internally to remove a managed entity without causing an update. + * This is fine because its only used when the entity is added to another team, + * which will fire the correct nametag updates etc. + */ + private void removeManagedEntity(String name) { + managedEntities.removeIf(entity -> name.equals(entity.teamIdentifier())); + } + private void refreshAllEntities() { for (Entity entity : session().getEntityCache().getEntities().values()) { entity.updateNametag(scoreboard.getTeamFor(entity.teamIdentifier())); diff --git a/core/src/main/java/org/geysermc/geyser/session/cache/EntityCache.java b/core/src/main/java/org/geysermc/geyser/session/cache/EntityCache.java index a80ed3e3a..78d21e63b 100644 --- a/core/src/main/java/org/geysermc/geyser/session/cache/EntityCache.java +++ b/core/src/main/java/org/geysermc/geyser/session/cache/EntityCache.java @@ -69,12 +69,13 @@ public class EntityCache { public void spawnEntity(Entity entity) { if (cacheEntity(entity)) { - entity.spawnEntity(); - - // start tracking newly spawned entities. - // This is however not called for players, that's done in addPlayerEntity + // start tracking newly spawned entities. Doing this before the actual entity spawn can result in combining + // the otherwise sent metadata packet (in the case of team visibility, which sets the NAME metadata to + // empty) with the entity spawn packet (which also includes metadata). Resulting in 1 less packet sent. session.getWorldCache().getScoreboard().entityRegistered(entity); + entity.spawnEntity(); + if (entity instanceof Tickable) { // Start ticking it tickableEntities.add((Tickable) entity); @@ -144,8 +145,6 @@ public class EntityCache { // notify scoreboard for new entity var scoreboard = session.getWorldCache().getScoreboard(); scoreboard.playerRegistered(entity); - // spawnPlayer's entityRegistered is not called for players - scoreboard.entityRegistered(entity); } public PlayerEntity getPlayerEntity(UUID uuid) { diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaPlayerInfoUpdateTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaPlayerInfoUpdateTranslator.java index 19f34db74..d950d9d0e 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaPlayerInfoUpdateTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/player/JavaPlayerInfoUpdateTranslator.java @@ -25,7 +25,6 @@ package org.geysermc.geyser.translator.protocol.java.entity.player; -import org.geysermc.mcprotocollib.auth.GameProfile; import org.checkerframework.checker.nullness.qual.Nullable; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.packet.PlayerListPacket; @@ -35,6 +34,7 @@ import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.skin.SkinManager; import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; +import org.geysermc.mcprotocollib.auth.GameProfile; import org.geysermc.mcprotocollib.protocol.data.game.PlayerListEntry; import org.geysermc.mcprotocollib.protocol.data.game.PlayerListEntryAction; import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.ClientboundPlayerInfoUpdatePacket; @@ -95,8 +95,6 @@ public class JavaPlayerInfoUpdateTranslator extends PacketTranslator GeyserImpl.getInstance().getLogger().debug("Loaded Local Bedrock Java Skin Data for " + session.getClientData().getUsername())); - } else { - playerEntity.setValid(true); } } } diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/spawn/JavaAddEntityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/spawn/JavaAddEntityTranslator.java index 572d233d0..ed1951243 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/spawn/JavaAddEntityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/spawn/JavaAddEntityTranslator.java @@ -25,17 +25,14 @@ package org.geysermc.geyser.translator.protocol.java.entity.spawn; -import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.Pose; -import org.geysermc.mcprotocollib.protocol.data.game.entity.object.Direction; -import org.geysermc.mcprotocollib.protocol.data.game.entity.object.FallingBlockData; -import org.geysermc.mcprotocollib.protocol.data.game.entity.object.ProjectileData; -import org.geysermc.mcprotocollib.protocol.data.game.entity.object.WardenData; -import org.geysermc.mcprotocollib.protocol.data.game.entity.type.EntityType; -import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.entity.spawn.ClientboundAddEntityPacket; import org.cloudburstmc.math.vector.Vector3f; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.entity.EntityDefinition; -import org.geysermc.geyser.entity.type.*; +import org.geysermc.geyser.entity.type.Entity; +import org.geysermc.geyser.entity.type.FallingBlockEntity; +import org.geysermc.geyser.entity.type.FishingHookEntity; +import org.geysermc.geyser.entity.type.ItemFrameEntity; +import org.geysermc.geyser.entity.type.PaintingEntity; import org.geysermc.geyser.entity.type.player.PlayerEntity; import org.geysermc.geyser.registry.Registries; import org.geysermc.geyser.session.GeyserSession; @@ -43,6 +40,14 @@ import org.geysermc.geyser.skin.SkinManager; import org.geysermc.geyser.text.GeyserLocale; import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; +import org.geysermc.geyser.util.EnvironmentUtils; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.Pose; +import org.geysermc.mcprotocollib.protocol.data.game.entity.object.Direction; +import org.geysermc.mcprotocollib.protocol.data.game.entity.object.FallingBlockData; +import org.geysermc.mcprotocollib.protocol.data.game.entity.object.ProjectileData; +import org.geysermc.mcprotocollib.protocol.data.game.entity.object.WardenData; +import org.geysermc.mcprotocollib.protocol.data.game.entity.type.EntityType; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.entity.spawn.ClientboundAddEntityPacket; @Translator(packet = ClientboundAddEntityPacket.class) public class JavaAddEntityTranslator extends PacketTranslator { @@ -83,10 +88,13 @@ public class JavaAddEntityTranslator extends PacketTranslator { diff --git a/core/src/main/java/org/geysermc/geyser/util/EntityUtils.java b/core/src/main/java/org/geysermc/geyser/util/EntityUtils.java index 8e5a57fae..f8b20fbc4 100644 --- a/core/src/main/java/org/geysermc/geyser/util/EntityUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/EntityUtils.java @@ -297,7 +297,7 @@ public final class EntityUtils { private static String translatedEntityName(@NonNull String namespace, @NonNull String name, @NonNull GeyserSession session) { // MinecraftLocale would otherwise invoke getBootstrap (which doesn't exist) and create some folders, // so use the default fallback value as used in Minecraft Java - if (EnvironmentUtils.isUnitTesting) { + if (EnvironmentUtils.IS_UNIT_TESTING) { return "entity." + namespace + "." + name; } return MinecraftLocale.getLocaleString("entity." + namespace + "." + name, session.locale()); diff --git a/core/src/main/java/org/geysermc/geyser/util/EnvironmentUtils.java b/core/src/main/java/org/geysermc/geyser/util/EnvironmentUtils.java index 909398bf4..35a1a1e8f 100644 --- a/core/src/main/java/org/geysermc/geyser/util/EnvironmentUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/EnvironmentUtils.java @@ -26,7 +26,7 @@ package org.geysermc.geyser.util; public final class EnvironmentUtils { - public static final boolean isUnitTesting = isUnitTesting(); + public static final boolean IS_UNIT_TESTING = isUnitTesting(); private EnvironmentUtils() {} diff --git a/core/src/test/java/org/geysermc/geyser/scoreboard/network/NameVisibilityScoreboardTest.java b/core/src/test/java/org/geysermc/geyser/scoreboard/network/NameVisibilityScoreboardTest.java index 523e4dca2..29882ca2e 100644 --- a/core/src/test/java/org/geysermc/geyser/scoreboard/network/NameVisibilityScoreboardTest.java +++ b/core/src/test/java/org/geysermc/geyser/scoreboard/network/NameVisibilityScoreboardTest.java @@ -27,7 +27,7 @@ package org.geysermc.geyser.scoreboard.network; import static org.geysermc.geyser.scoreboard.network.util.AssertUtils.assertNextPacket; import static org.geysermc.geyser.scoreboard.network.util.AssertUtils.assertNoNextPacket; -import static org.geysermc.geyser.scoreboard.network.util.GeyserMockContextScoreboard.mockAndAddPlayerEntity; +import static org.geysermc.geyser.scoreboard.network.util.GeyserMockContextScoreboard.spawnPlayerSilently; import static org.geysermc.geyser.scoreboard.network.util.GeyserMockContextScoreboard.mockContextScoreboard; import net.kyori.adventure.text.Component; @@ -47,7 +47,7 @@ public class NameVisibilityScoreboardTest { mockContextScoreboard(context -> { var setPlayerTeamTranslator = new JavaSetPlayerTeamTranslator(); - mockAndAddPlayerEntity(context, "player1", 2); + spawnPlayerSilently(context, "player1", 2); context.translate( setPlayerTeamTranslator, @@ -64,12 +64,12 @@ public class NameVisibilityScoreboardTest { new String[]{"player1"} ) ); - assertNextPacket(() -> { + assertNextPacket(context, () -> { var packet = new SetEntityDataPacket(); packet.setRuntimeEntityId(2); packet.getMetadata().put(EntityDataTypes.NAME, ""); return packet; - }, context); + }); }); } @@ -78,7 +78,7 @@ public class NameVisibilityScoreboardTest { mockContextScoreboard(context -> { var setPlayerTeamTranslator = new JavaSetPlayerTeamTranslator(); - mockAndAddPlayerEntity(context, "player1", 2); + spawnPlayerSilently(context, "player1", 2); context.translate( setPlayerTeamTranslator, @@ -96,12 +96,12 @@ public class NameVisibilityScoreboardTest { ) ); // only hidden if session player (Tim203) is in a team as well - assertNextPacket(() -> { + assertNextPacket(context, () -> { var packet = new SetEntityDataPacket(); packet.setRuntimeEntityId(2); packet.getMetadata().put(EntityDataTypes.NAME, "§4prefix§r§4player1§r§4suffix"); return packet; - }, context); + }); assertNoNextPacket(context); // create another team and add Tim203 to it @@ -121,12 +121,12 @@ public class NameVisibilityScoreboardTest { ) ); // Tim203 is now in another team, so it should be hidden - assertNextPacket(() -> { + assertNextPacket(context, () -> { var packet = new SetEntityDataPacket(); packet.setRuntimeEntityId(2); packet.getMetadata().put(EntityDataTypes.NAME, ""); return packet; - }, context); + }); assertNoNextPacket(context); // add Tim203 to same team as player1, score should be visible again @@ -134,12 +134,12 @@ public class NameVisibilityScoreboardTest { setPlayerTeamTranslator, new ClientboundSetPlayerTeamPacket("team1", TeamAction.ADD_PLAYER, new String[]{"Tim203"}) ); - assertNextPacket(() -> { + assertNextPacket(context, () -> { var packet = new SetEntityDataPacket(); packet.setRuntimeEntityId(2); packet.getMetadata().put(EntityDataTypes.NAME, "§4prefix§r§4player1§r§4suffix"); return packet; - }, context); + }); }); } @@ -148,7 +148,7 @@ public class NameVisibilityScoreboardTest { mockContextScoreboard(context -> { var setPlayerTeamTranslator = new JavaSetPlayerTeamTranslator(); - mockAndAddPlayerEntity(context, "player1", 2); + spawnPlayerSilently(context, "player1", 2); context.translate( setPlayerTeamTranslator, @@ -166,12 +166,12 @@ public class NameVisibilityScoreboardTest { ) ); // Tim203 is not in a team (let alone the same team), so should be visible - assertNextPacket(() -> { + assertNextPacket(context, () -> { var packet = new SetEntityDataPacket(); packet.setRuntimeEntityId(2); packet.getMetadata().put(EntityDataTypes.NAME, "§4prefix§r§4player1§r§4suffix"); return packet; - }, context); + }); assertNoNextPacket(context); // Tim203 is now in the same team as player1, so should be hidden @@ -179,12 +179,12 @@ public class NameVisibilityScoreboardTest { setPlayerTeamTranslator, new ClientboundSetPlayerTeamPacket("team1", TeamAction.ADD_PLAYER, new String[]{"Tim203"}) ); - assertNextPacket(() -> { + assertNextPacket(context, () -> { var packet = new SetEntityDataPacket(); packet.setRuntimeEntityId(2); packet.getMetadata().put(EntityDataTypes.NAME, ""); return packet; - }, context); + }); assertNoNextPacket(context); // create another team and add Tim203 to there, score should be visible again @@ -203,12 +203,12 @@ public class NameVisibilityScoreboardTest { new String[]{"Tim203"} ) ); - assertNextPacket(() -> { + assertNextPacket(context, () -> { var packet = new SetEntityDataPacket(); packet.setRuntimeEntityId(2); packet.getMetadata().put(EntityDataTypes.NAME, "§4prefix§r§4player1§r§4suffix"); return packet; - }, context); + }); }); } @@ -217,7 +217,7 @@ public class NameVisibilityScoreboardTest { mockContextScoreboard(context -> { var setPlayerTeamTranslator = new JavaSetPlayerTeamTranslator(); - mockAndAddPlayerEntity(context, "player1", 2); + spawnPlayerSilently(context, "player1", 2); context.translate( setPlayerTeamTranslator, @@ -234,12 +234,12 @@ public class NameVisibilityScoreboardTest { new String[]{"player1"} ) ); - assertNextPacket(() -> { + assertNextPacket(context, () -> { var packet = new SetEntityDataPacket(); packet.setRuntimeEntityId(2); packet.getMetadata().put(EntityDataTypes.NAME, "§4prefix§r§4player1§r§4suffix"); return packet; - }, context); + }); // adding self to another team shouldn't make a difference context.translate( diff --git a/core/src/test/java/org/geysermc/geyser/scoreboard/network/ScoreboardIssueTests.java b/core/src/test/java/org/geysermc/geyser/scoreboard/network/ScoreboardIssueTests.java index 1ec245007..17ad7f3d3 100644 --- a/core/src/test/java/org/geysermc/geyser/scoreboard/network/ScoreboardIssueTests.java +++ b/core/src/test/java/org/geysermc/geyser/scoreboard/network/ScoreboardIssueTests.java @@ -25,23 +25,58 @@ package org.geysermc.geyser.scoreboard.network; +import static org.geysermc.geyser.scoreboard.network.util.AssertUtils.assertNextPacket; +import static org.geysermc.geyser.scoreboard.network.util.AssertUtils.assertNextPacketMatch; import static org.geysermc.geyser.scoreboard.network.util.AssertUtils.assertNextPacketType; +import static org.geysermc.geyser.scoreboard.network.util.AssertUtils.assertNoNextPacket; import static org.geysermc.geyser.scoreboard.network.util.GeyserMockContextScoreboard.mockContextScoreboard; import static org.junit.jupiter.api.Assertions.assertDoesNotThrow; import static org.junit.jupiter.api.Assertions.assertEquals; +import net.kyori.adventure.text.Component; +import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; import org.cloudburstmc.protocol.bedrock.packet.AddEntityPacket; +import org.cloudburstmc.protocol.bedrock.packet.AddPlayerPacket; +import org.cloudburstmc.protocol.bedrock.packet.MoveEntityAbsolutePacket; +import org.cloudburstmc.protocol.bedrock.packet.PlayerListPacket; import org.cloudburstmc.protocol.bedrock.packet.RemoveEntityPacket; +import org.cloudburstmc.protocol.bedrock.packet.SetEntityDataPacket; import org.geysermc.geyser.entity.type.living.monster.EnderDragonPartEntity; import org.geysermc.geyser.session.cache.EntityCache; import org.geysermc.geyser.translator.protocol.java.entity.JavaRemoveEntitiesTranslator; +import org.geysermc.geyser.translator.protocol.java.entity.JavaSetEntityDataTranslator; +import org.geysermc.geyser.translator.protocol.java.entity.player.JavaPlayerInfoUpdateTranslator; +import org.geysermc.geyser.translator.protocol.java.entity.spawn.JavaAddEntityTranslator; import org.geysermc.geyser.translator.protocol.java.entity.spawn.JavaAddExperienceOrbTranslator; +import org.geysermc.geyser.translator.protocol.java.scoreboard.JavaSetPlayerTeamTranslator; +import org.geysermc.mcprotocollib.auth.GameProfile; +import org.geysermc.mcprotocollib.protocol.data.game.PlayerListEntry; +import org.geysermc.mcprotocollib.protocol.data.game.PlayerListEntryAction; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.EntityMetadata; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.MetadataType; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ByteEntityMetadata; +import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ObjectEntityMetadata; +import org.geysermc.mcprotocollib.protocol.data.game.entity.player.GameMode; +import org.geysermc.mcprotocollib.protocol.data.game.entity.type.EntityType; +import org.geysermc.mcprotocollib.protocol.data.game.scoreboard.CollisionRule; +import org.geysermc.mcprotocollib.protocol.data.game.scoreboard.NameTagVisibility; +import org.geysermc.mcprotocollib.protocol.data.game.scoreboard.TeamAction; +import org.geysermc.mcprotocollib.protocol.data.game.scoreboard.TeamColor; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.ClientboundPlayerInfoUpdatePacket; import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.entity.ClientboundRemoveEntitiesPacket; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.entity.ClientboundSetEntityDataPacket; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.entity.spawn.ClientboundAddEntityPacket; import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.entity.spawn.ClientboundAddExperienceOrbPacket; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.scoreboard.ClientboundSetPlayerTeamPacket; import org.junit.jupiter.api.Test; +import java.util.EnumSet; +import java.util.Optional; +import java.util.UUID; + /** - * Tests that don't fit in a larger system (e.g. sidebar objective) that were reported on GitHub + * Tests for issues reported on GitHub. */ public class ScoreboardIssueTests { /** @@ -90,4 +125,137 @@ public class ScoreboardIssueTests { }); }); } + + /** + * Test for #5089. + * It follows the reproduction steps with all the packets it sends along its way. + * Tested with the 2.0.0-SNAPSHOT version. + * Note that this exact issue is actually 2 issues: + *
    + *
  • + * An issue caused by remainders of code that was part of the initial PR that added support for players. + * The code is now more streamlined. + *
  • + *
  • Armor stands are excluded from team visibility checks (the only living entity)
  • + *
+ */ + @Test + void nameNotUpdating() { + mockContextScoreboard(context -> { + var playerInfoUpdateTranslator = new JavaPlayerInfoUpdateTranslator(); + var setPlayerTeamTranslator = new JavaSetPlayerTeamTranslator(); + var addEntityTranslator = new JavaAddEntityTranslator(); + var setEntityDataTranslator = new JavaSetEntityDataTranslator(); + + + // first command, create NPC + + + var npcUuid = UUID.fromString("b0eb01d7-52c9-4730-9fd3-2c03fcb00d6e"); + context.translate( + playerInfoUpdateTranslator, + new ClientboundPlayerInfoUpdatePacket( + EnumSet.of(PlayerListEntryAction.ADD_PLAYER, PlayerListEntryAction.UPDATE_LISTED), + new PlayerListEntry[] { + new PlayerListEntry(npcUuid, new GameProfile(npcUuid, "1297"), false, 0, GameMode.SURVIVAL, null, null, 0, null, null) + })); + + //todo we don't have to remove an entry that was never in the playerlist in the first place + assertNextPacket(context, () -> { + var packet = new PlayerListPacket(); + packet.getEntries().add(new PlayerListPacket.Entry(npcUuid)); + packet.setAction(PlayerListPacket.Action.REMOVE); + return packet; + }); + assertNoNextPacket(context); + + context.translate( + setPlayerTeamTranslator, + new ClientboundSetPlayerTeamPacket( + "npc_team_1297", + Component.empty(), + Component.empty(), + Component.empty(), + false, + false, + NameTagVisibility.NEVER, + CollisionRule.NEVER, + TeamColor.WHITE, + new String[0] + ) + ); + context.translate( + setPlayerTeamTranslator, + new ClientboundSetPlayerTeamPacket("npc_team_1297", TeamAction.ADD_PLAYER, new String[]{ "1297" })); + + context.translate(addEntityTranslator, new ClientboundAddEntityPacket(1297, npcUuid, EntityType.PLAYER, 1, 2, 3, 4, 5, 6)); + // then it updates the displayed skin parts, which isn't relevant for us + + assertNextPacketMatch(context, AddPlayerPacket.class, packet -> { + assertEquals(3, packet.getRuntimeEntityId()); + assertEquals(npcUuid, packet.getUuid()); + assertEquals("1297", packet.getUsername()); + assertEquals((byte) 1, packet.getMetadata().get(EntityDataTypes.NAMETAG_ALWAYS_SHOW)); + assertEquals("", packet.getMetadata().get(EntityDataTypes.NAME)); + }); + assertNoNextPacket(context); + + + // second command, create hologram + + + var hologramUuid = UUID.fromString("b1586291-5f68-44dc-847d-6c123c5b8cbf"); + context.translate( + addEntityTranslator, + new ClientboundAddEntityPacket(1298, hologramUuid, EntityType.ARMOR_STAND, 6, 5, 4, 3, 2, 1)); + + assertNextPacketMatch(context, AddEntityPacket.class, packet -> { + assertEquals(4, packet.getRuntimeEntityId()); + assertEquals("minecraft:armor_stand", packet.getIdentifier()); + }); + + // metadata set: invisible, custom name, custom name visible + context.translate(setEntityDataTranslator, new ClientboundSetEntityDataPacket(1298, new EntityMetadata[]{ + new ByteEntityMetadata(0, MetadataType.BYTE, (byte) 0x20), + new ObjectEntityMetadata<>(2, MetadataType.OPTIONAL_CHAT, Optional.of(Component.text("tesss"))), + new BooleanEntityMetadata(3, MetadataType.BOOLEAN, true) + })); + + assertNextPacketMatch(context, SetEntityDataPacket.class, packet -> { + assertEquals(4, packet.getRuntimeEntityId()); + var metadata = packet.getMetadata(); + assertEquals(0.0f, metadata.get(EntityDataTypes.SCALE)); + assertEquals("tesss", metadata.get(EntityDataTypes.NAME)); + assertEquals((byte) 1, metadata.get(EntityDataTypes.NAMETAG_ALWAYS_SHOW)); + }); + // because the armor stand turned invisible and has a nametag (nametag is hidden when invisible) + assertNextPacketType(context, MoveEntityAbsolutePacket.class); + + context.translate( + setPlayerTeamTranslator, + new ClientboundSetPlayerTeamPacket( + "npc_team_1298", + Component.empty(), + Component.empty(), + Component.empty(), + false, + false, + NameTagVisibility.NEVER, + CollisionRule.NEVER, + TeamColor.WHITE, + new String[0] + ) + ); + context.translate( + setPlayerTeamTranslator, + new ClientboundSetPlayerTeamPacket("npc_team_1298", TeamAction.ADD_PLAYER, new String[]{ hologramUuid.toString() })); + + assertNextPacket(context, () -> { + var packet = new SetEntityDataPacket(); + packet.getMetadata().put(EntityDataTypes.NAME, "§f§r§ftesss§r§f"); + packet.setRuntimeEntityId(4); + return packet; + }); + }); + } } diff --git a/core/src/test/java/org/geysermc/geyser/scoreboard/network/belowname/BasicBelownameScoreboardTests.java b/core/src/test/java/org/geysermc/geyser/scoreboard/network/belowname/BasicBelownameScoreboardTests.java index 5d8d8309f..dfe85a0ee 100644 --- a/core/src/test/java/org/geysermc/geyser/scoreboard/network/belowname/BasicBelownameScoreboardTests.java +++ b/core/src/test/java/org/geysermc/geyser/scoreboard/network/belowname/BasicBelownameScoreboardTests.java @@ -27,7 +27,7 @@ package org.geysermc.geyser.scoreboard.network.belowname; import static org.geysermc.geyser.scoreboard.network.util.AssertUtils.assertNextPacket; import static org.geysermc.geyser.scoreboard.network.util.AssertUtils.assertNoNextPacket; -import static org.geysermc.geyser.scoreboard.network.util.GeyserMockContextScoreboard.mockAndAddPlayerEntity; +import static org.geysermc.geyser.scoreboard.network.util.GeyserMockContextScoreboard.spawnPlayerSilently; import static org.geysermc.geyser.scoreboard.network.util.GeyserMockContextScoreboard.mockContextScoreboard; import net.kyori.adventure.text.Component; @@ -80,7 +80,7 @@ public class BasicBelownameScoreboardTests { var setObjectiveTranslator = new JavaSetObjectiveTranslator(); var setDisplayObjectiveTranslator = new JavaSetDisplayObjectiveTranslator(); - mockAndAddPlayerEntity(context, "player1", 2); + spawnPlayerSilently(context, "player1", 2); context.translate( setObjectiveTranslator, @@ -98,12 +98,12 @@ public class BasicBelownameScoreboardTests { setDisplayObjectiveTranslator, new ClientboundSetDisplayObjectivePacket(ScoreboardPosition.BELOW_NAME, "objective") ); - assertNextPacket(() -> { + assertNextPacket(context, () -> { var packet = new SetEntityDataPacket(); packet.setRuntimeEntityId(2); packet.getMetadata().put(EntityDataTypes.SCORE, "0 §r§9objective"); return packet; - }, context); + }); }); } @@ -113,7 +113,7 @@ public class BasicBelownameScoreboardTests { var setObjectiveTranslator = new JavaSetObjectiveTranslator(); var setDisplayObjectiveTranslator = new JavaSetDisplayObjectiveTranslator(); - mockAndAddPlayerEntity(context, "player1", 2); + spawnPlayerSilently(context, "player1", 2); context.translate( setObjectiveTranslator, @@ -131,24 +131,24 @@ public class BasicBelownameScoreboardTests { setDisplayObjectiveTranslator, new ClientboundSetDisplayObjectivePacket(ScoreboardPosition.BELOW_NAME, "objective") ); - assertNextPacket(() -> { + assertNextPacket(context, () -> { var packet = new SetEntityDataPacket(); packet.setRuntimeEntityId(2); packet.getMetadata().put(EntityDataTypes.SCORE, "0 §robjective"); return packet; - }, context); + }); assertNoNextPacket(context); context.translate( setDisplayObjectiveTranslator, new ClientboundSetDisplayObjectivePacket(ScoreboardPosition.BELOW_NAME, "") ); - assertNextPacket(() -> { + assertNextPacket(context, () -> { var packet = new SetEntityDataPacket(); packet.setRuntimeEntityId(2); packet.getMetadata().put(EntityDataTypes.SCORE, ""); return packet; - }, context); + }); }); } @@ -158,7 +158,7 @@ public class BasicBelownameScoreboardTests { var setObjectiveTranslator = new JavaSetObjectiveTranslator(); var setDisplayObjectiveTranslator = new JavaSetDisplayObjectiveTranslator(); - mockAndAddPlayerEntity(context, "player1", 2); + spawnPlayerSilently(context, "player1", 2); context.translate( setObjectiveTranslator, @@ -186,42 +186,42 @@ public class BasicBelownameScoreboardTests { setDisplayObjectiveTranslator, new ClientboundSetDisplayObjectivePacket(ScoreboardPosition.BELOW_NAME, "objective2") ); - assertNextPacket(() -> { + assertNextPacket(context, () -> { var packet = new SetEntityDataPacket(); packet.setRuntimeEntityId(2); packet.getMetadata().put(EntityDataTypes.SCORE, "0 §robjective2"); return packet; - }, context); + }); assertNoNextPacket(context); context.translate( setDisplayObjectiveTranslator, new ClientboundSetDisplayObjectivePacket(ScoreboardPosition.BELOW_NAME, "objective1") ); - assertNextPacket(() -> { + assertNextPacket(context, () -> { var packet = new SetEntityDataPacket(); packet.setRuntimeEntityId(2); packet.getMetadata().put(EntityDataTypes.SCORE, ""); return packet; - }, context); - assertNextPacket(() -> { + }); + assertNextPacket(context, () -> { var packet = new SetEntityDataPacket(); packet.setRuntimeEntityId(2); packet.getMetadata().put(EntityDataTypes.SCORE, "0 §robjective1"); return packet; - }, context); + }); assertNoNextPacket(context); context.translate( setDisplayObjectiveTranslator, new ClientboundSetDisplayObjectivePacket(ScoreboardPosition.BELOW_NAME, "") ); - assertNextPacket(() -> { + assertNextPacket(context, () -> { var packet = new SetEntityDataPacket(); packet.setRuntimeEntityId(2); packet.getMetadata().put(EntityDataTypes.SCORE, ""); return packet; - }, context); + }); }); } } diff --git a/core/src/test/java/org/geysermc/geyser/scoreboard/network/playerlist/BasicPlayerlistScoreboardTests.java b/core/src/test/java/org/geysermc/geyser/scoreboard/network/playerlist/BasicPlayerlistScoreboardTests.java index a3d4ad671..4ac5ee098 100644 --- a/core/src/test/java/org/geysermc/geyser/scoreboard/network/playerlist/BasicPlayerlistScoreboardTests.java +++ b/core/src/test/java/org/geysermc/geyser/scoreboard/network/playerlist/BasicPlayerlistScoreboardTests.java @@ -32,7 +32,6 @@ import static org.geysermc.geyser.scoreboard.network.util.GeyserMockContextScore import java.util.List; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; -import net.kyori.adventure.text.format.Style; import net.kyori.adventure.text.format.TextDecoration; import org.cloudburstmc.protocol.bedrock.data.ScoreInfo; import org.cloudburstmc.protocol.bedrock.packet.RemoveObjectivePacket; @@ -75,7 +74,7 @@ public class BasicPlayerlistScoreboardTests { setDisplayObjectiveTranslator, new ClientboundSetDisplayObjectivePacket(ScoreboardPosition.PLAYER_LIST, "objective") ); - assertNextPacket(() -> { + assertNextPacket(context, () -> { var packet = new SetDisplayObjectivePacket(); packet.setObjectiveId("0"); packet.setDisplayName("objective"); @@ -83,7 +82,7 @@ public class BasicPlayerlistScoreboardTests { packet.setDisplaySlot("list"); packet.setSortOrder(1); return packet; - }, context); + }); }); } @@ -98,7 +97,7 @@ public class BasicPlayerlistScoreboardTests { new ClientboundSetObjectivePacket( "objective", ObjectiveAction.ADD, - Component.text("objective", Style.style(NamedTextColor.AQUA, TextDecoration.BOLD)), + Component.text("objective", NamedTextColor.AQUA, TextDecoration.BOLD), ScoreType.INTEGER, null ) @@ -109,7 +108,7 @@ public class BasicPlayerlistScoreboardTests { setDisplayObjectiveTranslator, new ClientboundSetDisplayObjectivePacket(ScoreboardPosition.PLAYER_LIST, "objective") ); - assertNextPacket(() -> { + assertNextPacket(context, () -> { var packet = new SetDisplayObjectivePacket(); packet.setObjectiveId("0"); packet.setDisplayName("§b§lobjective"); @@ -117,7 +116,7 @@ public class BasicPlayerlistScoreboardTests { packet.setDisplaySlot("list"); packet.setSortOrder(1); return packet; - }, context); + }); }); } @@ -156,7 +155,7 @@ public class BasicPlayerlistScoreboardTests { setDisplayObjectiveTranslator, new ClientboundSetDisplayObjectivePacket(ScoreboardPosition.PLAYER_LIST, "objective2") ); - assertNextPacket(() -> { + assertNextPacket(context, () -> { var packet = new SetDisplayObjectivePacket(); packet.setObjectiveId("0"); packet.setDisplayName("objective2"); @@ -164,26 +163,26 @@ public class BasicPlayerlistScoreboardTests { packet.setDisplaySlot("list"); packet.setSortOrder(1); return packet; - }, context); - assertNextPacket(() -> { + }); + assertNextPacket(context, () -> { var packet = new SetScorePacket(); packet.setAction(SetScorePacket.Action.SET); // session player name is Tim203 packet.setInfos(List.of(new ScoreInfo(1, "0", 2, ScoreInfo.ScorerType.PLAYER, 1))); return packet; - }, context); + }); assertNoNextPacket(context); context.translate( setDisplayObjectiveTranslator, new ClientboundSetDisplayObjectivePacket(ScoreboardPosition.PLAYER_LIST, "objective1") ); - assertNextPacket(() -> { + assertNextPacket(context, () -> { var packet = new RemoveObjectivePacket(); packet.setObjectiveId("0"); return packet; - }, context); - assertNextPacket(() -> { + }); + assertNextPacket(context, () -> { var packet = new SetDisplayObjectivePacket(); packet.setObjectiveId("2"); packet.setDisplayName("objective1"); @@ -191,14 +190,14 @@ public class BasicPlayerlistScoreboardTests { packet.setDisplaySlot("list"); packet.setSortOrder(1); return packet; - }, context); - assertNextPacket(() -> { + }); + assertNextPacket(context, () -> { var packet = new SetScorePacket(); packet.setAction(SetScorePacket.Action.SET); // session player name is Tim203 packet.setInfos(List.of(new ScoreInfo(3, "2", 1, ScoreInfo.ScorerType.PLAYER, 1))); return packet; - }, context); + }); }); } } diff --git a/core/src/test/java/org/geysermc/geyser/scoreboard/network/server/CubecraftScoreboardTest.java b/core/src/test/java/org/geysermc/geyser/scoreboard/network/server/CubecraftScoreboardTest.java index dd693022c..80f562fc3 100644 --- a/core/src/test/java/org/geysermc/geyser/scoreboard/network/server/CubecraftScoreboardTest.java +++ b/core/src/test/java/org/geysermc/geyser/scoreboard/network/server/CubecraftScoreboardTest.java @@ -26,21 +26,22 @@ package org.geysermc.geyser.scoreboard.network.server; import static org.geysermc.geyser.scoreboard.network.util.AssertUtils.assertNextPacket; +import static org.geysermc.geyser.scoreboard.network.util.AssertUtils.assertNextPacketMatch; import static org.geysermc.geyser.scoreboard.network.util.AssertUtils.assertNoNextPacket; -import static org.geysermc.geyser.scoreboard.network.util.GeyserMockContextScoreboard.mockAndAddPlayerEntity; +import static org.geysermc.geyser.scoreboard.network.util.GeyserMockContextScoreboard.spawnPlayer; import static org.geysermc.geyser.scoreboard.network.util.GeyserMockContextScoreboard.mockContextScoreboard; +import static org.junit.jupiter.api.Assertions.assertEquals; import java.util.List; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; -import net.kyori.adventure.text.format.Style; import net.kyori.adventure.text.format.TextColor; import net.kyori.adventure.text.format.TextDecoration; import org.cloudburstmc.protocol.bedrock.data.ScoreInfo; import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; +import org.cloudburstmc.protocol.bedrock.packet.AddPlayerPacket; import org.cloudburstmc.protocol.bedrock.packet.RemoveObjectivePacket; import org.cloudburstmc.protocol.bedrock.packet.SetDisplayObjectivePacket; -import org.cloudburstmc.protocol.bedrock.packet.SetEntityDataPacket; import org.cloudburstmc.protocol.bedrock.packet.SetScorePacket; import org.geysermc.geyser.translator.protocol.java.scoreboard.JavaSetDisplayObjectiveTranslator; import org.geysermc.geyser.translator.protocol.java.scoreboard.JavaSetObjectiveTranslator; @@ -88,7 +89,7 @@ public class CubecraftScoreboardTest { setDisplayObjectiveTranslator, new ClientboundSetDisplayObjectivePacket(ScoreboardPosition.SIDEBAR, "sidebar") ); - assertNextPacket(() -> { + assertNextPacket(context, () -> { var packet = new SetDisplayObjectivePacket(); packet.setObjectiveId("0"); packet.setDisplayName("sidebar"); @@ -96,7 +97,7 @@ public class CubecraftScoreboardTest { packet.setDisplaySlot("sidebar"); packet.setSortOrder(1); return packet; - }, context); + }); // Now they're going to create a bunch of teams and add players to those teams in a very inefficient way. @@ -191,27 +192,23 @@ public class CubecraftScoreboardTest { ObjectiveAction.UPDATE, Component.empty() .append(Component.text( - "CubeCraft", Style.style(NamedTextColor.WHITE, TextDecoration.BOLD))), + "CubeCraft", NamedTextColor.WHITE, TextDecoration.BOLD)), ScoreType.INTEGER, null)); - assertNextPacket( - () -> { - var packet = new RemoveObjectivePacket(); - packet.setObjectiveId("0"); - return packet; - }, - context); - assertNextPacket( - () -> { - var packet = new SetDisplayObjectivePacket(); - packet.setObjectiveId("0"); - packet.setDisplayName("§f§lCubeCraft"); - packet.setCriteria("dummy"); - packet.setDisplaySlot("sidebar"); - packet.setSortOrder(1); - return packet; - }, - context); + assertNextPacket(context, () -> { + var packet = new RemoveObjectivePacket(); + packet.setObjectiveId("0"); + return packet; + }); + assertNextPacket(context, () -> { + var packet = new SetDisplayObjectivePacket(); + packet.setObjectiveId("0"); + packet.setDisplayName("§f§lCubeCraft"); + packet.setCriteria("dummy"); + packet.setDisplaySlot("sidebar"); + packet.setSortOrder(1); + return packet; + }); context.translate( setTeamTranslator, @@ -234,7 +231,7 @@ public class CubecraftScoreboardTest { new ClientboundSetPlayerTeamPacket( "SB_l-0", Component.text("SB_l-0"), - Component.empty().append(Component.text("", Style.style(NamedTextColor.BLACK))), + Component.empty().append(Component.text("", NamedTextColor.BLACK)), Component.empty(), true, true, @@ -244,14 +241,12 @@ public class CubecraftScoreboardTest { assertNoNextPacket(context); context.translate(setScoreTranslator, new ClientboundSetScorePacket("§0§0", "sidebar", 10)); - assertNextPacket( - () -> { - var packet = new SetScorePacket(); - packet.setAction(SetScorePacket.Action.SET); - packet.setInfos(List.of(new ScoreInfo(1, "0", 10, "§r§0§0§r"))); - return packet; - }, - context); + assertNextPacket(context, () -> { + var packet = new SetScorePacket(); + packet.setAction(SetScorePacket.Action.SET); + packet.setInfos(List.of(new ScoreInfo(1, "0", 10, "§r§0§0§r"))); + return packet; + }); context.translate( setTeamTranslator, @@ -287,14 +282,12 @@ public class CubecraftScoreboardTest { assertNoNextPacket(context); context.translate(setScoreTranslator, new ClientboundSetScorePacket("§0§1", "sidebar", 9)); - assertNextPacket( - () -> { - var packet = new SetScorePacket(); - packet.setAction(SetScorePacket.Action.SET); - packet.setInfos(List.of(new ScoreInfo(2, "0", 9, "§bUser: §r§fTim203§r§0§1§r"))); - return packet; - }, - context); + assertNextPacket(context, () -> { + var packet = new SetScorePacket(); + packet.setAction(SetScorePacket.Action.SET); + packet.setInfos(List.of(new ScoreInfo(2, "0", 9, "§bUser: §r§fTim203§r§0§1§r"))); + return packet; + }); context.translate( setTeamTranslator, @@ -330,14 +323,12 @@ public class CubecraftScoreboardTest { assertNoNextPacket(context); context.translate(setScoreTranslator, new ClientboundSetScorePacket("§0§2", "sidebar", 8)); - assertNextPacket( - () -> { - var packet = new SetScorePacket(); - packet.setAction(SetScorePacket.Action.SET); - packet.setInfos(List.of(new ScoreInfo(3, "0", 8, "§bRank: §r§f\uE1AB §r§0§2§r"))); - return packet; - }, - context); + assertNextPacket(context, () -> { + var packet = new SetScorePacket(); + packet.setAction(SetScorePacket.Action.SET); + packet.setInfos(List.of(new ScoreInfo(3, "0", 8, "§bRank: §r§f\uE1AB §r§0§2§r"))); + return packet; + }); context.translate( setTeamTranslator, @@ -370,14 +361,12 @@ public class CubecraftScoreboardTest { assertNoNextPacket(context); context.translate(setScoreTranslator, new ClientboundSetScorePacket("§0§3", "sidebar", 7)); - assertNextPacket( - () -> { - var packet = new SetScorePacket(); - packet.setAction(SetScorePacket.Action.SET); - packet.setInfos(List.of(new ScoreInfo(4, "0", 7, "§r§0§3§r"))); - return packet; - }, - context); + assertNextPacket(context, () -> { + var packet = new SetScorePacket(); + packet.setAction(SetScorePacket.Action.SET); + packet.setInfos(List.of(new ScoreInfo(4, "0", 7, "§r§0§3§r"))); + return packet; + }); context.translate( setTeamTranslator, @@ -410,14 +399,12 @@ public class CubecraftScoreboardTest { assertNoNextPacket(context); context.translate(setScoreTranslator, new ClientboundSetScorePacket("§0§4", "sidebar", 6)); - assertNextPacket( - () -> { - var packet = new SetScorePacket(); - packet.setAction(SetScorePacket.Action.SET); - packet.setInfos(List.of(new ScoreInfo(5, "0", 6, "§r§0§4§r"))); - return packet; - }, - context); + assertNextPacket(context, () -> { + var packet = new SetScorePacket(); + packet.setAction(SetScorePacket.Action.SET); + packet.setInfos(List.of(new ScoreInfo(5, "0", 6, "§r§0§4§r"))); + return packet; + }); context.translate( setTeamTranslator, @@ -450,14 +437,12 @@ public class CubecraftScoreboardTest { assertNoNextPacket(context); context.translate(setScoreTranslator, new ClientboundSetScorePacket("§0§5", "sidebar", 5)); - assertNextPacket( - () -> { - var packet = new SetScorePacket(); - packet.setAction(SetScorePacket.Action.SET); - packet.setInfos(List.of(new ScoreInfo(6, "0", 5, "§r§0§5§r"))); - return packet; - }, - context); + assertNextPacket(context, () -> { + var packet = new SetScorePacket(); + packet.setAction(SetScorePacket.Action.SET); + packet.setInfos(List.of(new ScoreInfo(6, "0", 5, "§r§0§5§r"))); + return packet; + }); context.translate( setTeamTranslator, @@ -493,14 +478,12 @@ public class CubecraftScoreboardTest { assertNoNextPacket(context); context.translate(setScoreTranslator, new ClientboundSetScorePacket("§0§6", "sidebar", 4)); - assertNextPacket( - () -> { - var packet = new SetScorePacket(); - packet.setAction(SetScorePacket.Action.SET); - packet.setInfos(List.of(new ScoreInfo(7, "0", 4, "§bLobby: §r§fEU #10§r§0§6§r"))); - return packet; - }, - context); + assertNextPacket(context, () -> { + var packet = new SetScorePacket(); + packet.setAction(SetScorePacket.Action.SET); + packet.setInfos(List.of(new ScoreInfo(7, "0", 4, "§bLobby: §r§fEU #10§r§0§6§r"))); + return packet; + }); context.translate( setTeamTranslator, @@ -536,14 +519,12 @@ public class CubecraftScoreboardTest { assertNoNextPacket(context); context.translate(setScoreTranslator, new ClientboundSetScorePacket("§0§7", "sidebar", 3)); - assertNextPacket( - () -> { - var packet = new SetScorePacket(); - packet.setAction(SetScorePacket.Action.SET); - packet.setInfos(List.of(new ScoreInfo(8, "0", 3, "§bPlayers: §r§f783§r§0§7§r"))); - return packet; - }, - context); + assertNextPacket(context, () -> { + var packet = new SetScorePacket(); + packet.setAction(SetScorePacket.Action.SET); + packet.setInfos(List.of(new ScoreInfo(8, "0", 3, "§bPlayers: §r§f783§r§0§7§r"))); + return packet; + }); context.translate( setTeamTranslator, @@ -576,14 +557,12 @@ public class CubecraftScoreboardTest { assertNoNextPacket(context); context.translate(setScoreTranslator, new ClientboundSetScorePacket("§0§8", "sidebar", 2)); - assertNextPacket( - () -> { - var packet = new SetScorePacket(); - packet.setAction(SetScorePacket.Action.SET); - packet.setInfos(List.of(new ScoreInfo(9, "0", 2, "§r§0§8§r"))); - return packet; - }, - context); + assertNextPacket(context, () -> { + var packet = new SetScorePacket(); + packet.setAction(SetScorePacket.Action.SET); + packet.setInfos(List.of(new ScoreInfo(9, "0", 2, "§r§0§8§r"))); + return packet; + }); context.translate( setTeamTranslator, @@ -616,14 +595,12 @@ public class CubecraftScoreboardTest { assertNoNextPacket(context); context.translate(setScoreTranslator, new ClientboundSetScorePacket("§0§9", "sidebar", 1)); - assertNextPacket( - () -> { - var packet = new SetScorePacket(); - packet.setAction(SetScorePacket.Action.SET); - packet.setInfos(List.of(new ScoreInfo(10, "0", 1, "§824/09/24 (g2208)§r§0§9§r"))); - return packet; - }, - context); + assertNextPacket(context, () -> { + var packet = new SetScorePacket(); + packet.setAction(SetScorePacket.Action.SET); + packet.setInfos(List.of(new ScoreInfo(10, "0", 1, "§824/09/24 (g2208)§r§0§9§r"))); + return packet; + }); context.translate( setTeamTranslator, @@ -656,14 +633,12 @@ public class CubecraftScoreboardTest { assertNoNextPacket(context); context.translate(setScoreTranslator, new ClientboundSetScorePacket("§0§a", "sidebar", 0)); - assertNextPacket( - () -> { - var packet = new SetScorePacket(); - packet.setAction(SetScorePacket.Action.SET); - packet.setInfos(List.of(new ScoreInfo(11, "0", 0, "§6play.cubecraft.net§r§0§a§r"))); - return packet; - }, - context); + assertNextPacket(context, () -> { + var packet = new SetScorePacket(); + packet.setAction(SetScorePacket.Action.SET); + packet.setInfos(List.of(new ScoreInfo(11, "0", 0, "§6play.cubecraft.net§r§0§a§r"))); + return packet; + }); // after this we get a ClientboundPlayerInfoUpdatePacket with the action UPDATE_DISPLAY_NAME, // but that one is only shown in the tablist so we don't have to handle that. @@ -672,85 +647,53 @@ public class CubecraftScoreboardTest { // CubeCraft seems to use two armor stands per player: 1 for the rank badge and 1 for the player name. // So the only thing we have to verify is that the nametag is hidden - mockAndAddPlayerEntity(context, "A_Player", 2); - assertNextPacket( - () -> { - var packet = new SetEntityDataPacket(); - packet.setRuntimeEntityId(2); - packet.getMetadata().put(EntityDataTypes.NAME, ""); - return packet; - }, - context); + spawnPlayer(context, "A_Player", 2); + assertNextPacketMatch(context, AddPlayerPacket.class, packet -> { + assertEquals(2, packet.getRuntimeEntityId()); + assertEquals("", packet.getMetadata().get(EntityDataTypes.NAME)); + }); - mockAndAddPlayerEntity(context, "B_Player", 3); - assertNextPacket( - () -> { - var packet = new SetEntityDataPacket(); - packet.setRuntimeEntityId(3); - packet.getMetadata().put(EntityDataTypes.NAME, ""); - return packet; - }, - context); + spawnPlayer(context, "B_Player", 3); + assertNextPacketMatch(context, AddPlayerPacket.class, packet -> { + assertEquals(3, packet.getRuntimeEntityId()); + assertEquals("", packet.getMetadata().get(EntityDataTypes.NAME)); + }); - mockAndAddPlayerEntity(context, "E_Player", 4); - assertNextPacket( - () -> { - var packet = new SetEntityDataPacket(); - packet.setRuntimeEntityId(4); - packet.getMetadata().put(EntityDataTypes.NAME, ""); - return packet; - }, - context); + spawnPlayer(context, "E_Player", 4); + assertNextPacketMatch(context, AddPlayerPacket.class, packet -> { + assertEquals(4, packet.getRuntimeEntityId()); + assertEquals("", packet.getMetadata().get(EntityDataTypes.NAME)); + }); - mockAndAddPlayerEntity(context, "H_Player", 5); - assertNextPacket( - () -> { - var packet = new SetEntityDataPacket(); - packet.setRuntimeEntityId(5); - packet.getMetadata().put(EntityDataTypes.NAME, ""); - return packet; - }, - context); + spawnPlayer(context, "H_Player", 5); + assertNextPacketMatch(context, AddPlayerPacket.class, packet -> { + assertEquals(5, packet.getRuntimeEntityId()); + assertEquals("", packet.getMetadata().get(EntityDataTypes.NAME)); + }); - mockAndAddPlayerEntity(context, "J_Player", 6); - assertNextPacket( - () -> { - var packet = new SetEntityDataPacket(); - packet.setRuntimeEntityId(6); - packet.getMetadata().put(EntityDataTypes.NAME, ""); - return packet; - }, - context); + spawnPlayer(context, "J_Player", 6); + assertNextPacketMatch(context, AddPlayerPacket.class, packet -> { + assertEquals(6, packet.getRuntimeEntityId()); + assertEquals("", packet.getMetadata().get(EntityDataTypes.NAME)); + }); - mockAndAddPlayerEntity(context, "K_Player", 7); - assertNextPacket( - () -> { - var packet = new SetEntityDataPacket(); - packet.setRuntimeEntityId(7); - packet.getMetadata().put(EntityDataTypes.NAME, ""); - return packet; - }, - context); + spawnPlayer(context, "K_Player", 7); + assertNextPacketMatch(context, AddPlayerPacket.class, packet -> { + assertEquals(7, packet.getRuntimeEntityId()); + assertEquals("", packet.getMetadata().get(EntityDataTypes.NAME)); + }); - mockAndAddPlayerEntity(context, "L_Player", 8); - assertNextPacket( - () -> { - var packet = new SetEntityDataPacket(); - packet.setRuntimeEntityId(8); - packet.getMetadata().put(EntityDataTypes.NAME, ""); - return packet; - }, - context); + spawnPlayer(context, "L_Player", 8); + assertNextPacketMatch(context, AddPlayerPacket.class, packet -> { + assertEquals(8, packet.getRuntimeEntityId()); + assertEquals("", packet.getMetadata().get(EntityDataTypes.NAME)); + }); - mockAndAddPlayerEntity(context, "O_Player", 9); - assertNextPacket( - () -> { - var packet = new SetEntityDataPacket(); - packet.setRuntimeEntityId(9); - packet.getMetadata().put(EntityDataTypes.NAME, ""); - return packet; - }, - context); + spawnPlayer(context, "O_Player", 9); + assertNextPacketMatch(context, AddPlayerPacket.class, packet -> { + assertEquals(9, packet.getRuntimeEntityId()); + assertEquals("", packet.getMetadata().get(EntityDataTypes.NAME)); + }); }); } } diff --git a/core/src/test/java/org/geysermc/geyser/scoreboard/network/sidebar/BasicSidebarScoreboardTests.java b/core/src/test/java/org/geysermc/geyser/scoreboard/network/sidebar/BasicSidebarScoreboardTests.java index b3999303e..bd0d64c80 100644 --- a/core/src/test/java/org/geysermc/geyser/scoreboard/network/sidebar/BasicSidebarScoreboardTests.java +++ b/core/src/test/java/org/geysermc/geyser/scoreboard/network/sidebar/BasicSidebarScoreboardTests.java @@ -32,7 +32,6 @@ import static org.geysermc.geyser.scoreboard.network.util.GeyserMockContextScore import java.util.List; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; -import net.kyori.adventure.text.format.Style; import net.kyori.adventure.text.format.TextDecoration; import org.cloudburstmc.protocol.bedrock.data.ScoreInfo; import org.cloudburstmc.protocol.bedrock.packet.RemoveObjectivePacket; @@ -75,7 +74,7 @@ public class BasicSidebarScoreboardTests { setDisplayObjectiveTranslator, new ClientboundSetDisplayObjectivePacket(ScoreboardPosition.PLAYER_LIST, "objective") ); - assertNextPacket(() -> { + assertNextPacket(context, () -> { var packet = new SetDisplayObjectivePacket(); packet.setObjectiveId("0"); packet.setDisplayName("objective"); @@ -83,17 +82,17 @@ public class BasicSidebarScoreboardTests { packet.setDisplaySlot("list"); packet.setSortOrder(1); return packet; - }, context); + }); context.translate( setDisplayObjectiveTranslator, new ClientboundSetDisplayObjectivePacket(ScoreboardPosition.PLAYER_LIST, "") ); - assertNextPacket(() -> { + assertNextPacket(context, () -> { var packet = new RemoveObjectivePacket(); packet.setObjectiveId("0"); return packet; - }, context); + }); }); } @@ -108,7 +107,7 @@ public class BasicSidebarScoreboardTests { new ClientboundSetObjectivePacket( "objective", ObjectiveAction.ADD, - Component.text("objective", Style.style(NamedTextColor.AQUA, TextDecoration.BOLD)), + Component.text("objective", NamedTextColor.AQUA, TextDecoration.BOLD), ScoreType.INTEGER, null ) @@ -119,7 +118,7 @@ public class BasicSidebarScoreboardTests { setDisplayObjectiveTranslator, new ClientboundSetDisplayObjectivePacket(ScoreboardPosition.SIDEBAR, "objective") ); - assertNextPacket(() -> { + assertNextPacket(context, () -> { var packet = new SetDisplayObjectivePacket(); packet.setObjectiveId("0"); packet.setDisplayName("§b§lobjective"); @@ -127,7 +126,7 @@ public class BasicSidebarScoreboardTests { packet.setDisplaySlot("sidebar"); packet.setSortOrder(1); return packet; - }, context); + }); }); } @@ -170,7 +169,7 @@ public class BasicSidebarScoreboardTests { new ClientboundSetDisplayObjectivePacket(ScoreboardPosition.SIDEBAR, "objective2") ); - assertNextPacket(() -> { + assertNextPacket(context, () -> { var packet = new SetDisplayObjectivePacket(); packet.setObjectiveId("0"); packet.setDisplayName("objective2"); @@ -178,13 +177,13 @@ public class BasicSidebarScoreboardTests { packet.setDisplaySlot("sidebar"); packet.setSortOrder(1); return packet; - }, context); - assertNextPacket(() -> { + }); + assertNextPacket(context, () -> { var packet = new SetScorePacket(); packet.setAction(SetScorePacket.Action.SET); packet.setInfos(List.of(new ScoreInfo(1, "0", 2, "Tim203"))); return packet; - }, context); + }); assertNoNextPacket(context); @@ -193,12 +192,12 @@ public class BasicSidebarScoreboardTests { new ClientboundSetDisplayObjectivePacket(ScoreboardPosition.SIDEBAR, "objective1") ); - assertNextPacket(() -> { + assertNextPacket(context, () -> { var packet = new RemoveObjectivePacket(); packet.setObjectiveId("0"); return packet; - }, context); - assertNextPacket(() -> { + }); + assertNextPacket(context, () -> { var packet = new SetDisplayObjectivePacket(); packet.setObjectiveId("2"); packet.setDisplayName("objective1"); @@ -206,13 +205,13 @@ public class BasicSidebarScoreboardTests { packet.setDisplaySlot("sidebar"); packet.setSortOrder(1); return packet; - }, context); - assertNextPacket(() -> { + }); + assertNextPacket(context, () -> { var packet = new SetScorePacket(); packet.setAction(SetScorePacket.Action.SET); packet.setInfos(List.of(new ScoreInfo(3, "2", 1, "Tim203"))); return packet; - }, context); + }); }); } } diff --git a/core/src/test/java/org/geysermc/geyser/scoreboard/network/sidebar/OrderAndLimitSidebarScoreboardTests.java b/core/src/test/java/org/geysermc/geyser/scoreboard/network/sidebar/OrderAndLimitSidebarScoreboardTests.java index 3e0be1c02..aab837456 100644 --- a/core/src/test/java/org/geysermc/geyser/scoreboard/network/sidebar/OrderAndLimitSidebarScoreboardTests.java +++ b/core/src/test/java/org/geysermc/geyser/scoreboard/network/sidebar/OrderAndLimitSidebarScoreboardTests.java @@ -98,7 +98,7 @@ public class OrderAndLimitSidebarScoreboardTests { setDisplayObjectiveTranslator, new ClientboundSetDisplayObjectivePacket(ScoreboardPosition.SIDEBAR, "objective") ); - assertNextPacket(() -> { + assertNextPacket(context, () -> { var packet = new SetDisplayObjectivePacket(); packet.setObjectiveId("0"); packet.setDisplayName("objective"); @@ -106,8 +106,8 @@ public class OrderAndLimitSidebarScoreboardTests { packet.setDisplaySlot("sidebar"); packet.setSortOrder(1); return packet; - }, context); - assertNextPacket(() -> { + }); + assertNextPacket(context, () -> { var packet = new SetScorePacket(); packet.setAction(SetScorePacket.Action.SET); packet.setInfos(List.of( @@ -128,7 +128,7 @@ public class OrderAndLimitSidebarScoreboardTests { new ScoreInfo(15, "0", 3, "c") )); return packet; - }, context); + }); assertNoNextPacket(context); // remove a score @@ -136,43 +136,43 @@ public class OrderAndLimitSidebarScoreboardTests { resetScoreTranslator, new ClientboundResetScorePacket("m", "objective") ); - assertNextPacket(() -> { + assertNextPacket(context, () -> { var packet = new SetScorePacket(); packet.setAction(SetScorePacket.Action.REMOVE); packet.setInfos(List.of(new ScoreInfo(5, "0", 13, "m"))); return packet; - }, context); - assertNextPacket(() -> { + }); + assertNextPacket(context, () -> { var packet = new SetScorePacket(); packet.setAction(SetScorePacket.Action.SET); packet.setInfos(List.of(new ScoreInfo(16, "0", 2, "b"))); return packet; - }, context); + }); // add a score context.translate( setScoreTranslator, new ClientboundSetScorePacket("aa", "objective", 13) ); - assertNextPacket(() -> { + assertNextPacket(context, () -> { var packet = new SetScorePacket(); packet.setAction(SetScorePacket.Action.REMOVE); packet.setInfos(List.of(new ScoreInfo(16, "0", 2, "b"))); return packet; - }, context); - assertNextPacket(() -> { + }); + assertNextPacket(context, () -> { var packet = new SetScorePacket(); packet.setAction(SetScorePacket.Action.SET); packet.setInfos(List.of(new ScoreInfo(17, "0", 13, "aa"))); return packet; - }, context); + }); // add score with same score value (after) context.translate( setScoreTranslator, new ClientboundSetScorePacket("ga", "objective", 9) ); - assertNextPacket(() -> { + assertNextPacket(context, () -> { var packet = new SetScorePacket(); packet.setAction(SetScorePacket.Action.REMOVE); packet.setInfos(List.of( @@ -180,8 +180,8 @@ public class OrderAndLimitSidebarScoreboardTests { new ScoreInfo(9, "0", 9, "§0§rg") )); return packet; - }, context); - assertNextPacket(() -> { + }); + assertNextPacket(context, () -> { var packet = new SetScorePacket(); packet.setAction(SetScorePacket.Action.SET); packet.setInfos(List.of( @@ -189,14 +189,14 @@ public class OrderAndLimitSidebarScoreboardTests { new ScoreInfo(18, "0", 9, "§1§rga") )); return packet; - }, context); + }); // add another score with same score value (before all) context.translate( setScoreTranslator, new ClientboundSetScorePacket("ag", "objective", 9) ); - assertNextPacket(() -> { + assertNextPacket(context, () -> { var packet = new SetScorePacket(); packet.setAction(SetScorePacket.Action.REMOVE); packet.setInfos(List.of( @@ -205,8 +205,8 @@ public class OrderAndLimitSidebarScoreboardTests { new ScoreInfo(18, "0", 9, "§2§rga") )); return packet; - }, context); - assertNextPacket(() -> { + }); + assertNextPacket(context, () -> { var packet = new SetScorePacket(); packet.setAction(SetScorePacket.Action.SET); packet.setInfos(List.of( @@ -215,14 +215,14 @@ public class OrderAndLimitSidebarScoreboardTests { new ScoreInfo(18, "0", 9, "§2§rga") )); return packet; - }, context); + }); // remove score with same value context.translate( resetScoreTranslator, new ClientboundResetScorePacket("g", "objective") ); - assertNextPacket(() -> { + assertNextPacket(context, () -> { var packet = new SetScorePacket(); packet.setAction(SetScorePacket.Action.REMOVE); packet.setInfos(List.of( @@ -230,8 +230,8 @@ public class OrderAndLimitSidebarScoreboardTests { new ScoreInfo(18, "0", 9, "§1§rga") )); return packet; - }, context); - assertNextPacket(() -> { + }); + assertNextPacket(context, () -> { var packet = new SetScorePacket(); packet.setAction(SetScorePacket.Action.SET); packet.setInfos(List.of( @@ -239,14 +239,14 @@ public class OrderAndLimitSidebarScoreboardTests { new ScoreInfo(20, "0", 4, "e") )); return packet; - }, context); + }); // remove the other score with the same value context.translate( resetScoreTranslator, new ClientboundResetScorePacket("ga", "objective") ); - assertNextPacket(() -> { + assertNextPacket(context, () -> { var packet = new SetScorePacket(); packet.setAction(SetScorePacket.Action.REMOVE); packet.setInfos(List.of( @@ -254,8 +254,8 @@ public class OrderAndLimitSidebarScoreboardTests { new ScoreInfo(19, "0", 9, "ag") )); return packet; - }, context); - assertNextPacket(() -> { + }); + assertNextPacket(context, () -> { var packet = new SetScorePacket(); packet.setAction(SetScorePacket.Action.SET); packet.setInfos(List.of( @@ -263,7 +263,7 @@ public class OrderAndLimitSidebarScoreboardTests { new ScoreInfo(21, "0", 3, "c") )); return packet; - }, context); + }); }); } @@ -327,7 +327,7 @@ public class OrderAndLimitSidebarScoreboardTests { setDisplayObjectiveTranslator, new ClientboundSetDisplayObjectivePacket(ScoreboardPosition.SIDEBAR, "objective") ); - assertNextPacket(() -> { + assertNextPacket(context, () -> { var packet = new SetDisplayObjectivePacket(); packet.setObjectiveId("0"); packet.setDisplayName("objective"); @@ -335,8 +335,8 @@ public class OrderAndLimitSidebarScoreboardTests { packet.setDisplaySlot("sidebar"); packet.setSortOrder(1); return packet; - }, context); - assertNextPacket(() -> { + }); + assertNextPacket(context, () -> { var packet = new SetScorePacket(); packet.setAction(SetScorePacket.Action.SET); packet.setInfos(List.of( @@ -357,7 +357,7 @@ public class OrderAndLimitSidebarScoreboardTests { new ScoreInfo(15, "0", 3, "c") )); return packet; - }, context); + }); assertNoNextPacket(context); // remove a score @@ -365,36 +365,36 @@ public class OrderAndLimitSidebarScoreboardTests { resetScoreTranslator, new ClientboundResetScorePacket("m", "objective") ); - assertNextPacket(() -> { + assertNextPacket(context, () -> { var packet = new SetScorePacket(); packet.setAction(SetScorePacket.Action.REMOVE); packet.setInfos(List.of(new ScoreInfo(5, "0", 13, "m"))); return packet; - }, context); - assertNextPacket(() -> { + }); + assertNextPacket(context, () -> { var packet = new SetScorePacket(); packet.setAction(SetScorePacket.Action.SET); packet.setInfos(List.of(new ScoreInfo(16, "0", 2, "b"))); return packet; - }, context); + }); // add a score context.translate( setScoreTranslator, new ClientboundSetScorePacket("aa", "objective", 13) ); - assertNextPacket(() -> { + assertNextPacket(context, () -> { var packet = new SetScorePacket(); packet.setAction(SetScorePacket.Action.REMOVE); packet.setInfos(List.of(new ScoreInfo(16, "0", 2, "b"))); return packet; - }, context); - assertNextPacket(() -> { + }); + assertNextPacket(context, () -> { var packet = new SetScorePacket(); packet.setAction(SetScorePacket.Action.SET); packet.setInfos(List.of(new ScoreInfo(17, "0", 13, "aa"))); return packet; - }, context); + }); // add some teams for the upcoming score adds context.translate( @@ -435,7 +435,7 @@ public class OrderAndLimitSidebarScoreboardTests { setScoreTranslator, new ClientboundSetScorePacket("oa", "objective", 11) ); - assertNextPacket(() -> { + assertNextPacket(context, () -> { var packet = new SetScorePacket(); packet.setAction(SetScorePacket.Action.REMOVE); packet.setInfos(List.of( @@ -443,8 +443,8 @@ public class OrderAndLimitSidebarScoreboardTests { new ScoreInfo(7, "0", 11, "§0§r§4prefix§r§4o§r§4suffix") )); return packet; - }, context); - assertNextPacket(() -> { + }); + assertNextPacket(context, () -> { var packet = new SetScorePacket(); packet.setAction(SetScorePacket.Action.SET); packet.setInfos(List.of( @@ -452,7 +452,7 @@ public class OrderAndLimitSidebarScoreboardTests { new ScoreInfo(18, "0", 11, "§1§r§3prefix§r§3oa§r§3suffix") )); return packet; - }, context); + }); // add a score that on Java should be before 'o', but would be after on Bedrock without manual order // due to the team color @@ -460,7 +460,7 @@ public class OrderAndLimitSidebarScoreboardTests { setScoreTranslator, new ClientboundSetScorePacket("ao", "objective", 11) ); - assertNextPacket(() -> { + assertNextPacket(context, () -> { var packet = new SetScorePacket(); packet.setAction(SetScorePacket.Action.REMOVE); packet.setInfos(List.of( @@ -469,8 +469,8 @@ public class OrderAndLimitSidebarScoreboardTests { new ScoreInfo(18, "0", 11, "§2§r§3prefix§r§3oa§r§3suffix") )); return packet; - }, context); - assertNextPacket(() -> { + }); + assertNextPacket(context, () -> { var packet = new SetScorePacket(); packet.setAction(SetScorePacket.Action.SET); packet.setInfos(List.of( @@ -479,14 +479,14 @@ public class OrderAndLimitSidebarScoreboardTests { new ScoreInfo(18, "0", 11, "§2§r§3prefix§r§3oa§r§3suffix") )); return packet; - }, context); + }); // remove original 'o' score context.translate( resetScoreTranslator, new ClientboundResetScorePacket("o", "objective") ); - assertNextPacket(() -> { + assertNextPacket(context, () -> { var packet = new SetScorePacket(); packet.setAction(SetScorePacket.Action.REMOVE); packet.setInfos(List.of( @@ -494,8 +494,8 @@ public class OrderAndLimitSidebarScoreboardTests { new ScoreInfo(18, "0", 11, "§1§r§3prefix§r§3oa§r§3suffix") )); return packet; - }, context); - assertNextPacket(() -> { + }); + assertNextPacket(context, () -> { var packet = new SetScorePacket(); packet.setAction(SetScorePacket.Action.SET); packet.setInfos(List.of( @@ -503,14 +503,14 @@ public class OrderAndLimitSidebarScoreboardTests { new ScoreInfo(20, "0", 4, "e") )); return packet; - }, context); + }); // remove the other score with the same value as 'o' context.translate( resetScoreTranslator, new ClientboundResetScorePacket("oa", "objective") ); - assertNextPacket(() -> { + assertNextPacket(context, () -> { var packet = new SetScorePacket(); packet.setAction(SetScorePacket.Action.REMOVE); packet.setInfos(List.of( @@ -518,8 +518,8 @@ public class OrderAndLimitSidebarScoreboardTests { new ScoreInfo(19, "0", 11, "§5prefix§r§5ao§r§5suffix") )); return packet; - }, context); - assertNextPacket(() -> { + }); + assertNextPacket(context, () -> { var packet = new SetScorePacket(); packet.setAction(SetScorePacket.Action.SET); packet.setInfos(List.of( @@ -527,7 +527,7 @@ public class OrderAndLimitSidebarScoreboardTests { new ScoreInfo(21, "0", 3, "c") )); return packet; - }, context); + }); }); } } diff --git a/core/src/test/java/org/geysermc/geyser/scoreboard/network/sidebar/VanillaSidebarScoreboardTests.java b/core/src/test/java/org/geysermc/geyser/scoreboard/network/sidebar/VanillaSidebarScoreboardTests.java index 0a02a58d9..f511f59c7 100644 --- a/core/src/test/java/org/geysermc/geyser/scoreboard/network/sidebar/VanillaSidebarScoreboardTests.java +++ b/core/src/test/java/org/geysermc/geyser/scoreboard/network/sidebar/VanillaSidebarScoreboardTests.java @@ -69,7 +69,7 @@ public class VanillaSidebarScoreboardTests { setDisplayObjectiveTranslator, new ClientboundSetDisplayObjectivePacket(ScoreboardPosition.SIDEBAR, "objective") ); - assertNextPacket(() -> { + assertNextPacket(context, () -> { var packet = new SetDisplayObjectivePacket(); packet.setObjectiveId("0"); packet.setDisplayName("objective"); @@ -77,16 +77,16 @@ public class VanillaSidebarScoreboardTests { packet.setDisplaySlot("sidebar"); packet.setSortOrder(1); return packet; - }, context); + }); assertNoNextPacket(context); context.translate(setScoreTranslator, new ClientboundSetScorePacket("owner", "objective", 1)); - assertNextPacket(() -> { + assertNextPacket(context, () -> { var packet = new SetScorePacket(); packet.setAction(SetScorePacket.Action.SET); packet.setInfos(List.of(new ScoreInfo(1, "0", 1, "owner"))); return packet; - }, context); + }); }); } @@ -114,7 +114,7 @@ public class VanillaSidebarScoreboardTests { setDisplayObjectiveTranslator, new ClientboundSetDisplayObjectivePacket(ScoreboardPosition.SIDEBAR, "objective") ); - assertNextPacket(() -> { + assertNextPacket(context, () -> { var packet = new SetDisplayObjectivePacket(); packet.setObjectiveId("0"); packet.setDisplayName("objective"); @@ -122,22 +122,22 @@ public class VanillaSidebarScoreboardTests { packet.setDisplaySlot("sidebar"); packet.setSortOrder(1); return packet; - }, context); - assertNextPacket(() -> { + }); + assertNextPacket(context, () -> { var packet = new SetScorePacket(); packet.setAction(SetScorePacket.Action.SET); packet.setInfos(List.of(new ScoreInfo(1, "0", 1, "owner"))); return packet; - }, context); + }); assertNoNextPacket(context); context.translate(setScoreTranslator, new ClientboundSetScorePacket("owner", "objective", 2)); - assertNextPacket(() -> { + assertNextPacket(context, () -> { var packet = new SetScorePacket(); packet.setAction(SetScorePacket.Action.SET); packet.setInfos(List.of(new ScoreInfo(1, "0", 2, "owner"))); return packet; - }, context); + }); }); } @@ -166,7 +166,7 @@ public class VanillaSidebarScoreboardTests { setDisplayObjectiveTranslator, new ClientboundSetDisplayObjectivePacket(ScoreboardPosition.SIDEBAR, "objective") ); - assertNextPacket(() -> { + assertNextPacket(context, () -> { var packet = new SetDisplayObjectivePacket(); packet.setObjectiveId("0"); packet.setDisplayName("objective"); @@ -174,31 +174,31 @@ public class VanillaSidebarScoreboardTests { packet.setDisplaySlot("sidebar"); packet.setSortOrder(1); return packet; - }, context); - assertNextPacket(() -> { + }); + assertNextPacket(context, () -> { var packet = new SetScorePacket(); packet.setAction(SetScorePacket.Action.SET); packet.setInfos(List.of(new ScoreInfo(1, "0", 1, "owner"))); return packet; - }, context); + }); assertNoNextPacket(context); context.translate( setScoreTranslator, new ClientboundSetScorePacket("owner", "objective", 1).withDisplay(Component.text("hi")) ); - assertNextPacket(() -> { + assertNextPacket(context, () -> { var packet = new SetScorePacket(); packet.setAction(SetScorePacket.Action.REMOVE); packet.setInfos(List.of(new ScoreInfo(1, "0", 1, "hi"))); return packet; - }, context); - assertNextPacket(() -> { + }); + assertNextPacket(context, () -> { var packet = new SetScorePacket(); packet.setAction(SetScorePacket.Action.SET); packet.setInfos(List.of(new ScoreInfo(1, "0", 1, "hi"))); return packet; - }, context); + }); }); } @@ -227,7 +227,7 @@ public class VanillaSidebarScoreboardTests { setDisplayObjectiveTranslator, new ClientboundSetDisplayObjectivePacket(ScoreboardPosition.SIDEBAR, "objective") ); - assertNextPacket(() -> { + assertNextPacket(context, () -> { var packet = new SetDisplayObjectivePacket(); packet.setObjectiveId("0"); packet.setDisplayName("objective"); @@ -235,31 +235,31 @@ public class VanillaSidebarScoreboardTests { packet.setDisplaySlot("sidebar"); packet.setSortOrder(1); return packet; - }, context); - assertNextPacket(() -> { + }); + assertNextPacket(context, () -> { var packet = new SetScorePacket(); packet.setAction(SetScorePacket.Action.SET); packet.setInfos(List.of(new ScoreInfo(1, "0", 1, "owner"))); return packet; - }, context); + }); assertNoNextPacket(context); context.translate( setScoreTranslator, new ClientboundSetScorePacket("owner", "objective", 2).withDisplay(Component.text("hi")) ); - assertNextPacket(() -> { + assertNextPacket(context, () -> { var packet = new SetScorePacket(); packet.setAction(SetScorePacket.Action.REMOVE); packet.setInfos(List.of(new ScoreInfo(1, "0", 2, "hi"))); return packet; - }, context); - assertNextPacket(() -> { + }); + assertNextPacket(context, () -> { var packet = new SetScorePacket(); packet.setAction(SetScorePacket.Action.SET); packet.setInfos(List.of(new ScoreInfo(1, "0", 2, "hi"))); return packet; - }, context); + }); }); } } diff --git a/core/src/test/java/org/geysermc/geyser/scoreboard/network/util/AssertUtils.java b/core/src/test/java/org/geysermc/geyser/scoreboard/network/util/AssertUtils.java index b15994533..9177f205a 100644 --- a/core/src/test/java/org/geysermc/geyser/scoreboard/network/util/AssertUtils.java +++ b/core/src/test/java/org/geysermc/geyser/scoreboard/network/util/AssertUtils.java @@ -26,6 +26,7 @@ package org.geysermc.geyser.scoreboard.network.util; import java.util.Collections; +import java.util.function.Consumer; import java.util.function.Supplier; import org.cloudburstmc.protocol.bedrock.packet.BedrockPacket; import org.junit.jupiter.api.Assertions; @@ -38,7 +39,7 @@ public class AssertUtils { Assertions.assertEquals(expected.get(), actual); } - public static void assertNextPacket(Supplier expected, GeyserMockContext context) { + public static void assertNextPacket(GeyserMockContext context, Supplier expected) { assertContextEquals(expected, context.nextPacket()); } @@ -50,6 +51,16 @@ public class AssertUtils { Assertions.assertEquals(type, actual.getClass()); } + public static void assertNextPacketMatch(GeyserMockContext context, Class type, Consumer matcher) { + var actual = context.nextPacket(); + if (actual == null) { + Assertions.fail("Expected another packet!"); + } + Assertions.assertEquals(type, actual.getClass(), "Expected packet to be an instance of " + type); + //noinspection unchecked verified in the line above me + matcher.accept((T) actual); + } + public static void assertNoNextPacket(GeyserMockContext context) { Assertions.assertEquals( Collections.emptyList(), diff --git a/core/src/test/java/org/geysermc/geyser/scoreboard/network/util/GeyserMockContext.java b/core/src/test/java/org/geysermc/geyser/scoreboard/network/util/GeyserMockContext.java index 72515d714..1d262d8b8 100644 --- a/core/src/test/java/org/geysermc/geyser/scoreboard/network/util/GeyserMockContext.java +++ b/core/src/test/java/org/geysermc/geyser/scoreboard/network/util/GeyserMockContext.java @@ -35,16 +35,15 @@ import java.util.function.Consumer; import org.cloudburstmc.protocol.bedrock.packet.BedrockPacket; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.configuration.GeyserConfiguration; +import org.geysermc.geyser.registry.Registries; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.protocol.PacketTranslator; -import org.mockito.MockedStatic; import org.mockito.Mockito; public class GeyserMockContext { private final List mocksAndSpies = new ArrayList<>(); private final List storedObjects = new ArrayList<>(); private final List packets = Collections.synchronizedList(new ArrayList<>()); - private MockedStatic geyserImplMock; public static void mockContext(Consumer geyserContext) { var context = new GeyserMockContext(); @@ -59,9 +58,15 @@ public class GeyserMockContext { var logger = context.storeObject(new EmptyGeyserLogger()); when(geyserImpl.getLogger()).thenReturn(logger); - try (var mocked = mockStatic(GeyserImpl.class)) { - mocked.when(GeyserImpl::getInstance).thenReturn(geyserImpl); - context.geyserImplMock = mocked; + try (var geyserImplMock = mockStatic(GeyserImpl.class)) { + geyserImplMock.when(GeyserImpl::getInstance).thenReturn(geyserImpl); + + // Since Geyser isn't actually loaded, the Registries#init will not be called. + // This means that we manually load the registries we want to use + Registries.ENTITY_DEFINITIONS.load(); + Registries.JAVA_ENTITY_IDENTIFIERS.load(); + Registries.BEDROCK_ENTITY_PROPERTIES.load(); + geyserContext.accept(context); } } @@ -136,8 +141,4 @@ public class GeyserMockContext { public void translate(PacketTranslator translator, T packet) { translator.translate(session(), packet); } - - public MockedStatic geyserImplMock() { - return geyserImplMock; - } } diff --git a/core/src/test/java/org/geysermc/geyser/scoreboard/network/util/GeyserMockContextScoreboard.java b/core/src/test/java/org/geysermc/geyser/scoreboard/network/util/GeyserMockContextScoreboard.java index bc76a1b70..e0d9918e5 100644 --- a/core/src/test/java/org/geysermc/geyser/scoreboard/network/util/GeyserMockContextScoreboard.java +++ b/core/src/test/java/org/geysermc/geyser/scoreboard/network/util/GeyserMockContextScoreboard.java @@ -25,6 +25,7 @@ package org.geysermc.geyser.scoreboard.network.util; +import static org.geysermc.geyser.scoreboard.network.util.AssertUtils.assertNextPacketType; import static org.geysermc.geyser.scoreboard.network.util.AssertUtils.assertNoNextPacket; import static org.geysermc.geyser.scoreboard.network.util.GeyserMockContext.mockContext; import static org.mockito.ArgumentMatchers.any; @@ -34,6 +35,8 @@ import static org.mockito.Mockito.when; import java.util.UUID; import java.util.function.Consumer; +import org.cloudburstmc.math.vector.Vector3f; +import org.cloudburstmc.protocol.bedrock.packet.AddPlayerPacket; import org.cloudburstmc.protocol.bedrock.packet.BedrockPacket; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.entity.type.player.PlayerEntity; @@ -82,15 +85,20 @@ public class GeyserMockContextScoreboard { when(worldCache.increaseAndGetScoreboardPacketsPerSecond()).thenReturn(0); } - public static PlayerEntity mockAndAddPlayerEntity(GeyserMockContext context, String username, long geyserId) { - var playerEntity = spy(new PlayerEntity(context.session(), geyserId, UUID.randomUUID(), username)); - // fake the player being spawned - when(playerEntity.isValid()).thenReturn(true); + public static PlayerEntity spawnPlayerSilently(GeyserMockContext context, String username, long geyserId) { + var player = spawnPlayer(context, username, geyserId); + assertNextPacketType(context, AddPlayerPacket.class); + return player; + } + + public static PlayerEntity spawnPlayer(GeyserMockContext context, String username, long geyserId) { + var playerEntity = spy(new PlayerEntity(context.session(), (int) geyserId, geyserId, UUID.randomUUID(), Vector3f.ZERO, Vector3f.ZERO, 0, 0, 0, username, null)); var entityCache = context.mockOrSpy(EntityCache.class); entityCache.addPlayerEntity(playerEntity); // called when the player spawns - entityCache.cacheEntity(playerEntity); + entityCache.spawnEntity(playerEntity); + return playerEntity; } } From 8f7a0d0778aa9106ea32527e535fe5d1cc7d7d0d Mon Sep 17 00:00:00 2001 From: Tim203 Date: Mon, 28 Oct 2024 00:56:39 +0100 Subject: [PATCH 06/10] Correct the loading of the block registries and the common registries --- .../java/org/geysermc/geyser/GeyserImpl.java | 12 ++++++-- .../geyser/registry/BlockRegistries.java | 30 ++++++++++++++----- .../geysermc/geyser/registry/Registries.java | 10 ++++--- 3 files changed, 37 insertions(+), 15 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/GeyserImpl.java b/core/src/main/java/org/geysermc/geyser/GeyserImpl.java index 4672aef5b..f679b412c 100644 --- a/core/src/main/java/org/geysermc/geyser/GeyserImpl.java +++ b/core/src/main/java/org/geysermc/geyser/GeyserImpl.java @@ -231,9 +231,15 @@ public class GeyserImpl implements GeyserApi, EventRegistrar { } logger.info("******************************************"); - /* Initialize registries */ - Registries.init(); - BlockRegistries.init(); + /* + First load the registries and then populate them. + Both the block registries and the common registries depend on each other, + so maintaining this order is crucial for Geyser to load. + */ + BlockRegistries.load(); + Registries.load(); + BlockRegistries.populate(); + Registries.populate(); RegistryCache.init(); diff --git a/core/src/main/java/org/geysermc/geyser/registry/BlockRegistries.java b/core/src/main/java/org/geysermc/geyser/registry/BlockRegistries.java index 2f15094ef..8cf11979f 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/BlockRegistries.java +++ b/core/src/main/java/org/geysermc/geyser/registry/BlockRegistries.java @@ -69,7 +69,7 @@ public class BlockRegistries { /** * A mapped registry containing which holds block IDs to its {@link BlockCollision}. */ - public static final ListRegistry COLLISIONS; + public static final ListRegistry COLLISIONS = ListRegistry.create(Pair.of("org.geysermc.geyser.translator.collision.CollisionRemapper", "mappings/collisions.nbt"), CollisionRegistryLoader::new); /** * A registry which stores Java IDs to {@link Block}, containing miscellaneous information about @@ -130,22 +130,36 @@ public class BlockRegistries { */ public static final SimpleMappedRegistry CUSTOM_SKULLS = SimpleMappedRegistry.create(RegistryLoaders.empty(Object2ObjectOpenHashMap::new)); - static { + public static void load() { + BLOCKS.load(); + BLOCK_STATES.load(); + // collisions are loaded later, because they are initialized later + JAVA_BLOCKS.load(); + JAVA_IDENTIFIER_TO_ID.load(); + WATERLOGGED.load(); + INTERACTIVE.load(); + INTERACTIVE_MAY_BUILD.load(); + CUSTOM_BLOCKS.load(); + CUSTOM_BLOCK_STATE_OVERRIDES.load(); + NON_VANILLA_BLOCK_STATE_OVERRIDES.load(); + CUSTOM_BLOCK_ITEM_OVERRIDES.load(); + EXTENDED_COLLISION_BOXES.load(); + CUSTOM_SKULLS.load(); + + COLLISIONS.load(); + } + + public static void populate() { Blocks.VAULT.javaId(); // FIXME CustomSkullRegistryPopulator.populate(); BlockRegistryPopulator.populate(BlockRegistryPopulator.Stage.PRE_INIT); CustomBlockRegistryPopulator.populate(CustomBlockRegistryPopulator.Stage.DEFINITION); CustomBlockRegistryPopulator.populate(CustomBlockRegistryPopulator.Stage.NON_VANILLA_REGISTRATION); BlockRegistryPopulator.populate(BlockRegistryPopulator.Stage.INIT_JAVA); - COLLISIONS = ListRegistry.create(Pair.of("org.geysermc.geyser.translator.collision.CollisionRemapper", "mappings/collisions.nbt"), CollisionRegistryLoader::new); CustomBlockRegistryPopulator.populate(CustomBlockRegistryPopulator.Stage.VANILLA_REGISTRATION); CustomBlockRegistryPopulator.populate(CustomBlockRegistryPopulator.Stage.CUSTOM_REGISTRATION); BlockRegistryPopulator.populate(BlockRegistryPopulator.Stage.INIT_BEDROCK); BlockRegistryPopulator.populate(BlockRegistryPopulator.Stage.POST_INIT); } - public static void init() { - // no-op - } - -} \ No newline at end of file +} diff --git a/core/src/main/java/org/geysermc/geyser/registry/Registries.java b/core/src/main/java/org/geysermc/geyser/registry/Registries.java index e9ff837ab..b86ea3bbf 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/Registries.java +++ b/core/src/main/java/org/geysermc/geyser/registry/Registries.java @@ -62,7 +62,7 @@ import java.util.*; * Holds all the common registries in Geyser. */ public final class Registries { - private static boolean initialized = false; + private static boolean loaded = false; /** * A registry holding all the providers. @@ -167,9 +167,9 @@ public final class Registries { */ public static final SimpleMappedRegistry> SOUND_TRANSLATORS = SimpleMappedRegistry.create("org.geysermc.geyser.translator.sound.SoundTranslator", SoundTranslatorRegistryLoader::new); - public static void init() { - if (initialized) return; - initialized = true; + public static void load() { + if (loaded) return; + loaded = true; PROVIDERS.load(); BEDROCK_ENTITY_IDENTIFIERS.load(); @@ -191,7 +191,9 @@ public final class Registries { SOUNDS.load(); SOUND_LEVEL_EVENTS.load(); SOUND_TRANSLATORS.load(); + } + public static void populate() { PacketRegistryPopulator.populate(); ItemRegistryPopulator.populate(); From 3f60db1483b8b48d00bc94b77afad0b79ad84dd9 Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Mon, 28 Oct 2024 01:38:45 -0400 Subject: [PATCH 07/10] Fix collision registry loading --- .../java/org/geysermc/geyser/registry/BlockRegistries.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/core/src/main/java/org/geysermc/geyser/registry/BlockRegistries.java b/core/src/main/java/org/geysermc/geyser/registry/BlockRegistries.java index 8cf11979f..b7c5e2d07 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/BlockRegistries.java +++ b/core/src/main/java/org/geysermc/geyser/registry/BlockRegistries.java @@ -145,8 +145,6 @@ public class BlockRegistries { CUSTOM_BLOCK_ITEM_OVERRIDES.load(); EXTENDED_COLLISION_BOXES.load(); CUSTOM_SKULLS.load(); - - COLLISIONS.load(); } public static void populate() { @@ -156,6 +154,7 @@ public class BlockRegistries { CustomBlockRegistryPopulator.populate(CustomBlockRegistryPopulator.Stage.DEFINITION); CustomBlockRegistryPopulator.populate(CustomBlockRegistryPopulator.Stage.NON_VANILLA_REGISTRATION); BlockRegistryPopulator.populate(BlockRegistryPopulator.Stage.INIT_JAVA); + COLLISIONS.load(); CustomBlockRegistryPopulator.populate(CustomBlockRegistryPopulator.Stage.VANILLA_REGISTRATION); CustomBlockRegistryPopulator.populate(CustomBlockRegistryPopulator.Stage.CUSTOM_REGISTRATION); BlockRegistryPopulator.populate(BlockRegistryPopulator.Stage.INIT_BEDROCK); From 74b25ea3a5f5e1e4ad45805140553b4c539837ee Mon Sep 17 00:00:00 2001 From: Tim203 Date: Wed, 30 Oct 2024 10:41:00 +0100 Subject: [PATCH 08/10] Use deferred where needed instead of a load method on all registries (#5112) * Use deferred where needed instead of a load method on all registries * We don't have to load the registries, they're now safe to use for tests * Renamed the deferred registries --- .../java/org/geysermc/geyser/GeyserImpl.java | 1 - .../AbstractMappedDeferredRegistry.java | 103 +++++++++++ .../geyser/registry/BlockRegistries.java | 20 +- .../geyser/registry/DeferredRegistry.java | 72 ++----- .../geyser/registry/ListDeferredRegistry.java | 175 ++++++++++++++++++ .../geyser/registry/ListRegistry.java | 12 ++ .../geysermc/geyser/registry/Registries.java | 55 +++--- .../geysermc/geyser/registry/Registry.java | 15 +- .../registry/SimpleDeferredRegistry.java | 119 ++++++++++++ .../SimpleMappedDeferredRegistry.java | 120 ++++++++++++ .../registry/VersionedDeferredRegistry.java | 114 ++++++++++++ .../registry/loader/RegistryLoaderHolder.java | 33 ---- .../network/util/GeyserMockContext.java | 6 - 13 files changed, 689 insertions(+), 156 deletions(-) create mode 100644 core/src/main/java/org/geysermc/geyser/registry/AbstractMappedDeferredRegistry.java create mode 100644 core/src/main/java/org/geysermc/geyser/registry/ListDeferredRegistry.java create mode 100644 core/src/main/java/org/geysermc/geyser/registry/SimpleDeferredRegistry.java create mode 100644 core/src/main/java/org/geysermc/geyser/registry/SimpleMappedDeferredRegistry.java create mode 100644 core/src/main/java/org/geysermc/geyser/registry/VersionedDeferredRegistry.java delete mode 100644 core/src/main/java/org/geysermc/geyser/registry/loader/RegistryLoaderHolder.java diff --git a/core/src/main/java/org/geysermc/geyser/GeyserImpl.java b/core/src/main/java/org/geysermc/geyser/GeyserImpl.java index f679b412c..0a8222f8d 100644 --- a/core/src/main/java/org/geysermc/geyser/GeyserImpl.java +++ b/core/src/main/java/org/geysermc/geyser/GeyserImpl.java @@ -236,7 +236,6 @@ public class GeyserImpl implements GeyserApi, EventRegistrar { Both the block registries and the common registries depend on each other, so maintaining this order is crucial for Geyser to load. */ - BlockRegistries.load(); Registries.load(); BlockRegistries.populate(); Registries.populate(); diff --git a/core/src/main/java/org/geysermc/geyser/registry/AbstractMappedDeferredRegistry.java b/core/src/main/java/org/geysermc/geyser/registry/AbstractMappedDeferredRegistry.java new file mode 100644 index 000000000..2506bb873 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/registry/AbstractMappedDeferredRegistry.java @@ -0,0 +1,103 @@ +/* + * 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.registry; + +import org.checkerframework.checker.nullness.qual.Nullable; +import org.geysermc.geyser.registry.loader.RegistryLoader; + +import java.util.Map; +import java.util.Optional; +import java.util.function.Function; +import java.util.function.Supplier; + +public abstract class AbstractMappedDeferredRegistry, R extends AbstractMappedRegistry> extends DeferredRegistry { + protected AbstractMappedDeferredRegistry(Function, R> registryLoader, RegistryLoader deferredLoader) { + super(registryLoader, deferredLoader); + } + + protected AbstractMappedDeferredRegistry(Function, R> registryLoader, Supplier> deferredLoader) { + super(registryLoader, deferredLoader); + } + + protected AbstractMappedDeferredRegistry(I input, RegistryInitializer registryInitializer, RegistryLoader deferredLoader) { + super(input, registryInitializer, deferredLoader); + } + + protected AbstractMappedDeferredRegistry(I input, RegistryInitializer registryInitializer, Supplier> deferredLoader) { + super(input, registryInitializer, deferredLoader); + } + + /** + * Returns the value registered by the given key. + * + * @param key the key + * @return the value registered by the given key. + */ + public @Nullable V get(K key) { + return get().get(key); + } + + /** + * Returns and maps the value by the given key if present. + * + * @param key the key + * @param mapper the mapper + * @param the type + * @return the mapped value from the given key if present + */ + public Optional map(K key, Function mapper) { + V value = this.get(key); + if (value == null) { + return Optional.empty(); + } else { + return Optional.ofNullable(mapper.apply(value)); + } + } + + /** + * Returns the value registered by the given key or the default value + * specified if null. + * + * @param key the key + * @param defaultValue the default value + * @return the value registered by the given key or the default value + * specified if null. + */ + public V getOrDefault(K key, V defaultValue) { + return get().getOrDefault(key, defaultValue); + } + + /** + * Registers a new value into this registry with the given key. + * + * @param key the key + * @param value the value + * @return a new value into this registry with the given key. + */ + public V register(K key, V value) { + return get().put(key, value); + } +} diff --git a/core/src/main/java/org/geysermc/geyser/registry/BlockRegistries.java b/core/src/main/java/org/geysermc/geyser/registry/BlockRegistries.java index b7c5e2d07..521d67542 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/BlockRegistries.java +++ b/core/src/main/java/org/geysermc/geyser/registry/BlockRegistries.java @@ -69,7 +69,7 @@ public class BlockRegistries { /** * A mapped registry containing which holds block IDs to its {@link BlockCollision}. */ - public static final ListRegistry COLLISIONS = ListRegistry.create(Pair.of("org.geysermc.geyser.translator.collision.CollisionRemapper", "mappings/collisions.nbt"), CollisionRegistryLoader::new); + public static final ListDeferredRegistry COLLISIONS = ListDeferredRegistry.create(Pair.of("org.geysermc.geyser.translator.collision.CollisionRemapper", "mappings/collisions.nbt"), CollisionRegistryLoader::new); /** * A registry which stores Java IDs to {@link Block}, containing miscellaneous information about @@ -130,23 +130,6 @@ public class BlockRegistries { */ public static final SimpleMappedRegistry CUSTOM_SKULLS = SimpleMappedRegistry.create(RegistryLoaders.empty(Object2ObjectOpenHashMap::new)); - public static void load() { - BLOCKS.load(); - BLOCK_STATES.load(); - // collisions are loaded later, because they are initialized later - JAVA_BLOCKS.load(); - JAVA_IDENTIFIER_TO_ID.load(); - WATERLOGGED.load(); - INTERACTIVE.load(); - INTERACTIVE_MAY_BUILD.load(); - CUSTOM_BLOCKS.load(); - CUSTOM_BLOCK_STATE_OVERRIDES.load(); - NON_VANILLA_BLOCK_STATE_OVERRIDES.load(); - CUSTOM_BLOCK_ITEM_OVERRIDES.load(); - EXTENDED_COLLISION_BOXES.load(); - CUSTOM_SKULLS.load(); - } - public static void populate() { Blocks.VAULT.javaId(); // FIXME CustomSkullRegistryPopulator.populate(); @@ -160,5 +143,4 @@ public class BlockRegistries { BlockRegistryPopulator.populate(BlockRegistryPopulator.Stage.INIT_BEDROCK); BlockRegistryPopulator.populate(BlockRegistryPopulator.Stage.POST_INIT); } - } diff --git a/core/src/main/java/org/geysermc/geyser/registry/DeferredRegistry.java b/core/src/main/java/org/geysermc/geyser/registry/DeferredRegistry.java index ce77261ae..f4273edea 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/DeferredRegistry.java +++ b/core/src/main/java/org/geysermc/geyser/registry/DeferredRegistry.java @@ -43,32 +43,36 @@ import java.util.function.Supplier; * * @param the value being held by the registry */ -public final class DeferredRegistry implements IRegistry { - private final Registry backingRegistry; +class DeferredRegistry> implements IRegistry { + private final R backingRegistry; private final Supplier loader; private boolean loaded; - private DeferredRegistry(Function, Registry> registryLoader, RegistryLoader deferredLoader) { + protected DeferredRegistry(Function, R> registryLoader, RegistryLoader deferredLoader) { this.backingRegistry = registryLoader.apply(RegistryLoaders.uninitialized()); this.loader = () -> deferredLoader.load(null); } - private DeferredRegistry(Function, Registry> registryLoader, Supplier> deferredLoader) { + protected DeferredRegistry(Function, R> registryLoader, Supplier> deferredLoader) { this.backingRegistry = registryLoader.apply(RegistryLoaders.uninitialized()); this.loader = () -> deferredLoader.get().load(null); } - private DeferredRegistry(I input, RegistryInitializer registryInitializer, RegistryLoader deferredLoader) { + protected DeferredRegistry(I input, RegistryInitializer registryInitializer, RegistryLoader deferredLoader) { this.backingRegistry = registryInitializer.initialize(input, RegistryLoaders.uninitialized()); this.loader = () -> deferredLoader.load(input); } - private DeferredRegistry(I input, RegistryInitializer registryInitializer, Supplier> deferredLoader) { + protected DeferredRegistry(I input, RegistryInitializer registryInitializer, Supplier> deferredLoader) { this.backingRegistry = registryInitializer.initialize(input, RegistryLoaders.uninitialized()); this.loader = () -> deferredLoader.get().load(input); } + protected R backingRegistry() { + return this.backingRegistry; + } + /** * Gets the underlying value held by this registry. * @@ -119,64 +123,12 @@ public final class DeferredRegistry implements IRegistry { return this.loaded; } - /** - * Creates a new deferred registry. - * - * @param registryLoader the registry loader - * @param deferredLoader the deferred loader - * @param the input type - * @param the registry type - * @return the new deferred registry - */ - public static DeferredRegistry create(Function, Registry> registryLoader, RegistryLoader deferredLoader) { - return new DeferredRegistry<>(registryLoader, deferredLoader); - } - - /** - * Creates a new deferred registry. - * - * @param registryLoader the registry loader - * @param deferredLoader the deferred loader - * @param the input type - * @param the registry type - * @return the new deferred registry - */ - public static DeferredRegistry create(Function, Registry> registryLoader, Supplier> deferredLoader) { - return new DeferredRegistry<>(registryLoader, deferredLoader); - } - - /** - * Creates a new deferred registry. - * - * @param registryInitializer the registry initializer - * @param deferredLoader the deferred loader - * @param the input type - * @param the registry type - * @return the new deferred registry - */ - public static DeferredRegistry create(I input, RegistryInitializer registryInitializer, RegistryLoader deferredLoader) { - return new DeferredRegistry<>(input, registryInitializer, deferredLoader); - } - - /** - * Creates a new deferred registry. - * - * @param registryInitializer the registry initializer - * @param deferredLoader the deferred loader - * @param the input type - * @param the registry type - * @return the new deferred registry - */ - public static DeferredRegistry create(I input, RegistryInitializer registryInitializer, Supplier> deferredLoader) { - return new DeferredRegistry<>(input, registryInitializer, deferredLoader); - } - /** * A registry initializer. * * @param the registry type */ - interface RegistryInitializer { + public interface RegistryInitializer> { /** * Initializes the registry. @@ -186,6 +138,6 @@ public final class DeferredRegistry implements IRegistry { * @param the input type * @return the initialized registry */ - Registry initialize(I input, RegistryLoader registryLoader); + R initialize(I input, RegistryLoader registryLoader); } } diff --git a/core/src/main/java/org/geysermc/geyser/registry/ListDeferredRegistry.java b/core/src/main/java/org/geysermc/geyser/registry/ListDeferredRegistry.java new file mode 100644 index 000000000..91dc74eb7 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/registry/ListDeferredRegistry.java @@ -0,0 +1,175 @@ +/* + * 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.registry; + +import org.checkerframework.checker.nullness.qual.Nullable; +import org.geysermc.geyser.registry.loader.RegistryLoader; + +import java.util.List; +import java.util.function.Function; +import java.util.function.Supplier; + +public class ListDeferredRegistry extends DeferredRegistry, ListRegistry> { + protected ListDeferredRegistry(Function>, ListRegistry> registryLoader, RegistryLoader> deferredLoader) { + super(registryLoader, deferredLoader); + } + + protected ListDeferredRegistry(Function>, ListRegistry> registryLoader, Supplier>> deferredLoader) { + super(registryLoader, deferredLoader); + } + + protected ListDeferredRegistry(I input, RegistryInitializer, ListRegistry> registryInitializer, RegistryLoader> deferredLoader) { + super(input, registryInitializer, deferredLoader); + } + + protected ListDeferredRegistry(I input, RegistryInitializer, ListRegistry> registryInitializer, Supplier>> deferredLoader) { + super(input, registryInitializer, deferredLoader); + } + /** + * Returns the value registered by the given index. + * + * @param index the index + * @return the value registered by the given index. + */ + @Nullable + public V get(int index) { + return backingRegistry().get(index); + } + + /** + * Returns the value registered by the given index or the default value + * specified if null. + * + * @param index the index + * @param defaultValue the default value + * @return the value registered by the given key or the default value + * specified if null. + */ + public V getOrDefault(int index, V defaultValue) { + return backingRegistry().getOrDefault(index, defaultValue); + } + + /** + * Registers a new value into this registry with the given index. + * + * @param index the index + * @param value the value + * @return a new value into this registry with the given index. + */ + public V register(int index, V value) { + return backingRegistry().register(index, value); + } + + /** + * Registers a new value into this registry with the given index, even if this value would normally be outside + * the range of a list. + * + * @param index the index + * @param value the value + * @param defaultValue the default value to fill empty spaces in the registry with. + * @return a new value into this registry with the given index. + */ + public V registerWithAnyIndex(int index, V value, V defaultValue) { + return backingRegistry().registerWithAnyIndex(index, value, defaultValue); + } + + /** + * Mark this registry as unsuitable for new additions. The backing list will then be optimized for storage. + */ + public void freeze() { + backingRegistry().freeze(); + } + + /** + * Creates a new deferred registry. + * + * @param registryLoader the registry loader + * @param deferredLoader the deferred loader + * @param the input type + * @return the new deferred registry + */ + public static ListDeferredRegistry create(Function>, ListRegistry> registryLoader, RegistryLoader> deferredLoader) { + return new ListDeferredRegistry<>(registryLoader, deferredLoader); + } + + /** + * Creates a new deferred registry. + * + * @param registryLoader the registry loader + * @param deferredLoader the deferred loader + * @param the input type + * @return the new deferred registry + */ + public static ListDeferredRegistry create(Function>, ListRegistry> registryLoader, Supplier>> deferredLoader) { + return new ListDeferredRegistry<>(registryLoader, deferredLoader); + } + + /** + * Creates a new deferred registry. + * + * @param registryInitializer the registry initializer + * @param deferredLoader the deferred loader + * @param the input type + * @return the new deferred registry + */ + public static ListDeferredRegistry create(I input, RegistryInitializer, ListRegistry> registryInitializer, RegistryLoader> deferredLoader) { + return new ListDeferredRegistry<>(input, registryInitializer, deferredLoader); + } + + /** + * Creates a new deferred registry. + * + * @param registryInitializer the registry initializer + * @param deferredLoader the deferred loader + * @param the input type + * @return the new deferred registry + */ + public static ListDeferredRegistry create(I input, RegistryInitializer, ListRegistry> registryInitializer, Supplier>> deferredLoader) { + return new ListDeferredRegistry<>(input, registryInitializer, deferredLoader); + } + + /** + * Creates a new deferred registry. + * + * @param deferredLoader the deferred loader + * @param the input type + * @return the new deferred registry + */ + public static ListDeferredRegistry create(I input, RegistryLoader> deferredLoader) { + return create(input, ListRegistry::create, deferredLoader); + } + + /** + * Creates a new deferred registry. + * + * @param deferredLoader the deferred loader + * @param the input type + * @return the new deferred registry + */ + public static ListDeferredRegistry create(I input, Supplier>> deferredLoader) { + return create(input, ListRegistry::create, deferredLoader); + } +} diff --git a/core/src/main/java/org/geysermc/geyser/registry/ListRegistry.java b/core/src/main/java/org/geysermc/geyser/registry/ListRegistry.java index 2070d67ae..d1d3d7af0 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/ListRegistry.java +++ b/core/src/main/java/org/geysermc/geyser/registry/ListRegistry.java @@ -140,6 +140,18 @@ public class ListRegistry extends Registry> { return new ListRegistry<>(null, registryLoader); } + /** + * Creates a new integer mapped registry with the given {@link RegistryLoader} and input. + * + * @param registryLoader the registry loader + * @param the input + * @param the type value + * @return a new registry with the given RegistryLoader + */ + public static ListRegistry create(I input, RegistryLoader> registryLoader) { + return new ListRegistry<>(input, registryLoader); + } + /** * Creates a new integer mapped registry with the given {@link RegistryLoader} and input. * diff --git a/core/src/main/java/org/geysermc/geyser/registry/Registries.java b/core/src/main/java/org/geysermc/geyser/registry/Registries.java index b86ea3bbf..0d286d5c3 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/Registries.java +++ b/core/src/main/java/org/geysermc/geyser/registry/Registries.java @@ -37,10 +37,18 @@ import org.geysermc.geyser.api.pack.ResourcePack; import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.inventory.recipe.GeyserRecipe; import org.geysermc.geyser.item.type.Item; -import org.geysermc.geyser.registry.loader.*; +import org.geysermc.geyser.registry.loader.BiomeIdentifierRegistryLoader; +import org.geysermc.geyser.registry.loader.BlockEntityRegistryLoader; +import org.geysermc.geyser.registry.loader.ParticleTypesRegistryLoader; +import org.geysermc.geyser.registry.loader.PotionMixRegistryLoader; +import org.geysermc.geyser.registry.loader.ProviderRegistryLoader; +import org.geysermc.geyser.registry.loader.RecipeRegistryLoader; +import org.geysermc.geyser.registry.loader.RegistryLoaders; +import org.geysermc.geyser.registry.loader.SoundEventsRegistryLoader; +import org.geysermc.geyser.registry.loader.SoundRegistryLoader; +import org.geysermc.geyser.registry.loader.SoundTranslatorRegistryLoader; import org.geysermc.geyser.registry.populator.ItemRegistryPopulator; import org.geysermc.geyser.registry.populator.PacketRegistryPopulator; -import org.geysermc.geyser.registry.loader.RecipeRegistryLoader; import org.geysermc.geyser.registry.provider.ProviderSupplier; import org.geysermc.geyser.registry.type.ItemMappings; import org.geysermc.geyser.registry.type.ParticleMapping; @@ -56,7 +64,13 @@ import org.geysermc.mcprotocollib.protocol.data.game.level.event.LevelEvent; import org.geysermc.mcprotocollib.protocol.data.game.level.particle.ParticleType; import org.geysermc.mcprotocollib.protocol.data.game.recipe.RecipeType; -import java.util.*; +import java.util.ArrayList; +import java.util.EnumMap; +import java.util.HashSet; +import java.util.IdentityHashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; /** * Holds all the common registries in Geyser. @@ -73,7 +87,7 @@ public final class Registries { /** * A registry holding a NbtMap of the known entity identifiers. */ - public static final SimpleRegistry BEDROCK_ENTITY_IDENTIFIERS = SimpleRegistry.create("bedrock/entity_identifiers.dat", RegistryLoaders.NBT); + public static final SimpleDeferredRegistry BEDROCK_ENTITY_IDENTIFIERS = SimpleDeferredRegistry.create("bedrock/entity_identifiers.dat", RegistryLoaders.NBT); /** * A registry containing all the Bedrock packet translators. @@ -83,17 +97,17 @@ public final class Registries { /** * A registry holding a NbtMap of all the known biomes. */ - public static final SimpleRegistry BIOMES_NBT = SimpleRegistry.create("bedrock/biome_definitions.dat", RegistryLoaders.NBT); + public static final SimpleDeferredRegistry BIOMES_NBT = SimpleDeferredRegistry.create("bedrock/biome_definitions.dat", RegistryLoaders.NBT); /** * A mapped registry which stores Java biome identifiers and their Bedrock biome identifier. */ - public static final SimpleRegistry> BIOME_IDENTIFIERS = SimpleRegistry.create("mappings/biomes.json", BiomeIdentifierRegistryLoader::new); + public static final SimpleDeferredRegistry> BIOME_IDENTIFIERS = SimpleDeferredRegistry.create("mappings/biomes.json", BiomeIdentifierRegistryLoader::new); /** * A mapped registry which stores a block entity identifier to its {@link BlockEntityTranslator}. */ - public static final SimpleMappedRegistry BLOCK_ENTITIES = SimpleMappedRegistry.create("org.geysermc.geyser.translator.level.block.entity.BlockEntity", BlockEntityRegistryLoader::new); + public static final SimpleMappedDeferredRegistry BLOCK_ENTITIES = SimpleMappedDeferredRegistry.create("org.geysermc.geyser.translator.level.block.entity.BlockEntity", BlockEntityRegistryLoader::new); /** * A map containing all entity types and their respective Geyser definitions @@ -135,55 +149,50 @@ public final class Registries { * A mapped registry holding the {@link ParticleType} to a corresponding {@link ParticleMapping}, containing various pieces of * data primarily for how Bedrock should handle the particle. */ - public static final SimpleMappedRegistry PARTICLES = SimpleMappedRegistry.create("mappings/particles.json", ParticleTypesRegistryLoader::new); + public static final SimpleMappedDeferredRegistry PARTICLES = SimpleMappedDeferredRegistry.create("mappings/particles.json", ParticleTypesRegistryLoader::new); /** * A registry holding all the potion mixes. */ - public static final VersionedRegistry> POTION_MIXES = VersionedRegistry.create(PotionMixRegistryLoader::new); + public static final VersionedDeferredRegistry> POTION_MIXES = VersionedDeferredRegistry.create(VersionedRegistry::create, PotionMixRegistryLoader::new); /** * A versioned registry holding all the recipes, with the net ID being the key, and {@link GeyserRecipe} as the value. */ - public static final SimpleMappedRegistry> RECIPES = SimpleMappedRegistry.create("mappings/recipes.nbt", RecipeRegistryLoader::new); + public static final SimpleMappedDeferredRegistry> RECIPES = SimpleMappedDeferredRegistry.create("mappings/recipes.nbt", RecipeRegistryLoader::new); /** * A mapped registry holding {@link ResourcePack}'s with the pack uuid as keys. */ - public static final DeferredRegistry> RESOURCE_PACKS = DeferredRegistry.create(GeyserImpl.getInstance().packDirectory(), SimpleMappedRegistry::create, RegistryLoaders.RESOURCE_PACKS); + public static final SimpleMappedDeferredRegistry RESOURCE_PACKS = SimpleMappedDeferredRegistry.create(GeyserImpl.getInstance().packDirectory(), RegistryLoaders.RESOURCE_PACKS); /** * A mapped registry holding sound identifiers to their corresponding {@link SoundMapping}. */ - public static final SimpleMappedRegistry SOUNDS = SimpleMappedRegistry.create("mappings/sounds.json", SoundRegistryLoader::new); + public static final SimpleMappedDeferredRegistry SOUNDS = SimpleMappedDeferredRegistry.create("mappings/sounds.json", SoundRegistryLoader::new); /** * A mapped registry holding {@link LevelEvent}s to their corresponding {@link LevelEventTranslator}. */ - public static final SimpleMappedRegistry SOUND_LEVEL_EVENTS = SimpleMappedRegistry.create("mappings/effects.json", SoundEventsRegistryLoader::new); + public static final SimpleMappedDeferredRegistry SOUND_LEVEL_EVENTS = SimpleMappedDeferredRegistry.create("mappings/effects.json", SoundEventsRegistryLoader::new); /** * A mapped registry holding {@link SoundTranslator}s to their corresponding {@link SoundInteractionTranslator}. */ - public static final SimpleMappedRegistry> SOUND_TRANSLATORS = SimpleMappedRegistry.create("org.geysermc.geyser.translator.sound.SoundTranslator", SoundTranslatorRegistryLoader::new); + public static final SimpleMappedDeferredRegistry> SOUND_TRANSLATORS = SimpleMappedDeferredRegistry.create("org.geysermc.geyser.translator.sound.SoundTranslator", SoundTranslatorRegistryLoader::new); public static void load() { if (loaded) return; loaded = true; - PROVIDERS.load(); + // the following registries are registries that are more complicated than initializing as an empty collection. + // They generally have in common that they either depend on loading a resource file directly or indirectly + // (by using the Items or Blocks class, which loads all the blocks) + BEDROCK_ENTITY_IDENTIFIERS.load(); - BEDROCK_PACKET_TRANSLATORS.load(); BIOMES_NBT.load(); BIOME_IDENTIFIERS.load(); BLOCK_ENTITIES.load(); - ENTITY_DEFINITIONS.load(); - BEDROCK_ENTITY_PROPERTIES.load(); - JAVA_ENTITY_IDENTIFIERS.load(); - JAVA_PACKET_TRANSLATORS.load(); - JAVA_ITEMS.load(); - JAVA_ITEM_IDENTIFIERS.load(); - ITEMS.load(); PARTICLES.load(); // load potion mixes later RECIPES.load(); diff --git a/core/src/main/java/org/geysermc/geyser/registry/Registry.java b/core/src/main/java/org/geysermc/geyser/registry/Registry.java index 4e83a3c2e..8a82af053 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/Registry.java +++ b/core/src/main/java/org/geysermc/geyser/registry/Registry.java @@ -27,7 +27,6 @@ package org.geysermc.geyser.registry; import java.util.function.Consumer; import org.geysermc.geyser.registry.loader.RegistryLoader; -import org.geysermc.geyser.registry.loader.RegistryLoaderHolder; /** * A wrapper around a value which is loaded based on the output from the provided @@ -63,9 +62,7 @@ import org.geysermc.geyser.registry.loader.RegistryLoaderHolder; * * @param the value being held by the registry */ -@SuppressWarnings("rawtypes") public abstract class Registry implements IRegistry { - protected RegistryLoaderHolder loaderHolder; protected M mappings; /** @@ -78,17 +75,7 @@ public abstract class Registry implements IRegistry { * @param the input type */ protected Registry(I input, RegistryLoader registryLoader) { - this.loaderHolder = new RegistryLoaderHolder<>(input, registryLoader); - } - - public void load() { - // don't load twice - if (this.mappings != null) return; - - var holder = this.loaderHolder; - this.loaderHolder = null; - //noinspection unchecked - this.mappings = (M) holder.registryLoader().load(holder.input()); + this.mappings = registryLoader.load(input); } /** diff --git a/core/src/main/java/org/geysermc/geyser/registry/SimpleDeferredRegistry.java b/core/src/main/java/org/geysermc/geyser/registry/SimpleDeferredRegistry.java new file mode 100644 index 000000000..cdbd985be --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/registry/SimpleDeferredRegistry.java @@ -0,0 +1,119 @@ +/* + * 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.registry; + +import org.geysermc.geyser.registry.loader.RegistryLoader; + +import java.util.function.Function; +import java.util.function.Supplier; + +public class SimpleDeferredRegistry extends DeferredRegistry> { + protected SimpleDeferredRegistry(Function, SimpleRegistry> registryLoader, RegistryLoader deferredLoader) { + super(registryLoader, deferredLoader); + } + + protected SimpleDeferredRegistry(Function, SimpleRegistry> registryLoader, Supplier> deferredLoader) { + super(registryLoader, deferredLoader); + } + + protected SimpleDeferredRegistry(I input, RegistryInitializer> registryInitializer, RegistryLoader deferredLoader) { + super(input, registryInitializer, deferredLoader); + } + + protected SimpleDeferredRegistry(I input, RegistryInitializer> registryInitializer, Supplier> deferredLoader) { + super(input, registryInitializer, deferredLoader); + } + + /** + * Creates a new deferred registry. + * + * @param registryLoader the registry loader + * @param deferredLoader the deferred loader + * @param the input type + * @return the new deferred registry + */ + public static SimpleDeferredRegistry create(Function, SimpleRegistry> registryLoader, RegistryLoader deferredLoader) { + return new SimpleDeferredRegistry<>(registryLoader, deferredLoader); + } + + /** + * Creates a new deferred registry. + * + * @param registryLoader the registry loader + * @param deferredLoader the deferred loader + * @param the input type + * @return the new deferred registry + */ + public static SimpleDeferredRegistry create(Function, SimpleRegistry> registryLoader, Supplier> deferredLoader) { + return new SimpleDeferredRegistry<>(registryLoader, deferredLoader); + } + + /** + * Creates a new deferred registry. + * + * @param registryInitializer the registry initializer + * @param deferredLoader the deferred loader + * @param the input type + * @return the new deferred registry + */ + public static SimpleDeferredRegistry create(I input, RegistryInitializer> registryInitializer, RegistryLoader deferredLoader) { + return new SimpleDeferredRegistry<>(input, registryInitializer, deferredLoader); + } + + /** + * Creates a new deferred registry. + * + * @param registryInitializer the registry initializer + * @param deferredLoader the deferred loader + * @param the input type + * @return the new deferred registry + */ + public static SimpleDeferredRegistry create(I input, RegistryInitializer> registryInitializer, Supplier> deferredLoader) { + return new SimpleDeferredRegistry<>(input, registryInitializer, deferredLoader); + } + + /** + * Creates a new deferred registry. + * + * @param deferredLoader the deferred loader + * @param the input type + * @return the new deferred registry + */ + public static SimpleDeferredRegistry create(I input, RegistryLoader deferredLoader) { + return create(input, SimpleRegistry::create, deferredLoader); + } + + /** + * Creates a new deferred registry. + * + * @param deferredLoader the deferred loader + * @param the input type + * @return the new deferred registry + */ + public static SimpleDeferredRegistry create(I input, Supplier> deferredLoader) { + return create(input, SimpleRegistry::create, deferredLoader); + } +} diff --git a/core/src/main/java/org/geysermc/geyser/registry/SimpleMappedDeferredRegistry.java b/core/src/main/java/org/geysermc/geyser/registry/SimpleMappedDeferredRegistry.java new file mode 100644 index 000000000..6a837c9e0 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/registry/SimpleMappedDeferredRegistry.java @@ -0,0 +1,120 @@ +/* + * 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.registry; + +import org.geysermc.geyser.registry.loader.RegistryLoader; + +import java.util.Map; +import java.util.function.Function; +import java.util.function.Supplier; + +public class SimpleMappedDeferredRegistry extends AbstractMappedDeferredRegistry, SimpleMappedRegistry> { + protected SimpleMappedDeferredRegistry(Function>, SimpleMappedRegistry> registryLoader, RegistryLoader> deferredLoader) { + super(registryLoader, deferredLoader); + } + + protected SimpleMappedDeferredRegistry(Function>, SimpleMappedRegistry> registryLoader, Supplier>> deferredLoader) { + super(registryLoader, deferredLoader); + } + + protected SimpleMappedDeferredRegistry(I input, RegistryInitializer, SimpleMappedRegistry> registryInitializer, RegistryLoader> deferredLoader) { + super(input, registryInitializer, deferredLoader); + } + + protected SimpleMappedDeferredRegistry(I input, RegistryInitializer, SimpleMappedRegistry> registryInitializer, Supplier>> deferredLoader) { + super(input, registryInitializer, deferredLoader); + } + + /** + * Creates a new deferred registry. + * + * @param registryLoader the registry loader + * @param deferredLoader the deferred loader + * @param the input type + * @return the new deferred registry + */ + public static SimpleMappedDeferredRegistry create(Function>, SimpleMappedRegistry> registryLoader, RegistryLoader> deferredLoader) { + return new SimpleMappedDeferredRegistry<>(registryLoader, deferredLoader); + } + + /** + * Creates a new deferred registry. + * + * @param registryLoader the registry loader + * @param deferredLoader the deferred loader + * @param the input type + * @return the new deferred registry + */ + public static SimpleMappedDeferredRegistry create(Function>, SimpleMappedRegistry> registryLoader, Supplier>> deferredLoader) { + return new SimpleMappedDeferredRegistry<>(registryLoader, deferredLoader); + } + + /** + * Creates a new deferred registry. + * + * @param registryInitializer the registry initializer + * @param deferredLoader the deferred loader + * @param the input type + * @return the new deferred registry + */ + public static SimpleMappedDeferredRegistry create(I input, DeferredRegistry.RegistryInitializer, SimpleMappedRegistry> registryInitializer, RegistryLoader> deferredLoader) { + return new SimpleMappedDeferredRegistry<>(input, registryInitializer, deferredLoader); + } + + /** + * Creates a new deferred registry. + * + * @param registryInitializer the registry initializer + * @param deferredLoader the deferred loader + * @param the input type + * @return the new deferred registry + */ + public static SimpleMappedDeferredRegistry create(I input, DeferredRegistry.RegistryInitializer, SimpleMappedRegistry> registryInitializer, Supplier>> deferredLoader) { + return new SimpleMappedDeferredRegistry<>(input, registryInitializer, deferredLoader); + } + + /** + * Creates a new deferred registry. + * + * @param deferredLoader the deferred loader + * @param the input type + * @return the new deferred registry + */ + public static SimpleMappedDeferredRegistry create(I input, RegistryLoader> deferredLoader) { + return create(input, SimpleMappedRegistry::create, deferredLoader); + } + + /** + * Creates a new deferred registry. + * + * @param deferredLoader the deferred loader + * @param the input type + * @return the new deferred registry + */ + public static SimpleMappedDeferredRegistry create(I input, Supplier>> deferredLoader) { + return create(input, SimpleMappedRegistry::create, deferredLoader); + } +} diff --git a/core/src/main/java/org/geysermc/geyser/registry/VersionedDeferredRegistry.java b/core/src/main/java/org/geysermc/geyser/registry/VersionedDeferredRegistry.java new file mode 100644 index 000000000..6b2f9906b --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/registry/VersionedDeferredRegistry.java @@ -0,0 +1,114 @@ +/* + * 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.registry; + +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; +import org.checkerframework.checker.nullness.qual.NonNull; +import org.geysermc.geyser.registry.loader.RegistryLoader; + +import java.util.function.Function; +import java.util.function.Supplier; + +public class VersionedDeferredRegistry extends AbstractMappedDeferredRegistry, VersionedRegistry> { + protected VersionedDeferredRegistry(Function>, VersionedRegistry> registryLoader, RegistryLoader> deferredLoader) { + super(registryLoader, deferredLoader); + } + + protected VersionedDeferredRegistry(Function>, VersionedRegistry> registryLoader, Supplier>> deferredLoader) { + super(registryLoader, deferredLoader); + } + + protected VersionedDeferredRegistry(I input, RegistryInitializer, VersionedRegistry> registryInitializer, RegistryLoader> deferredLoader) { + super(input, registryInitializer, deferredLoader); + } + + protected VersionedDeferredRegistry(I input, RegistryInitializer, VersionedRegistry> registryInitializer, Supplier>> deferredLoader) { + super(input, registryInitializer, deferredLoader); + } + + /** + * Gets the closest value for the specified version. Only + * returns versions higher up than the specified if one + * does not exist for the given one. Useful in the event + * that you want to get a resource which is guaranteed for + * older versions, but not on newer ones. + * + * @param version the version + * @return the closest value for the specified version + * @throws IllegalArgumentException if no values exist at or above the given version + */ + @NonNull + public V forVersion(int version) { + return backingRegistry().forVersion(version); + } + /** + * Creates a new deferred registry. + * + * @param registryLoader the registry loader + * @param deferredLoader the deferred loader + * @param the input type + * @return the new deferred registry + */ + public static VersionedDeferredRegistry create(Function>, VersionedRegistry> registryLoader, RegistryLoader> deferredLoader) { + return new VersionedDeferredRegistry<>(registryLoader, deferredLoader); + } + + /** + * Creates a new deferred registry. + * + * @param registryLoader the registry loader + * @param deferredLoader the deferred loader + * @param the input type + * @return the new deferred registry + */ + public static VersionedDeferredRegistry create(Function>, VersionedRegistry> registryLoader, Supplier>> deferredLoader) { + return new VersionedDeferredRegistry<>(registryLoader, deferredLoader); + } + + /** + * Creates a new deferred registry. + * + * @param registryInitializer the registry initializer + * @param deferredLoader the deferred loader + * @param the input type + * @return the new deferred registry + */ + public static VersionedDeferredRegistry create(I input, RegistryInitializer, VersionedRegistry> registryInitializer, RegistryLoader> deferredLoader) { + return new VersionedDeferredRegistry<>(input, registryInitializer, deferredLoader); + } + + /** + * Creates a new deferred registry. + * + * @param registryInitializer the registry initializer + * @param deferredLoader the deferred loader + * @param the input type + * @return the new deferred registry + */ + public static VersionedDeferredRegistry create(I input, RegistryInitializer, VersionedRegistry> registryInitializer, Supplier>> deferredLoader) { + return new VersionedDeferredRegistry<>(input, registryInitializer, deferredLoader); + } +} diff --git a/core/src/main/java/org/geysermc/geyser/registry/loader/RegistryLoaderHolder.java b/core/src/main/java/org/geysermc/geyser/registry/loader/RegistryLoaderHolder.java deleted file mode 100644 index 751cb4ed4..000000000 --- a/core/src/main/java/org/geysermc/geyser/registry/loader/RegistryLoaderHolder.java +++ /dev/null @@ -1,33 +0,0 @@ -/* - * 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.registry.loader; - -/** - * A holder of the constructor parameters to prevent them from automatically loading, - * and instead load them when the load method is called. - */ -public record RegistryLoaderHolder(I input, RegistryLoader registryLoader) { -} diff --git a/core/src/test/java/org/geysermc/geyser/scoreboard/network/util/GeyserMockContext.java b/core/src/test/java/org/geysermc/geyser/scoreboard/network/util/GeyserMockContext.java index 1d262d8b8..2b89867fb 100644 --- a/core/src/test/java/org/geysermc/geyser/scoreboard/network/util/GeyserMockContext.java +++ b/core/src/test/java/org/geysermc/geyser/scoreboard/network/util/GeyserMockContext.java @@ -61,12 +61,6 @@ public class GeyserMockContext { try (var geyserImplMock = mockStatic(GeyserImpl.class)) { geyserImplMock.when(GeyserImpl::getInstance).thenReturn(geyserImpl); - // Since Geyser isn't actually loaded, the Registries#init will not be called. - // This means that we manually load the registries we want to use - Registries.ENTITY_DEFINITIONS.load(); - Registries.JAVA_ENTITY_IDENTIFIERS.load(); - Registries.BEDROCK_ENTITY_PROPERTIES.load(); - geyserContext.accept(context); } } From 448c75e8f2ec330893f8669e5ab4b8d5fb7c3121 Mon Sep 17 00:00:00 2001 From: Tjorven Liebe <32434395+Tjorven-Liebe@users.noreply.github.com> Date: Wed, 30 Oct 2024 15:53:43 +0100 Subject: [PATCH 09/10] Fix pulling and placing skulls/heads from creative inventory (#5114) * fix: pulling and placing skulls/heads from creative inventory * fix: getting values of map * fix: correct submodule permalink --- .../registry/populator/Conversion685_671.java | 21 ++++---- .../registry/populator/Conversion712_685.java | 51 +++++++++---------- .../registry/populator/Conversion729_712.java | 1 + .../registry/populator/Conversion748_729.java | 48 +++++++++++++++++ .../populator/ItemRegistryPopulator.java | 10 +--- core/src/main/resources/mappings | 2 +- 6 files changed, 87 insertions(+), 46 deletions(-) create mode 100644 core/src/main/java/org/geysermc/geyser/registry/populator/Conversion748_729.java diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion685_671.java b/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion685_671.java index 0c7f540bf..c72ea64b2 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion685_671.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion685_671.java @@ -46,8 +46,7 @@ public class Conversion685_671 { static GeyserMappingItem remapItem(Item item, GeyserMappingItem mapping) { mapping = Conversion712_685.remapItem(item, mapping); - - String identifer = mapping.getBedrockIdentifier(); + String identifier = mapping.getBedrockIdentifier(); if (NEW_MUSIC_DISCS.contains(item)) { return mapping.withBedrockIdentifier("minecraft:music_disc_otherside"); @@ -59,12 +58,12 @@ public class Conversion685_671 { return mapping.withBedrockIdentifier("minecraft:glass_bottle"); } - if (!NEW_BLOCKS.contains(identifer)) { + if (!NEW_BLOCKS.contains(identifier)) { return mapping; } - if (NEW_CORAL_BLOCKS.contains(identifer)) { - switch (identifer) { + if (NEW_CORAL_BLOCKS.contains(identifier)) { + switch (identifier) { case "minecraft:tube_coral_block" -> { return mapping.withBedrockIdentifier("minecraft:coral_block").withBedrockData(0); } case "minecraft:brain_coral_block" -> { return mapping.withBedrockIdentifier("minecraft:coral_block").withBedrockData(1); } case "minecraft:bubble_coral_block" -> { return mapping.withBedrockIdentifier("minecraft:coral_block").withBedrockData(2); } @@ -78,8 +77,8 @@ public class Conversion685_671 { } } - if (NEW_DOUBLE_PLANTS.contains(identifer)) { - switch (identifer) { + if (NEW_DOUBLE_PLANTS.contains(identifier)) { + switch (identifier) { case "minecraft:sunflower" -> { return mapping.withBedrockIdentifier("minecraft:double_plant").withBedrockData(0); } case "minecraft:lilac" -> { return mapping.withBedrockIdentifier("minecraft:double_plant").withBedrockData(1); } case "minecraft:tall_grass" -> { return mapping.withBedrockIdentifier("minecraft:double_plant").withBedrockData(2); } @@ -89,8 +88,8 @@ public class Conversion685_671 { } } - if (NEW_STONE_BLOCK_SLABS.contains(identifer)) { - switch (identifer) { + if (NEW_STONE_BLOCK_SLABS.contains(identifier)) { + switch (identifier) { case "minecraft:smooth_stone_slab" -> { return mapping.withBedrockIdentifier("minecraft:stone_block_slab").withBedrockData(0); } case "minecraft:sandstone_slab" -> { return mapping.withBedrockIdentifier("minecraft:stone_block_slab").withBedrockData(1); } case "minecraft:petrified_oak_slab" -> { return mapping.withBedrockIdentifier("minecraft:stone_block_slab").withBedrockData(2); } @@ -102,8 +101,8 @@ public class Conversion685_671 { } } - if (NEW_TALLGRASSES.contains(identifer)) { - switch (identifer) { + if (NEW_TALLGRASSES.contains(identifier)) { + switch (identifier) { case "minecraft:short_grass" -> { return mapping.withBedrockIdentifier("minecraft:tallgrass").withBedrockData(1); } case "minecraft:fern" -> { return mapping.withBedrockIdentifier("minecraft:tallgrass").withBedrockData(2); } } diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion712_685.java b/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion712_685.java index db715e015..45963cb90 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion712_685.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion712_685.java @@ -33,35 +33,34 @@ public class Conversion712_685 { static GeyserMappingItem remapItem(Item item, GeyserMappingItem mapping) { mapping = Conversion729_712.remapItem(item, mapping); + String identifier = mapping.getBedrockIdentifier(); - String identifer = mapping.getBedrockIdentifier(); - - if (!NEW_BLOCKS.contains(identifer)) { + if (!NEW_BLOCKS.contains(identifier)) { return mapping; } - if (identifer.equals("minecraft:coarse_dirt")) { + if (identifier.equals("minecraft:coarse_dirt")) { return mapping.withBedrockIdentifier("minecraft:dirt").withBedrockData(1); } - if (identifer.equals("minecraft:dandelion")) { + if (identifier.equals("minecraft:dandelion")) { return mapping.withBedrockIdentifier("minecraft:yellow_flower").withBedrockData(0); } - if (identifer.equals("minecraft:red_sand")) { + if (identifier.equals("minecraft:red_sand")) { return mapping.withBedrockIdentifier("minecraft:sand").withBedrockData(1); } - if (NEW_PRISMARINE_BLOCKS.contains(identifer)) { - switch (identifer) { + if (NEW_PRISMARINE_BLOCKS.contains(identifier)) { + switch (identifier) { case "minecraft:prismarine" -> { return mapping.withBedrockIdentifier("minecraft:prismarine").withBedrockData(0); } case "minecraft:dark_prismarine" -> { return mapping.withBedrockIdentifier("minecraft:prismarine").withBedrockData(1); } case "minecraft:prismarine_bricks" -> { return mapping.withBedrockIdentifier("minecraft:prismarine").withBedrockData(2); } } } - if (NEW_SANDSTONE_BLOCKS.contains(identifer)) { - switch (identifer) { + if (NEW_SANDSTONE_BLOCKS.contains(identifier)) { + switch (identifier) { case "minecraft:sandstone" -> { return mapping.withBedrockIdentifier("minecraft:sandstone").withBedrockData(0); } case "minecraft:chiseled_sandstone" -> { return mapping.withBedrockIdentifier("minecraft:sandstone").withBedrockData(1); } case "minecraft:cut_sandstone" -> { return mapping.withBedrockIdentifier("minecraft:sandstone").withBedrockData(2); } @@ -69,8 +68,8 @@ public class Conversion712_685 { } } - if (NEW_RED_SANDSTONE_BLOCKS.contains(identifer)) { - switch (identifer) { + if (NEW_RED_SANDSTONE_BLOCKS.contains(identifier)) { + switch (identifier) { case "minecraft:red_sandstone" -> { return mapping.withBedrockIdentifier("minecraft:red_sandstone").withBedrockData(0); } case "minecraft:chiseled_red_sandstone" -> { return mapping.withBedrockIdentifier("minecraft:red_sandstone").withBedrockData(1); } case "minecraft:cut_red_sandstone" -> { return mapping.withBedrockIdentifier("minecraft:red_sandstone").withBedrockData(2); } @@ -78,8 +77,8 @@ public class Conversion712_685 { } } - if (NEW_QUARTZ_BLOCKS.contains(identifer)) { - switch (identifer) { + if (NEW_QUARTZ_BLOCKS.contains(identifier)) { + switch (identifier) { case "minecraft:quartz_block" -> { return mapping.withBedrockIdentifier("minecraft:quartz_block").withBedrockData(0); } case "minecraft:chiseled_quartz_block" -> { return mapping.withBedrockIdentifier("minecraft:quartz_block").withBedrockData(1); } case "minecraft:quartz_pillar" -> { return mapping.withBedrockIdentifier("minecraft:quartz_block").withBedrockData(2); } @@ -87,8 +86,8 @@ public class Conversion712_685 { } } - if (NEW_STONE_BLOCK_SLABS_2.contains(identifer)) { - switch (identifer) { + if (NEW_STONE_BLOCK_SLABS_2.contains(identifier)) { + switch (identifier) { case "minecraft:red_sandstone_slab" -> { return mapping.withBedrockIdentifier("minecraft:stone_block_slab2").withBedrockData(0); } case "minecraft:purpur_slab" -> { return mapping.withBedrockIdentifier("minecraft:stone_block_slab2").withBedrockData(1); } case "minecraft:prismarine_slab" -> { return mapping.withBedrockIdentifier("minecraft:stone_block_slab2").withBedrockData(2); } @@ -100,8 +99,8 @@ public class Conversion712_685 { } } - if (NEW_STONE_BLOCK_SLABS_3.contains(identifer)) { - switch (identifer) { + if (NEW_STONE_BLOCK_SLABS_3.contains(identifier)) { + switch (identifier) { case "minecraft:end_stone_brick_slab" -> { return mapping.withBedrockIdentifier("minecraft:stone_block_slab3").withBedrockData(0); } case "minecraft:smooth_red_sandstone_slab" -> { return mapping.withBedrockIdentifier("minecraft:stone_block_slab3").withBedrockData(1); } case "minecraft:polished_andesite_slab" -> { return mapping.withBedrockIdentifier("minecraft:stone_block_slab3").withBedrockData(2); } @@ -113,8 +112,8 @@ public class Conversion712_685 { } } - if (NEW_STONE_BLOCK_SLABS_4.contains(identifer)) { - switch (identifer) { + if (NEW_STONE_BLOCK_SLABS_4.contains(identifier)) { + switch (identifier) { case "minecraft:mossy_stone_brick_slab" -> { return mapping.withBedrockIdentifier("minecraft:stone_block_slab4").withBedrockData(0); } case "minecraft:smooth_quartz_slab" -> { return mapping.withBedrockIdentifier("minecraft:stone_block_slab4").withBedrockData(1); } case "minecraft:normal_stone_slab" -> { return mapping.withBedrockIdentifier("minecraft:stone_block_slab4").withBedrockData(2); } @@ -123,8 +122,8 @@ public class Conversion712_685 { } } - if (NEW_MONSTER_EGGS.contains(identifer)) { - switch (identifer) { + if (NEW_MONSTER_EGGS.contains(identifier)) { + switch (identifier) { case "minecraft:infested_stone" -> { return mapping.withBedrockIdentifier("minecraft:monster_egg").withBedrockData(0); } case "minecraft:infested_cobblestone" -> { return mapping.withBedrockIdentifier("minecraft:monster_egg").withBedrockData(1); } case "minecraft:infested_stone_bricks" -> { return mapping.withBedrockIdentifier("minecraft:monster_egg").withBedrockData(2); } @@ -134,8 +133,8 @@ public class Conversion712_685 { } } - if (NEW_STONEBRICK_BLOCKS.contains(identifer)) { - switch (identifer) { + if (NEW_STONEBRICK_BLOCKS.contains(identifier)) { + switch (identifier) { case "minecraft:stone_bricks" -> { return mapping.withBedrockIdentifier("minecraft:stonebrick").withBedrockData(0); } case "minecraft:mossy_stone_bricks" -> { return mapping.withBedrockIdentifier("minecraft:stonebrick").withBedrockData(1); } case "minecraft:cracked_stone_bricks" -> { return mapping.withBedrockIdentifier("minecraft:stonebrick").withBedrockData(2); } @@ -143,8 +142,8 @@ public class Conversion712_685 { } } - if (NEW_ANVILS.contains(identifer)) { - switch (identifer) { + if (NEW_ANVILS.contains(identifier)) { + switch (identifier) { case "minecraft:anvil" -> { return mapping.withBedrockIdentifier("minecraft:anvil").withBedrockData(0); } case "minecraft:chipped_anvil" -> { return mapping.withBedrockIdentifier("minecraft:anvil").withBedrockData(4); } case "minecraft:damaged_anvil" -> { return mapping.withBedrockIdentifier("minecraft:anvil").withBedrockData(8); } diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion729_712.java b/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion729_712.java index 5d4ebdc47..fbc2233bc 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion729_712.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion729_712.java @@ -16,6 +16,7 @@ public class Conversion729_712 { private static final List NEW_BLOCKS = Stream.of(NEW_PURPUR_BLOCKS, NEW_WALL_BLOCKS, NEW_SPONGE_BLOCKS, NEW_TNT_BLOCKS, STRUCTURE_VOID).flatMap(List::stream).toList(); static GeyserMappingItem remapItem(Item item, GeyserMappingItem mapping) { + mapping = Conversion748_729.remapItem(item, mapping); String identifier = mapping.getBedrockIdentifier(); if (!NEW_BLOCKS.contains(identifier)) { diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion748_729.java b/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion748_729.java new file mode 100644 index 000000000..7a2d1a0cb --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion748_729.java @@ -0,0 +1,48 @@ +/* + * 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.registry.populator; + +import org.geysermc.geyser.item.type.Item; +import org.geysermc.geyser.registry.type.GeyserMappingItem; + +import java.util.Map; + +public class Conversion748_729 { + + private static final Map NEW_PLAYER_HEADS = Map.of("minecraft:skeleton_skull", 0, "minecraft:wither_skeleton_skull", 1, "minecraft:zombie_head", 2, "minecraft:player_head", 3, "minecraft:creeper_head", 4, "minecraft:dragon_head", 5, "minecraft:piglin_head", 6); + + static GeyserMappingItem remapItem(Item item, GeyserMappingItem mapping) { + String identifier = mapping.getBedrockIdentifier(); + + if (NEW_PLAYER_HEADS.containsKey(identifier)) { + return mapping.withBedrockIdentifier("minecraft:skull") + .withBedrockData(NEW_PLAYER_HEADS.get(identifier)); + } + + return mapping; + } + +} diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java b/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java index 0b61c7999..65a35aa50 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/ItemRegistryPopulator.java @@ -113,14 +113,8 @@ public class ItemRegistryPopulator { paletteVersions.add(new PaletteVersion("1_20_80", Bedrock_v671.CODEC.getProtocolVersion(), Collections.emptyMap(), Conversion685_671::remapItem)); paletteVersions.add(new PaletteVersion("1_21_0", Bedrock_v685.CODEC.getProtocolVersion(), Collections.emptyMap(), Conversion712_685::remapItem)); paletteVersions.add(new PaletteVersion("1_21_20", Bedrock_v712.CODEC.getProtocolVersion(), Collections.emptyMap(), Conversion729_712::remapItem)); - paletteVersions.add(new PaletteVersion("1_21_30", Bedrock_v729.CODEC.getProtocolVersion())); - paletteVersions.add(new PaletteVersion("1_21_40", Bedrock_v748.CODEC.getProtocolVersion(), Collections.emptyMap(), (item, mapping) -> { - String identifier = item.javaIdentifier(); - if (identifier.endsWith("_head") || identifier.endsWith("_skull")) { - return mapping.withBedrockIdentifier(item.javaIdentifier()); - } - return mapping; - })); + paletteVersions.add(new PaletteVersion("1_21_30", Bedrock_v729.CODEC.getProtocolVersion(), Collections.emptyMap(), Conversion748_729::remapItem)); + paletteVersions.add(new PaletteVersion("1_21_40", Bedrock_v748.CODEC.getProtocolVersion())); GeyserBootstrap bootstrap = GeyserImpl.getInstance().getBootstrap(); diff --git a/core/src/main/resources/mappings b/core/src/main/resources/mappings index 93f207e7e..a6d04157d 160000 --- a/core/src/main/resources/mappings +++ b/core/src/main/resources/mappings @@ -1 +1 @@ -Subproject commit 93f207e7e9d73f58a7c8902f7deda9dcb0524c8e +Subproject commit a6d04157d1866e55e35f2ce3ebde3cf4e007aabf From b3e57fd4653282efbd2ed84f7bff3cb9f92273da Mon Sep 17 00:00:00 2001 From: Camotoy <20743703+Camotoy@users.noreply.github.com> Date: Wed, 30 Oct 2024 20:11:34 -0400 Subject: [PATCH 10/10] Indicate support for Bedrock 1.21.43 --- README.md | 2 +- .../main/java/org/geysermc/geyser/network/GameProtocol.java | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 3e99a96a7..fedb5bb96 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ The ultimate goal of this project is to allow Minecraft: Bedrock Edition users t Special thanks to the DragonProxy project for being a trailblazer in protocol translation and for all the team members who have joined us here! ## Supported Versions -Geyser is currently supporting Minecraft Bedrock 1.20.80 - 1.21.41 and Minecraft Java 1.21/1.21.1. For more information, please see [here](https://geysermc.org/wiki/geyser/supported-versions/). +Geyser is currently supporting Minecraft Bedrock 1.20.80 - 1.21.43 and Minecraft Java 1.21/1.21.1. For more information, please see [here](https://geysermc.org/wiki/geyser/supported-versions/). ## Setting Up Take a look [here](https://geysermc.org/wiki/geyser/setup/) for how to set up Geyser. diff --git a/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java b/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java index c39629917..464edd487 100644 --- a/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java +++ b/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java @@ -52,7 +52,7 @@ public final class GameProtocol { * release of the game that Geyser supports. */ public static final BedrockCodec DEFAULT_BEDROCK_CODEC = CodecProcessor.processCodec(Bedrock_v748.CODEC.toBuilder() - .minecraftVersion("1.21.41") + .minecraftVersion("1.21.43") .build()); /** @@ -83,7 +83,7 @@ public final class GameProtocol { .minecraftVersion("1.21.30/1.21.31") .build())); SUPPORTED_BEDROCK_CODECS.add(DEFAULT_BEDROCK_CODEC.toBuilder() - .minecraftVersion("1.21.40/1.21.41") + .minecraftVersion("1.21.40/1.21.41/1.21.43") .build()); }