From 3c06b62c9115fe940a23ee92b2caa6e462df3ffe Mon Sep 17 00:00:00 2001 From: Mark Vainomaa Date: Sun, 25 Sep 2016 00:46:00 +0300 Subject: [PATCH] Add BukkitUtils Currently it contains NMS ping getter and plugin message wrapper --- BukkitUtils/pom.xml | 45 ++++++++++ .../mikroskeem/utils/bukkit/MessageUtils.java | 40 +++++++++ .../mikroskeem/utils/bukkit/PlayerUtils.java | 48 ++++++++++ .../utils/bukkit/PluginMessage.java | 88 +++++++++++++++++++ pom.xml | 1 + 5 files changed, 222 insertions(+) create mode 100644 BukkitUtils/pom.xml create mode 100644 BukkitUtils/src/main/java/eu/mikroskeem/utils/bukkit/MessageUtils.java create mode 100644 BukkitUtils/src/main/java/eu/mikroskeem/utils/bukkit/PlayerUtils.java create mode 100644 BukkitUtils/src/main/java/eu/mikroskeem/utils/bukkit/PluginMessage.java diff --git a/BukkitUtils/pom.xml b/BukkitUtils/pom.xml new file mode 100644 index 0000000..33af7bd --- /dev/null +++ b/BukkitUtils/pom.xml @@ -0,0 +1,45 @@ + + + + utils + eu.mikroskeem + 1.0-SNAPSHOT + + 4.0.0 + + bukkitutils + + + + spigot-repo + https://hub.spigotmc.org/nexus/content/repositories/snapshots/ + + + + + + eu.mikroskeem + reflect + 1.0-SNAPSHOT + + + org.bukkit + bukkit + 1.10.2-R0.1-SNAPSHOT + provided + + + org.projectlombok + lombok + 1.16.10 + provided + + + org.jetbrains + annotations-java5 + RELEASE + + + \ No newline at end of file diff --git a/BukkitUtils/src/main/java/eu/mikroskeem/utils/bukkit/MessageUtils.java b/BukkitUtils/src/main/java/eu/mikroskeem/utils/bukkit/MessageUtils.java new file mode 100644 index 0000000..2dcf1a3 --- /dev/null +++ b/BukkitUtils/src/main/java/eu/mikroskeem/utils/bukkit/MessageUtils.java @@ -0,0 +1,40 @@ +package eu.mikroskeem.utils.bukkit; + +import org.bukkit.entity.Player; +import org.bukkit.plugin.Plugin; +import org.jetbrains.annotations.NotNull; + +public class MessageUtils { + /** + * Get new PluginMessage instance to be used in try-resource block + * + * @param plugin Plugin that initates plugin message sending + * @param player Player to send message over + * @param channel Channel to send message to + * @return PluginMessage instance + */ + public static PluginMessage newPluginMessage(@NotNull Plugin plugin, + @NotNull Player player, + @NotNull String channel){ + return new PluginMessage(plugin, player, channel); + } + + /** + * Send plugin message + * + * @param plugin Plugin that initates plugin message sending + * @param player Player to send message over + * @param channel Channel to send message to + * @param contents Message contents + */ + public static void sendPluginMessage(@NotNull Plugin plugin, + @NotNull Player player, + @NotNull String channel, + @NotNull String[] contents){ + try(PluginMessage message = newPluginMessage(plugin, player, channel)){ + for (String content : contents) { + message.writeUTF(content); + } + } + } +} diff --git a/BukkitUtils/src/main/java/eu/mikroskeem/utils/bukkit/PlayerUtils.java b/BukkitUtils/src/main/java/eu/mikroskeem/utils/bukkit/PlayerUtils.java new file mode 100644 index 0000000..a80b7fc --- /dev/null +++ b/BukkitUtils/src/main/java/eu/mikroskeem/utils/bukkit/PlayerUtils.java @@ -0,0 +1,48 @@ +package eu.mikroskeem.utils.bukkit; + +import eu.mikroskeem.utils.reflect.Reflect; +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; + +public class PlayerUtils { + /** + * Return player ping (via NMS reflection) + * + * Note: I'm bit disappointed, that Bukkit API doesn't expose method to get player's ping + * + * @param player Player who ping to query + * @return Player's ping (-1 if reflection failed) + */ + public static int getNMSPing(@NotNull Player player){ + int ping = -1; + + String bukkitPackageName = Bukkit.getServer().getClass().getPackage().getName(); + String nmsVer = bukkitPackageName.substring(bukkitPackageName.lastIndexOf(".") + 1); + + Class craftPlayerClass = Reflect.getClass( + String.format("org.bukkit.craftbukkit.%s.entity.CraftPlayer", nmsVer)); + Class craftEntityPlayerClass = Reflect.getClass( + String.format("net.minecraft.server.%s.EntityPlayer", nmsVer)); + + if(craftPlayerClass != null && craftEntityPlayerClass != null){ + Method getHandle = Reflect.getMethod(craftPlayerClass, "getHandle"); + if(getHandle != null){ + Object handle = Reflect.invokeMethod(getHandle, player); + if(handle != null){ + Field pingField = Reflect.getField(craftEntityPlayerClass, "ping"); + if(pingField != null){ + Integer nmsPing = (Integer)Reflect.readField(pingField, handle); + if(nmsPing != null){ + return nmsPing; + } + } + } + } + } + return ping; + } +} diff --git a/BukkitUtils/src/main/java/eu/mikroskeem/utils/bukkit/PluginMessage.java b/BukkitUtils/src/main/java/eu/mikroskeem/utils/bukkit/PluginMessage.java new file mode 100644 index 0000000..44fe968 --- /dev/null +++ b/BukkitUtils/src/main/java/eu/mikroskeem/utils/bukkit/PluginMessage.java @@ -0,0 +1,88 @@ +package eu.mikroskeem.utils.bukkit; + +import com.google.common.io.ByteArrayDataOutput; +import com.google.common.io.ByteStreams; +import lombok.Getter; +import org.bukkit.entity.Player; +import org.bukkit.plugin.Plugin; + +/** + * PluginMessage class + * + * Checks if plugin message channel is registered and sends message if try-resource block ends. + * You can use this like you would write normal plugin messages. + */ +public class PluginMessage implements AutoCloseable,ByteArrayDataOutput { + @Getter + private ByteArrayDataOutput pluginMessage = ByteStreams.newDataOutput(); + private String channel; + private Player player; + private Plugin plugin; + private boolean wasChannelRegistered = false; + + + public PluginMessage(Plugin plugin, Player player, String channel){ + this.channel = channel; + this.player = player; + this.plugin = plugin; + + /* Check if channel is registered */ + if(plugin.getServer().getMessenger().isOutgoingChannelRegistered(plugin, channel)){ + wasChannelRegistered = true; + } else { + plugin.getServer().getMessenger().registerOutgoingPluginChannel(plugin, channel); + } + } + @Override public void write(int b) { + pluginMessage.write(b); + } + @Override public void write(byte[] b) { + pluginMessage.write(b); + } + @Override public void write(byte[] b, int off, int len) { + pluginMessage.write(b, off, len); + } + @Override public void writeBoolean(boolean v) { + pluginMessage.writeBoolean(v); + } + @Override public void writeByte(int v) { + pluginMessage.writeByte(v); + } + @Override public void writeShort(int v) { + pluginMessage.writeShort(v); + } + @Override public void writeChar(int v) { + pluginMessage.writeChar(v); + } + @Override public void writeInt(int v) { + pluginMessage.writeInt(v); + } + @Override public void writeLong(long v) { + pluginMessage.writeLong(v); + } + @Override public void writeFloat(float v) { + pluginMessage.writeFloat(v); + } + @Override public void writeDouble(double v) { + pluginMessage.writeDouble(v); + } + @Override public void writeChars(String s) { + pluginMessage.writeChars(s); + } + @Override public void writeUTF(String s) { + pluginMessage.writeUTF(s); + } + @Override @SuppressWarnings("deprecation") + public void writeBytes(String s) { + pluginMessage.writeBytes(s); + } + @Override public byte[] toByteArray() { + return pluginMessage.toByteArray(); + } + @Override public void close() { + player.sendPluginMessage(plugin, channel, pluginMessage.toByteArray()); + if(!wasChannelRegistered){ + plugin.getServer().getMessenger().unregisterOutgoingPluginChannel(plugin, channel); + } + } +} diff --git a/pom.xml b/pom.xml index fd67075..78d3020 100644 --- a/pom.xml +++ b/pom.xml @@ -15,6 +15,7 @@ Paste Itemutils TextUtils + BukkitUtils