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