handle.clj
Branches > main > 4fbba8a > files / src / net / bowmap / server / game / handle.clj
(ns net.bowmap.server.game.handle
(:require
[com.wotbrew.relic :as rel]
[net.bowmap.server.game.player :as player]
[net.bowmap.server.game.server :as server]
[net.bowmap.server.network.connection :as connection]
[net.bowmap.server.packet.clientbound :as clientbound]
[net.bowmap.server.packet.component :as component]
[net.bowmap.server.packet.entity :as entity]
[net.bowmap.server.packet.gamemode :as gamemode]
[net.bowmap.server.packet.registry :as registry]
[net.bowmap.server.packet.schema :as p]
[net.bowmap.server.packet.schema.minecraft :as mc]
[net.bowmap.server.packet.serverbound :as serverbound]))
(defmulti handle-packet
"Handles a packet from a player given their connection uuid. Takes the game
state, and returns a vector of nil or a state value, followed by 0 or more
response packets."
(fn [state connection-uuid packet]
(::p/id packet)))
(defmethod handle-packet :default [_ _ _])
(defmethod handle-packet ::serverbound/status-request [state _ _]
[nil
{::p/id ::clientbound/status-response
::p/version-name "26.3"
::p/protocol 777
::p/motd {::component/text "Bowmap!"
::component/color "#9f9f9f"}
::p/online-player-count (count (state ::server/players))
::p/max-player-count server/max-player-count}])
(defmethod handle-packet ::serverbound/ping-request [_ _ {::p/keys! [timestamp]}]
[nil
{::p/id ::clientbound/pong-response
::p/timestamp timestamp}])
(defmethod handle-packet ::serverbound/login-start [state connection-uuid {::p/keys! [uuid username]}]
[(rel/transact state
[:insert ::server/players
{::player/uuid uuid
::player/username username
::connection/connection-uuid connection-uuid}])
{::p/id ::clientbound/login-success
::p/game-profile {::p/uuid uuid
::p/username username
::p/game-profile-properties []}
::p/session-uuid connection-uuid}])
(defmethod handle-packet ::serverbound/login-acknowledged [_ _ _]
[nil
{::p/id ::clientbound/known-packs
::p/known-packs [registry/core-data-pack]}])
(defmethod handle-packet ::serverbound/known-packs [state _ {::p/keys! [known-packs]}]
(if (= [registry/core-data-pack] known-packs)
(cons state
(conj registry/registry-packets
{::p/id ::clientbound/finish-config}))
(throw (ex-info "Client does not support the core datapack"
{:known-packs known-packs}))))
(defmethod handle-packet ::serverbound/finish-config [state connection-uuid _]
(let [entity-id (entity/next-entity-id)]
[(rel/transact state
[:update ::server/players
{::server/playing? true
::entity/id entity-id}
[= ::connection/connection-uuid connection-uuid]])
{::p/id ::clientbound/login
::entity/id entity-id
:dimensions [registry/world-dimension]
::p/max-player-count server/max-player-count
:render-distance 32
:simulation-distance 32
:current-dimension-registry-id (registry/registry-id ::mc/dimension_type registry/world-dimension)
:current-dimension registry/world-dimension
:first-8-bytes-of-the-sha-256-hash-of-the-world's-seed 0
::gamemode/gamemode ::gamemode/adventure
:superflat-world? true
:portal-cooldown-ticks 0
:sea-level 60
:enforce-secure-chat? true}
{::p/id ::clientbound/game-event
::p/game-event-id ::p/wait-for-chunk-event}]))