git » crow.game » commit a200710

dep specs, code style

author b0in
2023-12-07 00:37:50 UTC
committer b0in
2023-12-07 00:41:54 UTC
parent 5fd71e2dbd46645f96ab76af97dcbd131b8b3687

dep specs, code style

crow.game.codec.api/src/main/java/crow/game/codec/Context.java +37 -39
crow.game.codec.api/src/main/java/crow/game/codec/InetAddressAndPort.java +1 -4
crow.game.codec.api/src/main/java/crow/game/codec/Packet.java +1 -2
crow.game.codec.api/src/main/java/crow/game/codec/PacketHandler.java +77 -89
crow.game.codec.api/src/main/java/crow/game/codec/PacketRule.java +83 -94
crow.game.codec.api/src/main/java/crow/game/codec/package-info.java +25 -23
crow.game.codec.netty/pom.xml +0 -3
crow.game.codec.netty/src/main/java/crow/game/codec/netty/FrameCodec.java +65 -84
crow.game.codec.netty/src/main/java/crow/game/codec/netty/NettyWrappedContext.java +38 -41
crow.game.codec.netty/src/main/java/crow/game/codec/netty/PacketCodec.java +37 -55
crow.game.codec.netty/src/main/java/crow/game/codec/netty/package-info.java +1 -4
crow.game.examples.pingpong/pom.xml +4 -0
crow.game.examples.pingpong/src/main/java/crow/game/examples/pingpong/client/MainClient.java +22 -29
crow.game.examples.pingpong/src/main/java/crow/game/examples/pingpong/client/PingPongClientInitializer.java +39 -50
crow.game.examples.pingpong/src/main/java/crow/game/examples/pingpong/client/package-info.java +1 -3
crow.game.examples.pingpong/src/main/java/crow/game/examples/pingpong/proto/Constants.java +3 -3
crow.game.examples.pingpong/src/main/java/crow/game/examples/pingpong/proto/Ping.java +1 -3
crow.game.examples.pingpong/src/main/java/crow/game/examples/pingpong/proto/PingPacketHandler.java +13 -14
crow.game.examples.pingpong/src/main/java/crow/game/examples/pingpong/proto/Pong.java +1 -3
crow.game.examples.pingpong/src/main/java/crow/game/examples/pingpong/proto/PongPacketHandler.java +13 -13
crow.game.examples.pingpong/src/main/java/crow/game/examples/pingpong/proto/RootContext.java +46 -50
crow.game.examples.pingpong/src/main/java/crow/game/examples/pingpong/proto/package-info.java +13 -11
crow.game.examples.pingpong/src/main/java/crow/game/examples/pingpong/server/MainServer.java +24 -30
crow.game.examples.pingpong/src/main/java/crow/game/examples/pingpong/server/PingPongServerInitializer.java +42 -58
crow.game.examples.pingpong/src/main/java/crow/game/examples/pingpong/server/package-info.java +1 -3
crow.game.examples.pingpong/src/main/java/crow/game/examples/pingpong/utils/Main.java +13 -15
crow.game.examples.pingpong/src/main/java/crow/game/examples/pingpong/utils/PrefixThreadFactory.java +13 -17
crow.game.examples.pingpong/src/main/java/crow/game/examples/pingpong/utils/package-info.java +1 -3
pom.xml +37 -17

diff --git a/crow.game.codec.api/src/main/java/crow/game/codec/Context.java b/crow.game.codec.api/src/main/java/crow/game/codec/Context.java
index 14da0b3..0ac7523 100644
--- a/crow.game.codec.api/src/main/java/crow/game/codec/Context.java
+++ b/crow.game.codec.api/src/main/java/crow/game/codec/Context.java
@@ -4,45 +4,43 @@ import java.util.List;
 
 /**
  * Context wraps the calling context when performing packet logic.
- * <p>
- * It allows packet handlers to query details about the running system that may
- * change based on the given client, the network type, whether we are encoding
- * or decoding the packet.
+ *
+ * <p>It allows packet handlers to query details about the running system that may change based on
+ * the given client, the network type, whether we are encoding or decoding the packet.
  */
 public interface Context {
-    /**
-     * @return the current RO protocol version as an integer.
-     */
-    int supportedProtocolVersion();
-
-    List<PacketHandler<?>> lookupPacketHandler(int prefix);
-    List<PacketHandler<?>> lookupPacketHandler(Class<?> clz);
-
-    /**
-     * @return the underlying object, usually a Netty connection object.
-     */
-    Object underlyingObject();
-
-    /**
-     * @return the location of the codec workflow this context was built in.
-     */
-    Source callingSource();
-
-    /**
-     * Source determines where the context was constructed and called into. Packet Rules
-     * can be constructed in the INIT phase, the DECODE phase, or the ENCODE phase
-     * and packet handlers may want to know which is being called for now.
-     */
-    enum Source {
-        INIT,
-        DECODE,
-        ENCODE,
-    }
-
-    default boolean matchesPacketVersion(PacketRule pr) {
-        return (
-            this.supportedProtocolVersion() >= pr.minVersion() &&
-            this.supportedProtocolVersion() <= pr.maxVersion()
-        );
-    }
+  /**
+   * @return the current RO protocol version as an integer.
+   */
+  int supportedProtocolVersion();
+
+  List<PacketHandler<?>> lookupPacketHandler(int prefix);
+
+  List<PacketHandler<?>> lookupPacketHandler(Class<?> clz);
+
+  /**
+   * @return the underlying object, usually a Netty connection object.
+   */
+  Object underlyingObject();
+
+  /**
+   * @return the location of the codec workflow this context was built in.
+   */
+  Source callingSource();
+
+  /**
+   * Source determines where the context was constructed and called into. Packet Rules can be
+   * constructed in the INIT phase, the DECODE phase, or the ENCODE phase and packet handlers may
+   * want to know which is being called for now.
+   */
+  enum Source {
+    INIT,
+    DECODE,
+    ENCODE,
+  }
+
+  default boolean matchesPacketVersion(PacketRule pr) {
+    return (this.supportedProtocolVersion() >= pr.minVersion()
+        && this.supportedProtocolVersion() <= pr.maxVersion());
+  }
 }
diff --git a/crow.game.codec.api/src/main/java/crow/game/codec/InetAddressAndPort.java b/crow.game.codec.api/src/main/java/crow/game/codec/InetAddressAndPort.java
index 5038ae3..6392dfe 100644
--- a/crow.game.codec.api/src/main/java/crow/game/codec/InetAddressAndPort.java
+++ b/crow.game.codec.api/src/main/java/crow/game/codec/InetAddressAndPort.java
@@ -2,8 +2,5 @@ package crow.game.codec;
 
 import java.net.InetAddress;
 
-/**
- * Utility object for pairing the ip address and port together.
- *
- */
+/** Utility object for pairing the ip address and port together. */
 public record InetAddressAndPort(InetAddress addr, int port) {}
diff --git a/crow.game.codec.api/src/main/java/crow/game/codec/Packet.java b/crow.game.codec.api/src/main/java/crow/game/codec/Packet.java
index f47ecbc..c61f951 100644
--- a/crow.game.codec.api/src/main/java/crow/game/codec/Packet.java
+++ b/crow.game.codec.api/src/main/java/crow/game/codec/Packet.java
@@ -5,7 +5,6 @@ import io.netty.buffer.ByteBuf;
 /**
  * The packet object pairs the byte stream with the matched rule.
  *
- * The byte buffer does NOT contain the packet ID or length, that is already
- * read.
+ * <p>The byte buffer does NOT contain the packet ID or length, that is already read.
  */
 public record Packet(ByteBuf buffer, PacketRule rule) {}
