diff --git a/src/main/java/us/ajg0702/queue/Main.java b/src/main/java/us/ajg0702/queue/Main.java index 525f268..00e0a0e 100644 --- a/src/main/java/us/ajg0702/queue/Main.java +++ b/src/main/java/us/ajg0702/queue/Main.java @@ -20,6 +20,7 @@ import net.md_5.bungee.event.EventHandler; import us.ajg0702.queue.utils.BungeeConfig; import us.ajg0702.queue.utils.BungeeMessages; import us.ajg0702.queue.utils.BungeeStats; +import us.ajg0702.queue.utils.BungeeUtils; public class Main extends Plugin implements Listener { @@ -47,6 +48,8 @@ public class Main extends Plugin implements Listener { this.getProxy().getPluginManager().registerListener(this, this); + getProxy().registerChannel("ajqueue:tospigot"); + timeBetweenPlayers = config.getInt("wait-time"); updateOnlineServers(); @@ -115,14 +118,13 @@ public class Main extends Plugin implements Listener { int pos = plys.indexOf(ply)+1; if(pos == 0) continue; int len = plys.size(); + String or = msgs.get("status.offline.restarting"); + if(ot > config.getInt("offline-time")) { + or = msgs.get("status.offline.offline"); + } else { + //ply.sendMessage(formatMessage(ot + " <= "+offlineSecs)); + } if(notif) { - String or = msgs.get("status.offline.restarting"); - if(ot > config.getInt("offline-time")) { - or = msgs.get("status.offline.offline"); - } else { - //ply.sendMessage(formatMessage(ot + " <= "+offlineSecs)); - } - ply.sendMessage(formatMessage( msgs.get("status.offline.base") .replaceAll("\\{STATUS\\}", or) @@ -130,6 +132,12 @@ public class Main extends Plugin implements Listener { .replaceAll("\\{LEN\\}", len+"") )); } + if(getConfig().getBoolean("send-actionbar")) { + BungeeUtils.sendCustomData(ply, "actionbar", msgs.get("spigot.actionbar.offline") + .replaceAll("\\{POS\\}", pos+"") + .replaceAll("\\{LEN\\}", len+"") + .replaceAll("\\{STATUS\\}", or)+";time="+timeBetweenPlayers); + } } if(!notif) { notif = true; @@ -168,6 +176,12 @@ public class Main extends Plugin implements Listener { .replaceAll("\\{TIME\\}", timeStr) )); } + if(getConfig().getBoolean("send-actionbar")) { + BungeeUtils.sendCustomData(ply, "actionbar", msgs.get("spigot.actionbar.online") + .replaceAll("\\{POS\\}", pos+"") + .replaceAll("\\{LEN\\}", len+"") + .replaceAll("\\{TIME\\}", timeStr)+";time="+timeBetweenPlayers); + } } if(!notif) { notif = true; diff --git a/src/main/java/us/ajg0702/queue/spigot/Main.java b/src/main/java/us/ajg0702/queue/spigot/Main.java new file mode 100644 index 0000000..5687e79 --- /dev/null +++ b/src/main/java/us/ajg0702/queue/spigot/Main.java @@ -0,0 +1,44 @@ +package us.ajg0702.queue.spigot; + +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; +import org.bukkit.plugin.java.JavaPlugin; +import org.bukkit.plugin.messaging.PluginMessageListener; + +import com.google.common.io.ByteArrayDataInput; +import com.google.common.io.ByteStreams; + +import us.ajg0702.queue.spigot.utils.VersionSupport; + +public class Main extends JavaPlugin implements PluginMessageListener { + public void onEnable() { + getServer().getMessenger().registerIncomingPluginChannel(this, "ajqueue:tospigot", this); + getLogger().info("Spigot side enabled! v"+getDescription().getVersion()); + } + + @Override + public void onPluginMessageReceived(String channel, Player player, byte[] message) { + if (!channel.equals("ajqueue:tospigot")) return; + ByteArrayDataInput in = ByteStreams.newDataInput(message); + String subchannel = in.readUTF(); + if(subchannel.equals("actionbar")) { + String data = in.readUTF(); + VersionSupport.sendActionBar(player, data.split(";time=")[0]); + int time = Integer.parseInt(data.split(";time=")[1]); + if(time > 2) { + Bukkit.getScheduler().runTaskLater(this, new Runnable() { + public void run() { + VersionSupport.sendActionBar(player, data.split(";time=")[0]); + } + }, 2*20); + if(time > 4) { + Bukkit.getScheduler().runTaskLater(this, new Runnable() { + public void run() { + VersionSupport.sendActionBar(player, data.split(";time=")[0]); + } + }, 4*20); + } + } + } + } +} diff --git a/src/main/java/us/ajg0702/queue/spigot/utils/ActionBar.java b/src/main/java/us/ajg0702/queue/spigot/utils/ActionBar.java new file mode 100644 index 0000000..57e8652 --- /dev/null +++ b/src/main/java/us/ajg0702/queue/spigot/utils/ActionBar.java @@ -0,0 +1,71 @@ +package us.ajg0702.queue.spigot.utils; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; + +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; + +/** + * A cross-version actionbar class + * @author Based on ActionBarAPI from https://github.com/ConnorLinfoot + * + */ +public class ActionBar { + + private static String version; + private static boolean old; + + public static void send(Player player, String message) { + if(player == null) return; + if(!player.isOnline()) return; + + version = Bukkit.getServer().getClass().getPackage().getName(); + version = version.substring(version.lastIndexOf(".") + 1); + + old = version.equalsIgnoreCase("v1_8_R1") || version.startsWith("v1_7_"); + + try { + Class craftPlayerClass = Class.forName("org.bukkit.craftbukkit." + version + ".entity.CraftPlayer"); + Object craftPlayer = craftPlayerClass.cast(player); + Object packet; + Class packetPlayOutChatClass = Class.forName("net.minecraft.server." + version + ".PacketPlayOutChat"); + Class packetClass = Class.forName("net.minecraft.server." + version + ".Packet"); + if (old) { + Class chatSerializerClass = Class.forName("net.minecraft.server." + version + ".ChatSerializer"); + Class iChatBaseComponentClass = Class.forName("net.minecraft.server." + version + ".IChatBaseComponent"); + Method m3 = chatSerializerClass.getDeclaredMethod("a", String.class); + Object cbc = iChatBaseComponentClass.cast(m3.invoke(chatSerializerClass, "{\"text\": \"" + message + "\"}")); + packet = packetPlayOutChatClass.getConstructor(new Class[]{iChatBaseComponentClass, byte.class}).newInstance(cbc, (byte) 2); + } else { + Class chatComponentTextClass = Class.forName("net.minecraft.server." + version + ".ChatComponentText"); + Class iChatBaseComponentClass = Class.forName("net.minecraft.server." + version + ".IChatBaseComponent"); + try { + Class chatMessageTypeClass = Class.forName("net.minecraft.server." + version + ".ChatMessageType"); + Object[] chatMessageTypes = chatMessageTypeClass.getEnumConstants(); + Object chatMessageType = null; + for (Object o : chatMessageTypes) { + if (o.toString().equals("GAME_INFO")) { + chatMessageType = o; + } + } + Object chatCompontentText = chatComponentTextClass.getConstructor(new Class[]{String.class}).newInstance(message); + packet = packetPlayOutChatClass.getConstructor(new Class[]{iChatBaseComponentClass, chatMessageTypeClass}).newInstance(chatCompontentText, chatMessageType); + } catch (ClassNotFoundException e) { + Object chatCompontentText = chatComponentTextClass.getConstructor(new Class[]{String.class}).newInstance(message); + packet = packetPlayOutChatClass.getConstructor(new Class[]{iChatBaseComponentClass, byte.class}).newInstance(chatCompontentText, (byte) 2); + } + } + Method craftPlayerHandleMethod = craftPlayerClass.getDeclaredMethod("getHandle"); + Object craftPlayerHandle = craftPlayerHandleMethod.invoke(craftPlayer); + Field playerConnectionField = craftPlayerHandle.getClass().getDeclaredField("playerConnection"); + Object playerConnection = playerConnectionField.get(craftPlayerHandle); + Method sendPacketMethod = playerConnection.getClass().getDeclaredMethod("sendPacket", packetClass); + sendPacketMethod.invoke(playerConnection, packet); + + } catch (Exception e) { + e.printStackTrace(); + } + } + +} \ No newline at end of file diff --git a/src/main/java/us/ajg0702/queue/spigot/utils/VersionSupport.java b/src/main/java/us/ajg0702/queue/spigot/utils/VersionSupport.java new file mode 100644 index 0000000..ff3c551 --- /dev/null +++ b/src/main/java/us/ajg0702/queue/spigot/utils/VersionSupport.java @@ -0,0 +1,32 @@ +package us.ajg0702.queue.spigot.utils; + +import org.bukkit.Bukkit; +import org.bukkit.entity.Player; + +import net.md_5.bungee.api.ChatMessageType; +import net.md_5.bungee.api.chat.TextComponent; + +public class VersionSupport { + + public static String getVersion() { + return Bukkit.getVersion().split("\\(MC: ")[1].split("\\)")[0]; + } + public static int getMinorVersion() { + return Integer.parseInt(getVersion().split("\\.")[1]); + } + + /** + * Send the player an actionbar message + * @param ply The {@link org.bukkit.entity.Player Player} to send the actionbar to + * @param message The message to send in the actionbar. + */ + public static void sendActionBar(Player ply, String message) { + // Use spigot version if available, otherwise use packets. + if(getMinorVersion() >= 11) { + ply.spigot().sendMessage(ChatMessageType.ACTION_BAR, TextComponent.fromLegacyText(message)); + } else if(getMinorVersion() >= 8) { + ActionBar.send(ply, message); + } + } + +} diff --git a/src/main/java/us/ajg0702/queue/utils/BungeeConfig.java b/src/main/java/us/ajg0702/queue/utils/BungeeConfig.java index 1c4f910..9c4d4ee 100644 --- a/src/main/java/us/ajg0702/queue/utils/BungeeConfig.java +++ b/src/main/java/us/ajg0702/queue/utils/BungeeConfig.java @@ -59,6 +59,9 @@ public class BungeeConfig { } return r; } + public boolean getBoolean(String key) { + return config.getBoolean(key); + } public String getDefaultConfig() throws IOException { BufferedReader stream = new BufferedReader(new InputStreamReader(this.getClass().getResourceAsStream("/config.yml"))); diff --git a/src/main/java/us/ajg0702/queue/utils/BungeeMessages.java b/src/main/java/us/ajg0702/queue/utils/BungeeMessages.java index 25191a8..d561a2f 100644 --- a/src/main/java/us/ajg0702/queue/utils/BungeeMessages.java +++ b/src/main/java/us/ajg0702/queue/utils/BungeeMessages.java @@ -78,6 +78,9 @@ public class BungeeMessages { d.put("list.total", "&7Total players in queues: &f{TOTAL}"); d.put("list.none", "&7None"); + d.put("spigot.actionbar.online", "&7You are in position &f{POS}&7 of &f{LEN}&7. Estimated time: {TIME}"); + d.put("spigot.actionbar.offline", "&7You are in position &f{POS}&7 of &f{LEN}&7."); + d.put("send", "&aAdded &f{PLAYER}&a to the queue for &f{SERVER}"); diff --git a/src/main/java/us/ajg0702/queue/utils/BungeeStats.java b/src/main/java/us/ajg0702/queue/utils/BungeeStats.java index b505de6..4502833 100644 --- a/src/main/java/us/ajg0702/queue/utils/BungeeStats.java +++ b/src/main/java/us/ajg0702/queue/utils/BungeeStats.java @@ -24,7 +24,6 @@ import java.util.zip.GZIPOutputStream; *

* Check out https://bStats.org/ to learn more about bStats! */ -@SuppressWarnings({"WeakerAccess", "unused"}) public class BungeeStats { static { @@ -171,7 +170,8 @@ public class BungeeStats { * * @return The server specific data. */ - private JsonObject getServerData() { + @SuppressWarnings("deprecation") + private JsonObject getServerData() { // Minecraft specific data int playerAmount = Math.min(plugin.getProxy().getOnlineCount(), 500); int onlineMode = plugin.getProxy().getConfig().isOnlineMode() ? 1 : 0; diff --git a/src/main/java/us/ajg0702/queue/utils/BungeeUtils.java b/src/main/java/us/ajg0702/queue/utils/BungeeUtils.java new file mode 100644 index 0000000..9623db4 --- /dev/null +++ b/src/main/java/us/ajg0702/queue/utils/BungeeUtils.java @@ -0,0 +1,26 @@ +package us.ajg0702.queue.utils; + +import java.util.Collection; + +import com.google.common.io.ByteArrayDataOutput; +import com.google.common.io.ByteStreams; + +import net.md_5.bungee.api.ProxyServer; +import net.md_5.bungee.api.connection.ProxiedPlayer; + +public class BungeeUtils { + public static void sendCustomData(ProxiedPlayer player, String channel, String data1) { + Collection networkPlayers = ProxyServer.getInstance().getPlayers(); + // perform a check to see if globally are no players + if ( networkPlayers == null || networkPlayers.isEmpty()) return; + + ByteArrayDataOutput out = ByteStreams.newDataOutput(); + out.writeUTF( channel ); + out.writeUTF( data1 ); + + // we send the data to the server + // using ServerInfo the packet is being queued if there are no players in the server + // using only the server to send data the packet will be lost if no players are in it + player.getServer().getInfo().sendData( "ajqueue:tospigot", out.toByteArray() ); + } +} diff --git a/src/main/resources/config.yml b/src/main/resources/config.yml index 812309a..d7030e8 100644 --- a/src/main/resources/config.yml +++ b/src/main/resources/config.yml @@ -1,5 +1,5 @@ # Dont touch this number please -config-version: 2 +config-version: 3 # The time the server will wait between sending people in the queue # Default: 5 @@ -12,4 +12,8 @@ offline-time: 120 # If a player is in a server, you can have the plugin make them automatically join a queue for another server # Example with the default values: Player joins survivalfallback server, they will auto-join the queue for survival queue-servers: -- 'survivalfallback:survival' \ No newline at end of file +- 'survivalfallback:survival' + +# Should the plugin send an actionbar to the player? +# Requires this plugin to be installed on the server the player is on for it to work +send-actionbar: true \ No newline at end of file diff --git a/src/main/resources/plugin.yml b/src/main/resources/plugin.yml new file mode 100644 index 0000000..20348ff --- /dev/null +++ b/src/main/resources/plugin.yml @@ -0,0 +1,4 @@ +main: us.ajg0702.queue.spigot.Main +version: ${project.version} +author: ajgeiss0702 +name: ajQueue \ No newline at end of file