packet_handling.clj
Branches > client-handling-rewrite > ba43832 > files / src / net / bowmap / packet_handling.clj
(ns net.bowmap.packet-handling
(:require
[clojure.core.async :refer [<!! io-thread put! timeout]]
[net.bowmap.network.client :as c]
[net.bowmap.network.message :as msg]
[net.bowmap.network.message.client :as client]
[net.bowmap.network.message.server :as server]
[net.bowmap.network.registry :as registry]
[net.bowmap.network.state :as state]))
; "packet handling" is inherently about the low-level protocol level, so either handle stuff at a low level or turn
; packets into high level game events to be sent somewhere else
; It's per-client, but can send stuff into the player
; And it's stateful!
; Performs a side effect and returns the new client?
; TODO nil?
(defmulti handle-packet
(fn [msg client]
(::msg/id msg)))
; Returns the client and performs side effects...
; Should be run single-threaded?
; Hmm...
; TODO nil?
(defn handle-packet!! [client msg]
(handle-packet msg client))
(defn- send-message! [client msg]
;; TODO this is bad ofc.
;; Clients are kinda intractable?
;; TODO uhh can this be async?
;; I feel like this should block, no?
;; It can't right now because send/rec are in a single alt...
(put! (::c/messages-out client) msg))
(defmethod handle-packet :default [msg client]
(prn "Unhandled message:" msg)
client)
(defmethod handle-packet ::server/handshaking [msg client]
(assoc client ::state/connection-state (:intent msg)))
(defmethod handle-packet ::server/status-request [_ client]
(send-message! client
{::msg/id ::client/status-response
;; Should be un-bundled yeah.
:response {:version {:name "1.21.11"
:protocol 774}
:players {:online 0
:max 1000}
; Is this a text component? Could make that interface
:description {:text "Bowmap!"}
:enforcesSecureChat false}})
client)
(defmethod handle-packet ::server/ping-request [msg client]
(send-message! client
{::msg/id ::client/pong-response
:timestamp (:timestamp msg)})
client)
(defmethod handle-packet ::server/login-start [msg client]
(send-message! client
{::msg/id ::client/login-success
:uuid (:uuid msg)
:username (:username msg)
:properties []})
client)
(defmethod handle-packet ::server/login-acknowledged [_ client]
(send-message! client
{::msg/id ::client/known-packs
;; TODO also probably good to unbundle this
:known-packs [{:namespace "minecraft"
:id "core"
:version "1.12.11"}]})
(assoc client ::state/connection-state ::state/config))
(defmethod handle-packet ::server/known-packs [_ client]
(doseq [msg registry/registry-messages]
(send-message! client msg))
(send-message! client
{::msg/id ::client/finish-config})
client)
;; TODO Keepalive!
(defmethod handle-packet ::server/finish-config [_ client]
(send-message! client
{::msg/id ::client/login
:entity-id 0 ;; TODO magic zero :p
:hardcore? false
:dimension-names ["world"]
:max-players 1000
:view-distance 32
:simulation-distance 32
:reduced-debug-info? false
:enable-respawn-screen? false
:do-limited-crafting? false
:dimension-type-id 0
:dimension-name "world"
:hashed-seed 203894
:gamemode :creative
:previous-gamemode :unknown
:debug-world? false
:superflat-world? true
:has-death-location? false
:portal-cooldown 10
:sea-level 60
:enforce-secure-chat? true})
(send-message! client
{::msg/id ::client/game-event
:event :wait-for-chunks})
; TODO when the client disconnects?
(io-thread
(loop []
(<!! (timeout 5000))
(send-message! client {::msg/id ::client/keep-alive
:id (long (* (rand) Long/MAX_VALUE))})
(recur)))
(assoc client ::state/connection-state ::state/play))