package crtest; import java.lang.reflect.Type; import java.net.InetAddress; import java.util.UUID; import java.lang.reflect.Field; import java.lang.reflect.Modifier; import org.bukkit.Bukkit; import org.bukkit.ChatColor; import org.bukkit.event.Cancellable; import org.bukkit.event.Event; import org.bukkit.event.HandlerList; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonSerializationContext; import com.mojang.authlib.GameProfile; import net.minecraft.server.v1_13_R1.ChatModifier; import net.minecraft.server.v1_13_R1.ChatTypeAdapterFactory; import net.minecraft.server.v1_13_R1.IChatBaseComponent; import net.minecraft.server.v1_13_R1.IChatBaseComponent.ChatSerializer; import net.minecraft.server.v1_13_R1.PacketStatusOutServerInfo; import net.minecraft.server.v1_13_R1.ServerPing; import net.minecraft.server.v1_13_R1.ServerPing.ServerData; import net.minecraft.server.v1_13_R1.ServerPing.ServerPingPlayerSample; public class PingListener{ private static Gson a; { a = new GsonBuilder().registerTypeAdapter(ServerPing.ServerData.class, new OverridenServerDataSerializer()) .registerTypeAdapter(ServerPing.ServerPingPlayerSample.class, new OverridenServerSampleSerializer()) .registerTypeAdapter(ServerPing.class, new PingSerializer()) .registerTypeHierarchyAdapter(IChatBaseComponent.class, new IChatBaseComponent.ChatSerializer()) .registerTypeHierarchyAdapter(ChatModifier.class, new ChatModifier.ChatModifierSerializer()) .registerTypeAdapterFactory(new ChatTypeAdapterFactory()).create(); } private static InetAddress address; @SuppressWarnings("static-access") public PingListener(InetAddress address){ this.address = address; ReflectedObject.setStaticField(PacketStatusOutServerInfo.class, "a", a); } public static class PingSerializer extends ServerPing.Serializer{ @Override public JsonElement a(ServerPing serverPing, Type type, JsonSerializationContext jsonSerializationContext) { if(a == null) { return super.a(serverPing, type, jsonSerializationContext); } a = null; ServerPingEvent ev = new ServerPingEvent(address, serverPing.a().getText(), serverPing.b().c(), serverPing.getServerData().a(), serverPing.d()); Bukkit.getServer().getPluginManager().callEvent(ev); ReflectedObject ping = new ReflectedObject(serverPing); ReflectedObject playerSample = ping.get("b"); ReflectedObject serverData = ping.get("c"); if(ev.isCancelled()) return null; serverPing.setMOTD(getMOTD(ev.getMotdLine1(), ev.getMotdLine2())); playerSample.setField("c", getHover(ev.getHover())); serverData.setField("b",1); serverData.setField("a", color(ev.getVersion())); serverPing.setFavicon(ev.getPath()); return super.a(serverPing, type, jsonSerializationContext); } } public static String color(String str) { return ChatColor.translateAlternateColorCodes('&', str); } public static IChatBaseComponent getMOTD(String st, String nd) { if(nd != null && st != null) { return ChatSerializer.a("{\"text\": \"" + color(st + "\n" + nd) + "\"}"); } else if(st != null) { return ChatSerializer.a("{\"text\": \"" + color(st) + "\"}"); } else if(nd != null) { return ChatSerializer.a("{\"text\": \"" + color(nd) + "\"}"); } return ChatSerializer.a("{\"text\": \"\"}"); } public static GameProfile[] getHover(String[] changes) { if(changes == null || changes.length == 0) return new GameProfile[] {new GameProfile(new UUID(0, 0), "")}; GameProfile[] gameProfiles = new GameProfile[changes.length]; for(int i = 0; i < changes.length;) { if(changes[i] == null) { gameProfiles[i] = new GameProfile(new UUID(0, 0), ""); } else { gameProfiles[i] = new GameProfile(new UUID(0, 0), color(changes[i])); } i++; if(i >= 128) break; } return gameProfiles; } public static class OverridenServerDataSerializer extends ServerPing.ServerData.Serializer{ @Override public JsonElement a(ServerData serverData, Type type, JsonSerializationContext jsonSerializationContext) { return super.a(serverData, type, jsonSerializationContext); } } public static class OverridenServerSampleSerializer extends ServerPing.ServerPingPlayerSample.Serializer { @Override public JsonElement a(ServerPingPlayerSample serverPingPlayerSample, Type type, JsonSerializationContext jsonSerializationContext) { JsonObject jsonObject = (JsonObject) super.a(serverPingPlayerSample, type, jsonSerializationContext); return jsonObject; } } public static class ReflectedObject { private Object o; public ReflectedObject(Object o){ this.o = o; } public void setField(String field, Object o){ Field f = null; try{ f = this.getField(field); } catch(NoSuchFieldException e){ e.printStackTrace(); } catch(SecurityException e){ e.printStackTrace(); } if(f == null){ return; } f.setAccessible(true); try { f.set(this.o, o); } catch (IllegalArgumentException | IllegalAccessException e) { e.printStackTrace(); } } public ReflectedObject get(String field){ Field f = null; try{ f = this.getField(field); } catch(NoSuchFieldException e){ return null; } catch(SecurityException e){ e.printStackTrace(); } f.setAccessible(true); try { return new ReflectedObject(f.get(this.o)); } catch (IllegalArgumentException | IllegalAccessException e) { e.printStackTrace(); } return null; } private Field getField(String field) throws NoSuchFieldException, SecurityException{ return o.getClass().getDeclaredField(field); } public static void setStaticField(Class c, String name, Object set){ Field f = null; try{ f = c.getDeclaredField(name); } catch(NoSuchFieldException e){ e.printStackTrace(); } catch(SecurityException e){ e.printStackTrace(); } if(f == null){ throw new IllegalArgumentException("Error while getting the field '" + name + "'"); } f.setAccessible(true); try{ Field modifiersField = Field.class.getDeclaredField("modifiers"); modifiersField.setAccessible(true); modifiersField.setInt(f, modifiersField.getInt(f) - Modifier.FINAL); } catch(SecurityException e){ System.out.println("A security manager may be preventing you from setting this field."); e.printStackTrace(); } catch(IllegalAccessException | IllegalArgumentException | NoSuchFieldException e){ e.printStackTrace(); } try { f.set(null, set); } catch (IllegalArgumentException | IllegalAccessException e) { e.printStackTrace(); } } } public static class ServerPingEvent extends Event implements Cancellable{ private InetAddress address; private String motdline1; private String motdline2 = ""; private String[] hover; private String version; private String path; private boolean cancel = false; public ServerPingEvent(InetAddress address, String motd, GameProfile[] hover, String ver, String path) { this.address = address; final String[] lines = motd.split("\\n"); this.motdline1 = lines[0]; if(lines.length > 1) this.motdline2 = lines[1]; this.hover = new String[hover.length]; int i = 0; for(GameProfile gp : hover) { this.hover[i] = gp.getName(); i++; } this.version = ver; this.path = path; } public InetAddress getAddress() {return this.address;} public void setAddress(InetAddress a) {this.address = a;} public String getMotdLine1() {return this.motdline1;} public void setMotdLine1(String s) {this.motdline1 = s;} public String getMotdLine2() {return this.motdline2;} public void setMotdLine2(String s) {this.motdline2 = s;} public String[] getHover() {return this.hover;} public void setHover(String[] h) {this.hover = h;} public String getVersion() {return this.version;} public void setVersion(String v) {this.version = v;} public String getPath() {return this.path;} public void setPath(String p) {this.path = p;} private static final HandlerList handlers = new HandlerList(); public HandlerList getHandlers() { return handlers; } public static HandlerList getHandlerList() { return handlers; } @Override public boolean isCancelled() { return this.cancel; } @Override public void setCancelled(boolean b) { this.cancel = b; } } }