From 3f60ffd1efc74553c2f17cca511574b7a5f27809 Mon Sep 17 00:00:00 2001 From: James Puleo Date: Mon, 22 Feb 2021 01:29:46 -0500 Subject: [PATCH] Track the players selected slot index with PacketPlayInHeldItemChange, and allow changing of a players selected slot with PacketPlayOutHeldItemChange. Also introduces an event that can be used to change or cancel a player's selected slot change. I tried to follow the style and mannerisms of existing code, but what's up with the Unsafe class? The class is okay, but why are the methods named as such? Having all the methods named 'a' will be sure to cause conflict once two methods take the same parameters. --- .../Events/PlayerSelectedSlotChangeEvent.java | 32 +++++++++++++++++++ .../java/com/loohp/limbo/Player/Player.java | 20 +++++++++++- .../java/com/loohp/limbo/Player/Unsafe.java | 7 +++- .../loohp/limbo/Server/ClientConnection.java | 16 ++++++++++ .../Packets/PacketPlayInHeldItemChange.java | 21 ++++++++++++ .../Packets/PacketPlayOutHeldItemChange.java | 29 +++++++++++++++++ src/main/java/com/loohp/limbo/Unsafe.java | 9 ++++-- src/main/resources/mapping.json | 6 ++-- 8 files changed, 134 insertions(+), 6 deletions(-) create mode 100644 src/main/java/com/loohp/limbo/Events/PlayerSelectedSlotChangeEvent.java create mode 100644 src/main/java/com/loohp/limbo/Server/Packets/PacketPlayInHeldItemChange.java create mode 100644 src/main/java/com/loohp/limbo/Server/Packets/PacketPlayOutHeldItemChange.java diff --git a/src/main/java/com/loohp/limbo/Events/PlayerSelectedSlotChangeEvent.java b/src/main/java/com/loohp/limbo/Events/PlayerSelectedSlotChangeEvent.java new file mode 100644 index 0000000..a1003cf --- /dev/null +++ b/src/main/java/com/loohp/limbo/Events/PlayerSelectedSlotChangeEvent.java @@ -0,0 +1,32 @@ +package com.loohp.limbo.Events; + +import com.loohp.limbo.Player.Player; + +public class PlayerSelectedSlotChangeEvent extends PlayerEvent implements Cancellable { + + private boolean cancel = false; + private byte slot; + + public PlayerSelectedSlotChangeEvent(Player player, byte slot) { + super(player); + this.slot = slot; + } + + @Override + public void setCancelled(boolean cancelled) { + this.cancel = cancelled; + } + + @Override + public boolean isCancelled() { + return cancel; + } + + public byte getSlot() { + return slot; + } + + public void setSlot(byte slot) { + this.slot = slot; + } +} diff --git a/src/main/java/com/loohp/limbo/Player/Player.java b/src/main/java/com/loohp/limbo/Player/Player.java index 2fd109e..cd832ea 100644 --- a/src/main/java/com/loohp/limbo/Player/Player.java +++ b/src/main/java/com/loohp/limbo/Player/Player.java @@ -18,6 +18,7 @@ import com.loohp.limbo.Server.Packets.PacketPlayOutChat; import com.loohp.limbo.Server.Packets.PacketPlayOutGameState; import com.loohp.limbo.Server.Packets.PacketPlayOutPositionAndLook; import com.loohp.limbo.Server.Packets.PacketPlayOutRespawn; +import com.loohp.limbo.Server.Packets.PacketPlayOutHeldItemChange; import com.loohp.limbo.Utils.GameMode; import net.md_5.bungee.api.chat.BaseComponent; @@ -32,6 +33,7 @@ public class Player extends LivingEntity implements CommandSender { protected final String username; protected GameMode gamemode; protected DataWatcher watcher; + protected byte selectedSlot; @WatchableField(MetadataIndex = 14, WatchableObjectType = WatchableObjectType.FLOAT) protected float additionalHearts = 0.0F; @@ -56,7 +58,23 @@ public class Player extends LivingEntity implements CommandSender { this.watcher = new DataWatcher(this); this.watcher.update(); } - + + public byte getSelectedSlot() { + return selectedSlot; + } + + public void setSelectedSlot(byte slot) { + if(slot == selectedSlot) + return; + try { + PacketPlayOutHeldItemChange state = new PacketPlayOutHeldItemChange(slot); + clientConnection.sendPacket(state); + } catch (IOException e) { + e.printStackTrace(); + } + this.selectedSlot = slot; + } + public GameMode getGamemode() { return gamemode; } diff --git a/src/main/java/com/loohp/limbo/Player/Unsafe.java b/src/main/java/com/loohp/limbo/Player/Unsafe.java index b6864eb..f51f7c7 100644 --- a/src/main/java/com/loohp/limbo/Player/Unsafe.java +++ b/src/main/java/com/loohp/limbo/Player/Unsafe.java @@ -22,5 +22,10 @@ public class Unsafe { public void a(Player a, Location b) { a.setLocation(b); } - + + @Deprecated + public void a(Player a, byte b) { + a.selectedSlot = b; + } + } diff --git a/src/main/java/com/loohp/limbo/Server/ClientConnection.java b/src/main/java/com/loohp/limbo/Server/ClientConnection.java index 5a57259..89e8690 100644 --- a/src/main/java/com/loohp/limbo/Server/ClientConnection.java +++ b/src/main/java/com/loohp/limbo/Server/ClientConnection.java @@ -23,6 +23,7 @@ import com.loohp.limbo.Events.PlayerLoginEvent; import com.loohp.limbo.Events.PlayerMoveEvent; import com.loohp.limbo.Events.PlayerQuitEvent; import com.loohp.limbo.Events.StatusPingEvent; +import com.loohp.limbo.Events.PlayerSelectedSlotChangeEvent; import com.loohp.limbo.File.ServerProperties; import com.loohp.limbo.Location.Location; import com.loohp.limbo.Player.Player; @@ -58,6 +59,8 @@ import com.loohp.limbo.Server.Packets.PacketStatusInPing; import com.loohp.limbo.Server.Packets.PacketStatusInRequest; import com.loohp.limbo.Server.Packets.PacketStatusOutPong; import com.loohp.limbo.Server.Packets.PacketStatusOutResponse; +import com.loohp.limbo.Server.Packets.PacketPlayInHeldItemChange; +import com.loohp.limbo.Server.Packets.PacketPlayOutHeldItemChange; import com.loohp.limbo.Utils.CustomStringUtils; import com.loohp.limbo.Utils.DataTypeIO; import com.loohp.limbo.Utils.GameMode; @@ -427,6 +430,19 @@ public class ClientConnection extends Thread { } else { player.chat(chat.getMessage()); } + } else if(packetType.equals(PacketPlayInHeldItemChange.class)) { + PacketPlayInHeldItemChange change = new PacketPlayInHeldItemChange(input); + PlayerSelectedSlotChangeEvent event = Limbo.getInstance().getEventsManager().callEvent(new PlayerSelectedSlotChangeEvent(player, (byte)change.getSlot())); + if(event.isCancelled()) { + PacketPlayOutHeldItemChange cancelPacket = new PacketPlayOutHeldItemChange(player.getSelectedSlot()); + sendPacket(cancelPacket); + } else if(change.getSlot() != event.getSlot()) { + PacketPlayOutHeldItemChange changePacket = new PacketPlayOutHeldItemChange(event.getSlot()); + sendPacket(changePacket); + Limbo.getInstance().getUnsafe().setSelectedSlotSilently(player, event.getSlot()); + } else { + Limbo.getInstance().getUnsafe().setSelectedSlotSilently(player, event.getSlot()); + } } else { input.skipBytes(size - DataTypeIO.getVarIntLength(packetId)); } diff --git a/src/main/java/com/loohp/limbo/Server/Packets/PacketPlayInHeldItemChange.java b/src/main/java/com/loohp/limbo/Server/Packets/PacketPlayInHeldItemChange.java new file mode 100644 index 0000000..dc414c9 --- /dev/null +++ b/src/main/java/com/loohp/limbo/Server/Packets/PacketPlayInHeldItemChange.java @@ -0,0 +1,21 @@ +package com.loohp.limbo.Server.Packets; + +import java.io.DataInputStream; +import java.io.IOException; + +public class PacketPlayInHeldItemChange extends PacketIn { + + private final short slot; + + public PacketPlayInHeldItemChange(short slot) { + this.slot = slot; + } + + public PacketPlayInHeldItemChange(DataInputStream in) throws IOException { + this(in.readShort()); + } + + public short getSlot() { + return slot; + } +} diff --git a/src/main/java/com/loohp/limbo/Server/Packets/PacketPlayOutHeldItemChange.java b/src/main/java/com/loohp/limbo/Server/Packets/PacketPlayOutHeldItemChange.java new file mode 100644 index 0000000..337ae43 --- /dev/null +++ b/src/main/java/com/loohp/limbo/Server/Packets/PacketPlayOutHeldItemChange.java @@ -0,0 +1,29 @@ +package com.loohp.limbo.Server.Packets; + +import java.io.ByteArrayOutputStream; +import java.io.DataOutputStream; +import java.io.IOException; + +public class PacketPlayOutHeldItemChange extends PacketOut { + + private final byte slot; + + public PacketPlayOutHeldItemChange(byte slot) { + this.slot = slot; + } + + public byte getSlot() { + return slot; + } + + @Override + public byte[] serializePacket() throws IOException { + ByteArrayOutputStream buffer = new ByteArrayOutputStream(); + + DataOutputStream output = new DataOutputStream(buffer); + output.writeByte(Packet.getPlayOut().get(getClass())); + output.writeByte(slot); + + return buffer.toByteArray(); + } +} diff --git a/src/main/java/com/loohp/limbo/Unsafe.java b/src/main/java/com/loohp/limbo/Unsafe.java index 28638c4..8317eca 100644 --- a/src/main/java/com/loohp/limbo/Unsafe.java +++ b/src/main/java/com/loohp/limbo/Unsafe.java @@ -28,12 +28,17 @@ public class Unsafe { worldConstructor.setAccessible(false); } catch (Exception e) {e.printStackTrace();} } - + @Deprecated public void setPlayerGameModeSilently(Player player, GameMode mode) { playerUnsafe.a(player, mode); } - + + @Deprecated + public void setSelectedSlotSilently(Player player, byte slot) { + playerUnsafe.a(player, slot); + } + @Deprecated public void setPlayerEntityId(Player player, int entityId) { playerUnsafe.a(player, entityId); diff --git a/src/main/resources/mapping.json b/src/main/resources/mapping.json index ca0afcf..5c2b71f 100644 --- a/src/main/resources/mapping.json +++ b/src/main/resources/mapping.json @@ -18,7 +18,8 @@ "0x12": "PacketPlayInPosition", "0x14": "PacketPlayInRotation", "0x0B": "PacketPlayInPluginMessaging", - "0x06": "PacketPlayInTabComplete" + "0x06": "PacketPlayInTabComplete", + "0x25": "PacketPlayInHeldItemChange" }, "PlayOut": { "PacketPlayOutLogin": "0x24", @@ -41,7 +42,8 @@ "PacketPlayOutEntityDestroy": "0x36", "PacketPlayOutEntityMetadata": "0x44", "PacketPlayOutSpawnEntity": "0x00", - "PacketPlayOutSpawnEntityLiving": "0x02" + "PacketPlayOutSpawnEntityLiving": "0x02", + "PacketPlayOutHeldItemChange": "0x3F" }, "StatusIn": { "0x01": "PacketStatusInPing",