diff --git a/crow.game.codec.api/src/main/java/crow/game/codec/PacketHandler.java b/crow.game.codec.api/src/main/java/crow/game/codec/PacketHandler.java
index b3715ba..dd473fb 100644
--- a/crow.game.codec.api/src/main/java/crow/game/codec/PacketHandler.java
+++ b/crow.game.codec.api/src/main/java/crow/game/codec/PacketHandler.java
@@ -5,104 +5,92 @@ import java.net.InetAddress;
 import java.net.UnknownHostException;
 
 /**
- * Interface responsible for converting to and from Packet objects to a POJO
- * type
+ * Interface responsible for converting to and from Packet objects to a POJO type
  *
  * @param <T> The POJO that maps to the given packet.
  * @see Context
  */
 public interface PacketHandler<T> {
-    /**
-     * Convert the given buffer to the type.
-     *
-     * @param ctx    The calling context.
-     * @param buffer The input buffer stream.
-     *
-     * @return The POJO object
-     *
-     * @throws Exception
-     */
-    T fromPacket(Context ctx, ByteBuf buffer) throws Exception;
+  /**
+   * Convert the given buffer to the type.
+   *
+   * @param ctx The calling context.
+   * @param buffer The input buffer stream.
+   * @return The POJO object
+   * @throws Exception
+   */
+  T fromPacket(Context ctx, ByteBuf buffer) throws Exception;
 
-    /**
-     * Writes the object of type T to the byte buffer.
-     *
-     * @param ctx    The calling context.
-     * @param buffer The destination buffer.
-     * @param src    The source object we are converting.
-     *
-     * @throws Exception
-     */
-    void toPacket(Context ctx, ByteBuf buffer, T src) throws Exception;
+  /**
+   * Writes the object of type T to the byte buffer.
+   *
+   * @param ctx The calling context.
+   * @param buffer The destination buffer.
+   * @param src The source object we are converting.
+   * @throws Exception
+   */
+  void toPacket(Context ctx, ByteBuf buffer, T src) throws Exception;
 
-    /**
-     * @see PacketRule
-     *
-     * @param ctx The calling context.
-     * @return The packet rule object which specifies when this packet handler
-     *         should be called.
-     */
-    PacketRule rule(Context ctx);
+  /**
+   * @see PacketRule
+   * @param ctx The calling context.
+   * @return The packet rule object which specifies when this packet handler should be called.
+   */
+  PacketRule rule(Context ctx);
 
-    /**
-     * Parses the address and port pair from the kro server byte stream.
-     *
-     * @param buf The input buffer.
-     * @return The IP address and port pair
-     * @see InetAddressAndPort
-     * @throws UnknownHostException
-     */
-    static InetAddressAndPort readInetAddressAndPort(ByteBuf buf)
-        throws UnknownHostException {
-        byte[] addrBuf = new byte[4];
-        buf.readBytes(addrBuf);
+  /**
+   * Parses the address and port pair from the kro server byte stream.
+   *
+   * @param buf The input buffer.
+   * @return The IP address and port pair
+   * @see InetAddressAndPort
+   * @throws UnknownHostException
+   */
+  static InetAddressAndPort readInetAddressAndPort(ByteBuf buf) throws UnknownHostException {
+    byte[] addrBuf = new byte[4];
+    buf.readBytes(addrBuf);
 
-        InetAddress address = InetAddress.getByAddress(addrBuf);
-        int port = buf.readShort();
-        return new InetAddressAndPort(address, port);
-    }
+    InetAddress address = InetAddress.getByAddress(addrBuf);
+    int port = buf.readShort();
+    return new InetAddressAndPort(address, port);
+  }
 
-    /**
-     * Reads the string from the byte buffer. The byte buffer is read fully so you
-     * must pass in a sliced buffer of the given size.
-     * <p>
-     * Usage:
-     * <p>
-     * {@code
-     * 		PacketHandler.readStr(buffer.readSlice(N));
-     * }
-     * <br/>
-     * where N is the length of the string field in the packet.
-     *
-     * <p>
-     * NOTE:Strings in KRO are 0-terminated and use pre-determined lengths. So
-     * "hello" of length 20 will be "hello" 0x0 0x0 0x0...
-     *
-     * @param buf The byte buffer to read from.
-     * @return The string object.
-     */
-    static String readStr(ByteBuf buf) {
-        byte x = 0;
-        StringBuffer out = new StringBuffer();
-        do {
-            x = buf.readByte();
-            if (x != 0) {
-                out.append((char) x);
-            }
-        } while (x != 0);
-        return out.toString();
-    }
+  /**
+   * Reads the string from the byte buffer. The byte buffer is read fully so you must pass in a
+   * sliced buffer of the given size.
+   *
+   * <p>Usage:
+   *
+   * <p>{@code PacketHandler.readStr(buffer.readSlice(N)); } <br>
+   * where N is the length of the string field in the packet.
+   *
+   * <p>NOTE:Strings in KRO are 0-terminated and use pre-determined lengths. So "hello" of length 20
+   * will be "hello" 0x0 0x0 0x0...
+   *
+   * @param buf The byte buffer to read from.
+   * @return The string object.
+   */
+  static String readStr(ByteBuf buf) {
+    byte x = 0;
+    StringBuffer out = new StringBuffer();
+    do {
+      x = buf.readByte();
+      if (x != 0) {
+        out.append((char) x);
+      }
+    } while (x != 0);
+    return out.toString();
+  }
 
-    /**
-     * Writes the string to the given byte buffer, padding the given 0 bytes based
-     * on the length.
-     *
-     * @param buf The buffer to write to.
-     * @param str The string to write.
-     * @param len The length of the string in the byte stream.
-     */
-    static void writeStr(ByteBuf buf, String str, int len) {
-        buf.writeBytes(str.getBytes());
-        buf.writeZero(len - str.length());
-    }
+  /**
+   * Writes the string to the given byte buffer, padding the given 0 bytes based on the length.
+   *
+   * @param buf The buffer to write to.
+   * @param str The string to write.
+   * @param len The length of the string in the byte stream.
+   */
+  static void writeStr(ByteBuf buf, String str, int len) {
+    buf.writeBytes(str.getBytes());
+    buf.writeZero(len - str.length());
+  }
 }
diff --git a/crow.game.codec.api/src/main/java/crow/game/codec/PacketRule.java b/crow.game.codec.api/src/main/java/crow/game/codec/PacketRule.java
index 6c0136d..3a3caaa 100644
--- a/crow.game.codec.api/src/main/java/crow/game/codec/PacketRule.java
+++ b/crow.game.codec.api/src/main/java/crow/game/codec/PacketRule.java
@@ -1,105 +1,94 @@
 package crow.game.codec;
 
 /**
- * Represents a specification for which packet ID (labeled 'prefix' here) is of
- * what type (STATIC or DYNAMIC), what name and Java class POJO, and what kRO
- * packet version the POJO maps to.
- *
+ * Represents a specification for which packet ID (labeled 'prefix' here) is of what type (STATIC or
+ * DYNAMIC), what name and Java class POJO, and what kRO packet version the POJO maps to.
  */
 public record PacketRule(
-    int minVersion, int maxVersion, short prefix, int data, Type type, String name, Class<?> clz
-) {
-    /**
-     * The type of packet, currently only 2. see classdoc.
-     */
-    public enum Type {
-        STATIC,
-        DYNAMIC,
-    }
+    int minVersion, int maxVersion, short prefix, int data, Type type, String name, Class<?> clz) {
+  /** The type of packet, currently only 2. see classdoc. */
+  public enum Type {
+    STATIC,
+    DYNAMIC,
+  }
 
-    /**
-     * Simpler packet rule constructor.
-     *
-     * @param prefix The 2-byte code prefix for matching the packet.
-     * @param data The static or dynamic size tag indicator.
-     * @param type The type of the packet, STATIC or DYNAMIC
-     * @param clz The class of the POJO we are serializing and deserializing.
-     */
-    public PacketRule(short prefix, int data, Type type, Class<?> clz) {
-        this(-1, -1, prefix, data, type, clz.getSimpleName(), clz);
-    }
+  /**
+   * Simpler packet rule constructor.
+   *
+   * @param prefix The 2-byte code prefix for matching the packet.
+   * @param data The static or dynamic size tag indicator.
+   * @param type The type of the packet, STATIC or DYNAMIC
+   * @param clz The class of the POJO we are serializing and deserializing.
+   */
+  public PacketRule(short prefix, int data, Type type, Class<?> clz) {
+    this(-1, -1, prefix, data, type, clz.getSimpleName(), clz);
+  }
 
-    /**
-     * Simpler packet rule constructor.
-     *
-     * @param prefix The 2-byte code prefix for matching the packet.
-     * @param data The static or dynamic size tag indicator.
-     * @param type The type of the packet, STATIC or DYNAMIC
-     * @param name The name of the packet, currently only for logging.
-     * @param clz The class of the POJO we are serializing and deserializing.
-     */
-    public PacketRule(
-        short prefix,
-        int data,
-        Type type,
-        String name,
-        Class<?> clz
-    ) {
-        this(-1, -1, prefix, data, type, name, clz);
-    }
+  /**
+   * Simpler packet rule constructor.
+   *
+   * @param prefix The 2-byte code prefix for matching the packet.
+   * @param data The static or dynamic size tag indicator.
+   * @param type The type of the packet, STATIC or DYNAMIC
+   * @param name The name of the packet, currently only for logging.
+   * @param clz The class of the POJO we are serializing and deserializing.
+   */
+  public PacketRule(short prefix, int data, Type type, String name, Class<?> clz) {
+    this(-1, -1, prefix, data, type, name, clz);
+  }
 
-    /**
-     * Packet rule constructor.
-     *
-     * @param minVersion the min version, in YYYYMMDD format, or -1 for "as early as possible".
-     * @param maxVersion the maximum packet version this rule supports, in YYYYMMDD format, or -1 for "most recent"
-     * @param prefix The 2-byte code prefix for matching the packet.
-     * @param data The static or dynamic size tag indicator.
-     * @param type The type of the packet, STATIC or DYNAMIC
-     * @param name The name of the packet, currently only for logging.
-     * @param clz The class of the POJO we are serializing and deserializing.
-     */
-    public PacketRule(
-        int minVersion,
-        int maxVersion,
-        short prefix,
-        int data,
-        Type type,
-        String name,
-        Class<?> clz
-    ) {
-        this.minVersion = minVersion == -1 ? 19990101 : minVersion;
-        this.maxVersion = maxVersion == -1 ? 30000101 : maxVersion;
-        this.prefix = prefix;
-        this.data = data;
-        this.type = type;
-        this.name = name;
-        this.clz = clz;
-    }
+  /**
+   * Packet rule constructor.
+   *
+   * @param minVersion the min version, in YYYYMMDD format, or -1 for "as early as possible".
+   * @param maxVersion the maximum packet version this rule supports, in YYYYMMDD format, or -1 for
+   *     "most recent"
+   * @param prefix The 2-byte code prefix for matching the packet.
+   * @param data The static or dynamic size tag indicator.
+   * @param type The type of the packet, STATIC or DYNAMIC
+   * @param name The name of the packet, currently only for logging.
+   * @param clz The class of the POJO we are serializing and deserializing.
+   */
+  public PacketRule(
+      int minVersion,
+      int maxVersion,
+      short prefix,
+      int data,
+      Type type,
+      String name,
+      Class<?> clz) {
+    this.minVersion = minVersion == -1 ? 19990101 : minVersion;
+    this.maxVersion = maxVersion == -1 ? 30000101 : maxVersion;
+    this.prefix = prefix;
+    this.data = data;
+    this.type = type;
+    this.name = name;
+    this.clz = clz;
+  }
 
-    /**
-     * Utility constructor for building a non-packet version specific dynamic packet
-     * whose name is derived from the given class.
-     *
-     * @param prefix The 2-byte code prefix for matching the packet.
-     * @param sizeTag The size of the following "packet size" indicator, 2 or 4.
-     * @param clz The class that we are serializing and deserializing.
-     * @return The packet rule object.
-     */
-    public static PacketRule Dynamic(short prefix, int sizeTag, Class<?> clz) {
-        return new PacketRule(prefix, sizeTag, Type.DYNAMIC, clz);
-    }
+  /**
+   * Utility constructor for building a non-packet version specific dynamic packet whose name is
+   * derived from the given class.
+   *
+   * @param prefix The 2-byte code prefix for matching the packet.
+   * @param sizeTag The size of the following "packet size" indicator, 2 or 4.
+   * @param clz The class that we are serializing and deserializing.
+   * @return The packet rule object.
+   */
+  public static PacketRule Dynamic(short prefix, int sizeTag, Class<?> clz) {
+    return new PacketRule(prefix, sizeTag, Type.DYNAMIC, clz);
+  }
 
-    /**
-     * Utility constructor for building a non-packet version specific static packet
-     * whose name is derived from the given class.
-     *
-     * @param prefix The 2-byte code prefix for matching the packet.
-     * @param size The size of the following full packet.
-     * @param clz The class that we are serializing and deserializing.
-     * @return The packet rule object.
-     */
-    public static PacketRule Static(short prefix, int size, Class<?> clz) {
-        return new PacketRule(prefix, size, Type.STATIC, clz);
-    }
+  /**
+   * Utility constructor for building a non-packet version specific static packet whose name is
+   * derived from the given class.
+   *
+   * @param prefix The 2-byte code prefix for matching the packet.
+   * @param size The size of the following full packet.
+   * @param clz The class that we are serializing and deserializing.
+   * @return The packet rule object.
+   */
+  public static PacketRule Static(short prefix, int size, Class<?> clz) {
+    return new PacketRule(prefix, size, Type.STATIC, clz);
+  }
 }
