Skip to content

Commit

Permalink
implement curse of binding check for wolf armor removal
Browse files Browse the repository at this point in the history
  • Loading branch information
onebeastchris committed Apr 25, 2024
1 parent 16cb76f commit 8e3a3ea
Show file tree
Hide file tree
Showing 10 changed files with 81 additions and 39 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
import org.geysermc.geyser.item.Items;
import org.geysermc.geyser.registry.type.ItemMapping;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.translator.item.ItemTranslator;
import org.geysermc.geyser.util.AttributeUtils;
import org.geysermc.geyser.util.InteractionResult;
import org.geysermc.mcprotocollib.protocol.data.game.entity.attribute.Attribute;
Expand All @@ -57,6 +58,7 @@
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.type.FloatEntityMetadata;
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.item.ItemStack;

import java.util.*;

Expand All @@ -69,7 +71,7 @@ public class LivingEntity extends Entity {
protected ItemData leggings = ItemData.AIR;
protected ItemData boots = ItemData.AIR;
protected ItemData hand = ItemData.AIR;
protected ItemData offHand = 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
Expand All @@ -85,6 +87,36 @@ public LivingEntity(GeyserSession session, int entityId, long geyserId, UUID uui
super(session, entityId, geyserId, uuid, definition, position, motion, yaw, pitch, headYaw);
}

public void setHelmet(ItemStack stack) {
this.helmet = ItemTranslator.translateToBedrock(session, stack);
}

public void setChestplate(ItemStack stack) {
this.chestplate = ItemTranslator.translateToBedrock(session, stack);
}

public void setLeggings(ItemStack stack) {
this.leggings = ItemTranslator.translateToBedrock(session, stack);
}

public void setBoots(ItemStack stack) {
this.boots = ItemTranslator.translateToBedrock(session, stack);
}

public void setHand(ItemStack stack) {
this.hand = ItemTranslator.translateToBedrock(session, stack);
}

public void setOffhand(ItemStack stack) {
this.offhand = ItemTranslator.translateToBedrock(session, stack);
}

public void switchHands() {
ItemData offhand = this.offhand;
this.offhand = this.hand;
this.hand = offhand;
}

@Override
protected void initializeMetadata() {
super.initializeMetadata();
Expand Down Expand Up @@ -135,7 +167,7 @@ public void setHealth(FloatEntityMetadata entityMetadata) {
protected boolean hasShield(boolean offhand) {
ItemMapping shieldMapping = session.getItemMappings().getStoredItems().shield();
if (offhand) {
return offHand.getDefinition().equals(shieldMapping.getBedrockDefinition());
return this.offhand.getDefinition().equals(shieldMapping.getBedrockDefinition());
} else {
return hand.getDefinition().equals(shieldMapping.getBedrockDefinition());
}
Expand Down Expand Up @@ -247,7 +279,7 @@ public void updateOffHand(GeyserSession session) {

MobEquipmentPacket offHandPacket = new MobEquipmentPacket();
offHandPacket.setRuntimeEntityId(geyserId);
offHandPacket.setItem(offHand);
offHandPacket.setItem(offhand);
offHandPacket.setHotbarSlot(-1);
offHandPacket.setInventorySlot(0);
offHandPacket.setContainerId(ContainerId.OFFHAND);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
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.player.Hand;
import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack;

import java.util.Optional;
import java.util.UUID;
Expand Down Expand Up @@ -257,38 +258,38 @@ public InteractionResult interactAt(Hand hand) {
}

@Override
public void setHelmet(ItemData helmet) {
public void setHelmet(ItemStack helmet) {
super.setHelmet(helmet);
updateSecondEntityStatus(true);
}

@Override
public void setChestplate(ItemData chestplate) {
public void setChestplate(ItemStack chestplate) {
super.setChestplate(chestplate);
updateSecondEntityStatus(true);
}

@Override
public void setLeggings(ItemData leggings) {
public void setLeggings(ItemStack leggings) {
super.setLeggings(leggings);
updateSecondEntityStatus(true);
}

@Override
public void setBoots(ItemData boots) {
public void setBoots(ItemStack boots) {
super.setBoots(boots);
updateSecondEntityStatus(true);
}

@Override
public void setHand(ItemData hand) {
public void setHand(ItemStack hand) {
super.setHand(hand);
updateSecondEntityStatus(true);
}

@Override
public void setOffHand(ItemData offHand) {
super.setOffHand(offHand);
public void setOffhand(ItemStack offHand) {
super.setOffhand(offHand);
updateSecondEntityStatus(true);
}

Expand Down Expand Up @@ -324,7 +325,7 @@ private void updateSecondEntityStatus(boolean sendMetadata) {
}
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))) {
|| !boots.equals(ItemData.AIR) || !hand.equals(ItemData.AIR) || !offhand.equals(ItemData.AIR))) {
// Reset scale of the proper armor stand
this.dirtyMetadata.put(EntityDataTypes.SCALE, getScale());
// Set the proper armor stand to invisible to show armor
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,15 +33,19 @@
import org.cloudburstmc.protocol.bedrock.packet.UpdateAttributesPacket;
import org.geysermc.geyser.entity.EntityDefinition;
import org.geysermc.geyser.inventory.GeyserItemStack;
import org.geysermc.geyser.inventory.item.Enchantment;
import org.geysermc.geyser.item.Items;
import org.geysermc.geyser.item.type.DyeItem;
import org.geysermc.geyser.item.type.Item;
import org.geysermc.geyser.session.GeyserSession;
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.metadata.type.ByteEntityMetadata;
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.Hand;
import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack;

import java.util.Collections;
import java.util.Locale;
Expand All @@ -60,6 +64,8 @@ public class WolfEntity extends TameableEntity {

private byte collarColor = 14; // Red - default

private boolean isCurseOfBinding = false;

public WolfEntity(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);
}
Expand Down Expand Up @@ -119,6 +125,12 @@ public boolean canEat(Item item) {
return WOLF_FOODS.contains(item) && !isBaby();
}

@Override
public void setChestplate(ItemStack stack) {
super.setChestplate(stack);
isCurseOfBinding = ItemUtils.getEnchantmentLevel(stack.getDataComponents(), Enchantment.JavaEnchantment.BINDING_CURSE) > 0;
}

@Override
protected boolean canBeLeashed() {
return !getFlag(EntityFlag.ANGRY) && super.canBeLeashed();
Expand Down Expand Up @@ -146,7 +158,8 @@ protected InteractiveTag testMobInteraction(@NonNull Hand hand, @NonNull GeyserI
if (itemInHand.asItem() == Items.WOLF_ARMOR && !this.chestplate.isValid() && !getFlag(EntityFlag.BABY)) {
return InteractiveTag.EQUIP_WOLF_ARMOR;
}
if (itemInHand.asItem() == Items.SHEARS && this.chestplate.isValid()) { // TODO: check curse of binding
if (itemInHand.asItem() == Items.SHEARS && this.chestplate.isValid()
&& (!isCurseOfBinding || session.getGameMode().equals(GameMode.CREATIVE))) {
return InteractiveTag.REMOVE_WOLF_ARMOR;
}
if (Items.WOLF_ARMOR.isValidRepairItem(itemInHand.asItem()) && getFlag(EntityFlag.SITTING) &&
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ public void setDancing(BooleanEntityMetadata entityMetadata) {
@Override
public void updateOffHand(GeyserSession session) {
// 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, session.getTagCache().is(ItemTag.PIGLIN_LOVED, session.getItemMappings().getMapping(this.offhand).getJavaItem()));
super.updateBedrockMetadata();

super.updateOffHand(session);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ public void updateOffHand(GeyserSession session) {
protected void checkForCrossbow() {
ItemMapping crossbow = session.getItemMappings().getStoredItems().crossbow();
boolean hasCrossbow = this.hand.getDefinition() == crossbow.getBedrockDefinition()
|| this.offHand.getDefinition() == crossbow.getBedrockDefinition();
|| this.offhand.getDefinition() == crossbow.getBedrockDefinition();
setFlag(EntityFlag.USING_ITEM, hasCrossbow);
setFlag(EntityFlag.CHARGED, hasCrossbow);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -360,7 +360,7 @@ public static ItemDefinition getBedrockItemDefinition(GeyserSession session, @No
}

if (mapping.getJavaItem().equals(Items.PLAYER_HEAD)) {
CustomSkull customSkull = getCustomSkull(session, itemStack.getComponents());
CustomSkull customSkull = getCustomSkull(itemStack.getComponents());
if (customSkull != null) {
itemDefinition = session.getItemMappings().getCustomBlockItemDefinitions().get(customSkull.getCustomBlockData());
}
Expand Down Expand Up @@ -552,7 +552,7 @@ private static void translateCustomBlock(CustomBlockData customBlockData, Geyser
builder.blockDefinition(blockDefinition);
}

private static @Nullable CustomSkull getCustomSkull(GeyserSession session, DataComponents components) {
private static @Nullable CustomSkull getCustomSkull(DataComponents components) {
if (components == null) {
return null;
}
Expand All @@ -563,7 +563,7 @@ private static void translateCustomBlock(CustomBlockData customBlockData, Geyser
try {
textures = profile.getTextures(false);
} catch (PropertyException e) {
session.getGeyser().getLogger().debug("Failed to get textures from GameProfile: " + e);
GeyserImpl.getInstance().getLogger().debug("Failed to get textures from GameProfile: " + e);
}

if (textures == null || textures.isEmpty()) {
Expand All @@ -583,7 +583,7 @@ private static void translateCustomBlock(CustomBlockData customBlockData, Geyser
}

private static void translatePlayerHead(GeyserSession session, DataComponents components, ItemData.Builder builder) {
CustomSkull customSkull = getCustomSkull(session, components);
CustomSkull customSkull = getCustomSkull(components);
if (customSkull != null) {
CustomBlockData customBlockData = customSkull.getCustomBlockData();
ItemDefinition itemDefinition = session.getItemMappings().getCustomBlockItemDefinitions().get(customBlockData);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,10 @@

package org.geysermc.geyser.translator.protocol.java.entity;

import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.entity.ClientboundEntityEventPacket;
import org.cloudburstmc.protocol.bedrock.data.ParticleType;
import org.cloudburstmc.protocol.bedrock.data.SoundEvent;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityDataTypes;
import org.cloudburstmc.protocol.bedrock.data.entity.EntityEventType;
import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData;
import org.cloudburstmc.protocol.bedrock.packet.EntityEventPacket;
import org.cloudburstmc.protocol.bedrock.packet.LevelEventPacket;
import org.cloudburstmc.protocol.bedrock.packet.LevelSoundEvent2Packet;
Expand All @@ -46,6 +44,7 @@
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.translator.protocol.PacketTranslator;
import org.geysermc.geyser.translator.protocol.Translator;
import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.entity.ClientboundEntityEventPacket;

import java.util.concurrent.ThreadLocalRandom;

Expand Down Expand Up @@ -223,9 +222,7 @@ public void translate(GeyserSession session, ClientboundEntityEventPacket packet
return;
case PLAYER_SWAP_SAME_ITEM: // Not just used for players
if (entity instanceof LivingEntity livingEntity) {
ItemData newMainHand = livingEntity.getOffHand();
livingEntity.setOffHand(livingEntity.getHand());
livingEntity.setHand(newMainHand);
livingEntity.switchHands();

livingEntity.updateMainHand(session);
livingEntity.updateOffHand(session);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,19 +25,17 @@

package org.geysermc.geyser.translator.protocol.java.entity;

import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.Equipment;
import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack;
import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.entity.ClientboundSetEquipmentPacket;
import org.cloudburstmc.protocol.bedrock.data.inventory.ItemData;
import org.geysermc.geyser.entity.type.Entity;
import org.geysermc.geyser.entity.type.LivingEntity;
import org.geysermc.geyser.entity.type.player.PlayerEntity;
import org.geysermc.geyser.item.Items;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.skin.FakeHeadProvider;
import org.geysermc.geyser.translator.item.ItemTranslator;
import org.geysermc.geyser.translator.protocol.PacketTranslator;
import org.geysermc.geyser.translator.protocol.Translator;
import org.geysermc.mcprotocollib.protocol.data.game.entity.metadata.Equipment;
import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack;
import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.entity.ClientboundSetEquipmentPacket;

@Translator(packet = ClientboundSetEquipmentPacket.class)
public class JavaSetEquipmentTranslator extends PacketTranslator<ClientboundSetEquipmentPacket> {
Expand All @@ -58,7 +56,7 @@ public void translate(GeyserSession session, ClientboundSetEquipmentPacket packe
boolean mainHandUpdated = false;
boolean offHandUpdated = false;
for (Equipment equipment : packet.getEquipment()) {
ItemData item = ItemTranslator.translateToBedrock(session, equipment.getItem());
ItemStack stack = equipment.getItem();
switch (equipment.getSlot()) {
case HELMET -> {
ItemStack javaItem = equipment.getItem();
Expand All @@ -71,28 +69,28 @@ public void translate(GeyserSession session, ClientboundSetEquipmentPacket packe
FakeHeadProvider.restoreOriginalSkin(session, livingEntity);
}

livingEntity.setHelmet(item);
livingEntity.setHelmet(stack);
armorUpdated = true;
}
case CHESTPLATE, BODY -> {
// BODY is sent for llamas with a carpet equipped, as of 1.20.5
livingEntity.setChestplate(item);
livingEntity.setChestplate(stack);
armorUpdated = true;
}
case LEGGINGS -> {
livingEntity.setLeggings(item);
livingEntity.setLeggings(stack);
armorUpdated = true;
}
case BOOTS -> {
livingEntity.setBoots(item);
livingEntity.setBoots(stack);
armorUpdated = true;
}
case MAIN_HAND -> {
livingEntity.setHand(item);
livingEntity.setHand(stack);
mainHandUpdated = true;
}
case OFF_HAND -> {
livingEntity.setOffHand(item);
livingEntity.setOffhand(stack);
offHandUpdated = true;
}
}
Expand Down
4 changes: 2 additions & 2 deletions core/src/main/java/org/geysermc/geyser/util/BlockUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ public static double getBreakTime(GeyserSession session, BlockMapping blockMappi
toolCanBreak = canToolTierBreakBlock(session, blockMapping, toolTier);
}

int toolEfficiencyLevel = ItemUtils.getEnchantmentLevel(components, Enchantment.JavaEnchantment.EFFICIENCY.ordinal());
int toolEfficiencyLevel = ItemUtils.getEnchantmentLevel(components, Enchantment.JavaEnchantment.EFFICIENCY);
int hasteLevel = 0;
int miningFatigueLevel = 0;

Expand All @@ -160,7 +160,7 @@ public static double getBreakTime(GeyserSession session, BlockMapping blockMappi

boolean waterInEyes = session.getCollisionManager().isWaterInEyes();
boolean insideOfWaterWithoutAquaAffinity = waterInEyes &&
ItemUtils.getEnchantmentLevel(session.getPlayerInventory().getItem(5).getComponents(), Enchantment.JavaEnchantment.AQUA_AFFINITY.ordinal()) < 1;
ItemUtils.getEnchantmentLevel(session.getPlayerInventory().getItem(5).getComponents(), Enchantment.JavaEnchantment.AQUA_AFFINITY) < 1;

return calculateBreakTime(blockMapping.getHardness(), toolTier, canHarvestWithHand, correctTool, toolCanBreak, toolType, isShearsEffective,
toolEfficiencyLevel, hasteLevel, miningFatigueLevel, insideOfWaterWithoutAquaAffinity, session.getPlayerEntity().isOnGround());
Expand Down
5 changes: 3 additions & 2 deletions core/src/main/java/org/geysermc/geyser/util/ItemUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@

import net.kyori.adventure.text.Component;
import org.checkerframework.checker.nullness.qual.Nullable;
import org.geysermc.geyser.inventory.item.Enchantment;
import org.geysermc.geyser.item.Items;
import org.geysermc.geyser.item.type.FishingRodItem;
import org.geysermc.geyser.item.type.Item;
Expand All @@ -36,7 +37,7 @@

public class ItemUtils {

public static int getEnchantmentLevel(@Nullable DataComponents components, int enchantmentId) {
public static int getEnchantmentLevel(@Nullable DataComponents components, Enchantment.JavaEnchantment enchantment) {
if (components == null) {
return 0;
}
Expand All @@ -46,7 +47,7 @@ public static int getEnchantmentLevel(@Nullable DataComponents components, int e
return 0;
}

return enchantmentData.getEnchantments().getOrDefault(enchantmentId, 0);
return enchantmentData.getEnchantments().getOrDefault(enchantment.ordinal(), 0);
}

/**
Expand Down

0 comments on commit 8e3a3ea

Please sign in to comment.