Merge branch 'dev/object-pool' into dev/network-api
# Conflicts: # protocol/src/main/java/mc/protocol/PacketInboundHandler.java # protocol/src/main/java/mc/protocol/di/ProtocolModule.java # protocol/src/main/java/mc/protocol/io/codec/ProtocolDecoder.java
This commit is contained in:
@@ -19,7 +19,8 @@ ext {
|
|||||||
yaml : 'org.yaml:snakeyaml:1.28',
|
yaml : 'org.yaml:snakeyaml:1.28',
|
||||||
json : 'com.eclipsesource.minimal-json:minimal-json:0.9.5',
|
json : 'com.eclipsesource.minimal-json:minimal-json:0.9.5',
|
||||||
ioutils : 'commons-io:commons-io:2.6',
|
ioutils : 'commons-io:commons-io:2.6',
|
||||||
jopt : 'net.sf.jopt-simple:jopt-simple:6.0-alpha-3'
|
jopt : 'net.sf.jopt-simple:jopt-simple:6.0-alpha-3',
|
||||||
|
objpool : 'org.apache.commons:commons-pool2:2.9.0'
|
||||||
]
|
]
|
||||||
|
|
||||||
libs.logger = [
|
libs.logger = [
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ dependencies {
|
|||||||
|
|
||||||
implementation libs.netty
|
implementation libs.netty
|
||||||
implementation libs.json
|
implementation libs.json
|
||||||
|
implementation libs.objpool
|
||||||
|
|
||||||
testImplementation libs.lang3
|
testImplementation libs.lang3
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ import mc.protocol.api.Server;
|
|||||||
import mc.protocol.io.codec.ProtocolDecoder;
|
import mc.protocol.io.codec.ProtocolDecoder;
|
||||||
import mc.protocol.io.codec.ProtocolEncoder;
|
import mc.protocol.io.codec.ProtocolEncoder;
|
||||||
import mc.protocol.io.codec.ProtocolSplitter;
|
import mc.protocol.io.codec.ProtocolSplitter;
|
||||||
|
import mc.protocol.utils.PacketPool;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
@@ -26,6 +27,7 @@ import java.util.function.Consumer;
|
|||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class NettyServer implements Server {
|
public class NettyServer implements Server {
|
||||||
|
|
||||||
|
private final PacketPool packetPool;
|
||||||
private Consumer<ConnectionContext<?>> consumerNewConnection;
|
private Consumer<ConnectionContext<?>> consumerNewConnection;
|
||||||
private Consumer<ConnectionContext<?>> consumerDisconnect;
|
private Consumer<ConnectionContext<?>> consumerDisconnect;
|
||||||
|
|
||||||
@@ -77,9 +79,9 @@ public class NettyServer implements Server {
|
|||||||
|
|
||||||
map.put("packet_splitter", new ProtocolSplitter());
|
map.put("packet_splitter", new ProtocolSplitter());
|
||||||
map.put("logger", new LoggingHandler(LogLevel.DEBUG));
|
map.put("logger", new LoggingHandler(LogLevel.DEBUG));
|
||||||
map.put("packet_decoder", new ProtocolDecoder(true, consumerNewConnection, consumerDisconnect));
|
map.put("packet_decoder", new ProtocolDecoder(true, packetPool, consumerNewConnection, consumerDisconnect));
|
||||||
map.put("packet_encoder", new ProtocolEncoder());
|
map.put("packet_encoder", new ProtocolEncoder());
|
||||||
map.put("packet_handler", new PacketInboundHandler());
|
map.put("packet_handler", new PacketInboundHandler(packetPool));
|
||||||
|
|
||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,19 +5,24 @@ import io.netty.channel.SimpleChannelInboundHandler;
|
|||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import mc.protocol.api.ConnectionContext;
|
import mc.protocol.api.ConnectionContext;
|
||||||
import mc.protocol.packets.ClientSidePacket;
|
import mc.protocol.packets.ClientSidePacket;
|
||||||
|
import mc.protocol.utils.PacketPool;
|
||||||
import reactor.core.publisher.Sinks;
|
import reactor.core.publisher.Sinks;
|
||||||
|
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class PacketInboundHandler extends SimpleChannelInboundHandler<ClientSidePacket> {
|
public class PacketInboundHandler extends SimpleChannelInboundHandler<ClientSidePacket> {
|
||||||
|
|
||||||
|
private final PacketPool poolPackets;
|
||||||
|
|
||||||
@SuppressWarnings("rawtypes")
|
@SuppressWarnings("rawtypes")
|
||||||
@Override
|
@Override
|
||||||
protected void channelRead0(ChannelHandlerContext ctx, ClientSidePacket packet) {
|
protected void channelRead0(ChannelHandlerContext ctx, ClientSidePacket packet) throws Exception {
|
||||||
Sinks.Many<ConnectionContext> packetSinks = ctx.channel().attr(NetworkAttributes.STATE)
|
Sinks.Many<ConnectionContext> packetSinks = ctx.channel().attr(NetworkAttributes.STATE)
|
||||||
.get().getPacketSinks(packet.getClass());
|
.get().getPacketSinks(packet.getClass());
|
||||||
|
|
||||||
if (packetSinks != null) {
|
if (packetSinks != null) {
|
||||||
packetSinks.tryEmitNext(new NettyConnectionContext<>(ctx, packet));
|
packetSinks.tryEmitNext(new NettyConnectionContext<>(ctx, packet));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
poolPackets.returnObject(packet);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -81,6 +81,7 @@ public enum State {
|
|||||||
@Getter
|
@Getter
|
||||||
private final int id;
|
private final int id;
|
||||||
|
|
||||||
|
@Getter
|
||||||
private final Map<Integer, Class<? extends ClientSidePacket>> clientSidePackets;
|
private final Map<Integer, Class<? extends ClientSidePacket>> clientSidePackets;
|
||||||
private final Map<Class<? extends ServerSidePacket>, Integer> serverSidePackets;
|
private final Map<Class<? extends ServerSidePacket>, Integer> serverSidePackets;
|
||||||
|
|
||||||
|
|||||||
@@ -3,15 +3,40 @@ package mc.protocol.di;
|
|||||||
import dagger.Module;
|
import dagger.Module;
|
||||||
import dagger.Provides;
|
import dagger.Provides;
|
||||||
import mc.protocol.NettyServer;
|
import mc.protocol.NettyServer;
|
||||||
|
import mc.protocol.State;
|
||||||
import mc.protocol.api.Server;
|
import mc.protocol.api.Server;
|
||||||
|
import mc.protocol.packets.ClientSidePacket;
|
||||||
|
import mc.protocol.packets.UnknownPacket;
|
||||||
|
import mc.protocol.utils.PacketFactory;
|
||||||
|
import mc.protocol.utils.PacketPool;
|
||||||
|
import org.apache.commons.pool2.ObjectPool;
|
||||||
|
import org.apache.commons.pool2.impl.GenericObjectPool;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
@Module
|
@Module
|
||||||
public class ProtocolModule {
|
public class ProtocolModule {
|
||||||
|
|
||||||
@Provides
|
@Provides
|
||||||
@ServerScope
|
@ServerScope
|
||||||
Server provideServer() {
|
Server provideServer(PacketPool packetPool) {
|
||||||
return new NettyServer();
|
return new NettyServer(packetPool);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@ServerScope
|
||||||
|
@SuppressWarnings({ "rawtypes", "unchecked" })
|
||||||
|
PacketPool providePacketPool() {
|
||||||
|
Map<Class<? extends ClientSidePacket>, ObjectPool> map = Stream.of(State.values())
|
||||||
|
.flatMap(state -> state.getClientSidePackets().values().stream())
|
||||||
|
.distinct()
|
||||||
|
.collect(Collectors.toMap(
|
||||||
|
packetClass -> packetClass,
|
||||||
|
packetClass -> new GenericObjectPool(new PacketFactory<>(packetClass))));
|
||||||
|
map.put(UnknownPacket.class, new GenericObjectPool(new PacketFactory<>(UnknownPacket.class)));
|
||||||
|
|
||||||
|
return new PacketPool(map);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,17 +12,19 @@ import mc.protocol.api.ConnectionContext;
|
|||||||
import mc.protocol.io.NetByteBuf;
|
import mc.protocol.io.NetByteBuf;
|
||||||
import mc.protocol.packets.ClientSidePacket;
|
import mc.protocol.packets.ClientSidePacket;
|
||||||
import mc.protocol.packets.UnknownPacket;
|
import mc.protocol.packets.UnknownPacket;
|
||||||
|
import mc.protocol.utils.PacketPool;
|
||||||
|
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
@Slf4j
|
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
|
@Slf4j
|
||||||
public class ProtocolDecoder extends ByteToMessageDecoder {
|
public class ProtocolDecoder extends ByteToMessageDecoder {
|
||||||
|
|
||||||
private final boolean readUnknownPackets;
|
private final boolean readUnknownPackets;
|
||||||
|
private final PacketPool poolPackets;
|
||||||
private final Consumer<ConnectionContext<?>> consumerNewConnection;
|
private final Consumer<ConnectionContext<?>> consumerNewConnection;
|
||||||
private final Consumer<ConnectionContext<?>> consumerDisconnect;
|
private final Consumer<ConnectionContext<?>> consumerDisconnect;
|
||||||
|
|
||||||
@@ -49,14 +51,17 @@ public class ProtocolDecoder extends ByteToMessageDecoder {
|
|||||||
log.warn("Unknown packet: State {} ; Id 0x{}", state, packetIdAsHexcode(packetId));
|
log.warn("Unknown packet: State {} ; Id 0x{}", state, packetIdAsHexcode(packetId));
|
||||||
|
|
||||||
if (readUnknownPackets) {
|
if (readUnknownPackets) {
|
||||||
UnknownPacket unknownPacket = new UnknownPacket(state, packetId, netByteBuf.readableBytes());
|
UnknownPacket unknownPacket = poolPackets.borrowObject(UnknownPacket.class);
|
||||||
|
unknownPacket.setState(state);
|
||||||
|
unknownPacket.setId(packetId);
|
||||||
|
unknownPacket.setDataSize(netByteBuf.readableBytes());
|
||||||
unknownPacket.readSelf(netByteBuf);
|
unknownPacket.readSelf(netByteBuf);
|
||||||
out.add(unknownPacket);
|
out.add(unknownPacket);
|
||||||
} else {
|
} else {
|
||||||
netByteBuf.skipBytes(netByteBuf.readableBytes());
|
netByteBuf.skipBytes(netByteBuf.readableBytes());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
ClientSidePacket packet = packetClass.getDeclaredConstructor().newInstance();
|
ClientSidePacket packet = poolPackets.borrowObject(packetClass);
|
||||||
packet.readSelf(netByteBuf);
|
packet.readSelf(netByteBuf);
|
||||||
log.debug("IN: {}:{}", state, packet);
|
log.debug("IN: {}:{}", state, packet);
|
||||||
out.add(packet);
|
out.add(packet);
|
||||||
|
|||||||
@@ -8,4 +8,6 @@ import mc.protocol.io.NetByteBuf;
|
|||||||
public interface ClientSidePacket extends Packet {
|
public interface ClientSidePacket extends Packet {
|
||||||
|
|
||||||
void readSelf(NetByteBuf netByteBuf);
|
void readSelf(NetByteBuf netByteBuf);
|
||||||
|
|
||||||
|
void passivate();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,4 +13,9 @@ public abstract class EmptyPacket implements ClientSidePacket, ServerSidePacket
|
|||||||
public void writeSelf(NetByteBuf netByteBuf) {
|
public void writeSelf(NetByteBuf netByteBuf) {
|
||||||
// empty
|
// empty
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void passivate() {
|
||||||
|
// pass
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,6 +34,11 @@ public class PingPacket implements ClientSidePacket, ServerSidePacket {
|
|||||||
payload = netByteBuf.readLong();
|
payload = netByteBuf.readLong();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void passivate() {
|
||||||
|
this.payload = null;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void writeSelf(NetByteBuf netByteBuf) {
|
public void writeSelf(NetByteBuf netByteBuf) {
|
||||||
netByteBuf.writeLong(payload);
|
netByteBuf.writeLong(payload);
|
||||||
|
|||||||
@@ -1,17 +1,19 @@
|
|||||||
package mc.protocol.packets;
|
package mc.protocol.packets;
|
||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
import lombok.ToString;
|
import lombok.ToString;
|
||||||
import mc.protocol.State;
|
import mc.protocol.State;
|
||||||
import mc.protocol.io.NetByteBuf;
|
import mc.protocol.io.NetByteBuf;
|
||||||
|
|
||||||
|
@NoArgsConstructor
|
||||||
@Data
|
@Data
|
||||||
@ToString(exclude = "rawData")
|
@ToString(exclude = "rawData")
|
||||||
public class UnknownPacket implements ClientSidePacket {
|
public class UnknownPacket implements ClientSidePacket {
|
||||||
|
|
||||||
private final State state;
|
private State state;
|
||||||
private final int id;
|
private int id;
|
||||||
private final int dataSize;
|
private int dataSize;
|
||||||
private byte[] rawData;
|
private byte[] rawData;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -19,4 +21,12 @@ public class UnknownPacket implements ClientSidePacket {
|
|||||||
rawData = new byte[dataSize];
|
rawData = new byte[dataSize];
|
||||||
netByteBuf.readBytes(rawData);
|
netByteBuf.readBytes(rawData);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void passivate() {
|
||||||
|
this.state = null;
|
||||||
|
this.id = 0;
|
||||||
|
this.dataSize = 0;
|
||||||
|
this.rawData = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -51,6 +51,13 @@ public class CPlayerPositionAndLookPacket implements ClientSidePacket {
|
|||||||
this.onGround = netByteBuf.readBoolean();
|
this.onGround = netByteBuf.readBoolean();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void passivate() {
|
||||||
|
this.position = null;
|
||||||
|
this.look = null;
|
||||||
|
this.onGround = false;
|
||||||
|
}
|
||||||
|
|
||||||
public double getYPositionHead() {
|
public double getYPositionHead() {
|
||||||
return this.position.getY() + 1.62f;
|
return this.position.getY() + 1.62f;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -64,6 +64,16 @@ public class ClientSettingsPacket implements ClientSidePacket {
|
|||||||
this.mainHand = MainHand.valueById(netByteBuf.readVarInt());
|
this.mainHand = MainHand.valueById(netByteBuf.readVarInt());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void passivate() {
|
||||||
|
this.locale = null;
|
||||||
|
this.viewDistance = 0;
|
||||||
|
this.chatMode = null;
|
||||||
|
this.chatColors = false;
|
||||||
|
this.$displayedSkinPartsBitMask = 0;
|
||||||
|
this.mainHand = null;
|
||||||
|
}
|
||||||
|
|
||||||
public boolean isCapeEnabled() {
|
public boolean isCapeEnabled() {
|
||||||
return ($displayedSkinPartsBitMask & 0x01) > 0;
|
return ($displayedSkinPartsBitMask & 0x01) > 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,4 +47,12 @@ public class HandshakePacket implements ClientSidePacket {
|
|||||||
nextState = State.getById(netByteBuf.readVarInt());
|
nextState = State.getById(netByteBuf.readVarInt());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void passivate() {
|
||||||
|
this.protocolVersion = 0;
|
||||||
|
this.host = null;
|
||||||
|
this.port = 0;
|
||||||
|
this.nextState = null;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,4 +34,9 @@ public class LoginStartPacket implements ClientSidePacket {
|
|||||||
this.name = netByteBuf.readString();
|
this.name = netByteBuf.readString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void passivate() {
|
||||||
|
this.name = null;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,4 +39,10 @@ public class PlayerLookPacket implements ClientSidePacket {
|
|||||||
|
|
||||||
this.onGround = netByteBuf.readBoolean();
|
this.onGround = netByteBuf.readBoolean();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void passivate() {
|
||||||
|
this.look = null;
|
||||||
|
this.onGround = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -43,6 +43,12 @@ public class PlayerPositionPacket implements ClientSidePacket {
|
|||||||
this.onGround = netByteBuf.readBoolean();
|
this.onGround = netByteBuf.readBoolean();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void passivate() {
|
||||||
|
this.position = null;
|
||||||
|
this.onGround = false;
|
||||||
|
}
|
||||||
|
|
||||||
public double getYPositionHead() {
|
public double getYPositionHead() {
|
||||||
return this.position.getY() + 1.62f;
|
return this.position.getY() + 1.62f;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,4 +39,10 @@ public class PluginMessagePacket implements ClientSidePacket {
|
|||||||
this.rawData = new byte[netByteBuf.readableBytes()];
|
this.rawData = new byte[netByteBuf.readableBytes()];
|
||||||
netByteBuf.readBytes(this.rawData);
|
netByteBuf.readBytes(this.rawData);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void passivate() {
|
||||||
|
this.channelName = null;
|
||||||
|
this.rawData = null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,4 +33,9 @@ public class TeleportConfirmPacket implements ClientSidePacket {
|
|||||||
public void readSelf(NetByteBuf netByteBuf) {
|
public void readSelf(NetByteBuf netByteBuf) {
|
||||||
this.teleportId = netByteBuf.readVarInt();
|
this.teleportId = netByteBuf.readVarInt();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void passivate() {
|
||||||
|
this.teleportId = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
30
protocol/src/main/java/mc/protocol/utils/PacketFactory.java
Normal file
30
protocol/src/main/java/mc/protocol/utils/PacketFactory.java
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
package mc.protocol.utils;
|
||||||
|
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import mc.protocol.packets.ClientSidePacket;
|
||||||
|
import org.apache.commons.pool2.BasePooledObjectFactory;
|
||||||
|
import org.apache.commons.pool2.PooledObject;
|
||||||
|
import org.apache.commons.pool2.impl.DefaultPooledObject;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class PacketFactory<P extends ClientSidePacket> extends BasePooledObjectFactory<P> {
|
||||||
|
|
||||||
|
private final Class<P> clazz;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public P create() throws Exception {
|
||||||
|
return clazz.getDeclaredConstructor().newInstance();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public PooledObject<P> wrap(P packet) {
|
||||||
|
return new DefaultPooledObject<>(packet);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void passivateObject(PooledObject<P> pooledPacket) {
|
||||||
|
pooledPacket.getObject().passivate();
|
||||||
|
}
|
||||||
|
}
|
||||||
26
protocol/src/main/java/mc/protocol/utils/PacketPool.java
Normal file
26
protocol/src/main/java/mc/protocol/utils/PacketPool.java
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
package mc.protocol.utils;
|
||||||
|
|
||||||
|
import lombok.RequiredArgsConstructor;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import mc.protocol.packets.ClientSidePacket;
|
||||||
|
import org.apache.commons.pool2.ObjectPool;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
@Slf4j
|
||||||
|
@RequiredArgsConstructor
|
||||||
|
public class PacketPool {
|
||||||
|
|
||||||
|
@SuppressWarnings("rawtypes")
|
||||||
|
private final Map<Class<? extends ClientSidePacket>, ObjectPool> mapPoolPackets;
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public <P extends ClientSidePacket> P borrowObject(Class<P> packetClass) throws Exception {
|
||||||
|
return (P) mapPoolPackets.get(packetClass).borrowObject();
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
public <P extends ClientSidePacket> void returnObject(P packet) throws Exception {
|
||||||
|
mapPoolPackets.get(packet.getClass()).returnObject(packet);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user