628768c
Branches > main > 628768c > files / src / dev / grahp
Switch clientbound packets to use functions instead of macros
Commit: 628768cbbe49e56824f5bba60570f7780d7c05da
Parent: 2bdfa58
7 changed files:
src/net/bowmap/core.clj view file
@@ -5,7 +5,7 @@ [net.bowmap.client.state :as state] [net.bowmap.packet.read :as read] [net.bowmap.packet-handling :as handle]- [net.bowmap.packets.client :refer [encode-packet]]+ [net.bowmap.packet.client :refer [encode-packet]] [net.bowmap.packet.server :as sp]) (:import [io.netty.buffer ByteBuf Unpooled]src/net/bowmap/packet/client.clj src/net/bowmap/packets/client.clj view file
@@ -1,47 +1,27 @@-(ns net.bowmap.packets.client+(ns net.bowmap.packet.client "Clientbound packets" (:require [clojure.alpha.spec :as s] [dev.grahp.error :refer [assert!]] [net.bowmap.client.state :as state]- [net.bowmap.codecs.write :as write :refer [write-varint!]]- [net.bowmap.packet :as pk :refer [packet?]]- [net.bowmap.packets.registry :as reg])+ [net.bowmap.packet :as pk]+ [net.bowmap.packet.write :as write]) (:import [io.netty.buffer ByteBuf Unpooled])) -;; A lot of work to do in this file lol- ;; TODO this also looks identical to the serverbound packet ids...-(defmacro build-packet-ids [registry]+;; It is equally unreadable lmao+(defn build-packet-ids [registry] (into {} (mapcat (fn [[state packet-ids]] (into {} (map-indexed (fn [i pk] [{::state/state state ::pk/id pk} i])) packet-ids))) registry)) -(defn build-packet [pk-name schema]- (let [fn-name (symbol (str "encode-" (name pk-name) "-packet"))- fields (map :field schema)- types (map :type schema)- codecs (map write/writer types)- name-codec-pairs (for [codec codecs]- [(gensym) codec])- codec-names (map first name-codec-pairs)- bindings (apply concat name-codec-pairs)- pairs? (map vector fields codec-names)- buf (gensym "buf__")- pk (gensym "pk__")]- `(let [~@bindings]- (fn ~fn-name [~buf ~pk]- ~@(for [[field codec] pairs?]- `(~codec ~buf (~field ~pk)))- ~buf))))--(defmacro build-packets [registry]- (reduce (fn [acc [packet-id schema]]- (assoc acc packet-id (build-packet packet-id schema)))- {} (reg/conform-registry registry)))+(defn build-packets [registry]+ (reduce (fn [acc [packet-id table]]+ (assoc acc packet-id (write/writer [:table table])))+ {} registry)) (def ^{:spec (s/map-of (s/schema [::state/state ::pk/id]) ::pk/numeric-id)} packet-ids@@ -61,9 +41,6 @@ ::login-plugin-request ::login-cookie-request]})) -(defn numeric-id [state id]- (packet-ids {::state/state state ::pk/id id}))- (def ^{:spec (s/map-of ::pk/id (s/fspec :args (s/cat :buf #(instance? ByteBuf %) :pk ::pk/packet) :ret #(instance? ByteBuf %)))} packets@@ -76,19 +53,22 @@ :value :string :signature [:optional :string]]]]]})) +(defn numeric-id [state id]+ (packet-ids {::state/state state ::pk/id id}))+ (defn packet-encoder [pk] (packets (::pk/id pk))) (defn encode-packet "Encodes packet 'pk' into a ByteBuf of the packet bytes." [pk state]- {:pre [(packet? pk)]}+ {:pre [(pk/packet? pk)]} (let [id (assert! (numeric-id state (::pk/id pk))) encoder (assert! (packet-encoder pk)) data-buf (-> (Unpooled/buffer)- (write-varint! id)+ (write/write-varint! id) (encoder pk))] ;; This buffer only contains the data + a varint, which can never be larger than 5 bytes (-> (Unpooled/buffer (+ (ByteBuf/.writerIndex data-buf) 5))- (write-varint! (ByteBuf/.writerIndex data-buf))+ (write/write-varint! (ByteBuf/.writerIndex data-buf)) (ByteBuf/.writeBytes data-buf))))src/net/bowmap/packet/read.clj view file
@@ -2,7 +2,7 @@ (:require [clojure.alpha.spec :as s] [dev.grahp.error :refer [ensure-not! raise]]- [net.bowmap.packets.registry :as reg])+ [net.bowmap.packet.types :as t]) (:import [io.netty.buffer ByteBuf] [java.nio.charset Charset]@@ -76,7 +76,7 @@ :string read-string! :uuid read-uuid! :table (fn [table]- (let [table (->> (s/conform ::reg/table table)+ (let [table (->> (s/conform ::t/table table) ;; TODO make this :codec (mapv #(update % :type reader)))] (fn [buf]src/net/bowmap/packet/types.clj view file
@@ -0,0 +1,8 @@+(ns net.bowmap.packet.types+ (:require+ [clojure.alpha.spec :as s]))++(s/def ::table+ (s/* (s/cat :field keyword?+ :doc (s/? string?)+ :type #(or (keyword? %) (vector? %)))))src/net/bowmap/packet/write.clj src/net/bowmap/codecs/write.clj view file
@@ -1,14 +1,13 @@-(ns net.bowmap.codecs.write+(ns net.bowmap.packet.write (:require- [clojure.alpha.spec :as s]- [clojure.data.json :as json]- [dev.grahp.error :refer [raise]]- [net.bowmap.codecs.types :as types]- [net.bowmap.packets.registry :as reg])+ [clojure.alpha.spec :as s]+ [clojure.data.json :as json]+ [dev.grahp.error :refer [raise]]+ [net.bowmap.packet.types :as t]) (:import- [io.netty.buffer ByteBuf Unpooled]- [java.nio.charset Charset]- [java.util UUID]))+ [io.netty.buffer ByteBuf]+ [java.nio.charset Charset]+ [java.util UUID])) (defn write-varint! [buf n] (loop [buf buf@@ -29,8 +28,10 @@ (write-string! buf (json/write-str s))) (defn write-list! [buf t xs]+ ;; Reduce :p (doseq [x xs]- (t buf x)))+ (t buf x))+ buf) (defn write-uuid! [buf uuid] (ByteBuf/.writeLong buf (UUID/.getMostSignificantBits uuid))@@ -39,14 +40,15 @@ ;; TODO this is where optionality and nil checking should be, and the packet stuff should use this. (defn write-table! [buf t? m] (doseq [{:keys [field type]} t?]- (type buf (get m field))))+ (type buf (get m field)))+ buf) (declare writers) ;; I think this should have :required/:optional/:prefixed-optional, ;; and have it that non-optional fields are implicity :required and thus nil checked (defn writer- "Returns a form that will evaluate to a function that takes a buffer and writes the respective type to it."+ "" [t] (if (vector? t) (let [[t & args] t]@@ -64,29 +66,35 @@ (codec buf x) buf)) +(defn write-optional! [buf codec x]+ (write-boolean! buf x)+ (write-context-optional! buf codec x))+ (def writers- {:byte `ByteBuf/.writeByte- :ubyte `ByteBuf/.writeByte- :short `ByteBuf/.writeShort- :ushort `ByteBuf/.writeShort- :int `ByteBuf/.writeInt- :long `ByteBuf/.writeLong- :varint `write-varint!- :string `write-string!- :json `write-json!- :uuid `write-uuid!+ {:byte ByteBuf/.writeByte+ :ubyte ByteBuf/.writeByte+ :short ByteBuf/.writeShort+ :ushort ByteBuf/.writeShort+ :int ByteBuf/.writeInt+ :long ByteBuf/.writeLong+ :varint write-varint!+ :string write-string!+ :json write-json!+ :uuid write-uuid!+ ;; TODO These are kinda named backwards... :context-optional (fn [t]- `(fn ~'write-context-optional [buf# x#]- (write-context-optional! buf# ~(writer t) x#)))+ (let [codec (writer t)]+ (fn [buf x]+ (write-context-optional! buf codec x)))) :optional (fn [t]- `(fn ~'write-optional [buf# x#]- (write-boolean! buf# x#)- (write-context-optional! buf# ~(writer t) x#)))+ (let [codec (writer t)]+ (fn [buf x]+ (write-optional! buf codec x)))) :table (fn [t]- ;; TODO needs to be moved yeah.- (let [t (->> (s/conform ::reg/table t)src/net/bowmap/packet_handling.clj view file
@@ -2,7 +2,7 @@ (:require [net.bowmap.client.state :as state] [net.bowmap.packet :as pk]- [net.bowmap.packets.client :as cp]+ [net.bowmap.packet.client :as cp] [net.bowmap.packet.server :as sp])) (defmulti handle-packetsrc/net/bowmap/packets/registry.clj view file
@@ -1,21 +0,0 @@-(ns net.bowmap.packets.registry- (:require- [clojure.alpha.spec :as s]- [dev.grahp.error :refer [raise]]- [net.bowmap.packet :as pk]))--(s/def ::table- (s/* (s/cat :field keyword?- :doc (s/? string?)- :type #(or (keyword? %) (vector? %)))))--(s/def ::packet-registry- (s/map-of ::pk/id ::table))--(defn conform-registry- "Returns a registry conformed to '::packet-registry', or throws if it is invalid"- [registry]- (let [registry (s/conform ::packet-registry registry)]- (if (= ::s/invalid registry)- (raise "Invalid packet registry!" {:explanation (s/explain-data ::packet-registry registry)})- registry)))