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.EntityFlag;
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.MobEquipmentPacket;
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.inventory.GeyserItemStack;
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.session.GeyserSession;
import org.geysermc.geyser.session.cache.tags.ItemTag;
import org.geysermc.geyser.translator.item.ItemTranslator;
import org.geysermc.geyser.util.AttributeUtils;
import org.geysermc.geyser.util.EntityUtils;
@@ -82,15 +82,6 @@ import java.util.UUID;
public class LivingEntity extends Entity {
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)
protected float health = 1f; // The default value in Java Edition before any entity metadata is sent
@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) {
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) {
this.equipment.put(EquipmentSlot.HELMET, stack);
this.helmet = ItemTranslator.translateToBedrock(session, stack);
}
public void setChestplate(GeyserItemStack stack) {
this.equipment.put(EquipmentSlot.CHESTPLATE, stack);
this.chestplate = ItemTranslator.translateToBedrock(session, stack);
}
public void setLeggings(GeyserItemStack stack) {
this.equipment.put(EquipmentSlot.LEGGINGS, stack);
this.leggings = ItemTranslator.translateToBedrock(session, stack);
}
public void setBoots(GeyserItemStack stack) {
this.equipment.put(EquipmentSlot.BOOTS, stack);
this.boots = ItemTranslator.translateToBedrock(session, stack);
}
public void setBody(GeyserItemStack stack) {
this.equipment.put(EquipmentSlot.BODY, stack);
this.body = ItemTranslator.translateToBedrock(session, stack);
}
public void setSaddle(GeyserItemStack stack) {
this.equipment.put(EquipmentSlot.SADDLE, stack);
this.saddle = ItemTranslator.translateToBedrock(session, stack);
boolean saddled = false;
if (!stack.isEmpty()) {
@@ -162,12 +163,10 @@ public class LivingEntity extends Entity {
public void setHand(GeyserItemStack stack) {
this.equipment.put(EquipmentSlot.MAIN_HAND, stack);
this.hand = ItemTranslator.translateToBedrock(session, stack);
}
public void setOffhand(GeyserItemStack stack) {
this.equipment.put(EquipmentSlot.OFF_HAND, stack);
this.offhand = ItemTranslator.translateToBedrock(session, stack);
}
protected void updateSaddled(boolean saddled) {
@@ -182,13 +181,9 @@ public class LivingEntity extends Entity {
}
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.MAIN_HAND, javaOffhand);
ItemData bedrockOffhand = this.offhand;
this.offhand = this.hand;
this.hand = bedrockOffhand;
this.equipment.put(EquipmentSlot.MAIN_HAND, offhand);
}
@Override
@@ -283,11 +278,10 @@ public class LivingEntity extends Entity {
}
protected boolean hasShield(boolean offhand) {
ItemMapping shieldMapping = session.getItemMappings().getStoredItems().shield();
if (offhand) {
return this.offhand.getDefinition().equals(shieldMapping.getBedrockDefinition());
return getOffHandItem().is(Items.SHIELD);
} else {
return hand.getDefinition().equals(shieldMapping.getBedrockDefinition());
return getMainHandItem().is(Items.SHIELD);
}
}
@@ -398,39 +392,38 @@ public class LivingEntity extends Entity {
return InteractionResult.PASS;
}
public void updateArmor(GeyserSession session) {
public void updateArmor() {
if (!valid) return;
ItemData helmet = this.helmet;
ItemData chestplate = this.chestplate;
GeyserItemStack helmet = getItemInSlot(EquipmentSlot.HELMET);
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
// But don't overwrite the chestplate if it isn't empty
ItemMapping banner = session.getItemMappings().getStoredItems().banner();
if (ItemData.AIR.equals(chestplate) && helmet.getDefinition().equals(banner.getBedrockDefinition())) {
chestplate = this.helmet;
helmet = ItemData.AIR;
} else if (chestplate.getDefinition().equals(banner.getBedrockDefinition())) {
if (chestplate.isEmpty() && helmet.is(session, ItemTag.BANNERS)) {
chestplate = helmet;
helmet = GeyserItemStack.EMPTY;
} else if (chestplate.is(session, ItemTag.BANNERS)) {
// Prevent chestplate banners from showing erroneously
chestplate = ItemData.AIR;
chestplate = GeyserItemStack.EMPTY;
}
MobArmorEquipmentPacket armorEquipmentPacket = new MobArmorEquipmentPacket();
armorEquipmentPacket.setRuntimeEntityId(geyserId);
armorEquipmentPacket.setHelmet(helmet);
armorEquipmentPacket.setChestplate(chestplate);
armorEquipmentPacket.setLeggings(leggings);
armorEquipmentPacket.setBoots(boots);
armorEquipmentPacket.setBody(body);
armorEquipmentPacket.setHelmet(ItemTranslator.translateToBedrock(session, helmet));
armorEquipmentPacket.setChestplate(ItemTranslator.translateToBedrock(session, chestplate));
armorEquipmentPacket.setLeggings(ItemTranslator.translateToBedrock(session, getItemInSlot(EquipmentSlot.LEGGINGS)));
armorEquipmentPacket.setBoots(ItemTranslator.translateToBedrock(session, getItemInSlot(EquipmentSlot.BOOTS)));
armorEquipmentPacket.setBody(ItemTranslator.translateToBedrock(session, getItemInSlot(EquipmentSlot.BODY)));
session.sendUpstreamPacket(armorEquipmentPacket);
}
public void updateMainHand(GeyserSession session) {
public void updateMainHand() {
if (!valid) return;
MobEquipmentPacket handPacket = new MobEquipmentPacket();
handPacket.setRuntimeEntityId(geyserId);
handPacket.setItem(hand);
handPacket.setItem(ItemTranslator.translateToBedrock(session, getMainHandItem()));
handPacket.setHotbarSlot(-1);
handPacket.setInventorySlot(0);
handPacket.setContainerId(ContainerId.INVENTORY);
@@ -438,12 +431,12 @@ public class LivingEntity extends Entity {
session.sendUpstreamPacket(handPacket);
}
public void updateOffHand(GeyserSession session) {
public void updateOffHand() {
if (!valid) return;
MobEquipmentPacket offHandPacket = new MobEquipmentPacket();
offHandPacket.setRuntimeEntityId(geyserId);
offHandPacket.setItem(offhand);
offHandPacket.setItem(ItemTranslator.translateToBedrock(session, getOffHandItem()));
offHandPacket.setHotbarSlot(-1);
offHandPacket.setInventorySlot(0);
offHandPacket.setContainerId(ContainerId.OFFHAND);

View File

@@ -60,9 +60,9 @@ public class AllayEntity extends MobEntity {
if (this.canDuplicate && getFlag(EntityFlag.DANCING) && isDuplicationItem(itemInHand)) {
// Maybe better as another tag?
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;
} 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
return InteractiveTag.GIVE_ITEM_TO_ALLAY;
} else {
@@ -76,10 +76,10 @@ public class AllayEntity extends MobEntity {
if (this.canDuplicate && getFlag(EntityFlag.DANCING) && isDuplicationItem(itemInHand)) {
//TOCHECK sound
return InteractionResult.SUCCESS;
} else if (!this.hand.isValid() && !itemInHand.isEmpty()) {
} else if (getMainHandItem().isEmpty() && !itemInHand.isEmpty()) {
//TODO play sound?
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?
return InteractionResult.SUCCESS;
} 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.EntityDataTypes;
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.EntityDefinitions;
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.util.InteractionResult;
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.type.BooleanEntityMetadata;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.ByteEntityMetadata;
@@ -332,8 +332,7 @@ public class ArmorStandEntity extends LivingEntity {
return;
}
boolean isNametagEmpty = nametag.isEmpty();
if (!isNametagEmpty && (!helmet.equals(ItemData.AIR) || !chestplate.equals(ItemData.AIR) || !leggings.equals(ItemData.AIR)
|| !boots.equals(ItemData.AIR) || !hand.equals(ItemData.AIR) || !offhand.equals(ItemData.AIR))) {
if (!isNametagEmpty && hasAnyEquipment()) {
// Reset scale of the proper armor stand
setScale(getScale());
// 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
public float getBoundingBoxWidth() {
// For consistency with getBoundingBoxHeight()

View File

@@ -64,7 +64,7 @@ public class PandaEntity extends AnimalEntity {
packet.setRuntimeEntityId(geyserId);
packet.setType(EntityEventType.EATING_ITEM);
// 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);
}
}

View File

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

View File

@@ -29,7 +29,6 @@ import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.checker.nullness.qual.Nullable;
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.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.entity.type.Tickable;
@@ -116,8 +115,7 @@ public class PigEntity extends TemperatureVariantAnimal implements Tickable, Cli
vehicleComponent.tickBoost();
}
} else { // getHand() for session player seems to always return air
ItemDefinition itemDefinition = session.getItemMappings().getStoredItems().carrotOnAStick().getBedrockDefinition();
if (player.getHand().getDefinition() == itemDefinition || player.getOffhand().getDefinition() == itemDefinition) {
if (player.isHolding(Items.CARROT_ON_A_STICK)) {
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.InteractiveTag;
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.IntEntityMetadata;
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);
}
}
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;
}
if (itemInHand.asItem() == Items.SHEARS && this.body.isValid()
if (itemInHand.asItem() == Items.SHEARS && !getItemInSlot(EquipmentSlot.BODY).isEmpty()
&& (!isCurseOfBinding || session.getGameMode().equals(GameMode.CREATIVE))) {
return InteractiveTag.REMOVE_WOLF_ARMOR;
}
if (getFlag(EntityFlag.SITTING) &&
session.getTagCache().isItem(repairableItems, itemInHand.asItem()) &&
this.body.isValid() && this.body.getTag() != null &&
this.body.getTag().getInt("Damage") > 0) {
!getItemInSlot(EquipmentSlot.BODY).isEmpty() && getItemInSlot(EquipmentSlot.BODY).isDamaged()) {
return InteractiveTag.REPAIR_WOLF_ARMOR;
}
// Tamed and owned by player - can sit/stand

View File

@@ -26,10 +26,10 @@
package org.geysermc.geyser.entity.type.living.monster;
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.EntityFlag;
import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.item.Items;
import org.geysermc.geyser.session.GeyserSession;
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);
if ((xd & 4) == 4) {
ItemDefinition bow = session.getItemMappings().getStoredItems().bow().getBedrockDefinition();
setFlag(EntityFlag.FACING_TARGET_TO_RANGE_ATTACK, this.hand.getDefinition() == bow || this.offhand.getDefinition() == bow);
setFlag(EntityFlag.FACING_TARGET_TO_RANGE_ATTACK, isHolding(Items.BOW));
} else {
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.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.item.component.DataComponentTypes;
import java.util.UUID;
@@ -74,14 +75,14 @@ public class PiglinEntity extends BasePiglinEntity {
ItemMapping crossbow = session.getItemMappings().getStoredItems().crossbow();
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.CHARGE_AMOUNT, (byte) 0);
setFlag(EntityFlag.CHARGED, false);
setFlag(EntityFlag.USING_ITEM, false);
updateBedrockMetadata();
if (this.hand.isValid()) {
if (!getMainHandItem().isEmpty()) {
MobEquipmentPacket mobEquipmentPacket = new MobEquipmentPacket();
mobEquipmentPacket.setRuntimeEntityId(geyserId);
mobEquipmentPacket.setContainerId(ContainerId.INVENTORY);
@@ -96,11 +97,11 @@ public class PiglinEntity extends BasePiglinEntity {
}
@Override
public void updateMainHand(GeyserSession session) {
super.updateMainHand(session);
public void updateMainHand() {
super.updateMainHand();
if (this.hand.getDefinition() == session.getItemMappings().getStoredItems().crossbow().getBedrockDefinition()) {
if (this.hand.getTag() != null && this.hand.getTag().containsKey("chargedItem")) {
if (getMainHandItem().is(Items.CROSSBOW)) {
if (getMainHandItem().getComponent(DataComponentTypes.CHARGED_PROJECTILES) != null) {
dirtyMetadata.put(EntityDataTypes.CHARGE_AMOUNT, Byte.MAX_VALUE);
setFlag(EntityFlag.CHARGING, false);
setFlag(EntityFlag.CHARGED, true);
@@ -116,12 +117,12 @@ public class PiglinEntity extends BasePiglinEntity {
}
@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
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.updateOffHand(session);
super.updateOffHand();
}
@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.protocol.bedrock.data.entity.EntityDataTypes;
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.registry.type.ItemMapping;
import org.geysermc.geyser.inventory.GeyserItemStack;
import org.geysermc.geyser.item.Items;
import org.geysermc.geyser.session.GeyserSession;
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;
@@ -49,33 +50,32 @@ public class PillagerEntity extends AbstractIllagerEntity {
}
@Override
public void updateMainHand(GeyserSession session) {
public void updateMainHand() {
updateCrossbow();
super.updateMainHand(session);
super.updateMainHand();
}
@Override
public void updateOffHand(GeyserSession session) {
public void updateOffHand() {
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
*/
protected void updateCrossbow() {
ItemMapping crossbow = session.getItemMappings().getStoredItems().crossbow();
ItemData activeCrossbow = null;
if (this.hand.getDefinition() == crossbow.getBedrockDefinition()) {
activeCrossbow = this.hand;
} else if (this.offhand.getDefinition() == crossbow.getBedrockDefinition()) {
activeCrossbow = this.offhand;
GeyserItemStack activeCrossbow = null;
if (getMainHandItem().is(Items.CROSSBOW)) {
activeCrossbow = getMainHandItem();
} else if (getOffHandItem().is(Items.CROSSBOW)) {
activeCrossbow = getOffHandItem();
}
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);
setFlag(EntityFlag.CHARGING, false);
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.EntityFlag;
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.MovePlayerPacket;
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.level.block.Blocks;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.translator.item.ItemTranslator;
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.Pose;
@@ -135,7 +135,7 @@ public class PlayerEntity extends LivingEntity implements GeyserPlayerEntity {
addPlayerPacket.setPosition(position.sub(0, definition.offset(), 0));
addPlayerPacket.setRotation(getBedrockRotation());
addPlayerPacket.setMotion(motion);
addPlayerPacket.setHand(hand);
addPlayerPacket.setHand(ItemTranslator.translateToBedrock(session, getMainHandItem()));
addPlayerPacket.getAdventureSettings().setCommandPermission(CommandPermission.ANY);
addPlayerPacket.getAdventureSettings().setPlayerPermission(PlayerPermission.MEMBER);
addPlayerPacket.setDeviceId("");
@@ -164,12 +164,6 @@ public class PlayerEntity extends LivingEntity implements GeyserPlayerEntity {
this.nametag = username;
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() {

View File

@@ -41,6 +41,7 @@ import org.geysermc.geyser.level.physics.Direction;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.session.cache.SkullCache;
import org.geysermc.geyser.skin.SkullSkinManager;
import org.geysermc.geyser.translator.item.ItemTranslator;
import java.util.Objects;
import java.util.UUID;
@@ -86,7 +87,7 @@ public class SkullPlayerEntity extends PlayerEntity {
addPlayerPacket.setPosition(position.sub(0, definition.offset(), 0));
addPlayerPacket.setRotation(getBedrockRotation());
addPlayerPacket.setMotion(motion);
addPlayerPacket.setHand(hand);
addPlayerPacket.setHand(ItemTranslator.translateToBedrock(session, getMainHandItem()));
addPlayerPacket.getAdventureSettings().setCommandPermission(CommandPermission.ANY);
addPlayerPacket.getAdventureSettings().setPlayerPermission(PlayerPermission.MEMBER);
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;
}
public boolean isDamaged() {
return isDamageable() && getDamage() > 0;
}
public Item asItem() {
if (isEmpty()) {
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.geysermc.geyser.GeyserImpl;
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.item.Items;
import org.geysermc.geyser.item.type.Item;
@@ -75,11 +76,21 @@ public class ItemMappings implements DefinitionRegistry<ItemDefinition> {
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}.
*
* @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
public ItemMapping getMapping(@NonNull ItemStack itemStack) {

View File

@@ -259,8 +259,8 @@ public class JavaEntityEventTranslator extends PacketTranslator<ClientboundEntit
if (entity instanceof LivingEntity livingEntity) {
livingEntity.switchHands();
livingEntity.updateMainHand(session);
livingEntity.updateOffHand(session);
livingEntity.updateMainHand();
livingEntity.updateOffHand();
} else {
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) {
livingEntity.updateArmor(session);
livingEntity.updateArmor();
}
if (mainHandUpdated) {
livingEntity.updateMainHand(session);
livingEntity.updateMainHand();
}
if (offHandUpdated) {
livingEntity.updateOffHand(session);
livingEntity.updateOffHand();
}
}
}