70c3677
Branches > facts > 70c3677 > files / src / net / bowmap
Add clientbound packets
Commit: 70c3677d9d1008afd37a079e8d6b087c4ccc0f81
Parent: 66269b8
2 changed files:
src/net/bowmap/network/packets/clientbound.clj view file
@@ -0,0 +1,281 @@+(ns net.bowmap.network.packets.clientbound+ (:require+ [net.bowmap.network.packet :as pk]+ [net.bowmap.network.packets.writers :as write+ :refer [bit-mask-> boolean-> byte-> chunk-data-> coerce context-optional->+ double-> enum-> float-> identifier-> int-> json-> length-prefixed+ light-data-> list-> long-> nbt-> optional-> or-> position->+ string-> ubyte-> uuid-> varint->]]+ [net.bowmap.network.registry :as reg]+ [net.bowmap.network.state :as state]+ [net.bowmap.server.gamemode :as gamemode])+ (:import+ [io.netty.buffer Unpooled]))++(def packet-order+ {::state/status+ [::status-response+ ::pong-response]+ ::state/login+ ; TODO do the message ids actually have to be different just because a different encoded format is used for the same logic message?+ [::login-disconnect ; Uses JSON instead of a text component :p+ ::encryption-request+ ::login-success+ ::set-compression+ ::login-plugin-request+ ::cookie-request]+ ::state/config+ [::cookie-request+ ::plugin-message+ ::disconnect+ ::finish-config+ ::keep-alive+ ::ping+ ::reset-chat+ ::registry-data+ ::remove-resource-pack+ ::add-resource-pack+ ::store-cookie+ ::transfer+ ::feature-flags+ ::update-tags+ ::known-packs+ ::custom-report-details+ ::server-links+ ::clear-dialog+ ::show-dialog+ ::code-of-conduct]+ ::state/play+ [::bundle-delimiter+ ::spawn-entity+ ::entity-animation+ ::award-statistics+ ::acknowledge-block-change+ ::set-block-destroy-stage+ ::block-entity-data+ ::block-action+ ::block-update+ ::boss-bar+ ::change-difficulty+ ::chunk-batch-finished+ ::chunk-batch-start+ ::chunk-biomes+ ::clear-titles+ ::command-suggestions-response+ ::commands+ ::close-container+ ::set-container-content+ ::set-container-property+ ::set-container-slot+ ::cookie-request+ ::set-cooldown+ ::chat-suggestions+ ::plugin-message+ ::damage-event+ ::debug-block-value+ ::debug-chunk-value+ ::debug-entity-value+ ::debug-event+ ::debug-sample+ ::delete-message+ ::disconnect+ ::disguised-chat-message+ ::entity-event+ ::teleport-entity+ ::explosion+ ::unload-chunk+ ::game-event+ ::game-test-highlight-position+ ::open-horse-screen+ ::hurt-animation+ ::initialize-world-border+ ::keep-alive+ ::chunk-data-and-update-light+ ::world-event+ ::particle+ ::update-light+ ::login+ ::map-data+ ::merchant-offerssrc/net/bowmap/network/packets/writers.clj view file
@@ -0,0 +1,281 @@+(ns net.bowmap.network.packets.writers+ "Functions to write Minecraft protocol types.+ When given bad data, write functions will throw.+ See https://minecraft.wiki/w/Java_Edition_protocol/Packets#Data_types"+ (:require+ [clojure.spec.alpha :as s]+ [clojure.data.json :as json]+ [clojure.set :as set]+ [net.bowmap.network.packets.types :as t])+ (:import+ [io.netty.buffer ByteBuf CompositeByteBuf Unpooled]+ [java.nio.charset Charset]+ [java.util BitSet UUID]))++(defn varint-> [buf n]+ (loop [buf buf+ n n]+ (let [b (bit-and n 0x7F)+ nxt (unsigned-bit-shift-right n 7)]+ (if (zero? nxt)+ (ByteBuf/.writeByte buf b)+ (recur (ByteBuf/.writeByte buf (bit-or b 0x80))+ nxt)))))++(defn length-prefixed+ "Returns a new ByteBuf prefixed by an encoded varint of the length of 'buf'."+ [buf]+ (-> (Unpooled/compositeBuffer 2)+ (CompositeByteBuf/.addComponent true (varint-> (Unpooled/buffer t/max-varint-size) (ByteBuf/.writerIndex buf)))+ (CompositeByteBuf/.addComponent true buf)))++(defn string-> [buf s]+ (doto buf+ (varint-> (count s))+ (ByteBuf/.writeCharSequence s (Charset/forName "UTF-8"))))++(defn json-> [buf s]+ (string-> buf (json/write-str s)))++(defn uuid-> [buf uuid]+ (-> buf+ (ByteBuf/.writeLong (UUID/.getMostSignificantBits uuid))+ (ByteBuf/.writeLong (UUID/.getLeastSignificantBits uuid))))++; TODO This is where you could check for optionality I think. If the fields aren't [:optional ...]+; TODO Inline+(defn ^:private write-table! [buf table m]+ (reduce (fn [acc {::t/keys! [field codec]}]+ (codec acc (get m field)))+ buf table))++(defn boolean-> [buf x]+ (if x+ (ByteBuf/.writeByte buf 1)+ (ByteBuf/.writeByte buf 0)))++(defn context-optional-> [writer]+ (fn [buf x]+ (if x+ (writer buf x)+ buf)))++; Want to conform the given map to the table, and error if any non-optional keys are missing?+(defn table-> [t]+ (assert (s/valid? ::t/table t))+ (let [table (s/conform ::t/table t)]+ (fn [buf m]+ (write-table! buf table m))))++(defn coerce+ "If writer is an actual writer, returns it. If writer is a vector, turnes it into a table writer."+ [writer]+ (if (vector? writer)+ (table-> writer)+ writer))++; Only coerces these for now idk+(defn array-> [writer]+ (let [writer (coerce writer)]+ (fn [buf xs]+ (reduce (fn [acc x]+ (writer acc x))+ buf xs))))++(defn list-> [writer]+ (let [writer (array-> writer)]+ (fn [buf xs]+ (-> (varint-> buf (count xs))+ (writer xs)))))++;;; NBT++(defn write-modified-utf8! [buf s]+ (reduce (fn [acc code]+ (cond (zero? code) (-> buf+ (ByteBuf/.writeByte 0xC0)+ (ByteBuf/.writeByte 0x80))+ (<= 1 code 0x7F) (ByteBuf/.writeByte acc code)+ (<= 0x80 code 0x7FF) (-> acc