diff --git a/crow.game.codec.api/src/main/java/crow/game/codec/package-info.java b/crow.game.codec.api/src/main/java/crow/game/codec/package-info.java
index a7e5470..b4b4345 100644
--- a/crow.game.codec.api/src/main/java/crow/game/codec/package-info.java
+++ b/crow.game.codec.api/src/main/java/crow/game/codec/package-info.java
@@ -1,27 +1,29 @@
 /**
  * Package containing the base API objects for the protocol implementation.
- * <p>
- * This API is currently tied to Netty {@link io.netty.buffer.ByteBuf} but is
- * otherwise decoupled from Netty. sub-package contains the Netty-specific code
- * for building {@link crow.game.codec.Packet} objects.
- * <p>
- * TODO: switch to {@link java.nio.ByteBuffer} which can remove the netty dependency.
- * <p>
- * There are multiple hooks for handling differing packet versions in this API:
- * <p>
- * You can define your POJO as "MyPacket20NN0101" alongside {@link crow.game.codec.PacketHandler} "MyPacketHandler20NN0101"
- * that returns a {@link crow.game.codec.PacketRule} with the version specifiers enabled.
- * <p>
- * Then you would have a second POJO that maps to everything that the previous packet did not.
- * <p>
- * OR
- * <p>
- * You can define a standard packet "MyPacket" and {@link crow.game.codec.PacketHandler} "MyPacketHandle"
- * that, when you recieve calls into your handler, you can look at the current packet version
- * via {@link crow.game.codec.Context}.supportedProtocolVersion and act accordingly via branching logic.
- * <p>
- * Implementors note: It's a long shot but maybe it will be possible to support multiple protocol versions in the same
- * running server, via client version identification and pinning, then {@link crow.game.codec.Context}
- * may contain additional account and client info attached.
+ *
+ * <p>This API is currently tied to Netty {@link io.netty.buffer.ByteBuf} but is otherwise decoupled
+ * from Netty. sub-package contains the Netty-specific code for building {@link
+ * crow.game.codec.Packet} objects.
+ *
+ * <p>TODO: switch to {@link java.nio.ByteBuffer} which can remove the netty dependency.
+ *
+ * <p>There are multiple hooks for handling differing packet versions in this API:
+ *
+ * <p>You can define your POJO as "MyPacket20NN0101" alongside {@link crow.game.codec.PacketHandler}
+ * "MyPacketHandler20NN0101" that returns a {@link crow.game.codec.PacketRule} with the version
+ * specifiers enabled.
+ *
+ * <p>Then you would have a second POJO that maps to everything that the previous packet did not.
+ *
+ * <p>OR
+ *
+ * <p>You can define a standard packet "MyPacket" and {@link crow.game.codec.PacketHandler}
+ * "MyPacketHandle" that, when you recieve calls into your handler, you can look at the current
+ * packet version via {@link crow.game.codec.Context}.supportedProtocolVersion and act accordingly
+ * via branching logic.
+ *
+ * <p>Implementors note: It's a long shot but maybe it will be possible to support multiple protocol
+ * versions in the same running server, via client version identification and pinning, then {@link
+ * crow.game.codec.Context} may contain additional account and client info attached.
  */
 package crow.game.codec;
diff --git a/crow.game.codec.netty/pom.xml b/crow.game.codec.netty/pom.xml
index ec58861..643267a 100644
--- a/crow.game.codec.netty/pom.xml
+++ b/crow.game.codec.netty/pom.xml
@@ -17,13 +17,10 @@
     <dependency>
       <groupId>io.netty</groupId>
       <artifactId>netty-buffer</artifactId>
-      <version>4.1.101.Final</version>
     </dependency>
     <dependency>
       <groupId>org.slf4j</groupId>
       <artifactId>slf4j-api</artifactId>
-      <version>1.7.35</version>
-      <scope>provided</scope>
     </dependency>
   </dependencies>
 </project>
