2dca1d5
Branches > main > 2dca1d5 > files / src / net / bowmap / transport
Move transport level concerns to the transport package
Commit: 2dca1d5643151a29159cc6f65cc7c951c6ad8096
Parent: 6d328bc
9 changed files:
src/net/bowmap/protocol/handle.clj 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 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-dialog-play]})--(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->)])])]})--(defn build-packet-id-index- "Builds a map of connection states and message ids to packet ids.- Message ids may be duplicated across connection states."- [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-encode-functions- "Builds a map of message ids to message writers."- [registry]- (reduce (fn [acc [packet-id table]]- (assoc acc packet-id (coerce table)))- {} registry))--(def packet-ids (build-packet-id-index packet-order))-(def packet-encoders (build-packet-encode-functions 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))]- (length-prefixed (-> (Unpooled/buffer)- (varint-> (req! packet-ids {::pk/id (::pk/id packet) ::state/connection-state state}))- (payload-writer packet)))))src/net/bowmap/protocol/packet/serverbound.clj 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-signsrc/net/bowmap/transport/connection.clj 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 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 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 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 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.iosrc/net/bowmap/transport/writers.clj 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]