bdc7514
Branches > main > bdc7514 > files
the great packet purge...
Commit: bdc751415d3b16e80e7d6a97ca57cfee015e61c9
Parent: a8bd38f
10 changed files:
src/net/bowmap/message_application.clj view file
@@ -73,23 +73,23 @@ {::msg/id ::clientbound/finish-config})}) (defn- build-chunk-messages []- (let [pk {::msg/id ::clientbound/chunk-data-and-update-light- :chunk-data- (let [stone {:block-count (* 16 16 16)- :block-states {:bpe 0- :palatte 1}- :biomes {:bpe 0- :palatte 0}}- air {:block-count 0- :block-states {:bpe 0- :palatte 0}- :biomes {:bpe 0- :palatte 0}}]- {:data (cons stone (repeat (- chunk/world-height-chunk-sections 1) air))})- :light-data {}}]+ (let [msg {::msg/id ::clientbound/chunk-data-and-update-light+ :chunk-data+ (let [stone {:block-count (* 16 16 16)+ :block-states {:bpe 0+ :palatte 1}+ :biomes {:bpe 0+ :palatte 0}}+ air {:block-count 0+ :block-states {:bpe 0+ :palatte 0}+ :biomes {:bpe 0+ :palatte 0}}]+ {:data (cons stone (repeat (- chunk/world-height-chunk-sections 1) air))})+ :light-data {}}] (for [x (range -16 17) z (range -16 17)]- (assoc pk+ (assoc msg :chunk-x x :chunk-z z)))) src/net/bowmap/network/minecraft_server.clj view file
@@ -9,10 +9,11 @@ [net.bowmap.network.protocol.message.clientbound :as clientbound] [net.bowmap.network.protocol.message.serverbound :as serverbound] [net.bowmap.network.protocol.state :as state]- [net.bowmap.network.server :as server]))+ [net.bowmap.network.server :as server]+ [net.bowmap.server.step :as step])) -(defn handle-incoming-packet [client packet outgoing-messages]- (let [message (serverbound/packet->message packet (::state/connection-state client))+(defn handle-incoming-frame [client frame outgoing-messages]+ (let [message (serverbound/frame->message frame (::state/connection-state client)) {::client/keys! [client] ::a/keys [messages keep-alive?]} (a/handle-message message client)] (doseq [message messages] (put! outgoing-messages message))@@ -25,18 +26,18 @@ (recur))))) client)) -(defn handle-packets!! [client outgoing-messages]+(defn handle-client!! [client outgoing-messages] (let [{::server/keys! [incoming-frames outgoing-frames]} client] (alt!! incoming-frames ([frame] (if (some? frame)- (handle-incoming-packet client frame outgoing-messages)+ (handle-incoming-frame client frame outgoing-messages) (raise "client incoming frame channel closed!"))) outgoing-messages ([message] (if (some? message)- (do (>!! outgoing-frames (clientbound/message->packet message (::state/connection-state client)))+ (do (>!! outgoing-frames (clientbound/message->frame message (::state/connection-state client))) client) (raise "client outgoing message channel closed!")))))) @@ -44,7 +45,7 @@ (let [outgoing-messages (chan 1024)] (io-thread (loop [client client]- (recur (handle-packets!! client outgoing-messages))))+ (recur (handle-client!! client outgoing-messages)))) nil)) (defn closing-promise@@ -69,4 +70,8 @@ (do (connect! client) (recur)) (deliver shutdown :shutdown))))+ (io-thread+ (loop [model model]+ (let [[model' effects] (step/step model fact)])+ (recur))) shutdown))src/net/bowmap/network/protocol/frame.clj view file
@@ -0,0 +1,10 @@+(ns net.bowmap.network.protocol.frame+ (:require+ [clojure.spec.alpha :as s])+ (:import+ [io.netty.buffer ByteBuf]))++; The serialized byte form of a message+; See https://minecraft.wiki/w/Java_Edition_protocol/Packets++(s/def ::frame #(instance? ByteBuf %))src/net/bowmap/network/protocol/message.clj view file
@@ -4,15 +4,14 @@ [dev.grahp.spec :as S])) (S/def ::id- "The id of a message. See the serverbound and clientbound packet definitions for the names."+ "The id of a message. See the serverbound and clientbound message definitions for the names." qualified-keyword?) (S/def ::numeric-id- "Protocol id of a packet, i.e. 0x00, 0x80, etc.+ "Protocol id of a message, i.e. 0x00, 0x80, etc. Numeric ids are NOT unique across connection states! See the wiki" pos-int?) (S/def ::message- "Represents a logical message map (object) from client to/from server.- 'Packet' is used to refer to a serialized message"+ "Represents a logical message map (object) from client to/from server." (s/keys :opt [::id]))src/net/bowmap/network/protocol/message/clientbound.clj view file
@@ -4,7 +4,7 @@ [clojure.spec.alpha :as s] [dev.grahp.build :refer [build]] [net.bowmap.network.protocol.message :as msg]- [net.bowmap.network.protocol.packet :as pk]+ [net.bowmap.network.protocol.frame :as frame] [net.bowmap.network.protocol.types :as t] [net.bowmap.network.protocol.writers :as write :refer [bit-mask-> boolean-> byte-> chunk-data-> coerce context-optional->@@ -17,34 +17,34 @@ (:import [io.netty.buffer Unpooled])) -(defn build-packet-ids- "Builds a map of connection states and message ids to packet ids.+(defn build-numeric-ids+ "Builds a map of connection states and message ids to numeric ids. Message ids may be duplicated across connection states." [registry]- (build [[state packet-ids] registry- [i id] (map-indexed vector packet-ids)]+ (build [[state numeric-ids] registry+ [i id] (map-indexed vector numeric-ids)] [{::state/connection-state state ::msg/id id} i])) -(s/fdef build-packet-ids+(s/fdef build-numeric-ids :args (s/cat :registry (s/map-of ::state/connection-state (s/coll-of ::msg/id :type vector?))) :ret (s/map-of (s/keys :opt [::state/connection-state ::msg/id]) ::msg/numeric-id)) -(defn build-packets+(defn build-messages "Builds a map of message ids to message writers." [registry]- (reduce (fn [acc [packet-id table]]- (assoc acc packet-id (coerce table)))+ (reduce (fn [acc [numeric-id table]]+ (assoc acc numeric-id (coerce table))) {} registry)) -(s/fdef build-packets+(s/fdef build-messages :args (s/cat :registry (s/map-of ::msg/id ::t/table)) :ret (s/map-of ::msg/id ::write/writer)) ; TODO terrible name?-(def message->packet-ids- (build-packet-ids+(def numeric-id+ (build-numeric-ids {::state/status [::status-response ::pong-response]@@ -219,8 +219,8 @@ ::clear-dialog ::show-dialog-play]})) -(def packets- (build-packets+(def messages+ (build-messages {::status-response [:response "Response to serverbound ::status-request" json->] ::pong-response [:timestamp "The same timestamp as serverbound ::ping-request" long->] ::login-success [:uuid uuid->@@ -283,17 +283,17 @@ :relative-velocity-x :relative-velocity-y :relative-velocity-z :rotate-velocity])]})) -(defn message->packet- "Encodes a message into a packet.- Like decoding, encoding a packet requires the connection state, as packet- ids are not unique across connection states. Several packets are logically+(defn message->frame+ "Encodes a message into a frame.+ Like decoding, encoding a message requires the connection state, as message+ ids are not unique across connection states. Several messages are logically the same across states, and can be sent without needing to switch on state." [msg state]- (let [payload-writer (req! packets (::msg/id msg))]+ (let [payload-writer (req! messages (::msg/id msg))] (length-prefixed (-> (Unpooled/buffer)- (varint-> (req! message->packet-ids {::msg/id (::msg/id msg) ::state/connection-state state}))+ (varint-> (req! numeric-id {::msg/id (::msg/id msg) ::state/connection-state state})) (payload-writer msg))))) -(s/fdef message->packet+(s/fdef message->frame :args (s/cat :msg ::msg/message :state ::state/connection-state)- :ret ::pk/packet)+ :ret ::frame/frame)src/net/bowmap/network/protocol/message/serverbound.clj view file
@@ -5,7 +5,7 @@ [dev.grahp.build :refer [build]] [dev.grahp.error :refer [adorn raise]] [net.bowmap.network.protocol.message :as msg]- [net.bowmap.network.protocol.packet :as pk]+ [net.bowmap.network.protocol.frame :as frame] [net.bowmap.network.protocol.readers :refer [->bit-mask ->byte ->double ->enum ->float ->identifier ->int ->list ->long ->optional ->position ->short ->string ->ubyte@@ -16,19 +16,19 @@ ; TODO docstring, rename? (defn build-message-readers [registry]- (reduce (fn [acc [packet-id table]]- (assoc acc packet-id+ (reduce (fn [acc [numeric-id table]]+ (assoc acc numeric-id (let [reader (coerce table)] (fn [buf] (assoc (reader buf)- ::msg/id packet-id)))))+ ::msg/id numeric-id))))) {} registry)) ; TODO docstring, rename? ; TODO spec for sure (defn build-message-id-map [registry]- (build [[state packet-ids] registry- [i id] (map-indexed vector packet-ids)]+ (build [[state numeric-ids] registry+ [i id] (map-indexed vector numeric-ids)] [{::state/connection-state state ::msg/numeric-id i} id]))@@ -132,7 +132,7 @@ (def ^{:spec (s/map-of ::msg/id (s/fspec :args (s/cat :buf #(instance? ByteBuf %)) :ret ::msg/message))}- packets+ messages (build-message-readers ; Handshaking {::handshaking [:protocol ->varint@@ -174,8 +174,8 @@ ::custom-click-action TODO ::accept-code-of-conduct TODO - ;; This packet has more fields I just don't care about them :p- ;; This packet also has a bunch of fields that I probably do care about!+ ;; This message has more fields I just don't care about them :p+ ;; This message also has a bunch of fields that I probably do care about! ; Play @@ -263,28 +263,28 @@ ::use-item TODO})) (assert (= (set (vals numeric-ids))- (set (keys packets))))+ (set (keys messages)))) (comment (require '[clojure.set :as set]) (let [all-ids (set (vals numeric-ids))- present-ids (set (keys packets))]+ present-ids (set (keys messages))] (set/difference all-ids present-ids))) -(defn packet->message- "Deserializes one (framed, serialized) packet into a message.- The initial length field of the packet should be stripped from the buffer.+(defn frame->message+ "Deserializes one frame into a message.+ The initial length field of the frame should be stripped from the buffer! Can throw if:- 1. No such packet with the given numeric id and state exists- 2. No schema exists for that packet id+ 1. No such frame with the given numeric id and state exists+ 2. No schema exists for that message id 3. 'buf' is not properly framed- 4. The contents of 'buf' are not a valid packet"- [packet state]- (let [numeric-id (->varint packet)+ 4. The contents of 'buf' are not a valid message"+ [frame state]+ (let [numeric-id (->varint frame) message-id (req! numeric-ids {::state/connection-state state ::msg/numeric-id numeric-id})- reader (req! packets message-id)]- (adorn (reader packet) "Error while calling packet reader" {:numeric-id numeric-id :packet-id message-id :reader reader})))+ reader (req! messages message-id)]+ (adorn (reader frame) "Error while calling message reader" {:numeric-id numeric-id :message-id message-id :reader reader}))) -(s/fdef packet->message- :args (s/cat :packet ::pk/packet :state ::state/connection-state)+(s/fdef frame->message+ :args (s/cat :frame ::frame/frame :state ::state/connection-state) :ret ::msg/message)src/net/bowmap/network/protocol/packet.clj view file
@@ -1,11 +0,0 @@-(ns net.bowmap.network.protocol.packet- (:require- [dev.grahp.spec :as S])- (:import- [io.netty.buffer ByteBuf]))--; The serialized byte form of a message-; See https://minecraft.wiki/w/Java_Edition_protocol/Packets--; TODO rename to a frame, packet is still an overloaded term-(S/def ::packet #(instance? ByteBuf %))src/net/bowmap/network/protocol/readers.clj view file
@@ -1,5 +1,5 @@ (ns net.bowmap.network.protocol.readers- "Functions for reading data from serialized packet ByteBufs.+ "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" (:requiresrc/net/bowmap/network/server.clj view file
@@ -7,24 +7,24 @@ [java.net ServerSocket Socket])) (defn new-client [socket]- (let [packets-in (chan)- packets-out (chan)]+ (let [incoming-frames (chan)+ outgoing-frames (chan)] (io-thread (loop [] (try (let [frame (stream/read-frame!! (Socket/.getInputStream socket))]- (>!! packets-in frame))+ (>!! incoming-frames frame)) (catch Exception _- ; Disconnect packet?+ ; Disconnect? (Socket/.close socket))) (recur))) (io-thread (loop []- (let [frame (<!! packets-out)]+ (let [frame (<!! outgoing-frames)] (stream/write-frame!! frame (Socket/.getOutputStream socket))) (recur)))- {::incoming-frames packets-in- ::outgoing-frames packets-out}))+ {::incoming-frames incoming-frames+ ::outgoing-frames outgoing-frames})) (defn start-tcp-server! "Starts a TCP server at the given port. Returns a channel of clients as they connect.src/net/bowmap/server/step.clj view file
@@ -3,7 +3,7 @@ ; Where is this called, who's controlling this loop? (defn step [model fact] ; -> [model [effects]] (case (:id model)- :status-requested ; Effect status response which eventually sends out packets to the client+ :status-requested ; Effect status response which eventually sends out messages to the client (let [{:keys! [client]} fact] [model [{:effect/id :send-status-response