minecraft_server.clj
Branches > main > 0b86605 > 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!
timeout]]
[dev.grahp.error :refer [raise]]
[net.bowmap.message-application :as a]
[net.bowmap.network.client :as client]
[net.bowmap.network.protocol.message :as msg]
[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))
{::client/keys! [client] ::a/keys [messages keep-alive?]} (a/handle-message message client)]
(doseq [message messages]
(put! outgoing-messages message))
(when keep-alive?
(io-thread
(loop []
(when (>!! outgoing-messages {::msg/id ::clientbound/keep-alive
:id (long (* (rand) Long/MAX_VALUE))})
(<!! (timeout 20000))
(recur)))))
client))
(defn handle-packets!! [client outgoing-messages]
(let [{::server/keys! [incoming-frames outgoing-frames]} client]
(alt!!
incoming-frames
([frame]
(if (some? frame)
(handle-incoming-packet client frame outgoing-messages)
(raise "client incoming frame channel closed!")))
outgoing-messages
([message]
(if (some? message)
(do (>!! outgoing-frames (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 (handle-packets!! client outgoing-messages))))
nil))
(defn closing-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 (closing-promise clients)]
(io-thread
(loop []
(if-some [client (<!! clients)]
(do (connect! client)
(recur))
(deliver shutdown :shutdown))))
shutdown))