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);
|
else future.complete(event);
|
||||||
}));
|
}));
|
||||||
ProxyPingEvent event = future.join();
|
ProxyPingEvent event = future.join();
|
||||||
|
ServerPing response = event.getResponse();
|
||||||
GeyserPingInfo geyserPingInfo = new GeyserPingInfo(
|
GeyserPingInfo geyserPingInfo = new GeyserPingInfo(
|
||||||
event.getResponse().getDescription(),
|
response.getDescriptionComponent().toLegacyText(),
|
||||||
event.getResponse().getPlayers().getOnline(),
|
new GeyserPingInfo.Players(response.getPlayers().getMax(), response.getPlayers().getOnline()),
|
||||||
event.getResponse().getPlayers().getMax()
|
new GeyserPingInfo.Version(response.getVersion().getName(), response.getVersion().getProtocol())
|
||||||
);
|
);
|
||||||
if (event.getResponse().getPlayers().getSample() != null) {
|
if (event.getResponse().getPlayers().getSample() != null) {
|
||||||
Arrays.stream(event.getResponse().getPlayers().getSample()).forEach(proxiedPlayer -> {
|
Arrays.stream(event.getResponse().getPlayers().getSample()).forEach(proxiedPlayer -> {
|
||||||
geyserPingInfo.addPlayer(proxiedPlayer.getName());
|
geyserPingInfo.getPlayerList().add(proxiedPlayer.getName());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return geyserPingInfo;
|
return geyserPingInfo;
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
|
|
||||||
package org.geysermc.platform.spigot;
|
package org.geysermc.platform.spigot;
|
||||||
|
|
||||||
|
import com.github.steveice10.mc.protocol.MinecraftConstants;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import org.bukkit.Bukkit;
|
import org.bukkit.Bukkit;
|
||||||
import org.bukkit.entity.Player;
|
import org.bukkit.entity.Player;
|
||||||
|
@ -48,14 +49,15 @@ public class GeyserSpigotPingPassthrough implements IGeyserPingPassthrough {
|
||||||
try {
|
try {
|
||||||
ServerListPingEvent event = new GeyserPingEvent(InetAddress.getLocalHost(), Bukkit.getMotd(), Bukkit.getOnlinePlayers().size(), Bukkit.getMaxPlayers());
|
ServerListPingEvent event = new GeyserPingEvent(InetAddress.getLocalHost(), Bukkit.getMotd(), Bukkit.getOnlinePlayers().size(), Bukkit.getMaxPlayers());
|
||||||
Bukkit.getPluginManager().callEvent(event);
|
Bukkit.getPluginManager().callEvent(event);
|
||||||
GeyserPingInfo geyserPingInfo = new GeyserPingInfo(event.getMotd(), event.getNumPlayers(), event.getMaxPlayers());
|
GeyserPingInfo geyserPingInfo = new GeyserPingInfo(event.getMotd(),
|
||||||
Bukkit.getOnlinePlayers().forEach(player -> {
|
new GeyserPingInfo.Players(event.getMaxPlayers(), event.getNumPlayers()),
|
||||||
geyserPingInfo.addPlayer(player.getName());
|
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;
|
return geyserPingInfo;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
logger.debug("Error while getting Bukkit ping passthrough: " + e.toString());
|
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;
|
package org.geysermc.platform.sponge;
|
||||||
|
|
||||||
|
import com.github.steveice10.mc.protocol.MinecraftConstants;
|
||||||
import org.geysermc.connector.common.ping.GeyserPingInfo;
|
import org.geysermc.connector.common.ping.GeyserPingInfo;
|
||||||
import org.geysermc.connector.ping.IGeyserPingPassthrough;
|
import org.geysermc.connector.ping.IGeyserPingPassthrough;
|
||||||
import org.spongepowered.api.MinecraftVersion;
|
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.cause.EventContext;
|
||||||
import org.spongepowered.api.event.server.ClientPingServerEvent;
|
import org.spongepowered.api.event.server.ClientPingServerEvent;
|
||||||
import org.spongepowered.api.network.status.StatusClient;
|
import org.spongepowered.api.network.status.StatusClient;
|
||||||
|
import org.spongepowered.api.profile.GameProfile;
|
||||||
|
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.net.Inet4Address;
|
import java.net.Inet4Address;
|
||||||
|
@ -68,11 +70,18 @@ public class GeyserSpongePingPassthrough implements IGeyserPingPassthrough {
|
||||||
Sponge.getEventManager().post(event);
|
Sponge.getEventManager().post(event);
|
||||||
GeyserPingInfo geyserPingInfo = new GeyserPingInfo(
|
GeyserPingInfo geyserPingInfo = new GeyserPingInfo(
|
||||||
event.getResponse().getDescription().toPlain(),
|
event.getResponse().getDescription().toPlain(),
|
||||||
event.getResponse().getPlayers().orElseThrow(IllegalStateException::new).getOnline(),
|
new GeyserPingInfo.Players(
|
||||||
event.getResponse().getPlayers().orElseThrow(IllegalStateException::new).getMax());
|
event.getResponse().getPlayers().orElseThrow(IllegalStateException::new).getMax(),
|
||||||
event.getResponse().getPlayers().get().getProfiles().forEach(player -> {
|
event.getResponse().getPlayers().orElseThrow(IllegalStateException::new).getOnline()
|
||||||
geyserPingInfo.addPlayer(player.getName().orElseThrow(IllegalStateException::new));
|
),
|
||||||
});
|
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;
|
return geyserPingInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -59,13 +59,17 @@ public class GeyserVelocityPingPassthrough implements IGeyserPingPassthrough {
|
||||||
throw new RuntimeException(e);
|
throw new RuntimeException(e);
|
||||||
}
|
}
|
||||||
GeyserPingInfo geyserPingInfo = new GeyserPingInfo(
|
GeyserPingInfo geyserPingInfo = new GeyserPingInfo(
|
||||||
LegacyComponentSerializer.INSTANCE.serialize(event.getPing().getDescription(), '§'),
|
LegacyComponentSerializer.legacy().serialize(event.getPing().getDescription(), '§'),
|
||||||
event.getPing().getPlayers().orElseThrow(IllegalStateException::new).getOnline(),
|
new GeyserPingInfo.Players(
|
||||||
event.getPing().getPlayers().orElseThrow(IllegalStateException::new).getMax()
|
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 -> {
|
event.getPing().getPlayers().get().getSample().stream().map(ServerPing.SamplePlayer::getName).forEach(geyserPingInfo.getPlayerList()::add);
|
||||||
geyserPingInfo.addPlayer(player.getName());
|
|
||||||
});
|
|
||||||
return geyserPingInfo;
|
return geyserPingInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -26,8 +26,11 @@
|
||||||
|
|
||||||
package org.geysermc.connector.common.ping;
|
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.Data;
|
||||||
import lombok.Getter;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
@ -35,14 +38,56 @@ import java.util.Collection;
|
||||||
@Data
|
@Data
|
||||||
public class GeyserPingInfo {
|
public class GeyserPingInfo {
|
||||||
|
|
||||||
public final String motd;
|
private String description;
|
||||||
public final int currentPlayerCount;
|
|
||||||
public final int maxPlayerCount;
|
|
||||||
|
|
||||||
@Getter
|
private Players players;
|
||||||
private Collection<String> players = new ArrayList<>();
|
private Version version;
|
||||||
|
|
||||||
public void addPlayer(String username) {
|
@JsonIgnore
|
||||||
players.add(username);
|
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.setVersion(null); // Server tries to connect either way and it looks better
|
||||||
pong.setIpv4Port(config.getBedrock().getPort());
|
pong.setIpv4Port(config.getBedrock().getPort());
|
||||||
|
|
||||||
if (config.isPassthroughMotd() && pingInfo != null && pingInfo.motd != null) {
|
if (config.isPassthroughMotd() && pingInfo != null && pingInfo.getDescription() != null) {
|
||||||
String[] motd = MessageUtils.getBedrockMessage(MessageSerializer.fromString(pingInfo.motd)).split("\n");
|
String[] motd = MessageUtils.getBedrockMessage(MessageSerializer.fromString(pingInfo.getDescription())).split("\n");
|
||||||
String mainMotd = motd[0]; // First line of the motd.
|
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.
|
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) {
|
if (config.isPassthroughPlayerCounts() && pingInfo != null) {
|
||||||
pong.setPlayerCount(pingInfo.currentPlayerCount);
|
pong.setPlayerCount(pingInfo.getPlayers().getOnline());
|
||||||
pong.setMaximumPlayerCount(pingInfo.maxPlayerCount);
|
pong.setMaximumPlayerCount(pingInfo.getPlayers().getMax());
|
||||||
} else {
|
} else {
|
||||||
pong.setPlayerCount(connector.getPlayers().size());
|
pong.setPlayerCount(connector.getPlayers().size());
|
||||||
pong.setMaximumPlayerCount(config.getMaxPlayers());
|
pong.setMaximumPlayerCount(config.getMaxPlayers());
|
||||||
|
|
|
@ -148,7 +148,7 @@ public class QueryPacketHandler {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (connector.getConfig().isPassthroughMotd() && pingInfo != null) {
|
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.
|
motd = javaMotd[0].trim(); // First line of the motd.
|
||||||
} else {
|
} else {
|
||||||
motd = connector.getConfig().getBedrock().getMotd1();
|
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 passthrough player counts is enabled lets get players from the server
|
||||||
if (connector.getConfig().isPassthroughPlayerCounts() && pingInfo != null) {
|
if (connector.getConfig().isPassthroughPlayerCounts() && pingInfo != null) {
|
||||||
currentPlayerCount = String.valueOf(pingInfo.currentPlayerCount);
|
currentPlayerCount = String.valueOf(pingInfo.getPlayers().getOnline());
|
||||||
maxPlayerCount = String.valueOf(pingInfo.maxPlayerCount);
|
maxPlayerCount = String.valueOf(pingInfo.getPlayers().getMax());
|
||||||
} else {
|
} else {
|
||||||
currentPlayerCount = String.valueOf(connector.getPlayers().size());
|
currentPlayerCount = String.valueOf(connector.getPlayers().size());
|
||||||
maxPlayerCount = String.valueOf(connector.getConfig().getMaxPlayers());
|
maxPlayerCount = String.valueOf(connector.getConfig().getMaxPlayers());
|
||||||
|
@ -220,7 +220,7 @@ public class QueryPacketHandler {
|
||||||
|
|
||||||
// Fill player names
|
// Fill player names
|
||||||
if(pingInfo != null) {
|
if(pingInfo != null) {
|
||||||
for (String username : pingInfo.getPlayers()) {
|
for (String username : pingInfo.getPlayerList()) {
|
||||||
query.write(username.getBytes());
|
query.write(username.getBytes());
|
||||||
query.write((byte) 0x00);
|
query.write((byte) 0x00);
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,16 +26,21 @@
|
||||||
|
|
||||||
package org.geysermc.connector.ping;
|
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.MinecraftConstants;
|
||||||
import com.github.steveice10.mc.protocol.MinecraftProtocol;
|
import com.nukkitx.nbt.util.VarInts;
|
||||||
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 org.geysermc.connector.common.ping.GeyserPingInfo;
|
import org.geysermc.connector.common.ping.GeyserPingInfo;
|
||||||
import org.geysermc.connector.GeyserConnector;
|
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;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
public class GeyserLegacyPingPassthrough implements IGeyserPingPassthrough, Runnable {
|
public class GeyserLegacyPingPassthrough implements IGeyserPingPassthrough, Runnable {
|
||||||
|
@ -44,13 +49,10 @@ public class GeyserLegacyPingPassthrough implements IGeyserPingPassthrough, Runn
|
||||||
|
|
||||||
public GeyserLegacyPingPassthrough(GeyserConnector connector) {
|
public GeyserLegacyPingPassthrough(GeyserConnector connector) {
|
||||||
this.connector = connector;
|
this.connector = connector;
|
||||||
this.pingInfo = new GeyserPingInfo(null, 0, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private GeyserPingInfo pingInfo;
|
private GeyserPingInfo pingInfo;
|
||||||
|
|
||||||
private Client client;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Start legacy ping passthrough thread
|
* Start legacy ping passthrough thread
|
||||||
* @param connector GeyserConnector
|
* @param connector GeyserConnector
|
||||||
|
@ -76,15 +78,51 @@ public class GeyserLegacyPingPassthrough implements IGeyserPingPassthrough, Runn
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
try {
|
try {
|
||||||
this.client = new Client(connector.getConfig().getRemote().getAddress(), connector.getConfig().getRemote().getPort(), new MinecraftProtocol(SubProtocol.STATUS), new TcpSessionFactory());
|
Socket socket = new Socket();
|
||||||
this.client.getSession().setFlag(MinecraftConstants.SERVER_INFO_HANDLER_KEY, (ServerInfoHandler) (session, info) -> {
|
socket.connect(new InetSocketAddress(connector.getConfig().getRemote().getAddress(), connector.getConfig().getRemote().getPort()), 5000);
|
||||||
this.pingInfo = new GeyserPingInfo(((TextMessage) info.getDescription()).getText(), info.getPlayerInfo().getOnlinePlayers(), info.getPlayerInfo().getMaxPlayers());
|
|
||||||
this.client.getSession().disconnect(null);
|
|
||||||
});
|
|
||||||
|
|
||||||
client.getSession().connect();
|
ByteArrayOutputStream byteArrayStream = new ByteArrayOutputStream();
|
||||||
} catch (Exception ex) {
|
DataOutputStream handshake = new DataOutputStream(byteArrayStream);
|
||||||
ex.printStackTrace();
|
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