core.clj

Branches > client-handling-rewrite > 21d95e3 > files / src / net / bowmap / core.clj

(ns net.bowmap.core
  (:require
   [aleph.tcp :as tcp]
   [manifold.deferred :as d]
   [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 packet-framer-xf
  "Frames bytes from incoming byte arrays and calls 'xf' on ByteBufs of
   complete Minecraft protocol packet bytes."
  []
  (let [buf (Unpooled/buffer)]
    (fn [rf]
      (fn
        ([] (rf))
        ([res] (rf res))
        ([res input]
         (ByteBuf/.writeBytes buf input)
         (loop [res res]
           (if (read/can-read-packet? buf)
             (let [len (read/read-varint! buf)
                   ;; This copy is probably inefficient but fine for now.
                   res' (rf res (ByteBuf/.copy (ByteBuf/.readRetainedSlice buf len)))]
               (ByteBuf/.discardReadBytes buf)
               (recur res'))
             res)))))))

(defn handle-packet
  "Handles one framed Minecraft protocol packet bytes."
  [client packet-buf]
  (let [{:keys [client response]} (handle/response client (sp/decode-packet packet-buf (::state/state client)))]
    (doseq [pk response]
      (s/put! (::stream client) (encode-packet pk (::state/state client))))
    client))

(defn client-handler [stream _]
  (let [client {::state/state ::state/handshaking
                ::stream stream}]
    (d/catch (s/reduce #'handle-packet client (s/transform (packet-framer-xf) stream))
      (fn [e]
        (println "Exception in client packets:" e)))))

(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
  (require 'dev.grahp.bytebuf)
  (def server (start-server!))
  (.close server))