From d6d19b02b204ef21f74b203cf26badb36f42ec46 Mon Sep 17 00:00:00 2001 From: Tim203 Date: Sun, 27 Oct 2024 22:53:56 +0100 Subject: [PATCH] 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; } }