2dca1d5

Branches > main > 2dca1d5 > files / src / net / bowmap / transport / writers.clj

Move transport level concerns to the transport package

Grahp, 2026-08-24

Commit: 2dca1d5643151a29159cc6f65cc7c951c6ad8096
Parent: 6d328bc

9 changed files:

src/net/bowmap/protocol/handle.clj modified (view file)

@@ -7,11 +7,9 @@    [net.bowmap.protocol.packet.registry :as registry]    [net.bowmap.protocol.packet.serverbound :as serverbound]    [net.bowmap.protocol.registry :as reg]-   [net.bowmap.protocol.state :as state]    [net.bowmap.server.gamemode :as gamemode]    [net.bowmap.server.ping :as ping]    [net.bowmap.server.player :as player]-   [net.bowmap.server.position :as position]    [net.bowmap.server.server :as server]    [net.bowmap.stormbow.event :as event])) 

src/net/bowmap/protocol/packet/clientbound.clj modified (view file)

@@ -1,16 +1,88 @@ (ns net.bowmap.protocol.packet.clientbound   (:require-   [net.bowmap.protocol.packet :as pk]-   [net.bowmap.protocol.packet.writers :as write-    :refer [bit-mask-> boolean-> byte-> chunk-data-> coerce context-optional->+   [net.bowmap.transport.writers :as write+    :refer [bit-mask-> boolean-> byte-> chunk-data-> context-optional->             double-> enum-> float-> game-profile-> identifier-> int-> json->-            length-prefixed light-data-> list-> long-> nbt-> optional-> or->-            position-> string-> ubyte-> uuid-> varint->]]+            light-data-> list-> long-> nbt-> optional-> or-> position->+            string-> ubyte-> uuid-> varint->]]    [net.bowmap.protocol.registry :as reg]    [net.bowmap.protocol.state :as state]-   [net.bowmap.server.gamemode :as gamemode])-  (:import-   [io.netty.buffer Unpooled]))+   [net.bowmap.server.gamemode :as gamemode]))++(def packets+  {::status-response [:response "Response to serverbound ::status-request" json->]+   ::pong-response [:timestamp "The same timestamp as serverbound ::ping-request" long->]+   ::login-success [:profile game-profile->+                    :session-id uuid->]+   ; TODO these use text components, can do that later+   ::login-disconnect [:reason json->]+   ::disconnect [:reason nbt->]+   ::known-packs [:known-packs (list-> [:namespace string->+                                        :id string->+                                        :version string->])]++   ::registry-data [::reg/id identifier->+                    ::reg/entries (list-> [::reg/entry-id identifier->+                                           ::reg/entry-data (optional-> nbt->)])]+   ::recipe-book-settings [:crafting-recipe-book-open? boolean->+                           :crafting-recipe-book-filter-active? boolean->+                           :smelting-recipe-book-open? boolean->+                           :smelting-recipe-book-filter-active? boolean->+                           :blast-furnace-recipe-book-open? boolean->+                           :blast-furnace-recipe-book-filter-active? boolean->+                           :smoker-recipe-book-open? boolean->+                           :smoker-recipe-book-filter-active? boolean->]+   ::keep-alive [:id long->]+   ::finish-config []+   ::login [:entity-id int->+            :hardcore? boolean->+            :dimension-names (list-> identifier->)+            :max-players varint->+            :view-distance varint->+            :simulation-distance varint->+            :reduced-debug-info? boolean->+            :enable-respawn-screen? boolean->+            :do-limited-crafting? boolean->+            :dimension-type-id varint->+            :dimension-name identifier->+            :hashed-seed long->+            :gamemode (enum-> ubyte-> {0 ::gamemode/survival 1 ::gamemode/creative 2 ::gamemode/adventure 3 ::gamemode/spectator})+            :previous-gamemode (enum-> (or-> byte-> -1) {0 ::gamemode/survival 1 ::gamemode/creative 2 ::gamemode/adventure 3 ::gamemode/spectator})+            :debug-world? boolean->+            :superflat-world? boolean->+            :has-death-location? boolean->+            :death-dimension-name (context-optional-> identifier->)+            :death-location (context-optional-> position->)+            :portal-cooldown varint->+            :sea-level varint->+            :online-mode? boolean->+            :enforce-secure-chat? boolean->]+   ;; And others too but we don't talk about those+   ::game-event [:event (enum-> byte-> {3 :set-gamemode 13 :wait-for-chunks})+                 :value (or-> float-> 0)]+   ::chunk-data-and-update-light [:chunk-x int->+                                  :chunk-z int->+                                  :chunk-data chunk-data->+                                  :light-data light-data->]+   ; TODO this is for teleporting, it's kind of a terrible name :p+   ::synchronize-player-position [:teleport-id varint->+                                  ; TODO might want to extrac this into its own type(s)?+                                  :x double->+                                  :y double->+                                  :z double->+                                  :velocity-x double->+                                  :velocity-y double->+                                  :velocity-z double->+                                  :yaw float->+                                  :pitch float->+                                  :flags (bit-mask-> int->+                                                     [:relative-x :relative-y :relative-z+                                                      :relative-yaw :relative-pitch+                                                      :relative-velocity-x :relative-velocity-y :relative-velocity-z+                                                      :rotate-velocity])]+   ::update-tags [:tagged-registries (list-> [:registry identifier->+                                              :tags (list-> [:tag-name identifier->+                                                             :entries (list-> varint->)])])]})  (def packet-order   {::state/status@@ -187,109 +259,3 @@     ::waypoint     ::clear-dialog

Show all 207 lines

src/net/bowmap/protocol/packet/serverbound.clj modified (view file)

@@ -1,108 +1,12 @@ (ns net.bowmap.protocol.packet.serverbound   (:require-   [net.bowmap.protocol.packet :as pk]-   [net.bowmap.protocol.packet.readers+   [net.bowmap.transport.readers     :refer [->bit-mask ->boolean ->byte ->double ->enum ->float ->identifier             ->int ->list ->location ->long ->optional ->short ->string ->ubyte-            ->uuid ->varint coerce]]+            ->uuid ->varint]]    [net.bowmap.protocol.state :as state]    [net.bowmap.server.position :as position])) -(def packet-order-  "Map of connection states to vectors of serverbound packet ids in the order the appear in the protocol."-  {::state/handshaking-   [::handshaking]-   ::state/status-   [::status-request-    ::ping-request]-   ::state/login-   [::login-start-    ::encryption-response-    ::login-plugin-response-    ::login-acknowledged-    ::cookie-response]-   ::state/config-   [::client-information-    ::cookie-response-    ::plugin-message-    ::finish-config-    ::keep-alive-    ::pong-    ::resource-pack-response-    ::known-packs-    ::custom-click-action-    ::accept-code-of-conduct]-   ::state/play-   [::confirm-teleportation-    ::attack-    ::query-block-entity-tag-    ::bundle-item-selected-    ::change-difficulty-    ::change-game-mode-    ::acknowledge-message-    ::chat-command-    ::signed-chat-command-    ::chat-message-    ::player-session-    ::chunk-batch-received-    ::client-status-    ::client-tick-end-    ::client-information-    ::command-suggestions-request-    ::acknowledge-configuration-    ::click-container-button-    ::click-container-    ::close-container-    ::change-container-slot-state-    ::cookie-response-    ::plugin-message-    ::debug-subscription-request-    ::edit-book-    ::query-entity-tag-    ::interact-    ::jigsaw-generate-    ::keep-alive-    ::lock-difficulty-    ::set-player-position-    ::set-player-position-and-rotation-    ::set-player-rotation-    ::set-player-movement-flags-    ::move-vehicle-    ::paddle-boat-    ::pick-item-from-block-    ::pick-item-from-entity-    ::ping-request-    ::place-recipe-    ::player-abilities-    ::player-action-    ::player-command-    ::player-input-    ::player-loaded-    ::pong-    ::change-recipe-book-settings-    ::set-seen-recipe-    ::rename-item-    ::resource-pack-response-    ::seen-advancements-    ::select-trade-    ::set-beacon-effect-    ::select-hotbar-slot-    ::program-command-block-    ::program-command-block-minecart-    ::set-creative-mode-slot-    ::set-game-rules-    ::program-jigsaw-block-    ::program-structure-block-    ::set-test-block-    ::update-sign

Show all 242 lines

src/net/bowmap/transport/connection.clj modified (view file)

@@ -3,10 +3,11 @@   (:require    [clojure.core.async :refer [<!! chan close! io-thread put! timeout]]    [net.bowmap.protocol.packet :as pk]-   [net.bowmap.protocol.packet.clientbound :as clientbound :refer [encode-packet!]]-   [net.bowmap.protocol.packet.serverbound :as serverbound :refer [decode-packet!]]+   [net.bowmap.protocol.packet.clientbound :as clientbound]+   [net.bowmap.protocol.packet.serverbound :as serverbound]    [net.bowmap.protocol.state :as state]    [net.bowmap.server.player :as player]+   [net.bowmap.transport.packets :refer [decode-packet! encode-packet!]]    [net.bowmap.transport.streams :as streams])   (:import    [java.io EOFException]

src/net/bowmap/transport/packet_types.clj renamed from src/net/bowmap/protocol/packet/types.clj (view file)

@@ -1,4 +1,4 @@-(ns net.bowmap.protocol.packet.types+(ns net.bowmap.transport.packet_types   (:require    [clojure.spec.alpha :as s])) 

src/net/bowmap/transport/packets.clj added (view file)

@@ -0,0 +1,75 @@+(ns net.bowmap.transport.packets+  (:require+   [net.bowmap.protocol.packet :as pk]+   [net.bowmap.protocol.packet.clientbound :as clientbound]+   [net.bowmap.transport.readers :as readers]+   [net.bowmap.protocol.packet.serverbound :as serverbound]+   [net.bowmap.transport.writers :as writers]+   [net.bowmap.protocol.state :as state])+  (:import+   [io.netty.buffer Unpooled]))++; TODO docstrings+(defn build-clientbound-packet-id-index+  [registry]+  (into {}+        (for [[state packet-ids] registry+              [i id] (map-indexed vector packet-ids)]+          [{::state/connection-state state+            ::pk/id id}+           i])))++(defn build-packet-writers+  [registry]+  (reduce (fn [acc [packet-id table]]+            (assoc acc packet-id (writers/coerce table)))+          {} registry))++(def clientbound-packet-ids (build-clientbound-packet-id-index clientbound/packet-order))+(def packet-encoders (build-packet-writers clientbound/packets))++(defn encode-packet!+  "Encodes a packet into a frame.+   Requires the connection state, as packet ids are not unique across connection states.+   Several packets are logically the same across states."+  [packet state]+  (let [payload-writer (req! packet-encoders (::pk/id packet))]+    (writers/length-prefixed (-> (Unpooled/buffer)+                                 (writers/varint-> (req! clientbound-packet-ids {::pk/id (::pk/id packet) ::state/connection-state state}))+                                 (payload-writer packet)))))++; Serverbound++(defn build-serverbound-packet-id-index+  "Takes a map of connection states to vectors of packet ids and returns a map of [connection-state numeric-id] to packet ids"+  [registry]+  (into {}+        (for [[state packet-ids] registry+                [i id] (map-indexed vector packet-ids)]+               [{::state/connection-state state+                 ::pk/numeric-id i}+                id])))+++(defn build-packet-readers [registry]+  (reduce (fn [acc [packet-id table]]+            (assoc acc packet-id+                   (let [reader (readers/coerce table)]+                     (fn [buf]+                       (assoc (reader buf)+                              ::pk/id packet-id)))))+          {} registry))++(def serverbound-packet-ids (build-serverbound-packet-id-index serverbound/packet-order))+(def packet-decoders (build-packet-readers serverbound/packets))++; So _this_ belongs in transport+; As do the above maps and functions+; But the schema is fine here :)+(defn decode-packet!+  "Decodes a packet from a frame."+  [frame connection-state]+  (let [numeric-id (readers/->varint frame)+        packet-id (req! serverbound-packet-ids {::state/connection-state connection-state ::pk/numeric-id numeric-id})+        decode-fn (req! packet-decoders packet-id)]+    (decode-fn frame)))

src/net/bowmap/transport/readers.clj renamed from src/net/bowmap/protocol/packet/readers.clj (view file)

@@ -1,10 +1,10 @@-(ns net.bowmap.protocol.packet.readers+(ns net.bowmap.transport.readers   "Functions for reading data from frames.    When given bad data, read functions will throw.    See https://minecraft.wiki/w/Java_Edition_protocol/Packets#Data_types"   (:require    [clojure.spec.alpha :as s]-   [net.bowmap.protocol.packet.types :as t]+   [net.bowmap.transport.packet_types :as t]    [net.bowmap.server.location :as location])   (:import    [io.netty.buffer ByteBuf]

src/net/bowmap/transport/streams.clj modified (view file)

@@ -1,7 +1,7 @@ (ns net.bowmap.transport.streams   "Functions for reading and writing frames from input and output streams"   (:require-   [net.bowmap.protocol.packet.types :as t])+   [net.bowmap.transport.packet_types :as t])   (:import    [io.netty.buffer ByteBuf Unpooled]    [java.io

src/net/bowmap/transport/writers.clj renamed from src/net/bowmap/protocol/packet/writers.clj (view file)

@@ -1,4 +1,4 @@-(ns net.bowmap.protocol.packet.writers+(ns net.bowmap.transport.writers   "Functions to write Minecraft protocol types.    When given bad data, write functions will throw.    See https://minecraft.wiki/w/Java_Edition_protocol/Packets#Data_types"@@ -6,7 +6,7 @@    [clojure.spec.alpha :as s]    [clojure.data.json :as json]    [clojure.set :as set]-   [net.bowmap.protocol.packet.types :as t])+   [net.bowmap.transport.packet_types :as t])   (:import    [io.netty.buffer ByteBuf CompositeByteBuf Unpooled]    [java.nio.charset Charset]