An animated Motd?

Discussion in 'Plugin Development' started by MexMaster, Dec 4, 2014.

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

    MexMaster

    Hey all,
    I'm trying to figure out how to send motd updates without having the player to press the refresh button.
    Like in this plugin: <Edit by Moderator: Redacted not allowed paid resource url>
    or add the server to your list "<font color="#2c2c2c">macizun.me</font>
    " (this is no advertisement ._.) and click refresh, you will see

    So to my problem: I have nearly searched for 3-4 hours now but I can't find anything in the source of minecraft nor in the source of a minecraft server to allow this.

    Any experienced developer maybe got an idea?

    btw, things I found out which could help:
    I found out the are packets for sending the motd (and server info) on ping, but i can't send them again because I can just send packets to players online (maybe this could be a good idea).
    I found out that it maybe could be made with some extra software like a extra server connecting to the client and sending packets.
    I found out that the client !probably! (haven't checked this one) close the connection after the serverping packet got in after clicking refresh. That would make it hard to send packets to the then "unconnected" client.
    I found out that plugin channels can be used to receive a message when a ping goes in, but that doesn't seem to work the other way around (like sending updates).
    I found out some more things that i already forgot :p

    Hope you can help

    Thanks, :)
     
    Last edited by a moderator: Dec 6, 2016
  2. Offline

    Shevchik

    You can just keep sending server info messages, without sending pong message, and client will hold connection and display updated ping.
    Here is the POC implementation https://github.com/Shevchik/AnimatedPing
     
    MexMaster likes this.
  3. Offline

    MexMaster

    Thanks so much man! :D Shevchik
    I really thought the client would close the connection and it wouldn't any longer be possible :p
    Will try this when I get home later.

    Shevchik As I expected i get a "ChannelClosedException" (how I understood, it means the player closed the socket), how did you get that solved, I think I used more of your code correctly?
    Here's my code:
    Code:java
    1. public class PingListener {
    2.  
    3. public static boolean didIt = false;
    4.  
    5. public static void start(){
    6. MOTDPlus.ProtocolManager.addPacketListener(new PacketAdapter(PacketAdapter.params(MOTDPlus.Plugin, PacketType.Status.Server.OUT_SERVER_INFO, PacketType.Status.Server.OUT_PING).listenerPriority(ListenerPriority.HIGHEST)){
    7. public void onPacketSending(PacketEvent e){
    8. if(didIt){
    9. return;
    10. }
    11. e.setCancelled(true);
    12. didIt = true;
    13. if(e.getPacket().getType() == PacketType.Status.Server.OUT_SERVER_INFO){
    14. new MOTDUpdater(e.getPlayer(), e.getPacket().getServerPings().read(0), 300).start();
    15. }
    16. }
    17. });
    18. }
    19. }


    Code:java
    1. public class MOTDUpdater extends Thread {
    2.  
    3. private Player p;
    4. private WrappedServerPing packet;
    5. private int delay;
    6.  
    7. private boolean flag = false;
    8.  
    9. public MOTDUpdater(Player p, WrappedServerPing packet, int delay){
    10. this.p = p;
    11. this.packet = packet;
    12. this.delay = 0;
    13. }
    14.  
    15. @Override
    16. public void run(){
    17. try{
    18. Log.severe("Starting updater...");
    19. while(delay < 6){
    20. Log.severe("Checking online, receiving packet...");
    21. MOTDPlus.ProtocolManager.recieveClientPacket(p, new PacketContainer(PacketType.Status.Client.IN_PING));
    22. Log.severe("Packet received.");
    23. PacketContainer info = MOTDPlus.ProtocolManager.createPacket(PacketType.Status.Server.OUT_SERVER_INFO);
    24. if(flag){
    25. packet.setMotD("Höhö");
    26. packet.setPlayersMaximum(5341);
    27. packet.setPlayersOnline(5340);
    28. packet.setVersionProtocol(70);
    29. packet.setVersionName("haha");
    30. WrappedGameProfile profile = new WrappedGameProfile(UUID.randomUUID(), "Naa du Nudel!");
    31. packet.getPlayers().clear();
    32. packet.setPlayers(Arrays.asList(profile));
    33. }else{
    34. packet.setMotD("Haha");
    35. packet.setPlayersMaximum(5342);
    36. packet.setPlayersOnline(5341);
    37. packet.setVersionProtocol(70);
    38. packet.setVersionName("HÖHÖ");
    39. WrappedGameProfile profile = new WrappedGameProfile(UUID.randomUUID(), "Joo wahrscheinlich :p");
    40. packet.getPlayers().clear();
    41. packet.setPlayers(Arrays.asList(profile));
    42. }
    43. flag = !flag;
    44. Log.severe("Packet to send is constructed!");
    45. info.getServerPings().write(0, packet);
    46. Log.severe("Packet written");
    47. MOTDPlus.ProtocolManager.sendServerPacket(p, info);
    48. Log.severe("Packet send to player, sleeping...");
    49. Thread.sleep(1000);
    50. Log.severe("Woke up");
    51. delay++;
    52. if(delay > 5){
    53. Log.severe("Delay forced end!");
    54. break;
    55. }
    56. }
    57. }catch(Exception e){ Log.severe("Error"); return; }
    58. }
    59. }


    Everything works, but I get this error, so everything should be registered correctly

    Hope you can help, thanks

    @Moderators I don't edited my last post because that would currupt the whole spacing of the code and i don't have the code anymore to paste it in again (useful if somebody could fix this?)

    Shevchik I compiled your AnimatedPing Plugin and it does nothing. No error, just nothing. (But it makes my localhost server slower when pinging so i have a connection of around 50ms to my own pc :D). So could you please look over your own code and maybe say what's wrong?

    EDIT by Moderator: merged posts, please use the edit button instead of double posting.
     
    Last edited by a moderator: Jun 29, 2016
  4. Offline

    Shevchik

    You didn't configured it, so ofc it does nothing.

    Your problem if that you don't cancel Pong packets, you do this only 1 time actually.
     
  5. Offline

    teej107

    Java code tag is the only code tag that has this problem. The other code tags are fine.
     
  6. Offline

    MexMaster

    teej107 Good to know
    Shevchik I can't get it to work, now I cancel the Pong out packet but now it just shows me (no connection), I can see the motd but I can't change it.

    !Everything! is like in your AnimatedPing plugin except these two:
    Code:java
    1. @Override
    2. public void onPacketSending(PacketEvent event) {
    3. if(event.getPacket().getType() == PacketType.Status.Server.OUT_PING){
    4. event.setCancelled(true);
    5. }
    6. event.setCancelled(true);
    7. if (event.getPacket().getType() == PacketType.Status.Server.OUT_SERVER_INFO) {
    8. new PingResponseThread(event.getPlayer(), event.getPacket().getServerPings().read(0), 300, pluginRef.getConfiguration().getPings()).start();
    9. }
    10. }


    Code:java
    1. originalResponce.setPlayersOnline(Bukkit.getOnlinePlayers().!size()!);
    2. //Because it's not an array it's a list


    But it does nothing else than showing my "(no connection)" when hovering over the ping icon and that's it.

    Hope you can help
    At the meanwhile i will have a look at the mincraft code or search further through the internet :/

    Also i edited the PingResponseHandler:
    Code:java
    1. PacketContainer serverInfo = manager.createPacket(PacketType.Status.Server.OUT_SERVER_INFO);
    2. originalResponce.setPlayersOnline(Bukkit.getOnlinePlayers().size());
    3. originalResponce.setMotD("Noob");
    4. originalResponce.setVersionProtocol(70);
    5. originalResponce.setVersionName("Joo Wahrscheinlich");
    6. originalResponce.setPlayersMaximum(2001);
    7. originalResponce.setPlayersOnline(2000);
    8. /*PingData toDisplay = pingDatas[currentPingToDisplay];
    9.   if (toDisplay.getImage() != null) {
    10.   originalResponce.setFavicon(toDisplay.getImage());
    11.   }
    12.   if (toDisplay.getMotd() != null) {
    13.   originalResponce.setMotD(WrappedChatComponent.fromText(ChatColor.translateAlternateColorCodes('&', pingDatas[currentPingToDisplay].getMotd())));
    14.   }
    15.   if (toDisplay.getPlayers() != null) {
    16.   List<WrappedGameProfile> profiles = new ArrayList<WrappedGameProfile>();
    17.   for (String player : toDisplay.getPlayers()) {
    18.   WrappedGameProfile profile = new WrappedGameProfile(randomUUID, ChatColor.translateAlternateColorCodes('&', player));
    19.   profiles.add(profile);
    20.   }
    21.   originalResponce.setPlayers(profiles);
    22.   }*/
    23. serverInfo.getServerPings().write(0, originalResponce);
    24. manager.sendServerPacket(player, serverInfo, false);
    25. currentPingToDisplay++;
    26. if (currentPingToDisplay >= pingDatas.length) {
    27. currentPingToDisplay = 0;
    28. }
    29. Thread.sleep(1000);


    Great information:
    I think it's working!

    Code:java
    1. private static final ProtocolManager manager = ProtocolLibrary.getProtocolManager();
    2.  
    3. public PingListener(final AnimatedPing pluginRef) {
    4. manager.addPacketListener(
    5. new PacketAdapter(
    6. PacketAdapter
    7. .params(pluginRef, PacketType.Status.Server.OUT_SERVER_INFO, PacketType.Status.Server.OUT_PING)
    8. .listenerPriority(ListenerPriority.HIGHEST)
    9. ) {
    10. @Override
    11. public void onPacketSending(PacketEvent e) {
    12. if(e.getPacket().getType() == PacketType.Status.Server.OUT_SERVER_INFO){
    13. if(!e.getPacket().getServerPings().read(0).getVersionName().equals("Nudel1.0")){
    14. d("Server info request got in, editing packet");
    15. e.getPacket().getServerPings().read(0).setMotD("Yap");
    16. e.getPacket().getServerPings().read(0).setPlayersVisible(true);
    17. e.getPacket().getServerPings().read(0).setVersionProtocol(69);
    18. e.getPacket().getServerPings().read(0).setVersionName("DM");
    19. final Player p = e.getPlayer();
    20. final PacketContainer packet = e.getPacket();
    21. Bukkit.getScheduler().runTaskLater(pluginRef, new Runnable(){
    22. @Override
    23. public void run(){
    24. packet.getServerPings().read(0).setMotD("Haha");
    25. packet.getServerPings().read(0).setVersionName("Nudel1.0");
    26. packet.getServerPings().read(0).setPlayersOnline(5);
    27. try {
    28. manager.sendServerPacket(p, packet);
    29. d("Error while sending second packet:");
    30. e.printStackTrace();
    31. }
    32. }
    33. }, 40L);
    34. }
    35. }
    36. if(e.getPacket().getType() == PacketType.Status.Server.OUT_PING){
    37. d("Ping got in, cancelling");
    38. e.setCancelled(true);
    39. }
    40. }
    41. }
    42. );
    43. }
    44.  
    45. public void d(String msg){
    46. System.out.println(msg);
    47. }


    This what I used.
    I found out that the PacketEvent is also fired when I send a packet with "manager.sendServerPacket();", so i fixed that and tried some things, but now it's working fully.

    I'll leave this thread not solved because now I got into testing and maybe I will write if I need help here.
    Btw: I will mark it as solved when everything seems to work

    Btw2: Wouldn't this cause memory leaks in the client, because the socket remains open. Or is that no problem with minecraft?

    Ok well the "Btw2" is not true, the sockets close automatically when you click "Abort" (in ther server menu) or join a server.

    And the good thing is you will get a ChannelClosedException when this happens which means you can then just stop updating the motd of these players and you won't update while the client can't even get the updates :p

    At this point thanks to all who help solve this :)

    EDIT by Moderator: merged posts, please use the edit button instead of double posting.
     
    Last edited by a moderator: Jun 29, 2016
  7. Offline

    Deleted user

    MexMaster

    Actually, your fears are not unfound. Minecraft clients (through what limited testing I did) don't close connections if you spam refresh the server list, so you need to do some fancy work server-side in order to make sure the client doesn't use up all of it's connections.
     
  8. Offline

    Shevchik

    That 3rd arg in manager.sendServerPacket was there not for no reason. It bypasses protocollib filters.
     
  9. Offline

    MexMaster

    Shevchik thanks again :D I haven't looked into protocollib for now, because i don't really like depending on another plugin.
     
Thread Status:
Not open for further replies.

Share This Page