StatusPingEvent, support Legacy Ping

This commit is contained in:
LOOHP 2020-08-08 19:15:37 +08:00
parent e6005abc5a
commit 9c760b88ce
4 changed files with 159 additions and 17 deletions

View File

@ -49,6 +49,7 @@
</configuration>
</plugin>
</plugins>
<finalName>${project.artifactId}</finalName>
</build>
<repositories>
@ -64,6 +65,11 @@
<artifactId>NBT</artifactId>
<version>5.5</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.5</version>
</dependency>
<dependency>
<groupId>org.yaml</groupId>
<artifactId>snakeyaml</artifactId>

View File

@ -0,0 +1,81 @@
package com.loohp.limbo.Events;
import java.awt.image.BufferedImage;
import com.loohp.limbo.Server.ClientConnection;
import net.md_5.bungee.api.chat.BaseComponent;
public class StatusPingEvent extends Event {
private ClientConnection connection;
private String version;
private int protocol;
private BaseComponent[] motd;
private int maxPlayers;
private int playersOnline;
private BufferedImage favicon;
public StatusPingEvent(ClientConnection connection, String version, int protocol, BaseComponent[] motd, int maxPlayers, int playersOnline, BufferedImage favicon) {
this.connection = connection;
this.version = version;
this.protocol = protocol;
this.motd = motd;
this.maxPlayers = maxPlayers;
this.playersOnline = playersOnline;
this.favicon = favicon;
}
public ClientConnection getConnection() {
return connection;
}
public String getVersion() {
return version;
}
public void setVersion(String version) {
this.version = version;
}
public int getProtocol() {
return protocol;
}
public void setProtocol(int protocol) {
this.protocol = protocol;
}
public BaseComponent[] getMotd() {
return motd;
}
public void setMotd(BaseComponent[] motd) {
this.motd = motd;
}
public int getMaxPlayers() {
return maxPlayers;
}
public void setMaxPlayers(int maxPlayers) {
this.maxPlayers = maxPlayers;
}
public int getPlayersOnline() {
return playersOnline;
}
public void setPlayersOnline(int playersOnline) {
this.playersOnline = playersOnline;
}
public BufferedImage getFavicon() {
return favicon;
}
public void setFavicon(BufferedImage favicon) {
this.favicon = favicon;
}
}

View File

