forked from BLOCKFANTASY/LOOHP-Limbo
Changes to ChannelRead
This commit is contained in:
parent
31b3a954a2
commit
67f24599f2
|
|
@ -1,6 +1,5 @@
|
|||
package com.loohp.limbo.network;
|
||||
|
||||
import com.loohp.limbo.network.protocol.packets.Packet;
|
||||
import com.loohp.limbo.network.protocol.packets.PacketIn;
|
||||
import com.loohp.limbo.network.protocol.packets.PacketOut;
|
||||
import com.loohp.limbo.utils.DataTypeIO;
|
||||
|
|
@ -10,24 +9,20 @@ import com.loohp.limbo.utils.Pair;
|
|||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class Channel implements AutoCloseable {
|
||||
|
||||
private final ClientConnection clientConnection;
|
||||
private final List<Pair<NamespacedKey, ChannelPacketHandler>> handlers;
|
||||
private final AtomicBoolean valid;
|
||||
protected DataOutputStream output;
|
||||
protected DataInputStream input;
|
||||
protected final DataInputStream input;
|
||||
protected final DataOutputStream output;
|
||||
|
||||
public Channel(ClientConnection clientConnection, DataOutputStream output, DataInputStream input) {
|
||||
this.clientConnection = clientConnection;
|
||||
this.output = output;
|
||||
public Channel(DataInputStream input, DataOutputStream output) {
|
||||
this.input = input;
|
||||
this.output = output;
|
||||
this.handlers = new CopyOnWriteArrayList<>();
|
||||
this.valid = new AtomicBoolean(true);
|
||||
}
|
||||
|
|
@ -54,55 +49,20 @@ public class Channel implements AutoCloseable {
|
|||
return readPacket(-1);
|
||||
}
|
||||
|
||||
protected PacketIn readPacket(int size) throws Exception {
|
||||
protected PacketIn readPacket(int size) throws IOException {
|
||||
PacketIn packet = null;
|
||||
do {
|
||||
ensureOpen();
|
||||
size = size < 0 ? DataTypeIO.readVarInt(input) : size;
|
||||
int packetId = DataTypeIO.readVarInt(input);
|
||||
Class<? extends PacketIn> packetType;
|
||||
switch (clientConnection.getClientState()) {
|
||||
case HANDSHAKE:
|
||||
packetType = Packet.getHandshakeIn().get(packetId);
|
||||
break;
|
||||
case STATUS:
|
||||
packetType = Packet.getStatusIn().get(packetId);
|
||||
break;
|
||||
case LOGIN:
|
||||
packetType = Packet.getLoginIn().get(packetId);
|
||||
break;
|
||||
case PLAY:
|
||||
packetType = Packet.getPlayIn().get(packetId);
|
||||
break;
|
||||
default:
|
||||
throw new IllegalStateException("Illegal ClientState!");
|
||||
}
|
||||
if (packetType == null) {
|
||||
input.skipBytes(size - DataTypeIO.getVarIntLength(packetId));
|
||||
} else {
|
||||
Constructor<?>[] constructors = packetType.getConstructors();
|
||||
Constructor<?> constructor = Stream.of(constructors).filter(each -> each.getParameterCount() > 0 && each.getParameterTypes()[0].equals(DataInputStream.class)).findFirst().orElse(null);
|
||||
if (constructor == null) {
|
||||
throw new NoSuchMethodException(packetType + " has no valid constructors!");
|
||||
} else if (constructor.getParameterCount() == 1) {
|
||||
packet = (PacketIn) constructor.newInstance(input);
|
||||
} else if (constructor.getParameterCount() == 3) {
|
||||
packet = (PacketIn) constructor.newInstance(input, size, packetId);
|
||||
} else {
|
||||
throw new NoSuchMethodException(packetType + " has no valid constructors!");
|
||||
}
|
||||
ChannelPacketRead read = new ChannelPacketRead(packetId, packet);
|
||||
ChannelPacketRead read = new ChannelPacketRead(size, packetId, input);
|
||||
for (Pair<NamespacedKey, ChannelPacketHandler> pair : handlers) {
|
||||
read = pair.getSecond().read(read);
|
||||
if (read == null) {
|
||||
packet = null;
|
||||
break;
|
||||
}
|
||||
packet = read.getPacket();
|
||||
if (!packetType.isInstance(packet)) {
|
||||
throw new IllegalStateException("Packet Handler \"" + pair.getFirst() + "\" changed the packet type illegally!");
|
||||
}
|
||||
}
|
||||
packet = read.getReadPacket();
|
||||
}
|
||||
size = -1;
|
||||
} while (packet == null);
|
||||
|
|
@ -111,30 +71,12 @@ public class Channel implements AutoCloseable {
|
|||
|
||||
protected boolean writePacket(PacketOut packet) throws IOException {
|
||||
ensureOpen();
|
||||
int packetId;
|
||||
switch (clientConnection.getClientState()) {
|
||||
case STATUS:
|
||||
packetId = Packet.getStatusOut().get(packet.getClass());
|
||||
break;
|
||||
case LOGIN:
|
||||
packetId = Packet.getLoginOut().get(packet.getClass());
|
||||
break;
|
||||
case PLAY:
|
||||
packetId = Packet.getPlayOut().get(packet.getClass());
|
||||
break;
|
||||
default:
|
||||
throw new IllegalStateException("Illegal ClientState!");
|
||||
}
|
||||
Class<? extends PacketOut> packetType = packet.getClass();
|
||||
ChannelPacketWrite write = new ChannelPacketWrite(packet);
|
||||
for (Pair<NamespacedKey, ChannelPacketHandler> pair : handlers) {
|
||||
write = pair.getSecond().write(write);
|
||||
if (write == null) {
|
||||
return false;
|
||||
}
|
||||
if (!packetType.isInstance(write.getPacket())) {
|
||||
throw new IllegalStateException("Packet Handler \"" + pair.getFirst() + "\" changed the packet type illegally!");
|
||||
}
|
||||
}
|
||||
packet = write.getPacket();
|
||||
byte[] packetByte = packet.serializePacket();
|
||||
|
|
|
|||
|
|
@ -2,14 +2,28 @@ package com.loohp.limbo.network;
|
|||
|
||||
import com.loohp.limbo.network.protocol.packets.PacketIn;
|
||||
|
||||
import java.io.DataInput;
|
||||
|
||||
public final class ChannelPacketRead {
|
||||
|
||||
private int size;
|
||||
private int packetId;
|
||||
private DataInput input;
|
||||
private PacketIn packet;
|
||||
|
||||
protected ChannelPacketRead(int packetId, PacketIn packet) {
|
||||
ChannelPacketRead(int size, int packetId, DataInput input) {
|
||||
this.size = size;
|
||||
this.packetId = packetId;
|
||||
this.packet = packet;
|
||||
this.input = input;
|
||||
this.packet = null;
|
||||
}
|
||||
|
||||
public int getSize() {
|
||||
return size;
|
||||
}
|
||||
|
||||
public void setSize(int size) {
|
||||
this.size = size;
|
||||
}
|
||||
|
||||
public int getPacketId() {
|
||||
|
|
@ -20,7 +34,11 @@ public final class ChannelPacketRead {
|
|||
this.packetId = packetId;
|
||||
}
|
||||
|
||||
public PacketIn getPacket() {
|
||||
public boolean hasReadPacket() {
|
||||
return packet != null;
|
||||
}
|
||||
|
||||
public PacketIn getReadPacket() {
|
||||
return packet;
|
||||
}
|
||||
|
||||
|
|
@ -28,4 +46,8 @@ public final class ChannelPacketRead {
|
|||
this.packet = packet;
|
||||
}
|
||||
|
||||
public DataInput getDataInput() {
|
||||
return input;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ public final class ChannelPacketWrite {
|
|||
|
||||
private PacketOut packet;
|
||||
|
||||
protected ChannelPacketWrite(PacketOut packet) {
|
||||
ChannelPacketWrite(PacketOut packet) {
|
||||
this.packet = packet;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import com.loohp.limbo.events.player.PlayerSelectedSlotChangeEvent;
|
|||
import com.loohp.limbo.events.status.StatusPingEvent;
|
||||
import com.loohp.limbo.file.ServerProperties;
|
||||
import com.loohp.limbo.location.Location;
|
||||
import com.loohp.limbo.network.protocol.packets.Packet;
|
||||
import com.loohp.limbo.network.protocol.packets.PacketHandshakingIn;
|
||||
import com.loohp.limbo.network.protocol.packets.PacketIn;
|
||||
import com.loohp.limbo.network.protocol.packets.PacketLoginInLoginStart;
|
||||
|
|
@ -60,6 +61,7 @@ import com.loohp.limbo.utils.ForwardingUtils;
|
|||
import com.loohp.limbo.utils.GameMode;
|
||||
import com.loohp.limbo.utils.MojangAPIUtils;
|
||||
import com.loohp.limbo.utils.MojangAPIUtils.SkinResponse;
|
||||
import com.loohp.limbo.utils.NamespacedKey;
|
||||
import com.loohp.limbo.world.BlockPosition;
|
||||
import com.loohp.limbo.world.World;
|
||||
import net.kyori.adventure.text.Component;
|
||||
|
|
@ -71,9 +73,11 @@ import org.json.simple.JSONArray;
|
|||
import org.json.simple.JSONObject;
|
||||
import org.json.simple.parser.JSONParser;
|
||||
|
||||
import java.io.DataInput;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.net.InetAddress;
|
||||
import java.net.Socket;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
|
@ -89,11 +93,14 @@ import java.util.UUID;
|
|||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicLong;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
public class ClientConnection extends Thread {
|
||||
|
||||
private static final NamespacedKey DEFAULT_HANDLER_NAMESPACE = new NamespacedKey("default");
|
||||
|
||||
private final Random random = new Random();
|
||||
private final Socket client_socket;
|
||||
private final Socket clientSocket;
|
||||
protected Channel channel;
|
||||
private boolean running;
|
||||
private ClientState state;
|
||||
|
|
@ -105,12 +112,12 @@ public class ClientConnection extends Thread {
|
|||
private InetAddress inetAddress;
|
||||
private boolean ready;
|
||||
|
||||
public ClientConnection(Socket client_socket) {
|
||||
this.client_socket = client_socket;
|
||||
this.inetAddress = client_socket.getInetAddress();
|
||||
public ClientConnection(Socket clientSocket) {
|
||||
this.clientSocket = clientSocket;
|
||||
this.inetAddress = clientSocket.getInetAddress();
|
||||
this.lastPacketTimestamp = new AtomicLong(-1);
|
||||
this.lastKeepAlivePayLoad = new AtomicLong(-1);
|
||||
this.channel = new Channel(this, null, null);
|
||||
this.channel = null;
|
||||
this.running = false;
|
||||
this.ready = false;
|
||||
}
|
||||
|
|
@ -148,7 +155,7 @@ public class ClientConnection extends Thread {
|
|||
}
|
||||
|
||||
public Socket getSocket() {
|
||||
return client_socket;
|
||||
return clientSocket;
|
||||
}
|
||||
|
||||
public Channel getChannel() {
|
||||
|
|
@ -180,7 +187,7 @@ public class ClientConnection extends Thread {
|
|||
} catch (IOException ignored) {
|
||||
}
|
||||
try {
|
||||
client_socket.close();
|
||||
clientSocket.close();
|
||||
} catch (IOException ignored) {
|
||||
}
|
||||
}
|
||||
|
|
@ -196,27 +203,79 @@ public class ClientConnection extends Thread {
|
|||
} catch (IOException ignored) {
|
||||
}
|
||||
try {
|
||||
client_socket.close();
|
||||
clientSocket.close();
|
||||
} catch (IOException ignored) {
|
||||
}
|
||||
}
|
||||
|
||||
private void setChannel(DataInputStream input, DataOutputStream output) {
|
||||
this.channel = new Channel(input, output);
|
||||
|
||||
this.channel.addHandlerBefore(DEFAULT_HANDLER_NAMESPACE, new ChannelPacketHandler() {
|
||||
@Override
|
||||
public ChannelPacketRead read(ChannelPacketRead read) {
|
||||
if (read.hasReadPacket()) {
|
||||
return super.read(read);
|
||||
}
|
||||
try {
|
||||
DataInput input = read.getDataInput();
|
||||
int size = read.getSize();
|
||||
int packetId = read.getPacketId();
|
||||
Class<? extends PacketIn> packetType;
|
||||
switch (state) {
|
||||
case HANDSHAKE:
|
||||
packetType = Packet.getHandshakeIn().get(packetId);
|
||||
break;
|
||||
case STATUS:
|
||||
packetType = Packet.getStatusIn().get(packetId);
|
||||
break;
|
||||
case LOGIN:
|
||||
packetType = Packet.getLoginIn().get(packetId);
|
||||
break;
|
||||
case PLAY:
|
||||
packetType = Packet.getPlayIn().get(packetId);
|
||||
break;
|
||||
default:
|
||||
throw new IllegalStateException("Illegal ClientState!");
|
||||
}
|
||||
if (packetType == null) {
|
||||
input.skipBytes(size - DataTypeIO.getVarIntLength(packetId));
|
||||
return null;
|
||||
}
|
||||
Constructor<?>[] constructors = packetType.getConstructors();
|
||||
Constructor<?> constructor = Stream.of(constructors).filter(each -> each.getParameterCount() > 0 && each.getParameterTypes()[0].equals(DataInputStream.class)).findFirst().orElse(null);
|
||||
if (constructor == null) {
|
||||
throw new NoSuchMethodException(packetType + " has no valid constructors!");
|
||||
} else if (constructor.getParameterCount() == 1) {
|
||||
read.setPacket((PacketIn) constructor.newInstance(input));
|
||||
} else if (constructor.getParameterCount() == 3) {
|
||||
read.setPacket((PacketIn) constructor.newInstance(input, size, packetId));
|
||||
} else {
|
||||
throw new NoSuchMethodException(packetType + " has no valid constructors!");
|
||||
}
|
||||
return super.read(read);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Unable to read packet", e);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
@Override
|
||||
public void run() {
|
||||
running = true;
|
||||
state = ClientState.HANDSHAKE;
|
||||
try {
|
||||
client_socket.setKeepAlive(true);
|
||||
channel.input = new DataInputStream(client_socket.getInputStream());
|
||||
channel.output = new DataOutputStream(client_socket.getOutputStream());
|
||||
clientSocket.setKeepAlive(true);
|
||||
setChannel(new DataInputStream(clientSocket.getInputStream()), new DataOutputStream(clientSocket.getOutputStream()));
|
||||
int handShakeSize = DataTypeIO.readVarInt(channel.input);
|
||||
|
||||
//legacy ping
|
||||
if (handShakeSize == 0xFE) {
|
||||
state = ClientState.LEGACY;
|
||||
channel.output.writeByte(255);
|
||||
String str = inetAddress.getHostName() + ":" + client_socket.getPort();
|
||||
String str = inetAddress.getHostName() + ":" + clientSocket.getPort();
|
||||
Limbo.getInstance().getConsole().sendMessage("[/" + str + "] <-> Legacy Status has pinged");
|
||||
ServerProperties p = Limbo.getInstance().getServerProperties();
|
||||
StatusPingEvent event = Limbo.getInstance().getEventsManager().callEvent(new StatusPingEvent(this, p.getVersionString(), p.getProtocol(), p.getMotd(), p.getMaxPlayers(), Limbo.getInstance().getPlayers().size(), p.getFavicon().orElse(null)));
|
||||
|
|
@ -226,7 +285,7 @@ public class ClientConnection extends Thread {
|
|||
channel.output.write(bytes);
|
||||
|
||||
channel.close();
|
||||
client_socket.close();
|
||||
clientSocket.close();
|
||||
state = ClientState.DISCONNECTED;
|
||||
}
|
||||
|
||||
|
|
@ -243,10 +302,10 @@ public class ClientConnection extends Thread {
|
|||
switch (handshake.getHandshakeType()) {
|
||||
case STATUS:
|
||||
state = ClientState.STATUS;
|
||||
while (client_socket.isConnected()) {
|
||||
while (clientSocket.isConnected()) {
|
||||
PacketIn packetIn = channel.readPacket();
|
||||
if (packetIn instanceof PacketStatusInRequest) {
|
||||
String str = inetAddress.getHostName() + ":" + client_socket.getPort();
|
||||
String str = inetAddress.getHostName() + ":" + clientSocket.getPort();
|
||||
if (Limbo.getInstance().getServerProperties().handshakeVerboseEnabled()) {
|
||||
Limbo.getInstance().getConsole().sendMessage("[/" + str + "] <-> Handshake Status has pinged");
|
||||
}
|
||||
|
|
@ -302,7 +361,7 @@ public class ClientConnection extends Thread {
|
|||
}
|
||||
|
||||
int messageId = this.random.nextInt();
|
||||
while (client_socket.isConnected()) {
|
||||
while (clientSocket.isConnected()) {
|
||||
PacketIn packetIn = channel.readPacket();
|
||||
if (packetIn instanceof PacketLoginInLoginStart) {
|
||||
PacketLoginInLoginStart start = (PacketLoginInLoginStart) packetIn;
|
||||
|
|
@ -367,7 +426,7 @@ public class ClientConnection extends Thread {
|
|||
}
|
||||
} catch (Exception e) {
|
||||
channel.close();
|
||||
client_socket.close();
|
||||
clientSocket.close();
|
||||
state = ClientState.DISCONNECTED;
|
||||
}
|
||||
|
||||
|
|
@ -401,7 +460,7 @@ public class ClientConnection extends Thread {
|
|||
PacketPlayOutPlayerAbilities abilities = new PacketPlayOutPlayerAbilities(0.05F, 0.1F, flags.toArray(new PlayerAbilityFlags[flags.size()]));
|
||||
sendPacket(abilities);
|
||||
|
||||
String str = inetAddress.getHostName() + ":" + client_socket.getPort() + "|" + player.getName() + "(" + player.getUniqueId() + ")";
|
||||
String str = inetAddress.getHostName() + ":" + clientSocket.getPort() + "|" + player.getName() + "(" + player.getUniqueId() + ")";
|
||||
Limbo.getInstance().getConsole().sendMessage("[/" + str + "] <-> Player had connected to the Limbo server!");
|
||||
|
||||
PacketPlayOutDeclareCommands declare = DeclareCommands.getDeclareCommandsPacket(player);
|
||||
|
|
@ -465,7 +524,7 @@ public class ClientConnection extends Thread {
|
|||
};
|
||||
new Timer().schedule(keepAliveTask, 5000, 10000);
|
||||
|
||||
while (client_socket.isConnected()) {
|
||||
while (clientSocket.isConnected()) {
|
||||
try {
|
||||
CheckedBiConsumer<PlayerMoveEvent, Location, IOException> processMoveEvent = (event, originalTo) -> {
|
||||
if (event.isCancelled()) {
|
||||
|
|
@ -565,7 +624,7 @@ public class ClientConnection extends Thread {
|
|||
|
||||
Limbo.getInstance().getEventsManager().callEvent(new PlayerQuitEvent(player));
|
||||
|
||||
str = inetAddress.getHostName() + ":" + client_socket.getPort() + "|" + player.getName();
|
||||
str = inetAddress.getHostName() + ":" + clientSocket.getPort() + "|" + player.getName();
|
||||
Limbo.getInstance().getConsole().sendMessage("[/" + str + "] <-> Player had disconnected!");
|
||||
|
||||
}
|
||||
|
|
@ -575,7 +634,7 @@ public class ClientConnection extends Thread {
|
|||
|
||||
try {
|
||||
channel.close();
|
||||
client_socket.close();
|
||||
clientSocket.close();
|
||||
} catch (Exception ignored) {
|
||||
}
|
||||
state = ClientState.DISCONNECTED;
|
||||
|
|
|
|||
Loading…
Reference in New Issue