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 Hope you can help Thanks,
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
Thanks so much man! Shevchik I really thought the client would close the connection and it wouldn't any longer be possible 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 public class PingListener { public static boolean didIt = false; public static void start(){ MOTDPlus.ProtocolManager.addPacketListener(new PacketAdapter(PacketAdapter.params(MOTDPlus.Plugin, PacketType.Status.Server.OUT_SERVER_INFO, PacketType.Status.Server.OUT_PING).listenerPriority(ListenerPriority.HIGHEST)){ public void onPacketSending(PacketEvent e){ if(didIt){ return; } e.setCancelled(true); didIt = true; if(e.getPacket().getType() == PacketType.Status.Server.OUT_SERVER_INFO){ new MOTDUpdater(e.getPlayer(), e.getPacket().getServerPings().read(0), 300).start(); } } }); }} Code:java public class MOTDUpdater extends Thread { private Player p; private WrappedServerPing packet; private int delay; private boolean flag = false; public MOTDUpdater(Player p, WrappedServerPing packet, int delay){ this.p = p; this.packet = packet; this.delay = 0; } @Override public void run(){ try{ Log.severe("Starting updater..."); while(delay < 6){ Log.severe("Checking online, receiving packet..."); MOTDPlus.ProtocolManager.recieveClientPacket(p, new PacketContainer(PacketType.Status.Client.IN_PING)); Log.severe("Packet received."); PacketContainer info = MOTDPlus.ProtocolManager.createPacket(PacketType.Status.Server.OUT_SERVER_INFO); if(flag){ packet.setMotD("Höhö"); packet.setPlayersMaximum(5341); packet.setPlayersOnline(5340); packet.setVersionProtocol(70); packet.setVersionName("haha"); WrappedGameProfile profile = new WrappedGameProfile(UUID.randomUUID(), "Naa du Nudel!"); packet.getPlayers().clear(); packet.setPlayers(Arrays.asList(profile)); }else{ packet.setMotD("Haha"); packet.setPlayersMaximum(5342); packet.setPlayersOnline(5341); packet.setVersionProtocol(70); packet.setVersionName("HÖHÖ"); WrappedGameProfile profile = new WrappedGameProfile(UUID.randomUUID(), "Joo wahrscheinlich :p"); packet.getPlayers().clear(); packet.setPlayers(Arrays.asList(profile)); } flag = !flag; Log.severe("Packet to send is constructed!"); info.getServerPings().write(0, packet); Log.severe("Packet written"); MOTDPlus.ProtocolManager.sendServerPacket(p, info); Log.severe("Packet send to player, sleeping..."); Thread.sleep(1000); Log.severe("Woke up"); delay++; if(delay > 5){ Log.severe("Delay forced end!"); break; } } }catch(Exception e){ Log.severe("Error"); return; } }} 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 ). 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.
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.
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 @Overridepublic void onPacketSending(PacketEvent event) {if(event.getPacket().getType() == PacketType.Status.Server.OUT_PING){event.setCancelled(true);}event.setCancelled(true);if (event.getPacket().getType() == PacketType.Status.Server.OUT_SERVER_INFO) {new PingResponseThread(event.getPlayer(), event.getPacket().getServerPings().read(0), 300, pluginRef.getConfiguration().getPings()).start();}} Code:java originalResponce.setPlayersOnline(Bukkit.getOnlinePlayers().!size()!);//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 PacketContainer serverInfo = manager.createPacket(PacketType.Status.Server.OUT_SERVER_INFO); originalResponce.setPlayersOnline(Bukkit.getOnlinePlayers().size()); originalResponce.setMotD("Noob"); originalResponce.setVersionProtocol(70); originalResponce.setVersionName("Joo Wahrscheinlich"); originalResponce.setPlayersMaximum(2001); originalResponce.setPlayersOnline(2000); /*PingData toDisplay = pingDatas[currentPingToDisplay]; if (toDisplay.getImage() != null) { originalResponce.setFavicon(toDisplay.getImage()); } if (toDisplay.getMotd() != null) { originalResponce.setMotD(WrappedChatComponent.fromText(ChatColor.translateAlternateColorCodes('&', pingDatas[currentPingToDisplay].getMotd()))); } if (toDisplay.getPlayers() != null) { List<WrappedGameProfile> profiles = new ArrayList<WrappedGameProfile>(); for (String player : toDisplay.getPlayers()) { WrappedGameProfile profile = new WrappedGameProfile(randomUUID, ChatColor.translateAlternateColorCodes('&', player)); profiles.add(profile); } originalResponce.setPlayers(profiles); }*/ serverInfo.getServerPings().write(0, originalResponce); manager.sendServerPacket(player, serverInfo, false); currentPingToDisplay++; if (currentPingToDisplay >= pingDatas.length) { currentPingToDisplay = 0; } Thread.sleep(1000); Great information: I think it's working! Code:java private static final ProtocolManager manager = ProtocolLibrary.getProtocolManager(); public PingListener(final AnimatedPing pluginRef) { manager.addPacketListener( new PacketAdapter( PacketAdapter .params(pluginRef, PacketType.Status.Server.OUT_SERVER_INFO, PacketType.Status.Server.OUT_PING) .listenerPriority(ListenerPriority.HIGHEST) ) { @Override public void onPacketSending(PacketEvent e) { if(e.getPacket().getType() == PacketType.Status.Server.OUT_SERVER_INFO){ if(!e.getPacket().getServerPings().read(0).getVersionName().equals("Nudel1.0")){ d("Server info request got in, editing packet"); e.getPacket().getServerPings().read(0).setMotD("Yap"); e.getPacket().getServerPings().read(0).setPlayersVisible(true); e.getPacket().getServerPings().read(0).setVersionProtocol(69); e.getPacket().getServerPings().read(0).setVersionName("DM"); final Player p = e.getPlayer(); final PacketContainer packet = e.getPacket(); Bukkit.getScheduler().runTaskLater(pluginRef, new Runnable(){ @Override public void run(){ packet.getServerPings().read(0).setMotD("Haha"); packet.getServerPings().read(0).setVersionName("Nudel1.0"); packet.getServerPings().read(0).setPlayersOnline(5); try { manager.sendServerPacket(p, packet); } catch (InvocationTargetException e) { d("Error while sending second packet:"); e.printStackTrace(); } } }, 40L); } } if(e.getPacket().getType() == PacketType.Status.Server.OUT_PING){ d("Ping got in, cancelling"); e.setCancelled(true); } } } ); } public void d(String msg){ System.out.println(msg); } 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 At this point thanks to all who help solve this EDIT by Moderator: merged posts, please use the edit button instead of double posting.
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.
That 3rd arg in manager.sendServerPacket was there not for no reason. It bypasses protocollib filters.
Shevchik thanks again I haven't looked into protocollib for now, because i don't really like depending on another plugin.