connections.clj
Branches > main > 8c453b5 > files / src / net / bowmap / server / runtime / connections.clj
(ns net.bowmap.server.runtime.connections
(:require
[clojure.core.async :refer [io-thread]]
[net.bowmap.server.game.handle :as handle]
[net.bowmap.server.game.server :as state]
[net.bowmap.server.network.connection :as connection]
[net.bowmap.server.network.server :as server]
[net.bowmap.server.protocol.packet :as packet]
[net.bowmap.server.protocol.packet-serialization :as serialize]
[net.bowmap.server.protocol.phase :as phase]
[net.bowmap.server.protocol.serverbound-packets :as serverbound]))
(defn apply-packet
"Returns the value a client should take on when handling 'packet'."
[client packet]
(let [{::packet/keys! [id]} packet]
(case id
::serverbound/handshaking (assoc client ::phase/phase (req! packet ::phase/phase))
::serverbound/login-acknowledged (assoc client ::phase/phase ::phase/config)
::serverbound/finish-config (assoc client ::phase/phase ::phase/play)
client)))
(defn handle-connection! [connection]
(let [client-atom (atom {::phase/phase ::phase/handshaking})
connection-uuid (random-uuid)
send-packet! (fn [packet]
(let [frame (serialize/encode-packet @client-atom packet)]
(connection/send-frame! connection frame)))]
(loop []
(when-some [frame (connection/receive-frame!! connection)]
(let [client @client-atom
packet (serialize/decode-frame client frame)
client' (apply-packet client packet)]
(assert (compare-and-set! client-atom client client'))
(loop [state @state/state]
(let [[state' & packets] (handle/handle-packet state connection-uuid packet)]
(if (or (nil? state') (compare-and-set! state/state state state'))
(run! send-packet! packets)
(recur @state/state)))))
(recur)))))
(defn handle-connections!
[server]
(loop []
(let [connection (server/accept-connection!! server)]
(io-thread
(handle-connection! connection))
(recur))))