mirror of
https://github.com/Nan1t/NanoLimbo.git
synced 2025-07-14 21:20:15 +02:00
Reformatted packet handling. Moved packet snapshot in separated class
This commit is contained in:
parent
6aea0392d4
commit
9269751ed1
@ -43,6 +43,7 @@ public class ClientChannelInitializer extends ChannelInitializer<Channel> {
|
||||
|
||||
PacketDecoder decoder = new PacketDecoder();
|
||||
PacketEncoder encoder = new PacketEncoder();
|
||||
ClientConnection connection = new ClientConnection(channel, server, decoder, encoder);
|
||||
|
||||
pipeline.addLast("timeout", new ReadTimeoutHandler(server.getConfig().getReadTimeout(),
|
||||
TimeUnit.MILLISECONDS));
|
||||
@ -50,7 +51,7 @@ public class ClientChannelInitializer extends ChannelInitializer<Channel> {
|
||||
pipeline.addLast("frame_encoder", new VarIntLengthEncoder());
|
||||
pipeline.addLast("decoder", decoder);
|
||||
pipeline.addLast("encoder", encoder);
|
||||
pipeline.addLast("handler", new ClientConnection(channel, server, decoder, encoder));
|
||||
pipeline.addLast("handler", connection);
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -21,26 +21,20 @@ import com.grack.nanojson.JsonArray;
|
||||
import com.grack.nanojson.JsonObject;
|
||||
import com.grack.nanojson.JsonParser;
|
||||
import com.grack.nanojson.JsonParserException;
|
||||
import io.netty.buffer.Unpooled;
|
||||
import io.netty.channel.Channel;
|
||||
import io.netty.channel.ChannelFutureListener;
|
||||
import io.netty.channel.ChannelHandlerContext;
|
||||
import io.netty.channel.ChannelInboundHandlerAdapter;
|
||||
import ru.nanit.limbo.LimboConstants;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import ru.nanit.limbo.connection.pipeline.PacketDecoder;
|
||||
import ru.nanit.limbo.connection.pipeline.PacketEncoder;
|
||||
import ru.nanit.limbo.protocol.ByteMessage;
|
||||
import ru.nanit.limbo.protocol.PacketSnapshot;
|
||||
import ru.nanit.limbo.protocol.packets.PacketHandshake;
|
||||
import ru.nanit.limbo.protocol.Packet;
|
||||
import ru.nanit.limbo.protocol.packets.login.*;
|
||||
import ru.nanit.limbo.protocol.packets.play.*;
|
||||
import ru.nanit.limbo.protocol.packets.status.PacketStatusPing;
|
||||
import ru.nanit.limbo.protocol.packets.status.PacketStatusRequest;
|
||||
import ru.nanit.limbo.protocol.packets.status.PacketStatusResponse;
|
||||
import ru.nanit.limbo.protocol.registry.State;
|
||||
import ru.nanit.limbo.protocol.registry.Version;
|
||||
import ru.nanit.limbo.server.LimboServer;
|
||||
import ru.nanit.limbo.server.data.Title;
|
||||
import ru.nanit.limbo.server.Logger;
|
||||
import ru.nanit.limbo.util.UuidUtil;
|
||||
|
||||
@ -50,31 +44,11 @@ import java.net.InetSocketAddress;
|
||||
import java.net.SocketAddress;
|
||||
import java.security.InvalidKeyException;
|
||||
import java.security.MessageDigest;
|
||||
import java.util.Collections;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
|
||||
public class ClientConnection extends ChannelInboundHandlerAdapter {
|
||||
|
||||
private static PacketSnapshot PACKET_LOGIN_SUCCESS;
|
||||
private static PacketSnapshot PACKET_JOIN_GAME;
|
||||
private static PacketSnapshot PACKET_PLUGIN_MESSAGE;
|
||||
private static PacketSnapshot PACKET_PLAYER_ABILITIES;
|
||||
private static PacketSnapshot PACKET_PLAYER_INFO;
|
||||
private static PacketSnapshot PACKET_DECLARE_COMMANDS;
|
||||
private static PacketSnapshot PACKET_PLAYER_POS;
|
||||
private static PacketSnapshot PACKET_JOIN_MESSAGE;
|
||||
private static PacketSnapshot PACKET_BOSS_BAR;
|
||||
private static PacketSnapshot PACKET_HEADER_AND_FOOTER;
|
||||
|
||||
private static PacketSnapshot PACKET_TITLE_TITLE;
|
||||
private static PacketSnapshot PACKET_TITLE_SUBTITLE;
|
||||
private static PacketSnapshot PACKET_TITLE_TIMES;
|
||||
|
||||
private static PacketSnapshot PACKET_TITLE_LEGACY_TITLE;
|
||||
private static PacketSnapshot PACKET_TITLE_LEGACY_SUBTITLE;
|
||||
private static PacketSnapshot PACKET_TITLE_LEGACY_TIMES;
|
||||
|
||||
private final LimboServer server;
|
||||
private final Channel channel;
|
||||
private final GameProfile gameProfile;
|
||||
@ -113,8 +87,12 @@ public class ClientConnection extends ChannelInboundHandlerAdapter {
|
||||
return clientVersion;
|
||||
}
|
||||
|
||||
public GameProfile getGameProfile() {
|
||||
return gameProfile;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
|
||||
public void channelInactive(@NotNull ChannelHandlerContext ctx) throws Exception {
|
||||
if (state.equals(State.PLAY)) {
|
||||
server.getConnections().removeConnection(this);
|
||||
}
|
||||
@ -129,139 +107,52 @@ public class ClientConnection extends ChannelInboundHandlerAdapter {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void channelRead(ChannelHandlerContext ctx, Object msg) {
|
||||
public void channelRead(@NotNull ChannelHandlerContext ctx, @NotNull Object msg) {
|
||||
handlePacket(msg);
|
||||
}
|
||||
|
||||
public void handlePacket(Object packet) {
|
||||
if (packet instanceof PacketHandshake) {
|
||||
PacketHandshake handshake = (PacketHandshake) packet;
|
||||
clientVersion = handshake.getVersion();
|
||||
|
||||
updateStateAndVersion(handshake.getNextState(), clientVersion);
|
||||
|
||||
Logger.debug("Pinged from %s [%s]", address, clientVersion.toString());
|
||||
|
||||
if (server.getConfig().getInfoForwarding().isLegacy()) {
|
||||
String[] split = handshake.getHost().split("\00");
|
||||
|
||||
if (split.length == 3 || split.length == 4) {
|
||||
setAddress(split[1]);
|
||||
gameProfile.setUuid(UuidUtil.fromString(split[2]));
|
||||
} else {
|
||||
disconnectLogin("You've enabled player info forwarding. You need to connect with proxy");
|
||||
}
|
||||
} else if (server.getConfig().getInfoForwarding().isBungeeGuard()) {
|
||||
if (!checkBungeeGuardHandshake(handshake.getHost())) {
|
||||
disconnectLogin("Invalid BungeeGuard token or handshake format");
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (packet instanceof PacketStatusRequest) {
|
||||
sendPacket(new PacketStatusResponse(server));
|
||||
return;
|
||||
}
|
||||
|
||||
if (packet instanceof PacketStatusPing) {
|
||||
sendPacketAndClose(packet);
|
||||
return;
|
||||
}
|
||||
|
||||
if (packet instanceof PacketLoginStart) {
|
||||
if (server.getConfig().getMaxPlayers() > 0 &&
|
||||
server.getConnections().getCount() >= server.getConfig().getMaxPlayers()) {
|
||||
disconnectLogin("Too many players connected");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!clientVersion.isSupported()) {
|
||||
disconnectLogin("Unsupported client version");
|
||||
return;
|
||||
}
|
||||
|
||||
if (server.getConfig().getInfoForwarding().isModern()) {
|
||||
velocityLoginMessageId = ThreadLocalRandom.current().nextInt(0, Integer.MAX_VALUE);
|
||||
PacketLoginPluginRequest request = new PacketLoginPluginRequest();
|
||||
request.setMessageId(velocityLoginMessageId);
|
||||
request.setChannel(LimboConstants.VELOCITY_INFO_CHANNEL);
|
||||
request.setData(Unpooled.EMPTY_BUFFER);
|
||||
sendPacket(request);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!server.getConfig().getInfoForwarding().isModern()) {
|
||||
gameProfile.setUsername(((PacketLoginStart)packet).getUsername());
|
||||
gameProfile.setUuid(UuidUtil.getOfflineModeUuid(getUsername()));
|
||||
}
|
||||
|
||||
fireLoginSuccess();
|
||||
return;
|
||||
}
|
||||
|
||||
if (packet instanceof PacketLoginPluginResponse) {
|
||||
PacketLoginPluginResponse response = (PacketLoginPluginResponse) packet;
|
||||
|
||||
if (server.getConfig().getInfoForwarding().isModern()
|
||||
&& response.getMessageId() == velocityLoginMessageId) {
|
||||
|
||||
if (!response.isSuccessful() || response.getData() == null) {
|
||||
disconnectLogin("You need to connect with Velocity");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!checkVelocityKeyIntegrity(response.getData())) {
|
||||
disconnectLogin("Can't verify forwarded player info");
|
||||
return;
|
||||
}
|
||||
|
||||
// Order is important
|
||||
setAddress(response.getData().readString());
|
||||
gameProfile.setUuid(response.getData().readUuid());
|
||||
gameProfile.setUsername(response.getData().readString());
|
||||
|
||||
fireLoginSuccess();
|
||||
}
|
||||
if (packet instanceof Packet) {
|
||||
((Packet)packet).handle(this, server);
|
||||
}
|
||||
}
|
||||
|
||||
private void fireLoginSuccess() {
|
||||
public void fireLoginSuccess() {
|
||||
if (server.getConfig().getInfoForwarding().isModern() && velocityLoginMessageId == -1) {
|
||||
disconnectLogin("You need to connect with Velocity");
|
||||
return;
|
||||
}
|
||||
|
||||
writePacket(PACKET_LOGIN_SUCCESS);
|
||||
setPlayState();
|
||||
writePacket(PacketSnapshots.PACKET_LOGIN_SUCCESS);
|
||||
updateState(State.PLAY);
|
||||
|
||||
server.getConnections().addConnection(this);
|
||||
|
||||
writePacket(PACKET_JOIN_GAME);
|
||||
writePacket(PACKET_PLAYER_ABILITIES);
|
||||
writePacket(PACKET_PLAYER_POS);
|
||||
writePacket(PacketSnapshots.PACKET_JOIN_GAME);
|
||||
writePacket(PacketSnapshots.PACKET_PLAYER_ABILITIES);
|
||||
writePacket(PacketSnapshots.PACKET_PLAYER_POS);
|
||||
|
||||
if (server.getConfig().isUsePlayerList() || clientVersion.equals(Version.V1_16_4))
|
||||
writePacket(PACKET_PLAYER_INFO);
|
||||
writePacket(PacketSnapshots.PACKET_PLAYER_INFO);
|
||||
|
||||
if (clientVersion.moreOrEqual(Version.V1_13)) {
|
||||
writePacket(PACKET_DECLARE_COMMANDS);
|
||||
writePacket(PacketSnapshots.PACKET_DECLARE_COMMANDS);
|
||||
|
||||
if (PACKET_PLUGIN_MESSAGE != null)
|
||||
writePacket(PACKET_PLUGIN_MESSAGE);
|
||||
if (PacketSnapshots.PACKET_PLUGIN_MESSAGE != null)
|
||||
writePacket(PacketSnapshots.PACKET_PLUGIN_MESSAGE);
|
||||
}
|
||||
|
||||
if (PACKET_BOSS_BAR != null && clientVersion.moreOrEqual(Version.V1_9))
|
||||
writePacket(PACKET_BOSS_BAR);
|
||||
if (PacketSnapshots.PACKET_BOSS_BAR != null && clientVersion.moreOrEqual(Version.V1_9))
|
||||
writePacket(PacketSnapshots.PACKET_BOSS_BAR);
|
||||
|
||||
if (PACKET_JOIN_MESSAGE != null)
|
||||
writePacket(PACKET_JOIN_MESSAGE);
|
||||
if (PacketSnapshots.PACKET_JOIN_MESSAGE != null)
|
||||
writePacket(PacketSnapshots.PACKET_JOIN_MESSAGE);
|
||||
|
||||
if (PACKET_TITLE_TITLE != null)
|
||||
if (PacketSnapshots.PACKET_TITLE_TITLE != null)
|
||||
writeTitle();
|
||||
|
||||
if (PACKET_HEADER_AND_FOOTER != null)
|
||||
writePacket(PACKET_HEADER_AND_FOOTER);
|
||||
if (PacketSnapshots.PACKET_HEADER_AND_FOOTER != null)
|
||||
writePacket(PacketSnapshots.PACKET_HEADER_AND_FOOTER);
|
||||
|
||||
sendKeepAlive();
|
||||
}
|
||||
@ -276,13 +167,13 @@ public class ClientConnection extends ChannelInboundHandlerAdapter {
|
||||
|
||||
public void writeTitle() {
|
||||
if (clientVersion.moreOrEqual(Version.V1_17)) {
|
||||
writePacket(PACKET_TITLE_TITLE);
|
||||
writePacket(PACKET_TITLE_SUBTITLE);
|
||||
writePacket(PACKET_TITLE_TIMES);
|
||||
writePacket(PacketSnapshots.PACKET_TITLE_TITLE);
|
||||
writePacket(PacketSnapshots.PACKET_TITLE_SUBTITLE);
|
||||
writePacket(PacketSnapshots.PACKET_TITLE_TIMES);
|
||||
} else {
|
||||
writePacket(PACKET_TITLE_LEGACY_TITLE);
|
||||
writePacket(PACKET_TITLE_LEGACY_SUBTITLE);
|
||||
writePacket(PACKET_TITLE_LEGACY_TIMES);
|
||||
writePacket(PacketSnapshots.PACKET_TITLE_LEGACY_TITLE);
|
||||
writePacket(PacketSnapshots.PACKET_TITLE_LEGACY_SUBTITLE);
|
||||
writePacket(PacketSnapshots.PACKET_TITLE_LEGACY_TIMES);
|
||||
}
|
||||
}
|
||||
|
||||
@ -313,25 +204,23 @@ public class ClientConnection extends ChannelInboundHandlerAdapter {
|
||||
return channel.isActive();
|
||||
}
|
||||
|
||||
private void setPlayState() {
|
||||
this.state = State.PLAY;
|
||||
decoder.updateState(this.state);
|
||||
encoder.updateState(this.state);
|
||||
}
|
||||
|
||||
public void updateStateAndVersion(State state, Version version) {
|
||||
public void updateState(State state) {
|
||||
this.state = state;
|
||||
decoder.updateVersion(version);
|
||||
decoder.updateState(state);
|
||||
encoder.updateVersion(version);
|
||||
encoder.updateState(state);
|
||||
}
|
||||
|
||||
private void setAddress(String host) {
|
||||
public void updateVersion(Version version) {
|
||||
clientVersion = version;
|
||||
decoder.updateVersion(version);
|
||||
encoder.updateVersion(version);
|
||||
}
|
||||
|
||||
public void setAddress(String host) {
|
||||
this.address = new InetSocketAddress(host, ((InetSocketAddress)this.address).getPort());
|
||||
}
|
||||
|
||||
private boolean checkBungeeGuardHandshake(String handshake) {
|
||||
boolean checkBungeeGuardHandshake(String handshake) {
|
||||
String[] split = handshake.split("\00");
|
||||
|
||||
if (split.length != 4)
|
||||
@ -370,7 +259,15 @@ public class ClientConnection extends ChannelInboundHandlerAdapter {
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean checkVelocityKeyIntegrity(ByteMessage buf) {
|
||||
int getVelocityLoginMessageId() {
|
||||
return velocityLoginMessageId;
|
||||
}
|
||||
|
||||
void setVelocityLoginMessageId(int velocityLoginMessageId) {
|
||||
this.velocityLoginMessageId = velocityLoginMessageId;
|
||||
}
|
||||
|
||||
boolean checkVelocityKeyIntegrity(ByteMessage buf) {
|
||||
byte[] signature = new byte[32];
|
||||
buf.readBytes(signature);
|
||||
byte[] data = new byte[buf.readableBytes()];
|
||||
@ -389,122 +286,4 @@ public class ClientConnection extends ChannelInboundHandlerAdapter {
|
||||
throw new IllegalStateException("Unsupported forwarding version " + version + ", wanted " + '\001');
|
||||
return true;
|
||||
}
|
||||
|
||||
public static void initPackets(LimboServer server) {
|
||||
final String username = server.getConfig().getPingData().getVersion();
|
||||
final UUID uuid = UuidUtil.getOfflineModeUuid(username);
|
||||
|
||||
PacketLoginSuccess loginSuccess = new PacketLoginSuccess();
|
||||
loginSuccess.setUsername(username);
|
||||
loginSuccess.setUuid(uuid);
|
||||
|
||||
PacketJoinGame joinGame = new PacketJoinGame();
|
||||
joinGame.setEntityId(0);
|
||||
joinGame.setEnableRespawnScreen(true);
|
||||
joinGame.setFlat(false);
|
||||
joinGame.setGameMode(server.getConfig().getGameMode());
|
||||
joinGame.setHardcore(false);
|
||||
joinGame.setMaxPlayers(server.getConfig().getMaxPlayers());
|
||||
joinGame.setPreviousGameMode(-1);
|
||||
joinGame.setReducedDebugInfo(true);
|
||||
joinGame.setDebug(false);
|
||||
joinGame.setViewDistance(0);
|
||||
joinGame.setWorldName("minecraft:world");
|
||||
joinGame.setWorldNames("minecraft:world");
|
||||
joinGame.setHashedSeed(0);
|
||||
joinGame.setDimensionRegistry(server.getDimensionRegistry());
|
||||
|
||||
PacketPlayerAbilities playerAbilities = new PacketPlayerAbilities();
|
||||
playerAbilities.setFlyingSpeed(0.0F);
|
||||
playerAbilities.setFlags(0x02);
|
||||
playerAbilities.setFieldOfView(0.1F);
|
||||
|
||||
PacketPlayerPositionAndLook positionAndLook = new PacketPlayerPositionAndLook();
|
||||
positionAndLook.setX(server.getConfig().getSpawnPosition().getX());
|
||||
positionAndLook.setY(server.getConfig().getSpawnPosition().getY());
|
||||
positionAndLook.setZ(server.getConfig().getSpawnPosition().getZ());
|
||||
positionAndLook.setYaw(server.getConfig().getSpawnPosition().getYaw());
|
||||
positionAndLook.setPitch(server.getConfig().getSpawnPosition().getPitch());
|
||||
positionAndLook.setTeleportId(ThreadLocalRandom.current().nextInt());
|
||||
|
||||
PacketDeclareCommands declareCommands = new PacketDeclareCommands();
|
||||
declareCommands.setCommands(Collections.emptyList());
|
||||
|
||||
PacketPlayerInfo info = new PacketPlayerInfo();
|
||||
info.setUsername(server.getConfig().getPlayerListUsername());
|
||||
info.setGameMode(server.getConfig().getGameMode());
|
||||
info.setUuid(uuid);
|
||||
|
||||
PACKET_LOGIN_SUCCESS = PacketSnapshot.of(loginSuccess);
|
||||
PACKET_JOIN_GAME = PacketSnapshot.of(joinGame);
|
||||
PACKET_PLAYER_ABILITIES = PacketSnapshot.of(playerAbilities);
|
||||
PACKET_PLAYER_POS = PacketSnapshot.of(positionAndLook);
|
||||
PACKET_PLAYER_INFO = PacketSnapshot.of(info);
|
||||
|
||||
PACKET_DECLARE_COMMANDS = PacketSnapshot.of(declareCommands);
|
||||
|
||||
if (server.getConfig().isUseHeaderAndFooter()) {
|
||||
PacketPlayerListHeader header = new PacketPlayerListHeader();
|
||||
header.setHeader(server.getConfig().getPlayerListHeader());
|
||||
header.setFooter(server.getConfig().getPlayerListFooter());
|
||||
PACKET_HEADER_AND_FOOTER = PacketSnapshot.of(header);
|
||||
}
|
||||
|
||||
if (server.getConfig().isUseBrandName()){
|
||||
PacketPluginMessage pluginMessage = new PacketPluginMessage();
|
||||
pluginMessage.setChannel(LimboConstants.BRAND_CHANNEL);
|
||||
pluginMessage.setMessage(server.getConfig().getBrandName());
|
||||
PACKET_PLUGIN_MESSAGE = PacketSnapshot.of(pluginMessage);
|
||||
}
|
||||
|
||||
if (server.getConfig().isUseJoinMessage()) {
|
||||
PacketChatMessage joinMessage = new PacketChatMessage();
|
||||
joinMessage.setJsonData(server.getConfig().getJoinMessage());
|
||||
joinMessage.setPosition(PacketChatMessage.Position.CHAT);
|
||||
joinMessage.setSender(UUID.randomUUID());
|
||||
PACKET_JOIN_MESSAGE = PacketSnapshot.of(joinMessage);
|
||||
}
|
||||
|
||||
if (server.getConfig().isUseBossBar()) {
|
||||
PacketBossBar bossBar = new PacketBossBar();
|
||||
bossBar.setBossBar(server.getConfig().getBossBar());
|
||||
bossBar.setUuid(UUID.randomUUID());
|
||||
PACKET_BOSS_BAR = PacketSnapshot.of(bossBar);
|
||||
}
|
||||
|
||||
if (server.getConfig().isUseTitle()) {
|
||||
Title title = server.getConfig().getTitle();
|
||||
|
||||
PacketTitleSetTitle packetTitle = new PacketTitleSetTitle();
|
||||
PacketTitleSetSubTitle packetSubtitle = new PacketTitleSetSubTitle();
|
||||
PacketTitleTimes packetTimes = new PacketTitleTimes();
|
||||
|
||||
PacketTitleLegacy legacyTitle = new PacketTitleLegacy();
|
||||
PacketTitleLegacy legacySubtitle = new PacketTitleLegacy();
|
||||
PacketTitleLegacy legacyTimes = new PacketTitleLegacy();
|
||||
|
||||
packetTitle.setTitle(title.getTitle());
|
||||
packetSubtitle.setSubtitle(title.getSubtitle());
|
||||
packetTimes.setFadeIn(title.getFadeIn());
|
||||
packetTimes.setStay(title.getStay());
|
||||
packetTimes.setFadeOut(title.getFadeOut());
|
||||
|
||||
legacyTitle.setTitle(title);
|
||||
legacyTitle.setAction(PacketTitleLegacy.Action.SET_TITLE);
|
||||
|
||||
legacySubtitle.setTitle(title);
|
||||
legacySubtitle.setAction(PacketTitleLegacy.Action.SET_SUBTITLE);
|
||||
|
||||
legacyTimes.setTitle(title);
|
||||
legacyTimes.setAction(PacketTitleLegacy.Action.SET_TIMES_AND_DISPLAY);
|
||||
|
||||
PACKET_TITLE_TITLE = PacketSnapshot.of(packetTitle);
|
||||
PACKET_TITLE_SUBTITLE = PacketSnapshot.of(packetSubtitle);
|
||||
PACKET_TITLE_TIMES = PacketSnapshot.of(packetTimes);
|
||||
|
||||
PACKET_TITLE_LEGACY_TITLE = PacketSnapshot.of(legacyTitle);
|
||||
PACKET_TITLE_LEGACY_SUBTITLE = PacketSnapshot.of(legacySubtitle);
|
||||
PACKET_TITLE_LEGACY_TIMES = PacketSnapshot.of(legacyTimes);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
129
src/main/java/ru/nanit/limbo/connection/PacketHandler.java
Normal file
129
src/main/java/ru/nanit/limbo/connection/PacketHandler.java
Normal file
@ -0,0 +1,129 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Nan1t
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package ru.nanit.limbo.connection;
|
||||
|
||||
import io.netty.buffer.Unpooled;
|
||||
import ru.nanit.limbo.LimboConstants;
|
||||
import ru.nanit.limbo.protocol.packets.PacketHandshake;
|
||||
import ru.nanit.limbo.protocol.packets.login.PacketLoginPluginRequest;
|
||||
import ru.nanit.limbo.protocol.packets.login.PacketLoginPluginResponse;
|
||||
import ru.nanit.limbo.protocol.packets.login.PacketLoginStart;
|
||||
import ru.nanit.limbo.protocol.packets.status.PacketStatusPing;
|
||||
import ru.nanit.limbo.protocol.packets.status.PacketStatusRequest;
|
||||
import ru.nanit.limbo.server.LimboServer;
|
||||
import ru.nanit.limbo.server.Logger;
|
||||
import ru.nanit.limbo.util.UuidUtil;
|
||||
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
|
||||
public class PacketHandler {
|
||||
|
||||
private final LimboServer server;
|
||||
|
||||
public PacketHandler(LimboServer server) {
|
||||
this.server = server;
|
||||
}
|
||||
|
||||
public void handle(ClientConnection conn, PacketHandshake packet) {
|
||||
conn.updateVersion(packet.getVersion());
|
||||
conn.updateState(packet.getNextState());
|
||||
|
||||
Logger.debug("Pinged from %s [%s]", conn.getAddress(),
|
||||
conn.getClientVersion().toString());
|
||||
|
||||
if (server.getConfig().getInfoForwarding().isLegacy()) {
|
||||
String[] split = packet.getHost().split("\00");
|
||||
|
||||
if (split.length == 3 || split.length == 4) {
|
||||
conn.setAddress(split[1]);
|
||||
conn.getGameProfile().setUuid(UuidUtil.fromString(split[2]));
|
||||
} else {
|
||||
conn.disconnectLogin("You've enabled player info forwarding. You need to connect with proxy");
|
||||
}
|
||||
} else if (server.getConfig().getInfoForwarding().isBungeeGuard()) {
|
||||
if (!conn.checkBungeeGuardHandshake(packet.getHost())) {
|
||||
conn.disconnectLogin("Invalid BungeeGuard token or handshake format");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void handle(ClientConnection conn, PacketStatusRequest packet) {
|
||||
conn.sendPacket(PacketSnapshots.PACKET_STATUS_RESPONSE);
|
||||
}
|
||||
|
||||
public void handle(ClientConnection conn, PacketStatusPing packet) {
|
||||
conn.sendPacketAndClose(packet);
|
||||
}
|
||||
|
||||
public void handle(ClientConnection conn, PacketLoginStart packet) {
|
||||
if (server.getConfig().getMaxPlayers() > 0 &&
|
||||
server.getConnections().getCount() >= server.getConfig().getMaxPlayers()) {
|
||||
conn.disconnectLogin("Too many players connected");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!conn.getClientVersion().isSupported()) {
|
||||
conn.disconnectLogin("Unsupported client version");
|
||||
return;
|
||||
}
|
||||
|
||||
if (server.getConfig().getInfoForwarding().isModern()) {
|
||||
int loginId = ThreadLocalRandom.current().nextInt(0, Integer.MAX_VALUE);
|
||||
PacketLoginPluginRequest request = new PacketLoginPluginRequest();
|
||||
|
||||
request.setMessageId(loginId);
|
||||
request.setChannel(LimboConstants.VELOCITY_INFO_CHANNEL);
|
||||
request.setData(Unpooled.EMPTY_BUFFER);
|
||||
|
||||
conn.setVelocityLoginMessageId(loginId);
|
||||
conn.sendPacket(request);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!server.getConfig().getInfoForwarding().isModern()) {
|
||||
conn.getGameProfile().setUsername(packet.getUsername());
|
||||
conn.getGameProfile().setUuid(UuidUtil.getOfflineModeUuid(packet.getUsername()));
|
||||
}
|
||||
|
||||
conn.fireLoginSuccess();
|
||||
}
|
||||
|
||||
public void handle(ClientConnection conn, PacketLoginPluginResponse packet) {
|
||||
if (server.getConfig().getInfoForwarding().isModern()
|
||||
&& packet.getMessageId() == conn.getVelocityLoginMessageId()) {
|
||||
|
||||
if (!packet.isSuccessful() || packet.getData() == null) {
|
||||
conn.disconnectLogin("You need to connect with Velocity");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!conn.checkVelocityKeyIntegrity(packet.getData())) {
|
||||
conn.disconnectLogin("Can't verify forwarded player info");
|
||||
return;
|
||||
}
|
||||
|
||||
// Order is important
|
||||
conn.setAddress(packet.getData().readString());
|
||||
conn.getGameProfile().setUuid(packet.getData().readUuid());
|
||||
conn.getGameProfile().setUsername(packet.getData().readString());
|
||||
|
||||
conn.fireLoginSuccess();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
175
src/main/java/ru/nanit/limbo/connection/PacketSnapshots.java
Normal file
175
src/main/java/ru/nanit/limbo/connection/PacketSnapshots.java
Normal file
@ -0,0 +1,175 @@
|
||||
/*
|
||||
* Copyright (C) 2020 Nan1t
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package ru.nanit.limbo.connection;
|
||||
|
||||
import ru.nanit.limbo.LimboConstants;
|
||||
import ru.nanit.limbo.protocol.PacketSnapshot;
|
||||
import ru.nanit.limbo.protocol.packets.login.PacketLoginSuccess;
|
||||
import ru.nanit.limbo.protocol.packets.play.*;
|
||||
import ru.nanit.limbo.protocol.packets.status.PacketStatusResponse;
|
||||
import ru.nanit.limbo.server.LimboServer;
|
||||
import ru.nanit.limbo.server.data.Title;
|
||||
import ru.nanit.limbo.util.UuidUtil;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
|
||||
public final class PacketSnapshots {
|
||||
|
||||
public static PacketSnapshot PACKET_STATUS_RESPONSE;
|
||||
public static PacketSnapshot PACKET_LOGIN_SUCCESS;
|
||||
public static PacketSnapshot PACKET_JOIN_GAME;
|
||||
public static PacketSnapshot PACKET_PLUGIN_MESSAGE;
|
||||
public static PacketSnapshot PACKET_PLAYER_ABILITIES;
|
||||
public static PacketSnapshot PACKET_PLAYER_INFO;
|
||||
public static PacketSnapshot PACKET_DECLARE_COMMANDS;
|
||||
public static PacketSnapshot PACKET_PLAYER_POS;
|
||||
public static PacketSnapshot PACKET_JOIN_MESSAGE;
|
||||
public static PacketSnapshot PACKET_BOSS_BAR;
|
||||
public static PacketSnapshot PACKET_HEADER_AND_FOOTER;
|
||||
|
||||
public static PacketSnapshot PACKET_TITLE_TITLE;
|
||||
public static PacketSnapshot PACKET_TITLE_SUBTITLE;
|
||||
public static PacketSnapshot PACKET_TITLE_TIMES;
|
||||
|
||||
public static PacketSnapshot PACKET_TITLE_LEGACY_TITLE;
|
||||
public static PacketSnapshot PACKET_TITLE_LEGACY_SUBTITLE;
|
||||
public static PacketSnapshot PACKET_TITLE_LEGACY_TIMES;
|
||||
|
||||
private PacketSnapshots() { }
|
||||
|
||||
public static void initPackets(LimboServer server) {
|
||||
final String username = server.getConfig().getPingData().getVersion();
|
||||
final UUID uuid = UuidUtil.getOfflineModeUuid(username);
|
||||
|
||||
PacketLoginSuccess loginSuccess = new PacketLoginSuccess();
|
||||
loginSuccess.setUsername(username);
|
||||
loginSuccess.setUuid(uuid);
|
||||
|
||||
PacketJoinGame joinGame = new PacketJoinGame();
|
||||
joinGame.setEntityId(0);
|
||||
joinGame.setEnableRespawnScreen(true);
|
||||
joinGame.setFlat(false);
|
||||
joinGame.setGameMode(server.getConfig().getGameMode());
|
||||
joinGame.setHardcore(false);
|
||||
joinGame.setMaxPlayers(server.getConfig().getMaxPlayers());
|
||||
joinGame.setPreviousGameMode(-1);
|
||||
joinGame.setReducedDebugInfo(true);
|
||||
joinGame.setDebug(false);
|
||||
joinGame.setViewDistance(0);
|
||||
joinGame.setWorldName("minecraft:world");
|
||||
joinGame.setWorldNames("minecraft:world");
|
||||
joinGame.setHashedSeed(0);
|
||||
joinGame.setDimensionRegistry(server.getDimensionRegistry());
|
||||
|
||||
PacketPlayerAbilities playerAbilities = new PacketPlayerAbilities();
|
||||
playerAbilities.setFlyingSpeed(0.0F);
|
||||
playerAbilities.setFlags(0x02);
|
||||
playerAbilities.setFieldOfView(0.1F);
|
||||
|
||||
PacketPlayerPositionAndLook positionAndLook = new PacketPlayerPositionAndLook();
|
||||
positionAndLook.setX(server.getConfig().getSpawnPosition().getX());
|
||||
positionAndLook.setY(server.getConfig().getSpawnPosition().getY());
|
||||
positionAndLook.setZ(server.getConfig().getSpawnPosition().getZ());
|
||||
positionAndLook.setYaw(server.getConfig().getSpawnPosition().getYaw());
|
||||
positionAndLook.setPitch(server.getConfig().getSpawnPosition().getPitch());
|
||||
positionAndLook.setTeleportId(ThreadLocalRandom.current().nextInt());
|
||||
|
||||
PacketDeclareCommands declareCommands = new PacketDeclareCommands();
|
||||
declareCommands.setCommands(Collections.emptyList());
|
||||
|
||||
PacketPlayerInfo info = new PacketPlayerInfo();
|
||||
info.setUsername(server.getConfig().getPlayerListUsername());
|
||||
info.setGameMode(server.getConfig().getGameMode());
|
||||
info.setUuid(uuid);
|
||||
|
||||
PACKET_STATUS_RESPONSE = PacketSnapshot.of(new PacketStatusResponse(server));
|
||||
PACKET_LOGIN_SUCCESS = PacketSnapshot.of(loginSuccess);
|
||||
PACKET_JOIN_GAME = PacketSnapshot.of(joinGame);
|
||||
PACKET_PLAYER_ABILITIES = PacketSnapshot.of(playerAbilities);
|
||||
PACKET_PLAYER_POS = PacketSnapshot.of(positionAndLook);
|
||||
PACKET_PLAYER_INFO = PacketSnapshot.of(info);
|
||||
|
||||
PACKET_DECLARE_COMMANDS = PacketSnapshot.of(declareCommands);
|
||||
|
||||
if (server.getConfig().isUseHeaderAndFooter()) {
|
||||
PacketPlayerListHeader header = new PacketPlayerListHeader();
|
||||
header.setHeader(server.getConfig().getPlayerListHeader());
|
||||
header.setFooter(server.getConfig().getPlayerListFooter());
|
||||
PACKET_HEADER_AND_FOOTER = PacketSnapshot.of(header);
|
||||
}
|
||||
|
||||
if (server.getConfig().isUseBrandName()){
|
||||
PacketPluginMessage pluginMessage = new PacketPluginMessage();
|
||||
pluginMessage.setChannel(LimboConstants.BRAND_CHANNEL);
|
||||
pluginMessage.setMessage(server.getConfig().getBrandName());
|
||||
PACKET_PLUGIN_MESSAGE = PacketSnapshot.of(pluginMessage);
|
||||
}
|
||||
|
||||
if (server.getConfig().isUseJoinMessage()) {
|
||||
PacketChatMessage joinMessage = new PacketChatMessage();
|
||||
joinMessage.setJsonData(server.getConfig().getJoinMessage());
|
||||
joinMessage.setPosition(PacketChatMessage.Position.CHAT);
|
||||
joinMessage.setSender(UUID.randomUUID());
|
||||
PACKET_JOIN_MESSAGE = PacketSnapshot.of(joinMessage);
|
||||
}
|
||||
|
||||
if (server.getConfig().isUseBossBar()) {
|
||||
PacketBossBar bossBar = new PacketBossBar();
|
||||
bossBar.setBossBar(server.getConfig().getBossBar());
|
||||
bossBar.setUuid(UUID.randomUUID());
|
||||
PACKET_BOSS_BAR = PacketSnapshot.of(bossBar);
|
||||
}
|
||||
|
||||
if (server.getConfig().isUseTitle()) {
|
||||
Title title = server.getConfig().getTitle();
|
||||
|
||||
PacketTitleSetTitle packetTitle = new PacketTitleSetTitle();
|
||||
PacketTitleSetSubTitle packetSubtitle = new PacketTitleSetSubTitle();
|
||||
PacketTitleTimes packetTimes = new PacketTitleTimes();
|
||||
|
||||
PacketTitleLegacy legacyTitle = new PacketTitleLegacy();
|
||||
PacketTitleLegacy legacySubtitle = new PacketTitleLegacy();
|
||||
PacketTitleLegacy legacyTimes = new PacketTitleLegacy();
|
||||
|
||||
packetTitle.setTitle(title.getTitle());
|
||||
packetSubtitle.setSubtitle(title.getSubtitle());
|
||||
packetTimes.setFadeIn(title.getFadeIn());
|
||||
packetTimes.setStay(title.getStay());
|
||||
packetTimes.setFadeOut(title.getFadeOut());
|
||||
|
||||
legacyTitle.setTitle(title);
|
||||
legacyTitle.setAction(PacketTitleLegacy.Action.SET_TITLE);
|
||||
|
||||
legacySubtitle.setTitle(title);
|
||||
legacySubtitle.setAction(PacketTitleLegacy.Action.SET_SUBTITLE);
|
||||
|
||||
legacyTimes.setTitle(title);
|
||||
legacyTimes.setAction(PacketTitleLegacy.Action.SET_TIMES_AND_DISPLAY);
|
||||
|
||||
PACKET_TITLE_TITLE = PacketSnapshot.of(packetTitle);
|
||||
PACKET_TITLE_SUBTITLE = PacketSnapshot.of(packetSubtitle);
|
||||
PACKET_TITLE_TIMES = PacketSnapshot.of(packetTimes);
|
||||
|
||||
PACKET_TITLE_LEGACY_TITLE = PacketSnapshot.of(legacyTitle);
|
||||
PACKET_TITLE_LEGACY_SUBTITLE = PacketSnapshot.of(legacySubtitle);
|
||||
PACKET_TITLE_LEGACY_TIMES = PacketSnapshot.of(legacyTimes);
|
||||
}
|
||||
}
|
||||
}
|
@ -17,7 +17,9 @@
|
||||
|
||||
package ru.nanit.limbo.protocol;
|
||||
|
||||
import ru.nanit.limbo.connection.ClientConnection;
|
||||
import ru.nanit.limbo.protocol.registry.Version;
|
||||
import ru.nanit.limbo.server.LimboServer;
|
||||
|
||||
public interface Packet {
|
||||
|
||||
@ -25,4 +27,8 @@ public interface Packet {
|
||||
|
||||
void decode(ByteMessage msg, Version version);
|
||||
|
||||
default void handle(ClientConnection conn, LimboServer server) {
|
||||
// Ignored by default
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -17,10 +17,14 @@
|
||||
|
||||
package ru.nanit.limbo.protocol.packets;
|
||||
|
||||
import ru.nanit.limbo.connection.ClientConnection;
|
||||
import ru.nanit.limbo.protocol.ByteMessage;
|
||||
import ru.nanit.limbo.protocol.PacketIn;
|
||||
import ru.nanit.limbo.protocol.registry.State;
|
||||
import ru.nanit.limbo.protocol.registry.Version;
|
||||
import ru.nanit.limbo.server.LimboServer;
|
||||
import ru.nanit.limbo.server.Logger;
|
||||
import ru.nanit.limbo.util.UuidUtil;
|
||||
|
||||
public class PacketHandshake implements PacketIn {
|
||||
|
||||
@ -62,4 +66,9 @@ public class PacketHandshake implements PacketIn {
|
||||
public String toString() {
|
||||
return getClass().getSimpleName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(ClientConnection conn, LimboServer server) {
|
||||
server.getPacketHandler().handle(conn, this);
|
||||
}
|
||||
}
|
||||
|
@ -17,9 +17,11 @@
|
||||
|
||||
package ru.nanit.limbo.protocol.packets.login;
|
||||
|
||||
import ru.nanit.limbo.connection.ClientConnection;
|
||||
import ru.nanit.limbo.protocol.ByteMessage;
|
||||
import ru.nanit.limbo.protocol.PacketIn;
|
||||
import ru.nanit.limbo.protocol.registry.Version;
|
||||
import ru.nanit.limbo.server.LimboServer;
|
||||
|
||||
public class PacketLoginPluginResponse implements PacketIn {
|
||||
|
||||
@ -50,6 +52,11 @@ public class PacketLoginPluginResponse implements PacketIn {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(ClientConnection conn, LimboServer server) {
|
||||
server.getPacketHandler().handle(conn, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getClass().getSimpleName();
|
||||
|
@ -17,9 +17,11 @@
|
||||
|
||||
package ru.nanit.limbo.protocol.packets.login;
|
||||
|
||||
import ru.nanit.limbo.connection.ClientConnection;
|
||||
import ru.nanit.limbo.protocol.ByteMessage;
|
||||
import ru.nanit.limbo.protocol.PacketIn;
|
||||
import ru.nanit.limbo.protocol.registry.Version;
|
||||
import ru.nanit.limbo.server.LimboServer;
|
||||
|
||||
public class PacketLoginStart implements PacketIn {
|
||||
|
||||
@ -34,6 +36,11 @@ public class PacketLoginStart implements PacketIn {
|
||||
this.username = msg.readString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(ClientConnection conn, LimboServer server) {
|
||||
server.getPacketHandler().handle(conn, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getClass().getSimpleName();
|
||||
|
@ -17,9 +17,11 @@
|
||||
|
||||
package ru.nanit.limbo.protocol.packets.status;
|
||||
|
||||
import ru.nanit.limbo.connection.ClientConnection;
|
||||
import ru.nanit.limbo.protocol.ByteMessage;
|
||||
import ru.nanit.limbo.protocol.Packet;
|
||||
import ru.nanit.limbo.protocol.registry.Version;
|
||||
import ru.nanit.limbo.server.LimboServer;
|
||||
|
||||
public class PacketStatusPing implements Packet {
|
||||
|
||||
@ -35,6 +37,11 @@ public class PacketStatusPing implements Packet {
|
||||
this.randomId = msg.readLong();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(ClientConnection conn, LimboServer server) {
|
||||
server.getPacketHandler().handle(conn, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getClass().getSimpleName();
|
||||
|
@ -17,9 +17,11 @@
|
||||
|
||||
package ru.nanit.limbo.protocol.packets.status;
|
||||
|
||||
import ru.nanit.limbo.connection.ClientConnection;
|
||||
import ru.nanit.limbo.protocol.ByteMessage;
|
||||
import ru.nanit.limbo.protocol.PacketIn;
|
||||
import ru.nanit.limbo.protocol.registry.Version;
|
||||
import ru.nanit.limbo.server.LimboServer;
|
||||
|
||||
public class PacketStatusRequest implements PacketIn {
|
||||
|
||||
@ -28,6 +30,11 @@ public class PacketStatusRequest implements PacketIn {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handle(ClientConnection conn, LimboServer server) {
|
||||
server.getPacketHandler().handle(conn, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return getClass().getSimpleName();
|
||||
|
@ -30,6 +30,8 @@ import io.netty.util.ResourceLeakDetector;
|
||||
import ru.nanit.limbo.configuration.LimboConfig;
|
||||
import ru.nanit.limbo.connection.ClientChannelInitializer;
|
||||
import ru.nanit.limbo.connection.ClientConnection;
|
||||
import ru.nanit.limbo.connection.PacketHandler;
|
||||
import ru.nanit.limbo.connection.PacketSnapshots;
|
||||
import ru.nanit.limbo.world.dimension.DimensionRegistry;
|
||||
|
||||
import java.nio.file.Paths;
|
||||
@ -39,6 +41,7 @@ import java.util.concurrent.TimeUnit;
|
||||
public final class LimboServer {
|
||||
|
||||
private LimboConfig config;
|
||||
private PacketHandler packetHandler;
|
||||
private Connections connections;
|
||||
private DimensionRegistry dimensionRegistry;
|
||||
private ScheduledFuture<?> keepAliveTask;
|
||||
@ -50,6 +53,10 @@ public final class LimboServer {
|
||||
return config;
|
||||
}
|
||||
|
||||
public PacketHandler getPacketHandler() {
|
||||
return packetHandler;
|
||||
}
|
||||
|
||||
public Connections getConnections() {
|
||||
return connections;
|
||||
}
|
||||
@ -66,11 +73,12 @@ public final class LimboServer {
|
||||
config = new LimboConfig(Paths.get("./"));
|
||||
config.load();
|
||||
|
||||
packetHandler = new PacketHandler(this);
|
||||
dimensionRegistry = new DimensionRegistry(this);
|
||||
dimensionRegistry.load(config.getDimensionType());
|
||||
connections = new Connections();
|
||||
|
||||
ClientConnection.initPackets(this);
|
||||
PacketSnapshots.initPackets(this);
|
||||
|
||||
startBootstrap();
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user