diff --git a/core/src/main/java/org/geysermc/geyser/GeyserImpl.java b/core/src/main/java/org/geysermc/geyser/GeyserImpl.java index 9df1d218966..15e50aec6cc 100644 --- a/core/src/main/java/org/geysermc/geyser/GeyserImpl.java +++ b/core/src/main/java/org/geysermc/geyser/GeyserImpl.java @@ -34,6 +34,30 @@ import io.netty.util.NettyRuntime; import io.netty.util.concurrent.DefaultThreadFactory; import io.netty.util.internal.SystemPropertyUtil; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.net.UnknownHostException; +import java.nio.file.Path; +import java.security.Key; +import java.text.DecimalFormat; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Objects; +import java.util.UUID; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.function.Consumer; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import lombok.AccessLevel; import lombok.Getter; import lombok.Setter; @@ -103,31 +127,6 @@ import org.geysermc.geyser.util.WebUtils; import org.geysermc.mcprotocollib.network.tcp.TcpSession; -import java.io.File; -import java.io.FileWriter; -import java.io.IOException; -import java.net.InetAddress; -import java.net.InetSocketAddress; -import java.net.UnknownHostException; -import java.nio.file.Path; -import java.security.Key; -import java.text.DecimalFormat; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.Objects; -import java.util.UUID; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.function.Consumer; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - @Getter public class GeyserImpl implements GeyserApi, EventRegistrar { public static final ObjectMapper JSON_MAPPER = new ObjectMapper() @@ -297,7 +296,7 @@ private void startInstance() { SkinProvider.registerCacheImageTask(this); - Registries.RESOURCE_PACKS.load(); + Registries.resourcePacks().load(); String geyserUdpPort = System.getProperty("geyserUdpPort", ""); String pluginUdpPort = geyserUdpPort.isEmpty() ? System.getProperty("pluginUdpPort", "") : geyserUdpPort; @@ -723,7 +722,7 @@ public void disable() { runIfNonNull(newsHandler, NewsHandler::shutdown); runIfNonNull(erosionUnixListener, UnixSocketClientListener::close); - Registries.RESOURCE_PACKS.get().clear(); + Registries.resourcePacks().get().clear(); this.setEnabled(false); } @@ -781,7 +780,7 @@ public CommandRegistry commandRegistry() { @Override @SuppressWarnings("unchecked") public @NonNull R provider(@NonNull Class apiClass, @Nullable Object... args) { - ProviderSupplier provider = Registries.PROVIDERS.get(apiClass); + ProviderSupplier provider = Registries.providers().get(apiClass); if (provider == null) { throw new IllegalArgumentException("No provider found for " + apiClass); } 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 ea3950bd4e6..4e3bd8f2168 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.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 Builder addTranslator(EntityMetadataTranslator translator) { 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); } /** @@ -165,10 +159,10 @@ public EntityDefinition build(boolean register) { } EntityDefinition definition = new EntityDefinition<>(factory, type, identifier, width, height, offset, registeredProperties, translators); if (register && definition.entityType() != null) { - Registries.ENTITY_DEFINITIONS.get().putIfAbsent(definition.entityType(), definition); - Registries.JAVA_ENTITY_IDENTIFIERS.get().putIfAbsent("minecraft:" + type.name().toLowerCase(Locale.ROOT), definition); + Registries.entityDefinitions().get().putIfAbsent(definition.entityType(), definition); + Registries.javaEntityIdentifiers().get().putIfAbsent("minecraft:" + type.name().toLowerCase(Locale.ROOT), definition); if (definition.registeredProperties() != null) { - Registries.BEDROCK_ENTITY_PROPERTIES.get().add(definition.registeredProperties().toNbtMap(identifier)); + Registries.bedrockEntityProperties().get().add(definition.registeredProperties().toNbtMap(identifier)); } } return definition; 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 39357eb609e..a9ede532a97 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.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.javaEntityIdentifiers().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/type/AreaEffectCloudEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/AreaEffectCloudEntity.java index 16549550614..85d0dd6be4d 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/AreaEffectCloudEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/AreaEffectCloudEntity.java @@ -25,6 +25,7 @@ package org.geysermc.geyser.entity.type; +import java.util.UUID; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.ParticleType; import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; @@ -38,8 +39,6 @@ import org.geysermc.mcprotocollib.protocol.data.game.level.particle.EntityEffectParticleData; import org.geysermc.mcprotocollib.protocol.data.game.level.particle.Particle; -import java.util.UUID; - public class AreaEffectCloudEntity extends Entity { public AreaEffectCloudEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, EntityDefinition definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) { @@ -69,7 +68,7 @@ public void setRadius(FloatEntityMetadata entityMetadata) { public void setParticle(EntityMetadata entityMetadata) { Particle particle = entityMetadata.getValue(); - Registries.PARTICLES.map(particle.getType(), p -> p.levelEventType() instanceof ParticleType particleType ? particleType : null).ifPresent(type -> + Registries.particles().map(particle.getType(), p -> p.levelEventType() instanceof ParticleType particleType ? particleType : null).ifPresent(type -> dirtyMetadata.put(EntityDataTypes.AREA_EFFECT_CLOUD_PARTICLE, type)); if (particle.getData() instanceof EntityEffectParticleData effectParticleData) { diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/ThrownPotionEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/ThrownPotionEntity.java index 88cf4f8b97c..21334f367d6 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/ThrownPotionEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/ThrownPotionEntity.java @@ -25,6 +25,8 @@ package org.geysermc.geyser.entity.type; +import java.util.EnumSet; +import java.util.UUID; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag; @@ -40,9 +42,6 @@ import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents; import org.geysermc.mcprotocollib.protocol.data.game.item.component.PotionContents; -import java.util.EnumSet; -import java.util.UUID; - public class ThrownPotionEntity extends ThrowableItemEntity { private static final EnumSet NON_ENCHANTED_POTIONS = EnumSet.of(Potion.WATER, Potion.MUNDANE, Potion.THICK, Potion.AWKWARD); @@ -73,7 +72,7 @@ public void setItem(EntityMetadata entityMetadata) { } } - boolean isLingering = Registries.JAVA_ITEMS.get().get(itemStack.getId()) == Items.LINGERING_POTION; + boolean isLingering = Registries.javaItems().get().get(itemStack.getId()) == Items.LINGERING_POTION; setFlag(EntityFlag.LINGERING, isLingering); } } 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 d057f09c7da..6aa743c6c52 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 @@ -25,8 +25,11 @@ package org.geysermc.geyser.entity.type.living; +import java.util.Optional; +import java.util.UUID; 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 +39,7 @@ 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; @@ -45,9 +49,6 @@ import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand; import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack; -import java.util.Optional; -import java.util.UUID; - public class ArmorStandEntity extends LivingEntity { // These are used to store the state of the armour stand for use when handling invisibility @@ -123,6 +124,12 @@ public void moveAbsolute(Vector3f position, float yaw, float pitch, float headYa 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 4e0de44ea79..2abc34d2b1d 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.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 PlayerEntity(GeyserSession session, int entityId, long geyserId, UUID uui 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 void sendPlayer() { 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/inventory/GeyserItemStack.java b/core/src/main/java/org/geysermc/geyser/inventory/GeyserItemStack.java index 744ad70b6fe..90b9ccf6787 100644 --- a/core/src/main/java/org/geysermc/geyser/inventory/GeyserItemStack.java +++ b/core/src/main/java/org/geysermc/geyser/inventory/GeyserItemStack.java @@ -25,7 +25,12 @@ package org.geysermc.geyser.inventory; -import lombok.*; +import java.util.HashMap; +import lombok.AccessLevel; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.Getter; +import lombok.Setter; import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.Nullable; import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData; @@ -39,8 +44,6 @@ import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType; import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponents; -import java.util.HashMap; - @Data public class GeyserItemStack { public static final GeyserItemStack EMPTY = new GeyserItemStack(Items.AIR_ID, 0, null); @@ -165,7 +168,7 @@ public ItemMapping getMapping(GeyserSession session) { public Item asItem() { if (item == null) { - return (item = Registries.JAVA_ITEMS.get().get(javaId)); + return (item = Registries.javaItems().get().get(javaId)); } return item; } diff --git a/core/src/main/java/org/geysermc/geyser/item/Items.java b/core/src/main/java/org/geysermc/geyser/item/Items.java index 462e98d194e..f113e4947df 100644 --- a/core/src/main/java/org/geysermc/geyser/item/Items.java +++ b/core/src/main/java/org/geysermc/geyser/item/Items.java @@ -25,14 +25,46 @@ package org.geysermc.geyser.item; +import static org.geysermc.geyser.item.type.Item.builder; + import org.geysermc.geyser.item.components.Rarity; import org.geysermc.geyser.item.components.ToolTier; -import org.geysermc.geyser.item.type.*; +import org.geysermc.geyser.item.type.ArmorItem; +import org.geysermc.geyser.item.type.ArrowItem; +import org.geysermc.geyser.item.type.AxolotlBucketItem; +import org.geysermc.geyser.item.type.BannerItem; +import org.geysermc.geyser.item.type.BlockItem; +import org.geysermc.geyser.item.type.BoatItem; +import org.geysermc.geyser.item.type.CompassItem; +import org.geysermc.geyser.item.type.CrossbowItem; +import org.geysermc.geyser.item.type.DecoratedPotItem; +import org.geysermc.geyser.item.type.DyeItem; +import org.geysermc.geyser.item.type.DyeableArmorItem; +import org.geysermc.geyser.item.type.ElytraItem; +import org.geysermc.geyser.item.type.EnchantedBookItem; +import org.geysermc.geyser.item.type.FilledMapItem; +import org.geysermc.geyser.item.type.FireworkRocketItem; +import org.geysermc.geyser.item.type.FireworkStarItem; +import org.geysermc.geyser.item.type.FishingRodItem; +import org.geysermc.geyser.item.type.GoatHornItem; +import org.geysermc.geyser.item.type.Item; +import org.geysermc.geyser.item.type.MaceItem; +import org.geysermc.geyser.item.type.MapItem; +import org.geysermc.geyser.item.type.OminousBottleItem; +import org.geysermc.geyser.item.type.PlayerHeadItem; +import org.geysermc.geyser.item.type.PotionItem; +import org.geysermc.geyser.item.type.ShieldItem; +import org.geysermc.geyser.item.type.ShulkerBoxItem; +import org.geysermc.geyser.item.type.SpawnEggItem; +import org.geysermc.geyser.item.type.TieredItem; +import org.geysermc.geyser.item.type.TippedArrowItem; +import org.geysermc.geyser.item.type.TropicalFishBucketItem; +import org.geysermc.geyser.item.type.WolfArmorItem; +import org.geysermc.geyser.item.type.WritableBookItem; +import org.geysermc.geyser.item.type.WrittenBookItem; import org.geysermc.geyser.level.block.Blocks; import org.geysermc.geyser.registry.Registries; -import static org.geysermc.geyser.item.type.Item.builder; - /** * A list, in order, of all Java items. */ @@ -1375,13 +1407,13 @@ public final class Items { public static final int AIR_ID = AIR.javaId(); private static T register(T item) { - return register(item, Registries.JAVA_ITEMS.get().size()); + return register(item, Registries.javaItems().get().size()); } public static T register(T item, int id) { item.setJavaId(id); - Registries.JAVA_ITEMS.registerWithAnyIndex(id, item, AIR); - Registries.JAVA_ITEM_IDENTIFIERS.register(item.javaIdentifier(), item); + Registries.javaItems().registerWithAnyIndex(id, item, AIR); + Registries.javaItemIdentifiers().register(item.javaIdentifier(), item); return item; } diff --git a/core/src/main/java/org/geysermc/geyser/item/enchantment/Enchantment.java b/core/src/main/java/org/geysermc/geyser/item/enchantment/Enchantment.java index 301f69a5f35..4bf565956ec 100644 --- a/core/src/main/java/org/geysermc/geyser/item/enchantment/Enchantment.java +++ b/core/src/main/java/org/geysermc/geyser/item/enchantment/Enchantment.java @@ -26,6 +26,11 @@ package org.geysermc.geyser.item.enchantment; import it.unimi.dsi.fastutil.ints.IntArrays; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.function.ToIntFunction; import net.kyori.adventure.key.Key; import org.checkerframework.checker.nullness.qual.Nullable; import org.cloudburstmc.nbt.NbtMap; @@ -37,12 +42,6 @@ import org.geysermc.geyser.util.MinecraftKey; import org.geysermc.mcprotocollib.protocol.data.game.item.component.HolderSet; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.function.ToIntFunction; - /** * @param description only populated if {@link #bedrockEnchantment()} is not null. * @param anvilCost also as a rarity multiplier @@ -60,7 +59,7 @@ public static Enchantment read(RegistryEntryContext context) { NbtMap data = context.data(); Set effects = readEnchantmentComponents(data.getCompound("effects")); - HolderSet supportedItems = readHolderSet(data.get("supported_items"), itemId -> Registries.JAVA_ITEM_IDENTIFIERS.getOrDefault(itemId.asString(), Items.AIR).javaId()); + HolderSet supportedItems = readHolderSet(data.get("supported_items"), itemId -> Registries.javaItemIdentifiers().getOrDefault(itemId.asString(), Items.AIR).javaId()); int maxLevel = data.getInt("max_level"); int anvilCost = data.getInt("anvil_cost"); diff --git a/core/src/main/java/org/geysermc/geyser/network/UpstreamPacketHandler.java b/core/src/main/java/org/geysermc/geyser/network/UpstreamPacketHandler.java index 5c48df1f913..66ddc6681b8 100644 --- a/core/src/main/java/org/geysermc/geyser/network/UpstreamPacketHandler.java +++ b/core/src/main/java/org/geysermc/geyser/network/UpstreamPacketHandler.java @@ -26,6 +26,13 @@ package org.geysermc.geyser.network; import io.netty.buffer.Unpooled; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.channels.SeekableByteChannel; +import java.util.ArrayDeque; +import java.util.Deque; +import java.util.HashMap; +import java.util.OptionalInt; import org.cloudburstmc.protocol.bedrock.BedrockDisconnectReasons; import org.cloudburstmc.protocol.bedrock.codec.BedrockCodec; import org.cloudburstmc.protocol.bedrock.codec.compat.BedrockCompat; @@ -69,14 +76,6 @@ import org.geysermc.geyser.util.MathUtils; import org.geysermc.geyser.util.VersionCheckUtils; -import java.io.IOException; -import java.nio.ByteBuffer; -import java.nio.channels.SeekableByteChannel; -import java.util.ArrayDeque; -import java.util.Deque; -import java.util.HashMap; -import java.util.OptionalInt; - public class UpstreamPacketHandler extends LoggingPacketHandler { private boolean networkSettingsRequested = false; @@ -94,7 +93,7 @@ public UpstreamPacketHandler(GeyserImpl geyser, GeyserSession session) { } private PacketSignal translateAndDefault(BedrockPacket packet) { - Registries.BEDROCK_PACKET_TRANSLATORS.translate(packet.getClass(), packet, session); + Registries.bedrockPacketTranslators().translate(packet.getClass(), packet, session); return PacketSignal.HANDLED; // PacketSignal.UNHANDLED will log a WARN publicly } @@ -182,7 +181,7 @@ public PacketSignal handle(LoginPacket loginPacket) { // Set the block translation based off of version session.setBlockMappings(BlockRegistries.BLOCKS.forVersion(loginPacket.getProtocolVersion())); - session.setItemMappings(Registries.ITEMS.forVersion(loginPacket.getProtocolVersion())); + session.setItemMappings(Registries.items().forVersion(loginPacket.getProtocolVersion())); LoginEncryptionUtils.encryptPlayerConnection(session, loginPacket); @@ -200,7 +199,7 @@ public PacketSignal handle(LoginPacket loginPacket) { geyser.getSessionManager().addPendingSession(session); - this.resourcePackLoadEvent = new SessionLoadResourcePacksEventImpl(session, new HashMap<>(Registries.RESOURCE_PACKS.get())); + this.resourcePackLoadEvent = new SessionLoadResourcePacksEventImpl(session, new HashMap<>(Registries.resourcePacks().get())); this.geyser.eventBus().fire(this.resourcePackLoadEvent); ResourcePacksInfoPacket resourcePacksInfo = new ResourcePacksInfoPacket(); diff --git a/core/src/main/java/org/geysermc/geyser/registry/CommonRegistries.java b/core/src/main/java/org/geysermc/geyser/registry/CommonRegistries.java new file mode 100644 index 00000000000..dcca7bdd1f7 --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/registry/CommonRegistries.java @@ -0,0 +1,152 @@ +/* + * 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.objects.Object2IntMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import org.cloudburstmc.nbt.NbtMap; +import org.cloudburstmc.protocol.bedrock.data.inventory.crafting.PotionMixData; +import org.cloudburstmc.protocol.bedrock.packet.BedrockPacket; +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.provider.ProviderSupplier; +import org.geysermc.geyser.registry.type.ItemMappings; +import org.geysermc.geyser.registry.type.ParticleMapping; +import org.geysermc.geyser.registry.type.SoundMapping; +import org.geysermc.geyser.translator.level.block.entity.BlockEntityTranslator; +import org.geysermc.geyser.translator.level.event.LevelEventTranslator; +import org.geysermc.geyser.translator.sound.SoundInteractionTranslator; +import org.geysermc.geyser.translator.sound.SoundTranslator; +import org.geysermc.mcprotocollib.network.packet.Packet; +import org.geysermc.mcprotocollib.protocol.data.game.entity.type.EntityType; +import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType; +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; + +public interface CommonRegistries { + /** + * A registry holding all the providers. + * This has to be initialized first to allow extensions to access providers during other registry events. + */ + SimpleMappedRegistry, ProviderSupplier> providers(); + + /** + * A registry holding a CompoundTag of the known entity identifiers. + */ + SimpleRegistry bedrockEntityIdentifiers(); + /** + * A map containing all Java entity identifiers and their respective Geyser definitions + */ + SimpleMappedRegistry> javaEntityIdentifiers(); + + /** + * A map containing all entity types and their respective Geyser definitions + */ + SimpleMappedRegistry> entityDefinitions(); + /** + * A registry holding a list of all the known entity properties to be sent to the client after start game. + */ + SimpleRegistry> bedrockEntityProperties(); + + /** + * A registry holding a CompoundTag of all the known biomes. + */ + SimpleRegistry biomesNbt(); + /** + * A mapped registry which stores Java biome identifiers and their Bedrock biome identifier. + */ + SimpleRegistry> biomeIdentifiers(); + + /** + * A mapped registry which stores a block entity identifier to its {@link BlockEntityTranslator}. + */ + SimpleMappedRegistry blockEntities(); + + /** + * A registry containing all the Bedrock packet translators. + */ + PacketTranslatorRegistry bedrockPacketTranslators(); + /** + * A registry containing all the Java packet translators. + */ + PacketTranslatorRegistry javaPacketTranslators(); + + /** + * A registry containing all Java items ordered by their network ID. + */ + ListRegistry javaItems(); + SimpleMappedRegistry javaItemIdentifiers(); + /** + * A versioned registry which holds {@link ItemMappings} for each version. These item mappings contain + * primarily Bedrock version-specific data. + */ + VersionedRegistry items(); + + /** + * 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. + */ + SimpleMappedRegistry particles(); + + /** + * A registry holding all the potion mixes. + */ + VersionedRegistry> potionMixes(); + /** + * A versioned registry holding all the recipes, with the net ID being the key, and {@link GeyserRecipe} as the value. + */ + SimpleMappedRegistry> recipes(); + + /** + * A mapped registry holding {@link ResourcePack}'s with the pack uuid as keys. + */ + DeferredRegistry> resourcePacks(); + + /** + * A mapped registry holding sound identifiers to their corresponding {@link SoundMapping}. + */ + SimpleMappedRegistry sounds(); + /** + * A mapped registry holding {@link LevelEvent}s to their corresponding {@link LevelEventTranslator}. + */ + SimpleMappedRegistry soundLevelEvents(); + /** + * A mapped registry holding {@link SoundTranslator}s to their corresponding {@link SoundInteractionTranslator}. + */ + SimpleMappedRegistry> soundTranslators(); + + /** + * Called after the instance has been set for {@link Registries#instance()}. + * This allows registries that depend on other registries to continue working. + * Done specifically for the {@link org.geysermc.geyser.item.Items} class. + */ + void postInit(); +} diff --git a/core/src/main/java/org/geysermc/geyser/registry/CommonRegistriesDefault.java b/core/src/main/java/org/geysermc/geyser/registry/CommonRegistriesDefault.java new file mode 100644 index 00000000000..f14ef9b4a3e --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/registry/CommonRegistriesDefault.java @@ -0,0 +1,238 @@ +/* + * 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.Int2ObjectOpenHashMap; +import it.unimi.dsi.fastutil.objects.Object2IntMap; +import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; +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; +import org.cloudburstmc.nbt.NbtMap; +import org.cloudburstmc.nbt.NbtMapBuilder; +import org.cloudburstmc.protocol.bedrock.data.inventory.crafting.PotionMixData; +import org.cloudburstmc.protocol.bedrock.packet.BedrockPacket; +import org.geysermc.geyser.GeyserImpl; +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.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.provider.ProviderSupplier; +import org.geysermc.geyser.registry.type.ItemMappings; +import org.geysermc.geyser.registry.type.ParticleMapping; +import org.geysermc.geyser.registry.type.SoundMapping; +import org.geysermc.geyser.translator.level.block.entity.BlockEntityTranslator; +import org.geysermc.geyser.translator.level.event.LevelEventTranslator; +import org.geysermc.geyser.translator.sound.SoundInteractionTranslator; +import org.geysermc.geyser.translator.sound.SoundTranslator; +import org.geysermc.mcprotocollib.network.packet.Packet; +import org.geysermc.mcprotocollib.protocol.data.game.entity.type.EntityType; +import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType; +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; + +/** + * Holds all the common registries in Geyser. + */ +public final class CommonRegistriesDefault implements CommonRegistries { + private static final CommonRegistriesDefault INSTANCE = new CommonRegistriesDefault(); + + private final SimpleMappedRegistry, ProviderSupplier> providers = SimpleMappedRegistry.create(new IdentityHashMap<>(), ProviderRegistryLoader::new); + + private final SimpleRegistry bedrockEntityIdentifiers = SimpleRegistry.create("bedrock/entity_identifiers.dat", RegistryLoaders.NBT); + private final SimpleMappedRegistry> javaEntityIdentifiers = SimpleMappedRegistry.create(RegistryLoaders.empty(Object2ObjectOpenHashMap::new)); + + private final SimpleMappedRegistry> entityDefinitions = SimpleMappedRegistry.create(RegistryLoaders.empty(() -> new EnumMap<>(EntityType.class))); + private final SimpleRegistry> bedrockEntityProperties = SimpleRegistry.create(RegistryLoaders.empty(HashSet::new)); + + private final SimpleRegistry biomesNbt = SimpleRegistry.create("bedrock/biome_definitions.dat", RegistryLoaders.NBT); + private final SimpleRegistry> biomeIdentifiers = SimpleRegistry.create("mappings/biomes.json", BiomeIdentifierRegistryLoader::new); + + private final SimpleMappedRegistry blockEntities = SimpleMappedRegistry.create("org.geysermc.geyser.translator.level.block.entity.BlockEntity", BlockEntityRegistryLoader::new); + + private final PacketTranslatorRegistry bedrockPacketTranslators = PacketTranslatorRegistry.create(); + private final PacketTranslatorRegistry javaPacketTranslators = PacketTranslatorRegistry.create(); + + private final ListRegistry javaItems = ListRegistry.create(RegistryLoaders.empty(ArrayList::new)); + private final SimpleMappedRegistry javaItemIdentifiers = SimpleMappedRegistry.create(RegistryLoaders.empty(Object2ObjectOpenHashMap::new)); + private final VersionedRegistry items = VersionedRegistry.create(RegistryLoaders.empty(Int2ObjectOpenHashMap::new)); + + private final SimpleMappedRegistry particles = SimpleMappedRegistry.create("mappings/particles.json", ParticleTypesRegistryLoader::new); + + private VersionedRegistry> potionMixes; + private final SimpleMappedRegistry> recipes = SimpleMappedRegistry.create("mappings/recipes.nbt", RecipeRegistryLoader::new); + + private final DeferredRegistry> resourcePacks = DeferredRegistry.create(GeyserImpl.getInstance().packDirectory(), SimpleMappedRegistry::create, RegistryLoaders.RESOURCE_PACKS); + + private final SimpleMappedRegistry sounds = SimpleMappedRegistry.create("mappings/sounds.json", SoundRegistryLoader::new); + private final SimpleMappedRegistry soundLevelEvents = SimpleMappedRegistry.create("mappings/effects.json", SoundEventsRegistryLoader::new); + private final SimpleMappedRegistry> soundTranslators = SimpleMappedRegistry.create("org.geysermc.geyser.translator.sound.SoundTranslator", SoundTranslatorRegistryLoader::new); + + CommonRegistriesDefault() {} + + public static CommonRegistriesDefault instance() { + return INSTANCE; + } + + @Override + public void postInit() { + PacketRegistryPopulator.populate(this); + ItemRegistryPopulator.populate(this); + + // Create registries that require other registries to load first + potionMixes = VersionedRegistry.create(this, PotionMixRegistryLoader::new); + + // Remove unneeded client generation data from NbtMapBuilder + NbtMapBuilder biomesNbt = NbtMap.builder(); + for (Map.Entry entry : this.biomesNbt.get().entrySet()) { + String key = entry.getKey(); + NbtMapBuilder value = ((NbtMap) entry.getValue()).toBuilder(); + value.remove("minecraft:consolidated_features"); + value.remove("minecraft:multinoise_generation_rules"); + value.remove("minecraft:surface_material_adjustments"); + value.remove( "minecraft:surface_parameters"); + biomesNbt.put(key, value.build()); + } + this.biomesNbt.set(biomesNbt.build()); + } + + @Override + public SimpleMappedRegistry, ProviderSupplier> providers() { + return providers; + } + + @Override + public SimpleRegistry bedrockEntityIdentifiers() { + return bedrockEntityIdentifiers; + } + + @Override + public SimpleMappedRegistry> javaEntityIdentifiers() { + return javaEntityIdentifiers; + } + + @Override + public SimpleMappedRegistry> entityDefinitions() { + return entityDefinitions; + } + + @Override + public SimpleRegistry> bedrockEntityProperties() { + return bedrockEntityProperties; + } + + @Override + public SimpleRegistry biomesNbt() { + return biomesNbt; + } + + @Override + public SimpleRegistry> biomeIdentifiers() { + return biomeIdentifiers; + } + + @Override + public SimpleMappedRegistry blockEntities() { + return blockEntities; + } + + @Override + public PacketTranslatorRegistry bedrockPacketTranslators() { + return bedrockPacketTranslators; + } + + @Override + public PacketTranslatorRegistry javaPacketTranslators() { + return javaPacketTranslators; + } + + @Override + public ListRegistry javaItems() { + return javaItems; + } + + @Override + public SimpleMappedRegistry javaItemIdentifiers() { + return javaItemIdentifiers; + } + + @Override + public VersionedRegistry items() { + return items; + } + + @Override + public SimpleMappedRegistry particles() { + return particles; + } + + @Override + public VersionedRegistry> potionMixes() { + return potionMixes; + } + + @Override + public SimpleMappedRegistry> recipes() { + return recipes; + } + + @Override + public DeferredRegistry> resourcePacks() { + return resourcePacks; + } + + @Override + public SimpleMappedRegistry sounds() { + return sounds; + } + + @Override + public SimpleMappedRegistry soundLevelEvents() { + return soundLevelEvents; + } + + @Override + public SimpleMappedRegistry> soundTranslators() { + return soundTranslators; + } +} 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 30d3c076345..7fb1ed3196e 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/Registries.java +++ b/core/src/main/java/org/geysermc/geyser/registry/Registries.java @@ -25,22 +25,17 @@ package org.geysermc.geyser.registry; -import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import it.unimi.dsi.fastutil.objects.Object2IntMap; -import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; import org.cloudburstmc.nbt.NbtMap; -import org.cloudburstmc.nbt.NbtMapBuilder; import org.cloudburstmc.protocol.bedrock.data.inventory.crafting.PotionMixData; import org.cloudburstmc.protocol.bedrock.packet.BedrockPacket; -import org.geysermc.geyser.GeyserImpl; 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.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,134 +51,159 @@ import org.geysermc.mcprotocollib.protocol.data.game.level.particle.ParticleType; import org.geysermc.mcprotocollib.protocol.data.game.recipe.RecipeType; -import java.util.*; - /** * Holds all the common registries in Geyser. + * Block specific registries can be found in {@link BlockRegistries} */ public final class Registries { + private static CommonRegistries backingRegistries; + + public static CommonRegistries instance() { + return CommonRegistriesDefault.instance(); + } + /** * A registry holding all the providers. * This has to be initialized first to allow extensions to access providers during other registry events. */ - public static final SimpleMappedRegistry, ProviderSupplier> PROVIDERS = SimpleMappedRegistry.create(new IdentityHashMap<>(), ProviderRegistryLoader::new); + public static SimpleMappedRegistry, ProviderSupplier> providers() { + return backingRegistries.providers(); + } /** * A registry holding a CompoundTag of the known entity identifiers. */ - public static final SimpleRegistry BEDROCK_ENTITY_IDENTIFIERS = SimpleRegistry.create("bedrock/entity_identifiers.dat", RegistryLoaders.NBT); + public static SimpleRegistry bedrockEntityIdentifiers() { + return backingRegistries.bedrockEntityIdentifiers(); + } /** * A registry containing all the Bedrock packet translators. */ - public static final PacketTranslatorRegistry BEDROCK_PACKET_TRANSLATORS = PacketTranslatorRegistry.create(); + public static PacketTranslatorRegistry bedrockPacketTranslators() { + return backingRegistries.bedrockPacketTranslators(); + } /** * A registry holding a CompoundTag of all the known biomes. */ - public static final SimpleRegistry BIOMES_NBT = SimpleRegistry.create("bedrock/biome_definitions.dat", RegistryLoaders.NBT); + public static SimpleRegistry biomesNbt() { + return backingRegistries.biomesNbt(); + } /** * 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 SimpleRegistry> biomeIdentifiers() { + return backingRegistries.biomeIdentifiers(); + } /** * 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 SimpleMappedRegistry blockEntities() { + return backingRegistries.blockEntities(); + } /** * A map containing all entity types and their respective Geyser definitions */ - public static final SimpleMappedRegistry> ENTITY_DEFINITIONS = SimpleMappedRegistry.create(RegistryLoaders.empty(() -> new EnumMap<>(EntityType.class))); + public static SimpleMappedRegistry> entityDefinitions() { + return backingRegistries.entityDefinitions(); + } /** * A registry holding a list of all the known entity properties to be sent to the client after start game. */ - public static final SimpleRegistry> BEDROCK_ENTITY_PROPERTIES = SimpleRegistry.create(RegistryLoaders.empty(HashSet::new)); + public static SimpleRegistry> bedrockEntityProperties() { + return backingRegistries.bedrockEntityProperties(); + } /** * A map containing all Java entity identifiers and their respective Geyser definitions */ - public static final SimpleMappedRegistry> JAVA_ENTITY_IDENTIFIERS = SimpleMappedRegistry.create(RegistryLoaders.empty(Object2ObjectOpenHashMap::new)); + public static SimpleMappedRegistry> javaEntityIdentifiers() { + return backingRegistries.javaEntityIdentifiers(); + } /** * A registry containing all the Java packet translators. */ - public static final PacketTranslatorRegistry JAVA_PACKET_TRANSLATORS = PacketTranslatorRegistry.create(); + public static PacketTranslatorRegistry javaPacketTranslators() { + return backingRegistries.javaPacketTranslators(); + } /** * A registry containing all Java items ordered by their network ID. */ - public static final ListRegistry JAVA_ITEMS = ListRegistry.create(RegistryLoaders.empty(ArrayList::new)); + public static ListRegistry javaItems() { + return backingRegistries.javaItems(); + } - public static final SimpleMappedRegistry JAVA_ITEM_IDENTIFIERS = SimpleMappedRegistry.create(RegistryLoaders.empty(Object2ObjectOpenHashMap::new)); + public static SimpleMappedRegistry javaItemIdentifiers() { + return backingRegistries.javaItemIdentifiers(); + } /** * A versioned registry which holds {@link ItemMappings} for each version. These item mappings contain * primarily Bedrock version-specific data. */ - public static final VersionedRegistry ITEMS = VersionedRegistry.create(RegistryLoaders.empty(Int2ObjectOpenHashMap::new)); + public static VersionedRegistry items() { + return backingRegistries.items(); + } /** * 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 SimpleMappedRegistry particles() { + return backingRegistries.particles(); + } /** * A registry holding all the potion mixes. */ - public static final VersionedRegistry> POTION_MIXES; + public static VersionedRegistry> potionMixes() { + return backingRegistries.potionMixes(); + } /** * 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 SimpleMappedRegistry> recipes() { + return backingRegistries.recipes(); + } /** * 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 DeferredRegistry> resourcePacks() { + return backingRegistries.resourcePacks(); + } /** * 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 SimpleMappedRegistry sounds() { + return backingRegistries.sounds(); + } /** * 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 SimpleMappedRegistry soundLevelEvents() { + return backingRegistries.soundLevelEvents(); + } /** * 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 SimpleMappedRegistry> soundTranslators() { + return backingRegistries.soundTranslators(); + } public static void init() { - // no-op - } - - static { - PacketRegistryPopulator.populate(); - ItemRegistryPopulator.populate(); - - // Create registries that require other registries to load first - POTION_MIXES = VersionedRegistry.create(PotionMixRegistryLoader::new); - - // Remove unneeded client generation data from NbtMapBuilder - NbtMapBuilder biomesNbt = NbtMap.builder(); - for (Map.Entry entry : BIOMES_NBT.get().entrySet()) { - String key = entry.getKey(); - NbtMapBuilder value = ((NbtMap) entry.getValue()).toBuilder(); - value.remove("minecraft:consolidated_features"); - value.remove("minecraft:multinoise_generation_rules"); - value.remove("minecraft:surface_material_adjustments"); - value.remove( "minecraft:surface_parameters"); - biomesNbt.put(key, value.build()); - } - BIOMES_NBT.set(biomesNbt.build()); + backingRegistries = instance(); + backingRegistries.postInit(); } } 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 8836502b37b..64514818c2e 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,8 @@ package org.geysermc.geyser.registry; -import org.geysermc.geyser.registry.loader.RegistryLoader; - import java.util.function.Consumer; +import org.geysermc.geyser.registry.loader.RegistryLoader; /** * A wrapper around a value which is loaded based on the output from the provided @@ -58,7 +57,7 @@ * however it demonstrates a fairly basic use case of how this system works. Typically * though, the first parameter would be a location of some sort, such as a file path * where the loader will load the mappings from. The NBT registry is a good reference - * point for something both simple and practical. See {@link Registries#BIOMES_NBT} and + * point for something both simple and practical. See {@link Registries#biomesNbt} and * {@link org.geysermc.geyser.registry.loader.NbtRegistryLoader}. * * @param the value being held by the registry @@ -111,4 +110,4 @@ public void set(M mappings) { 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 eae4e2bead1..9ab9c3ca1f9 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 @@ -27,19 +27,18 @@ import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; import org.cloudburstmc.protocol.bedrock.data.inventory.crafting.PotionMixData; import org.geysermc.geyser.inventory.item.Potion; import org.geysermc.geyser.item.Items; import org.geysermc.geyser.item.type.Item; -import org.geysermc.geyser.registry.Registries; +import org.geysermc.geyser.registry.CommonRegistries; import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.registry.type.ItemMappings; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; - /** * Generates a collection of {@link PotionMixData} that enables the * Bedrock client to place brewing items into the brewing stand. @@ -49,12 +48,12 @@ * (Ex: Bedrock cannot normally place glass bottles or fully upgraded * potions into the brewing stand, but Java can.) */ -public class PotionMixRegistryLoader implements RegistryLoader>> { +public class PotionMixRegistryLoader implements RegistryLoader>> { @Override - public Int2ObjectMap> load(Object input) { - var allPotionMixes = new Int2ObjectOpenHashMap>(Registries.ITEMS.get().size()); - for (var entry : Registries.ITEMS.get().int2ObjectEntrySet()) { + public Int2ObjectMap> load(CommonRegistries registries) { + var allPotionMixes = new Int2ObjectOpenHashMap>(registries.items().get().size()); + for (var entry : registries.items().get().int2ObjectEntrySet()) { ItemMappings mappings = entry.getValue(); List ingredients = new ArrayList<>(); ingredients.add(getNonNull(mappings, Items.NETHER_WART)); @@ -120,9 +119,10 @@ public Int2ObjectMap> load(Object input) { private static ItemMapping getNonNull(ItemMappings mappings, Item javaItem) { ItemMapping itemMapping = mappings.getMapping(javaItem); - if (itemMapping == null) + if (itemMapping == null) { throw new NullPointerException("No item entry exists for java identifier: " + javaItem.javaIdentifier()); + } return itemMapping; } -} \ No newline at end of file +} diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java b/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java index bface58da2d..75947e6ac91 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/BlockRegistryPopulator.java @@ -39,6 +39,20 @@ import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import it.unimi.dsi.fastutil.objects.ObjectIntPair; import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; +import java.io.DataInputStream; +import java.io.InputStream; +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.BitSet; +import java.util.Comparator; +import java.util.Iterator; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Set; +import java.util.stream.Stream; +import java.util.zip.GZIPInputStream; import org.cloudburstmc.nbt.NBTInputStream; import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMapBuilder; @@ -68,21 +82,6 @@ import org.geysermc.geyser.util.BlockUtils; import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack; -import java.io.DataInputStream; -import java.io.InputStream; -import java.nio.charset.StandardCharsets; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.BitSet; -import java.util.Comparator; -import java.util.Iterator; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.Set; -import java.util.stream.Stream; -import java.util.zip.GZIPInputStream; - /** * Populates the block registries. */ @@ -461,7 +460,7 @@ private static void registerJavaBlocks() { @Override public ItemStack pickItem(BlockState state) { if (this.item == null) { - this.item = Registries.JAVA_ITEM_IDENTIFIERS.get(pickItem); + this.item = Registries.javaItemIdentifiers().get(pickItem); if (this.item == null) { GeyserImpl.getInstance().getLogger().warning("We could not find item " + pickItem + " for getting the item for block " + javaBlockState.identifier()); 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 bea213aa4fc..41c360023a3 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,22 @@ 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 java.io.InputStream; +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; import org.checkerframework.checker.nullness.qual.NonNull; import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMapBuilder; @@ -64,12 +79,14 @@ 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 java.io.InputStream; -import java.util.*; -import java.util.concurrent.atomic.AtomicInteger; +import org.geysermc.geyser.registry.CommonRegistries; +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; /** * Populates the item registries. @@ -89,7 +106,7 @@ interface Remapper { GeyserMappingItem remap(Item item, GeyserMappingItem mapping); } - public static void populate() { + public static void populate(CommonRegistries registries) { List paletteVersions = new ArrayList<>(3); 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)); @@ -218,7 +235,7 @@ public static void populate() { Set registeredItemNames = new ObjectOpenHashSet<>(); // This is used to check for duplicate item names for (Map.Entry entry : items.entrySet()) { - Item javaItem = Registries.JAVA_ITEM_IDENTIFIERS.get(entry.getKey()); + Item javaItem = registries.javaItemIdentifiers().get(entry.getKey()); if (javaItem == null) { throw new RuntimeException("Extra item in mappings? " + entry.getKey()); } @@ -619,7 +636,7 @@ public static void populate() { .customBlockItemDefinitions(customBlockItemDefinitions) .build(); - Registries.ITEMS.register(palette.protocolVersion(), itemMappings); + registries.items().register(palette.protocolVersion(), itemMappings); firstMappingsPass = false; } diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/PacketRegistryPopulator.java b/core/src/main/java/org/geysermc/geyser/registry/populator/PacketRegistryPopulator.java index 9be00732ceb..ad07be8f4a1 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/PacketRegistryPopulator.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/PacketRegistryPopulator.java @@ -27,7 +27,7 @@ import org.cloudburstmc.protocol.bedrock.packet.BedrockPacket; import org.geysermc.geyser.GeyserImpl; -import org.geysermc.geyser.registry.Registries; +import org.geysermc.geyser.registry.CommonRegistries; import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; import org.geysermc.geyser.util.FileUtils; @@ -36,7 +36,7 @@ public class PacketRegistryPopulator { @SuppressWarnings("unchecked") - public static void populate() { + public static void populate(CommonRegistries registries) { for (Class clazz : FileUtils.getGeneratedClassesForAnnotation(Translator.class)) { Class packet = clazz.getAnnotation(Translator.class).packet(); @@ -47,12 +47,12 @@ public static void populate() { Class targetPacket = (Class) packet; PacketTranslator translator = (PacketTranslator) clazz.getConstructor().newInstance(); - Registries.JAVA_PACKET_TRANSLATORS.register(targetPacket, translator); + registries.javaPacketTranslators().register(targetPacket, translator); } else if (BedrockPacket.class.isAssignableFrom(packet)) { Class targetPacket = (Class) packet; PacketTranslator translator = (PacketTranslator) clazz.getConstructor().newInstance(); - Registries.BEDROCK_PACKET_TRANSLATORS.register(targetPacket, translator); + registries.bedrockPacketTranslators().register(targetPacket, translator); } else { GeyserImpl.getInstance().getLogger().error("Class " + clazz.getCanonicalName() + " is annotated as a translator but has an invalid target packet."); } 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 d7c06ac4fad..50752353996 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 void addEntities(String... names) { // 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 @@ private void removeRemovedEntities(Set names) { } } + /** + * 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/GeyserSession.java b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java index 9c20e990974..3534687caf6 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -35,6 +35,26 @@ import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import it.unimi.dsi.fastutil.objects.ObjectOpenHashSet; +import java.net.ConnectException; +import java.net.InetSocketAddress; +import java.nio.charset.StandardCharsets; +import java.time.Instant; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.BitSet; +import java.util.Collections; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Queue; +import java.util.Set; +import java.util.UUID; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionException; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.ScheduledFuture; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicInteger; import lombok.AccessLevel; import lombok.Getter; import lombok.Setter; @@ -191,7 +211,6 @@ import org.geysermc.mcprotocollib.network.packet.Packet; import org.geysermc.mcprotocollib.network.tcp.TcpClientSession; import org.geysermc.mcprotocollib.network.tcp.TcpSession; -import org.geysermc.mcprotocollib.protocol.ClientListener; import org.geysermc.mcprotocollib.protocol.MinecraftConstants; import org.geysermc.mcprotocollib.protocol.MinecraftProtocol; import org.geysermc.mcprotocollib.protocol.data.ProtocolState; @@ -207,8 +226,6 @@ import org.geysermc.mcprotocollib.protocol.data.game.statistic.CustomStatistic; import org.geysermc.mcprotocollib.protocol.data.game.statistic.Statistic; import org.geysermc.mcprotocollib.protocol.packet.common.serverbound.ServerboundClientInformationPacket; -import org.geysermc.mcprotocollib.protocol.packet.configuration.clientbound.ClientboundFinishConfigurationPacket; -import org.geysermc.mcprotocollib.protocol.packet.configuration.serverbound.ServerboundFinishConfigurationPacket; import org.geysermc.mcprotocollib.protocol.packet.handshake.serverbound.ClientIntentionPacket; import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.ServerboundChatCommandSignedPacket; import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.ServerboundChatPacket; @@ -218,27 +235,6 @@ import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundUseItemPacket; import org.geysermc.mcprotocollib.protocol.packet.login.serverbound.ServerboundCustomQueryAnswerPacket; -import java.net.ConnectException; -import java.net.InetSocketAddress; -import java.nio.charset.StandardCharsets; -import java.time.Instant; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.BitSet; -import java.util.Collections; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Queue; -import java.util.Set; -import java.util.UUID; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.CompletionException; -import java.util.concurrent.ConcurrentLinkedQueue; -import java.util.concurrent.ScheduledFuture; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicInteger; - @Getter public class GeyserSession implements GeyserConnection, GeyserCommandSource { @@ -754,11 +750,11 @@ public void connect() { ChunkUtils.sendEmptyChunks(this, playerEntity.getPosition().toInt(), 0, false); BiomeDefinitionListPacket biomeDefinitionListPacket = new BiomeDefinitionListPacket(); - biomeDefinitionListPacket.setDefinitions(Registries.BIOMES_NBT.get()); + biomeDefinitionListPacket.setDefinitions(Registries.biomesNbt().get()); upstream.sendPacket(biomeDefinitionListPacket); AvailableEntityIdentifiersPacket entityPacket = new AvailableEntityIdentifiersPacket(); - entityPacket.setIdentifiers(Registries.BEDROCK_ENTITY_IDENTIFIERS.get()); + entityPacket.setIdentifiers(Registries.bedrockEntityIdentifiers().get()); upstream.sendPacket(entityPacket); CameraPresetsPacket cameraPresetsPacket = new CameraPresetsPacket(); @@ -772,7 +768,7 @@ public void connect() { // Potion mixes are registered by default, as they are needed to be able to put ingredients into the brewing stand. CraftingDataPacket craftingDataPacket = new CraftingDataPacket(); craftingDataPacket.setCleanRecipes(true); - craftingDataPacket.getPotionMixData().addAll(Registries.POTION_MIXES.forVersion(this.upstream.getProtocolVersion())); + craftingDataPacket.getPotionMixData().addAll(Registries.potionMixes().forVersion(this.upstream.getProtocolVersion())); upstream.sendPacket(craftingDataPacket); PlayStatusPacket playStatusPacket = new PlayStatusPacket(); @@ -1152,7 +1148,7 @@ public void disconnected(DisconnectedEvent event) { @Override public void packetReceived(Session session, Packet packet) { - Registries.JAVA_PACKET_TRANSLATORS.translate(packet.getClass(), packet, GeyserSession.this); + Registries.javaPacketTranslators().translate(packet.getClass(), packet, GeyserSession.this); } @Override @@ -1683,7 +1679,7 @@ private void startGame() { } private void syncEntityProperties() { - for (NbtMap nbtMap : Registries.BEDROCK_ENTITY_PROPERTIES.get()) { + for (NbtMap nbtMap : Registries.bedrockEntityProperties().get()) { SyncEntityPropertyPacket syncEntityPropertyPacket = new SyncEntityPropertyPacket(); syncEntityPropertyPacket.setData(nbtMap); upstream.sendPacket(syncEntityPropertyPacket); 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 a80ed3e3aa7..78d21e63be1 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 EntityCache(GeyserSession session) { 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 void addPlayerEntity(PlayerEntity entity) { // 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/inventory/ShulkerInventoryTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/inventory/ShulkerInventoryTranslator.java index 464bf07f7e3..3e773617e98 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/inventory/ShulkerInventoryTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/inventory/ShulkerInventoryTranslator.java @@ -48,7 +48,7 @@ public class ShulkerInventoryTranslator extends AbstractBlockInventoryTranslator public ShulkerInventoryTranslator() { // Ensure that the shulker box default state won't be trying to open in a state facing the player super(27, new BlockInventoryHolder(Blocks.SHULKER_BOX.defaultBlockState().withValue(Properties.FACING, Direction.NORTH), ContainerType.CONTAINER) { - private final BlockEntityTranslator shulkerBoxTranslator = Registries.BLOCK_ENTITIES.get(BlockEntityType.SHULKER_BOX); + private final BlockEntityTranslator shulkerBoxTranslator = Registries.blockEntities().get(BlockEntityType.SHULKER_BOX); @Override protected boolean isValidBlock(BlockState blockState) { diff --git a/core/src/main/java/org/geysermc/geyser/translator/item/ItemTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/item/ItemTranslator.java index 163eef20b32..5ccc4dbb57c 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/item/ItemTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/item/ItemTranslator.java @@ -25,6 +25,12 @@ package org.geysermc.geyser.translator.item; +import java.text.DecimalFormat; +import java.util.ArrayList; +import java.util.EnumMap; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import net.kyori.adventure.text.Component; import net.kyori.adventure.text.format.NamedTextColor; import org.checkerframework.checker.nullness.qual.NonNull; @@ -64,13 +70,6 @@ import org.geysermc.mcprotocollib.protocol.data.game.item.component.HolderSet; import org.geysermc.mcprotocollib.protocol.data.game.item.component.ItemAttributeModifiers; -import java.text.DecimalFormat; -import java.util.ArrayList; -import java.util.EnumMap; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - public final class ItemTranslator { /** @@ -128,7 +127,7 @@ public static ItemStack translateToJava(GeyserSession session, ItemData data) { session.getGeyser().getLogger().debug("ItemMapping returned air: " + javaId); return ItemData.builder(); } - return translateToBedrock(session, Registries.JAVA_ITEMS.get().get(javaId), bedrockItem, count, components); + return translateToBedrock(session, Registries.javaItems().get().get(javaId), bedrockItem, count, components); } @NonNull @@ -143,7 +142,7 @@ public static ItemData translateToBedrock(GeyserSession session, ItemStack stack return ItemData.AIR; } // Java item needs to be loaded separately. The mapping for tipped arrow would - return translateToBedrock(session, Registries.JAVA_ITEMS.get().get(stack.getId()), bedrockItem, stack.getAmount(), stack.getDataComponents()) + return translateToBedrock(session, Registries.javaItems().get().get(stack.getId()), bedrockItem, stack.getAmount(), stack.getDataComponents()) .build(); } diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/BiomeTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/BiomeTranslator.java index 166089b6baf..2213f6b04d9 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/BiomeTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/BiomeTranslator.java @@ -25,12 +25,6 @@ package org.geysermc.geyser.translator.level; -import org.geysermc.mcprotocollib.protocol.data.game.RegistryEntry; -import org.geysermc.mcprotocollib.protocol.data.game.chunk.BitStorage; -import org.geysermc.mcprotocollib.protocol.data.game.chunk.DataPalette; -import org.geysermc.mcprotocollib.protocol.data.game.chunk.palette.GlobalPalette; -import org.geysermc.mcprotocollib.protocol.data.game.chunk.palette.Palette; -import org.geysermc.mcprotocollib.protocol.data.game.chunk.palette.SingletonPalette; import it.unimi.dsi.fastutil.ints.IntArrayList; import it.unimi.dsi.fastutil.ints.IntList; import it.unimi.dsi.fastutil.ints.IntLists; @@ -40,13 +34,19 @@ import org.geysermc.geyser.level.chunk.bitarray.SingletonBitArray; import org.geysermc.geyser.registry.Registries; import org.geysermc.geyser.session.GeyserSession; +import org.geysermc.mcprotocollib.protocol.data.game.RegistryEntry; +import org.geysermc.mcprotocollib.protocol.data.game.chunk.BitStorage; +import org.geysermc.mcprotocollib.protocol.data.game.chunk.DataPalette; +import org.geysermc.mcprotocollib.protocol.data.game.chunk.palette.GlobalPalette; +import org.geysermc.mcprotocollib.protocol.data.game.chunk.palette.Palette; +import org.geysermc.mcprotocollib.protocol.data.game.chunk.palette.SingletonPalette; // Array index formula by https://wiki.vg/Chunk_Format public class BiomeTranslator { public static int loadServerBiome(RegistryEntry entry) { String javaIdentifier = entry.getId().asString(); - return Registries.BIOME_IDENTIFIERS.get().getOrDefault(javaIdentifier, 0); + return Registries.biomeIdentifiers().get().getOrDefault(javaIdentifier, 0); } public static BlockStorage toNewBedrockBiome(GeyserSession session, DataPalette biomeData) { diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/SpawnerBlockEntityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/SpawnerBlockEntityTranslator.java index 14f706f2789..62e27362ba9 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/SpawnerBlockEntityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/SpawnerBlockEntityTranslator.java @@ -118,7 +118,7 @@ private static void translateSpawnData(@NonNull NbtMapBuilder builder, @Nullable // As of 1.19.3, spawners can be empty builder.put("EntityIdentifier", entityId); - EntityDefinition definition = Registries.JAVA_ENTITY_IDENTIFIERS.get(entityId); + EntityDefinition definition = Registries.javaEntityIdentifiers().get(entityId); if (definition != null) { builder.putFloat("DisplayEntityWidth", definition.width()); builder.putFloat("DisplayEntityHeight", definition.height()); diff --git a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/TrialSpawnerBlockEntityTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/TrialSpawnerBlockEntityTranslator.java index 25925a89b5f..303bd3a2752 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/TrialSpawnerBlockEntityTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/level/block/entity/TrialSpawnerBlockEntityTranslator.java @@ -47,7 +47,7 @@ public void translateTag(GeyserSession session, NbtMapBuilder bedrockNbt, NbtMap return; } NbtMapBuilder spawnData = NbtMap.builder(); - EntityDefinition definition = Registries.JAVA_ENTITY_IDENTIFIERS.get(entityData.getString("id")); + EntityDefinition definition = Registries.javaEntityIdentifiers().get(entityData.getString("id")); if (definition != null) { spawnData.putString("TypeId", definition.identifier()); } diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaCommandsTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaCommandsTranslator.java index f189658cd82..4bda5e36bb3 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaCommandsTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaCommandsTranslator.java @@ -32,12 +32,29 @@ import it.unimi.dsi.fastutil.ints.IntOpenHashSet; import it.unimi.dsi.fastutil.ints.IntSet; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenCustomHashMap; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.EnumSet; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Set; +import java.util.function.Supplier; import lombok.Getter; import lombok.ToString; import net.kyori.adventure.key.Key; import net.kyori.adventure.text.format.NamedTextColor; import org.checkerframework.checker.nullness.qual.MonotonicNonNull; -import org.cloudburstmc.protocol.bedrock.data.command.*; +import org.cloudburstmc.protocol.bedrock.data.command.CommandData; +import org.cloudburstmc.protocol.bedrock.data.command.CommandEnumConstraint; +import org.cloudburstmc.protocol.bedrock.data.command.CommandEnumData; +import org.cloudburstmc.protocol.bedrock.data.command.CommandOverloadData; +import org.cloudburstmc.protocol.bedrock.data.command.CommandParam; +import org.cloudburstmc.protocol.bedrock.data.command.CommandParamData; +import org.cloudburstmc.protocol.bedrock.data.command.CommandPermission; import org.cloudburstmc.protocol.bedrock.packet.AvailableCommandsPacket; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.api.event.java.ServerDefineCommandsEvent; @@ -55,9 +72,6 @@ import org.geysermc.mcprotocollib.protocol.data.game.entity.attribute.AttributeType; import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.ClientboundCommandsPacket; -import java.util.*; -import java.util.function.Supplier; - @SuppressWarnings("removal") // We know. This is our doing. @Translator(packet = ClientboundCommandsPacket.class) public class JavaCommandsTranslator extends PacketTranslator { @@ -360,14 +374,14 @@ private String[] getEntityTypes() { if (entityTypes != null) { return entityTypes; } - return (entityTypes = Registries.JAVA_ENTITY_IDENTIFIERS.get().keySet().toArray(new String[0])); + return (entityTypes = Registries.javaEntityIdentifiers().get().keySet().toArray(new String[0])); } public String[] getItemNames() { if (itemNames != null) { return itemNames; } - return (itemNames = Registries.JAVA_ITEM_IDENTIFIERS.get().keySet().toArray(new String[0])); + return (itemNames = Registries.javaItemIdentifiers().get().keySet().toArray(new String[0])); } private CommandEnumData getTeams() { diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaUpdateRecipesTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaUpdateRecipesTranslator.java index 689e0448a02..4ae30dd5e4e 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaUpdateRecipesTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/JavaUpdateRecipesTranslator.java @@ -25,11 +25,25 @@ package org.geysermc.geyser.translator.protocol.java; +import static org.geysermc.geyser.util.InventoryUtils.LAST_RECIPE_NET_ID; + import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import it.unimi.dsi.fastutil.ints.Int2ObjectOpenHashMap; import it.unimi.dsi.fastutil.ints.IntIterator; import it.unimi.dsi.fastutil.ints.IntOpenHashSet; import it.unimi.dsi.fastutil.ints.IntSet; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Set; +import java.util.UUID; +import java.util.stream.Collectors; import lombok.AllArgsConstructor; import lombok.EqualsAndHashCode; import org.cloudburstmc.protocol.bedrock.data.definitions.ItemDefinition; @@ -68,21 +82,6 @@ import org.geysermc.mcprotocollib.protocol.data.game.recipe.data.StoneCuttingRecipeData; import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.ClientboundUpdateRecipesPacket; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.Comparator; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Objects; -import java.util.Set; -import java.util.UUID; -import java.util.stream.Collectors; - -import static org.geysermc.geyser.util.InventoryUtils.LAST_RECIPE_NET_ID; - /** * Used to send all valid recipes from Java to Bedrock. *

@@ -154,7 +153,7 @@ public void translate(GeyserSession session, ClientboundUpdateRecipesPacket pack if (stoneCuttingData.getIngredient().getOptions().length == 0) { if (GeyserImpl.getInstance().getConfig().isDebugMode()) { GeyserImpl.getInstance().getLogger().debug("Received broken stone cutter recipe: " + stoneCuttingData + " " + - recipe.getIdentifier() + " " + Registries.JAVA_ITEMS.get().get(stoneCuttingData.getResult().getId()).javaIdentifier()); + recipe.getIdentifier() + " " + Registries.javaItems().get().get(stoneCuttingData.getResult().getId()).javaIdentifier()); } continue; } @@ -215,7 +214,7 @@ public void translate(GeyserSession session, ClientboundUpdateRecipesPacket pack craftingDataPacket.getCraftingData().add(MultiRecipeData.of(UUID.fromString("00000000-0000-0000-0000-000000000002"), context.getAndIncrementNetId())); } default -> { - List recipes = Registries.RECIPES.get(recipe.getType()); + List recipes = Registries.recipes().get(recipe.getType()); if (recipes != null) { List bedrockRecipeIds = new ArrayList<>(); if (recipe.getType() == RecipeType.CRAFTING_SPECIAL_TIPPEDARROW) { @@ -247,14 +246,14 @@ public void translate(GeyserSession session, ClientboundUpdateRecipesPacket pack } } craftingDataPacket.getCraftingData().addAll(CARTOGRAPHY_RECIPES); - craftingDataPacket.getPotionMixData().addAll(Registries.POTION_MIXES.forVersion(session.getUpstream().getProtocolVersion())); + craftingDataPacket.getPotionMixData().addAll(Registries.potionMixes().forVersion(session.getUpstream().getProtocolVersion())); Int2ObjectMap stonecutterRecipeMap = new Int2ObjectOpenHashMap<>(); for (Int2ObjectMap.Entry> data : unsortedStonecutterData.int2ObjectEntrySet()) { // Sort the list by each output item's Java identifier - this is how it's sorted on Java, and therefore // We can get the correct order for button pressing data.getValue().sort(Comparator.comparing((stoneCuttingRecipeData -> - Registries.JAVA_ITEMS.get().get(stoneCuttingRecipeData.getResult().getId()) + Registries.javaItems().get().get(stoneCuttingRecipeData.getResult().getId()) // See RecipeManager#getRecipesFor as of 1.21 .translationKey()))); @@ -452,7 +451,7 @@ List translateShulkerBoxRecipe(GeyserShapelessRecipe recipe) { return null; } - Item javaItem = Registries.JAVA_ITEMS.get(result.getId()); + Item javaItem = Registries.javaItems().get(result.getId()); if (!(javaItem instanceof BedrockRequiresTagItem)) { // Strip NBT - tools won't appear in the recipe book otherwise output = output.toBuilder().tag(null).build(); @@ -481,7 +480,7 @@ List translateShapelessRecipe(GeyserShapelessRecipe recipe) { return null; } - Item javaItem = Registries.JAVA_ITEMS.get(result.getId()); + Item javaItem = Registries.javaItems().get(result.getId()); if (!(javaItem instanceof BedrockRequiresTagItem)) { // Strip NBT - tools won't appear in the recipe book otherwise output = output.toBuilder().tag(null).build(); @@ -510,7 +509,7 @@ List translateShapedRecipe(GeyserShapedRecipe recipe) { return null; } - Item javaItem = Registries.JAVA_ITEMS.get(result.getId()); + Item javaItem = Registries.javaItems().get(result.getId()); if (!(javaItem instanceof BedrockRequiresTagItem)) { // Strip NBT - tools won't appear in the recipe book otherwise output = output.toBuilder().tag(null).build(); 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 19f34db74b6..9e269296cce 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,10 @@ package org.geysermc.geyser.translator.protocol.java.entity.player; -import org.geysermc.mcprotocollib.auth.GameProfile; +import java.util.ArrayList; +import java.util.List; +import java.util.Set; +import java.util.UUID; import org.checkerframework.checker.nullness.qual.Nullable; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.packet.PlayerListPacket; @@ -35,15 +38,11 @@ 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; -import java.util.ArrayList; -import java.util.List; -import java.util.Set; -import java.util.UUID; - @Translator(packet = ClientboundPlayerInfoUpdatePacket.class) public class JavaPlayerInfoUpdateTranslator extends PacketTranslator { @Override @@ -95,8 +94,6 @@ public void translate(GeyserSession session, ClientboundPlayerInfoUpdatePacket p if (self) { SkinManager.requestAndHandleSkinAndCape(playerEntity, session, skinAndCape -> 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 572d233d03b..644ff4bb32d 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,13 +40,21 @@ 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 { @Override public void translate(GeyserSession session, ClientboundAddEntityPacket packet) { - EntityDefinition definition = Registries.ENTITY_DEFINITIONS.get(packet.getType()); + EntityDefinition definition = Registries.entityDefinitions().get(packet.getType()); if (definition == null) { session.getGeyser().getLogger().debug("Could not find an entity definition with type " + packet.getType()); return; @@ -83,10 +88,13 @@ public void translate(GeyserSession session, ClientboundAddEntityPacket packet) entity.setHeadYaw(headYaw); entity.setMotion(motion); } - session.getEntityCache().cacheEntity(entity); entity.sendPlayer(); - SkinManager.requestAndHandleSkinAndCape(entity, session, null); + // only load skin if we're not in a test environment. + // Otherwise, it tries to load various resources + if (!EnvironmentUtils.IS_UNIT_TESTING) { + SkinManager.requestAndHandleSkinAndCape(entity, session, null); + } return; } diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/inventory/JavaMerchantOffersTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/inventory/JavaMerchantOffersTranslator.java index 97006143672..6ecf2dc845d 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/inventory/JavaMerchantOffersTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/inventory/JavaMerchantOffersTranslator.java @@ -25,9 +25,8 @@ package org.geysermc.geyser.translator.protocol.java.inventory; -import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack; -import org.geysermc.mcprotocollib.protocol.data.game.inventory.VillagerTrade; -import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.inventory.ClientboundMerchantOffersPacket; +import java.util.ArrayList; +import java.util.List; import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.nbt.NbtMapBuilder; import org.cloudburstmc.nbt.NbtType; @@ -46,9 +45,9 @@ import org.geysermc.geyser.translator.protocol.Translator; import org.geysermc.geyser.util.InventoryUtils; import org.geysermc.geyser.util.MathUtils; - -import java.util.ArrayList; -import java.util.List; +import org.geysermc.mcprotocollib.protocol.data.game.inventory.VillagerTrade; +import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.inventory.ClientboundMerchantOffersPacket; @Translator(packet = ClientboundMerchantOffersPacket.class) public class JavaMerchantOffersTranslator extends PacketTranslator { @@ -173,7 +172,7 @@ private static NbtMap getItemTag(GeyserSession session, ItemStack stack, int spe // Bedrock expects all price adjustments to be applied to the item's count int count = stack.getAmount() + ((int) Math.max(Math.floor(stack.getAmount() * demand * priceMultiplier), 0)) + specialPrice; - count = MathUtils.constrain(count, 1, Registries.JAVA_ITEMS.get().get(stack.getId()).maxStackSize()); + count = MathUtils.constrain(count, 1, Registries.javaItems().get().get(stack.getId()).maxStackSize()); return getItemTag(session, stack, mapping, count); } diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaCooldownTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaCooldownTranslator.java index 6366716514a..a68d2d9812c 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaCooldownTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaCooldownTranslator.java @@ -25,7 +25,6 @@ package org.geysermc.geyser.translator.protocol.java.level; -import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.ClientboundCooldownPacket; import org.cloudburstmc.protocol.bedrock.packet.PlayerStartItemCooldownPacket; import org.geysermc.geyser.item.Items; import org.geysermc.geyser.item.type.Item; @@ -33,13 +32,14 @@ import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.ClientboundCooldownPacket; @Translator(packet = ClientboundCooldownPacket.class) public class JavaCooldownTranslator extends PacketTranslator { @Override public void translate(GeyserSession session, ClientboundCooldownPacket packet) { - Item item = Registries.JAVA_ITEMS.get().get(packet.getItemId()); + Item item = Registries.javaItems().get().get(packet.getItemId()); // Not every item, as of 1.19, appears to be server-driven. Just these two. // Use a map here if it gets too big. String cooldownCategory; diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaLevelEventTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaLevelEventTranslator.java index 5b4ff1de749..a915cb4c5f8 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaLevelEventTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaLevelEventTranslator.java @@ -25,6 +25,11 @@ package org.geysermc.geyser.translator.protocol.java.level; +import java.util.Collections; +import java.util.Optional; +import java.util.Random; +import java.util.Set; +import java.util.concurrent.ThreadLocalRandom; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.math.vector.Vector3i; import org.cloudburstmc.nbt.NbtMap; @@ -62,12 +67,6 @@ import org.geysermc.mcprotocollib.protocol.data.game.level.event.UnknownLevelEventData; import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.level.ClientboundLevelEventPacket; -import java.util.Collections; -import java.util.Optional; -import java.util.Random; -import java.util.Set; -import java.util.concurrent.ThreadLocalRandom; - @Translator(packet = ClientboundLevelEventPacket.class) public class JavaLevelEventTranslator extends PacketTranslator { @@ -87,7 +86,7 @@ public void translate(GeyserSession session, ClientboundLevelEventPacket packet) Vector3f pos = Vector3f.from(origin.getX() + 0.5f, origin.getY() + 0.5f, origin.getZ() + 0.5f); // Prioritize level events because it makes parrots dance. - SoundMapping mapping = Registries.SOUNDS.get(jukeboxSong.soundEvent().replace("minecraft:", "")); + SoundMapping mapping = Registries.sounds().get(jukeboxSong.soundEvent().replace("minecraft:", "")); SoundEvent soundEvent = null; if (mapping != null) { String bedrock = mapping.getBedrock(); @@ -133,7 +132,7 @@ public void translate(GeyserSession session, ClientboundLevelEventPacket packet) } // Check for a sound event translator - LevelEventTranslator transformer = Registries.SOUND_LEVEL_EVENTS.get(packet.getEvent()); + LevelEventTranslator transformer = Registries.soundLevelEvents().get(packet.getEvent()); if (transformer != null) { transformer.translate(session, packet); return; diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaLevelParticlesTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaLevelParticlesTranslator.java index 65f84a59598..57449db00c4 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaLevelParticlesTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaLevelParticlesTranslator.java @@ -25,18 +25,13 @@ package org.geysermc.geyser.translator.protocol.java.level; -import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack; -import org.geysermc.mcprotocollib.protocol.data.game.level.particle.BlockParticleData; -import org.geysermc.mcprotocollib.protocol.data.game.level.particle.DustParticleData; -import org.geysermc.mcprotocollib.protocol.data.game.level.particle.ItemParticleData; -import org.geysermc.mcprotocollib.protocol.data.game.level.particle.Particle; -import org.geysermc.mcprotocollib.protocol.data.game.level.particle.VibrationParticleData; -import org.geysermc.mcprotocollib.protocol.data.game.level.particle.positionsource.BlockPositionSource; -import org.geysermc.mcprotocollib.protocol.data.game.level.particle.positionsource.EntityPositionSource; -import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.level.ClientboundLevelParticlesPacket; +import java.util.Optional; +import java.util.Random; +import java.util.concurrent.ThreadLocalRandom; +import java.util.function.Function; import org.checkerframework.checker.nullness.qual.Nullable; -import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.math.vector.Vector3f; +import org.cloudburstmc.nbt.NbtMap; import org.cloudburstmc.protocol.bedrock.data.LevelEvent; import org.cloudburstmc.protocol.bedrock.data.ParticleType; import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData; @@ -52,11 +47,15 @@ import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; import org.geysermc.geyser.util.DimensionUtils; - -import java.util.Optional; -import java.util.Random; -import java.util.concurrent.ThreadLocalRandom; -import java.util.function.Function; +import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack; +import org.geysermc.mcprotocollib.protocol.data.game.level.particle.BlockParticleData; +import org.geysermc.mcprotocollib.protocol.data.game.level.particle.DustParticleData; +import org.geysermc.mcprotocollib.protocol.data.game.level.particle.ItemParticleData; +import org.geysermc.mcprotocollib.protocol.data.game.level.particle.Particle; +import org.geysermc.mcprotocollib.protocol.data.game.level.particle.VibrationParticleData; +import org.geysermc.mcprotocollib.protocol.data.game.level.particle.positionsource.BlockPositionSource; +import org.geysermc.mcprotocollib.protocol.data.game.level.particle.positionsource.EntityPositionSource; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.level.ClientboundLevelParticlesPacket; @Translator(packet = ClientboundLevelParticlesPacket.class) public class JavaLevelParticlesTranslator extends PacketTranslator { @@ -178,7 +177,7 @@ public void translate(GeyserSession session, ClientboundLevelParticlesPacket pac }; } default -> { - ParticleMapping particleMapping = Registries.PARTICLES.get(particle.getType()); + ParticleMapping particleMapping = Registries.particles().get(particle.getType()); if (particleMapping == null) { //TODO ensure no particle can be null return null; } diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/scoreboard/JavaSetDisplayObjectiveTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/scoreboard/JavaSetDisplayObjectiveTranslator.java index 4ce971cdf20..241c54cba7a 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/scoreboard/JavaSetDisplayObjectiveTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/scoreboard/JavaSetDisplayObjectiveTranslator.java @@ -25,13 +25,13 @@ package org.geysermc.geyser.translator.protocol.java.scoreboard; -import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.scoreboard.ClientboundSetDisplayObjectivePacket; import org.geysermc.geyser.scoreboard.Scoreboard; import org.geysermc.geyser.scoreboard.ScoreboardUpdater; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.cache.WorldCache; import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.Translator; +import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.scoreboard.ClientboundSetDisplayObjectivePacket; @Translator(packet = ClientboundSetDisplayObjectivePacket.class) public class JavaSetDisplayObjectiveTranslator extends PacketTranslator { diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/scoreboard/JavaSetPlayerTeamTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/scoreboard/JavaSetPlayerTeamTranslator.java index 3a1ee63739d..5118ee715b5 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/scoreboard/JavaSetPlayerTeamTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/scoreboard/JavaSetPlayerTeamTranslator.java @@ -25,7 +25,6 @@ package org.geysermc.geyser.translator.protocol.java.scoreboard; -import java.util.Arrays; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.GeyserLogger; import org.geysermc.geyser.scoreboard.Scoreboard; @@ -43,10 +42,6 @@ public class JavaSetPlayerTeamTranslator extends PacketTranslator> interactionEntry : Registries.SOUND_TRANSLATORS.get().entrySet()) { + for (Map.Entry> interactionEntry : Registries.soundTranslators().get().entrySet()) { if (!(interactionEntry.getValue() instanceof BlockSoundInteractionTranslator)) { continue; } diff --git a/core/src/main/java/org/geysermc/geyser/util/BlockEntityUtils.java b/core/src/main/java/org/geysermc/geyser/util/BlockEntityUtils.java index 1462378e91f..9df0b0da53a 100644 --- a/core/src/main/java/org/geysermc/geyser/util/BlockEntityUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/BlockEntityUtils.java @@ -25,6 +25,8 @@ package org.geysermc.geyser.util; +import java.util.Locale; +import java.util.Map; import org.checkerframework.checker.nullness.qual.NonNull; import org.cloudburstmc.math.vector.Vector3i; import org.cloudburstmc.nbt.NbtMap; @@ -34,9 +36,6 @@ import org.geysermc.geyser.translator.level.block.entity.BlockEntityTranslator; import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType; -import java.util.Locale; -import java.util.Map; - public class BlockEntityUtils { /** * Contains a list of irregular block entity name translations that can't be fit into the regex @@ -68,7 +67,7 @@ public static String getBedrockBlockEntityId(BlockEntityType type) { } public static BlockEntityTranslator getBlockEntityTranslator(BlockEntityType type) { - return Registries.BLOCK_ENTITIES.get(type); + return Registries.blockEntities().get(type); } public static void updateBlockEntity(GeyserSession session, @NonNull NbtMap blockEntity, Vector3i position) { 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 8e5a57fae56..f8b20fbc40c 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 static GameType toBedrockGamemode(GameMode gamemode) { 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 909398bf4d8..35a1a1e8fdf 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/main/java/org/geysermc/geyser/util/InventoryUtils.java b/core/src/main/java/org/geysermc/geyser/util/InventoryUtils.java index a0bd5a4c7a5..507576da026 100644 --- a/core/src/main/java/org/geysermc/geyser/util/InventoryUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/InventoryUtils.java @@ -25,6 +25,12 @@ package org.geysermc.geyser.util; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.Objects; +import java.util.concurrent.TimeUnit; +import java.util.function.IntFunction; import org.checkerframework.checker.nullness.qual.Nullable; import org.cloudburstmc.math.vector.Vector3i; import org.cloudburstmc.nbt.NbtMap; @@ -38,7 +44,11 @@ import org.cloudburstmc.protocol.bedrock.packet.InventorySlotPacket; import org.cloudburstmc.protocol.bedrock.packet.PlayerHotbarPacket; import org.geysermc.geyser.GeyserImpl; -import org.geysermc.geyser.inventory.*; +import org.geysermc.geyser.inventory.Container; +import org.geysermc.geyser.inventory.GeyserItemStack; +import org.geysermc.geyser.inventory.Inventory; +import org.geysermc.geyser.inventory.LecternContainer; +import org.geysermc.geyser.inventory.PlayerInventory; import org.geysermc.geyser.inventory.click.Click; import org.geysermc.geyser.inventory.recipe.GeyserRecipe; import org.geysermc.geyser.inventory.recipe.GeyserShapedRecipe; @@ -64,13 +74,6 @@ import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.inventory.ServerboundSetCreativeModeSlotPacket; import org.jetbrains.annotations.Contract; -import java.util.Arrays; -import java.util.Collections; -import java.util.HashMap; -import java.util.Objects; -import java.util.concurrent.TimeUnit; -import java.util.function.IntFunction; - public class InventoryUtils { /** * Stores the last used recipe network ID. Since 1.16.200 (and for server-authoritative inventories), @@ -238,7 +241,7 @@ public static IntFunction createUnusableSpaceBlock(String description) } private static ItemDefinition getUnusableSpaceBlockDefinition(int protocolVersion) { - ItemMappings mappings = Registries.ITEMS.forVersion(protocolVersion); + ItemMappings mappings = Registries.items().forVersion(protocolVersion); String unusableSpaceBlock = GeyserImpl.getInstance().getConfig().getUnusableSpaceBlock(); ItemDefinition itemDefinition = mappings.getDefinition(unusableSpaceBlock); @@ -252,13 +255,13 @@ private static ItemDefinition getUnusableSpaceBlockDefinition(int protocolVersio public static IntFunction getUpgradeTemplate() { return protocolVersion -> ItemData.builder() - .definition(Registries.ITEMS.forVersion(protocolVersion).getStoredItems().upgradeTemplate().getBedrockDefinition()) + .definition(Registries.items().forVersion(protocolVersion).getStoredItems().upgradeTemplate().getBedrockDefinition()) .count(1).build(); } public static IntFunction getTotemOfUndying() { return protocolVersion -> ItemData.builder() - .definition(Registries.ITEMS.forVersion(protocolVersion).getStoredItems().totem().getBedrockDefinition()) + .definition(Registries.items().forVersion(protocolVersion).getStoredItems().totem().getBedrockDefinition()) .count(1).build(); } @@ -317,7 +320,7 @@ public static void findOrCreateItem(GeyserSession session, ItemStack itemStack) // Please remove!!! public static void findOrCreateItem(GeyserSession session, String itemName) { - findOrCreateItem(session, Registries.JAVA_ITEM_IDENTIFIERS.getOrDefault(itemName, Items.AIR)); + findOrCreateItem(session, Registries.javaItemIdentifiers().getOrDefault(itemName, Items.AIR)); } /** diff --git a/core/src/main/java/org/geysermc/geyser/util/SoundUtils.java b/core/src/main/java/org/geysermc/geyser/util/SoundUtils.java index 693ce136acc..b4311b264e8 100644 --- a/core/src/main/java/org/geysermc/geyser/util/SoundUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/SoundUtils.java @@ -25,6 +25,7 @@ package org.geysermc.geyser.util; +import java.util.Locale; import org.checkerframework.checker.nullness.qual.Nullable; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.LevelEvent; @@ -40,8 +41,6 @@ import org.geysermc.geyser.session.GeyserSession; import org.geysermc.mcprotocollib.protocol.data.game.level.sound.Sound; -import java.util.Locale; - public final class SoundUtils { /** @@ -67,7 +66,7 @@ public final class SoundUtils { */ public static String translatePlaySound(String javaIdentifier) { String soundIdentifier = removeMinecraftNamespace(javaIdentifier); - SoundMapping soundMapping = Registries.SOUNDS.get(soundIdentifier); + SoundMapping soundMapping = Registries.sounds().get(soundIdentifier); if (soundMapping == null || soundMapping.getPlaysound() == null) { // no mapping GeyserImpl.getInstance().getLogger().debug("[PlaySound] Defaulting to sound server gave us for " + javaIdentifier); @@ -104,7 +103,7 @@ private static void playSound(GeyserSession session, String bedrockName, Vector3 public static void playSound(GeyserSession session, Sound javaSound, Vector3f position, float volume, float pitch) { String soundIdentifier = removeMinecraftNamespace(javaSound.getName()); - SoundMapping soundMapping = Registries.SOUNDS.get(soundIdentifier); + SoundMapping soundMapping = Registries.sounds().get(soundIdentifier); if (soundMapping == null) { session.getGeyser().getLogger().debug("[Builtin] Sound mapping for " + soundIdentifier + " not found; assuming custom."); playSound(session, soundIdentifier, position, volume, pitch); diff --git a/core/src/main/java/org/geysermc/geyser/util/StatisticsUtils.java b/core/src/main/java/org/geysermc/geyser/util/StatisticsUtils.java index 9847c0cfc0e..61c854e1285 100644 --- a/core/src/main/java/org/geysermc/geyser/util/StatisticsUtils.java +++ b/core/src/main/java/org/geysermc/geyser/util/StatisticsUtils.java @@ -26,6 +26,12 @@ package org.geysermc.geyser.util; import it.unimi.dsi.fastutil.objects.Object2IntMap; +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; +import java.util.function.IntFunction; +import java.util.regex.Matcher; +import java.util.regex.Pattern; import org.geysermc.cumulus.form.SimpleForm; import org.geysermc.cumulus.util.FormImage; import org.geysermc.geyser.item.type.Item; @@ -35,14 +41,16 @@ import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.text.GeyserLocale; import org.geysermc.geyser.text.MinecraftLocale; -import org.geysermc.mcprotocollib.protocol.data.game.statistic.*; - -import java.util.ArrayList; -import java.util.List; -import java.util.Locale; -import java.util.function.IntFunction; -import java.util.regex.Matcher; -import java.util.regex.Pattern; +import org.geysermc.mcprotocollib.protocol.data.game.statistic.BreakBlockStatistic; +import org.geysermc.mcprotocollib.protocol.data.game.statistic.BreakItemStatistic; +import org.geysermc.mcprotocollib.protocol.data.game.statistic.CraftItemStatistic; +import org.geysermc.mcprotocollib.protocol.data.game.statistic.CustomStatistic; +import org.geysermc.mcprotocollib.protocol.data.game.statistic.DropItemStatistic; +import org.geysermc.mcprotocollib.protocol.data.game.statistic.KillEntityStatistic; +import org.geysermc.mcprotocollib.protocol.data.game.statistic.KilledByEntityStatistic; +import org.geysermc.mcprotocollib.protocol.data.game.statistic.PickupItemStatistic; +import org.geysermc.mcprotocollib.protocol.data.game.statistic.Statistic; +import org.geysermc.mcprotocollib.protocol.data.game.statistic.UseItemStatistic; public class StatisticsUtils { private static final Pattern CONTENT_PATTERN = Pattern.compile("^\\S+:", Pattern.MULTILINE); @@ -76,7 +84,7 @@ public static void buildAndSendStatisticsMenu(GeyserSession session) { List content = new ArrayList<>(); - List itemRegistry = Registries.JAVA_ITEMS.get(); + List itemRegistry = Registries.javaItems().get(); switch (response.clickedButtonId()) { case 0: builder.title("stat.generalButton"); 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 523e4dca2a2..2a72269a2c9 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 @@ -64,12 +64,12 @@ void playerVisibilityNever() { new String[]{"player1"} ) ); - assertNextPacket(() -> { + assertNextPacket(context, () -> { var packet = new SetEntityDataPacket(); packet.setRuntimeEntityId(2); packet.getMetadata().put(EntityDataTypes.NAME, ""); return packet; - }, context); + }); }); } @@ -96,12 +96,12 @@ void playerVisibilityHideForOtherTeam() { ) ); // 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 @@ void playerVisibilityHideForOtherTeam() { ) ); // 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 @@ void playerVisibilityHideForOtherTeam() { 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); + }); }); } @@ -166,12 +166,12 @@ void playerVisibilityHideForOwnTeam() { ) ); // 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 @@ void playerVisibilityHideForOwnTeam() { 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 @@ void playerVisibilityHideForOwnTeam() { 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); + }); }); } @@ -234,12 +234,12 @@ void playerVisibilityAlways() { 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 1ec245007f2..99c2533d7d8 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,57 @@ 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 java.util.EnumSet; +import java.util.Optional; +import java.util.UUID; +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; /** - * 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 +124,136 @@ void entityWithoutType() { }); }); } + + /** + * 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()); + }); + + // 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 5d8d8309fd3..a23b684aecb 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 @@ -98,12 +98,12 @@ void displayColorWithOnePlayer() { 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); + }); }); } @@ -131,24 +131,24 @@ void displayWithOnePlayerAndRemove() { 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); + }); }); } @@ -186,42 +186,42 @@ void overrideAndRemove() { 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 a3d4ad671f3..4ac5ee0980f 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 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 @@ void display() { setDisplayObjectiveTranslator, new ClientboundSetDisplayObjectivePacket(ScoreboardPosition.PLAYER_LIST, "objective") ); - assertNextPacket(() -> { + assertNextPacket(context, () -> { var packet = new SetDisplayObjectivePacket(); packet.setObjectiveId("0"); packet.setDisplayName("objective"); @@ -83,7 +82,7 @@ void display() { packet.setDisplaySlot("list"); packet.setSortOrder(1); return packet; - }, context); + }); }); } @@ -98,7 +97,7 @@ void displayNameColors() { 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 @@ void displayNameColors() { 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 @@ void displayNameColors() { packet.setDisplaySlot("list"); packet.setSortOrder(1); return packet; - }, context); + }); }); } @@ -156,7 +155,7 @@ void overrideWithOneScore() { setDisplayObjectiveTranslator, new ClientboundSetDisplayObjectivePacket(ScoreboardPosition.PLAYER_LIST, "objective2") ); - assertNextPacket(() -> { + assertNextPacket(context, () -> { var packet = new SetDisplayObjectivePacket(); packet.setObjectiveId("0"); packet.setDisplayName("objective2"); @@ -164,26 +163,26 @@ void overrideWithOneScore() { 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 @@ void overrideWithOneScore() { 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 dd693022cf7..365c2713329 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 @@ -33,7 +33,6 @@ 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; @@ -88,7 +87,7 @@ void test() { setDisplayObjectiveTranslator, new ClientboundSetDisplayObjectivePacket(ScoreboardPosition.SIDEBAR, "sidebar") ); - assertNextPacket(() -> { + assertNextPacket(context, () -> { var packet = new SetDisplayObjectivePacket(); packet.setObjectiveId("0"); packet.setDisplayName("sidebar"); @@ -96,7 +95,7 @@ void test() { 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 +190,23 @@ void test() { 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 +229,7 @@ void test() { 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 +239,12 @@ void test() { 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 +280,12 @@ void test() { 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 +321,12 @@ void test() { 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 +359,12 @@ void test() { 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 +397,12 @@ void test() { 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 +435,12 @@ void test() { 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 +476,12 @@ void test() { 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 +517,12 @@ void test() { 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 +555,12 @@ void test() { 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 +593,12 @@ void test() { 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 +631,12 @@ void test() { 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. @@ -673,84 +646,68 @@ void test() { // 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); + assertNextPacket(context, () -> { + var packet = new SetEntityDataPacket(); + packet.setRuntimeEntityId(2); + packet.getMetadata().put(EntityDataTypes.NAME, ""); + return packet; + }); mockAndAddPlayerEntity(context, "B_Player", 3); - assertNextPacket( - () -> { - var packet = new SetEntityDataPacket(); - packet.setRuntimeEntityId(3); - packet.getMetadata().put(EntityDataTypes.NAME, ""); - return packet; - }, - context); + assertNextPacket(context, () -> { + var packet = new SetEntityDataPacket(); + packet.setRuntimeEntityId(3); + packet.getMetadata().put(EntityDataTypes.NAME, ""); + return packet; + }); mockAndAddPlayerEntity(context, "E_Player", 4); - assertNextPacket( - () -> { - var packet = new SetEntityDataPacket(); - packet.setRuntimeEntityId(4); - packet.getMetadata().put(EntityDataTypes.NAME, ""); - return packet; - }, - context); + assertNextPacket(context, () -> { + var packet = new SetEntityDataPacket(); + packet.setRuntimeEntityId(4); + packet.getMetadata().put(EntityDataTypes.NAME, ""); + return packet; + }); mockAndAddPlayerEntity(context, "H_Player", 5); - assertNextPacket( - () -> { - var packet = new SetEntityDataPacket(); - packet.setRuntimeEntityId(5); - packet.getMetadata().put(EntityDataTypes.NAME, ""); - return packet; - }, - context); + assertNextPacket(context, () -> { + var packet = new SetEntityDataPacket(); + packet.setRuntimeEntityId(5); + packet.getMetadata().put(EntityDataTypes.NAME, ""); + return packet; + }); mockAndAddPlayerEntity(context, "J_Player", 6); - assertNextPacket( - () -> { - var packet = new SetEntityDataPacket(); - packet.setRuntimeEntityId(6); - packet.getMetadata().put(EntityDataTypes.NAME, ""); - return packet; - }, - context); + assertNextPacket(context, () -> { + var packet = new SetEntityDataPacket(); + packet.setRuntimeEntityId(6); + packet.getMetadata().put(EntityDataTypes.NAME, ""); + return packet; + }); mockAndAddPlayerEntity(context, "K_Player", 7); - assertNextPacket( - () -> { - var packet = new SetEntityDataPacket(); - packet.setRuntimeEntityId(7); - packet.getMetadata().put(EntityDataTypes.NAME, ""); - return packet; - }, - context); + assertNextPacket(context, () -> { + var packet = new SetEntityDataPacket(); + packet.setRuntimeEntityId(7); + packet.getMetadata().put(EntityDataTypes.NAME, ""); + return packet; + }); mockAndAddPlayerEntity(context, "L_Player", 8); - assertNextPacket( - () -> { - var packet = new SetEntityDataPacket(); - packet.setRuntimeEntityId(8); - packet.getMetadata().put(EntityDataTypes.NAME, ""); - return packet; - }, - context); + assertNextPacket(context, () -> { + var packet = new SetEntityDataPacket(); + packet.setRuntimeEntityId(8); + packet.getMetadata().put(EntityDataTypes.NAME, ""); + return packet; + }); mockAndAddPlayerEntity(context, "O_Player", 9); - assertNextPacket( - () -> { - var packet = new SetEntityDataPacket(); - packet.setRuntimeEntityId(9); - packet.getMetadata().put(EntityDataTypes.NAME, ""); - return packet; - }, - context); + assertNextPacket(context, () -> { + var packet = new SetEntityDataPacket(); + packet.setRuntimeEntityId(9); + packet.getMetadata().put(EntityDataTypes.NAME, ""); + return packet; + }); }); } } 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 b3999303e32..bd0d64c80fb 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 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 @@ void displayAndRemove() { setDisplayObjectiveTranslator, new ClientboundSetDisplayObjectivePacket(ScoreboardPosition.PLAYER_LIST, "objective") ); - assertNextPacket(() -> { + assertNextPacket(context, () -> { var packet = new SetDisplayObjectivePacket(); packet.setObjectiveId("0"); packet.setDisplayName("objective"); @@ -83,17 +82,17 @@ void displayAndRemove() { 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 @@ void displayNameColors() { 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 @@ void displayNameColors() { setDisplayObjectiveTranslator, new ClientboundSetDisplayObjectivePacket(ScoreboardPosition.SIDEBAR, "objective") ); - assertNextPacket(() -> { + assertNextPacket(context, () -> { var packet = new SetDisplayObjectivePacket(); packet.setObjectiveId("0"); packet.setDisplayName("§b§lobjective"); @@ -127,7 +126,7 @@ void displayNameColors() { packet.setDisplaySlot("sidebar"); packet.setSortOrder(1); return packet; - }, context); + }); }); } @@ -170,7 +169,7 @@ void override() { new ClientboundSetDisplayObjectivePacket(ScoreboardPosition.SIDEBAR, "objective2") ); - assertNextPacket(() -> { + assertNextPacket(context, () -> { var packet = new SetDisplayObjectivePacket(); packet.setObjectiveId("0"); packet.setDisplayName("objective2"); @@ -178,13 +177,13 @@ void override() { 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 @@ void override() { 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 @@ void override() { 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 3e0be1c026e..aab837456e8 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 @@ void aboveDisplayLimit() { setDisplayObjectiveTranslator, new ClientboundSetDisplayObjectivePacket(ScoreboardPosition.SIDEBAR, "objective") ); - assertNextPacket(() -> { + assertNextPacket(context, () -> { var packet = new SetDisplayObjectivePacket(); packet.setObjectiveId("0"); packet.setDisplayName("objective"); @@ -106,8 +106,8 @@ void aboveDisplayLimit() { 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 @@ void aboveDisplayLimit() { new ScoreInfo(15, "0", 3, "c") )); return packet; - }, context); + }); assertNoNextPacket(context); // remove a score @@ -136,43 +136,43 @@ void aboveDisplayLimit() { 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 @@ void aboveDisplayLimit() { 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 @@ void aboveDisplayLimit() { 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 @@ void aboveDisplayLimit() { 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 @@ void aboveDisplayLimit() { 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 @@ void aboveDisplayLimit() { 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 @@ void aboveDisplayLimit() { 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 @@ void aboveDisplayLimit() { 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 @@ void aboveDisplayLimit() { new ScoreInfo(21, "0", 3, "c") )); return packet; - }, context); + }); }); } @@ -327,7 +327,7 @@ void aboveDisplayLimitWithTeam() { setDisplayObjectiveTranslator, new ClientboundSetDisplayObjectivePacket(ScoreboardPosition.SIDEBAR, "objective") ); - assertNextPacket(() -> { + assertNextPacket(context, () -> { var packet = new SetDisplayObjectivePacket(); packet.setObjectiveId("0"); packet.setDisplayName("objective"); @@ -335,8 +335,8 @@ void aboveDisplayLimitWithTeam() { 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 @@ void aboveDisplayLimitWithTeam() { new ScoreInfo(15, "0", 3, "c") )); return packet; - }, context); + }); assertNoNextPacket(context); // remove a score @@ -365,36 +365,36 @@ void aboveDisplayLimitWithTeam() { 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 @@ void aboveDisplayLimitWithTeam() { 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 @@ void aboveDisplayLimitWithTeam() { 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 @@ void aboveDisplayLimitWithTeam() { 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 @@ void aboveDisplayLimitWithTeam() { 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 @@ void aboveDisplayLimitWithTeam() { 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 @@ void aboveDisplayLimitWithTeam() { 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 @@ void aboveDisplayLimitWithTeam() { 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 @@ void aboveDisplayLimitWithTeam() { 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 @@ void aboveDisplayLimitWithTeam() { 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 @@ void aboveDisplayLimitWithTeam() { 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 0a02a58d9a7..f511f59c7ac 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 @@ void displayAndAddScore() { setDisplayObjectiveTranslator, new ClientboundSetDisplayObjectivePacket(ScoreboardPosition.SIDEBAR, "objective") ); - assertNextPacket(() -> { + assertNextPacket(context, () -> { var packet = new SetDisplayObjectivePacket(); packet.setObjectiveId("0"); packet.setDisplayName("objective"); @@ -77,16 +77,16 @@ void displayAndAddScore() { 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 @@ void displayAndChangeScoreValue() { setDisplayObjectiveTranslator, new ClientboundSetDisplayObjectivePacket(ScoreboardPosition.SIDEBAR, "objective") ); - assertNextPacket(() -> { + assertNextPacket(context, () -> { var packet = new SetDisplayObjectivePacket(); packet.setObjectiveId("0"); packet.setDisplayName("objective"); @@ -122,22 +122,22 @@ void displayAndChangeScoreValue() { 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 @@ void displayAndChangeScoreDisplayName() { setDisplayObjectiveTranslator, new ClientboundSetDisplayObjectivePacket(ScoreboardPosition.SIDEBAR, "objective") ); - assertNextPacket(() -> { + assertNextPacket(context, () -> { var packet = new SetDisplayObjectivePacket(); packet.setObjectiveId("0"); packet.setDisplayName("objective"); @@ -174,31 +174,31 @@ void displayAndChangeScoreDisplayName() { 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 @@ void displayAndChangeScoreDisplayNameAndValue() { setDisplayObjectiveTranslator, new ClientboundSetDisplayObjectivePacket(ScoreboardPosition.SIDEBAR, "objective") ); - assertNextPacket(() -> { + assertNextPacket(context, () -> { var packet = new SetDisplayObjectivePacket(); packet.setObjectiveId("0"); packet.setDisplayName("objective"); @@ -235,31 +235,31 @@ void displayAndChangeScoreDisplayNameAndValue() { 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 b15994533de..9177f205af4 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 static void assertContextEquals(Supplier expected, T act 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 static void assertNextPacketType(GeyserMockContext context, Class 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/CommonRegistriesMock.java b/core/src/test/java/org/geysermc/geyser/scoreboard/network/util/CommonRegistriesMock.java new file mode 100644 index 00000000000..ce68cd26eea --- /dev/null +++ b/core/src/test/java/org/geysermc/geyser/scoreboard/network/util/CommonRegistriesMock.java @@ -0,0 +1,174 @@ +/* + * 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.scoreboard.network.util; + +import it.unimi.dsi.fastutil.objects.Object2IntMap; +import java.util.EnumMap; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import org.cloudburstmc.nbt.NbtMap; +import org.cloudburstmc.protocol.bedrock.data.inventory.crafting.PotionMixData; +import org.cloudburstmc.protocol.bedrock.packet.BedrockPacket; +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.CommonRegistries; +import org.geysermc.geyser.registry.DeferredRegistry; +import org.geysermc.geyser.registry.ListRegistry; +import org.geysermc.geyser.registry.PacketTranslatorRegistry; +import org.geysermc.geyser.registry.SimpleMappedRegistry; +import org.geysermc.geyser.registry.SimpleRegistry; +import org.geysermc.geyser.registry.VersionedRegistry; +import org.geysermc.geyser.registry.loader.RegistryLoaders; +import org.geysermc.geyser.registry.provider.ProviderSupplier; +import org.geysermc.geyser.registry.type.ItemMappings; +import org.geysermc.geyser.registry.type.ParticleMapping; +import org.geysermc.geyser.registry.type.SoundMapping; +import org.geysermc.geyser.translator.level.block.entity.BlockEntityTranslator; +import org.geysermc.geyser.translator.level.event.LevelEventTranslator; +import org.geysermc.geyser.translator.sound.SoundInteractionTranslator; +import org.geysermc.geyser.translator.sound.SoundTranslator; +import org.geysermc.mcprotocollib.network.packet.Packet; +import org.geysermc.mcprotocollib.protocol.data.game.entity.type.EntityType; +import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityType; +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; + +public class CommonRegistriesMock implements CommonRegistries { + private final SimpleMappedRegistry> entityDefinitions = SimpleMappedRegistry.create(RegistryLoaders.empty(() -> new EnumMap<>(EntityType.class))); + private final SimpleRegistry> bedrockEntityProperties = SimpleRegistry.create(RegistryLoaders.empty(HashSet::new)); + + @Override + public SimpleMappedRegistry, ProviderSupplier> providers() { + throw new UnsupportedOperationException(); + } + + @Override + public SimpleRegistry bedrockEntityIdentifiers() { + throw new UnsupportedOperationException(); + } + + @Override + public SimpleMappedRegistry> javaEntityIdentifiers() { + // not used in current unit tests, can be safely ignored + return SimpleMappedRegistry.create(RegistryLoaders.empty(HashMap::new)); + } + + @Override + public SimpleMappedRegistry> entityDefinitions() { + // it is safely initialized by EntityDefinitions + return entityDefinitions; + } + + @Override + public SimpleRegistry> bedrockEntityProperties() { + // it is safely initialized by EntityDefinitions + return bedrockEntityProperties; + } + + @Override + public SimpleRegistry biomesNbt() { + throw new UnsupportedOperationException(); + } + + @Override + public SimpleRegistry> biomeIdentifiers() { + throw new UnsupportedOperationException(); + } + + @Override + public SimpleMappedRegistry blockEntities() { + throw new UnsupportedOperationException(); + } + + @Override + public PacketTranslatorRegistry bedrockPacketTranslators() { + throw new UnsupportedOperationException(); + } + + @Override + public PacketTranslatorRegistry javaPacketTranslators() { + throw new UnsupportedOperationException(); + } + + @Override + public ListRegistry javaItems() { + throw new UnsupportedOperationException(); + } + + @Override + public SimpleMappedRegistry javaItemIdentifiers() { + throw new UnsupportedOperationException(); + } + + @Override + public VersionedRegistry items() { + throw new UnsupportedOperationException(); + } + + @Override + public SimpleMappedRegistry particles() { + throw new UnsupportedOperationException(); + } + + @Override + public VersionedRegistry> potionMixes() { + throw new UnsupportedOperationException(); + } + + @Override + public SimpleMappedRegistry> recipes() { + throw new UnsupportedOperationException(); + } + + @Override + public DeferredRegistry> resourcePacks() { + throw new UnsupportedOperationException(); + } + + @Override + public SimpleMappedRegistry sounds() { + throw new UnsupportedOperationException(); + } + + @Override + public SimpleMappedRegistry soundLevelEvents() { + throw new UnsupportedOperationException(); + } + + @Override + public SimpleMappedRegistry> soundTranslators() { + throw new UnsupportedOperationException(); + } + + @Override + public void postInit() {} +} 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 72515d7146d..1e06379a4e7 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 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,10 +58,18 @@ public static void mockContext(Consumer geyserContext) { 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; - geyserContext.accept(context); + try (var geyserImplMock = mockStatic(GeyserImpl.class)) { + geyserImplMock.when(GeyserImpl::getInstance).thenReturn(geyserImpl); + + // Registries contains static methods that all call 'backingRegistries', that's the one we override. + // So every other static method will invoke the real method. + try (var registriesMock = mockStatic(Registries.class, Mockito.CALLS_REAL_METHODS)) { + var commonRegistries = context.storeObject(new CommonRegistriesMock()); + registriesMock.when(Registries::instance).thenReturn(commonRegistries); + Registries.init(); + + geyserContext.accept(context); + } } } @@ -136,8 +143,4 @@ public List packets() { 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 bc76a1b70bd..b2bd77e71b5 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 @@ -34,6 +34,7 @@ import java.util.UUID; import java.util.function.Consumer; +import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.packet.BedrockPacket; import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.entity.type.player.PlayerEntity; @@ -83,7 +84,7 @@ private static void createSessionSpy(GeyserMockContext context) { } public static PlayerEntity mockAndAddPlayerEntity(GeyserMockContext context, String username, long geyserId) { - var playerEntity = spy(new PlayerEntity(context.session(), geyserId, UUID.randomUUID(), username)); + var playerEntity = spy(new PlayerEntity(context.session(), (int) geyserId, geyserId, UUID.randomUUID(), Vector3f.ZERO, Vector3f.ZERO, 0, 0, 0, username, null)); // fake the player being spawned when(playerEntity.isValid()).thenReturn(true);