1
0
mirror of https://github.com/GeyserMC/Geyser.git synced 2025-12-19 14:59:27 +00:00

Only store GeyserItemStacks for equipment in LivingEntity

This commit is contained in:
Eclipse
2025-09-27 08:33:45 +00:00
parent af20c68236
commit 21bb3df7df
16 changed files with 110 additions and 106 deletions

View File

@@ -35,7 +35,6 @@ import org.cloudburstmc.protocol.bedrock.data.AttributeData;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; 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.cloudburstmc.protocol.bedrock.data.inventory.ContainerId; import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerId;
import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData;
import org.cloudburstmc.protocol.bedrock.packet.MobArmorEquipmentPacket; import org.cloudburstmc.protocol.bedrock.packet.MobArmorEquipmentPacket;
import org.cloudburstmc.protocol.bedrock.packet.MobEquipmentPacket; import org.cloudburstmc.protocol.bedrock.packet.MobEquipmentPacket;
import org.cloudburstmc.protocol.bedrock.packet.UpdateAttributesPacket; import org.cloudburstmc.protocol.bedrock.packet.UpdateAttributesPacket;
@@ -46,9 +45,10 @@ import org.geysermc.geyser.entity.vehicle.ClientVehicle;
import org.geysermc.geyser.entity.vehicle.HappyGhastVehicleComponent; import org.geysermc.geyser.entity.vehicle.HappyGhastVehicleComponent;
import org.geysermc.geyser.inventory.GeyserItemStack; import org.geysermc.geyser.inventory.GeyserItemStack;
import org.geysermc.geyser.item.Items; import org.geysermc.geyser.item.Items;
import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.item.type.Item;
import org.geysermc.geyser.scoreboard.Team; import org.geysermc.geyser.scoreboard.Team;
import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.session.cache.tags.ItemTag;
import org.geysermc.geyser.translator.item.ItemTranslator; import org.geysermc.geyser.translator.item.ItemTranslator;
import org.geysermc.geyser.util.AttributeUtils; import org.geysermc.geyser.util.AttributeUtils;
import org.geysermc.geyser.util.EntityUtils; import org.geysermc.geyser.util.EntityUtils;
@@ -82,15 +82,6 @@ import java.util.UUID;
public class LivingEntity extends Entity { public class LivingEntity extends Entity {
protected EnumMap<EquipmentSlot, GeyserItemStack> equipment = new EnumMap<>(EquipmentSlot.class); protected EnumMap<EquipmentSlot, GeyserItemStack> equipment = new EnumMap<>(EquipmentSlot.class);
protected ItemData helmet = ItemData.AIR;
protected ItemData chestplate = ItemData.AIR;
protected ItemData leggings = ItemData.AIR;
protected ItemData boots = ItemData.AIR;
protected ItemData body = ItemData.AIR;
protected ItemData saddle = ItemData.AIR;
protected ItemData hand = ItemData.AIR;
protected ItemData offhand = ItemData.AIR;
@Getter(value = AccessLevel.NONE) @Getter(value = AccessLevel.NONE)
protected float health = 1f; // The default value in Java Edition before any entity metadata is sent protected float health = 1f; // The default value in Java Edition before any entity metadata is sent
@Getter(value = AccessLevel.NONE) @Getter(value = AccessLevel.NONE)
@@ -116,40 +107,50 @@ public class LivingEntity extends Entity {
public LivingEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, EntityDefinition<?> definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) { public LivingEntity(GeyserSession session, int entityId, long geyserId, UUID uuid, EntityDefinition<?> definition, Vector3f position, Vector3f motion, float yaw, float pitch, float headYaw) {
super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw); super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw);
for (EquipmentSlot slot : EquipmentSlot.values()) {
equipment.put(slot, GeyserItemStack.EMPTY);
} }
public GeyserItemStack getItemInSlot(EquipmentSlot slot) {
GeyserItemStack stack = equipment.get(slot);
if (stack == null) {
return GeyserItemStack.EMPTY;
}
return stack;
}
public GeyserItemStack getMainHandItem() {
return getItemInSlot(EquipmentSlot.MAIN_HAND);
}
public GeyserItemStack getOffHandItem() {
return getItemInSlot(EquipmentSlot.OFF_HAND);
}
public boolean isHolding(Item item) {
return getMainHandItem().is(item) || getOffHandItem().is(item);
} }
public void setHelmet(GeyserItemStack stack) { public void setHelmet(GeyserItemStack stack) {
this.equipment.put(EquipmentSlot.HELMET, stack); this.equipment.put(EquipmentSlot.HELMET, stack);
this.helmet = ItemTranslator.translateToBedrock(session, stack);
} }
public void setChestplate(GeyserItemStack stack) { public void setChestplate(GeyserItemStack stack) {
this.equipment.put(EquipmentSlot.CHESTPLATE, stack); this.equipment.put(EquipmentSlot.CHESTPLATE, stack);
this.chestplate = ItemTranslator.translateToBedrock(session, stack);
} }
public void setLeggings(GeyserItemStack stack) { public void setLeggings(GeyserItemStack stack) {
this.equipment.put(EquipmentSlot.LEGGINGS, stack); this.equipment.put(EquipmentSlot.LEGGINGS, stack);
this.leggings = ItemTranslator.translateToBedrock(session, stack);
} }
public void setBoots(GeyserItemStack stack) { public void setBoots(GeyserItemStack stack) {
this.equipment.put(EquipmentSlot.BOOTS, stack); this.equipment.put(EquipmentSlot.BOOTS, stack);
this.boots = ItemTranslator.translateToBedrock(session, stack);
} }
public void setBody(GeyserItemStack stack) { public void setBody(GeyserItemStack stack) {
this.equipment.put(EquipmentSlot.BODY, stack); this.equipment.put(EquipmentSlot.BODY, stack);
this.body = ItemTranslator.translateToBedrock(session, stack);
} }
public void setSaddle(GeyserItemStack stack) { public void setSaddle(GeyserItemStack stack) {
this.equipment.put(EquipmentSlot.SADDLE, stack); this.equipment.put(EquipmentSlot.SADDLE, stack);
this.saddle = ItemTranslator.translateToBedrock(session, stack);
boolean saddled = false; boolean saddled = false;
if (!stack.isEmpty()) { if (!stack.isEmpty()) {
@@ -162,12 +163,10 @@ public class LivingEntity extends Entity {
public void setHand(GeyserItemStack stack) { public void setHand(GeyserItemStack stack) {
this.equipment.put(EquipmentSlot.MAIN_HAND, stack); this.equipment.put(EquipmentSlot.MAIN_HAND, stack);
this.hand = ItemTranslator.translateToBedrock(session, stack);
} }
public void setOffhand(GeyserItemStack stack) { public void setOffhand(GeyserItemStack stack) {
this.equipment.put(EquipmentSlot.OFF_HAND, stack); this.equipment.put(EquipmentSlot.OFF_HAND, stack);
this.offhand = ItemTranslator.translateToBedrock(session, stack);
} }
protected void updateSaddled(boolean saddled) { protected void updateSaddled(boolean saddled) {
@@ -182,13 +181,9 @@ public class LivingEntity extends Entity {
} }
public void switchHands() { public void switchHands() {
GeyserItemStack javaOffhand = this.equipment.get(EquipmentSlot.OFF_HAND); GeyserItemStack offhand = this.equipment.get(EquipmentSlot.OFF_HAND);
this.equipment.put(EquipmentSlot.OFF_HAND, this.equipment.get(EquipmentSlot.MAIN_HAND)); this.equipment.put(EquipmentSlot.OFF_HAND, this.equipment.get(EquipmentSlot.MAIN_HAND));
this.equipment.put(EquipmentSlot.MAIN_HAND, javaOffhand); this.equipment.put(EquipmentSlot.MAIN_HAND, offhand);
ItemData bedrockOffhand = this.offhand;
this.offhand = this.hand;
this.hand = bedrockOffhand;
} }
@Override @Override
@@ -283,11 +278,10 @@ public class LivingEntity extends Entity {
} }
protected boolean hasShield(boolean offhand) { protected boolean hasShield(boolean offhand) {
ItemMapping shieldMapping = session.getItemMappings().getStoredItems().shield();
if (offhand) { if (offhand) {
return this.offhand.getDefinition().equals(shieldMapping.getBedrockDefinition()); return getOffHandItem().is(Items.SHIELD);
} else { } else {
return hand.getDefinition().equals(shieldMapping.getBedrockDefinition()); return getMainHandItem().is(Items.SHIELD);
} }
} }
@@ -398,39 +392,38 @@ public class LivingEntity extends Entity {
return InteractionResult.PASS; return InteractionResult.PASS;
} }
public void updateArmor(GeyserSession session) { public void updateArmor() {
if (!valid) return; if (!valid) return;
ItemData helmet = this.helmet; GeyserItemStack helmet = getItemInSlot(EquipmentSlot.HELMET);
ItemData chestplate = this.chestplate; GeyserItemStack chestplate = getItemInSlot(EquipmentSlot.CHESTPLATE);
// If an entity has a banner on them, it will be in the helmet slot in Java but the chestplate spot in Bedrock // If an entity has a banner on them, it will be in the helmet slot in Java but the chestplate spot in Bedrock
// But don't overwrite the chestplate if it isn't empty // But don't overwrite the chestplate if it isn't empty
ItemMapping banner = session.getItemMappings().getStoredItems().banner(); if (chestplate.isEmpty() && helmet.is(session, ItemTag.BANNERS)) {
if (ItemData.AIR.equals(chestplate) && helmet.getDefinition().equals(banner.getBedrockDefinition())) { chestplate = helmet;
chestplate = this.helmet; helmet = GeyserItemStack.EMPTY;
helmet = ItemData.AIR; } else if (chestplate.is(session, ItemTag.BANNERS)) {
} else if (chestplate.getDefinition().equals(banner.getBedrockDefinition())) {
// Prevent chestplate banners from showing erroneously // Prevent chestplate banners from showing erroneously
chestplate = ItemData.AIR; chestplate = GeyserItemStack.EMPTY;
} }
MobArmorEquipmentPacket armorEquipmentPacket = new MobArmorEquipmentPacket(); MobArmorEquipmentPacket armorEquipmentPacket = new MobArmorEquipmentPacket();
armorEquipmentPacket.setRuntimeEntityId(geyserId); armorEquipmentPacket.setRuntimeEntityId(geyserId);
armorEquipmentPacket.setHelmet(helmet); armorEquipmentPacket.setHelmet(ItemTranslator.translateToBedrock(session, helmet));
armorEquipmentPacket.setChestplate(chestplate); armorEquipmentPacket.setChestplate(ItemTranslator.translateToBedrock(session, chestplate));
armorEquipmentPacket.setLeggings(leggings); armorEquipmentPacket.setLeggings(ItemTranslator.translateToBedrock(session, getItemInSlot(EquipmentSlot.LEGGINGS)));
armorEquipmentPacket.setBoots(boots); armorEquipmentPacket.setBoots(ItemTranslator.translateToBedrock(session, getItemInSlot(EquipmentSlot.BOOTS)));
armorEquipmentPacket.setBody(body); armorEquipmentPacket.setBody(ItemTranslator.translateToBedrock(session, getItemInSlot(EquipmentSlot.BODY)));
session.sendUpstreamPacket(armorEquipmentPacket); session.sendUpstreamPacket(armorEquipmentPacket);
} }
public void updateMainHand(GeyserSession session) { public void updateMainHand() {
if (!valid) return; if (!valid) return;
MobEquipmentPacket handPacket = new MobEquipmentPacket(); MobEquipmentPacket handPacket = new MobEquipmentPacket();
handPacket.setRuntimeEntityId(geyserId); handPacket.setRuntimeEntityId(geyserId);
handPacket.setItem(hand); handPacket.setItem(ItemTranslator.translateToBedrock(session, getMainHandItem()));
handPacket.setHotbarSlot(-1); handPacket.setHotbarSlot(-1);
handPacket.setInventorySlot(0); handPacket.setInventorySlot(0);
handPacket.setContainerId(ContainerId.INVENTORY); handPacket.setContainerId(ContainerId.INVENTORY);
@@ -438,12 +431,12 @@ public class LivingEntity extends Entity {
session.sendUpstreamPacket(handPacket); session.sendUpstreamPacket(handPacket);
} }
public void updateOffHand(GeyserSession session) { public void updateOffHand() {
if (!valid) return; if (!valid) return;
MobEquipmentPacket offHandPacket = new MobEquipmentPacket(); MobEquipmentPacket offHandPacket = new MobEquipmentPacket();
offHandPacket.setRuntimeEntityId(geyserId); offHandPacket.setRuntimeEntityId(geyserId);
offHandPacket.setItem(offhand); offHandPacket.setItem(ItemTranslator.translateToBedrock(session, getOffHandItem()));
offHandPacket.setHotbarSlot(-1); offHandPacket.setHotbarSlot(-1);
offHandPacket.setInventorySlot(0); offHandPacket.setInventorySlot(0);
offHandPacket.setContainerId(ContainerId.OFFHAND); offHandPacket.setContainerId(ContainerId.OFFHAND);

View File

@@ -60,9 +60,9 @@ public class AllayEntity extends MobEntity {
if (this.canDuplicate && getFlag(EntityFlag.DANCING) && isDuplicationItem(itemInHand)) { if (this.canDuplicate && getFlag(EntityFlag.DANCING) && isDuplicationItem(itemInHand)) {
// Maybe better as another tag? // Maybe better as another tag?
return InteractiveTag.GIVE_ITEM_TO_ALLAY; return InteractiveTag.GIVE_ITEM_TO_ALLAY;
} else if (!this.hand.isValid() && !itemInHand.isEmpty()) { } else if (getMainHandItem().isEmpty() && !itemInHand.isEmpty()) {
return InteractiveTag.GIVE_ITEM_TO_ALLAY; return InteractiveTag.GIVE_ITEM_TO_ALLAY;
} else if (this.hand.isValid() && hand == Hand.MAIN_HAND && itemInHand.isEmpty()) { } else if (!getMainHandItem().isEmpty() && hand == Hand.MAIN_HAND && itemInHand.isEmpty()) {
// Seems like there isn't a good tag for this yet // Seems like there isn't a good tag for this yet
return InteractiveTag.GIVE_ITEM_TO_ALLAY; return InteractiveTag.GIVE_ITEM_TO_ALLAY;
} else { } else {
@@ -76,10 +76,10 @@ public class AllayEntity extends MobEntity {
if (this.canDuplicate && getFlag(EntityFlag.DANCING) && isDuplicationItem(itemInHand)) { if (this.canDuplicate && getFlag(EntityFlag.DANCING) && isDuplicationItem(itemInHand)) {
//TOCHECK sound //TOCHECK sound
return InteractionResult.SUCCESS; return InteractionResult.SUCCESS;
} else if (!this.hand.isValid() && !itemInHand.isEmpty()) { } else if (getMainHandItem().isEmpty() && !itemInHand.isEmpty()) {
//TODO play sound? //TODO play sound?
return InteractionResult.SUCCESS; return InteractionResult.SUCCESS;
} else if (this.hand.isValid() && hand == Hand.MAIN_HAND && itemInHand.isEmpty()) { } else if (!getMainHandItem().isEmpty() && hand == Hand.MAIN_HAND && itemInHand.isEmpty()) {
//TOCHECK also play sound here? //TOCHECK also play sound here?
return InteractionResult.SUCCESS; return InteractionResult.SUCCESS;
} else { } else {

View File

@@ -32,7 +32,6 @@ import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataType; import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataType;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; 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.cloudburstmc.protocol.bedrock.data.inventory.ItemData;
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.entity.type.LivingEntity; import org.geysermc.geyser.entity.type.LivingEntity;
@@ -42,6 +41,7 @@ import org.geysermc.geyser.scoreboard.Team;
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.MathUtils; import org.geysermc.geyser.util.MathUtils;
import org.geysermc.mcprotocollib.protocol.data.game.entity.EquipmentSlot;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.EntityMetadata; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.EntityMetadata;
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.ByteEntityMetadata; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ByteEntityMetadata;
@@ -332,8 +332,7 @@ public class ArmorStandEntity extends LivingEntity {
return; return;
} }
boolean isNametagEmpty = nametag.isEmpty(); boolean isNametagEmpty = nametag.isEmpty();
if (!isNametagEmpty && (!helmet.equals(ItemData.AIR) || !chestplate.equals(ItemData.AIR) || !leggings.equals(ItemData.AIR) if (!isNametagEmpty && hasAnyEquipment()) {
|| !boots.equals(ItemData.AIR) || !hand.equals(ItemData.AIR) || !offhand.equals(ItemData.AIR))) {
// Reset scale of the proper armor stand // Reset scale of the proper armor stand
setScale(getScale()); setScale(getScale());
// Set the proper armor stand to invisible to show armor // Set the proper armor stand to invisible to show armor
@@ -396,6 +395,12 @@ public class ArmorStandEntity extends LivingEntity {
} }
} }
private boolean hasAnyEquipment() {
return (!getItemInSlot(EquipmentSlot.HELMET).isEmpty() || !getItemInSlot(EquipmentSlot.CHESTPLATE).isEmpty()
|| !getItemInSlot(EquipmentSlot.LEGGINGS).isEmpty() || !getItemInSlot(EquipmentSlot.BOOTS).isEmpty()
|| !getMainHandItem().isEmpty() || !getOffHandItem().isEmpty());
}
@Override @Override
public float getBoundingBoxWidth() { public float getBoundingBoxWidth() {
// For consistency with getBoundingBoxHeight() // For consistency with getBoundingBoxHeight()

View File

@@ -64,7 +64,7 @@ public class PandaEntity extends AnimalEntity {
packet.setRuntimeEntityId(geyserId); packet.setRuntimeEntityId(geyserId);
packet.setType(EntityEventType.EATING_ITEM); packet.setType(EntityEventType.EATING_ITEM);
// As of 1.20.5 - pandas can eat cake // As of 1.20.5 - pandas can eat cake
packet.setData(this.hand.getDefinition().getRuntimeId() << 16); packet.setData(session.getItemMappings().getMapping(getMainHandItem()).getBedrockDefinition().getRuntimeId() << 16);
session.sendUpstreamPacket(packet); session.sendUpstreamPacket(packet);
} }
} }

View File

@@ -29,7 +29,6 @@ import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.checker.nullness.qual.Nullable;
import org.cloudburstmc.math.vector.Vector2f; import org.cloudburstmc.math.vector.Vector2f;
import org.cloudburstmc.math.vector.Vector3f; 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.data.entity.EntityFlag;
import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.entity.type.Entity; import org.geysermc.geyser.entity.type.Entity;
@@ -157,8 +156,7 @@ public class StriderEntity extends AnimalEntity implements Tickable, ClientVehic
vehicleComponent.tickBoost(); vehicleComponent.tickBoost();
} }
} else { // getHand() for session player seems to always return air } else { // getHand() for session player seems to always return air
ItemDefinition itemDefinition = session.getItemMappings().getStoredItems().warpedFungusOnAStick().getBedrockDefinition(); if (player.isHolding(Items.WARPED_FUNGUS_ON_A_STICK)) {
if (player.getHand().getDefinition() == itemDefinition || player.getOffhand().getDefinition() == itemDefinition) {
vehicleComponent.tickBoost(); vehicleComponent.tickBoost();
} }
} }

View File

@@ -29,7 +29,6 @@ import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable; import org.checkerframework.checker.nullness.qual.Nullable;
import org.cloudburstmc.math.vector.Vector2f; import org.cloudburstmc.math.vector.Vector2f;
import org.cloudburstmc.math.vector.Vector3f; 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.data.entity.EntityFlag;
import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.entity.type.Tickable; import org.geysermc.geyser.entity.type.Tickable;
@@ -116,8 +115,7 @@ public class PigEntity extends TemperatureVariantAnimal implements Tickable, Cli
vehicleComponent.tickBoost(); vehicleComponent.tickBoost();
} }
} else { // getHand() for session player seems to always return air } else { // getHand() for session player seems to always return air
ItemDefinition itemDefinition = session.getItemMappings().getStoredItems().carrotOnAStick().getBedrockDefinition(); if (player.isHolding(Items.CARROT_ON_A_STICK)) {
if (player.getHand().getDefinition() == itemDefinition || player.getOffhand().getDefinition() == itemDefinition) {
vehicleComponent.tickBoost(); vehicleComponent.tickBoost();
} }
} }

View File

@@ -47,6 +47,7 @@ import org.geysermc.geyser.session.cache.tags.Tag;
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.geyser.util.ItemUtils; import org.geysermc.geyser.util.ItemUtils;
import org.geysermc.mcprotocollib.protocol.data.game.entity.EquipmentSlot;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ByteEntityMetadata; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ByteEntityMetadata;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.IntEntityMetadata; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.IntEntityMetadata;
import org.geysermc.mcprotocollib.protocol.data.game.entity.player.GameMode; import org.geysermc.mcprotocollib.protocol.data.game.entity.player.GameMode;
@@ -159,17 +160,16 @@ public class WolfEntity extends TameableEntity implements VariantIntHolder {
return super.testMobInteraction(hand, itemInHand); return super.testMobInteraction(hand, itemInHand);
} }
} }
if (itemInHand.asItem() == Items.WOLF_ARMOR && !this.body.isValid() && !getFlag(EntityFlag.BABY)) { if (itemInHand.asItem() == Items.WOLF_ARMOR && !getItemInSlot(EquipmentSlot.BODY).isEmpty() && !getFlag(EntityFlag.BABY)) {
return InteractiveTag.EQUIP_WOLF_ARMOR; return InteractiveTag.EQUIP_WOLF_ARMOR;
} }
if (itemInHand.asItem() == Items.SHEARS && this.body.isValid() if (itemInHand.asItem() == Items.SHEARS && !getItemInSlot(EquipmentSlot.BODY).isEmpty()
&& (!isCurseOfBinding || session.getGameMode().equals(GameMode.CREATIVE))) { && (!isCurseOfBinding || session.getGameMode().equals(GameMode.CREATIVE))) {
return InteractiveTag.REMOVE_WOLF_ARMOR; return InteractiveTag.REMOVE_WOLF_ARMOR;
} }
if (getFlag(EntityFlag.SITTING) && if (getFlag(EntityFlag.SITTING) &&
session.getTagCache().isItem(repairableItems, itemInHand.asItem()) && session.getTagCache().isItem(repairableItems, itemInHand.asItem()) &&
this.body.isValid() && this.body.getTag() != null && !getItemInSlot(EquipmentSlot.BODY).isEmpty() && getItemInSlot(EquipmentSlot.BODY).isDamaged()) {
this.body.getTag().getInt("Damage") > 0) {
return InteractiveTag.REPAIR_WOLF_ARMOR; return InteractiveTag.REPAIR_WOLF_ARMOR;
} }
// Tamed and owned by player - can sit/stand // Tamed and owned by player - can sit/stand

