b6d3d26
Branches > main > b6d3d26 > files
Send Login (Play) to client
Commit: b6d3d26f475aa28c88e87b263f548644ce45c2f9
Parent: 7bcccfb
9 changed files:
src/net/bowmap/server/game/handle.clj view file
@@ -6,9 +6,12 @@ [net.bowmap.server.network.connection :as connection] [net.bowmap.server.protocol.clientbound-packets :as clientbound] [net.bowmap.server.protocol.component :as component]+ [net.bowmap.server.protocol.entity :as entity]+ [net.bowmap.server.protocol.gamemode :as gamemode] [net.bowmap.server.protocol.packet :as packet] [net.bowmap.server.protocol.registry :as registry] [net.bowmap.server.protocol.schema :as p]+ [net.bowmap.server.protocol.schema.minecraft :as mc] [net.bowmap.server.protocol.serverbound-packets :as serverbound])) (defmulti handle-packet@@ -28,7 +31,7 @@ ::p/motd {::component/text "Bowmap!" ::component/color "#9f9f9f"} ::p/online-player-count (count (state ::server/players))- ::p/max-player-count 1000}])+ ::p/max-player-count server/max-player-count}]) (defmethod handle-packet ::serverbound/ping-request [_ _ {::p/keys! [timestamp]}] [nil@@ -59,3 +62,25 @@ {::packet/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]])+ {::packet/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}]))src/net/bowmap/server/game/server.clj view file
@@ -4,6 +4,8 @@ [com.wotbrew.relic :as relic] [net.bowmap.server.game.player :as player])) +(def max-player-count 1000)+ (s/def ::players (s/coll-of ::player/player :kind set?)) (s/def ::server (s/keys :opt [::players])) src/net/bowmap/server/protocol/block.clj view file
@@ -0,0 +1,8 @@+(ns net.bowmap.server.protocol.block+ (:require+ [clojure.spec.alpha :as s]))++(s/def ::x int?)+(s/def ::y int?)+(s/def ::z int?)+(s/def ::location (s/keys :opt [::x ::y ::z]))src/net/bowmap/server/protocol/clientbound_packets.clj view file
@@ -1,5 +1,7 @@ (ns net.bowmap.server.protocol.clientbound-packets (:require+ [net.bowmap.server.protocol.entity :as entity]+ [net.bowmap.server.protocol.gamemode :as gamemode] [net.bowmap.server.protocol.phase :as phase] [net.bowmap.server.protocol.schema :as p] [net.bowmap.server.protocol.writers :refer :all]))@@ -98,7 +100,29 @@ ::world-event nil ::particle nil ::update-light nil- ::login nil+ ::login (map> ::entity/id int>+ :hardcore? boolean>+ :dimensions (list> identifier>)+ ::p/max-player-count varint>+ :render-distance varint>+ :simulation-distance varint>+ :reduced-debug-info? boolean>+ :use-respawn-screen? boolean>+ :do-limited-crafting? boolean>+ :current-dimension-registry-id varint>+ :current-dimension identifier>+ :first-8-bytes-of-the-sha-256-hash-of-the-world's-seed long>+ ::gamemode/gamemode (enum> varint> {0 ::gamemode/survival 1 ::gamemode/creative 2 ::gamemode/adventure 3 ::gamemode/spectator})+ :previous-gamemode (enum> varint> {0 nil 1 ::gamemode/survival 2 ::gamemode/creative 3 ::gamemode/adventure 4 ::gamemode/spectator})+ :debug-world? boolean>+ :superflat-world? boolean>+ :has-death-location? boolean>+ :death-dimension-name (context-optional> identifier>)+ :death-location (context-optional> block-location>)+ :portal-cooldown-ticks varint>+ :sea-level varint>+ :online? boolean>+ :enforce-secure-chat? boolean>) ::low-disk-space-warning nil ::map-data nil ::merchant-offers nilsrc/net/bowmap/server/protocol/entity.clj view file
@@ -0,0 +1,9 @@+(ns net.bowmap.server.protocol.entity)++(defonce highest-entity-id (atom 0))++(defn next-entity-id+ "Returns the next highest available entity ID.+ Entity IDs are unique used in the protocol to refer to entities."+ []+ (swap! highest-entity-id inc))src/net/bowmap/server/protocol/gamemode.clj view file
@@ -0,0 +1,5 @@+(ns net.bowmap.server.protocol.gamemode+ (:require+ [clojure.spec.alpha :as s]))++(s/def ::gamemode #{::survival ::creative ::adventure ::spectator})src/net/bowmap/server/protocol/registry.clj view file
@@ -304,6 +304,9 @@ (defonce registry-ids->values (update-vals registry #(zipmap (range) (keys %)))) (defonce registry-values->ids (update-vals registry-ids->values set/map-invert)) +(defn registry-id [registry value]+ (req! (registry-values->ids registry) value))+ (let [registry-packets (for [[registry-id entries] registry] {::packet/id ::clientbound/registry-datasrc/net/bowmap/server/protocol/serverbound_packets.clj view file
@@ -27,7 +27,7 @@ [::client-information nil ::cookie-response nil ::plugin-message nil- ::finish-config nil+ ::finish-config (map<) ::keep-alive nil ::pong nil ::resource-pack-response nilsrc/net/bowmap/server/protocol/writers.clj view file
@@ -4,11 +4,13 @@ See https://minecraft.wiki/w/Java_Edition_protocol/Packets#Data_types" (:require [clojure.data.json :as json]+ [clojure.set :as set] [clojure.spec.alpha :as s]+ [net.bowmap.server.protocol.block :as block] [net.bowmap.server.protocol.buffer :as buffer] [net.bowmap.server.protocol.identifier :as identifier]- [net.bowmap.server.protocol.schema :as p]- [net.bowmap.server.protocol.nbt :as nbt])+ [net.bowmap.server.protocol.nbt :as nbt]+ [net.bowmap.server.protocol.schema :as p]) (:import [java.nio.charset StandardCharsets] [java.util UUID]))@@ -188,6 +190,31 @@ ::p/game-profile-property-value (string> 32767) ::p/game-profile-property-signature (optional> (string> 1024))))) +(defn enum>+ "Returns a writer that writes one of a set of values via 'writer'.+ Takes a map of encoded values to decoded values (values that will appear in+ the packet map), same as the enum reader. For example, the map {1 :foo}+ will write 1 (via 'writer') when given :foo, so the map is 'backwards'.+ When the value is not in the enum map, calls 'writer' with nil."+ [writer m]+ (let [m (set/map-invert m)]+ (fn [buf x]+ (writer buf (m x)))))++(defn block-location>+ "Writes a block location as a 64-bit integer made of 3 signed integers: 26+ bits for the x, 26 bits for the y, and 16 bits for the z. Throws if any+ of the coordinates do not fit within their respective integer sizes."+ [buf {::block/keys! [x y z]}]+ {:pre [(<= (Math/pow -2 25) x (- (Math/pow 2 25) 1))+ (<= (Math/pow -2 25) z (- (Math/pow 2 25) 1))+ (<= (Math/pow -2 11) y (- (Math/pow 2 11) 1))]}+ (long> buf+ (bit-or+ (bit-shift-left (bit-and x 0x3FFFFFF) 38)+ (bit-shift-left (bit-and z 0x3FFFFFF) 12)+ (bit-and y 0xFFF))))+ (defn- utf-16-code-units [s] (map int (String/.toCharArray s)))