42f9fba

Branches > client-handling-rewrite > 42f9fba > files / src / net / bowmap / minecraft_server.clj

Update client message writing

Grahp, 2026-06-02

Commit: 42f9fba9fbd23946cb6b20d501472c2ebda79df2
Parent: 15f3896

3 changed files:

src/dev/grahp/error.clj modified (view file)

@@ -71,3 +71,9 @@                     (str/trim-newline (s/explain-str ~spec x#)))                (assoc ~m '~x x#))         x#))))++(defmacro get!+  "Same as '(get k m)', but throws an error when the key is not present"+  ([m k] (get! ~m ~k "Failed get!, no such key in map!"))+  ([m k msg]+   `(get ~m ~k (raise ~msg {:map ~m :key ~k}))))

src/net/bowmap/network/message/client.clj modified (view file)

@@ -4,19 +4,19 @@   (:require    [clojure.alpha.spec :as s]    [dev.grahp.build :refer [build]]-   [dev.grahp.error :refer [adorn assert!]]+   [dev.grahp.error :refer [adorn get!]]    [net.bowmap.network.message :as msg]    [net.bowmap.network.packet :as pk]-   [net.bowmap.network.packet.types :as t]    [net.bowmap.network.packet.write :refer [boolean-> byte->                                             context-optional-> enum-> float->-                                            identifier-> int-> json-> list->-                                            long-> nbt-> optional-> or->-                                            position-> string-> table->-                                            ubyte-> uuid-> varint->]]+                                            identifier-> int-> json->+                                            length-prefixed list-> long->+                                            nbt-> optional-> or-> position->+                                            string-> table-> ubyte-> uuid->+                                            varint->]]    [net.bowmap.network.state :as state])   (:import-   [io.netty.buffer ByteBuf CompositeByteBuf Unpooled]))+   [io.netty.buffer ByteBuf Unpooled]))  ; TODO docstrings! (defn build-packet-ids [registry]@@ -32,14 +32,12 @@             (assoc acc packet-id (table-> table)))           {} registry)) +; TODO docstring? (def ^{:spec (s/map-of (s/schema [::state/connection-state ::msg/id]) ::pk/id)}   packet-ids-  ; TODO docstrings shouldn't contain these yeag...-  ; Update-  "Map of [::state/state ::pk/id] to numeric-id.-   Packet ids (::pk/id) could map directly to numeric-ids and be stateless,-    but some packets have duplicates across connection states that you'd want to handle in the same way.-   If it turns out that I don't end up handling packets in this way, then packet ids could map directly to numeric ids."+  ; Packet ids could map directly to numeric-ids and be stateless,+  ; but some packets have duplicates across connection states that you'd want to handle in the same way.+  ; If it turns out that I don't end up handling packets in this way, then packet ids could map directly to numeric ids."   (build-packet-ids     {::state/status      [::status-response@@ -218,8 +216,8 @@                                         :ret #(instance? ByteBuf %)))}   packets   (build-packets-    {::status-response [:response "Response to ::sp/status-request" json->]-     ::pong-response [:timestamp "The same timestamp as ::sp/ping-request" long->]+    {::status-response [:response "Response to serverbound ::status-request" json->]+     ::pong-response [:timestamp "The same timestamp as serverbound ::ping-request" long->]      ::login-success [:uuid uuid->                       :username string->                       :properties (list-> (table-> [:name string->@@ -261,32 +259,6 @@      ::game-event [:event (enum-> byte-> {3 :set-gamemode 13 :wait-for-chunks})                    :value (or-> float-> 0)]})) -(defn- numeric-id [pk state]-  (assert! (packet-ids {::state/connection-state state ::msg/id (::msg/id pk)})-           {:pk pk :state state}-           "No such packet with that id."))--(defn- packet-encoder [pk]-  (assert! (packets (::msg/id pk))-           {:pk pk}-           "No such encoder for that packet."))--(defn- length-prefixed-  "Returns a composite bytebuf prefixed by the varint length of 'buf'."-  [buf]-  (-> (Unpooled/compositeBuffer 2)-      ; TODO document, 5 is the max lenght a varint could be, same with the other magic number 5-      (CompositeByteBuf/.addComponent true (varint-> (Unpooled/buffer t/max-varint-size) (ByteBuf/.writerIndex buf)))-      (CompositeByteBuf/.addComponent true buf)))--(defn- encoded-packet-  "Returns an encoded packet."-  [pk state]-  (let [encode-body (packet-encoder pk)]-    (length-prefixed (-> (Unpooled/buffer)-                         (varint-> (numeric-id pk state))-                         (encode-body pk)))))- (defn message->packet   "Encodes packet 'pk' into a ByteBuf of the packet bytes.    Like decoding, encoding a packet also requires the connection state, as@@ -295,6 +267,9 @@    There are several packets (disconnect, keep alive) that are logically the     same across connection states, and so can be sent without needing to switch     on the connection state."-  [pk state]-  (adorn (encoded-packet pk state)-         "Error while encoding message into packet" {:pk pk :state state}))+  [msg state]+  (-> (let [encode-body (get! packets msg)]+        (length-prefixed (-> (Unpooled/buffer)+                             (varint-> (get! packet-ids msg state))+                             (encode-body msg))))+      (adorn "Error while encoding message into packet" {:pk msg :state state})))

src/net/bowmap/network/packet/write.clj modified (view file)

@@ -9,7 +9,7 @@    [dev.grahp.spec :as S]    [net.bowmap.network.packet.types :as t])   (:import-   [io.netty.buffer ByteBuf]+   [io.netty.buffer ByteBuf CompositeByteBuf Unpooled]    [java.nio.charset Charset]    [java.util UUID])) @@ -23,6 +23,14 @@         (recur (ByteBuf/.writeByte buf (bit-or b 0x80))                nxt))))) +(defn length-prefixed+  "Returns a new ByteBuf prefixed by an encoded varint of the length of 'buf'."+  [buf]+  (-> (Unpooled/compositeBuffer 2)+      (CompositeByteBuf/.addComponent true (varint-> (Unpooled/buffer t/max-varint-size) (ByteBuf/.writerIndex buf)))+      (CompositeByteBuf/.addComponent true buf)))++ (defn string-> [buf s]   (doto buf     (varint-> (count s))