Skip to content

Commit a5e45ad

Browse files
committed
Workaround for goat horns on the client side
1 parent 34fda8a commit a5e45ad

File tree

3 files changed

+54
-0
lines changed

3 files changed

+54
-0
lines changed

core/src/main/java/org/geysermc/geyser/session/cache/WorldCache.java

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
import org.checkerframework.checker.nullness.qual.Nullable;
3535
import org.cloudburstmc.math.vector.Vector3i;
3636
import org.cloudburstmc.protocol.bedrock.packet.SetTitlePacket;
37+
import org.geysermc.geyser.item.type.Item;
3738
import org.geysermc.geyser.scoreboard.Scoreboard;
3839
import org.geysermc.geyser.scoreboard.ScoreboardUpdater.ScoreboardSession;
3940
import org.geysermc.geyser.session.GeyserSession;
@@ -70,6 +71,8 @@ public final class WorldCache {
7071
@Setter
7172
private boolean editingSignOnFront;
7273

74+
private final Object2IntMap<Item> activeCooldowns = new Object2IntOpenHashMap<>(2);
75+
7376
public WorldCache(GeyserSession session) {
7477
this.session = session;
7578
this.scoreboard = new Scoreboard(session);
@@ -201,4 +204,32 @@ public void addActiveRecord(Vector3i pos, String bedrockPlaySound) {
201204
public String removeActiveRecord(Vector3i pos) {
202205
return this.activeRecords.remove(pos);
203206
}
207+
208+
public void setCooldown(Item item, int ticks) {
209+
if (ticks == 0) {
210+
// As of Java 1.21
211+
this.activeCooldowns.removeInt(item);
212+
return;
213+
}
214+
this.activeCooldowns.put(item, session.getTicks() + ticks);
215+
}
216+
217+
public boolean hasCooldown(Item item) {
218+
return this.activeCooldowns.containsKey(item);
219+
}
220+
221+
public void tick() {
222+
// Implementation note: technically we could empty the field during hasCooldown checks,
223+
// but we don't want the cooldown field to balloon in size from overuse.
224+
if (!this.activeCooldowns.isEmpty()) {
225+
int ticks = session.getTicks();
226+
Iterator<Object2IntMap.Entry<Item>> it = Object2IntMaps.fastIterator(this.activeCooldowns);
227+
while (it.hasNext()) {
228+
Object2IntMap.Entry<Item> entry = it.next();
229+
if (entry.getIntValue() <= ticks) {
230+
it.remove();
231+
}
232+
}
233+
}
234+
}
204235
}

core/src/main/java/org/geysermc/geyser/translator/protocol/bedrock/BedrockInventoryTransactionTranslator.java

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
import org.cloudburstmc.math.vector.Vector3f;
3232
import org.cloudburstmc.math.vector.Vector3i;
3333
import org.cloudburstmc.protocol.bedrock.data.LevelEvent;
34+
import org.cloudburstmc.protocol.bedrock.data.SoundEvent;
3435
import org.cloudburstmc.protocol.bedrock.data.definitions.BlockDefinition;
3536
import org.cloudburstmc.protocol.bedrock.data.definitions.ItemDefinition;
3637
import org.cloudburstmc.protocol.bedrock.data.inventory.ContainerType;
@@ -42,6 +43,7 @@
4243
import org.cloudburstmc.protocol.bedrock.packet.ContainerOpenPacket;
4344
import org.cloudburstmc.protocol.bedrock.packet.InventoryTransactionPacket;
4445
import org.cloudburstmc.protocol.bedrock.packet.LevelEventPacket;
46+
import org.cloudburstmc.protocol.bedrock.packet.LevelSoundEventPacket;
4547
import org.cloudburstmc.protocol.bedrock.packet.UpdateBlockPacket;
4648
import org.geysermc.geyser.entity.EntityDefinitions;
4749
import org.geysermc.geyser.entity.type.Entity;
@@ -75,12 +77,15 @@
7577
import org.geysermc.geyser.util.EntityUtils;
7678
import org.geysermc.geyser.util.InteractionResult;
7779
import org.geysermc.geyser.util.InventoryUtils;
80+
import org.geysermc.mcprotocollib.protocol.data.game.Holder;
7881
import org.geysermc.mcprotocollib.protocol.data.game.entity.object.Direction;
7982
import org.geysermc.mcprotocollib.protocol.data.game.entity.player.GameMode;
8083
import org.geysermc.mcprotocollib.protocol.data.game.entity.player.Hand;
8184
import org.geysermc.mcprotocollib.protocol.data.game.entity.player.InteractAction;
8285
import org.geysermc.mcprotocollib.protocol.data.game.entity.player.PlayerAction;
8386
import org.geysermc.mcprotocollib.protocol.data.game.item.ItemStack;
87+
import org.geysermc.mcprotocollib.protocol.data.game.item.component.DataComponentType;
88+
import org.geysermc.mcprotocollib.protocol.data.game.item.component.Instrument;
8489
import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.inventory.ServerboundContainerClickPacket;
8590
import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundInteractPacket;
8691
import org.geysermc.mcprotocollib.protocol.packet.ingame.serverbound.player.ServerboundMovePlayerPosRotPacket;
@@ -373,6 +378,22 @@ public void translate(GeyserSession session, InventoryTransactionPacket packet)
373378
break;
374379
} else if (packet.getItemInHand().getDefinition() == session.getItemMappings().getStoredItems().writtenBook().getBedrockDefinition()) {
375380
session.setCurrentBook(packet.getItemInHand());
381+
} else if (session.getPlayerInventory().getItemInHand().asItem() == Items.GOAT_HORN) {
382+
// Temporary workaround while we don't have full item/block use tracking.
383+
if (!session.getWorldCache().hasCooldown(Items.GOAT_HORN)) {
384+
Holder<Instrument> instrument = session.getPlayerInventory()
385+
.getItemInHand()
386+
.getComponent(DataComponentType.INSTRUMENT);
387+
if (instrument != null && instrument.isId()) {
388+
// BDS uses a LevelSoundEvent2Packet, but that doesn't work here... (as of 1.21.20)
389+
LevelSoundEventPacket soundPacket = new LevelSoundEventPacket();
390+
soundPacket.setSound(SoundEvent.valueOf("GOAT_CALL_" + instrument.id()));
391+
soundPacket.setPosition(session.getPlayerEntity().getPosition());
392+
soundPacket.setIdentifier("minecraft:player");
393+
soundPacket.setExtraData(-1);
394+
session.sendUpstreamPacket(soundPacket);
395+
}
396+
}
376397
}
377398
}
378399

core/src/main/java/org/geysermc/geyser/translator/protocol/java/level/JavaCooldownTranslator.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,5 +57,7 @@ public void translate(GeyserSession session, ClientboundCooldownPacket packet) {
5757
bedrockPacket.setCooldownDuration(packet.getCooldownTicks());
5858
session.sendUpstreamPacket(bedrockPacket);
5959
}
60+
61+
session.getWorldCache().setCooldown(item, packet.getCooldownTicks());
6062
}
6163
}

0 commit comments

Comments
 (0)