server.clj

Branches > facts > bf7e6f7 > files / src / net / bowmap / network / server.clj

(ns net.bowmap.network.server
  (:require
   [clojure.core.async :refer [<!! alt!! io-thread put!]]
   [net.bowmap.network.client :as client :refer [send-packet!!]]
   [net.bowmap.network.connection :as connection]
   [net.bowmap.network.handle :as handle]
   [net.bowmap.network.minecraft-server :as mc]
   [net.bowmap.network.packets.serverbound :refer [decode-packet!]]
   [net.bowmap.network.state :as state]
   [net.bowmap.server.entity :as entity]
   [net.bowmap.server.logic :as logic]
   [net.bowmap.stormbow.fact :as fact]
   [net.bowmap.stormbow.responses :refer [handle-responses!]]))

(defn handle-connection [connection]
  (io-thread
    (let [client (client/client connection)
          clientbound-packets (req! client ::client/clientbound-packets)
          serverbound-frames (req! connection ::connection/serverbound-frames)]
      (try
        (loop [client client]
          (alt!!
            serverbound-frames ([frame]
                                (when (some? frame)
                                  (let [packet (decode-packet! frame (::state/connection-state client))
                                        {:keys [client packets facts] :or {:client client}} (handle/handle-packet client packet)]
                                    (doseq [pk packets]
                                      (put! clientbound-packets pk))
                                    (doseq [fact facts]
                                      (handle-responses! (logic/handle-fact fact)))
                                    (recur client))))
            clientbound-packets ([pk]
                                 (if (some? pk)
                                   ; Would be nice to enqueue frames so there is symmetry
                                   (do (send-packet!! client pk)
                                       (recur client))
                                   (throw (Exception. "Clientbound packets was closed idk why"))))))
        (finally
          ; TODO Send player disconnected fact, and update the player list from that
          #_(handle-responses! (logic/handle-fact {::fact/id ::fact/player-left
                                                   ::entity/uuid (::entity/uuid client)}))
          ((::close-fn connection)))))))

(defn start-server! [port]
  (let [connections (mc/start-server! port)]
    (loop []
      (when-let [connection (<!! connections)]
        (handle-connection connection))
      (recur))))