@ -1,6 +1,7 @@
package com.loohp.limbo;
import java.awt.GraphicsEnvironment;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileReader;
@ -11,19 +12,25 @@ import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel;
import java.nio.file.Files;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.loohp.limbo.Commands.CommandSender;
import com.loohp.limbo.Events.EventsManager;
import com.loohp.limbo.File.ServerProperties;
@ -44,6 +51,8 @@ import com.loohp.limbo.World.Schematic;
import com.loohp.limbo.World.World;
import com.loohp.limbo.World.World.Environment;
import net.md_5.bungee.api.chat.BaseComponent;
import net.md_5.bungee.chat.ComponentSerializer;
import net.querz.nbt.io.NBTUtil;
import net.querz.nbt.tag.CompoundTag;
@ -340,22 +349,48 @@ public class Limbo {
return null;
}
public String getServerListResponseJson() throws IOException {
String base = ServerProperties.JSON_BASE_RESPONSE;
base = base.replace("%VERSION%", properties.getVersionString());
base = base.replace("%PROTOCOL%", String.valueOf(properties.getProtocol()));
base = base.replace("%MOTD%", properties.getMotdJson());
base = base.replace("%MAXPLAYERS%", String.valueOf(properties.getMaxPlayers()));
base = base.replace("%ONLINECLIENTS%", String.valueOf(getPlayers().size()));
@SuppressWarnings("unchecked")
public String buildServerListResponseJson(String version, int protocol, BaseComponent[] motd, int maxPlayers, int playersOnline, BufferedImage favicon) throws IOException {
JSONObject json = new JSONObject();
JSONObject versionJson = new JSONObject();
versionJson.put("name", version);
versionJson.put("protocol", protocol);
json.put("version", versionJson);
if (properties.getFavicon().isPresent()) {
String icon = "\"favicon\":\"data:image/png;base64," + ImageUtils.imgToBase64String(properties.getFavicon().get(), "png") + "\",";
base = base.replace("%FAVICON%", icon);
} else {
base = base.replace("%FAVICON%", "");
JSONObject playersJson = new JSONObject();
playersJson.put("max", maxPlayers);
playersJson.put("online", playersOnline);
json.put("players", playersJson);
json.put("description", "%MOTD%");
if (favicon != null) {
if (favicon.getWidth() == 64 && favicon.getHeight() == 64) {
String base64 = "data:image/png;base64," + ImageUtils.imgToBase64String(favicon, "png");
json.put("favicon", base64);
} else {
console.sendMessage("Server List Favicon must be 64 x 64 in size!");
}
}
return base;
JSONObject modInfoJson = new JSONObject();
modInfoJson.put("type", "FML");
modInfoJson.put("modList", new JSONArray());
json.put("modinfo", modInfoJson);
TreeMap<String, Object> treeMap = new TreeMap<String, Object>(String.CASE_INSENSITIVE_ORDER);
treeMap.putAll(json);
Gson g = new GsonBuilder().create();
return g.toJson(treeMap).replace("\"%MOTD%\"", ComponentSerializer.toString(motd));
}
public String buildLegacyPingResponse(String version, BaseComponent[] motd, int maxPlayers, int playersOnline) {
String begin = "§1";
return String.join("\00", begin, "127", version, String.join("", Arrays.asList(motd).stream().map(each -> each.toLegacyText()).collect(Collectors.toList())), String.valueOf(playersOnline), String.valueOf(maxPlayers));
}
public void stopServer() {

View File

@ -18,6 +18,7 @@ import com.loohp.limbo.Limbo;
import com.loohp.limbo.Events.PlayerJoinEvent;
import com.loohp.limbo.Events.PlayerLoginEvent;
import com.loohp.limbo.Events.PlayerQuitEvent;
import com.loohp.limbo.Events.StatusPingEvent;
import com.loohp.limbo.File.ServerProperties;
import com.loohp.limbo.Location.Location;
import com.loohp.limbo.Player.Player;
@ -71,6 +72,7 @@ import net.querz.mca.Chunk;
public class ClientConnection extends Thread {
public enum ClientState {
LEGACY,
HANDSHAKE,
STATUS,
LOGIN,
@ -164,10 +166,26 @@ public class ClientConnection extends Thread {
client_socket.setKeepAlive(true);
input = new DataInputStream(client_socket.getInputStream());
output = new DataOutputStream(client_socket.getOutputStream());
DataTypeIO.readVarInt(input);
int handShakeSize = DataTypeIO.readVarInt(input);
//legacy ping
if (handShakeSize == 0xFE) {
state = ClientState.LEGACY;
output.writeByte(255);
ServerProperties p = Limbo.getInstance().getServerProperties();
StatusPingEvent event = (StatusPingEvent) Limbo.getInstance().getEventsManager().callEvent(new StatusPingEvent(this, p.getVersionString(), p.getProtocol(), ComponentSerializer.parse(p.getMotdJson()), p.getMaxPlayers(), Limbo.getInstance().getPlayers().size(), p.getFavicon().orElse(null)));
String response = Limbo.getInstance().buildLegacyPingResponse(event.getVersion(), event.getMotd(), event.getMaxPlayers(), event.getPlayersOnline());
System.out.println(response);
byte[] bytes = response.getBytes(StandardCharsets.UTF_16BE);
output.writeShort(response.length());
output.write(bytes);
client_socket.close();
state = ClientState.DISCONNECTED;
}
//int handShakeId = DataTypeIO.readVarInt(input);
DataTypeIO.readVarInt(input);
@SuppressWarnings("unused")
int handShakeId = DataTypeIO.readVarInt(input);
PacketHandshakingIn handshake = new PacketHandshakingIn(input);
@ -188,7 +206,9 @@ public class ClientConnection extends Thread {
} else if (packetType.equals(PacketStatusInRequest.class)) {
String str = client_socket.getInetAddress().getHostName() + ":" + client_socket.getPort();
Limbo.getInstance().getConsole().sendMessage("[/" + str + "] <-> Handshake Status has pinged");
PacketStatusOutResponse packet = new PacketStatusOutResponse(Limbo.getInstance().getServerListResponseJson());
ServerProperties p = Limbo.getInstance().getServerProperties();
StatusPingEvent event = (StatusPingEvent) Limbo.getInstance().getEventsManager().callEvent(new StatusPingEvent(this, p.getVersionString(), p.getProtocol(), ComponentSerializer.parse(p.getMotdJson()), p.getMaxPlayers(), Limbo.getInstance().getPlayers().size(), p.getFavicon().orElse(null)));
PacketStatusOutResponse packet = new PacketStatusOutResponse(Limbo.getInstance().buildServerListResponseJson(event.getVersion(), event.getProtocol(), event.getMotd(), event.getMaxPlayers(), event.getPlayersOnline(), event.getFavicon()));
sendPacket(packet);
} else if (packetType.equals(PacketStatusInPing.class)) {
PacketStatusInPing ping = new PacketStatusInPing(input);