Skip to content

Instantly share code, notes, and snippets.

@aadnk
Last active August 29, 2015 14:00
Show Gist options
  • Save aadnk/11198274 to your computer and use it in GitHub Desktop.
Save aadnk/11198274 to your computer and use it in GitHub Desktop.
Cancel inventory clicks with TinyProtocol
package com.comphenix.example;
import org.bukkit.entity.Player;
import org.bukkit.event.Listener;
import org.bukkit.inventory.ItemStack;
import org.bukkit.plugin.java.JavaPlugin;
import com.comphenix.example.Reflection.FieldAccessor;
import com.comphenix.example.Reflection.MethodInvoker;
import net.minecraft.util.io.netty.channel.Channel;
public class CancelInventoryClick extends JavaPlugin {
// net.minecraft.server.ItemStack
private Class<Object> nmsStackClass = Reflection.getUntypedClass("{nms}.ItemStack");
// Explosion packet
private Class<?> inventoryClickPacket = Reflection.getClass("{nms}.PacketPlayInWindowClick");
// Convert an NMS item stack to a CraftBukkit item stack
private MethodInvoker getItemStack = Reflection.getMethod("{obc}.inventory.CraftItemStack", "asCraftMirror", nmsStackClass);
// 0 is the player inventory
private FieldAccessor<Integer> windowId = Reflection.getField(inventoryClickPacket, int.class, 0);
private FieldAccessor<Integer> slotIndex = Reflection.getField(inventoryClickPacket, int.class, 1);
private FieldAccessor<Integer> button = Reflection.getField(inventoryClickPacket, int.class, 2);
private FieldAccessor<Short> actionNumber = Reflection.getField(inventoryClickPacket, short.class, 0);
private FieldAccessor<Object> itemStack = Reflection.getField(inventoryClickPacket, nmsStackClass, 0);
private FieldAccessor<Integer> clickMode = Reflection.getField(inventoryClickPacket, int.class, 3);
private TinyProtocol protocol;
@Override
public void onEnable() {
protocol = new TinyProtocol(this) {
@Override
public Object onPacketInAsync(final Player sender, Channel channel, Object packet) {
if (windowId.hasField(packet)) {
ItemStack stack = (ItemStack) getItemStack.invoke(null, itemStack.get(packet));
int index = slotIndex.get(packet);
System.out.println("Clicked: " + stack + " at " + index);
// To cancel
if (index == 0) {
// THE CURRENT METHOD IS ASYNC, SO WE CANNOT CALL BUKKIT API DIRECTLY.
// Instead, we have to use the scheduler
getServer().getScheduler().scheduleSyncDelayedTask(CancelInventoryClick.this, new Runnable() {
@SuppressWarnings("deprecation")
@Override
public void run() {
// This is needed to properly restore the inventory state on the client side
sender.updateInventory();
}
});
return null;
}
}
return packet;
}
@Override
public Object onPacketOutAsync(Player reciever, Channel channel, Object packet) {
return packet;
}
};
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment