minecraft_server.clj

Branches > main > 615c075 > files / src / net / bowmap / network / minecraft_server.clj

(ns net.bowmap.network.minecraft-server 
  (:require
   [clojure.core.async :refer [<!! >!! alt!! chan close! io-thread put!]]
   [dev.grahp.error :refer [raise]]
   [net.bowmap.message-application :as a]
   [net.bowmap.network.client :as client]
   [net.bowmap.network.protocol.message.clientbound :as clientbound]
   [net.bowmap.network.protocol.message.serverbound :as serverbound]
   [net.bowmap.network.protocol.state :as state]
   [net.bowmap.network.server :as server]))

;;;

(defn handle-incoming-packet [client packet outgoing-messages]
  (let [message (serverbound/packet->message packet (::state/connection-state client))
        {:keys [::client/client ::a/messages]} (a/apply-message message client)]
    (doseq [message messages]
      (put! outgoing-messages message))
    client))

(defn handle-packets!! [client outgoing-messages]
  (let [{::server/keys! [packets-in packets-out]} client]
    (alt!!
      packets-in ([packet]
                  (if (some? packet)
                    (handle-incoming-packet client packet outgoing-messages)
                    (raise "client incoming packet channel closed!")))
      outgoing-messages ([message]
                         (if (some? message)
                           (do (>!! packets-out (clientbound/message->packet message (::state/connection-state client)))
                               client)
                           (raise "client outgoing message channel closed!"))))))

(defn connect! [client]
  (let [outgoing-messages (chan 1024)]
    (io-thread
      (loop [client client]
        (recur (or (handle-packets!! client outgoing-messages) client))))
    nil))

(defn closable-promise
  "Returns a promise that closes 'ch' when it is resolved."
  [ch]
  (let [p (promise)]
    (io-thread
      @p
      (close! ch))
    p))

(defn start-minecraft-server!
  "Starts the Minecraft server.
   Returns a promise that will deliver when the server closes.
   Delivering the promise will also close the server."
  []
  (let [clients (server/start-tcp-server! {:port 25565})
        shutdown (closable-promise clients)]
    (io-thread
      (loop []
        (if-some [client (<!! clients)]
          (do (connect! client)
              (recur))
          (deliver shutdown :shutdown))))
    shutdown))