diff --git a/crow.game.codec.netty/src/main/java/crow/game/codec/netty/FrameCodec.java b/crow.game.codec.netty/src/main/java/crow/game/codec/netty/FrameCodec.java
index 6af1a9d..1742f41 100644
--- a/crow.game.codec.netty/src/main/java/crow/game/codec/netty/FrameCodec.java
+++ b/crow.game.codec.netty/src/main/java/crow/game/codec/netty/FrameCodec.java
@@ -14,9 +14,9 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 /**
- * The FrameCodec converts to and from {@link ByteBuf} streams into individual
- * {@link crow.game.codec.Packet} objects. The first two bytes of a packet determine which type
- * of packet it is (called the packet ID).
+ * The FrameCodec converts to and from {@link ByteBuf} streams into individual {@link
+ * crow.game.codec.Packet} objects. The first two bytes of a packet determine which type of packet
+ * it is (called the packet ID).
  *
  * @see crow.game.codec.PacketRule
  * @see crow.game.codec.Packet
@@ -24,99 +24,80 @@ import org.slf4j.LoggerFactory;
  */
 public class FrameCodec extends ByteToMessageCodec<Packet> {
 
-    static Logger logger = LoggerFactory.getLogger(FrameCodec.class);
+  static Logger logger = LoggerFactory.getLogger(FrameCodec.class);
 
-    //
-    protected final Context context;
+  //
+  protected final Context context;
 
-    public FrameCodec(Context context) {
-        this.context = context;
-    }
+  public FrameCodec(Context context) {
+    this.context = context;
+  }
 
-    protected boolean packetRuleHasMoreData(ByteBuf in, PacketRule pr) {
-        PacketRule.Type s = pr.type();
-        return switch (s) {
-            case DYNAMIC -> true;
-            case STATIC -> pr.data() <= in.readableBytes() + 2;
-        };
-    }
+  protected boolean packetRuleHasMoreData(ByteBuf in, PacketRule pr) {
+    PacketRule.Type s = pr.type();
+    return switch (s) {
+      case DYNAMIC -> true;
+      case STATIC -> pr.data() <= in.readableBytes() + 2;
+    };
+  }
+
+  protected Optional<PacketRule> resolvePacketRule(Context ctx, int prefix, ByteBuf in) {
+    return ctx.lookupPacketHandler(prefix).stream() //
+        .map(((PacketHandler<?> ph) -> ph.rule(ctx)))
+        .filter((PacketRule pr) -> ctx.matchesPacketVersion(pr))
+        .filter((PacketRule pr) -> packetRuleHasMoreData(in, pr))
+        .findFirst();
+  }
+
+  @Override
+  protected void encode(ChannelHandlerContext ctx, Packet msg, ByteBuf out) {
+    PacketRule pr = msg.rule();
 
-    protected Optional<PacketRule> resolvePacketRule(
-        Context ctx,
-        int prefix,
-        ByteBuf in
-    ) {
-        return ctx
-            .lookupPacketHandler(prefix)
-            .stream() //
-            .map(((PacketHandler<?> ph) -> ph.rule(ctx)))
-            .filter((PacketRule pr) -> ctx.matchesPacketVersion(pr))
-            .filter((PacketRule pr) -> packetRuleHasMoreData(in, pr))
-            .findFirst();
+    short prefix = pr.prefix();
+    out.writeShortLE(prefix);
+    if (pr.type() == PacketRule.Type.DYNAMIC) {
+      if (pr.data() == 2) {
+        out.writeShortLE(msg.buffer().readableBytes() + 2);
+      } else {
+        out.writeIntLE(msg.buffer().readableBytes() + 4);
+      }
     }
 
-    @Override
-    protected void encode(ChannelHandlerContext ctx, Packet msg, ByteBuf out) {
-        PacketRule pr = msg.rule();
+    out.writeBytes(msg.buffer());
+  }
 
-        short prefix = pr.prefix();
-        out.writeShortLE(prefix);
-        if (pr.type() == PacketRule.Type.DYNAMIC) {
-            if (pr.data() == 2) {
-                out.writeShortLE(msg.buffer().readableBytes() + 2);
-            } else {
-                out.writeIntLE(msg.buffer().readableBytes() + 4);
-            }
-        }
+  @Override
+  protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) {
+    short x = in.getShortLE(in.readerIndex());
+    String readableX = String.format("0x%x", x);
+    Context wrapped = new NettyWrappedContext(Context.Source.DECODE, this.context, ctx);
 
-        out.writeBytes(msg.buffer());
+    Optional<PacketRule> rule = resolvePacketRule(wrapped, x, in);
+    if (rule.isEmpty()) {
+      logger.warn("no packet rule for {} - {}", readableX, x);
+      throw new UnsupportedMessageTypeException();
     }
 
-    @Override
-    protected void decode(
-        ChannelHandlerContext ctx,
-        ByteBuf in,
-        List<Object> out
-    ) {
-        short x = in.getShortLE(in.readerIndex());
-        String readableX = String.format("0x%x", x);
-        Context wrapped = new NettyWrappedContext(
-            Context.Source.DECODE,
-            this.context,
-            ctx
-        );
+    PacketRule packetRule = rule.get();
 
-        Optional<PacketRule> rule = resolvePacketRule(wrapped, x, in);
-        if (rule.isEmpty()) {
-            logger.warn("no packet rule for {} - {}", readableX, x);
-            throw new UnsupportedMessageTypeException();
+    if (packetRule.type().equals(PacketRule.Type.STATIC)) {
+      out.add(new Packet(in.readBytes(rule.get().data() + 2).copy(), rule.get()));
+    } else {
+      int size = -1;
+      // all packets sizes are just the 2 or 4 byte words AFTER the packet id
+      if (packetRule.data() == 2) {
+        if (in.readableBytes() >= 2 + 2) {
+          size = in.getShortLE(in.readerIndex() + 2);
         }
-
-        PacketRule packetRule = rule.get();
-
-        if (packetRule.type().equals(PacketRule.Type.STATIC)) {
-            out.add(
-                new Packet(
-                    in.readBytes(rule.get().data() + 2).copy(),
-                    rule.get()
-                )
-            );
-        } else {
-            int size = -1;
-            // all packets sizes are just the 2 or 4 byte words AFTER the packet id
-            if (packetRule.data() == 2) {
-                if (in.readableBytes() >= 2 + 2) {
-                    size = in.getShortLE(in.readerIndex() + 2);
-                }
-            } else {
-                if (in.readableBytes() > 2 + 4) {
-                    size = in.getIntLE(in.readerIndex() + 2);
-                }
-            }
-            if (in.readableBytes() < 2 + size) {
-                return;
-            }
-            out.add(new Packet(in.readBytes(size), rule.get()));
+      } else {
+        if (in.readableBytes() > 2 + 4) {
+          size = in.getIntLE(in.readerIndex() + 2);
         }
+      }
+      if (in.readableBytes() < 2 + size) {
+        return;
+      }
+      out.add(new Packet(in.readBytes(size), rule.get()));
     }
+  }
 }
diff --git a/crow.game.codec.netty/src/main/java/crow/game/codec/netty/NettyWrappedContext.java b/crow.game.codec.netty/src/main/java/crow/game/codec/netty/NettyWrappedContext.java
index 09e1bb6..ffe6e70 100644
--- a/crow.game.codec.netty/src/main/java/crow/game/codec/netty/NettyWrappedContext.java
+++ b/crow.game.codec.netty/src/main/java/crow/game/codec/netty/NettyWrappedContext.java
@@ -6,48 +6,45 @@ import io.netty.channel.ChannelHandlerContext;
 import java.util.List;
 
 /**
- * Implementation of {@link Context} which wraps an upper-level context and sets the
- * {@link crow.game.codec.Context.Source} to the given value and sets the underlying object to an
- * instance of {@link ChannelHandlerContext}.
+ * Implementation of {@link Context} which wraps an upper-level context and sets the {@link
+ * crow.game.codec.Context.Source} to the given value and sets the underlying object to an instance
+ * of {@link ChannelHandlerContext}.
  */
 public class NettyWrappedContext implements Context {
 
-    protected final Context context;
-    protected final ChannelHandlerContext nettyContext;
-    protected final Context.Source source;
-
-    public NettyWrappedContext(
-        Context.Source src,
-        Context context,
-        ChannelHandlerContext nettyContext
-    ) {
-        this.context = context;
-        this.nettyContext = nettyContext;
-        this.source = src;
-    }
-
-    @Override
-    public int supportedProtocolVersion() {
-        return this.context.supportedProtocolVersion();
-    }
-
-    @Override
-    public List<PacketHandler<?>> lookupPacketHandler(Class<?> clz) {
-        return this.context.lookupPacketHandler(clz);
-    }
-
-    @Override
-    public List<PacketHandler<?>> lookupPacketHandler(int prefix) {
-        return this.context.lookupPacketHandler(prefix);
-    }
-
-    @Override
-    public Object underlyingObject() {
-        return this.nettyContext;
-    }
-
-    @Override
-    public Source callingSource() {
-        return this.source;
-    }
+  protected final Context context;
+  protected final ChannelHandlerContext nettyContext;
+  protected final Context.Source source;
+
+  public NettyWrappedContext(
+      Context.Source src, Context context, ChannelHandlerContext nettyContext) {
+    this.context = context;
+    this.nettyContext = nettyContext;
+    this.source = src;
+  }
+
+  @Override
+  public int supportedProtocolVersion() {
+    return this.context.supportedProtocolVersion();
+  }
+
+  @Override
+  public List<PacketHandler<?>> lookupPacketHandler(Class<?> clz) {
+    return this.context.lookupPacketHandler(clz);
+  }
+
+  @Override
+  public List<PacketHandler<?>> lookupPacketHandler(int prefix) {
+    return this.context.lookupPacketHandler(prefix);
+  }
+
+  @Override
+  public Object underlyingObject() {
+    return this.nettyContext;
+  }
+
+  @Override
+  public Source callingSource() {
+    return this.source;
+  }
 }
diff --git a/crow.game.codec.netty/src/main/java/crow/game/codec/netty/PacketCodec.java b/crow.game.codec.netty/src/main/java/crow/game/codec/netty/PacketCodec.java
index 3e9e912..80472ad 100644
--- a/crow.game.codec.netty/src/main/java/crow/game/codec/netty/PacketCodec.java
+++ b/crow.game.codec.netty/src/main/java/crow/game/codec/netty/PacketCodec.java
@@ -15,62 +15,44 @@ import java.util.List;
  */
 public class PacketCodec extends MessageToMessageCodec<Packet, Object> {
 
-    protected final Context context;
-
-    public PacketCodec(Context ctx) {
-        this.context = ctx;
-    }
-
-    @Override
-    protected void decode(
-        ChannelHandlerContext ctx,
-        Packet msg,
-        List<Object> out
-    ) throws Exception {
-        Context wrCtx = new NettyWrappedContext(
-            Context.Source.DECODE,
-            context,
-            ctx
-        );
-        PacketHandler<?> h =
-            (
-                wrCtx
-                    .lookupPacketHandler(msg.rule().prefix()) //
-                    .stream() //
-                    .filter(hx -> wrCtx.matchesPacketVersion(hx.rule(wrCtx))) //
-                    .findFirst() //
-                    .orElseThrow()
-            );
-
-        msg.buffer().readShortLE(); // drop the packet ID
-        out.add(h.fromPacket(wrCtx, msg.buffer()));
-    }
-
-    @Override
-    protected void encode(
-        ChannelHandlerContext ctx,
-        Object msg,
-        List<Object> out
-    ) throws Exception {
-        Context wrCtx = new NettyWrappedContext(
-            Context.Source.ENCODE,
-            this.context,
-            ctx
-        );
-
-        @SuppressWarnings("unchecked")
-        PacketHandler<Object> h = (PacketHandler<Object>) wrCtx
-            .lookupPacketHandler(msg.getClass())
+  protected final Context context;
+
+  public PacketCodec(Context ctx) {
+    this.context = ctx;
+  }
+
+  @Override
+  protected void decode(ChannelHandlerContext ctx, Packet msg, List<Object> out) throws Exception {
+    Context wrCtx = new NettyWrappedContext(Context.Source.DECODE, context, ctx);
+    PacketHandler<?> h =
+        (wrCtx
+            .lookupPacketHandler(msg.rule().prefix()) //
             .stream() //
             .filter(hx -> wrCtx.matchesPacketVersion(hx.rule(wrCtx))) //
             .findFirst() //
-            .orElseThrow();
-
-        // TODO: idk, pool this? use better buffer sizes??
-        // TODO: does this leak
-        ByteBuf directBuffer = Unpooled.directBuffer(1024);
-
-        h.toPacket(wrCtx, directBuffer, msg);
-        out.add(new Packet(directBuffer, h.rule(wrCtx)));
-    }
+            .orElseThrow());
+
+    msg.buffer().readShortLE(); // drop the packet ID
+    out.add(h.fromPacket(wrCtx, msg.buffer()));
+  }
+
+  @Override
+  protected void encode(ChannelHandlerContext ctx, Object msg, List<Object> out) throws Exception {
+    Context wrCtx = new NettyWrappedContext(Context.Source.ENCODE, this.context, ctx);
+
+    @SuppressWarnings("unchecked")
+    PacketHandler<Object> h =
+        (PacketHandler<Object>)
+            wrCtx.lookupPacketHandler(msg.getClass()).stream() //
+                .filter(hx -> wrCtx.matchesPacketVersion(hx.rule(wrCtx))) //
+                .findFirst() //
+                .orElseThrow();
+
+    // TODO: idk, pool this? use better buffer sizes??
+    // TODO: does this leak
+    ByteBuf directBuffer = Unpooled.directBuffer(1024);
+
+    h.toPacket(wrCtx, directBuffer, msg);
+    out.add(new Packet(directBuffer, h.rule(wrCtx)));
+  }
 }
diff --git a/crow.game.codec.netty/src/main/java/crow/game/codec/netty/package-info.java b/crow.game.codec.netty/src/main/java/crow/game/codec/netty/package-info.java
index 92c9c67..3d13680 100644
--- a/crow.game.codec.netty/src/main/java/crow/game/codec/netty/package-info.java
+++ b/crow.game.codec.netty/src/main/java/crow/game/codec/netty/package-info.java
@@ -1,5 +1,2 @@
-/**
- * Package containing all the serialization and deserialization logic for the
- * protocol.
- */
+/** Package containing all the serialization and deserialization logic for the protocol. */
 package crow.game.codec.netty;
diff --git a/crow.game.examples.pingpong/pom.xml b/crow.game.examples.pingpong/pom.xml
index 334750c..60b06a4 100644
--- a/crow.game.examples.pingpong/pom.xml
+++ b/crow.game.examples.pingpong/pom.xml
@@ -24,5 +24,9 @@
       <artifactId>slf4j-simple</artifactId>
       <version>1.7.36</version>
     </dependency>
+    <dependency>
+      <groupId>io.netty</groupId>
+      <artifactId>netty-handler</artifactId>
+    </dependency>
   </dependencies>
 </project>
diff --git a/crow.game.examples.pingpong/src/main/java/crow/game/examples/pingpong/client/MainClient.java b/crow.game.examples.pingpong/src/main/java/crow/game/examples/pingpong/client/MainClient.java
index 7287ebc..d383914 100644
--- a/crow.game.examples.pingpong/src/main/java/crow/game/examples/pingpong/client/MainClient.java
+++ b/crow.game.examples.pingpong/src/main/java/crow/game/examples/pingpong/client/MainClient.java
@@ -13,43 +13,36 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 /**
- * This wraps the client into a runnable that can be run as a main entrypoint
- * OR passed into a Thread.
+ * This wraps the client into a runnable that can be run as a main entrypoint OR passed into a
+ * Thread.
  *
  * @see crow.game.examples.pingpong.utils.Main
  */
 public class MainClient implements Runnable {
 
-    protected static final Logger logger = LoggerFactory.getLogger(
-        MainClient.class
-    );
+  protected static final Logger logger = LoggerFactory.getLogger(MainClient.class);
 
-    public static void main(String[] args) {
-        new MainClient().run();
-    }
+  public static void main(String[] args) {
+    new MainClient().run();
+  }
 
-    public void run() {
-        EventLoopGroup workerGroup = new NioEventLoopGroup(
-            new PrefixThreadFactory("client-worker")
-        );
-        Context context = new RootContext();
-        try {
-            Bootstrap b = new Bootstrap(); //
+  public void run() {
+    EventLoopGroup workerGroup = new NioEventLoopGroup(new PrefixThreadFactory("client-worker"));
+    Context context = new RootContext();
+    try {
+      Bootstrap b = new Bootstrap(); //
 
-            b
-                .group(workerGroup) //
-                .channel(NioSocketChannel.class) //
-                .handler(new PingPongClientInitializer(context));
+      b.group(workerGroup) //
+          .channel(NioSocketChannel.class) //
+          .handler(new PingPongClientInitializer(context));
 
-            ChannelFuture f = b
-                .connect("127.0.0.1", Constants.LISTEN_PORT)
-                .sync();
-            f.channel().closeFuture().sync();
-        } catch (InterruptedException e) {
-            //e.printStackTrace();
-        } finally {
-            workerGroup.shutdownGracefully();
-        }
-        logger.info("client finished");
+      ChannelFuture f = b.connect("127.0.0.1", Constants.LISTEN_PORT).sync();
+      f.channel().closeFuture().sync();
+    } catch (InterruptedException e) {
+      // e.printStackTrace();
+    } finally {
+      workerGroup.shutdownGracefully();
     }
+    logger.info("client finished");
+  }
 }
diff --git a/crow.game.examples.pingpong/src/main/java/crow/game/examples/pingpong/client/PingPongClientInitializer.java b/crow.game.examples.pingpong/src/main/java/crow/game/examples/pingpong/client/PingPongClientInitializer.java
index cac4f26..b798dd1 100644
--- a/crow.game.examples.pingpong/src/main/java/crow/game/examples/pingpong/client/PingPongClientInitializer.java
+++ b/crow.game.examples.pingpong/src/main/java/crow/game/examples/pingpong/client/PingPongClientInitializer.java
@@ -13,56 +13,45 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 /**
- * Netty clients logic for the ping pong example. it registers
- * the standard {@link FrameCodec} and {@link PacketCodec} then
- * just sends a {@link Ping} message once the connection is established, finally
- * drops the connection once a {@link Pong} is received.
+ * Netty clients logic for the ping pong example. it registers the standard {@link FrameCodec} and
+ * {@link PacketCodec} then just sends a {@link Ping} message once the connection is established,
+ * finally drops the connection once a {@link Pong} is received.
  */
-public class PingPongClientInitializer
-    extends ChannelInitializer<SocketChannel> {
-
-    public static final Logger logger = LoggerFactory.getLogger(
-        PingPongClientInitializer.class
-    );
-
-    protected final Context context;
-
-    public PingPongClientInitializer(Context ctx) {
-        this.context = ctx;
-    }
-
-    @Override
-    protected void initChannel(SocketChannel ch) throws Exception {
-        logger.info("initializing channel");
-        ch
-            .pipeline() //
-            .addLast(new FrameCodec(context)) //
-            .addLast(new PacketCodec(context)) //
-            .addLast(
-                new ChannelInboundHandlerAdapter() {
-                    @Override
-                    public void channelActive(ChannelHandlerContext ctx)
-                        throws Exception {
-                        ctx.writeAndFlush(new Ping()).sync();
-                    }
-
-                    @Override
-                    public void channelRead(
-                        ChannelHandlerContext ctx,
-                        Object msg
-                    ) throws Exception {
-                        if (msg instanceof Pong) {
-                            logger.info("GOT PONG");
-                            ctx.close();
-                        }
-                    }
-
-                    @Override
-                    public void channelInactive(ChannelHandlerContext ctx)
-                        throws Exception {
-                        logger.info("channel done");
-                    }
+public class PingPongClientInitializer extends ChannelInitializer<SocketChannel> {
+
+  public static final Logger logger = LoggerFactory.getLogger(PingPongClientInitializer.class);
+
+  protected final Context context;
+
+  public PingPongClientInitializer(Context ctx) {
+    this.context = ctx;
+  }
+
+  @Override
+  protected void initChannel(SocketChannel ch) throws Exception {
+    logger.info("initializing channel");
+    ch.pipeline() //
+        .addLast(new FrameCodec(context)) //
+        .addLast(new PacketCodec(context)) //
+        .addLast(
+            new ChannelInboundHandlerAdapter() {
+              @Override
+              public void channelActive(ChannelHandlerContext ctx) throws Exception {
+                ctx.writeAndFlush(new Ping()).sync();
+              }
+
+              @Override
+              public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
+                if (msg instanceof Pong) {
+                  logger.info("GOT PONG");
+                  ctx.close();
                 }
-            );
-    }
+              }
+
+              @Override
+              public void channelInactive(ChannelHandlerContext ctx) throws Exception {
+                logger.info("channel done");
+              }
+            });
+  }
 }
diff --git a/crow.game.examples.pingpong/src/main/java/crow/game/examples/pingpong/client/package-info.java b/crow.game.examples.pingpong/src/main/java/crow/game/examples/pingpong/client/package-info.java
index b9e9579..fc60024 100644
--- a/crow.game.examples.pingpong/src/main/java/crow/game/examples/pingpong/client/package-info.java
+++ b/crow.game.examples.pingpong/src/main/java/crow/game/examples/pingpong/client/package-info.java
@@ -1,4 +1,2 @@
-/**
- * The client code for the ping/pong example.
- */
+/** The client code for the ping/pong example. */
 package crow.game.examples.pingpong.client;
diff --git a/crow.game.examples.pingpong/src/main/java/crow/game/examples/pingpong/proto/Constants.java b/crow.game.examples.pingpong/src/main/java/crow/game/examples/pingpong/proto/Constants.java
index 74237bc..58a3b6e 100644
--- a/crow.game.examples.pingpong/src/main/java/crow/game/examples/pingpong/proto/Constants.java
+++ b/crow.game.examples.pingpong/src/main/java/crow/game/examples/pingpong/proto/Constants.java
@@ -2,8 +2,8 @@ package crow.game.examples.pingpong.proto;
 
 public class Constants {
 
-    public static final int LISTEN_PORT = 9991;
+  public static final int LISTEN_PORT = 9991;
 
-    public static final short PING_PREFIX = (short) 0x9901;
-    public static final short PONG_PREFIX = (short) 0x9902;
+  public static final short PING_PREFIX = (short) 0x9901;
+  public static final short PONG_PREFIX = (short) 0x9902;
 }
diff --git a/crow.game.examples.pingpong/src/main/java/crow/game/examples/pingpong/proto/Ping.java b/crow.game.examples.pingpong/src/main/java/crow/game/examples/pingpong/proto/Ping.java
index 5bb84d2..0e71785 100644
--- a/crow.game.examples.pingpong/src/main/java/crow/game/examples/pingpong/proto/Ping.java
+++ b/crow.game.examples.pingpong/src/main/java/crow/game/examples/pingpong/proto/Ping.java
@@ -1,6 +1,4 @@
 package crow.game.examples.pingpong.proto;
 
-/**
- * The super simple Ping request POJO
- */
+/** The super simple Ping request POJO */
 public class Ping {}
diff --git a/crow.game.examples.pingpong/src/main/java/crow/game/examples/pingpong/proto/PingPacketHandler.java b/crow.game.examples.pingpong/src/main/java/crow/game/examples/pingpong/proto/PingPacketHandler.java
index 2c3e83e..c921eef 100644
--- a/crow.game.examples.pingpong/src/main/java/crow/game/examples/pingpong/proto/PingPacketHandler.java
+++ b/crow.game.examples.pingpong/src/main/java/crow/game/examples/pingpong/proto/PingPacketHandler.java
@@ -6,23 +6,22 @@ import crow.game.codec.PacketRule;
 import io.netty.buffer.ByteBuf;
 
 /**
- * This is the packet handler for the Ping message. It, ironically, is empty
- * since Ping is a 0-byte message (ignoring packet id) so this handler is
- * only responsible for constructing and defining the packet details.
+ * This is the packet handler for the Ping message. It, ironically, is empty since Ping is a 0-byte
+ * message (ignoring packet id) so this handler is only responsible for constructing and defining
+ * the packet details.
  */
 public class PingPacketHandler implements PacketHandler<Ping> {
 
-    @Override
-    public Ping fromPacket(Context ctx, ByteBuf buffer) throws Exception {
-        return new Ping();
-    }
+  @Override
+  public Ping fromPacket(Context ctx, ByteBuf buffer) throws Exception {
+    return new Ping();
+  }
 
-    @Override
-    public void toPacket(Context ctx, ByteBuf buffer, Ping src)
-        throws Exception {}
+  @Override
+  public void toPacket(Context ctx, ByteBuf buffer, Ping src) throws Exception {}
 
-    @Override
-    public PacketRule rule(Context ctx) {
-        return PacketRule.Static(Constants.PING_PREFIX, 0, Ping.class);
-    }
+  @Override
+  public PacketRule rule(Context ctx) {
+    return PacketRule.Static(Constants.PING_PREFIX, 0, Ping.class);
+  }
 }
diff --git a/crow.game.examples.pingpong/src/main/java/crow/game/examples/pingpong/proto/Pong.java b/crow.game.examples.pingpong/src/main/java/crow/game/examples/pingpong/proto/Pong.java
index bc1f71f..276ffe1 100644
--- a/crow.game.examples.pingpong/src/main/java/crow/game/examples/pingpong/proto/Pong.java
+++ b/crow.game.examples.pingpong/src/main/java/crow/game/examples/pingpong/proto/Pong.java
@@ -1,6 +1,4 @@
 package crow.game.examples.pingpong.proto;
 
-/**
- * The super simple Pong response POJO
- */
+/** The super simple Pong response POJO */
 public class Pong {}
diff --git a/crow.game.examples.pingpong/src/main/java/crow/game/examples/pingpong/proto/PongPacketHandler.java b/crow.game.examples.pingpong/src/main/java/crow/game/examples/pingpong/proto/PongPacketHandler.java
index 4854fa8..edbaa24 100644
--- a/crow.game.examples.pingpong/src/main/java/crow/game/examples/pingpong/proto/PongPacketHandler.java
+++ b/crow.game.examples.pingpong/src/main/java/crow/game/examples/pingpong/proto/PongPacketHandler.java
@@ -6,22 +6,22 @@ import crow.game.codec.PacketRule;
 import io.netty.buffer.ByteBuf;
 
 /**
- * This is the packet handler for the Pong message. It, ironically, is empty
- * since Pong is a 0-byte message (ignoring packet id) so this handler is
- * only responsible for constructing and defining the packet details.
+ * This is the packet handler for the Pong message. It, ironically, is empty since Pong is a 0-byte
+ * message (ignoring packet id) so this handler is only responsible for constructing and defining
+ * the packet details.
  */
 public class PongPacketHandler implements PacketHandler<Pong> {
 
-    @Override
-    public Pong fromPacket(Context ctx, ByteBuf buffer) {
-        return new Pong();
-    }
+  @Override
+  public Pong fromPacket(Context ctx, ByteBuf buffer) {
+    return new Pong();
+  }
 
-    @Override
-    public void toPacket(Context ctx, ByteBuf buffer, Pong src) {}
+  @Override
+  public void toPacket(Context ctx, ByteBuf buffer, Pong src) {}
 
-    @Override
-    public PacketRule rule(Context ctx) {
-        return PacketRule.Static(Constants.PONG_PREFIX, 0, Ping.class);
-    }
+  @Override
+  public PacketRule rule(Context ctx) {
+    return PacketRule.Static(Constants.PONG_PREFIX, 0, Ping.class);
+  }
 }
diff --git a/crow.game.examples.pingpong/src/main/java/crow/game/examples/pingpong/proto/RootContext.java b/crow.game.examples.pingpong/src/main/java/crow/game/examples/pingpong/proto/RootContext.java
index 5f8f4bb..74bd4ab 100644
--- a/crow.game.examples.pingpong/src/main/java/crow/game/examples/pingpong/proto/RootContext.java
+++ b/crow.game.examples.pingpong/src/main/java/crow/game/examples/pingpong/proto/RootContext.java
@@ -2,64 +2,60 @@ package crow.game.examples.pingpong.proto;
 
 import crow.game.codec.Context;
 import crow.game.codec.PacketHandler;
-import java.util.Arrays;
 import java.util.List;
 
 /**
- * The root context is the context implementation for the Ping/Pong
- * server and defines the packet version and provides the {@link PacketHandler}s.
- * <p>
- * More complicated client/server implementations could use spring or guice or SPI
- * to lookup packet POJOs and {@link PacketHandler}s but this one is too simple
- * to justify that level of work.
- * <p>
- * Ideally we will have a common server or client module that implements a Context
- * that does use guice or spring and then that module is just marked as "requiring
- * injection library".
+ * The root context is the context implementation for the Ping/Pong server and defines the packet
+ * version and provides the {@link PacketHandler}s.
  *
+ * <p>More complicated client/server implementations could use spring or guice or SPI to lookup
+ * packet POJOs and {@link PacketHandler}s but this one is too simple to justify that level of work.
+ *
+ * <p>Ideally we will have a common server or client module that implements a Context that does use
+ * guice or spring and then that module is just marked as "requiring injection library".
  */
 public class RootContext implements Context {
 
-    protected final PacketHandler<Ping> pingPacketHandler;
-    protected final PacketHandler<Pong> pongPacketHandler;
-
-    public RootContext() {
-        this.pingPacketHandler = new PingPacketHandler();
-        this.pongPacketHandler = new PongPacketHandler();
-    }
-
-    public Context.Source callingSource() {
-        return Context.Source.INIT;
-    }
-
-    public int supportedProtocolVersion() {
-        return 20231115;
+  protected final PacketHandler<Ping> pingPacketHandler;
+  protected final PacketHandler<Pong> pongPacketHandler;
+
+  public RootContext() {
+    this.pingPacketHandler = new PingPacketHandler();
+    this.pongPacketHandler = new PongPacketHandler();
+  }
+
+  public Context.Source callingSource() {
+    return Context.Source.INIT;
+  }
+
+  public int supportedProtocolVersion() {
+    return 20231115;
+  }
+
+  @Override
+  public List<PacketHandler<?>> lookupPacketHandler(int prefix) {
+    if (prefix == Constants.PING_PREFIX) {
+      return List.of(pingPacketHandler);
+    } else if (prefix == Constants.PONG_PREFIX) {
+      return List.of(pongPacketHandler);
+    } else {
+      return List.of();
     }
-
-    @Override
-    public List<PacketHandler<?>> lookupPacketHandler(int prefix) {
-        if (prefix == Constants.PING_PREFIX) {
-            return List.of(pingPacketHandler);
-        } else if (prefix == Constants.PONG_PREFIX) {
-            return List.of(pongPacketHandler);
-        } else {
-            return List.of();
-        }
+  }
+
+  @Override
+  public List<PacketHandler<?>> lookupPacketHandler(Class<?> clz) {
+    if (clz.isAssignableFrom(Ping.class)) {
+      return List.of(pingPacketHandler);
+    } else if (clz.isAssignableFrom(Pong.class)) {
+      return List.of(pongPacketHandler);
+    } else {
+      return List.of();
     }
+  }
 
-    @Override
-    public List<PacketHandler<?>> lookupPacketHandler(Class<?> clz) {
-        if (clz.isAssignableFrom(Ping.class)) {
-            return List.of(pingPacketHandler);
-        } else if (clz.isAssignableFrom(Pong.class)) {
-            return List.of(pongPacketHandler);
-        } else {
-            return List.of();
-        }
-    }
-
-    @Override
-    public Object underlyingObject() {
-        return this;
-    }
+  @Override
+  public Object underlyingObject() {
+    return this;
+  }
 }
diff --git a/crow.game.examples.pingpong/src/main/java/crow/game/examples/pingpong/proto/package-info.java b/crow.game.examples.pingpong/src/main/java/crow/game/examples/pingpong/proto/package-info.java
index 48ca944..7bbfcea 100644
--- a/crow.game.examples.pingpong/src/main/java/crow/game/examples/pingpong/proto/package-info.java
+++ b/crow.game.examples.pingpong/src/main/java/crow/game/examples/pingpong/proto/package-info.java
@@ -1,16 +1,18 @@
 /**
- * This is the ping pong protocol package and would, in more complex scenarios,
- * be in its own JAR. It contains the POJOs and PacketHandlers for both client
- * and server needs and is meant to be included in both sides to support bidirectional
- * communication.
- * <p>
- * If you look at the {@link crow.game.examples.pingpong.proto.Ping} and {@link crow.game.examples.pingpong.proto.Pong}
- * objects and their corresponding PacketHandlers, you'll notice there is no real
- * different between the two. The request/response model in this system is not defined(1) so
- * objects can be both, providing their PacketHandlers implement both decode and encode.
- * <p>
- * (1) NOTE: This may change in the future!
+ * This is the ping pong protocol package and would, in more complex scenarios, be in its own JAR.
+ * It contains the POJOs and PacketHandlers for both client and server needs and is meant to be
+ * included in both sides to support bidirectional communication.
+ *
+ * <p>If you look at the {@link crow.game.examples.pingpong.proto.Ping} and {@link
+ * crow.game.examples.pingpong.proto.Pong} objects and their corresponding PacketHandlers, you'll
+ * notice there is no real different between the two. The request/response model in this system is
+ * not defined(1) so objects can be both, providing their PacketHandlers implement both decode and
+ * encode.
+ *
+ * <p>(1) NOTE: This may change in the future!
+ *
  * <p>
+ *
  * @see crow.game.examples.pingpong.proto.RootContext
  */
 package crow.game.examples.pingpong.proto;
diff --git a/crow.game.examples.pingpong/src/main/java/crow/game/examples/pingpong/server/MainServer.java b/crow.game.examples.pingpong/src/main/java/crow/game/examples/pingpong/server/MainServer.java
index 4536d2b..c9f4c0b 100644
--- a/crow.game.examples.pingpong/src/main/java/crow/game/examples/pingpong/server/MainServer.java
+++ b/crow.game.examples.pingpong/src/main/java/crow/game/examples/pingpong/server/MainServer.java
@@ -14,43 +14,37 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 /**
- * This wraps the server into a runnable that can be run as a main entrypoint
- * OR passed into a Thread.
+ * This wraps the server into a runnable that can be run as a main entrypoint OR passed into a
+ * Thread.
  *
  * @see crow.game.examples.pingpong.utils.Main
  */
 public class MainServer implements Runnable {
 
-    public static final Logger logger = LoggerFactory.getLogger(
-        MainServer.class
-    );
+  public static final Logger logger = LoggerFactory.getLogger(MainServer.class);
 
-    public static void main(String[] args) {
-        new MainServer().run();
-    }
+  public static void main(String[] args) {
+    new MainServer().run();
+  }
 
-    public void run() {
-        EventLoopGroup bossGroup = new NioEventLoopGroup(
-            new PrefixThreadFactory("server-boss")
-        );
-        EventLoopGroup workerGroup = new NioEventLoopGroup(
-            new PrefixThreadFactory("server-worker")
-        );
-        Context context = new RootContext();
-        try {
-            ServerBootstrap b = new ServerBootstrap(); //
-            b
-                .group(bossGroup, workerGroup) //
-                .channel(NioServerSocketChannel.class) //
-                .childHandler(new PingPongServerInitializer(context)) //
-                .option(ChannelOption.SO_BACKLOG, 128) //
-                .childOption(ChannelOption.SO_KEEPALIVE, true);
+  public void run() {
+    EventLoopGroup bossGroup = new NioEventLoopGroup(new PrefixThreadFactory("server-boss"));
+    EventLoopGroup workerGroup = new NioEventLoopGroup(new PrefixThreadFactory("server-worker"));
+    Context context = new RootContext();
+    try {
+      ServerBootstrap b = new ServerBootstrap(); //
+      b.group(bossGroup, workerGroup) //
+          .channel(NioServerSocketChannel.class) //
+          .childHandler(new PingPongServerInitializer(context)) //
+          .option(ChannelOption.SO_BACKLOG, 128) //
+          .childOption(ChannelOption.SO_KEEPALIVE, true);
 
-            ChannelFuture f = b.bind(Constants.LISTEN_PORT).sync(); // (7)
-            f.channel().closeFuture().sync();
-        } catch (InterruptedException e) {} finally {
-            workerGroup.shutdownGracefully();
-            bossGroup.shutdownGracefully();
-        }
+      ChannelFuture f = b.bind(Constants.LISTEN_PORT).sync(); // (7)
+      f.channel().closeFuture().sync();
+    } catch (InterruptedException e) {
+    } finally {
+      workerGroup.shutdownGracefully();
+      bossGroup.shutdownGracefully();
     }
+  }
 }
diff --git a/crow.game.examples.pingpong/src/main/java/crow/game/examples/pingpong/server/PingPongServerInitializer.java b/crow.game.examples.pingpong/src/main/java/crow/game/examples/pingpong/server/PingPongServerInitializer.java
index df76cd9..29f813d 100644
--- a/crow.game.examples.pingpong/src/main/java/crow/game/examples/pingpong/server/PingPongServerInitializer.java
+++ b/crow.game.examples.pingpong/src/main/java/crow/game/examples/pingpong/server/PingPongServerInitializer.java
@@ -15,64 +15,48 @@ import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 /**
- * Netty server logic for the ping pong example. it registers
- * the standard {@link FrameCodec} and {@link PacketCodec} then
- * just waits for a {@link Ping} object to come from a client.
- * <p>
- * The bottom of the pipeline is a {@link SimpleChannelInboundHandler} with
- * two functions: listen for Ping messages and handle exceptions thrown by the
- * codecs and report and drop the connection as needed.
+ * Netty server logic for the ping pong example. it registers the standard {@link FrameCodec} and
+ * {@link PacketCodec} then just waits for a {@link Ping} object to come from a client.
+ *
+ * <p>The bottom of the pipeline is a {@link SimpleChannelInboundHandler} with two functions: listen
+ * for Ping messages and handle exceptions thrown by the codecs and report and drop the connection
+ * as needed.
  */
-public class PingPongServerInitializer
-    extends ChannelInitializer<SocketChannel> {
-
-    public static final Logger logger = LoggerFactory.getLogger(
-        PingPongServerInitializer.class
-    );
-
-    protected final Context context;
-
-    public PingPongServerInitializer(Context ctx) {
-        this.context = ctx;
-    }
-
-    @Override
-    protected void initChannel(SocketChannel ch) {
-        ch
-            .pipeline() //
-            .addLast(new FrameCodec(context)) //
-            .addLast(new PacketCodec(context)) //
-            .addLast(
-                new SimpleChannelInboundHandler<Ping>() {
-                    @Override
-                    protected void channelRead0(
-                        ChannelHandlerContext channelHandlerContext,
-                        Ping ping
-                    ) {
-                        logger.info("GOT PING, RESPONDING");
-                        channelHandlerContext.writeAndFlush(new Pong());
-                    }
-
-                    @Override
-                    public void exceptionCaught(
-                        ChannelHandlerContext ctx,
-                        Throwable cause
-                    ) {
-                        if (cause instanceof DecoderException) {
-                            if (
-                                cause.getCause() instanceof UnsupportedMessageTypeException
-                            ) {
-                                logger.warn(
-                                    "dropping connection due to malformed packet"
-                                );
-                                ctx.close();
-                                return;
-                            }
-                        }
-
-                        logger.error("error", cause);
-                    }
+public class PingPongServerInitializer extends ChannelInitializer<SocketChannel> {
+
+  public static final Logger logger = LoggerFactory.getLogger(PingPongServerInitializer.class);
+
+  protected final Context context;
+
+  public PingPongServerInitializer(Context ctx) {
+    this.context = ctx;
+  }
+
+  @Override
+  protected void initChannel(SocketChannel ch) {
+    ch.pipeline() //
+        .addLast(new FrameCodec(context)) //
+        .addLast(new PacketCodec(context)) //
+        .addLast(
+            new SimpleChannelInboundHandler<Ping>() {
+              @Override
+              protected void channelRead0(ChannelHandlerContext channelHandlerContext, Ping ping) {
+                logger.info("GOT PING, RESPONDING");
+                channelHandlerContext.writeAndFlush(new Pong());
+              }
+
+              @Override
+              public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
+                if (cause instanceof DecoderException) {
+                  if (cause.getCause() instanceof UnsupportedMessageTypeException) {
+                    logger.warn("dropping connection due to malformed packet");
+                    ctx.close();
+                    return;
+                  }
                 }
-            );
-    }
+
+                logger.error("error", cause);
+              }
+            });
+  }
 }
diff --git a/crow.game.examples.pingpong/src/main/java/crow/game/examples/pingpong/server/package-info.java b/crow.game.examples.pingpong/src/main/java/crow/game/examples/pingpong/server/package-info.java
index e4bc059..6212ce8 100644
--- a/crow.game.examples.pingpong/src/main/java/crow/game/examples/pingpong/server/package-info.java
+++ b/crow.game.examples.pingpong/src/main/java/crow/game/examples/pingpong/server/package-info.java
@@ -1,4 +1,2 @@
-/**
- * The server code for the ping/pong example.
- */
+/** The server code for the ping/pong example. */
 package crow.game.examples.pingpong.server;
diff --git a/crow.game.examples.pingpong/src/main/java/crow/game/examples/pingpong/utils/Main.java b/crow.game.examples.pingpong/src/main/java/crow/game/examples/pingpong/utils/Main.java
index f942842..90e0ae1 100644
--- a/crow.game.examples.pingpong/src/main/java/crow/game/examples/pingpong/utils/Main.java
+++ b/crow.game.examples.pingpong/src/main/java/crow/game/examples/pingpong/utils/Main.java
@@ -5,22 +5,20 @@ import crow.game.examples.pingpong.server.MainServer;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-/**
- * This main runs both client and server as separate threads.
- */
+/** This main runs both client and server as separate threads. */
 public class Main {
 
-    public static void main(String[] args) {
-        Logger l = LoggerFactory.getLogger(Main.class);
-        l.info("running...");
-        Thread thr1 = new Thread(new MainServer(), "server");
-        thr1.start();
-        try {
-            Thread.sleep(3000);
-        } catch (InterruptedException e) {
-            throw new RuntimeException(e);
-        }
-        new MainClient().run();
-        thr1.interrupt();
+  public static void main(String[] args) {
+    Logger l = LoggerFactory.getLogger(Main.class);
+    l.info("running...");
+    Thread thr1 = new Thread(new MainServer(), "server");
+    thr1.start();
+    try {
+      Thread.sleep(3000);
+    } catch (InterruptedException e) {
+      throw new RuntimeException(e);
     }
+    new MainClient().run();
+    thr1.interrupt();
+  }
 }
diff --git a/crow.game.examples.pingpong/src/main/java/crow/game/examples/pingpong/utils/PrefixThreadFactory.java b/crow.game.examples.pingpong/src/main/java/crow/game/examples/pingpong/utils/PrefixThreadFactory.java
index a2d397e..a0ab15f 100644
--- a/crow.game.examples.pingpong/src/main/java/crow/game/examples/pingpong/utils/PrefixThreadFactory.java
+++ b/crow.game.examples.pingpong/src/main/java/crow/game/examples/pingpong/utils/PrefixThreadFactory.java
@@ -4,27 +4,23 @@ import java.util.concurrent.ThreadFactory;
 import java.util.concurrent.atomic.AtomicInteger;
 
 /**
- * Thread factory which prefixes the thread with the given
- * name and an incremental integer. Useful for debugging
- * thread pools built by Netty.
+ * Thread factory which prefixes the thread with the given name and an incremental integer. Useful
+ * for debugging thread pools built by Netty.
  */
 public class PrefixThreadFactory implements ThreadFactory {
 
-    AtomicInteger at;
+  AtomicInteger at;
 
-    String prefix;
+  String prefix;
 
-    public PrefixThreadFactory(String p) {
-        at = new AtomicInteger(0);
-        prefix = p;
-    }
+  public PrefixThreadFactory(String p) {
+    at = new AtomicInteger(0);
+    prefix = p;
+  }
 
-    @Override
-    public Thread newThread(Runnable arg0) {
-        Thread thr = new Thread(
-            arg0,
-            String.format("%s-%d", prefix, at.getAndIncrement())
-        );
-        return thr;
-    }
+  @Override
+  public Thread newThread(Runnable arg0) {
+    Thread thr = new Thread(arg0, String.format("%s-%d", prefix, at.getAndIncrement()));
+    return thr;
+  }
 }
diff --git a/crow.game.examples.pingpong/src/main/java/crow/game/examples/pingpong/utils/package-info.java b/crow.game.examples.pingpong/src/main/java/crow/game/examples/pingpong/utils/package-info.java
index bcfb2f8..8a6808b 100644
--- a/crow.game.examples.pingpong/src/main/java/crow/game/examples/pingpong/utils/package-info.java
+++ b/crow.game.examples.pingpong/src/main/java/crow/game/examples/pingpong/utils/package-info.java
@@ -1,4 +1,2 @@
-/**
- * Shared utilities and launcher for the ping pong example.
- */
+/** Shared utilities and launcher for the ping pong example. */
 package crow.game.examples.pingpong.utils;
diff --git a/pom.xml b/pom.xml
index b8e63f8..b2410cc 100644
--- a/pom.xml
+++ b/pom.xml
@@ -42,7 +42,37 @@
     <maven.compiler.target>17</maven.compiler.target>
     <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
     <maven.build.timestamp.format>yyyyMMdd_HHmm</maven.build.timestamp.format>
+    <netty.version>4.1.101.Final</netty.version>
   </properties>
+  <dependencyManagement>
+    <dependencies>
+      <dependency>
+        <groupId>org.slf4j</groupId>
+        <artifactId>slf4j-api</artifactId>
+        <version>1.7.36</version>
+      </dependency>
+      <dependency>
+        <groupId>io.netty</groupId>
+        <artifactId>netty-buffer</artifactId>
+        <version>${netty.version}</version>
+      </dependency>
+      <dependency>
+        <groupId>io.netty</groupId>
+        <artifactId>netty-codec</artifactId>
+        <version>${netty.version}</version>
+      </dependency>
+      <dependency>
+        <groupId>io.netty</groupId>
+        <artifactId>netty-transport</artifactId>
+        <version>${netty.version}</version>
+      </dependency>
+      <dependency>
+        <groupId>io.netty</groupId>
+        <artifactId>netty-handler</artifactId>
+        <version>${netty.version}</version>
+      </dependency>
+    </dependencies>
+  </dependencyManagement>
   <build>
     <plugins>
       <plugin>
@@ -61,29 +91,19 @@
               <sortPlugins>groupId,artifactId</sortPlugins>
             </sortPom>
           </pom>
+          <java>
+            <includes>
+              <include>crow*/src/main/java/**/*.java</include>
+              <include>crow*/src/test/java/**/*.java</include>
+            </includes>
+            <googleJavaFormat></googleJavaFormat>
+          </java>
           <markdown>
             <includes>
               <include>**/*.md</include>
             </includes>
             <flexmark></flexmark>
           </markdown>
-          <formats>
-            <format>
-              <includes>
-                <include>src/*/java/**/*.java</include>
-              </includes>
-              <prettier>
-                <devDependencies>
-                  <prettier>2.0.5</prettier>
-                  <prettier-plugin-java>1.4.0</prettier-plugin-java>
-                </devDependencies>
-                <config>
-                  <tabWidth>4</tabWidth>
-                  <parser>java</parser>
-                </config>
-              </prettier>
-            </format>
-          </formats>
         </configuration>
         <executions>
           <execution>