core.clj
Branches > namespace-reorganization > 886f56a > files / src / net / bowmap / core.clj
(ns net.bowmap.core
(:require
[aleph.tcp :as tcp]
[manifold.stream :as s]
[net.bowmap.client.state :as state]
[net.bowmap.packet-handling :as handle]
[net.bowmap.packet.client :refer [encode-packet]]
[net.bowmap.packet.read :as read]
[net.bowmap.packet.server :as sp])
(:import
[io.netty.bootstrap ServerBootstrap]
[io.netty.buffer ByteBuf Unpooled]
[io.netty.channel ChannelOption]))
(defn handle-packets
"Hands all (zero or more) unhandled Minecraft protocol packets the client has sent.
Returns a new client.
Packets are parsed and handled synchronously as packet decoding can update
client state, so is impure."
[client]
(let [{::keys [buf stream]} client]
(loop [client client]
(if (read/can-read-packet? buf)
(let [pk (sp/decode-packet! buf (::state/state client))
{:keys [::state/state response]} (handle/handle-packet pk client)
client (cond-> client state (assoc ::state/state state))]
(when response
(s/put! stream (encode-packet response (::state/state client))))
(ByteBuf/.discardReadBytes buf)
(recur client))
client))))
(defn handle-bytes
"Takes a client and a byte array of one TCP packet, and handles all
unhandled Minecraft protocol packets in the client's buffer.
Returns the new client state, per 'handle-packets'."
[client bs]
(try
(ByteBuf/.writeBytes (::buf client) bs)
(handle-packets client)
(catch Exception e
(prn "Exception in bytes:" e)
(.close (::stream client)))))
(defn client-handler [stream _]
(let [client {::state/state ::state/handshaking
::buf (Unpooled/buffer)
::stream stream}]
(s/reduce #'handle-bytes client stream)))
(defn start-server! []
(tcp/start-server #'client-handler
{:port 25565
:bootstrap-transform #(ServerBootstrap/.childOption % ChannelOption/TCP_NODELAY true)}))
(defn -main [& _args]
(start-server!)
(println "Server Started"))
(comment
(def server (start-server!))
(.close server))