forked from GeyserMC/Geyser
parent
cc2bbc675f
commit
8ac5d6e13d
8 changed files with 152 additions and 53 deletions
|
@ -60,14 +60,15 @@ public class GeyserBungeePingPassthrough implements IGeyserPingPassthrough, List
|
|||
else future.complete(event);
|
||||
}));
|
||||
ProxyPingEvent event = future.join();
|
||||
ServerPing response = event.getResponse();
|
||||
GeyserPingInfo geyserPingInfo = new GeyserPingInfo(
|
||||
event.getResponse().getDescription(),
|
||||
event.getResponse().getPlayers().getOnline(),
|
||||
event.getResponse().getPlayers().getMax()
|
||||
response.getDescriptionComponent().toLegacyText(),
|
||||
new GeyserPingInfo.Players(response.getPlayers().getMax(), response.getPlayers().getOnline()),
|
||||
new GeyserPingInfo.Version(response.getVersion().getName(), response.getVersion().getProtocol())
|
||||
);
|
||||
if (event.getResponse().getPlayers().getSample() != null) {
|
||||
Arrays.stream(event.getResponse().getPlayers().getSample()).forEach(proxiedPlayer -> {
|
||||
geyserPingInfo.addPlayer(proxiedPlayer.getName());
|
||||
geyserPingInfo.getPlayerList().add(proxiedPlayer.getName());
|
||||
});
|
||||
}
|
||||
return geyserPingInfo;
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
|
||||
package org.geysermc.platform.spigot;
|
||||
|
||||
import com.github.steveice10.mc.protocol.MinecraftConstants;
|
||||
import lombok.AllArgsConstructor;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.entity.Player;
|
||||
|
@ -48,14 +49,15 @@ public class GeyserSpigotPingPassthrough implements IGeyserPingPassthrough {
|
|||
try {
|
||||
ServerListPingEvent event = new GeyserPingEvent(InetAddress.getLocalHost(), Bukkit.getMotd(), Bukkit.getOnlinePlayers().size(), Bukkit.getMaxPlayers());
|
||||
Bukkit.getPluginManager().callEvent(event);
|
||||
GeyserPingInfo geyserPingInfo = new GeyserPingInfo(event.getMotd(), event.getNumPlayers(), event.getMaxPlayers());
|
||||
Bukkit.getOnlinePlayers().forEach(player -> {
|
||||
geyserPingInfo.addPlayer(player.getName());
|
||||
});
|
||||
GeyserPingInfo geyserPingInfo = new GeyserPingInfo(event.getMotd(),
|
||||
new GeyserPingInfo.Players(event.getMaxPlayers(), event.getNumPlayers()),
|
||||
new GeyserPingInfo.Version(Bukkit.getVersion(), MinecraftConstants.PROTOCOL_VERSION) // thanks Spigot for not exposing this, just default to latest
|
||||
);
|
||||
Bukkit.getOnlinePlayers().stream().map(Player::getName).forEach(geyserPingInfo.getPlayerList()::add);
|
||||
return geyserPingInfo;
|
||||
} catch (Exception e) {
|
||||
logger.debug("Error while getting Bukkit ping passthrough: " + e.toString());
|
||||
return new GeyserPingInfo(null, 0, 0);
|
||||
return new GeyserPingInfo(null, null, null);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
|
||||
package org.geysermc.platform.sponge;
|
||||
|
||||
import com.github.steveice10.mc.protocol.MinecraftConstants;
|
||||
import org.geysermc.connector.common.ping.GeyserPingInfo;
|
||||
import org.geysermc.connector.ping.IGeyserPingPassthrough;
|
||||
import org.spongepowered.api.MinecraftVersion;
|
||||
|
@ -35,6 +36,7 @@ import org.spongepowered.api.event.cause.Cause;
|
|||
import org.spongepowered.api.event.cause.EventContext;
|
||||
import org.spongepowered.api.event.server.ClientPingServerEvent;
|
||||
import org.spongepowered.api.network.status.StatusClient;
|
||||
import org.spongepowered.api.profile.GameProfile;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.Inet4Address;
|
||||
|
@ -68,11 +70,18 @@ public class GeyserSpongePingPassthrough implements IGeyserPingPassthrough {
|
|||
Sponge.getEventManager().post(event);
|
||||
GeyserPingInfo geyserPingInfo = new GeyserPingInfo(
|
||||
event.getResponse().getDescription().toPlain(),
|
||||
event.getResponse().getPlayers().orElseThrow(IllegalStateException::new).getOnline(),
|
||||
event.getResponse().getPlayers().orElseThrow(IllegalStateException::new).getMax());
|
||||
event.getResponse().getPlayers().get().getProfiles().forEach(player -> {
|
||||
geyserPingInfo.addPlayer(player.getName().orElseThrow(IllegalStateException::new));
|
||||
});
|
||||
new GeyserPingInfo.Players(
|
||||
event.getResponse().getPlayers().orElseThrow(IllegalStateException::new).getMax(),
|
||||
event.getResponse().getPlayers().orElseThrow(IllegalStateException::new).getOnline()
|
||||
),
|
||||
new GeyserPingInfo.Version(
|
||||
event.getResponse().getVersion().getName(),
|
||||
MinecraftConstants.PROTOCOL_VERSION) // thanks for also not exposing this sponge
|
||||
);
|
||||
event.getResponse().getPlayers().get().getProfiles().stream()
|
||||
.map(GameProfile::getName)
|
||||
.map(op -> op.orElseThrow(IllegalStateException::new))
|
||||
.forEach(geyserPingInfo.getPlayerList()::add);
|
||||
return geyserPingInfo;
|
||||
}
|
||||
|
||||
|
|
|
@ -59,13 +59,17 @@ public class GeyserVelocityPingPassthrough implements IGeyserPingPassthrough {
|
|||
throw new RuntimeException(e);
|
||||
}
|
||||
GeyserPingInfo geyserPingInfo = new GeyserPingInfo(
|
||||
LegacyComponentSerializer.INSTANCE.serialize(event.getPing().getDescription(), '§'),
|
||||
event.getPing().getPlayers().orElseThrow(IllegalStateException::new).getOnline(),
|
||||
event.getPing().getPlayers().orElseThrow(IllegalStateException::new).getMax()
|
||||
LegacyComponentSerializer.legacy().serialize(event.getPing().getDescription(), '§'),
|
||||
new GeyserPingInfo.Players(
|
||||
event.getPing().getPlayers().orElseThrow(IllegalStateException::new).getMax(),
|
||||
event.getPing().getPlayers().orElseThrow(IllegalStateException::new).getOnline()
|
||||
),
|
||||
new GeyserPingInfo.Version(
|
||||
event.getPing().getVersion().getName(),
|
||||
event.getPing().getVersion().getProtocol()
|
||||
)
|
||||
);
|
||||
event.getPing().getPlayers().get().getSample().forEach(player -> {
|
||||
geyserPingInfo.addPlayer(player.getName());
|
||||
});
|
||||
event.getPing().getPlayers().get().getSample().stream().map(ServerPing.SamplePlayer::getName).forEach(geyserPingInfo.getPlayerList()::add);
|
||||
return geyserPingInfo;
|
||||
}
|
||||
|
||||
|
|
|
@ -26,8 +26,11 @@
|
|||
|
||||
package org.geysermc.connector.common.ping;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
|
||||
import com.fasterxml.jackson.annotation.JsonSetter;
|
||||
import com.fasterxml.jackson.databind.JsonNode;
|
||||
import lombok.Data;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
|
@ -35,14 +38,56 @@ import java.util.Collection;
|
|||
@Data
|
||||
public class GeyserPingInfo {
|
||||
|
||||
public final String motd;
|
||||
public final int currentPlayerCount;
|
||||
public final int maxPlayerCount;
|
||||
private String description;
|
||||
|
||||
@Getter
|
||||
private Collection<String> players = new ArrayList<>();
|
||||
private Players players;
|
||||
private Version version;
|
||||
|
||||
public void addPlayer(String username) {
|
||||
players.add(username);
|
||||
@JsonIgnore
|
||||
private Collection<String> playerList = new ArrayList<>();
|
||||
|
||||
public GeyserPingInfo() {
|
||||
}
|
||||
|
||||
public GeyserPingInfo(String description, Players players, Version version) {
|
||||
this.description = description;
|
||||
this.players = players;
|
||||
this.version = version;
|
||||
}
|
||||
|
||||
@JsonSetter("description")
|
||||
void setDescription(JsonNode description) {
|
||||
this.description = description.toString();
|
||||
}
|
||||
|
||||
@Data
|
||||
@JsonIgnoreProperties(ignoreUnknown = true)
|
||||
public static class Players {
|
||||
|
||||
private int max;
|
||||
private int online;
|
||||
|
||||
public Players() {
|
||||
}
|
||||
|
||||
public Players(int max, int online) {
|
||||
this.max = max;
|
||||
this.online = online;
|
||||
}
|
||||
}
|
||||
|
||||
@Data
|
||||
public static class Version {
|
||||
|
||||
private String name;
|
||||
private int protocol;
|
||||
|
||||
public Version() {
|
||||
}
|
||||
|
||||
public Version(String name, int protocol) {
|
||||
this.name = name;
|
||||
this.protocol = protocol;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -74,8 +74,8 @@ public class ConnectorServerEventHandler implements BedrockServerEventHandler {
|
|||
pong.setVersion(null); // Server tries to connect either way and it looks better
|
||||
pong.setIpv4Port(config.getBedrock().getPort());
|
||||
|
||||
if (config.isPassthroughMotd() && pingInfo != null && pingInfo.motd != null) {
|
||||
String[] motd = MessageUtils.getBedrockMessage(MessageSerializer.fromString(pingInfo.motd)).split("\n");
|
||||
if (config.isPassthroughMotd() && pingInfo != null && pingInfo.getDescription() != null) {
|
||||
String[] motd = MessageUtils.getBedrockMessage(MessageSerializer.fromString(pingInfo.getDescription())).split("\n");
|
||||
String mainMotd = motd[0]; // First line of the motd.
|
||||
String subMotd = (motd.length != 1) ? motd[1] : ""; // Second line of the motd if present, otherwise blank.
|
||||
|
||||
|
@ -87,8 +87,8 @@ public class ConnectorServerEventHandler implements BedrockServerEventHandler {
|
|||
}
|
||||
|
||||
if (config.isPassthroughPlayerCounts() && pingInfo != null) {
|
||||
pong.setPlayerCount(pingInfo.currentPlayerCount);
|
||||
pong.setMaximumPlayerCount(pingInfo.maxPlayerCount);
|
||||
pong.setPlayerCount(pingInfo.getPlayers().getOnline());
|
||||
pong.setMaximumPlayerCount(pingInfo.getPlayers().getMax());
|
||||
} else {
|
||||
pong.setPlayerCount(connector.getPlayers().size());
|
||||
pong.setMaximumPlayerCount(config.getMaxPlayers());
|
||||
|
|
|
@ -148,7 +148,7 @@ public class QueryPacketHandler {
|
|||
}
|
||||
|
||||
if (connector.getConfig().isPassthroughMotd() && pingInfo != null) {
|
||||
String[] javaMotd = MessageUtils.getBedrockMessage(MessageSerializer.fromString(pingInfo.motd)).split("\n");
|
||||
String[] javaMotd = MessageUtils.getBedrockMessage(MessageSerializer.fromString(pingInfo.getDescription())).split("\n");
|
||||
motd = javaMotd[0].trim(); // First line of the motd.
|
||||
} else {
|
||||
motd = connector.getConfig().getBedrock().getMotd1();
|
||||
|
@ -156,8 +156,8 @@ public class QueryPacketHandler {
|
|||
|
||||
// If passthrough player counts is enabled lets get players from the server
|
||||
if (connector.getConfig().isPassthroughPlayerCounts() && pingInfo != null) {
|
||||
currentPlayerCount = String.valueOf(pingInfo.currentPlayerCount);
|
||||
maxPlayerCount = String.valueOf(pingInfo.maxPlayerCount);
|
||||
currentPlayerCount = String.valueOf(pingInfo.getPlayers().getOnline());
|
||||
maxPlayerCount = String.valueOf(pingInfo.getPlayers().getMax());
|
||||
} else {
|
||||
currentPlayerCount = String.valueOf(connector.getPlayers().size());
|
||||
maxPlayerCount = String.valueOf(connector.getConfig().getMaxPlayers());
|
||||
|
@ -220,7 +220,7 @@ public class QueryPacketHandler {
|
|||
|
||||
// Fill player names
|
||||
if(pingInfo != null) {
|
||||
for (String username : pingInfo.getPlayers()) {
|
||||
for (String username : pingInfo.getPlayerList()) {
|
||||
query.write(username.getBytes());
|
||||
query.write((byte) 0x00);
|
||||
}
|
||||
|
|
|
@ -26,16 +26,21 @@
|
|||
|
||||
package org.geysermc.connector.ping;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonParseException;
|
||||
import com.fasterxml.jackson.databind.JsonMappingException;
|
||||
import com.github.steveice10.mc.protocol.MinecraftConstants;
|
||||
import com.github.steveice10.mc.protocol.MinecraftProtocol;
|
||||
import com.github.steveice10.mc.protocol.data.SubProtocol;
|
||||
import com.github.steveice10.mc.protocol.data.message.TextMessage;
|
||||
import com.github.steveice10.mc.protocol.data.status.handler.ServerInfoHandler;
|
||||
import com.github.steveice10.packetlib.Client;
|
||||
import com.github.steveice10.packetlib.tcp.TcpSessionFactory;
|
||||
import com.nukkitx.nbt.util.VarInts;
|
||||
import org.geysermc.connector.common.ping.GeyserPingInfo;
|
||||
import org.geysermc.connector.GeyserConnector;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.net.ConnectException;
|
||||
import java.net.InetSocketAddress;
|
||||
import java.net.Socket;
|
||||
import java.net.SocketTimeoutException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
public class GeyserLegacyPingPassthrough implements IGeyserPingPassthrough, Runnable {
|
||||
|
@ -44,13 +49,10 @@ public class GeyserLegacyPingPassthrough implements IGeyserPingPassthrough, Runn
|
|||
|
||||
public GeyserLegacyPingPassthrough(GeyserConnector connector) {
|
||||
this.connector = connector;
|
||||
this.pingInfo = new GeyserPingInfo(null, 0, 0);
|
||||
}
|
||||
|
||||
private GeyserPingInfo pingInfo;
|
||||
|
||||
private Client client;
|
||||
|
||||
/**
|
||||
* Start legacy ping passthrough thread
|
||||
* @param connector GeyserConnector
|
||||
|
@ -76,15 +78,51 @@ public class GeyserLegacyPingPassthrough implements IGeyserPingPassthrough, Runn
|
|||
@Override
|
||||
public void run() {
|
||||
try {
|
||||
this.client = new Client(connector.getConfig().getRemote().getAddress(), connector.getConfig().getRemote().getPort(), new MinecraftProtocol(SubProtocol.STATUS), new TcpSessionFactory());
|
||||
this.client.getSession().setFlag(MinecraftConstants.SERVER_INFO_HANDLER_KEY, (ServerInfoHandler) (session, info) -> {
|
||||
this.pingInfo = new GeyserPingInfo(((TextMessage) info.getDescription()).getText(), info.getPlayerInfo().getOnlinePlayers(), info.getPlayerInfo().getMaxPlayers());
|
||||
this.client.getSession().disconnect(null);
|
||||
});
|
||||
Socket socket = new Socket();
|
||||
socket.connect(new InetSocketAddress(connector.getConfig().getRemote().getAddress(), connector.getConfig().getRemote().getPort()), 5000);
|
||||
|
||||
client.getSession().connect();
|
||||
} catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
ByteArrayOutputStream byteArrayStream = new ByteArrayOutputStream();
|
||||
DataOutputStream handshake = new DataOutputStream(byteArrayStream);
|
||||
handshake.write(0x0);
|
||||
VarInts.writeUnsignedInt(handshake, MinecraftConstants.PROTOCOL_VERSION);
|
||||
VarInts.writeUnsignedInt(handshake, socket.getInetAddress().getHostAddress().length());
|
||||
handshake.writeBytes(socket.getInetAddress().getHostAddress());
|
||||
handshake.writeShort(socket.getPort());
|
||||
VarInts.writeUnsignedInt(handshake, 1);
|
||||
|
||||
DataOutputStream dataOutputStream = new DataOutputStream(socket.getOutputStream());
|
||||
VarInts.writeUnsignedInt(dataOutputStream, byteArrayStream.size());
|
||||
dataOutputStream.write(byteArrayStream.toByteArray());
|
||||
dataOutputStream.writeByte(0x01);
|
||||
dataOutputStream.writeByte(0x00);
|
||||
|
||||
DataInputStream dataInputStream = new DataInputStream(socket.getInputStream());
|
||||
VarInts.readUnsignedInt(dataInputStream);
|
||||
VarInts.readUnsignedInt(dataInputStream);
|
||||
int length = VarInts.readUnsignedInt(dataInputStream);
|
||||
byte[] buffer = new byte[length];
|
||||
dataInputStream.readFully(buffer);
|
||||
dataOutputStream.writeByte(0x09);
|
||||
dataOutputStream.writeByte(0x01);
|
||||
dataOutputStream.writeLong(System.currentTimeMillis());
|
||||
|
||||
VarInts.readUnsignedInt(dataInputStream);
|
||||
String json = new String(buffer);
|
||||
|
||||
this.pingInfo = GeyserConnector.JSON_MAPPER.readValue(json, GeyserPingInfo.class);
|
||||
|
||||
byteArrayStream.close();
|
||||
handshake.close();
|
||||
dataOutputStream.close();
|
||||
dataInputStream.close();
|
||||
socket.close();
|
||||
} catch (SocketTimeoutException | ConnectException ex) {
|
||||
this.pingInfo = null;
|
||||
this.connector.getLogger().debug("Connection timeout for ping passthrough.");
|
||||
} catch (JsonParseException | JsonMappingException ex) {
|
||||
this.connector.getLogger().error("Failed to parse json when pinging server!", ex);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue