Skip to content

Commit

Permalink
Fix: Totem animation when playing totem effects manually (GeyserMC#4860)
Browse files Browse the repository at this point in the history
* Fix: Totem animation for manually played totem effects

* Ensure we always reset the offhand correctly
  • Loading branch information
onebeastchris authored Jul 14, 2024
1 parent 9cdda70 commit 0689050
Show file tree
Hide file tree
Showing 4 changed files with 39 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import lombok.Setter;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.geysermc.geyser.GeyserImpl;
import org.geysermc.geyser.item.type.Item;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand;
import org.jetbrains.annotations.Range;
Expand Down Expand Up @@ -73,6 +74,10 @@ public GeyserItemStack getItemInHand() {
return items[36 + heldItemSlot];
}

public boolean eitherHandMatchesItem(@NonNull Item item) {
return getItemInHand().asItem() == item || getItemInHand(Hand.OFF_HAND).asItem() == item;
}

public void setItemInHand(@NonNull GeyserItemStack item) {
if (36 + heldItemSlot > this.size) {
GeyserImpl.getInstance().getLogger().debug("Held item slot was larger than expected!");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ public class StoredItemMappings {
private final ItemMapping milkBucket;
private final ItemMapping powderSnowBucket;
private final ItemMapping shield;
private final ItemMapping totem;
private final ItemMapping upgradeTemplate;
private final ItemMapping wheat;
private final ItemMapping writableBook;
Expand All @@ -66,6 +67,7 @@ public StoredItemMappings(Map<Item, ItemMapping> itemMappings) {
this.milkBucket = load(itemMappings, Items.MILK_BUCKET);
this.powderSnowBucket = load(itemMappings, Items.POWDER_SNOW_BUCKET);
this.shield = load(itemMappings, Items.SHIELD);
this.totem = load(itemMappings, Items.TOTEM_OF_UNDYING);
this.upgradeTemplate = load(itemMappings, Items.NETHERITE_UPGRADE_SMITHING_TEMPLATE);
this.wheat = load(itemMappings, Items.WHEAT);
this.writableBook = load(itemMappings, Items.WRITABLE_BOOK);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,9 @@
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.ContainerId;
import org.cloudburstmc.protocol.bedrock.packet.EntityEventPacket;
import org.cloudburstmc.protocol.bedrock.packet.InventoryContentPacket;
import org.cloudburstmc.protocol.bedrock.packet.LevelEventPacket;
import org.cloudburstmc.protocol.bedrock.packet.LevelSoundEvent2Packet;
import org.cloudburstmc.protocol.bedrock.packet.PlaySoundPacket;
Expand All @@ -42,11 +44,15 @@
import org.geysermc.geyser.entity.type.LivingEntity;
import org.geysermc.geyser.entity.type.living.animal.ArmadilloEntity;
import org.geysermc.geyser.entity.type.living.monster.WardenEntity;
import org.geysermc.geyser.item.Items;
import org.geysermc.geyser.session.GeyserSession;
import org.geysermc.geyser.translator.inventory.InventoryTranslator;
import org.geysermc.geyser.translator.protocol.PacketTranslator;
import org.geysermc.geyser.translator.protocol.Translator;
import org.geysermc.geyser.util.InventoryUtils;
import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.entity.ClientboundEntityEventPacket;

import java.util.Collections;
import java.util.concurrent.ThreadLocalRandom;

@Translator(packet = ClientboundEntityEventPacket.class)
Expand Down Expand Up @@ -154,6 +160,16 @@ public void translate(GeyserSession session, ClientboundEntityEventPacket packet
entityEventPacket.setType(EntityEventType.WITCH_HAT_MAGIC); //TODO: CHECK
break;
case TOTEM_OF_UNDYING_MAKE_SOUND:
// Bedrock will not play the spinning animation without the item in the hand o.o
// Fixes https://github.com/GeyserMC/Geyser/issues/2446
boolean totemItemWorkaround = !session.getPlayerInventory().eitherHandMatchesItem(Items.TOTEM_OF_UNDYING);
if (totemItemWorkaround) {
InventoryContentPacket offhandPacket = new InventoryContentPacket();
offhandPacket.setContainerId(ContainerId.OFFHAND);
offhandPacket.setContents(Collections.singletonList(InventoryUtils.getTotemOfUndying().apply(session.getUpstream().getProtocolVersion())));
session.sendUpstreamPacket(offhandPacket);
}

entityEventPacket.setType(EntityEventType.CONSUME_TOTEM);

PlaySoundPacket playSoundPacket = new PlaySoundPacket();
Expand All @@ -162,7 +178,16 @@ public void translate(GeyserSession session, ClientboundEntityEventPacket packet
playSoundPacket.setVolume(1.0F);
playSoundPacket.setPitch(1.0F + (ThreadLocalRandom.current().nextFloat() * 0.1F) - 0.05F);
session.sendUpstreamPacket(playSoundPacket);
break;

// Sent here early to ensure we have the totem in our hand
session.sendUpstreamPacket(entityEventPacket);

if (totemItemWorkaround) {
// Reset the item again
InventoryTranslator.PLAYER_INVENTORY_TRANSLATOR.updateSlot(session, session.getPlayerInventory(), 45);
}

return;
case SHEEP_GRAZE_OR_TNT_CART_EXPLODE:
if (entity.getDefinition() == EntityDefinitions.SHEEP) {
entityEventPacket.setType(EntityEventType.EAT_GRASS);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,12 @@ public static IntFunction<ItemData> getUpgradeTemplate() {
.count(1).build();
}

public static IntFunction<ItemData> getTotemOfUndying() {
return protocolVersion -> ItemData.builder()
.definition(Registries.ITEMS.forVersion(protocolVersion).getStoredItems().totem().getBedrockDefinition())
.count(1).build();
}

/**
* See {@link #findOrCreateItem(GeyserSession, String)}. This is for finding a specified {@link ItemStack}.
*
Expand Down

0 comments on commit 0689050

Please sign in to comment.