forked from BLOCKFANTASY/LOOHP-Limbo
StatusPingEvent, support Legacy Ping
This commit is contained in:
parent
e6005abc5a
commit
9c760b88ce
6
pom.xml
6
pom.xml
|
|
@ -49,6 +49,7 @@
|
||||||
</configuration>
|
</configuration>
|
||||||
</plugin>
|
</plugin>
|
||||||
</plugins>
|
</plugins>
|
||||||
|
<finalName>${project.artifactId}</finalName>
|
||||||
</build>
|
</build>
|
||||||
|
|
||||||
<repositories>
|
<repositories>
|
||||||
|
|
@ -64,6 +65,11 @@
|
||||||
<artifactId>NBT</artifactId>
|
<artifactId>NBT</artifactId>
|
||||||
<version>5.5</version>
|
<version>5.5</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.google.code.gson</groupId>
|
||||||
|
<artifactId>gson</artifactId>
|
||||||
|
<version>2.8.5</version>
|
||||||
|
</dependency>
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>org.yaml</groupId>
|
<groupId>org.yaml</groupId>
|
||||||
<artifactId>snakeyaml</artifactId>
|
<artifactId>snakeyaml</artifactId>
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
package com.loohp.limbo;
|
package com.loohp.limbo;
|
||||||
|
|
||||||
import java.awt.GraphicsEnvironment;
|
import java.awt.GraphicsEnvironment;
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
import java.io.FileReader;
|
import java.io.FileReader;
|
||||||
|
|
@ -11,19 +12,25 @@ import java.nio.channels.Channels;
|
||||||
import java.nio.channels.ReadableByteChannel;
|
import java.nio.channels.ReadableByteChannel;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.TreeMap;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
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.JSONObject;
|
||||||
import org.json.simple.parser.JSONParser;
|
import org.json.simple.parser.JSONParser;
|
||||||
import org.json.simple.parser.ParseException;
|
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.Commands.CommandSender;
|
||||||
import com.loohp.limbo.Events.EventsManager;
|
import com.loohp.limbo.Events.EventsManager;
|
||||||
import com.loohp.limbo.File.ServerProperties;
|
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;
|
||||||
import com.loohp.limbo.World.World.Environment;
|
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.io.NBTUtil;
|
||||||
import net.querz.nbt.tag.CompoundTag;
|
import net.querz.nbt.tag.CompoundTag;
|
||||||
|
|
||||||
|
|
@ -340,22 +349,48 @@ public class Limbo {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getServerListResponseJson() throws IOException {
|
@SuppressWarnings("unchecked")
|
||||||
String base = ServerProperties.JSON_BASE_RESPONSE;
|
public String buildServerListResponseJson(String version, int protocol, BaseComponent[] motd, int maxPlayers, int playersOnline, BufferedImage favicon) throws IOException {
|
||||||
base = base.replace("%VERSION%", properties.getVersionString());
|
JSONObject json = new JSONObject();
|
||||||
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()));
|
|
||||||
|
|
||||||
if (properties.getFavicon().isPresent()) {
|
JSONObject versionJson = new JSONObject();
|
||||||
String icon = "\"favicon\":\"data:image/png;base64," + ImageUtils.imgToBase64String(properties.getFavicon().get(), "png") + "\",";
|
versionJson.put("name", version);
|
||||||
base = base.replace("%FAVICON%", icon);
|
versionJson.put("protocol", protocol);
|
||||||
|
json.put("version", versionJson);
|
||||||
|
|
||||||
|
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 {
|
} else {
|
||||||
base = base.replace("%FAVICON%", "");
|
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() {
|
public void stopServer() {
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@ import com.loohp.limbo.Limbo;
|
||||||
import com.loohp.limbo.Events.PlayerJoinEvent;
|
import com.loohp.limbo.Events.PlayerJoinEvent;
|
||||||
import com.loohp.limbo.Events.PlayerLoginEvent;
|
import com.loohp.limbo.Events.PlayerLoginEvent;
|
||||||
import com.loohp.limbo.Events.PlayerQuitEvent;
|
import com.loohp.limbo.Events.PlayerQuitEvent;
|
||||||
|
import com.loohp.limbo.Events.StatusPingEvent;
|
||||||
import com.loohp.limbo.File.ServerProperties;
|
import com.loohp.limbo.File.ServerProperties;
|
||||||
import com.loohp.limbo.Location.Location;
|
import com.loohp.limbo.Location.Location;
|
||||||
import com.loohp.limbo.Player.Player;
|
import com.loohp.limbo.Player.Player;
|
||||||
|
|
@ -71,6 +72,7 @@ import net.querz.mca.Chunk;
|
||||||
public class ClientConnection extends Thread {
|
public class ClientConnection extends Thread {
|
||||||
|
|
||||||
public enum ClientState {
|
public enum ClientState {
|
||||||
|
LEGACY,
|
||||||
HANDSHAKE,
|
HANDSHAKE,
|
||||||
STATUS,
|
STATUS,
|
||||||
LOGIN,
|
LOGIN,
|
||||||
|
|
@ -164,10 +166,26 @@ public class ClientConnection extends Thread {
|
||||||
client_socket.setKeepAlive(true);
|
client_socket.setKeepAlive(true);
|
||||||
input = new DataInputStream(client_socket.getInputStream());
|
input = new DataInputStream(client_socket.getInputStream());
|
||||||
output = new DataOutputStream(client_socket.getOutputStream());
|
output = new DataOutputStream(client_socket.getOutputStream());
|
||||||
DataTypeIO.readVarInt(input);
|
int handShakeSize = DataTypeIO.readVarInt(input);
|
||||||
|
|
||||||
//int handShakeId = DataTypeIO.readVarInt(input);
|
//legacy ping
|
||||||
DataTypeIO.readVarInt(input);
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
int handShakeId = DataTypeIO.readVarInt(input);
|
||||||
|
|
||||||
PacketHandshakingIn handshake = new PacketHandshakingIn(input);
|
PacketHandshakingIn handshake = new PacketHandshakingIn(input);
|
||||||
|
|
||||||
|
|
@ -188,7 +206,9 @@ public class ClientConnection extends Thread {
|
||||||
} else if (packetType.equals(PacketStatusInRequest.class)) {
|
} else if (packetType.equals(PacketStatusInRequest.class)) {
|
||||||
String str = client_socket.getInetAddress().getHostName() + ":" + client_socket.getPort();
|
String str = client_socket.getInetAddress().getHostName() + ":" + client_socket.getPort();
|
||||||
Limbo.getInstance().getConsole().sendMessage("[/" + str + "] <-> Handshake Status has pinged");
|
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);
|
sendPacket(packet);
|
||||||
} else if (packetType.equals(PacketStatusInPing.class)) {
|
} else if (packetType.equals(PacketStatusInPing.class)) {
|
||||||
PacketStatusInPing ping = new PacketStatusInPing(input);
|
PacketStatusInPing ping = new PacketStatusInPing(input);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue