2817adb
Branches > main > 2817adb > files / src / net / bowmap / network / registry.clj
big ol' packet/message refactor
Commit: 2817adb0bf5e7739d4e83d214b8efb20cf71fa15
Parent: 409601f
14 changed files:
src/net/bowmap/core.clj view file
@@ -1,12 +1,12 @@ (ns net.bowmap.core (:require [clojure.core.async :refer [<!! >!! alt!! chan io-thread put! timeout]]- [net.bowmap.client.state :as state]- [net.bowmap.packet :as pk]+ [net.bowmap.network.message :as msg]+ [net.bowmap.network.state :as state] [net.bowmap.packet-handling :as handle]- [net.bowmap.packet.client :as cp]- [net.bowmap.packet.server :as sp]- [net.bowmap.server :as server]))+ [net.bowmap.network.message.client :as client]+ [net.bowmap.network.message.server :as server]+ [net.bowmap.server :as server-managere-instance-thing-not-sure-what-to-call-it])) ; Glossary to probably use @@ -18,7 +18,7 @@ "Handles one ByteBuf of a framed serialized serverbound packet, and returns a map of :client and :packets." [client packet-buf]- (let [pk (sp/decode-packet packet-buf (::state/state client))]+ (let [pk (server/packet->message packet-buf (::state/state client))] (handle/response client pk))) ; could return a map of side-effects as data and be pure.@@ -55,14 +55,14 @@ (io-thread (loop [] (<!! (timeout 5000))- (when (>!! packets-out {::pk/id ::cp/keep-alive+ (when (>!! packets-out {::msg/id ::client/keep-alive :id (long (* (rand) Long/MAX_VALUE))}) (recur))))) (doseq [pk (:response response)] (put! packets-out pk)) (:client response)))) packets-out ([pk]- (assert (>!! out (cp/encode-packet pk (::state/state client))))+ (assert (>!! out (client/encode-packet pk (::state/state client)))) client))) ; Do I need to close out?@@ -76,7 +76,7 @@ (println "In client handler: " e))))) (defn start-server []- (server/start-server2! {:handler #'client-handler+ (server-managere-instance-thing-not-sure-what-to-call-it/start-server2! {:handler #'client-handler :port 25565})) (defn -main [& _args]src/net/bowmap/network/chunk.clj src/net/bowmap/packet/chunk.clj view file
@@ -1,4 +1,4 @@-(ns net.bowmap.packet.chunk+(ns net.bowmap.network.chunk (:require [clojure.alpha.spec :as s])) (s/def ::coordinate (s/schema [::x ::y ::z]))src/net/bowmap/network/message.clj src/net/bowmap/packet.clj view file
@@ -1,14 +1,10 @@-(ns net.bowmap.packet- (:require [clojure.alpha.spec :as s]))+(ns net.bowmap.network.message+ (:require+ [clojure.alpha.spec :as s])) -; The protocol id of a packet, i.e. 0x00, 0x80, etc.-; Numeric ids are not unique across connection states (see ::net.bowmap.client.state/state)-(s/def ::numeric-id pos-int?)-; The name of the packet id keyword, i.e. ::server/handshaking-; ::ids are also not unique across connections states, as a few packets are repeated across-; states, such as disconnect and keepalive+; TODO update comments they are old+ (s/def ::id qualified-keyword?)- ; Represents a deserialized Minecraft protocol packet ; See net.bowmap.packets.client and net.bowmap.packets.server for those. ; In serialized form, uncompressed packets have the following structure:@@ -20,8 +16,8 @@ ; direct function of numeric ids to '::id's, or vice versa. ; See 'net.bowmap.packet.client/packet-ids' and 'net.bowmap.packet.server/packet-ids'. ; Packet maps will also contain other fields as defined in the 'packets' var of the above namespaces-(s/def ::packet (s/schema [::id]))+(s/def ::message (s/schema [::id])) ; This could actually check the id and fields to see if it's valid if there's any point in that-(defn packet? [x]- (some? (::id x)))+(defn message? [x]+ (boolean (find x ::id)))src/net/bowmap/network/message/client.clj src/net/bowmap/packet/client.clj view file
@@ -1,12 +1,20 @@-(ns net.bowmap.packet.client+; TODO+(ns net.bowmap.network.message.client "Clientbound packets" (:require [clojure.alpha.spec :as s] [dev.grahp.build :refer [build]] [dev.grahp.error :refer [adorn assert!]]- [net.bowmap.client.state :as state]- [net.bowmap.packet :as pk]- [net.bowmap.packet.write :as write])+ [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->]]+ [net.bowmap.network.state :as state]) (:import [io.netty.buffer ByteBuf CompositeByteBuf Unpooled])) @@ -14,16 +22,18 @@ (build [[state packet-ids] registry [i id] (map-indexed vector packet-ids)] [{::state/state state- ::pk/id id}+ ::msg/id id} i])) (defn build-packets [registry] (reduce (fn [acc [packet-id table]]- (assoc acc packet-id (write/writer [:table table])))+ (assoc acc packet-id (table-> table))) {} registry)) -(def ^{:spec (s/map-of (s/schema [::state/state ::pk/id]) ::pk/numeric-id)}+(def ^{:spec (s/map-of (s/schema [::state/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.@@ -202,60 +212,60 @@ ::clear-dialog ::show-dialog-play]})) -(def ^{:spec (s/map-of ::pk/id (s/fspec :args (s/cat :buf #(instance? ByteBuf %) :pk ::pk/packet)+(def ^{:spec (s/map-of ::msg/id (s/fspec :args (s/cat :buf #(instance? ByteBuf %) :pk ::msg/message) :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]- ::login-success [:uuid :uuid- :username :string- :properties [:list [:table [:name :string- :value :string- :signature [:optional :string]]]]]- ::known-packs [:known-packs [:list [:table [:namespace :string- :id :string- :version :string]]]]+ {::status-response [:response "Response to ::sp/status-request" json->]+ ::pong-response [:timestamp "The same timestamp as ::sp/ping-request" long->]+ ::login-success [:uuid uuid->+ :username string->+ :properties (list-> (table-> [:name string->+ :value string->+ :signature (optional-> string->)]))]+ ::known-packs [:known-packs (list-> (table-> [:namespace string->+ :id string->+ :version string->]))] - ::registry-data [:registry-id :identifier- :entries [:list [:table [:id :identifier- :data [:optional :nbt]]]]]- ::keep-alive [:id :long]+ ::registry-data [:registry-id identifier->+ :entries (list-> (table-> [:id identifier->+ :data (optional-> nbt->)]))]+ ::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+ ::login [:entity-id int->+ :hardcore? boolean->src/net/bowmap/network/message/server.clj src/net/bowmap/packet/server.clj view file
@@ -1,36 +1,40 @@-(ns net.bowmap.packet.server+(ns net.bowmap.network.message.server (:require [clojure.alpha.spec :as s] [dev.grahp.build :refer [build]]- [dev.grahp.error :refer [raise]]- [net.bowmap.client.state :as state]- [net.bowmap.packet :as pk]- [net.bowmap.packet.read :as read])+ [dev.grahp.error :refer [adorn raise]]+ [net.bowmap.network.message :as msg]+ [net.bowmap.network.packet :as pk]+ [net.bowmap.network.packet.read :refer [->bit-mask ->byte ->double ->enum+ ->float ->long ->short ->string+ ->table ->ubyte ->uuid ->varint]]+ [net.bowmap.network.state :as state]) (:import [io.netty.buffer ByteBuf])) -; TODO docstring-(defn build-packets [registry]+; TODO docstring, rename?+(defn build-message-readers [registry] (reduce (fn [acc [packet-id table]] (assoc acc packet-id- (let [reader (read/reader [:table table])]+ (let [reader (->table table)] (fn [buf] (assoc (reader buf)- ::pk/id packet-id)))))+ ::msg/id packet-id))))) {} registry)) -; TODO docstring-(defn build-packet-ids [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)] [{::state/state state- ::pk/numeric-id i}+ ::pk/id i} id])) ; TODO document why ids are enumerated like this?-(def ^{:spec (s/map-of (s/schema [::state/state ::pk/numeric-id]) ::pk/id)}+(def ^{:spec (s/map-of (s/schema [::state/state ::pk/id]) ::msg/id)} packet-ids- (build-packet-ids+ (build-message-id-map {::state/handshaking [::handshaking] ::state/status@@ -121,18 +125,18 @@ ::use-item ::custom-click-action]})) -(def ^{:spec (s/map-of ::pk/id (s/fspec :args (s/cat :buf #(instance? ByteBuf %))- :ret ::pk/packet))}+(def ^{:spec (s/map-of ::msg/id (s/fspec :args (s/cat :buf #(instance? ByteBuf %))+ :ret ::msg/message))} packets- (build-packets- {::handshaking [:protocol :varint- :address :string- :port :short- :intent [:enum :varint {1 ::state/status 2 ::state/login 3 ::state/transfer}]]+ (build-message-readers+ {::handshaking [:protocol ->varint+ :address ->string+ :port ->short+ :intent (->enum ->varint {1 ::state/status 2 ::state/login 3 ::state/transfer})] ::status-request []- ::ping-request [:timestamp :long]- ::login-start [:username :string- :uuid :uuid]+ ::ping-request [:timestamp ->long]+ ::login-start [:username ->string+ :uuid ->uuid] ::login-acknowledged [] ;; This packet has more fields I just don't care about them :p ::plugin-message []@@ -140,26 +144,26 @@ ::client-information [] ::known-packs [] ::finish-config []- ::keep-alive [:id :long]+ ::keep-alive [:id ->long] ::client-tick-end [] ::player-loaded []- ::player-input [:flags [:bit-mask :ubyte [:forward :backward :left :right :jump :sneak :sprint]]]- ::set-player-rotation [:yaw :float- :pitch :float- :flags :byte]- ::set-player-position [:x :double- :feet-y :double- :z :double- :flags :byte]src/net/bowmap/network/packet.clj view file
@@ -0,0 +1,7 @@+(ns net.bowmap.network.packet+ (:require [clojure.alpha.spec :as s]))++; The protocol id of a packet, i.e. 0x00, 0x80, etc.+; Numeric ids are not unique across connection states (see ::net.bowmap.client.state/state)+; TODO rename to ::id+(s/def ::id pos-int?)src/net/bowmap/network/packet/read.clj src/net/bowmap/packet/read.clj view file
@@ -1,11 +1,11 @@-(ns net.bowmap.packet.read+(ns net.bowmap.network.packet.read "Functions for reading data from serialized packet ByteBufs. When given bad data, read functions will throw. See https://minecraft.wiki/w/Java_Edition_protocol/Packets#Data_types" (:require- [clojure.alpha.spec :as s]- [dev.grahp.error :refer [ensure-not! raise]]- [net.bowmap.packet.types :as t])+ [dev.grahp.error :refer [adorn ensure-not! raise]]+ [dev.grahp.spec :as spec]+ [net.bowmap.network.packet.types :as t]) (:import [io.netty.buffer ByteBuf] [java.nio.charset Charset]@@ -17,7 +17,7 @@ [buf] (loop [num-read 0 result 0]- (if (>= num-read 5)+ (if (>= num-read t/max-varint-size) (raise "VarInt too long") (when (< num-read (ByteBuf/.readableBytes buf)) (let [b (ByteBuf/.getByte buf (+ (ByteBuf/.readerIndex buf)@@ -27,10 +27,10 @@ (>= (ByteBuf/.readableBytes buf) (+ result' num-read 1)) (recur (inc num-read) result'))))))) -(defn read-varint! [buf]+(defn ->varint [buf] (loop [num-read 0 result 0]- (if (>= num-read 5)+ (if (>= num-read t/max-varint-size) (raise "VarInt too long") (let [b (ByteBuf/.readByte buf) result' (bit-or result (bit-shift-left (bit-and b 0x7F) (* 7 num-read)))]@@ -38,26 +38,16 @@ result' (recur (inc num-read) result')))))) -(defn read-string! [buf]- (let [len (read-varint! buf)]+(defn ->string [buf]+ (let [len (->varint buf)] (ensure-not! neg? len) (ByteBuf/.readCharSequence buf len (Charset/forName "UTF-8")))) -(defn read-uuid! [buf]+(defn ->uuid [buf] (UUID. (ByteBuf/.readLong buf) (ByteBuf/.readLong buf))) -(defn read-enum! [codec m buf]- (m (codec buf)))- #_(defn read-array [codec len buf]) -(defn read-table! [buf codec-fields]- (reduce (fn [acc {:keys [field codec]}]- (if-some [x (codec buf)]- (assoc acc field x)- acc))- {} codec-fields))- (defn- mapize-vector-or-something "Returns a map of keys to vals, where vectors will map their indecies to their values." [x]@@ -66,7 +56,7 @@ (zipmap (range) x) x)) -(defn read-bit-mask! [buf codec mask]+(defn ^:prviate read-bit-mask! [buf codec mask] (let [n (codec buf)] (reduce-kv (fn [acc bit x] (if (bit-test n bit)@@ -74,40 +64,34 @@ acc)) #{} mask))) -(declare readers)+(def ->byte ByteBuf/.readByte)+(def ->ubyte (comp unchecked-byte ByteBuf/.readByte))+(def ->short ByteBuf/.readShort)+(def ->ushort (comp unchecked-byte ByteBuf/.readShort))+(def ->int ByteBuf/.readInt)+(def ->long ByteBuf/.readLong)+(def ->float ByteBuf/.readFloat)+(def ->double ByteBuf/.readDouble) -(defn reader- "Returns a function of a ByteBuf that reads the respective type, as defined by 'readers'.- Throws if no such type exists."- [t]- (if (vector? t)- (let [[t & args] t]- (apply (reader t) args))- (or (readers t)- (raise (str "No such type! " (name t)) {:type t}))))+(def ->identifer ->string) -(def readers- "Map of type names to read functions.- See https://minecraft.wiki/w/Java_Edition_protocol/Packets#Data_types"- {:byte ByteBuf/.readByte- :ubyte (comp unchecked-byte ByteBuf/.readByte)- :short ByteBuf/.readShort- :ushort (comp unchecked-short ByteBuf/.readShort)- :int ByteBuf/.readInt- :long ByteBuf/.readLong- :float ByteBuf/.readFloat- :double ByteBuf/.readDouble- :varint read-varint!- :string read-string!- :uuid read-uuid!- :identifer read-string!- :bit-mask (fn [t mask]- (let [mask (mapize-vector-or-something mask)]- (fn [buf] (read-bit-mask! buf (reader t) mask))))- :table (fn [table]- (let [table (->> (s/conform ::t/table table)- (mapv #(assoc % :codec (reader (:type %)))))]- (fn [buf]- (read-table! buf table))))- :enum (fn [t m]- (fn [buf] (read-enum! (reader t) m buf)))})+(defn ->enum [reader m]+ (fn [buf]+ (m (reader buf))))++; Table is a keyword?+(defn ->table [table-fields]+ ; TODO other one too+ (let [table (spec/ensure-conform ::t/table table-fields)]+ (fn [buf]+ (reduce (fn [acc {::t/keys [field codec]}]+ (adorn (if-some [x (codec buf)]+ (assoc acc field x)+ acc)+ "Error while reading message table field" {:table table :field field :codec codec}))+ {} table))))++(defn ->bit-mask [reader mask]+ (let [mask (mapize-vector-or-something mask)]+ (fn [buf]+ (read-bit-mask! buf reader mask))))src/net/bowmap/network/packet/types.clj view file
@@ -0,0 +1,13 @@+(ns net.bowmap.network.packet.types+ (:require+ [clojure.alpha.spec :as s]))++(def max-varint-size 5)+(def max-varlong-size 5)++; Tables used by readers and writers+; see reader and write functions 'read-table!' and 'write-table!'+(s/def ::table+ (s/* (s/cat ::field keyword?+ ::doc (s/? string?)+ ::codec fn?)))src/net/bowmap/network/packet/write.clj src/net/bowmap/packet/write.clj view file
@@ -1,19 +1,19 @@-(ns net.bowmap.packet.write+(ns net.bowmap.network.packet.write "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" (:require- [clojure.alpha.spec :as s] [clojure.data.json :as json] [clojure.set :as set] [dev.grahp.error :refer [adorn raise]]- [net.bowmap.packet.types :as t])+ [dev.grahp.spec :as spec]+ [net.bowmap.network.packet.types :as t]) (:import [io.netty.buffer ByteBuf] [java.nio.charset Charset] [java.util UUID])) -(defn write-varint! [buf n]+(defn varint-> [buf n] (loop [buf buf n n] (let [b (bit-and n 0x7F)@@ -23,51 +23,49 @@ (recur (ByteBuf/.writeByte buf (bit-or b 0x80)) nxt))))) -(defn write-string! [buf s]+(defn string-> [buf s] (doto buf- (write-varint! (count s))+ (varint-> (count s)) (ByteBuf/.writeCharSequence s (Charset/forName "UTF-8")))) -(defn write-json! [buf s]- (write-string! buf (json/write-str s)))+(defn json-> [buf s]+ (string-> buf (json/write-str s))) -(defn write-array! [buf codec xs]- (reduce (fn [acc x]- (codec acc x))- buf xs))+(defn array-> [writer]+ (fn [buf xs]+ (reduce (fn [acc x]+ (writer acc x))+ buf xs))) -(defn write-list! [buf codec xs]- (write-array! (write-varint! buf (count xs)) codec xs))+(defn list-> [writer]+ (let [writer (array-> writer)]+ (fn [buf xs]+ (-> (varint-> buf (count xs))+ (writer xs))))) -(defn write-uuid! [buf uuid]+(defn uuid-> [buf uuid] (-> buf (ByteBuf/.writeLong (UUID/.getMostSignificantBits uuid)) (ByteBuf/.writeLong (UUID/.getLeastSignificantBits uuid)))) -; This is where you could check for optionality I think. If the fields aren't [:optional ...]-(defn write-table! [buf codec-fields m]- (reduce (fn [acc {:keys [field codec]}]+; TODO This is where you could check for optionality I think. If the fields aren't [:optional ...]+; TODO Inline+(defn ^:private write-table! [buf table m]+ (reduce (fn [acc {::t/keys [field codec]}] (adorn (codec acc (get m field))- "Error while encoding packet field" {:field field :value (get m field)}))- buf codec-fields))+ "Error while writing message table field" {:field field :writer codec :value (get m field)}))+ buf table)) -(defn write-boolean! [buf x]+(defn boolean-> [buf x] (if x (ByteBuf/.writeByte buf 1) (ByteBuf/.writeByte buf 0))) -(defn write-context-optional! [buf codec x]- (if x- (codec buf x)- buf))--(defn write-optional! [buf codec x]- (write-boolean! buf x)- (write-context-optional! buf codec x))--(defn write-enum! [buf codec m x]- (codec buf (m x)))-+(defn context-optional-> [writer]+ (fn [buf x]+ (if x+ (writer buf x)+ buf)))src/net/bowmap/network/registry.clj src/net/bowmap/packet/registry.clj view file
@@ -1,8 +1,8 @@-(ns net.bowmap.packet.registry+(ns net.bowmap.network.registry (:require- [net.bowmap.packet.chunk :as chunk]- [net.bowmap.packet :as pk]- [net.bowmap.packet.client :as cp]))+ [net.bowmap.network.chunk :as chunk]+ [net.bowmap.network.message :as msg]+ [net.bowmap.network.message.client :as client])) ;; Some way to keep track of order of these things and make that clear... ;; Probably a map of id -> order?@@ -90,7 +90,7 @@ ;; TODO this shouldn't be here :p (def registry-packets (for [[id m] (partition 2 registries)]- {::pk/id ::cp/registry-data+ {::msg/id ::client/registry-data :registry-id id :entries (for [[entry-id data] m] {:id entry-idsrc/net/bowmap/network/state.clj src/net/bowmap/client/state.clj view file
@@ -1,4 +1,4 @@-(ns net.bowmap.client.state+(ns net.bowmap.network.state (:require [clojure.alpha.spec :as s])) (s/def ::state #{::handshaking ::status ::login ::config ::play})src/net/bowmap/packet/types.clj view file
@@ -1,10 +0,0 @@-(ns net.bowmap.packet.types- (:require- [clojure.alpha.spec :as s]))--; Tables used by packet schemas-; See read-table! and write-table!-(s/def ::table- (s/* (s/cat :field keyword?- :doc (s/? string?)- :type #(or (keyword? %) (vector? %)))))src/net/bowmap/packet_handling.clj view file
@@ -1,17 +1,17 @@ (ns net.bowmap.packet-handling (:require- [net.bowmap.client.state :as state]- [net.bowmap.packet :as pk]- [net.bowmap.packet.client :as cp]- [net.bowmap.packet.registry :as registry]- [net.bowmap.packet.server :as sp]))+ [net.bowmap.network.state :as state]+ [net.bowmap.network.message :as msg]+ [net.bowmap.network.message.client :as client]+ [net.bowmap.network.registry :as registry]+ [net.bowmap.network.message.server :as server])) ; "packet handling" is inherently about the low-level protocol level, so either handle stuff at a low level or turn ; packets into high level game events to be sent somewhere else (defmulti handle-packet- (fn [pk client]- (::pk/id pk)))+ (fn [msg client]+ (::msg/id msg))) ; Should return just a client... ; Should be a much better interface as well@@ -19,20 +19,20 @@ (defn response "Returns a map of a client, and any other keys a packet handler may use. Client may be unchanged, or adorned with any information, such as a new state."- [client pk]- (let [response (handle-packet pk client)]+ [client msg]+ (let [response (handle-packet msg client)] (if (:client response) response (assoc response :client client)))) -(defmethod handle-packet :default [pk client]- (prn "Unhandled packet:" pk))+(defmethod handle-packet :default [msg client]+ (prn "Unhandled message:" msg)) -(defmethod handle-packet ::sp/handshaking [pk client]- {:client (assoc client ::state/state (:intent pk))})+(defmethod handle-packet ::server/handshaking [msg client]+ {:client (assoc client ::state/state (:intent msg))}) -(defmethod handle-packet ::sp/status-request [pk client]- {:response [{::pk/id ::cp/status-response+(defmethod handle-packet ::server/status-request [msg client]+ {:response [{::msg/id ::client/status-response ;; Should be un-bundled yeah. :response {:version {:name "1.21.11" :protocol 774}@@ -42,30 +42,30 @@ :description {:text "Bowmap!"} :enforcesSecureChat false}}]}) -(defmethod handle-packet ::sp/ping-request [pk client]- {:response [{::pk/id ::cp/pong-response- :timestamp (:timestamp pk)}]})+(defmethod handle-packet ::server/ping-request [msg client]+ {:response [{::msg/id ::client/pong-response+ :timestamp (:timestamp msg)}]}) -(defmethod handle-packet ::sp/login-start [pk client]- {:response [{::pk/id ::cp/login-success- :uuid (:uuid pk)- :username (:username pk)+(defmethod handle-packet ::server/login-start [msg client]+ {:response [{::msg/id ::client/login-success+ :uuid (:uuid msg)+ :username (:username msg) :properties []}]}) -(defmethod handle-packet ::sp/login-acknowledged [pk client]+(defmethod handle-packet ::server/login-acknowledged [msg client] {:client (assoc client ::state/state ::state/config)- :response [{::pk/id ::cp/known-packs+ :response [{::msg/id ::client/known-packs ;; TODO also probably good to unbundle this :known-packs [{:namespace "minecraft" :id "core" :version "1.12.11"}]}]}) -(defmethod handle-packet ::sp/known-packs [pk client]+(defmethod handle-packet ::server/known-packs [msg client] {:response (conj (vec registry/registry-packets)- {::pk/id ::cp/finish-config})})+ {::msg/id ::client/finish-config})}) -(defmethod handle-packet ::sp/finish-config [pk client]+(defmethod handle-packet ::server/finish-config [msg client] {:client (assoc client ::state/state ::state/play) :keepalive true- :response [{::pk/id ::cp/login+ :response [{::msg/id ::client/login :entity-id 0 ;; TODO magic zero :p :hardcore? false :dimension-names ["world"]@@ -86,5 +86,5 @@ :portal-cooldown 10src/net/bowmap/server.clj view file
@@ -3,7 +3,7 @@ [aleph.tcp :as tcp] [clojure.core.async :refer [chan io-thread]] [manifold.stream :as s]- [net.bowmap.packet.read :as read])+ [net.bowmap.network.packet.read :as read :refer [->varint]]) (:import [io.netty.bootstrap ServerBootstrap] [io.netty.buffer ByteBuf Unpooled]@@ -21,7 +21,7 @@ (ByteBuf/.writeBytes buf input) (loop [res res] (if (read/can-read-packet? buf)- (let [len (read/read-varint! buf)+ (let [len (->varint buf) res' (rf res (ByteBuf/.copy (ByteBuf/.readRetainedSlice buf len)))] (ByteBuf/.discardReadBytes buf) (recur res'))