serverbound.clj
Branches > main > c5b37b5 > files / src / net / bowmap / network / packets / serverbound.clj
(ns net.bowmap.network.packets.serverbound
(:require
[net.bowmap.network.packet :as pk]
[net.bowmap.network.packets.readers
:refer [->bit-mask ->byte ->double ->enum ->float ->identifier ->int
->list ->long ->optional ->position ->short ->string ->ubyte
->uuid ->varint coerce]]
[net.bowmap.network.state :as state]))
(def packet-order
"Map of connection states to vectors of serverbound packet ids in the order the appear in the protocol."
{::state/handshaking
[::handshaking]
::state/status
[::status-request
::ping-request]
::state/login
[::login-start
::encryption-response
::login-plugin-response
::login-acknowledged
::cookie-response]
::state/config
[::client-information
::cookie-response
::plugin-message
::finish-config
::keep-alive
::pong
::resource-pack-response
::known-packs
::custom-click-action
::accept-code-of-conduct]
::state/play
[::confirm-teleportation
::attack
::query-block-entity-tag
::bundle-item-selected
::change-difficulty
::change-game-mode
::acknowledge-message
::chat-command
::signed-chat-command
::chat-message
::player-session
::chunk-batch-received
::client-status
::client-tick-end
::client-information
::command-suggestions-request
::acknowledge-configuration
::click-container-button
::click-container
::close-container
::change-container-slot-state
::cookie-response
::plugin-message
::debug-subscription-request
::edit-book
::query-entity-tag
::interact
::jigsaw-generate
::keep-alive
::lock-difficulty
::set-player-position
::set-player-position-and-rotation
::set-player-rotation
::set-player-movement-flags
::move-vehicle
::paddle-boat
::pick-item-from-block
::pick-item-from-entity
::ping-request
::place-recipe
::player-abilities
::player-action
::player-command
::player-input
::player-loaded
::pong
::change-recipe-book-settings
::set-seen-recipe
::rename-item
::resource-pack-response
::seen-advancements
::select-trade
::set-beacon-effect
::select-hotbar-slot
::program-command-block
::program-command-block-minecart
::set-creative-mode-slot
::set-game-rules
::program-jigsaw-block
::program-structure-block
::set-test-block
::update-sign
::spectator-action
::swing-arm
::teleport-to-entity
::test-instance-block-action
::use-item-on
::use-item
::custom-click-action]})
(def unused-fields [])
(def packets
"Map of packet ids to schemas"
; Handshaking
{::handshaking [:protocol ->varint
:address ->string
:port ->short
:intent (->enum ->varint {1 ::state/status 2 ::state/login 3 ::state/transfer})]
; Status
::status-request []
::ping-request [:timestamp ->long]
; Login
::login-start [:username ->string
:uuid ->uuid]
::encryption-response [:shared-secret (->list ->byte)]
::login-plugin-response [:message ->varint
:data (fn [buf] (throw (Exception. "Fuck you")))]
::login-acknowledged []
::cookie-response [:key ->identifier
:payload (->optional (->list ->byte))]
; Config
::client-information unused-fields
::plugin-message unused-fields
::finish-config []
::pong [:id ->int]
::resource-pack-response [:uuid ->uuid
:result (->enum ->varint {0 :sucessfully-downloaded
1 :declined
2 :failed-to-download
3 :accepted
4 :downloaded
5 :invalid-url
6 :failed-to-reload
7 :discarded})]
; The wiki is too damn confusing
::known-packs unused-fields
#_::custom-click-action
#_::accept-code-of-conduct
;; This packet has more fields I just don't care about them :p
;; This packet also has a bunch of fields that I probably do care about!
; Play
::confirm-teleportation [:teleport-id ->varint]
#_::query-block-entity-tag
#_::bundle-item-selected
#_::change-difficulty
#_::change-game-mode
#_::acknowledge-message
#_::chat-command
#_::signed-chat-command
#_::chat-message
#_::player-session
#_::chunk-batch-received
#_::client-status
::client-tick-end []
#_::command-suggestions-request
#_::acknowledge-configuration
#_::click-container-button
#_::click-container
::close-container [:window-id ->varint]
#_::change-container-slot-state
#_::debug-subscription-request
#_::edit-book
#_::query-entity-tag
#_::interact
#_::jigsaw-generate
::keep-alive [:id ->long]
#_::lock-difficulty
::set-player-rotation [:yaw ->float
:pitch ->float
:flags ->byte]
::set-player-position-and-rotation [:x ->double
:feet-y ->double
:z ->double
:yaw ->float
:pitch ->float
:flags ->byte]
::set-player-position [:x ->double
:feet-y ->double
:z ->double
:flags ->byte]
::set-player-movement-flags [:flags (->bit-mask ->byte [:on-ground :pushing-against-wall])]
#_::move-vehicle
#_::paddle-boat
#_::pick-item-from-block
#_::pick-item-from-entity
; TODO is this different?
#_[::ping-request]
#_::place-recipe
::player-abilities [:flags (->bit-mask ->byte {1 :flying?})] ; is this right?
::player-action [:status (->enum ->varint [:started-digging :canceled-digging :finished-digging
:drop-item-stack :drop-item :update-item-state :swap-item-in-hand])
; TODO aren't positions and locations different things?
:location ->position
; TODO block face might be something logical
:face (->enum ->byte [:bottom :top :north :south :west :east])
:sequence ->varint]
::player-command [:entity-id ->varint
:action-id (->enum ->varint [:leave-bed :start-sprinting :stop-sprinting :start-jumping-with-horse
:stop-jumping-with-horse :open-vehicle-inventory :start-flying-with-elytra])
:jump-boost ->varint]
::player-input [:flags (->bit-mask ->ubyte [:forward :backward :left :right :jump :sneak :sprint])]
::player-loaded []
#_::change-recipe-book-settings
#_::set-seen-recipe
#_::rename-item
#_::seen-advancements
#_::select-trade
#_::set-beacon-effect
::select-hotbar-slot [:slot "Slots 0-8" ->varint]
#_::program-command-block
#_::program-command-block-minecart
#_::set-creative-mode-slot
#_::program-jigsaw-block
#_::program-structure-block
#_::set-test-block
#_::update-sign
::swing-arm [:hand (->enum ->varint [:main-hand :off-hand])]
#_::teleport-to-entity
#_::test-instance-block-action
#_::use-item-on
#_::use-item})
; TODO is this called "registry"?
(defn build-packet-decode-functions [registry]
(reduce (fn [acc [packet-id table]]
(assoc acc packet-id
(let [reader (coerce table)]
(fn [buf]
(assoc (reader buf)
::pk/id packet-id)))))
{} registry))
(defn build-packet-id-index
"Takes a map of connection states to vectors of packet ids and returns a map of [connection-state numeric-id] to packet ids"
[registry]
(into {}
(for [[state packet-ids] registry
[i id] (map-indexed vector packet-ids)]
[{::state/connection-state state
::pk/numeric-id i}
id])))
(def packet-ids (build-packet-id-index packet-order))
(def packet-decoders (build-packet-decode-functions packets))
(defn decode-packet!
"Decodes a packet from a frame."
[frame connection-state]
(let [numeric-id (->varint frame)
packet-id (req! packet-ids {::state/connection-state connection-state ::pk/numeric-id numeric-id})
decode-fn (req! packet-decoders packet-id)]
(decode-fn frame)))