diff --git a/src/main/java/mc/core/netty/EventBus.java b/src/main/java/mc/core/netty/EventBus.java new file mode 100644 index 0000000..1544c15 --- /dev/null +++ b/src/main/java/mc/core/netty/EventBus.java @@ -0,0 +1,89 @@ +/* + * DmitriyMX + * 2018-03-28 + */ +package mc.core.netty; + +import io.netty.channel.Channel; +import lombok.EqualsAndHashCode; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import mc.core.Packet; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.*; + +@Slf4j +public class EventBus { + private static EventBus instance = new EventBus(); + + @RequiredArgsConstructor + @EqualsAndHashCode + private static class PairKey { + private final int stateId; + private final int packetId; + } + + @RequiredArgsConstructor + private static class PairValue { + private final Object object; + private final Method method; + } + + public interface Listener {} + + @Target(ElementType.METHOD) + @Retention(RetentionPolicy.RUNTIME) + public @interface EventHandler { + State value(); + } + + public static EventBus getInstance() { + return instance; + } + + private Map> listenersMap = new HashMap<>(); + + public void listenIncomingPacket(final Listener listener) { + Arrays.stream(listener.getClass().getDeclaredMethods()) + .filter(method -> method.isAnnotationPresent(EventHandler.class) + && method.getParameterCount() == 2 + && Packet.class.isAssignableFrom(method.getParameterTypes()[0]) + && Channel.class.isAssignableFrom(method.getParameterTypes()[1])) + .forEach(method -> { + State state = method.getAnnotation(EventHandler.class).value(); + + Class pktClass = method.getParameterTypes()[0]; + Optional optPacketId = state.getPacketId(pktClass.asSubclass(Packet.class)); + if (optPacketId.isPresent()) { + PairKey key = new PairKey( + state.getId(), + optPacketId.get() + ); + + PairValue value = new PairValue(listener, method); + + List listValues = listenersMap.computeIfAbsent(key, f -> new ArrayList<>()); + listValues.add(value); + } + }); + } + + public void eventIncomingPacket(final int stateId, final Packet packet, final Channel channel) { + List listValues = listenersMap.get(new PairKey(stateId, packet.getId())); + if (listValues != null) { + listValues.forEach(pairValue -> { + try { + pairValue.method.invoke(pairValue.object, packet, channel); + } catch (IllegalAccessException | InvocationTargetException e) { + log.error("Method invoke", e); + } + }); + } + } +} diff --git a/src/main/java/mc/core/netty/NettyServer.java b/src/main/java/mc/core/netty/NettyServer.java index 8feebcc..4b192d0 100644 --- a/src/main/java/mc/core/netty/NettyServer.java +++ b/src/main/java/mc/core/netty/NettyServer.java @@ -13,6 +13,7 @@ import io.netty.channel.socket.nio.NioServerSocketChannel; import io.netty.handler.logging.LoggingHandler; import mc.core.Server; import mc.core.StartServerException; +import mc.core.netty.handlers.HandshakeHandler; public class NettyServer implements Server { private EventLoopGroup bossGroup, workerGroup; @@ -48,6 +49,8 @@ public class NettyServer implements Server { ServerBootstrap serverBootstrap = buildServerBootstrap(); + EventBus.getInstance().listenIncomingPacket(new HandshakeHandler()); + try { serverBootstrap.bind(host, port).sync().channel().closeFuture().sync(); } catch (InterruptedException e) { diff --git a/src/main/java/mc/core/netty/PacketHandler.java b/src/main/java/mc/core/netty/PacketHandler.java index 226a7e0..56ed584 100644 --- a/src/main/java/mc/core/netty/PacketHandler.java +++ b/src/main/java/mc/core/netty/PacketHandler.java @@ -26,10 +26,10 @@ public class PacketHandler extends SimpleChannelInboundHandler { packet.getClass().getSimpleName(), packet.toString()); - if (equalsPacket(packet, "HandshakeRequestPacket")) { - HandshakeRequestPacket pkt = (HandshakeRequestPacket) packet; - context.channel().attr(State.ATTR_STATE).set(pkt.getNextState()); - context.channel().writeAndFlush(new HandshakeResponsePacket()); - } + EventBus.getInstance().eventIncomingPacket( + context.channel().attr(State.ATTR_STATE).get().getId(), + packet, + context.channel() + ); } } diff --git a/src/main/java/mc/core/netty/State.java b/src/main/java/mc/core/netty/State.java index 58e7f4f..272b72e 100644 --- a/src/main/java/mc/core/netty/State.java +++ b/src/main/java/mc/core/netty/State.java @@ -4,6 +4,8 @@ */ package mc.core.netty; +import com.google.common.collect.BiMap; +import com.google.common.collect.ImmutableBiMap; import com.google.common.collect.ImmutableMap; import io.netty.util.AttributeKey; import lombok.Getter; @@ -16,11 +18,11 @@ import java.util.Map; import java.util.Optional; public enum State { - Handshaking(1, ImmutableMap.of( + Handshaking(1, ImmutableBiMap.of( 0, HandshakeRequestPacket.class, 1, PingPacket.class )), - Status(0, ImmutableMap.of(1, PingPacket.class)); + Status(0, ImmutableBiMap.of(1, PingPacket.class)); public static final AttributeKey ATTR_STATE = AttributeKey.newInstance("ATTR_STATE"); @@ -30,9 +32,9 @@ public enum State { @Getter private final int id; - private final Map> requestMap; + private final BiMap> requestMap; - State(int id, Map> requestMap) { + State(int id, BiMap> requestMap) { this.id = id; this.requestMap = requestMap; } @@ -40,4 +42,8 @@ public enum State { public Optional> getPacketClass(int id) { return Optional.ofNullable(requestMap.get(id)); } + + public Optional getPacketId(Class clazz) { + return Optional.ofNullable(requestMap.inverse().get(clazz)); + } } diff --git a/src/main/java/mc/core/netty/handlers/HandshakeHandler.java b/src/main/java/mc/core/netty/handlers/HandshakeHandler.java new file mode 100644 index 0000000..0c55536 --- /dev/null +++ b/src/main/java/mc/core/netty/handlers/HandshakeHandler.java @@ -0,0 +1,21 @@ +/* + * DmitriyMX + * 2018-03-28 + */ +package mc.core.netty.handlers; + +import io.netty.channel.Channel; +import lombok.extern.slf4j.Slf4j; +import mc.core.netty.EventBus; +import mc.core.netty.State; +import mc.core.netty.packets.HandshakeRequestPacket; +import mc.core.netty.packets.HandshakeResponsePacket; + +@Slf4j +public class HandshakeHandler implements EventBus.Listener { + @EventBus.EventHandler(State.Handshaking) + public void onRequestHandshake(HandshakeRequestPacket packet, Channel channel) { + channel.attr(State.ATTR_STATE).set(packet.getNextState()); + channel.writeAndFlush(new HandshakeResponsePacket()); + } +}