Archived
0

повторное использование объектов Packet

This commit is contained in:
2021-05-04 18:49:24 +03:00
parent 87dc18f009
commit b77d6b16e8
20 changed files with 180 additions and 11 deletions

View File

@@ -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 = [

View File

@@ -4,6 +4,7 @@ dependencies {
api libs.netty api libs.netty
api libs.reactor api libs.reactor
implementation libs.json implementation libs.json
implementation libs.objpool
testImplementation libs.lang3 testImplementation libs.lang3
} }

View File

@@ -4,19 +4,24 @@ import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler; import io.netty.channel.SimpleChannelInboundHandler;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
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<ChannelContext> packetSinks = ctx.channel().attr(NetworkAttributes.STATE) Sinks.Many<ChannelContext> packetSinks = ctx.channel().attr(NetworkAttributes.STATE)
.get().getPacketSinks(packet.getClass()); .get().getPacketSinks(packet.getClass());
if (packetSinks != null) { if (packetSinks != null) {
packetSinks.tryEmitNext(new ChannelContext<>(ctx, packet)); packetSinks.tryEmitNext(new ChannelContext<>(ctx, packet));
} }
poolPackets.returnObject(packet);
} }
} }

View File

@@ -80,6 +80,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;

View File

@@ -13,14 +13,23 @@ import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler; import io.netty.handler.logging.LoggingHandler;
import mc.protocol.NettyServer; import mc.protocol.NettyServer;
import mc.protocol.PacketInboundHandler; import mc.protocol.PacketInboundHandler;
import mc.protocol.State;
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.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 javax.annotation.Nonnull; import javax.annotation.Nonnull;
import javax.inject.Provider; import javax.inject.Provider;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.Map; import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@Module @Module
public class ProtocolModule { public class ProtocolModule {
@@ -55,15 +64,30 @@ public class ProtocolModule {
} }
@Provides @Provides
Map<String, ChannelHandler> provideChannelHandlerMap() { Map<String, ChannelHandler> provideChannelHandlerMap(PacketPool packetPool) {
Map<String, ChannelHandler> map = new LinkedHashMap<>(); Map<String, ChannelHandler> map = new LinkedHashMap<>();
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)); map.put("packet_decoder", new ProtocolDecoder(true, packetPool));
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;
} }
@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);
}
} }

View File

@@ -10,15 +10,17 @@ import mc.protocol.State;
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 java.util.List; import java.util.List;
import java.util.Objects; import java.util.Objects;
@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;
@Override @Override
public void channelActive(ChannelHandlerContext ctx) throws Exception { public void channelActive(ChannelHandlerContext ctx) throws Exception {
@@ -43,14 +45,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);

View File

@@ -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();
} }

View File

@@ -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
}
} }

View File

@@ -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);

View File

@@ -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;
}
} }

View File

@@ -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;
} }

View File

@@ -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;
} }

View File

@@ -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;
}
} }

View File

@@ -34,4 +34,9 @@ public class LoginStartPacket implements ClientSidePacket {
this.name = netByteBuf.readString(); this.name = netByteBuf.readString();
} }
@Override
public void passivate() {
this.name = null;
}
} }

View File

@@ -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;
}
} }

View File

@@ -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;
} }

View File

@@ -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;
}
} }

View File

@@ -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;
}
} }

View File

@@ -0,0 +1,31 @@
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 {
log.info("Create {}", clazz);
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();
}
}

View 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);
}
}