diff --git a/README.md b/README.md index dcd9b8530..db462db26 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ The ultimate goal of this project is to allow Minecraft: Bedrock Edition users t Special thanks to the DragonProxy project for being a trailblazer in protocol translation and for all the team members who have joined us here! ## Supported Versions -Geyser is currently supporting Minecraft Bedrock 1.21.40 - 1.21.62 and Minecraft Java 1.21.4. For more information, please see [here](https://geysermc.org/wiki/geyser/supported-versions/). +Geyser is currently supporting Minecraft Bedrock 1.21.40 - 1.21.70 and Minecraft Java 1.21.4. For more information, please see [here](https://geysermc.org/wiki/geyser/supported-versions/). ## Setting Up Take a look [here](https://geysermc.org/wiki/geyser/setup/) for how to set up Geyser. diff --git a/build-logic/src/main/kotlin/geyser.base-conventions.gradle.kts b/build-logic/src/main/kotlin/geyser.base-conventions.gradle.kts index 093f0a8c0..09440ac6a 100644 --- a/build-logic/src/main/kotlin/geyser.base-conventions.gradle.kts +++ b/build-logic/src/main/kotlin/geyser.base-conventions.gradle.kts @@ -62,11 +62,12 @@ repositories { name = "viaversion" } + // For Adventure snapshots + maven("https://s01.oss.sonatype.org/content/repositories/snapshots/") + // Jitpack for e.g. MCPL maven("https://jitpack.io") { content { includeGroupByRegex("com\\.github\\..*") } } - // For Adventure snapshots - maven("https://s01.oss.sonatype.org/content/repositories/snapshots/") } 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 c8488238d..757c126b9 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java +++ b/core/src/main/java/org/geysermc/geyser/entity/EntityDefinitions.java @@ -28,7 +28,7 @@ package org.geysermc.geyser.entity; import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag; import org.geysermc.geyser.entity.factory.EntityFactory; -import org.geysermc.geyser.entity.properties.GeyserEntityProperties; +import org.geysermc.geyser.entity.properties.VanillaEntityProperties; import org.geysermc.geyser.entity.type.AbstractArrowEntity; import org.geysermc.geyser.entity.type.AbstractWindChargeEntity; import org.geysermc.geyser.entity.type.AreaEffectCloudEntity; @@ -462,6 +462,7 @@ public final class EntityDefinitions { EGG = EntityDefinition.inherited(ThrowableItemEntity::new, throwableItemBase) .type(EntityType.EGG) .heightAndWidth(0.25f) + .properties(VanillaEntityProperties.CLIMATE_VARIANT) .build(); ENDER_PEARL = EntityDefinition.inherited(ThrowableItemEntity::new, throwableItemBase) .type(EntityType.ENDER_PEARL) @@ -685,15 +686,7 @@ public final class EntityDefinitions { .addTranslator(MetadataTypes.BOOLEAN, CreakingEntity::setActive) .addTranslator(MetadataTypes.BOOLEAN, CreakingEntity::setIsTearingDown) .addTranslator(MetadataTypes.OPTIONAL_POSITION, CreakingEntity::setHomePos) - .properties(new GeyserEntityProperties.Builder() - .addEnum(CreakingEntity.CREAKING_STATE, - "neutral", - "hostile_observed", - "hostile_unobserved", - "twitching", - "crumbling") - .addInt(CreakingEntity.CREAKING_SWAYING_TICKS, 0, 6) - .build()) + .properties(VanillaEntityProperties.CREAKING) .build(); CREEPER = EntityDefinition.inherited(CreeperEntity::new, mobEntityBase) .type(EntityType.CREEPER) @@ -946,15 +939,7 @@ public final class EntityDefinitions { ARMADILLO = EntityDefinition.inherited(ArmadilloEntity::new, ageableEntityBase) .type(EntityType.ARMADILLO) .height(0.65f).width(0.7f) - .properties(new GeyserEntityProperties.Builder() - .addEnum( - "minecraft:armadillo_state", - "unrolled", - "rolled_up", - "rolled_up_peeking", - "rolled_up_relaxing", - "rolled_up_unrolling") - .build()) + .properties(VanillaEntityProperties.ARMADILLO) .addTranslator(MetadataTypes.ARMADILLO_STATE, ArmadilloEntity::setArmadilloState) .build(); AXOLOTL = EntityDefinition.inherited(AxolotlEntity::new, ageableEntityBase) @@ -967,19 +952,19 @@ public final class EntityDefinitions { BEE = EntityDefinition.inherited(BeeEntity::new, ageableEntityBase) .type(EntityType.BEE) .heightAndWidth(0.6f) - .properties(new GeyserEntityProperties.Builder() - .addBoolean("minecraft:has_nectar") - .build()) + .properties(VanillaEntityProperties.BEE) .addTranslator(MetadataTypes.BYTE, BeeEntity::setBeeFlags) .addTranslator(MetadataTypes.INT, BeeEntity::setAngerTime) .build(); CHICKEN = EntityDefinition.inherited(ChickenEntity::new, ageableEntityBase) .type(EntityType.CHICKEN) .height(0.7f).width(0.4f) + .properties(VanillaEntityProperties.CLIMATE_VARIANT) .build(); COW = EntityDefinition.inherited(CowEntity::new, ageableEntityBase) .type(EntityType.COW) .height(1.4f).width(0.9f) + .properties(VanillaEntityProperties.CLIMATE_VARIANT) .build(); FOX = EntityDefinition.inherited(FoxEntity::new, ageableEntityBase) .type(EntityType.FOX) @@ -1030,6 +1015,7 @@ public final class EntityDefinitions { PIG = EntityDefinition.inherited(PigEntity::new, ageableEntityBase) .type(EntityType.PIG) .heightAndWidth(0.9f) + .properties(VanillaEntityProperties.CLIMATE_VARIANT) .addTranslator(MetadataTypes.BOOLEAN, (pigEntity, entityMetadata) -> pigEntity.setFlag(EntityFlag.SADDLED, ((BooleanEntityMetadata) entityMetadata).getPrimitiveValue())) .addTranslator(MetadataTypes.INT, PigEntity::setBoost) .build(); @@ -1176,6 +1162,7 @@ public final class EntityDefinitions { WOLF = EntityDefinition.inherited(WolfEntity::new, tameableEntityBase) .type(EntityType.WOLF) .height(0.85f).width(0.6f) + .properties(VanillaEntityProperties.WOLF_SOUND_VARIANT) // "Begging" on wiki.vg, "Interested" in Nukkit - the tilt of the head .addTranslator(MetadataTypes.BOOLEAN, (wolfEntity, entityMetadata) -> wolfEntity.setFlag(EntityFlag.INTERESTED, ((BooleanEntityMetadata) entityMetadata).getPrimitiveValue())) .addTranslator(MetadataTypes.INT, WolfEntity::setCollarColor) diff --git a/core/src/main/java/org/geysermc/geyser/entity/properties/GeyserEntityProperties.java b/core/src/main/java/org/geysermc/geyser/entity/properties/GeyserEntityProperties.java index 1729b0583..eaa7b7448 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/properties/GeyserEntityProperties.java +++ b/core/src/main/java/org/geysermc/geyser/entity/properties/GeyserEntityProperties.java @@ -162,4 +162,4 @@ public class GeyserEntityProperties { return new GeyserEntityProperties(properties, propertyIndices); } } -} \ No newline at end of file +} diff --git a/core/src/main/java/org/geysermc/geyser/entity/properties/VanillaEntityProperties.java b/core/src/main/java/org/geysermc/geyser/entity/properties/VanillaEntityProperties.java new file mode 100644 index 000000000..305dbf22e --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/entity/properties/VanillaEntityProperties.java @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2025 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.entity.properties; + +import org.geysermc.geyser.entity.type.living.monster.CreakingEntity; + +public class VanillaEntityProperties { + + public static final String CLIMATE_VARIANT_ID = "minecraft:climate_variant"; + + public static final GeyserEntityProperties ARMADILLO = new GeyserEntityProperties.Builder() + .addEnum("minecraft:armadillo_state", + "unrolled", + "rolled_up", + "rolled_up_peeking", + "rolled_up_relaxing", + "rolled_up_unrolling") + .build(); + + public static final GeyserEntityProperties BEE = new GeyserEntityProperties.Builder() + .addBoolean("minecraft:has_nectar") + .build(); + + public static final GeyserEntityProperties CLIMATE_VARIANT = new GeyserEntityProperties.Builder() + .addEnum(CLIMATE_VARIANT_ID, + "temperate", + "warm", + "cold") + .build(); + + public static final GeyserEntityProperties CREAKING = new GeyserEntityProperties.Builder() + .addEnum(CreakingEntity.CREAKING_STATE, + "neutral", + "hostile_observed", + "hostile_unobserved", + "twitching", + "crumbling") + .addInt(CreakingEntity.CREAKING_SWAYING_TICKS, 0, 6) + .build(); + + public static final GeyserEntityProperties WOLF_SOUND_VARIANT = new GeyserEntityProperties.Builder() + .addEnum("minecraft:sound_variant", + "default", + "big", + "cute", + "grumpy", + "mad", + "puglin", + "sad") + .build(); +} diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/BoatEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/BoatEntity.java index 7d789fb2a..f93845d9a 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/BoatEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/BoatEntity.java @@ -28,6 +28,7 @@ package org.geysermc.geyser.entity.type; import lombok.Getter; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; +import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag; import org.cloudburstmc.protocol.bedrock.packet.AnimatePacket; import org.cloudburstmc.protocol.bedrock.packet.MoveEntityAbsolutePacket; import org.geysermc.geyser.entity.EntityDefinition; @@ -85,7 +86,14 @@ public class BoatEntity extends Entity implements Leashable, Tickable { // Required to be able to move on land 1.16.200+ or apply gravity not in the water 1.16.100+ dirtyMetadata.put(EntityDataTypes.IS_BUOYANT, true); - dirtyMetadata.put(EntityDataTypes.BUOYANCY_DATA, BUOYANCY_DATA); + dirtyMetadata.put(EntityDataTypes.BUOYANCY_DATA, BUOYANCY_DATA);; + } + + @Override + protected void initializeMetadata() { + super.initializeMetadata(); + // Without this flag you cant stand on boats + setFlag(EntityFlag.COLLIDABLE, true); } @Override diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/Entity.java b/core/src/main/java/org/geysermc/geyser/entity/type/Entity.java index c986a8067..eac070327 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/Entity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/Entity.java @@ -200,6 +200,7 @@ public class Entity implements GeyserEntity { addAdditionalSpawnData(addEntityPacket); valid = true; + session.sendUpstreamPacket(addEntityPacket); flagsDirty = false; @@ -372,6 +373,10 @@ public class Entity implements GeyserEntity { flagsDirty = false; } dirtyMetadata.apply(entityDataPacket.getMetadata()); + if (propertyManager != null && propertyManager.hasProperties()) { + propertyManager.applyIntProperties(entityDataPacket.getProperties().getIntProperties()); + propertyManager.applyFloatProperties(entityDataPacket.getProperties().getFloatProperties()); + } session.sendUpstreamPacket(entityDataPacket); } } diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/ThrowableItemEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/ThrowableItemEntity.java index fbbe2de50..e49ce864a 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/ThrowableItemEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/ThrowableItemEntity.java @@ -28,10 +28,13 @@ package org.geysermc.geyser.entity.type; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag; +import org.cloudburstmc.protocol.bedrock.packet.AddEntityPacket; import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.entity.EntityDefinitions; +import org.geysermc.geyser.entity.properties.VanillaEntityProperties; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.EntityMetadata; +import org.geysermc.mcprotocollib.protocol.data.game.entity.type.EntityType; import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack; import java.util.UUID; @@ -53,6 +56,14 @@ public class ThrowableItemEntity extends ThrowableEntity { age = 0; } + @Override + public void addAdditionalSpawnData(AddEntityPacket addEntityPacket) { + if (definition.entityType() == EntityType.EGG) { + propertyManager.add(VanillaEntityProperties.CLIMATE_VARIANT_ID, "temperate"); + propertyManager.applyIntProperties(addEntityPacket.getProperties().getIntProperties()); + } + } + @Override protected void initializeMetadata() { super.initializeMetadata(); diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/ChickenEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/ChickenEntity.java index 0c8e437c8..231c408d6 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/ChickenEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/ChickenEntity.java @@ -27,7 +27,9 @@ package org.geysermc.geyser.entity.type.living.animal; import org.checkerframework.checker.nullness.qual.Nullable; import org.cloudburstmc.math.vector.Vector3f; +import org.cloudburstmc.protocol.bedrock.packet.AddEntityPacket; import org.geysermc.geyser.entity.EntityDefinition; +import org.geysermc.geyser.entity.properties.VanillaEntityProperties; import org.geysermc.geyser.item.type.Item; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.cache.tags.ItemTag; @@ -41,6 +43,12 @@ public class ChickenEntity extends AnimalEntity { super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw); } + @Override + public void addAdditionalSpawnData(AddEntityPacket addEntityPacket) { + propertyManager.add(VanillaEntityProperties.CLIMATE_VARIANT_ID, "temperate"); + propertyManager.applyIntProperties(addEntityPacket.getProperties().getIntProperties()); + } + @Override @Nullable protected Tag getFoodTag() { diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/CowEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/CowEntity.java index 66210068b..6c83b9dd1 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/CowEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/CowEntity.java @@ -30,7 +30,9 @@ import org.checkerframework.checker.nullness.qual.Nullable; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.SoundEvent; import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag; +import org.cloudburstmc.protocol.bedrock.packet.AddEntityPacket; import org.geysermc.geyser.entity.EntityDefinition; +import org.geysermc.geyser.entity.properties.VanillaEntityProperties; import org.geysermc.geyser.inventory.GeyserItemStack; import org.geysermc.geyser.item.Items; import org.geysermc.geyser.item.type.Item; @@ -48,6 +50,12 @@ public class CowEntity extends AnimalEntity { super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw); } + @Override + public void addAdditionalSpawnData(AddEntityPacket addEntityPacket) { + propertyManager.add(VanillaEntityProperties.CLIMATE_VARIANT_ID, "temperate"); + propertyManager.applyIntProperties(addEntityPacket.getProperties().getIntProperties()); + } + @NonNull @Override protected InteractiveTag testMobInteraction(@NonNull Hand hand, @NonNull GeyserItemStack itemInHand) { diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/MooshroomEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/MooshroomEntity.java index 2c9040b53..dce1adf79 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/MooshroomEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/MooshroomEntity.java @@ -28,6 +28,7 @@ package org.geysermc.geyser.entity.type.living.animal; import org.checkerframework.checker.nullness.qual.NonNull; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; +import org.cloudburstmc.protocol.bedrock.packet.AddEntityPacket; import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.inventory.GeyserItemStack; import org.geysermc.geyser.item.Items; @@ -52,6 +53,11 @@ public class MooshroomEntity extends CowEntity { dirtyMetadata.put(EntityDataTypes.VARIANT, isBrown ? 1 : 0); } + @Override + public void addAdditionalSpawnData(AddEntityPacket addEntityPacket) { + // There are no variants for mooshroom cows, so far + } + @NonNull @Override protected InteractiveTag testMobInteraction(@NonNull Hand hand, @NonNull GeyserItemStack itemInHand) { diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/PigEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/PigEntity.java index b8ba2c94f..d4227cfd9 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/PigEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/PigEntity.java @@ -31,7 +31,9 @@ import org.cloudburstmc.math.vector.Vector2f; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.definitions.ItemDefinition; import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag; +import org.cloudburstmc.protocol.bedrock.packet.AddEntityPacket; import org.geysermc.geyser.entity.EntityDefinition; +import org.geysermc.geyser.entity.properties.VanillaEntityProperties; import org.geysermc.geyser.entity.type.Tickable; import org.geysermc.geyser.entity.type.player.PlayerEntity; import org.geysermc.geyser.entity.vehicle.BoostableVehicleComponent; @@ -58,6 +60,12 @@ public class PigEntity extends AnimalEntity implements Tickable, ClientVehicle { super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw); } + @Override + public void addAdditionalSpawnData(AddEntityPacket addEntityPacket) { + propertyManager.add(VanillaEntityProperties.CLIMATE_VARIANT_ID, "temperate"); + propertyManager.applyIntProperties(addEntityPacket.getProperties().getIntProperties()); + } + @Override @Nullable protected Tag getFoodTag() { diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/tameable/WolfEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/tameable/WolfEntity.java index c8b6a6f58..0fb742f71 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/tameable/WolfEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/animal/tameable/WolfEntity.java @@ -30,6 +30,7 @@ import org.checkerframework.checker.nullness.qual.Nullable; import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag; +import org.cloudburstmc.protocol.bedrock.packet.AddEntityPacket; import org.cloudburstmc.protocol.bedrock.packet.UpdateAttributesPacket; import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.inventory.GeyserItemStack; @@ -67,6 +68,12 @@ public class WolfEntity extends TameableEntity { super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw); } + @Override + public void addAdditionalSpawnData(AddEntityPacket addEntityPacket) { + propertyManager.add("minecraft:sound_variant", "default"); + propertyManager.applyIntProperties(addEntityPacket.getProperties().getIntProperties()); + } + @Override public void setTameableFlags(ByteEntityMetadata entityMetadata) { super.setTameableFlags(entityMetadata); diff --git a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/EndermanEntity.java b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/EndermanEntity.java index 586ba5cd9..94ff657d2 100644 --- a/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/EndermanEntity.java +++ b/core/src/main/java/org/geysermc/geyser/entity/type/living/monster/EndermanEntity.java @@ -30,7 +30,7 @@ import org.cloudburstmc.protocol.bedrock.data.SoundEvent; import org.cloudburstmc.protocol.bedrock.data.definitions.BlockDefinition; import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag; -import org.cloudburstmc.protocol.bedrock.packet.LevelSoundEvent2Packet; +import org.cloudburstmc.protocol.bedrock.packet.LevelSoundEventPacket; import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata; @@ -57,7 +57,7 @@ public class EndermanEntity extends MonsterEntity { //TODO see if Bedrock controls this differently // Java Edition this controls which ambient sound is used if (entityMetadata.getPrimitiveValue()) { - LevelSoundEvent2Packet packet = new LevelSoundEvent2Packet(); + LevelSoundEventPacket packet = new LevelSoundEventPacket(); packet.setSound(SoundEvent.STARE); packet.setPosition(this.position); packet.setExtraData(-1); diff --git a/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java b/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java index 8625dfac5..a9c86ba07 100644 --- a/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java +++ b/core/src/main/java/org/geysermc/geyser/network/GameProtocol.java @@ -30,6 +30,7 @@ import org.cloudburstmc.protocol.bedrock.codec.BedrockCodec; import org.cloudburstmc.protocol.bedrock.codec.v748.Bedrock_v748; import org.cloudburstmc.protocol.bedrock.codec.v766.Bedrock_v766; import org.cloudburstmc.protocol.bedrock.codec.v776.Bedrock_v776; +import org.cloudburstmc.protocol.bedrock.codec.v786.Bedrock_v786; import org.cloudburstmc.protocol.bedrock.netty.codec.packet.BedrockPacketCodec; import org.geysermc.geyser.session.GeyserSession; import org.geysermc.mcprotocollib.protocol.codec.MinecraftCodec; @@ -48,8 +49,8 @@ public final class GameProtocol { * Default Bedrock codec that should act as a fallback. Should represent the latest available * release of the game that Geyser supports. */ - public static final BedrockCodec DEFAULT_BEDROCK_CODEC = CodecProcessor.processCodec(Bedrock_v776.CODEC.toBuilder() - .minecraftVersion("1.21.60") + public static final BedrockCodec DEFAULT_BEDROCK_CODEC = CodecProcessor.processCodec(Bedrock_v786.CODEC.toBuilder() + .minecraftVersion("1.21.70") .build()); /** @@ -70,6 +71,9 @@ public final class GameProtocol { SUPPORTED_BEDROCK_CODECS.add(CodecProcessor.processCodec(Bedrock_v766.CODEC.toBuilder() .minecraftVersion("1.21.50 - 1.21.51") .build())); + SUPPORTED_BEDROCK_CODECS.add(CodecProcessor.processCodec(Bedrock_v776.CODEC.toBuilder() + .minecraftVersion("1.21.60 - 1.21.62") + .build())); SUPPORTED_BEDROCK_CODECS.add(DEFAULT_BEDROCK_CODEC); } diff --git a/core/src/main/java/org/geysermc/geyser/network/InvalidPacketHandler.java b/core/src/main/java/org/geysermc/geyser/network/InvalidPacketHandler.java index 974d6fdce..34b97f36f 100644 --- a/core/src/main/java/org/geysermc/geyser/network/InvalidPacketHandler.java +++ b/core/src/main/java/org/geysermc/geyser/network/InvalidPacketHandler.java @@ -51,7 +51,7 @@ public class InvalidPacketHandler extends ChannelInboundHandlerAdapter { if (!(rootCause instanceof IllegalArgumentException)) { // Kick users that cause exceptions - logger.warning("Exception caught in session of" + session.bedrockUsername() + ": " + rootCause.getMessage()); + logger.warning("Exception caught in session of " + session.bedrockUsername() + ": " + rootCause.getMessage()); session.disconnect("An internal error occurred!"); return; } diff --git a/core/src/main/java/org/geysermc/geyser/network/LoggingPacketHandler.java b/core/src/main/java/org/geysermc/geyser/network/LoggingPacketHandler.java index 2d8db9517..39c3f5aa9 100644 --- a/core/src/main/java/org/geysermc/geyser/network/LoggingPacketHandler.java +++ b/core/src/main/java/org/geysermc/geyser/network/LoggingPacketHandler.java @@ -906,4 +906,14 @@ public class LoggingPacketHandler implements BedrockPacketHandler { public PacketSignal handle(ServerboundDiagnosticsPacket packet) { return defaultHandler(packet); } + + @Override + public PacketSignal handle(UpdateClientOptionsPacket packet) { + return defaultHandler(packet); + } + + @Override + public PacketSignal handle(PlayerUpdateEntityOverridesPacket packet) { + return defaultHandler(packet); + } } 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 59cdd52c4..81f1fec46 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 @@ -45,6 +45,7 @@ import org.cloudburstmc.nbt.NbtUtils; import org.cloudburstmc.protocol.bedrock.codec.v748.Bedrock_v748; import org.cloudburstmc.protocol.bedrock.codec.v766.Bedrock_v766; import org.cloudburstmc.protocol.bedrock.codec.v776.Bedrock_v776; +import org.cloudburstmc.protocol.bedrock.codec.v786.Bedrock_v786; import org.cloudburstmc.protocol.bedrock.data.BlockPropertyData; import org.cloudburstmc.protocol.bedrock.data.definitions.BlockDefinition; import org.geysermc.geyser.GeyserImpl; @@ -117,41 +118,10 @@ public final class BlockRegistryPopulator { private static void registerBedrockBlocks() { var blockMappers = ImmutableMap., Remapper>builder() .put(ObjectIntPair.of("1_21_40", Bedrock_v748.CODEC.getProtocolVersion()), Conversion766_748::remapBlock) - .put(ObjectIntPair.of("1_21_50", Bedrock_v766.CODEC.getProtocolVersion()), tag -> tag) // TODO: Finish me - .put(ObjectIntPair.of("1_21_60", Bedrock_v776.CODEC.getProtocolVersion()), tag -> { - final String name = tag.getString("name"); - if (name.equals("minecraft:creaking_heart") && tag.getCompound("states").containsKey("active")) { - NbtMapBuilder builder = tag.getCompound("states").toBuilder(); - builder.remove("active"); - builder.putString("creaking_heart_state", "awake"); - NbtMap states = builder.build(); - return tag.toBuilder().putCompound("states", states).build(); - } - if ((name.endsWith("_door") || name.endsWith("fence_gate")) && tag.getCompound("states").containsKey("direction")) { - NbtMapBuilder builder = tag.getCompound("states").toBuilder(); - Integer directionCardinality = (Integer) builder.remove("direction"); - switch (directionCardinality) { - case 0: - builder.putString("minecraft:cardinal_direction", "south"); - break; - case 1: - builder.putString("minecraft:cardinal_direction", "west"); - break; - case 2: - builder.putString( "minecraft:cardinal_direction" , "north"); - break; - case 3: - builder.putString("minecraft:cardinal_direction", "east"); - break; - default: - throw new AssertionError("Invalid direction: " + directionCardinality); - } - NbtMap states = builder.build(); - return tag.toBuilder().putCompound("states", states).build(); - } - return tag; - }) - .build(); + .put(ObjectIntPair.of("1_21_50", Bedrock_v766.CODEC.getProtocolVersion()), Conversion776_766::remapBlock) + .put(ObjectIntPair.of("1_21_60", Bedrock_v776.CODEC.getProtocolVersion()), tag -> tag) + .put(ObjectIntPair.of("1_21_70", Bedrock_v786.CODEC.getProtocolVersion()), tag -> tag) + .build(); // We can keep this strong as nothing should be garbage collected // Safe to intern since Cloudburst NBT is immutable diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion766_748.java b/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion766_748.java index 4568d0154..6f2bc61e2 100644 --- a/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion766_748.java +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion766_748.java @@ -85,6 +85,10 @@ public class Conversion766_748 { } static NbtMap remapBlock(NbtMap tag) { + + // First: Downgrade from 1.21.60 -> 1.21.50 + tag = Conversion776_766.remapBlock(tag); + String name = tag.getString("name").replace("minecraft:", ""); if (PALE_WOODEN_BLOCKS.contains(name)) { return withName(tag, name.replace("pale_oak", "birch")); diff --git a/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion776_766.java b/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion776_766.java new file mode 100644 index 000000000..edc2543ae --- /dev/null +++ b/core/src/main/java/org/geysermc/geyser/registry/populator/Conversion776_766.java @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2025 GeyserMC. http://geysermc.org + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * @author GeyserMC + * @link https://github.com/GeyserMC/Geyser + */ + +package org.geysermc.geyser.registry.populator; + +import org.cloudburstmc.nbt.NbtMap; +import org.cloudburstmc.nbt.NbtMapBuilder; + +public class Conversion776_766 { + + public static NbtMap remapBlock(NbtMap tag) { + final String name = tag.getString("name"); + + if (name.equals("minecraft:creaking_heart")) { + NbtMapBuilder builder = tag.getCompound("states").toBuilder(); + String value = (String) builder.remove("creaking_heart_state"); + builder.putBoolean("active", value.equals("awake")); + + return tag.toBuilder().putCompound("states", builder.build()).build(); + } + + if (name.endsWith("_door") || name.endsWith("fence_gate")) { + NbtMapBuilder builder = tag.getCompound("states").toBuilder(); + String cardinalDirection = (String) builder.remove("minecraft:cardinal_direction"); + switch (cardinalDirection) { + case "south" -> builder.putInt("direction", 0); + case "west" -> builder.putInt("direction", 1); + case "east" -> builder.putInt("direction", 3); + case "north" -> builder.putInt("direction", 2); + default -> throw new AssertionError("Invalid direction: " + cardinalDirection); + } + NbtMap states = builder.build(); + return tag.toBuilder().putCompound("states", states).build(); + } + + return tag; + } + +} 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 c0c006549..0b8d7f982 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 @@ -48,6 +48,7 @@ import org.cloudburstmc.nbt.NbtUtils; import org.cloudburstmc.protocol.bedrock.codec.v748.Bedrock_v748; import org.cloudburstmc.protocol.bedrock.codec.v766.Bedrock_v766; import org.cloudburstmc.protocol.bedrock.codec.v776.Bedrock_v776; +import org.cloudburstmc.protocol.bedrock.codec.v786.Bedrock_v786; import org.cloudburstmc.protocol.bedrock.data.definitions.BlockDefinition; import org.cloudburstmc.protocol.bedrock.data.definitions.ItemDefinition; import org.cloudburstmc.protocol.bedrock.data.definitions.SimpleItemDefinition; @@ -151,6 +152,7 @@ public class ItemRegistryPopulator { paletteVersions.add(new PaletteVersion("1_21_40", Bedrock_v748.CODEC.getProtocolVersion(), itemFallbacks, (item, mapping) -> mapping)); paletteVersions.add(new PaletteVersion("1_21_50", Bedrock_v766.CODEC.getProtocolVersion())); paletteVersions.add(new PaletteVersion("1_21_60", Bedrock_v776.CODEC.getProtocolVersion())); + paletteVersions.add(new PaletteVersion("1_21_70", Bedrock_v786.CODEC.getProtocolVersion())); GeyserBootstrap bootstrap = GeyserImpl.getInstance().getBootstrap(); 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 005e72097..c1ca49af4 100644 --- a/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java +++ b/core/src/main/java/org/geysermc/geyser/session/GeyserSession.java @@ -91,7 +91,7 @@ import org.cloudburstmc.protocol.bedrock.packet.EmoteListPacket; import org.cloudburstmc.protocol.bedrock.packet.GameRulesChangedPacket; import org.cloudburstmc.protocol.bedrock.packet.ItemComponentPacket; import org.cloudburstmc.protocol.bedrock.packet.LevelEventPacket; -import org.cloudburstmc.protocol.bedrock.packet.LevelSoundEvent2Packet; +import org.cloudburstmc.protocol.bedrock.packet.LevelSoundEventPacket; import org.cloudburstmc.protocol.bedrock.packet.PlayStatusPacket; import org.cloudburstmc.protocol.bedrock.packet.SetCommandsEnabledPacket; import org.cloudburstmc.protocol.bedrock.packet.SetTimePacket; @@ -1933,7 +1933,7 @@ public class GeyserSession implements GeyserConnection, GeyserCommandSource { } public void playSoundEvent(SoundEvent sound, Vector3f position) { - LevelSoundEvent2Packet packet = new LevelSoundEvent2Packet(); + LevelSoundEventPacket packet = new LevelSoundEventPacket(); packet.setPosition(position); packet.setSound(sound); packet.setIdentifier(":"); diff --git a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaEntityEventTranslator.java b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaEntityEventTranslator.java index 2e2734410..9599be3fc 100644 --- a/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaEntityEventTranslator.java +++ b/core/src/main/java/org/geysermc/geyser/translator/protocol/java/entity/JavaEntityEventTranslator.java @@ -33,7 +33,7 @@ import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerId; import org.cloudburstmc.protocol.bedrock.packet.EntityEventPacket; import org.cloudburstmc.protocol.bedrock.packet.InventoryContentPacket; import org.cloudburstmc.protocol.bedrock.packet.LevelEventPacket; -import org.cloudburstmc.protocol.bedrock.packet.LevelSoundEvent2Packet; +import org.cloudburstmc.protocol.bedrock.packet.LevelSoundEventPacket; import org.cloudburstmc.protocol.bedrock.packet.PlaySoundPacket; import org.cloudburstmc.protocol.bedrock.packet.SetEntityDataPacket; import org.cloudburstmc.protocol.bedrock.packet.SetEntityMotionPacket; @@ -143,7 +143,7 @@ public class JavaEntityEventTranslator extends PacketTranslator