Boat changes applied

This commit is contained in:
Camotoy 2024-10-20 14:54:27 -04:00
parent e2f40569f8
commit 93d96ef5a4
No known key found for this signature in database
GPG key ID: 7EEFB66FE798081F
14 changed files with 178 additions and 99 deletions

View file

@ -152,29 +152,37 @@ import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.FloatE
import org.geysermc.mcprotocollib.protocol.data.game.entity.type.EntityType; import org.geysermc.mcprotocollib.protocol.data.game.entity.type.EntityType;
public final class EntityDefinitions { public final class EntityDefinitions {
public static final EntityDefinition<BoatEntity> ACACIA_BOAT;
public static final EntityDefinition<ChestBoatEntity> ACACIA_CHEST_BOAT;
public static final EntityDefinition<AllayEntity> ALLAY; public static final EntityDefinition<AllayEntity> ALLAY;
public static final EntityDefinition<AreaEffectCloudEntity> AREA_EFFECT_CLOUD; public static final EntityDefinition<AreaEffectCloudEntity> AREA_EFFECT_CLOUD;
public static final EntityDefinition<ArmadilloEntity> ARMADILLO; public static final EntityDefinition<ArmadilloEntity> ARMADILLO;
public static final EntityDefinition<ArmorStandEntity> ARMOR_STAND; public static final EntityDefinition<ArmorStandEntity> ARMOR_STAND;
public static final EntityDefinition<ArrowEntity> ARROW; public static final EntityDefinition<ArrowEntity> ARROW;
public static final EntityDefinition<AxolotlEntity> AXOLOTL; public static final EntityDefinition<AxolotlEntity> AXOLOTL;
public static final EntityDefinition<BoatEntity> BAMBOO_RAFT;
public static final EntityDefinition<ChestBoatEntity> BAMBOO_CHEST_RAFT;
public static final EntityDefinition<BatEntity> BAT; public static final EntityDefinition<BatEntity> BAT;
public static final EntityDefinition<BeeEntity> BEE; public static final EntityDefinition<BeeEntity> BEE;
public static final EntityDefinition<BoatEntity> BIRCH_BOAT;
public static final EntityDefinition<ChestBoatEntity> BIRCH_CHEST_BOAT;
public static final EntityDefinition<BlazeEntity> BLAZE; public static final EntityDefinition<BlazeEntity> BLAZE;
public static final EntityDefinition<BoatEntity> BOAT;
public static final EntityDefinition<BoggedEntity> BOGGED; public static final EntityDefinition<BoggedEntity> BOGGED;
public static final EntityDefinition<BreezeEntity> BREEZE; public static final EntityDefinition<BreezeEntity> BREEZE;
public static final EntityDefinition<AbstractWindChargeEntity> BREEZE_WIND_CHARGE; public static final EntityDefinition<AbstractWindChargeEntity> BREEZE_WIND_CHARGE;
public static final EntityDefinition<CamelEntity> CAMEL; public static final EntityDefinition<CamelEntity> CAMEL;
public static final EntityDefinition<CatEntity> CAT; public static final EntityDefinition<CatEntity> CAT;
public static final EntityDefinition<SpiderEntity> CAVE_SPIDER; public static final EntityDefinition<SpiderEntity> CAVE_SPIDER;
public static final EntityDefinition<BoatEntity> CHERRY_BOAT;
public static final EntityDefinition<ChestBoatEntity> CHERRY_CHEST_BOAT;
public static final EntityDefinition<MinecartEntity> CHEST_MINECART; public static final EntityDefinition<MinecartEntity> CHEST_MINECART;
public static final EntityDefinition<ChickenEntity> CHICKEN; public static final EntityDefinition<ChickenEntity> CHICKEN;
public static final EntityDefinition<ChestBoatEntity> CHEST_BOAT;
public static final EntityDefinition<AbstractFishEntity> COD; public static final EntityDefinition<AbstractFishEntity> COD;
public static final EntityDefinition<CommandBlockMinecartEntity> COMMAND_BLOCK_MINECART; public static final EntityDefinition<CommandBlockMinecartEntity> COMMAND_BLOCK_MINECART;
public static final EntityDefinition<CowEntity> COW; public static final EntityDefinition<CowEntity> COW;
public static final EntityDefinition<CreeperEntity> CREEPER; public static final EntityDefinition<CreeperEntity> CREEPER;
public static final EntityDefinition<BoatEntity> DARK_OAK_BOAT;
public static final EntityDefinition<ChestBoatEntity> DARK_OAK_CHEST_BOAT;
public static final EntityDefinition<DolphinEntity> DOLPHIN; public static final EntityDefinition<DolphinEntity> DOLPHIN;
public static final EntityDefinition<ChestedHorseEntity> DONKEY; public static final EntityDefinition<ChestedHorseEntity> DONKEY;
public static final EntityDefinition<FireballEntity> DRAGON_FIREBALL; public static final EntityDefinition<FireballEntity> DRAGON_FIREBALL;
@ -213,14 +221,20 @@ public final class EntityDefinitions {
public static final EntityDefinition<IronGolemEntity> IRON_GOLEM; public static final EntityDefinition<IronGolemEntity> IRON_GOLEM;
public static final EntityDefinition<ItemEntity> ITEM; public static final EntityDefinition<ItemEntity> ITEM;
public static final EntityDefinition<ItemFrameEntity> ITEM_FRAME; public static final EntityDefinition<ItemFrameEntity> ITEM_FRAME;
public static final EntityDefinition<BoatEntity> JUNGLE_BOAT;
public static final EntityDefinition<ChestBoatEntity> JUNGLE_CHEST_BOAT;
public static final EntityDefinition<LeashKnotEntity> LEASH_KNOT; public static final EntityDefinition<LeashKnotEntity> LEASH_KNOT;
public static final EntityDefinition<LightningEntity> LIGHTNING_BOLT; public static final EntityDefinition<LightningEntity> LIGHTNING_BOLT;
public static final EntityDefinition<LlamaEntity> LLAMA; public static final EntityDefinition<LlamaEntity> LLAMA;
public static final EntityDefinition<ThrowableEntity> LLAMA_SPIT; public static final EntityDefinition<ThrowableEntity> LLAMA_SPIT;
public static final EntityDefinition<MagmaCubeEntity> MAGMA_CUBE; public static final EntityDefinition<MagmaCubeEntity> MAGMA_CUBE;
public static final EntityDefinition<BoatEntity> MANGROVE_BOAT;
public static final EntityDefinition<ChestBoatEntity> MANGROVE_CHEST_BOAT;
public static final EntityDefinition<MinecartEntity> MINECART; public static final EntityDefinition<MinecartEntity> MINECART;
public static final EntityDefinition<MooshroomEntity> MOOSHROOM; public static final EntityDefinition<MooshroomEntity> MOOSHROOM;
public static final EntityDefinition<ChestedHorseEntity> MULE; public static final EntityDefinition<ChestedHorseEntity> MULE;
public static final EntityDefinition<BoatEntity> OAK_BOAT;
public static final EntityDefinition<ChestBoatEntity> OAK_CHEST_BOAT;
public static final EntityDefinition<OcelotEntity> OCELOT; public static final EntityDefinition<OcelotEntity> OCELOT;
public static final EntityDefinition<PaintingEntity> PAINTING; public static final EntityDefinition<PaintingEntity> PAINTING;
public static final EntityDefinition<PandaEntity> PANDA; public static final EntityDefinition<PandaEntity> PANDA;
@ -251,6 +265,8 @@ public final class EntityDefinitions {
public static final EntityDefinition<SpawnerMinecartEntity> SPAWNER_MINECART; // Not present on Bedrock public static final EntityDefinition<SpawnerMinecartEntity> SPAWNER_MINECART; // Not present on Bedrock
public static final EntityDefinition<AbstractArrowEntity> SPECTRAL_ARROW; public static final EntityDefinition<AbstractArrowEntity> SPECTRAL_ARROW;
public static final EntityDefinition<SpiderEntity> SPIDER; public static final EntityDefinition<SpiderEntity> SPIDER;
public static final EntityDefinition<BoatEntity> SPRUCE_BOAT;
public static final EntityDefinition<ChestBoatEntity> SPRUCE_CHEST_BOAT;
public static final EntityDefinition<SquidEntity> SQUID; public static final EntityDefinition<SquidEntity> SQUID;
public static final EntityDefinition<AbstractSkeletonEntity> STRAY; public static final EntityDefinition<AbstractSkeletonEntity> STRAY;
public static final EntityDefinition<StriderEntity> STRIDER; public static final EntityDefinition<StriderEntity> STRIDER;
@ -309,23 +325,6 @@ public final class EntityDefinitions {
.addTranslator(null) // Waiting .addTranslator(null) // Waiting
.addTranslator(MetadataType.PARTICLE, AreaEffectCloudEntity::setParticle) .addTranslator(MetadataType.PARTICLE, AreaEffectCloudEntity::setParticle)
.build(); .build();
BOAT = EntityDefinition.inherited(BoatEntity::new, entityBase)
.type(EntityType.BOAT)
.height(0.6f).width(1.6f)
.offset(0.35f)
.addTranslator(MetadataType.INT, (boatEntity, entityMetadata) -> boatEntity.getDirtyMetadata().put(EntityDataTypes.HURT_TICKS, entityMetadata.getValue())) // Time since last hit
.addTranslator(MetadataType.INT, (boatEntity, entityMetadata) -> boatEntity.getDirtyMetadata().put(EntityDataTypes.HURT_DIRECTION, entityMetadata.getValue())) // Rocking direction
.addTranslator(MetadataType.FLOAT, (boatEntity, entityMetadata) ->
// 'Health' in Bedrock, damage taken in Java - it makes motion in Bedrock
boatEntity.getDirtyMetadata().put(EntityDataTypes.STRUCTURAL_INTEGRITY, 40 - ((int) ((FloatEntityMetadata) entityMetadata).getPrimitiveValue())))
.addTranslator(MetadataType.INT, BoatEntity::setVariant)
.addTranslator(MetadataType.BOOLEAN, BoatEntity::setPaddlingLeft)
.addTranslator(MetadataType.BOOLEAN, BoatEntity::setPaddlingRight)
.addTranslator(MetadataType.INT, (boatEntity, entityMetadata) -> boatEntity.getDirtyMetadata().put(EntityDataTypes.BOAT_BUBBLE_TIME, entityMetadata.getValue())) // May not actually do anything
.build();
CHEST_BOAT = EntityDefinition.inherited(ChestBoatEntity::new, BOAT)
.type(EntityType.CHEST_BOAT)
.build();
DRAGON_FIREBALL = EntityDefinition.inherited(FireballEntity::new, entityBase) DRAGON_FIREBALL = EntityDefinition.inherited(FireballEntity::new, entityBase)
.type(EntityType.DRAGON_FIREBALL) .type(EntityType.DRAGON_FIREBALL)
.heightAndWidth(1.0f) .heightAndWidth(1.0f)
@ -568,6 +567,45 @@ public final class EntityDefinitions {
.build(false); .build(false);
} }
// Boats
{
EntityDefinition<BoatEntity> boatBase = EntityDefinition.<BoatEntity>inherited(null, entityBase)
.height(0.6f).width(1.6f)
.offset(0.35f)
.addTranslator(MetadataType.INT, (boatEntity, entityMetadata) -> boatEntity.getDirtyMetadata().put(EntityDataTypes.HURT_TICKS, entityMetadata.getValue())) // Time since last hit
.addTranslator(MetadataType.INT, (boatEntity, entityMetadata) -> boatEntity.getDirtyMetadata().put(EntityDataTypes.HURT_DIRECTION, entityMetadata.getValue())) // Rocking direction
.addTranslator(MetadataType.FLOAT, (boatEntity, entityMetadata) ->
// 'Health' in Bedrock, damage taken in Java - it makes motion in Bedrock
boatEntity.getDirtyMetadata().put(EntityDataTypes.STRUCTURAL_INTEGRITY, 40 - ((int) ((FloatEntityMetadata) entityMetadata).getPrimitiveValue())))
.addTranslator(MetadataType.BOOLEAN, BoatEntity::setPaddlingLeft)
.addTranslator(MetadataType.BOOLEAN, BoatEntity::setPaddlingRight)
.addTranslator(MetadataType.INT, (boatEntity, entityMetadata) -> boatEntity.getDirtyMetadata().put(EntityDataTypes.BOAT_BUBBLE_TIME, entityMetadata.getValue())) // May not actually do anything
.build();
ACACIA_BOAT = buildBoat(boatBase, EntityType.ACACIA_BOAT, BoatEntity.BoatVariant.ACACIA);
BAMBOO_RAFT = buildBoat(boatBase, EntityType.BAMBOO_RAFT, BoatEntity.BoatVariant.BAMBOO);
BIRCH_BOAT = buildBoat(boatBase, EntityType.BIRCH_BOAT, BoatEntity.BoatVariant.BIRCH);
CHERRY_BOAT = buildBoat(boatBase, EntityType.CHERRY_BOAT, BoatEntity.BoatVariant.CHERRY);
DARK_OAK_BOAT = buildBoat(boatBase, EntityType.DARK_OAK_BOAT, BoatEntity.BoatVariant.DARK_OAK);
JUNGLE_BOAT = buildBoat(boatBase, EntityType.JUNGLE_BOAT, BoatEntity.BoatVariant.JUNGLE);
MANGROVE_BOAT = buildBoat(boatBase, EntityType.MANGROVE_BOAT, BoatEntity.BoatVariant.MANGROVE);
OAK_BOAT = buildBoat(boatBase, EntityType.OAK_BOAT, BoatEntity.BoatVariant.OAK);
SPRUCE_BOAT = buildBoat(boatBase, EntityType.SPRUCE_BOAT, BoatEntity.BoatVariant.SPRUCE);
EntityDefinition<ChestBoatEntity> chestBoatBase = EntityDefinition.<ChestBoatEntity>inherited(null, boatBase)
.build();
ACACIA_CHEST_BOAT = buildChestBoat(chestBoatBase, EntityType.ACACIA_CHEST_BOAT, BoatEntity.BoatVariant.ACACIA);
BAMBOO_CHEST_RAFT = buildChestBoat(chestBoatBase, EntityType.BAMBOO_CHEST_RAFT, BoatEntity.BoatVariant.BAMBOO);
BIRCH_CHEST_BOAT = buildChestBoat(chestBoatBase, EntityType.BIRCH_CHEST_BOAT, BoatEntity.BoatVariant.BIRCH);
CHERRY_CHEST_BOAT = buildChestBoat(chestBoatBase, EntityType.CHERRY_CHEST_BOAT, BoatEntity.BoatVariant.CHERRY);
DARK_OAK_CHEST_BOAT = buildChestBoat(chestBoatBase, EntityType.DARK_OAK_CHEST_BOAT, BoatEntity.BoatVariant.DARK_OAK);
JUNGLE_CHEST_BOAT = buildChestBoat(chestBoatBase, EntityType.JUNGLE_CHEST_BOAT, BoatEntity.BoatVariant.JUNGLE);
MANGROVE_CHEST_BOAT = buildChestBoat(chestBoatBase, EntityType.MANGROVE_CHEST_BOAT, BoatEntity.BoatVariant.MANGROVE);
OAK_CHEST_BOAT = buildChestBoat(chestBoatBase, EntityType.OAK_CHEST_BOAT, BoatEntity.BoatVariant.OAK);
SPRUCE_CHEST_BOAT = buildChestBoat(chestBoatBase, EntityType.SPRUCE_CHEST_BOAT, BoatEntity.BoatVariant.SPRUCE);
}
EntityDefinition<LivingEntity> livingEntityBase = EntityDefinition.inherited(LivingEntity::new, entityBase) EntityDefinition<LivingEntity> livingEntityBase = EntityDefinition.inherited(LivingEntity::new, entityBase)
.addTranslator(MetadataType.BYTE, LivingEntity::setLivingEntityFlags) .addTranslator(MetadataType.BYTE, LivingEntity::setLivingEntityFlags)
.addTranslator(MetadataType.FLOAT, LivingEntity::setHealth) .addTranslator(MetadataType.FLOAT, LivingEntity::setHealth)
@ -1128,6 +1166,22 @@ public final class EntityDefinitions {
} }
} }
private static EntityDefinition<BoatEntity> buildBoat(EntityDefinition<BoatEntity> base, EntityType entityType, BoatEntity.BoatVariant variant) {
return EntityDefinition.inherited((session, javaId, bedrockId, uuid, definition, position, motion, yaw, pitch, headYaw) ->
new BoatEntity(session, javaId, bedrockId, uuid, definition, position, motion, yaw, variant), base)
.type(entityType)
.identifier("minecraft:boat")
.build();
}
private static EntityDefinition<ChestBoatEntity> buildChestBoat(EntityDefinition<ChestBoatEntity> base, EntityType entityType, BoatEntity.BoatVariant variant) {
return EntityDefinition.inherited((session, javaId, bedrockId, uuid, definition, position, motion, yaw, pitch, headYaw) ->
new ChestBoatEntity(session, javaId, bedrockId, uuid, definition, position, motion, yaw, variant), base)
.type(entityType)
.identifier("minecraft:chest_boat")
.build();
}
public static void init() { public static void init() {
// no-op // no-op
} }

View file

@ -32,11 +32,12 @@ import org.cloudburstmc.protocol.bedrock.packet.AnimatePacket;
import org.cloudburstmc.protocol.bedrock.packet.MoveEntityAbsolutePacket; import org.cloudburstmc.protocol.bedrock.packet.MoveEntityAbsolutePacket;
import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.entity.EntityDefinitions; import org.geysermc.geyser.entity.EntityDefinitions;
import org.geysermc.geyser.item.Items;
import org.geysermc.geyser.item.type.Item;
import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.util.InteractionResult; import org.geysermc.geyser.util.InteractionResult;
import org.geysermc.geyser.util.InteractiveTag; import org.geysermc.geyser.util.InteractiveTag;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.BooleanEntityMetadata;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.IntEntityMetadata;
import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand; import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand;
import java.util.UUID; import java.util.UUID;
@ -63,16 +64,19 @@ public class BoatEntity extends Entity implements Leashable, Tickable {
* Saved for using the "pick" functionality on a boat. * Saved for using the "pick" functionality on a boat.
*/ */
@Getter @Getter
private int variant; protected final BoatVariant variant;
private long leashHolderBedrockId = -1; private long leashHolderBedrockId = -1;
// Looks too fast and too choppy with 0.1f, which is how I believe the Microsoftian client handles it // Looks too fast and too choppy with 0.1f, which is how I believe the Microsoftian client handles it
private final float ROWING_SPEED = 0.1f; private final float ROWING_SPEED = 0.1f;
public BoatEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, EntityDefinition<?> definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) { public BoatEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, EntityDefinition<?> definition, Vector3f position, Vector3f motion, float yaw, BoatVariant variant) {
// Initial rotation is incorrect // Initial rotation is incorrect
super(session, entityId, geyserId, uuid, definition, position.add(0d, definition.offset(), 0d), motion, yaw + 90, 0, yaw + 90); super(session, entityId, geyserId, uuid, definition, position.add(0d, definition.offset(), 0d), motion, yaw + 90, 0, yaw + 90);
this.variant = variant;
dirtyMetadata.put(EntityDataTypes.VARIANT, variant.ordinal());
// Required to be able to move on land 1.16.200+ or apply gravity not in the water 1.16.100+ // 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.IS_BUOYANT, true);
@ -124,15 +128,6 @@ public class BoatEntity extends Entity implements Leashable, Tickable {
moveRelative(0, 0, 0, yaw + 90, 0, 0, isOnGround); moveRelative(0, 0, 0, yaw + 90, 0, 0, isOnGround);
} }
public void setVariant(IntEntityMetadata entityMetadata) {
variant = entityMetadata.getPrimitiveValue();
dirtyMetadata.put(EntityDataTypes.VARIANT, switch (variant) {
case 6, 7, 8 -> variant - 1; // dark_oak, mangrove, bamboo
case 5 -> 8; // cherry
default -> variant;
});
}
public void setPaddlingLeft(BooleanEntityMetadata entityMetadata) { public void setPaddlingLeft(BooleanEntityMetadata entityMetadata) {
isPaddlingLeft = entityMetadata.getPrimitiveValue(); isPaddlingLeft = entityMetadata.getPrimitiveValue();
if (!isPaddlingLeft) { if (!isPaddlingLeft) {
@ -212,6 +207,10 @@ public class BoatEntity extends Entity implements Leashable, Tickable {
return leashHolderBedrockId; return leashHolderBedrockId;
} }
public Item getPickItem() {
return variant.pickItem;
}
private void sendAnimationPacket(GeyserSession session, Entity rower, AnimatePacket.Action action, float rowTime) { private void sendAnimationPacket(GeyserSession session, Entity rower, AnimatePacket.Action action, float rowTime) {
AnimatePacket packet = new AnimatePacket(); AnimatePacket packet = new AnimatePacket();
packet.setRuntimeEntityId(rower.getGeyserId()); packet.setRuntimeEntityId(rower.getGeyserId());
@ -219,4 +218,27 @@ public class BoatEntity extends Entity implements Leashable, Tickable {
packet.setRowingTime(rowTime); packet.setRowingTime(rowTime);
session.sendUpstreamPacket(packet); session.sendUpstreamPacket(packet);
} }
/**
* Ordered by Bedrock ordinal
*/
public enum BoatVariant {
OAK(Items.OAK_BOAT, Items.OAK_CHEST_BOAT),
SPRUCE(Items.SPRUCE_BOAT, Items.SPRUCE_CHEST_BOAT),
BIRCH(Items.BIRCH_BOAT, Items.BIRCH_CHEST_BOAT),
JUNGLE(Items.JUNGLE_BOAT, Items.JUNGLE_CHEST_BOAT),
ACACIA(Items.ACACIA_BOAT, Items.ACACIA_CHEST_BOAT),
DARK_OAK(Items.DARK_OAK_BOAT, Items.DARK_OAK_CHEST_BOAT),
MANGROVE(Items.MANGROVE_BOAT, Items.MANGROVE_CHEST_BOAT),
BAMBOO(Items.BAMBOO_RAFT, Items.BAMBOO_CHEST_RAFT),
CHERRY(Items.CHERRY_BOAT, Items.CHERRY_CHEST_BOAT);
private final Item pickItem;
final Item chestPickItem;
BoatVariant(Item pickItem, Item chestPickItem) {
this.pickItem = pickItem;
this.chestPickItem = chestPickItem;
}
}
} }

View file

@ -27,6 +27,7 @@ package org.geysermc.geyser.entity.type;
import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.math.vector.Vector3f;
import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.item.type.Item;
import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.util.InteractionResult; import org.geysermc.geyser.util.InteractionResult;
import org.geysermc.geyser.util.InteractiveTag; import org.geysermc.geyser.util.InteractiveTag;
@ -35,8 +36,8 @@ import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand;
import java.util.UUID; import java.util.UUID;
public class ChestBoatEntity extends BoatEntity { public class ChestBoatEntity extends BoatEntity {
public ChestBoatEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, EntityDefinition<?> definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) { public ChestBoatEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, EntityDefinition<?> definition, Vector3f position, Vector3f motion, float yaw, BoatVariant variant) {
super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw); super(session, entityId, geyserId, uuid, definition, position, motion, yaw, variant);
} }
@Override @Override
@ -48,4 +49,9 @@ public class ChestBoatEntity extends BoatEntity {
public InteractionResult interact(Hand hand) { public InteractionResult interact(Hand hand) {
return passengers.isEmpty() && !session.isSneaking() ? super.interact(hand) : InteractionResult.SUCCESS; return passengers.isEmpty() && !session.isSneaking() ? super.interact(hand) : InteractionResult.SUCCESS;
} }
@Override
public Item getPickItem() {
return this.variant.chestPickItem;
}
} }

View file

@ -51,29 +51,14 @@ public class BedrockEntityPickRequestTranslator extends PacketTranslator<EntityP
Entity entity = session.getEntityCache().getEntityByGeyserId(packet.getRuntimeEntityId()); Entity entity = session.getEntityCache().getEntityByGeyserId(packet.getRuntimeEntityId());
if (entity == null) return; if (entity == null) return;
if (entity instanceof BoatEntity boat) {
InventoryUtils.findOrCreateItem(session, boat.getPickItem());
return;
}
// Get the corresponding item // Get the corresponding item
String itemName; String itemName;
switch (entity.getDefinition().entityType()) { switch (entity.getDefinition().entityType()) {
case BOAT, CHEST_BOAT -> {
// Include type of boat in the name
int variant = ((BoatEntity) entity).getVariant();
String typeOfBoat = switch (variant) {
case 1 -> "spruce";
case 2 -> "birch";
case 3 -> "jungle";
case 4 -> "acacia";
case 5 -> "cherry";
case 6 -> "dark_oak";
case 7 -> "mangrove";
case 8 -> "bamboo";
default -> "oak";
};
itemName = typeOfBoat + "_" + entity.getDefinition().entityType().name().toLowerCase(Locale.ROOT);
// Bamboo boat is a raft
if (variant == 8) {
itemName = itemName.replace("boat", "raft");
}
}
case LEASH_KNOT -> itemName = "lead"; case LEASH_KNOT -> itemName = "lead";
case CHEST_MINECART, COMMAND_BLOCK_MINECART, FURNACE_MINECART, HOPPER_MINECART, TNT_MINECART -> case CHEST_MINECART, COMMAND_BLOCK_MINECART, FURNACE_MINECART, HOPPER_MINECART, TNT_MINECART ->
// The Bedrock identifier matches the item name which moves MINECART to the end of the name // The Bedrock identifier matches the item name which moves MINECART to the end of the name

View file

@ -296,6 +296,7 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
Hand.MAIN_HAND, Hand.MAIN_HAND,
packet.getClickPosition().getX(), packet.getClickPosition().getY(), packet.getClickPosition().getZ(), packet.getClickPosition().getX(), packet.getClickPosition().getY(), packet.getClickPosition().getZ(),
false, false,
false,
sequence); sequence);
session.sendDownstreamGamePacket(blockPacket); session.sendDownstreamGamePacket(blockPacket);
@ -698,9 +699,9 @@ public class BedrockInventoryTransactionTranslator extends PacketTranslator<Inve
float pitch = (float) -Math.toDegrees(Math.atan2(yDiff, xzHypot)); float pitch = (float) -Math.toDegrees(Math.atan2(yDiff, xzHypot));
SessionPlayerEntity entity = session.getPlayerEntity(); SessionPlayerEntity entity = session.getPlayerEntity();
ServerboundMovePlayerPosRotPacket returnPacket = new ServerboundMovePlayerPosRotPacket(entity.isOnGround(), playerPosition.getX(), playerPosition.getY(), playerPosition.getZ(), entity.getYaw(), entity.getPitch()); ServerboundMovePlayerPosRotPacket returnPacket = new ServerboundMovePlayerPosRotPacket(entity.isOnGround(), false, playerPosition.getX(), playerPosition.getY(), playerPosition.getZ(), entity.getYaw(), entity.getPitch());
// This matches Java edition behavior // This matches Java edition behavior
ServerboundMovePlayerPosRotPacket movementPacket = new ServerboundMovePlayerPosRotPacket(entity.isOnGround(), playerPosition.getX(), playerPosition.getY(), playerPosition.getZ(), yaw, pitch); ServerboundMovePlayerPosRotPacket movementPacket = new ServerboundMovePlayerPosRotPacket(entity.isOnGround(), false, playerPosition.getX(), playerPosition.getY(), playerPosition.getZ(), yaw, pitch);
session.sendDownstreamGamePacket(movementPacket); session.sendDownstreamGamePacket(movementPacket);
if (session.getLookBackScheduledFuture() != null) { if (session.getLookBackScheduledFuture() != null) {

View file

@ -27,7 +27,6 @@ package org.geysermc.geyser.translator.protocol.bedrock;
import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.packet.MoveEntityAbsolutePacket; import org.cloudburstmc.protocol.bedrock.packet.MoveEntityAbsolutePacket;
import org.geysermc.geyser.entity.EntityDefinitions;
import org.geysermc.geyser.entity.type.BoatEntity; import org.geysermc.geyser.entity.type.BoatEntity;
import org.geysermc.geyser.entity.type.Entity; import org.geysermc.geyser.entity.type.Entity;
import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.GeyserSession;
@ -66,7 +65,7 @@ public class BedrockMoveEntityAbsoluteTranslator extends PacketTranslator<MoveEn
float y = packet.getPosition().getY(); float y = packet.getPosition().getY();
if (ridingEntity instanceof BoatEntity && !ridingEntity.isOnGround()) { if (ridingEntity instanceof BoatEntity && !ridingEntity.isOnGround()) {
// Remove the offset to prevents boats from looking like they're floating in water // Remove the offset to prevents boats from looking like they're floating in water
y -= EntityDefinitions.BOAT.offset(); y -= ridingEntity.getDefinition().offset();
} }
ServerboundMoveVehiclePacket ServerboundMoveVehiclePacket = new ServerboundMoveVehiclePacket( ServerboundMoveVehiclePacket ServerboundMoveVehiclePacket = new ServerboundMoveVehiclePacket(
packet.getPosition().getX(), y, packet.getPosition().getZ(), packet.getPosition().getX(), y, packet.getPosition().getZ(),

View file

@ -25,11 +25,8 @@
package org.geysermc.geyser.translator.protocol.bedrock; package org.geysermc.geyser.translator.protocol.bedrock;
import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.level.ServerboundMoveVehiclePacket;
import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.level.ServerboundPlayerInputPacket;
import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.packet.PlayerInputPacket; import org.cloudburstmc.protocol.bedrock.packet.PlayerInputPacket;
import org.geysermc.geyser.entity.EntityDefinitions;
import org.geysermc.geyser.entity.type.BoatEntity; import org.geysermc.geyser.entity.type.BoatEntity;
import org.geysermc.geyser.entity.type.Entity; import org.geysermc.geyser.entity.type.Entity;
import org.geysermc.geyser.entity.type.living.animal.horse.AbstractHorseEntity; import org.geysermc.geyser.entity.type.living.animal.horse.AbstractHorseEntity;
@ -37,6 +34,7 @@ import org.geysermc.geyser.entity.type.living.animal.horse.LlamaEntity;
import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.PacketTranslator;
import org.geysermc.geyser.translator.protocol.Translator; import org.geysermc.geyser.translator.protocol.Translator;
import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.level.ServerboundMoveVehiclePacket;
/** /**
* Sent by the client for minecarts and boats. * Sent by the client for minecarts and boats.
@ -46,11 +44,11 @@ public class BedrockPlayerInputTranslator extends PacketTranslator<PlayerInputPa
@Override @Override
public void translate(GeyserSession session, PlayerInputPacket packet) { public void translate(GeyserSession session, PlayerInputPacket packet) {
ServerboundPlayerInputPacket playerInputPacket = new ServerboundPlayerInputPacket( // ServerboundPlayerInputPacket playerInputPacket = new ServerboundPlayerInputPacket(
packet.getInputMotion().getX(), packet.getInputMotion().getY(), packet.isJumping(), packet.isSneaking() // packet.getInputMotion().getX(), packet.getInputMotion().getY(), packet.isJumping(), packet.isSneaking()
); // );
//
session.sendDownstreamGamePacket(playerInputPacket); // session.sendDownstreamGamePacket(playerInputPacket);
session.getPlayerEntity().setVehicleInput(packet.getInputMotion()); session.getPlayerEntity().setVehicleInput(packet.getInputMotion());
@ -78,7 +76,7 @@ public class BedrockPlayerInputTranslator extends PacketTranslator<PlayerInputPa
if (vehicle instanceof BoatEntity && !vehicle.isOnGround()) { if (vehicle instanceof BoatEntity && !vehicle.isOnGround()) {
// Remove some Y position to prevents boats flying up // Remove some Y position to prevents boats flying up
vehiclePosition = vehiclePosition.down(EntityDefinitions.BOAT.offset()); vehiclePosition = vehiclePosition.down(vehicle.getDefinition().offset());
} }
ServerboundMoveVehiclePacket moveVehiclePacket = new ServerboundMoveVehiclePacket( ServerboundMoveVehiclePacket moveVehiclePacket = new ServerboundMoveVehiclePacket(

View file

@ -350,6 +350,7 @@ public class BedrockActionTranslator extends PacketTranslator<PlayerActionPacket
Hand.MAIN_HAND, Hand.MAIN_HAND,
0, 0, 0, 0, 0, 0,
false, false,
false,
session.getWorldCache().nextPredictionSequence()); session.getWorldCache().nextPredictionSequence());
session.sendDownstreamGamePacket(blockPacket); session.sendDownstreamGamePacket(blockPacket);
break; break;

View file

@ -25,16 +25,11 @@
package org.geysermc.geyser.translator.protocol.bedrock.entity.player; package org.geysermc.geyser.translator.protocol.bedrock.entity.player;
import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand;
import org.geysermc.mcprotocollib.protocol.data.game.entity.player.InteractAction;
import org.geysermc.mcprotocollib.protocol.data.game.entity.player.PlayerState;
import org.geysermc.mcprotocollib.protocol.data.game.entity.type.EntityType;
import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundInteractPacket;
import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundPlayerCommandPacket;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityLinkData; import org.cloudburstmc.protocol.bedrock.data.entity.EntityLinkData;
import org.cloudburstmc.protocol.bedrock.packet.InteractPacket; import org.cloudburstmc.protocol.bedrock.packet.InteractPacket;
import org.cloudburstmc.protocol.bedrock.packet.SetEntityLinkPacket; import org.cloudburstmc.protocol.bedrock.packet.SetEntityLinkPacket;
import org.geysermc.geyser.entity.type.ChestBoatEntity;
import org.geysermc.geyser.entity.type.Entity; import org.geysermc.geyser.entity.type.Entity;
import org.geysermc.geyser.entity.type.living.animal.horse.AbstractHorseEntity; import org.geysermc.geyser.entity.type.living.animal.horse.AbstractHorseEntity;
import org.geysermc.geyser.item.Items; import org.geysermc.geyser.item.Items;
@ -42,6 +37,11 @@ import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.translator.protocol.PacketTranslator; import org.geysermc.geyser.translator.protocol.PacketTranslator;
import org.geysermc.geyser.translator.protocol.Translator; import org.geysermc.geyser.translator.protocol.Translator;
import org.geysermc.geyser.util.InventoryUtils; import org.geysermc.geyser.util.InventoryUtils;
import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand;
import org.geysermc.mcprotocollib.protocol.data.game.entity.player.InteractAction;
import org.geysermc.mcprotocollib.protocol.data.game.entity.player.PlayerState;
import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundInteractPacket;
import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundPlayerCommandPacket;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
@ -119,7 +119,7 @@ public class BedrockInteractTranslator extends PacketTranslator<InteractPacket>
case OPEN_INVENTORY: case OPEN_INVENTORY:
if (session.getOpenInventory() == null) { if (session.getOpenInventory() == null) {
Entity ridingEntity = session.getPlayerEntity().getVehicle(); Entity ridingEntity = session.getPlayerEntity().getVehicle();
if (ridingEntity instanceof AbstractHorseEntity || (ridingEntity != null && ridingEntity.getDefinition().entityType() == EntityType.CHEST_BOAT)) { if (ridingEntity instanceof AbstractHorseEntity || ridingEntity instanceof ChestBoatEntity) {
// This mob has an inventory of its own that we should open instead. // This mob has an inventory of its own that we should open instead.
ServerboundPlayerCommandPacket openVehicleWindowPacket = new ServerboundPlayerCommandPacket(session.getPlayerEntity().getEntityId(), PlayerState.OPEN_VEHICLE_INVENTORY); ServerboundPlayerCommandPacket openVehicleWindowPacket = new ServerboundPlayerCommandPacket(session.getPlayerEntity().getEntityId(), PlayerState.OPEN_VEHICLE_INVENTORY);
session.sendDownstreamGamePacket(openVehicleWindowPacket); session.sendDownstreamGamePacket(openVehicleWindowPacket);

View file

@ -84,7 +84,7 @@ public class BedrockMovePlayerTranslator extends PacketTranslator<MovePlayerPack
// This isn't needed, but it makes the packets closer to vanilla // This isn't needed, but it makes the packets closer to vanilla
// It also means you can't "lag back" while only looking, in theory // It also means you can't "lag back" while only looking, in theory
if (!positionChanged && rotationChanged) { if (!positionChanged && rotationChanged) {
ServerboundMovePlayerRotPacket playerRotationPacket = new ServerboundMovePlayerRotPacket(packet.isOnGround(), yaw, pitch); ServerboundMovePlayerRotPacket playerRotationPacket = new ServerboundMovePlayerRotPacket(packet.isOnGround(), false, yaw, pitch);
entity.setYaw(yaw); entity.setYaw(yaw);
entity.setPitch(pitch); entity.setPitch(pitch);
@ -138,6 +138,7 @@ public class BedrockMovePlayerTranslator extends PacketTranslator<MovePlayerPack
// Send rotation updates as well // Send rotation updates as well
movePacket = new ServerboundMovePlayerPosRotPacket( movePacket = new ServerboundMovePlayerPosRotPacket(
onGround, onGround,
false,
position.getX(), yPosition, position.getZ(), position.getX(), yPosition, position.getZ(),
yaw, pitch yaw, pitch
); );
@ -146,7 +147,7 @@ public class BedrockMovePlayerTranslator extends PacketTranslator<MovePlayerPack
entity.setHeadYaw(headYaw); entity.setHeadYaw(headYaw);
} else { } else {
// Rotation did not change; don't send an update with rotation // Rotation did not change; don't send an update with rotation
movePacket = new ServerboundMovePlayerPosPacket(onGround, position.getX(), yPosition, position.getZ()); movePacket = new ServerboundMovePlayerPosPacket(onGround, false, position.getX(), yPosition, position.getZ());
} }
entity.setPositionManual(packet.getPosition()); entity.setPositionManual(packet.getPosition());

View file

@ -89,6 +89,7 @@ public class BedrockLevelSoundEventTranslator extends PacketTranslator<LevelSoun
Hand.MAIN_HAND, Hand.MAIN_HAND,
0, 0, 0, 0, 0, 0,
false, false,
false,
session.getWorldCache().nextPredictionSequence()); session.getWorldCache().nextPredictionSequence());
session.sendDownstreamGamePacket(blockPacket); session.sendDownstreamGamePacket(blockPacket);
} }

View file

@ -39,7 +39,7 @@ public class JavaCooldownTranslator extends PacketTranslator<ClientboundCooldown
@Override @Override
public void translate(GeyserSession session, ClientboundCooldownPacket packet) { public void translate(GeyserSession session, ClientboundCooldownPacket packet) {
Item item = Registries.JAVA_ITEMS.get().get(packet.getItemId()); Item item = Registries.JAVA_ITEMS.get().get(0); // FIXME
// Not every item, as of 1.19, appears to be server-driven. Just these two. // Not every item, as of 1.19, appears to be server-driven. Just these two.
// Use a map here if it gets too big. // Use a map here if it gets too big.
String cooldownCategory; String cooldownCategory;

View file

@ -25,7 +25,6 @@
package org.geysermc.geyser.util; package org.geysermc.geyser.util;
import java.util.Locale;
import net.kyori.adventure.key.Key; import net.kyori.adventure.key.Key;
import org.checkerframework.checker.nullness.qual.NonNull; import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.checker.nullness.qual.Nullable;
@ -35,6 +34,7 @@ import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag; import org.cloudburstmc.protocol.bedrock.data.entity.EntityFlag;
import org.geysermc.geyser.entity.EntityDefinitions; import org.geysermc.geyser.entity.EntityDefinitions;
import org.geysermc.geyser.entity.type.BoatEntity; import org.geysermc.geyser.entity.type.BoatEntity;
import org.geysermc.geyser.entity.type.ChestBoatEntity;
import org.geysermc.geyser.entity.type.Entity; import org.geysermc.geyser.entity.type.Entity;
import org.geysermc.geyser.entity.type.TextDisplayEntity; import org.geysermc.geyser.entity.type.TextDisplayEntity;
import org.geysermc.geyser.entity.type.living.ArmorStandEntity; import org.geysermc.geyser.entity.type.living.ArmorStandEntity;
@ -49,6 +49,8 @@ import org.geysermc.mcprotocollib.protocol.data.game.entity.player.GameMode;
import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand; import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand;
import org.geysermc.mcprotocollib.protocol.data.game.entity.type.EntityType; import org.geysermc.mcprotocollib.protocol.data.game.entity.type.EntityType;
import java.util.Locale;
public final class EntityUtils { public final class EntityUtils {
/** /**
* A constant array of the two hands that a player can interact with an entity. * A constant array of the two hands that a player can interact with an entity.
@ -93,6 +95,10 @@ public final class EntityUtils {
} }
private static float getMountedHeightOffset(Entity mount) { private static float getMountedHeightOffset(Entity mount) {
if (mount instanceof BoatEntity boat && boat.getVariant() != BoatEntity.BoatVariant.BAMBOO) {
return -0.1f;
}
float height = mount.getBoundingBoxHeight(); float height = mount.getBoundingBoxHeight();
float mountedHeightOffset = height * 0.75f; float mountedHeightOffset = height * 0.75f;
switch (mount.getDefinition().entityType()) { switch (mount.getDefinition().entityType()) {
@ -105,10 +111,7 @@ public final class EntityUtils {
case TRADER_LLAMA, LLAMA -> mountedHeightOffset = height * 0.6f; case TRADER_LLAMA, LLAMA -> mountedHeightOffset = height * 0.6f;
case MINECART, HOPPER_MINECART, TNT_MINECART, CHEST_MINECART, FURNACE_MINECART, SPAWNER_MINECART, case MINECART, HOPPER_MINECART, TNT_MINECART, CHEST_MINECART, FURNACE_MINECART, SPAWNER_MINECART,
COMMAND_BLOCK_MINECART -> mountedHeightOffset = 0; COMMAND_BLOCK_MINECART -> mountedHeightOffset = 0;
case BOAT, CHEST_BOAT -> { case BAMBOO_RAFT, BAMBOO_CHEST_RAFT -> mountedHeightOffset = 0.25f;
boolean isBamboo = ((BoatEntity) mount).getVariant() == 8;
mountedHeightOffset = isBamboo ? 0.25f : -0.1f;
}
case HOGLIN, ZOGLIN -> { case HOGLIN, ZOGLIN -> {
boolean isBaby = mount.getFlag(EntityFlag.BABY); boolean isBaby = mount.getFlag(EntityFlag.BABY);
mountedHeightOffset = height - (isBaby ? 0.2f : 0.15f); mountedHeightOffset = height - (isBaby ? 0.2f : 0.15f);
@ -174,15 +177,6 @@ public final class EntityUtils {
float yOffset = mountedHeightOffset + heightOffset; float yOffset = mountedHeightOffset + heightOffset;
float zOffset = 0; float zOffset = 0;
switch (mount.getDefinition().entityType()) { switch (mount.getDefinition().entityType()) {
case BOAT -> {
// Without the X offset, more than one entity on a boat is stacked on top of each other
if (moreThanOneEntity) {
xOffset = rider ? 0.2f : -0.6f;
if (passenger instanceof AnimalEntity) {
xOffset += 0.2f;
}
}
}
case CAMEL -> { case CAMEL -> {
zOffset = 0.5f; zOffset = 0.5f;
if (moreThanOneEntity) { if (moreThanOneEntity) {
@ -201,7 +195,6 @@ public final class EntityUtils {
} }
} }
} }
case CHEST_BOAT -> xOffset = 0.15F;
case CHICKEN -> zOffset = -0.1f; case CHICKEN -> zOffset = -0.1f;
case TRADER_LLAMA, LLAMA -> zOffset = -0.3f; case TRADER_LLAMA, LLAMA -> zOffset = -0.3f;
case TEXT_DISPLAY -> { case TEXT_DISPLAY -> {
@ -217,6 +210,17 @@ public final class EntityUtils {
} }
} }
} }
if (mount instanceof ChestBoatEntity) {
xOffset = 0.15F;
} else if (mount instanceof BoatEntity) {
// Without the X offset, more than one entity on a boat is stacked on top of each other
if (moreThanOneEntity) {
xOffset = rider ? 0.2f : -0.6f;
if (passenger instanceof AnimalEntity) {
xOffset += 0.2f;
}
}
}
/* /*
* Bedrock Differences * Bedrock Differences
* Zoglin & Hoglin seem to be taller in Bedrock edition * Zoglin & Hoglin seem to be taller in Bedrock edition
@ -231,13 +235,19 @@ public final class EntityUtils {
} }
switch (mount.getDefinition().entityType()) { switch (mount.getDefinition().entityType()) {
case MINECART, HOPPER_MINECART, TNT_MINECART, CHEST_MINECART, FURNACE_MINECART, SPAWNER_MINECART, case MINECART, HOPPER_MINECART, TNT_MINECART, CHEST_MINECART, FURNACE_MINECART, SPAWNER_MINECART,
COMMAND_BLOCK_MINECART, BOAT, CHEST_BOAT -> yOffset -= mount.getDefinition().height() * 0.5f; COMMAND_BLOCK_MINECART -> yOffset -= mount.getDefinition().height() * 0.5f;
} }
switch (passenger.getDefinition().entityType()) { switch (passenger.getDefinition().entityType()) {
case MINECART, HOPPER_MINECART, TNT_MINECART, CHEST_MINECART, FURNACE_MINECART, SPAWNER_MINECART, case MINECART, HOPPER_MINECART, TNT_MINECART, CHEST_MINECART, FURNACE_MINECART, SPAWNER_MINECART,
COMMAND_BLOCK_MINECART, BOAT, CHEST_BOAT -> yOffset += passenger.getDefinition().height() * 0.5f; COMMAND_BLOCK_MINECART -> yOffset += passenger.getDefinition().height() * 0.5f;
case FALLING_BLOCK -> yOffset += 0.5f; case FALLING_BLOCK -> yOffset += 0.5f;
} }
if (mount instanceof BoatEntity) {
yOffset -= mount.getDefinition().height() * 0.5f;
}
if (passenger instanceof BoatEntity) {
yOffset += passenger.getDefinition().height() * 0.5f;
}
if (mount instanceof ArmorStandEntity armorStand) { if (mount instanceof ArmorStandEntity armorStand) {
yOffset -= armorStand.getYOffset(); yOffset -= armorStand.getYOffset();
} }

View file

@ -485,7 +485,7 @@ public class InventoryUtils {
} }
for (int i = 0; i < data.ingredients().length; i++) { for (int i = 0; i < data.ingredients().length; i++) {
Ingredient ingredient = data.ingredients()[i]; Ingredient ingredient = data.ingredients()[i];
for (ItemStack itemStack : ingredient.getOptions()) { for (int item : ingredient.getValues().getHolders()) { // FIXME
boolean inventoryHasItem = false; boolean inventoryHasItem = false;
// Iterate only over the crafting table to find this item // Iterate only over the crafting table to find this item
crafting: crafting:
@ -493,11 +493,11 @@ public class InventoryUtils {
for (int col = firstCol; col < width + firstCol; col++) { for (int col = firstCol; col < width + firstCol; col++) {
GeyserItemStack geyserItemStack = inventoryGetter.apply(col + (row * gridDimensions) + 1); GeyserItemStack geyserItemStack = inventoryGetter.apply(col + (row * gridDimensions) + 1);
if (geyserItemStack.isEmpty()) { if (geyserItemStack.isEmpty()) {
inventoryHasItem = itemStack == null || itemStack.getId() == 0; inventoryHasItem = item == 0;
if (inventoryHasItem) { if (inventoryHasItem) {
break crafting; break crafting;
} }
} else if (itemStack.equals(geyserItemStack.getItemStack(1))) { } else if (item == geyserItemStack.getJavaId()) {
inventoryHasItem = true; inventoryHasItem = true;
break crafting; break crafting;
} }
@ -522,14 +522,15 @@ public class InventoryUtils {
for (int col = firstCol; col < width + firstCol; col++) { for (int col = firstCol; col < width + firstCol; col++) {
GeyserItemStack geyserItemStack = inventoryGetter.apply(col + (row * gridDimensions) + 1); GeyserItemStack geyserItemStack = inventoryGetter.apply(col + (row * gridDimensions) + 1);
Ingredient ingredient = ingredients[ingredientIndex++]; Ingredient ingredient = ingredients[ingredientIndex++];
if (ingredient.getOptions().length == 0) { int[] items = ingredient.getValues().getHolders(); // FIXME
if (items.length == 0) {
if (!geyserItemStack.isEmpty()) { if (!geyserItemStack.isEmpty()) {
return false; return false;
} }
} else { } else {
boolean inventoryHasItem = false; boolean inventoryHasItem = false;
for (ItemStack item : ingredient.getOptions()) { for (int item : items) {
if (Objects.equals(geyserItemStack.getItemStack(1), item)) { if (geyserItemStack.getJavaId() == item) {
inventoryHasItem = true; inventoryHasItem = true;
break; break;
} }