API PingAPI: Listen for and modify outgoing ping responses

Discussion in 'Resources' started by Skionz, Feb 7, 2015.

Thread Status:
Not open for further replies.
  1. Offline

    Skionz

    [​IMG]
    PingAPI lets you listen for outgoing PacketStatusOutServerInfo packets and allows you to easily modify them. You can also leave the connection open and send multiple PacketStatusOutServerInfo packets. Have you ever seen that AnimatedMOTD plugin that I am not aloud to link to? This is how that plugin works and can easily be implemented with PingAPI.

    Links
    - GitHub
    - Download (Until accepted on BukkitDev)

    What can it do?
    - Modify the online player count and the max players
    - Change the player sample (list of players shown when hovering over the player count)
    - Fake the protocol name and version to display text instead of the player count
    - Create server list 'animations'
    - Hide the player count


    Tutorials: For each mutator featured in these tutorials there is a corresponding accessor method.
    Creating a basic listener (open)

    To use PingAPI to it's full potential you have to create a Listener. This is done similar to registering a Bukkit listener. Before we actually register it we need to create it. You can either create a new class that implements 'PingListener,' or just an anonymous inner class which is my method of choice. Here is a simple example of a PingListener
    Code:
    public class TestListener implements PingListener {
        public void onPing(PingEvent event) {
            event.getReply().setMOTD("This is an MOTD");
        }
    }
    Now that we have created the PingListener we need to actually register it. You can do so by invoking the static method 'PingAPI.registerListener(PingListener).' Here is an example using an anonymous inner class.
    Code:
    public class MyPlugin extends JavaPlugin {
       public void onEnable() {
            PingAPI.registerListener(new PingListener() {
                public void onPing(PingEvent event) {
                    event.getReply().setMOTD("This is an MOTD");
                }
            }
        }
    }
    Changing the player count (open)

    Bukkit does not support changing the online player count with the ServerListPingEvent due to obvious reasons, but PingAPI does. You can easily do this by invoking PingReply#setOnlinePlayers(int). Here is an example:
    Code:
    public class TestListener implements PingListener {
        public void onPing(PingEvent event) {
            event.getReply().setOnlinePlayers(5000);
        }
    }
    This is the output:
    [​IMG]
    Sending multiple PacketStatusOutServerInfo packets (open)

    You can easily send multiple PacketStatusOutServerInfo packets. Basically when the 'onPing' method is finished it constructs and new PacketStatusOutServerInfo packet based on the properties in the PingReply object. If the PingEvent is cancelled (Use PingEvent#setCancelled(boolean)) it won't send the packet. Here is an example of canceling the original packet, but creating and sending a different one which is redundant, but a good example.
    Code:
    public class TestListener implements PingListener {
        public void onPing(PingEvent event) {
            ServerInfoPacket packet = event.createNewPacket(event.getReply());
            packet.send();
            reply.setCancelled(true);
        }
    }
    The ServerInfoPacket is basically a simple PacketStatusOutServerInfo wrapper which creates and sends a new packet based on the information stored in the PingReply object.
    Note that the 'onPing' method is not invoked on the main thread. This said you can easily create an animated motd, but after a few seconds the client will close the connection and you will no longer be able to send PacketStatusOutServerInfo packets.
    Changing the player count to text (open)

    The client sends a ping packet to the server and it replies with all your information including the server's protocol version and compares it to that of the client. If the protocol version's do not match it displays a red message in replacement of the player count such as "Spigot 1.8." We can use this and send a fake protocol version such as -1 and change the default protocol name message to a new one. Here is an example:
    Code:
    public class TestListener implements PingListener {
        public void onPing(PingEvent event) {
            PingReply reply = event.getReply();
            reply.setProtocolVersion(-1);
            reply.setProtocolName(ChatColor.GREEN + "This is a message...");
        }
    }
    The result would look like this:
    [​IMG]
    Changing the player sample (hover message) (open)

    As you probably know, when you hover over the player count it displays a list of a few random player's names. This can easily be changed to your own message with PingAPI. Here is an example:
    Code:
    public class TestListener implements PingListener {
        public void onPing(PingEvent event) {
            List<String> sample = new ArrayList<String>();
            sample.add(ChatColor.BLUE + "GenericCraft");
            sample.add("-------------------------");
            sample.add(ChatColor.GOLD + "New game thing available");
            sample.add(ChatColor.AQUA + "Join for free stuff now!");
            event.getReply().setPlayerSample(sample);
        }
    }
    This is the output
    [​IMG]


    Documentation
    PingEvent: Stores the PingReply and defines whether the event is cancelled or not
    • getReply() - PingReply
    • createNewPacket(PingReply) - ServerInfoPacket
    • isCancelled() - boolean
    • setCancelled(boolean) - void
    PingReply: A class that stores the data to send to the client
    • getOnlinePlayers() - int
    • getMaxPlayers() - int
    • getMOTD() - String
    • getProtocolVersion() - int
    • getProtocolName() - String
    • getPlayerSample() - GameProfile[]
    • arePlayersHidden() - boolean
    • setOnlinePlayers(int) - void
    • setMaxPlayers(int) - void
    • setMOTD(String) - void
    • setProtocolVersion(int) - void
    • setProtocolName(String) - void
    • setPlayerSample(GameProfile[]) - void
    • hidePlayers(boolean) - void
    ServerInfoPacket: Represents a PacketStatusOutServerInfo instance
    • send() - void
    • setPingReply() - void
    • getPingReply() - PingReply
    Make sure to add 'depend: [PingAPI]' to your plugin.yml file.
     
    Last edited: Feb 19, 2015
  2. Offline

    Monkey_Swag

  3. Offline

    Yekllurt

    This is nice !
     
    Skionz likes this.
  4. Offline

    mrCookieSlime

    Moved to Alternatives Section as this requires an Alternative to be used.
     
    xXBeLkAXx likes this.
  5. Offline

    Monkey_Swag

  6. Offline

    Skionz

    Yeah, just you.
     
  7. Offline

    mine-care

    @Skionz <3 <3 Luv U!
    just a question. is it just for 1.8? because i have seen a server running something similar to that (moving motd, custom playercount ect), where the server is V 1.7.2 and my 1.7.2 client can see the moving stuff :3
     
  8. Offline

    Skionz

    Currently mine is, but I will probably add back compatibility.
     
    mine-care likes this.
  9. Offline

    TehHypnoz

    Didn't know this was possible, will try it now. @mrCookieSlime what alternative are you talking about? Spigot?
     
  10. Offline

    mrCookieSlime

    @TehHypnoz
    Bukkit 1.8
    And this is not going to be another one of those discussions.
    Bukkit 1.8 was made by the Spigot Team and is therefore considered to be an Alternative.
     
  11. Offline

    TehHypnoz

    Oh okay. And yes I know it's an alternative, since it's not an official release.
     
    timtower likes this.
  12. Offline

    mine-care

  13. Offline

    ProStriker123

    @Skionz, Wow, Man you are awsome!! Nice job!
     
  14. Another great Resource. Well done @Skionz
     
  15. Offline

    AdityaTD

    public class TestListener implements PingListener {
    public void onPing(PingEvent event) {
    PingReply reply = event.getReply();
    reply.setProtocolVersion(-1);
    reply.setProtocolName(ChatColor.GREEN + "This is a message...");
    }
    }

    How can I use it on BungeeCord??
     
  16. Offline

    Skionz

    Its a Bukkit plugin, not a BungeeCord plugin. I didn't think it was necessary to make a BungeeCord implementation because md_5 gives you a lot more control on Bungee's ping event.
     
  17. Offline

    jebbo

    Thanks for this API :D

    How can I add a second Line in the MOTD?
     
  18. Offline

    Gamecube762

    Nice! I was wondering when someone was going to make an API for this.
     
  19. Offline

    mrCookieSlime

    Moved to Resources as this was built against 1.7
     
  20. Offline

    Skionz

    Alright I added support for 1.7.10 an hour or so ago, but 1.8 and 1.7.10 are the only version I currently have.
    Also, if anyone is interested I am starting to make a few classes oriented specifically towards animation.
     
    Monkey_Swag, Gingerbreadman and jebbo like this.
  21. Offline

    jebbo

    @Skionz
    I have a small problem here, when nobody is on the Server, the MOTD shows perfectly. But when people are online it just shows the bukkit standart motd.. :/ No error in Console
     
  22. Offline

    Skionz

    @jebbo Thanks for reporting this. It should be fixed soon.
    EDIT: Fixed. Update to the new version on Spigot
     
    Last edited: Feb 9, 2015
    Gingerbreadman likes this.
  23. Offline

    Gingerbreadman

    @Skionz I am going to use this in my new plugins!
    Good job! xD
     
    Skionz likes this.
  24. @Skionz Good job! Although, if it isn't too much hassle, I know that this is good for 1.8 and 1.7.10 but maybe you could go a version lower and get 1.7.9? I know that it's a hassle, but when I'm trying to update my plugins to 1.7.10 I'm having multiple errors and issues that doesn't have an easy solution. About 3 of my commands were dysfunctional, and couldn't be fixed. Anyway, if you can't it's okay. Thanks. :)

    ~ CodePlaysMinecraft
     
  25. Offline

    Skionz

    @CodePlaysMinecraft Added :)
    You can download it from spigot, but it won't be on BukkitDev for an hour or so.
     
  26. @Skionz Also, forgot to mention, I think I may have found a bug.
    When setting the hover message, the line "event.getReply().setPlayerSample(sample);" is giving me the error, "The methods setPlayerSample(List<String>) in the type PingReply is not applicable for the arguments (GameProfile[])". I'm using CraftBukkit 1.7.9 R0.1
    Here is my code (if needed):
    Code:
    package me.CodePlaysMC.TheRealmCore.PingAPI;
    
    import java.util.UUID;
    
    import me.CodePlaysMC.TheRealmCore.PluginListener;
    import me.CodePlaysMC.TheRealmCore.TheRealmCore;
    import net.minecraft.util.com.mojang.authlib.GameProfile;
    
    import org.bukkit.ChatColor;
    import org.bukkit.event.EventHandler;
    
    import com.skionz.pingapi.PingEvent;
    import com.skionz.pingapi.PingListener;
    
    public class PCM extends PluginListener implements PingListener {
    
        public PCM(TheRealmCore pl) {
            super(pl);
        }
    
        @EventHandler
        public void onPing(PingEvent event) {
            GameProfile[] line = new GameProfile[4];
            line[1] = new GameProfile(UUID.randomUUID(), ChatColor.DARK_BLUE + "" + ChatColor.BOLD + "The Realm");
            line[2] = new GameProfile(UUID.randomUUID(), "--------------------");
            line[3] = new GameProfile(UUID.randomUUID(), ChatColor.AQUA + "Custom plugins!");
            line[4] = new GameProfile(UUID.randomUUID(), ChatColor.AQUA + "Mini games!");
            event.getReply().setPlayerSample(line);
        }
    }
    One last thing, sorry if this is a stupid question but, how would I make an animation (like the gif you have)? Would I use a Bukkit Runnable...?
     
    Last edited: Feb 10, 2015
  27. Offline

    Skionz

    @CodePlaysMinecraft I changed 'setPlayerSample()' to take a String List instead of an array of GameProfiles because nobody actually uses the player sample for its original purpose. I should update the tutorials.

    Anyways, to create an animation first you would cancel the pong by invoking PingEvent#cancelPong(true). Then you would create a for loop incrementing an integer and creating a delayed task. In that runnable (delayed task) you would create a new ServerInfoPacket by invoking PingEvent#createNewPacket(PingReply) and using the event's PingReply as the only argument. You could then set the PingReply's MOTD (PingReply#setMOTD(String)) to whatever you like and invoke ServerInfoPacket#send() to actually send the packet. When your animation is complete you should use PingEvent#cancelPong(false).
     
  28. Offline

    Plukkies

    this is not working:
    Code:
    PingEvent.createNewPacket(PingReply);
    
    Can i fix this?
     
  29. Offline

    Skionz

    What do you mean it isn't working? It should returns a 'ServerInfoPacket' object, but it takes a 'PingReply' object as its only argument and PingEvent#getReply() returns one.
     
Thread Status:
Not open for further replies.

Share This Page