package de.joethei.core.api; import io.netty.channel.Channel; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelPipeline; import io.netty.handler.codec.MessageToMessageDecoder; import java.lang.reflect.Array; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.UUID; import java.util.function.Consumer; import org.bukkit.Bukkit; import org.bukkit.entity.Player; import org.bukkit.event.EventHandler; import org.bukkit.event.Listener; import org.bukkit.event.player.PlayerJoinEvent; import org.bukkit.plugin.Plugin; import org.bukkit.scheduler.BukkitScheduler; public final class SignInput implements Listener, Runnable { private static final String VERSION; private final Plugin plugin; private final Map> inputResults; static { String path = Bukkit.getServer().getClass().getPackage().getName(); VERSION = path.substring(path.lastIndexOf(".") + 1, path.length()); } public SignInput(Plugin plugin) { this.plugin = plugin; this.inputResults = new HashMap(); Bukkit.getScheduler().runTaskTimer(this.plugin, this, 0L, 60L); } public boolean readInput(Player p, Consumer result) { this.inputResults.put(p.getUniqueId(), result); try { Class packetClass = Class.forName(getNMSClass("PacketPlayOutOpenSignEditor")); Class blockPositionClass = Class.forName(getNMSClass("BlockPosition")); Constructor blockPosCon = blockPositionClass .getConstructor(new Class[] { Integer.TYPE, Integer.TYPE, Integer.TYPE }); Object blockPosition = blockPosCon.newInstance(new Object[] { Integer.valueOf(0), Integer.valueOf(0), Integer.valueOf(0) }); Constructor packetCon = packetClass .getConstructor(new Class[] { blockPositionClass }); Object packet = packetCon .newInstance(new Object[] { blockPosition }); Method getHandle = p.getClass().getMethod("getHandle", new Class[0]); Object nmsPlayer = getHandle.invoke(p, new Object[0]); Field pConnectionField = nmsPlayer.getClass().getField( "playerConnection"); Object pConnection = pConnectionField.get(nmsPlayer); Method sendMethod = pConnection.getClass().getMethod("sendPacket", new Class[] { Class.forName(getNMSClass("Packet")) }); sendMethod.invoke(pConnection, new Object[] { packet }); return true; } catch (Exception ex) { ex.printStackTrace(); }return false; } public void run() { for (UUID uuid : this.inputResults.keySet()) if (Bukkit.getPlayer(uuid) == null) this.inputResults.remove(uuid); } @EventHandler public void onJoin(PlayerJoinEvent e) { Player p = e.getPlayer(); getNettyChannel(p).pipeline().addAfter("decoder", "signListener", new MessageToMessageDecoder() { protected void decode(ChannelHandlerContext chc, Object packet, List packetList) throws Exception { if (SignInput.this.instanceOf(packet, SignInput.access(SignInput.this, "PacketPlayInUpdateSign"))) { Method bMethod = packet.getClass().getMethod("b", new Class[0]); Object chatBaseComponents = bMethod.invoke(packet, new Object[0]); String[] lines = new String[4]; for (int i = 0; i < 4; i++) { Object chatComponent = Array.get( chatBaseComponents, i); Method getText = chatComponent.getClass() .getMethod("getText", new Class[0]); lines[i] = ((String)getText .invoke(chatComponent, new Object[0])); } if (SignInput.this.inputResults.containsKey(p.getUniqueId())) { ((Consumer)SignInput.this.inputResults.get(p.getUniqueId())).accept(lines); SignInput.this.inputResults.remove(p.getUniqueId()); } } packetList.add(packet); } }); } private Channel getNettyChannel(Player p) { Channel ch = null; try { Method getHandle = p.getClass().getMethod("getHandle", new Class[0]); Object nmsPlayer = getHandle.invoke(p, new Object[0]); Field pConnectionField = nmsPlayer.getClass().getField( "playerConnection"); Object pConnection = pConnectionField.get(nmsPlayer); Field networkManagerField = pConnection.getClass().getField( "networkManager"); Object networkManager = networkManagerField.get(pConnection); ch = (Channel)networkManager.getClass().getField("k") .get(networkManager); } catch (Exception ex) { ex.printStackTrace(); } return ch; } private boolean instanceOf(Object o, String className) { try { return Class.forName(className).isInstance(o); } catch (ClassNotFoundException e) { e.printStackTrace(); } return false; } private String getNMSClass(String className) { return "net.minecraft.server." + VERSION + "." + className; } }