server.clj
Branches > main > f490e57 > files / src / net / bowmap / packet / server.clj
(ns net.bowmap.packet.server
(:require
[clojure.alpha.spec :as s]
[dev.grahp.error :refer [raise]]
[net.bowmap.client.state :as state]
[net.bowmap.packet.read :as read]
[net.bowmap.packet :as pk])
(:import
[io.netty.buffer ByteBuf]))
(defn build-packets [registry]
(reduce (fn [acc [packet-id table]]
(assoc acc packet-id
(let [reader (read/reader [:table table])]
(fn [buf]
(assoc (reader buf)
::pk/id packet-id)))))
{} registry))
;; TODO this is unreadable lol
(defn build-packet-ids [registry]
(into {}
(mapcat (fn [[state packet-ids]]
(into {}
(map-indexed (fn [i pk] [{::state/state state ::pk/numeric-id i} pk]))
packet-ids)))
registry))
(def ^{:spec (s/map-of (s/schema [::state/state ::pk/numeric-id]) ::pk/id)}
packet-ids
(build-packet-ids
{::state/handshaking
[::handshaking]
::state/status
[::status-request
::ping-request]
::state/login
[::login-start
::encryption-response
::login-plugin-response
::login-acknowledged
::login-cookie-response]}))
(def ^{:spec (s/map-of ::pk/id (s/fspec :args (s/cat :buf #(instance? ByteBuf %))
:ret ::pk/packet))}
packets
(build-packets
{::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]}))
(defn decode-packet!
"Decodes and returns one packet from ByteBuf 'buf', which should contain at least one readable packet.
The initial length field of the packet should not be stripped from 'buf'.
Can throw if:
1. No such packet with the packet id and state exists
2. 'buf' is not properly framed, and does not contain a full packet
3. The contents of 'buf' are not a valid packet"
[buf state]
{:pre [(read/can-read-packet? buf)]}
;; The length is currently unsed, though there are packets that require it in order to decode.
;; None of those packets have been implemented yet, though.
(let [_unused-length (read/read-varint! buf)
numeric-id (read/read-varint! buf)
packet-id (packet-ids {::state/state state ::pk/numeric-id numeric-id})
dedec (packets packet-id)]
(if dedec
(dedec buf)
(raise "Failed to decode packet, no such packet with that id." {:id numeric-id :state state :packet-id packet-id}))))