View File

@@ -26,10 +26,10 @@
package org.geysermc.geyser.entity.type.living.monster; package org.geysermc.geyser.entity.type.living.monster;
import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.definitions.ItemDefinition;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; 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.EntityDefinition; import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.item.Items;
import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ByteEntityMetadata; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ByteEntityMetadata;
@@ -49,8 +49,7 @@ public class AbstractSkeletonEntity extends MonsterEntity {
dirtyMetadata.put(EntityDataTypes.TARGET_EID, ((xd & 4) == 4) ? geyserId : 0); dirtyMetadata.put(EntityDataTypes.TARGET_EID, ((xd & 4) == 4) ? geyserId : 0);
if ((xd & 4) == 4) { if ((xd & 4) == 4) {
ItemDefinition bow = session.getItemMappings().getStoredItems().bow().getBedrockDefinition(); setFlag(EntityFlag.FACING_TARGET_TO_RANGE_ATTACK, isHolding(Items.BOW));
setFlag(EntityFlag.FACING_TARGET_TO_RANGE_ATTACK, this.hand.getDefinition() == bow || this.offhand.getDefinition() == bow);
} else { } else {
setFlag(EntityFlag.FACING_TARGET_TO_RANGE_ATTACK, false); setFlag(EntityFlag.FACING_TARGET_TO_RANGE_ATTACK, false);
} }

View File

@@ -42,6 +42,7 @@ 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.player.Hand; import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand;
import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentTypes;
import java.util.UUID; import java.util.UUID;
@@ -74,14 +75,14 @@ public class PiglinEntity extends BasePiglinEntity {
ItemMapping crossbow = session.getItemMappings().getStoredItems().crossbow(); ItemMapping crossbow = session.getItemMappings().getStoredItems().crossbow();
boolean toCrossbow = stack != null && stack.asItem() == crossbow.getJavaItem(); boolean toCrossbow = stack != null && stack.asItem() == crossbow.getJavaItem();
if (toCrossbow ^ this.hand.getDefinition() == crossbow.getBedrockDefinition()) { // If switching to/from crossbow if (toCrossbow ^ getMainHandItem().is(Items.CROSSBOW)) { // If switching to/from crossbow
dirtyMetadata.put(EntityDataTypes.BLOCK, session.getBlockMappings().getDefinition(toCrossbow ? 0 : 1)); dirtyMetadata.put(EntityDataTypes.BLOCK, session.getBlockMappings().getDefinition(toCrossbow ? 0 : 1));
dirtyMetadata.put(EntityDataTypes.CHARGE_AMOUNT, (byte) 0); dirtyMetadata.put(EntityDataTypes.CHARGE_AMOUNT, (byte) 0);
setFlag(EntityFlag.CHARGED, false); setFlag(EntityFlag.CHARGED, false);
setFlag(EntityFlag.USING_ITEM, false); setFlag(EntityFlag.USING_ITEM, false);
updateBedrockMetadata(); updateBedrockMetadata();
if (this.hand.isValid()) { if (!getMainHandItem().isEmpty()) {
MobEquipmentPacket mobEquipmentPacket = new MobEquipmentPacket(); MobEquipmentPacket mobEquipmentPacket = new MobEquipmentPacket();
mobEquipmentPacket.setRuntimeEntityId(geyserId); mobEquipmentPacket.setRuntimeEntityId(geyserId);
mobEquipmentPacket.setContainerId(ContainerId.INVENTORY); mobEquipmentPacket.setContainerId(ContainerId.INVENTORY);
@@ -96,11 +97,11 @@ public class PiglinEntity extends BasePiglinEntity {
} }
@Override @Override
public void updateMainHand(GeyserSession session) { public void updateMainHand() {
super.updateMainHand(session); super.updateMainHand();
if (this.hand.getDefinition() == session.getItemMappings().getStoredItems().crossbow().getBedrockDefinition()) { if (getMainHandItem().is(Items.CROSSBOW)) {
if (this.hand.getTag() != null && this.hand.getTag().containsKey("chargedItem")) { if (getMainHandItem().getComponent(DataComponentTypes.CHARGED_PROJECTILES) != null) {
dirtyMetadata.put(EntityDataTypes.CHARGE_AMOUNT, Byte.MAX_VALUE); dirtyMetadata.put(EntityDataTypes.CHARGE_AMOUNT, Byte.MAX_VALUE);
setFlag(EntityFlag.CHARGING, false); setFlag(EntityFlag.CHARGING, false);
setFlag(EntityFlag.CHARGED, true); setFlag(EntityFlag.CHARGED, true);
@@ -116,12 +117,12 @@ public class PiglinEntity extends BasePiglinEntity {
} }
@Override @Override
public void updateOffHand(GeyserSession session) { public void updateOffHand() {
// Check if the Piglin is holding Gold and set the ADMIRING flag accordingly so its pose updates // Check if the Piglin is holding Gold and set the ADMIRING flag accordingly so its pose updates
setFlag(EntityFlag.ADMIRING, session.getTagCache().is(ItemTag.PIGLIN_LOVED, session.getItemMappings().getMapping(this.offhand).getJavaItem())); setFlag(EntityFlag.ADMIRING, getOffHandItem().is(session, ItemTag.PIGLIN_LOVED));
super.updateBedrockMetadata(); super.updateBedrockMetadata();
super.updateOffHand(session); super.updateOffHand();
} }
@NonNull @NonNull

View File

@@ -28,11 +28,12 @@ package org.geysermc.geyser.entity.type.living.monster.raid;
import org.cloudburstmc.math.vector.Vector3f; import org.cloudburstmc.math.vector.Vector3f;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; 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.cloudburstmc.protocol.bedrock.data.inventory.ItemData;
import org.geysermc.geyser.entity.EntityDefinition; import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.registry.type.ItemMapping; import org.geysermc.geyser.inventory.GeyserItemStack;
import org.geysermc.geyser.item.Items;
import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.GeyserSession;
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.item.component.DataComponentTypes;
import java.util.UUID; import java.util.UUID;
@@ -49,33 +50,32 @@ public class PillagerEntity extends AbstractIllagerEntity {
} }
@Override @Override
public void updateMainHand(GeyserSession session) { public void updateMainHand() {
updateCrossbow(); updateCrossbow();
super.updateMainHand(session); super.updateMainHand();
} }
@Override @Override
public void updateOffHand(GeyserSession session) { public void updateOffHand() {
updateCrossbow(); updateCrossbow();
super.updateOffHand(session); super.updateOffHand();
} }
/** /**
* Check for a crossbow in either the mainhand or offhand. If one exists, indicate that the pillager should be posing * Check for a crossbow in either the mainhand or offhand. If one exists, indicate that the pillager should be posing
*/ */
protected void updateCrossbow() { protected void updateCrossbow() {
ItemMapping crossbow = session.getItemMappings().getStoredItems().crossbow(); GeyserItemStack activeCrossbow = null;
ItemData activeCrossbow = null; if (getMainHandItem().is(Items.CROSSBOW)) {
if (this.hand.getDefinition() == crossbow.getBedrockDefinition()) { activeCrossbow = getMainHandItem();
activeCrossbow = this.hand; } else if (getOffHandItem().is(Items.CROSSBOW)) {
} else if (this.offhand.getDefinition() == crossbow.getBedrockDefinition()) { activeCrossbow = getOffHandItem();
activeCrossbow = this.offhand;
} }
if (activeCrossbow != null) { if (activeCrossbow != null) {
if (activeCrossbow.getTag() != null && activeCrossbow.getTag().containsKey("chargedItem")) { if (activeCrossbow.getComponent(DataComponentTypes.CHARGED_PROJECTILES) != null) {
dirtyMetadata.put(EntityDataTypes.CHARGE_AMOUNT, Byte.MAX_VALUE); dirtyMetadata.put(EntityDataTypes.CHARGE_AMOUNT, Byte.MAX_VALUE);
setFlag(EntityFlag.CHARGING, false); setFlag(EntityFlag.CHARGING, false);
setFlag(EntityFlag.CHARGED, true); setFlag(EntityFlag.CHARGED, true);

View File

@@ -39,7 +39,6 @@ import org.cloudburstmc.protocol.bedrock.data.command.CommandPermission;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes; 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.cloudburstmc.protocol.bedrock.data.entity.EntityLinkData; import org.cloudburstmc.protocol.bedrock.data.entity.EntityLinkData;
import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData;
import org.cloudburstmc.protocol.bedrock.packet.AddPlayerPacket; import org.cloudburstmc.protocol.bedrock.packet.AddPlayerPacket;
import org.cloudburstmc.protocol.bedrock.packet.MovePlayerPacket; import org.cloudburstmc.protocol.bedrock.packet.MovePlayerPacket;
import org.cloudburstmc.protocol.bedrock.packet.SetEntityLinkPacket; import org.cloudburstmc.protocol.bedrock.packet.SetEntityLinkPacket;
@@ -52,6 +51,7 @@ import org.geysermc.geyser.entity.type.LivingEntity;
import org.geysermc.geyser.entity.type.living.animal.tameable.ParrotEntity; import org.geysermc.geyser.entity.type.living.animal.tameable.ParrotEntity;
import org.geysermc.geyser.level.block.Blocks; import org.geysermc.geyser.level.block.Blocks;
import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.translator.item.ItemTranslator;
import org.geysermc.geyser.util.ChunkUtils; import org.geysermc.geyser.util.ChunkUtils;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.EntityMetadata; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.EntityMetadata;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.Pose; import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.Pose;
@@ -135,7 +135,7 @@ public class PlayerEntity extends LivingEntity implements GeyserPlayerEntity {
addPlayerPacket.setPosition(position.sub(0, definition.offset(), 0)); addPlayerPacket.setPosition(position.sub(0, definition.offset(), 0));
addPlayerPacket.setRotation(getBedrockRotation()); addPlayerPacket.setRotation(getBedrockRotation());
addPlayerPacket.setMotion(motion); addPlayerPacket.setMotion(motion);
addPlayerPacket.setHand(hand); addPlayerPacket.setHand(ItemTranslator.translateToBedrock(session, getMainHandItem()));
addPlayerPacket.getAdventureSettings().setCommandPermission(CommandPermission.ANY); addPlayerPacket.getAdventureSettings().setCommandPermission(CommandPermission.ANY);
addPlayerPacket.getAdventureSettings().setPlayerPermission(PlayerPermission.MEMBER); addPlayerPacket.getAdventureSettings().setPlayerPermission(PlayerPermission.MEMBER);
addPlayerPacket.setDeviceId(""); addPlayerPacket.setDeviceId("");
@@ -164,12 +164,6 @@ public class PlayerEntity extends LivingEntity implements GeyserPlayerEntity {
this.nametag = username; this.nametag = username;
this.equipment.clear(); this.equipment.clear();
this.hand = ItemData.AIR;
this.offhand = ItemData.AIR;
this.boots = ItemData.AIR;
this.leggings = ItemData.AIR;
this.chestplate = ItemData.AIR;
this.helmet = ItemData.AIR;
} }
public void resetMetadata() { public void resetMetadata() {

View File

@@ -41,6 +41,7 @@ import org.geysermc.geyser.level.physics.Direction;
import org.geysermc.geyser.session.GeyserSession; import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.session.cache.SkullCache; import org.geysermc.geyser.session.cache.SkullCache;
import org.geysermc.geyser.skin.SkullSkinManager; import org.geysermc.geyser.skin.SkullSkinManager;
import org.geysermc.geyser.translator.item.ItemTranslator;
import java.util.Objects; import java.util.Objects;
import java.util.UUID; import java.util.UUID;
@@ -86,7 +87,7 @@ public class SkullPlayerEntity extends PlayerEntity {
addPlayerPacket.setPosition(position.sub(0, definition.offset(), 0)); addPlayerPacket.setPosition(position.sub(0, definition.offset(), 0));
addPlayerPacket.setRotation(getBedrockRotation()); addPlayerPacket.setRotation(getBedrockRotation());
addPlayerPacket.setMotion(motion); addPlayerPacket.setMotion(motion);
addPlayerPacket.setHand(hand); addPlayerPacket.setHand(ItemTranslator.translateToBedrock(session, getMainHandItem()));
addPlayerPacket.getAdventureSettings().setCommandPermission(CommandPermission.ANY); addPlayerPacket.getAdventureSettings().setCommandPermission(CommandPermission.ANY);
addPlayerPacket.getAdventureSettings().setPlayerPermission(PlayerPermission.MEMBER); addPlayerPacket.getAdventureSettings().setPlayerPermission(PlayerPermission.MEMBER);
addPlayerPacket.setDeviceId(""); addPlayerPacket.setDeviceId("");

View File

@@ -275,6 +275,10 @@ public class GeyserItemStack {
return getComponent(DataComponentTypes.MAX_DAMAGE) != null && getComponent(DataComponentTypes.UNBREAKABLE) == null && getComponent(DataComponentTypes.DAMAGE) != null; return getComponent(DataComponentTypes.MAX_DAMAGE) != null && getComponent(DataComponentTypes.UNBREAKABLE) == null && getComponent(DataComponentTypes.DAMAGE) != null;
} }
public boolean isDamaged() {
return isDamageable() && getDamage() > 0;
}
public Item asItem() { public Item asItem() {
if (isEmpty()) { if (isEmpty()) {
return Items.AIR; return Items.AIR;

View File

@@ -38,6 +38,7 @@ import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData;
import org.cloudburstmc.protocol.common.DefinitionRegistry; import org.cloudburstmc.protocol.common.DefinitionRegistry;
import org.geysermc.geyser.GeyserImpl; import org.geysermc.geyser.GeyserImpl;
import org.geysermc.geyser.api.block.custom.CustomBlockData; import org.geysermc.geyser.api.block.custom.CustomBlockData;
import org.geysermc.geyser.inventory.GeyserItemStack;
import org.geysermc.geyser.inventory.item.StoredItemMappings; import org.geysermc.geyser.inventory.item.StoredItemMappings;
import org.geysermc.geyser.item.Items; import org.geysermc.geyser.item.Items;
import org.geysermc.geyser.item.type.Item; import org.geysermc.geyser.item.type.Item;
@@ -75,11 +76,21 @@ public class ItemMappings implements DefinitionRegistry<ItemDefinition> {
Object2ObjectMap<CustomBlockData, ItemDefinition> customBlockItemDefinitions; Object2ObjectMap<CustomBlockData, ItemDefinition> customBlockItemDefinitions;
/**
* Gets an {@link ItemMapping} from the given {@link GeyserItemStack}.
*
* @param itemStack the itemstack
* @return an item entry from the given item stack
*/
public ItemMapping getMapping(@NonNull GeyserItemStack itemStack) {
return this.getMapping(itemStack.getJavaId());
}
/** /**
* Gets an {@link ItemMapping} from the given {@link ItemStack}. * Gets an {@link ItemMapping} from the given {@link ItemStack}.
* *
* @param itemStack the itemstack * @param itemStack the itemstack
* @return an item entry from the given java edition identifier * @return an item entry from the given java edition item stack
*/ */
@NonNull @NonNull
public ItemMapping getMapping(@NonNull ItemStack itemStack) { public ItemMapping getMapping(@NonNull ItemStack itemStack) {

View File

@@ -259,8 +259,8 @@ public class JavaEntityEventTranslator extends PacketTranslator<ClientboundEntit
if (entity instanceof LivingEntity livingEntity) { if (entity instanceof LivingEntity livingEntity) {
livingEntity.switchHands(); livingEntity.switchHands();
livingEntity.updateMainHand(session); livingEntity.updateMainHand();
livingEntity.updateOffHand(session); livingEntity.updateOffHand();
} else { } else {
session.getGeyser().getLogger().debug("Got status message to swap hands for a non-living entity."); session.getGeyser().getLogger().debug("Got status message to swap hands for a non-living entity.");
} }

View File

@@ -104,13 +104,13 @@ public class JavaSetEquipmentTranslator extends PacketTranslator<ClientboundSetE
} }
if (armorUpdated) { if (armorUpdated) {
livingEntity.updateArmor(session); livingEntity.updateArmor();
} }
if (mainHandUpdated) { if (mainHandUpdated) {
livingEntity.updateMainHand(session); livingEntity.updateMainHand();
} }
if (offHandUpdated) { if (offHandUpdated) {
livingEntity.updateOffHand(session); livingEntity.updateOffHand();
} }
} }
} }