codec.clj

Bowmap · bowmap.git · Tickets

Branches > main > f236013 > files / src / net / bowmap / server / protocol / codec.clj

(ns net.bowmap.server.protocol.codec
  (:require
   [net.bowmap.server.protocol.clientbound-packets :refer [clientbound-packets]]
   [net.bowmap.server.protocol.frame :refer [frame length-prefixed]]
   [net.bowmap.server.protocol.packet :as packet]
   [net.bowmap.server.protocol.phase :as phase]
   [net.bowmap.server.protocol.readers :as readers]
   [net.bowmap.server.protocol.serverbound-packets :refer [serverbound-packets]]
   [net.bowmap.server.protocol.writers :as writers]))

(defn- find-indexed
  "Takes a seq of pairs and returns both the index of the first pair
   'keyed' by the given id and its 'value' in linear time.
   E.g. (find-indexed [:a [] :b {} :c #{}] :b) -> [1 {}]"
  [id pairs]
  (some (fn [[i [k v]]]
          (when (= id k)
            [i v]))
        (map-indexed vector (partition 2 pairs))))

(defn encode-packet
  "Encodes a packet into a frame.
   Throws when the packet cannot be encoded."
  [{::phase/keys! [phase]} {::packet/keys! [id] :as packet}]
  (let [schemas (clientbound-packets phase)
        [numeric-id schema] (find-indexed id schemas)
        payload-writer (writers/to-writer schema)]
    (length-prefixed
      (-> (frame)
          (writers/varint-> numeric-id)
          (payload-writer packet)))))

(defn decode-frame
  "Decodes a packet from a frame.
   Can throw if the frame does not contain a valid packet."
  [{:keys! [::phase/phase]} frame]
  (let [numeric-id (readers/->varint frame)
        schemas (serverbound-packets phase)
        [id schema] (nth (partition 2 schemas) numeric-id)
        payload-reader (readers/to-reader schema)]
    (assoc (payload-reader frame)
           ::packet/id id)))