ci: remove macos-15-intel
This commit is contained in:
parent
afbe839dea
commit
3103e97e18
2
.github/workflows/docker.yml
vendored
2
.github/workflows/docker.yml
vendored
@ -23,7 +23,7 @@ jobs:
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- os: ubuntu-24.04-arm
|
||||
- os: ubuntu-26.04-arm
|
||||
platform: linux/arm64
|
||||
- os: ubuntu-latest
|
||||
platform: linux/amd64
|
||||
|
||||
4
.github/workflows/rust.yml
vendored
4
.github/workflows/rust.yml
vendored
@ -82,11 +82,10 @@ jobs:
|
||||
os:
|
||||
[
|
||||
ubuntu-latest,
|
||||
ubuntu-24.04-arm,
|
||||
ubuntu-26.04-arm,
|
||||
windows-latest,
|
||||
windows-11-arm,
|
||||
macos-latest,
|
||||
macos-15-intel,
|
||||
]
|
||||
toolchain:
|
||||
- stable
|
||||
@ -114,7 +113,6 @@ jobs:
|
||||
windows-latest,
|
||||
windows-11-arm,
|
||||
macos-latest,
|
||||
macos-15-intel,
|
||||
]
|
||||
toolchain:
|
||||
- stable
|
||||
|
||||
772
Cargo.lock
generated
772
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
19
Cargo.toml
19
Cargo.toml
@ -119,7 +119,7 @@ tempfile = { version = "3.27.0", default-features = false }
|
||||
proc-macro-error2 = { version = "2", default-features = false }
|
||||
aes = { version = "0.9", default-features = false }
|
||||
async-compression = { version = "0.4.42", default-features = false }
|
||||
base64 = { version = "0.22.1", default-features = false, features = ["std"] }
|
||||
base64 = { version = "0.23.0", default-features = false, features = ["std"] }
|
||||
bitflags = { version = "2.13.1", default-features = false, features = ["std"] }
|
||||
cesu8 = { version = "1.1", default-features = false }
|
||||
cfb8 = { version = "0.9", default-features = false }
|
||||
@ -133,7 +133,6 @@ crossfire = { version = "3.1.19", default-features = false, features = ["compat"
|
||||
crypto-bigint = { version = "0.7.5", default-features = false }
|
||||
dashmap = { version = "6.2", default-features = false }
|
||||
ecdsa = { version = "0.17.0", default-features = false, features = ["std"] }
|
||||
either = { version = "1.16.0", default-features = false }
|
||||
enum_dispatch = { version = "0.3.13", default-features = false }
|
||||
flate2 = { version = "1.1.9", default-features = false, features = ["rust_backend"] }
|
||||
heck = { version = "0.5", default-features = false }
|
||||
@ -145,7 +144,7 @@ lru = { version = "0.18.1", default-features = false }
|
||||
lz4-java-wrc = { version = "0.2.0", default-features = false, features = ["lz4_flex"] }
|
||||
md5 = { version = "0.8", default-features = false }
|
||||
num-bigint = { version = "0.5", default-features = false, features = ["std"] }
|
||||
num-derive = { version = "0.4", default-features = false }
|
||||
num-derive = { version = "0.5", default-features = false }
|
||||
num-traits = { version = "0.2", default-features = false, features = ["std"] }
|
||||
p384 = { version = "0.14.0", default-features = false, features = ["std", "arithmetic", "pkcs8", "ecdh"] }
|
||||
phf = { version = "0.14.0", default-features = false, features = ["std"] }
|
||||
@ -178,11 +177,9 @@ tracing-subscriber = { version = "0.3.23", default-features = false, features =
|
||||
"std",
|
||||
] }
|
||||
slotmap = { version = "1.1", default-features = false, features = ["std"] }
|
||||
temp-dir = { version = "0.2.0", default-features = false }
|
||||
thread_local = { version = "1.1.10", default-features = false }
|
||||
time = { version = "0.3", default-features = false, features = ["std"] }
|
||||
arc-swap = { version = "1.9", default-features = false }
|
||||
tokio-util = { version = "0.7.18", default-features = false }
|
||||
tokio-util = { version = "0.7.19", default-features = false }
|
||||
toml = { version = "1.1", default-features = false, features = ["parse", "display", "serde"] }
|
||||
ureq = { version = "3.3.0", default-features = false, features = ["rustls"] }
|
||||
notify = { version = "8.2.0", default-features = false, features = ["macos_fsevent"] }
|
||||
@ -192,12 +189,12 @@ rustc_version_runtime = { version = "0.3", default-features = false }
|
||||
ordered-float = { version = "5.3", default-features = false, features = ["std"] }
|
||||
xxhash-rust = { version = "0.8", default-features = false, features = ["xxh64"] }
|
||||
|
||||
wasmtime = { version = "46.0", default-features = false, features = ["runtime", "component-model", "async", "cache", "cranelift", "gc", "gc-drc", "threads", "std"] }
|
||||
wasmtime-wasi = { version = "46.0", default-features = false, features = ["p2"] }
|
||||
wasmtime-wasi-http = { version = "46.0", default-features = false, features = ["p2", "default-send-request"] }
|
||||
wasmtime = { version = "47.0", default-features = false, features = ["runtime", "component-model", "async", "cache", "cranelift", "gc", "gc-drc", "threads", "std"] }
|
||||
wasmtime-wasi = { version = "47.0", default-features = false, features = ["p2"] }
|
||||
wasmtime-wasi-http = { version = "47.0", default-features = false, features = ["p2", "default-send-request"] }
|
||||
# needed for interacting with wasmtime-wasi-http - keep in sync
|
||||
hyper = { version = "^1.10", default-features = false }
|
||||
wit-bindgen = { version = "0.59", default-features = false, features = ["macros"] }
|
||||
hyper = { version = "^1.11", default-features = false }
|
||||
wit-bindgen = { version = "0.60", default-features = false, features = ["macros"] }
|
||||
|
||||
postcard = { version = "1.1", default-features = false, features = ["alloc"] }
|
||||
tracing-serde-structured = { version = "0.4", default-features = false }
|
||||
|
||||
@ -8,7 +8,6 @@ license.workspace = true
|
||||
[dependencies]
|
||||
serde_json.workspace = true
|
||||
tracing.workspace = true
|
||||
either.workspace = true
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
@ -1,5 +1,34 @@
|
||||
use crate::{DataResult, Decode, DynamicOps, Encode};
|
||||
use either::Either;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||
pub enum Either<L, R> {
|
||||
Left(L),
|
||||
Right(R),
|
||||
}
|
||||
|
||||
impl<L, R> Either<L, R> {
|
||||
pub const fn is_left(&self) -> bool {
|
||||
matches!(self, Self::Left(_))
|
||||
}
|
||||
|
||||
pub const fn is_right(&self) -> bool {
|
||||
matches!(self, Self::Right(_))
|
||||
}
|
||||
|
||||
pub fn left(self) -> Option<L> {
|
||||
match self {
|
||||
Self::Left(l) => Some(l),
|
||||
Self::Right(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn right(self) -> Option<R> {
|
||||
match self {
|
||||
Self::Left(_) => None,
|
||||
Self::Right(r) => Some(r),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<L: Encode, R: Encode> Encode for Either<L, R> {
|
||||
fn encode<O: DynamicOps>(&self, ops: &'static O, prefix: O::Value) -> DataResult<O::Value> {
|
||||
@ -46,9 +75,9 @@ impl<L: Decode, R: Decode> Decode for Either<L, R> {
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::Either;
|
||||
use crate::json_ops::JsonOps;
|
||||
use crate::{assert_decode, assert_encode_success};
|
||||
use either::Either;
|
||||
use serde_json::json;
|
||||
|
||||
#[test]
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
mod either;
|
||||
pub mod either;
|
||||
pub mod list;
|
||||
pub mod map;
|
||||
pub mod optional_field;
|
||||
|
||||
@ -21,6 +21,7 @@ pub use number::Number;
|
||||
pub use crate::codec::Decode;
|
||||
pub use crate::codec::Encode;
|
||||
|
||||
pub use crate::codec::either::Either;
|
||||
pub use crate::codec::primitive::ByteBuffer;
|
||||
pub use crate::codec::primitive::IntStream;
|
||||
pub use crate::codec::primitive::LongStream;
|
||||
|
||||
104
pumpkin-codegen/Cargo.lock
generated
104
pumpkin-codegen/Cargo.lock
generated
@ -32,6 +32,12 @@ version = "0.22.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
|
||||
|
||||
[[package]]
|
||||
name = "base64"
|
||||
version = "0.23.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b25655df2c3cdd83c5e5b293b88acd880332b2ddadd7c30ac43144fdc0033da9"
|
||||
|
||||
[[package]]
|
||||
name = "base64ct"
|
||||
version = "1.8.3"
|
||||
@ -40,9 +46,9 @@ checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.13.0"
|
||||
version = "2.13.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b4388bee8683e3d04af747c73422af53102d2bd24d9eadb6cbc100baef4b43f8"
|
||||
checksum = "b588b76d00fde79687d7646a9b5bdf3cc0f655e0bbd080335a95d7e96f3587da"
|
||||
|
||||
[[package]]
|
||||
name = "block-buffer"
|
||||
@ -324,7 +330,7 @@ dependencies = [
|
||||
"once_cell",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 2.0.118",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -584,13 +590,13 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "num-derive"
|
||||
version = "0.4.2"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202"
|
||||
checksum = "e4e98dc3b890f6c23a0f9d3d491a2823d0dea0fa656302a13dd225fa924112a8"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 3.0.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -667,7 +673,7 @@ dependencies = [
|
||||
"pest_meta",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 2.0.118",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -723,7 +729,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"syn",
|
||||
"syn 2.0.118",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -788,7 +794,7 @@ dependencies = [
|
||||
"serde_json",
|
||||
"serde_json5",
|
||||
"serde_repr",
|
||||
"syn",
|
||||
"syn 3.0.2",
|
||||
"wit-encoder",
|
||||
]
|
||||
|
||||
@ -800,6 +806,7 @@ dependencies = [
|
||||
"cesu8",
|
||||
"flate2",
|
||||
"pumpkin-codecs",
|
||||
"rustc-hash",
|
||||
"serde",
|
||||
"thiserror",
|
||||
"tracing",
|
||||
@ -810,7 +817,7 @@ dependencies = [
|
||||
name = "pumpkin-util"
|
||||
version = "0.1.0-dev+26.2"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"base64 0.23.0",
|
||||
"bytes",
|
||||
"colored",
|
||||
"crypto-bigint",
|
||||
@ -828,7 +835,7 @@ dependencies = [
|
||||
"serde",
|
||||
"serde_json",
|
||||
"sha2 0.11.0",
|
||||
"syn",
|
||||
"syn 3.0.2",
|
||||
"thiserror",
|
||||
"tokio",
|
||||
"ureq",
|
||||
@ -918,6 +925,12 @@ dependencies = [
|
||||
"zeroize",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc-hash"
|
||||
version = "2.1.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6b1e7f9a428571be2dc5bc0505c13fb6bf936822b894ec87abf8a08a4e51742d"
|
||||
|
||||
[[package]]
|
||||
name = "rustls"
|
||||
version = "0.23.39"
|
||||
@ -985,9 +998,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.228"
|
||||
version = "1.0.229"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
|
||||
checksum = "4148590afebada386688f18773da617792bf2ef03ffc1e4cbd2b1d45b023e0ba"
|
||||
dependencies = [
|
||||
"serde_core",
|
||||
"serde_derive",
|
||||
@ -995,29 +1008,29 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "serde_core"
|
||||
version = "1.0.228"
|
||||
version = "1.0.229"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad"
|
||||
checksum = "67dca2c9c51e58a4791a4b1ed58308b39c64224d349a935ab5039aa360942a48"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.228"
|
||||
version = "1.0.229"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
|
||||
checksum = "e7a5d71263a5a7d47b41f6b3f06ba276f10cc18b0931f1799f710578e2309348"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 3.0.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_json"
|
||||
version = "1.0.150"
|
||||
version = "1.0.151"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e8014e44b4736ed0538adeecded0fce2a272f22dc9578a7eb6b2d9993c74cfb9"
|
||||
checksum = "c841b55ecdae098c80dcae9cf767f6f8a0c2cdb3416bbef72181df4d0fe73f14"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"itoa",
|
||||
@ -1046,7 +1059,7 @@ checksum = "175ee3e80ae9982737ca543e96133087cbd9a485eecc3bc4de9c1a37b47ea59c"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 2.0.118",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1130,6 +1143,17 @@ dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "3.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a207d6d6a2b7fc470b80443726053f18a2481b7e1eee970597051596567987a3"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "2.0.18"
|
||||
@ -1147,14 +1171,14 @@ checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 2.0.118",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio"
|
||||
version = "1.52.0"
|
||||
version = "1.53.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a91135f59b1cbf38c91e73cf3386fca9bb77915c45ce2771460c9d92f0f3d776"
|
||||
checksum = "202caea871b69668250d242070849eb495be178ed697a3e98aebce5bc81a0bed"
|
||||
dependencies = [
|
||||
"pin-project-lite",
|
||||
]
|
||||
@ -1178,7 +1202,7 @@ checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 2.0.118",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1226,7 +1250,7 @@ version = "3.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dea7109cdcd5864d4eeb1b58a1648dc9bf520360d7af16ec26d0a9354bafcfc0"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"base64 0.22.1",
|
||||
"log",
|
||||
"percent-encoding",
|
||||
"rustls",
|
||||
@ -1242,7 +1266,7 @@ version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e994ba84b0bd1b1b0cf92878b7ef898a5c1760108fe7b6010327e274917a808c"
|
||||
dependencies = [
|
||||
"base64",
|
||||
"base64 0.22.1",
|
||||
"http",
|
||||
"httparse",
|
||||
"log",
|
||||
@ -1256,9 +1280,9 @@ checksum = "b8c0a043c9540bae7c578c88f91dda8bd82e59ae27c21baca69c8b191aaf5a6e"
|
||||
|
||||
[[package]]
|
||||
name = "uuid"
|
||||
version = "1.23.0"
|
||||
version = "1.24.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5ac8b6f42ead25368cf5b098aeb3dc8a1a2c05a3eee8a9a1a68c640edbfc79d9"
|
||||
checksum = "bf3923a6f5c4c6382e0b653c4117f48d631ea17f38ed86e2a828e6f7412f5239"
|
||||
dependencies = [
|
||||
"getrandom 0.4.1",
|
||||
"js-sys",
|
||||
@ -1329,7 +1353,7 @@ dependencies = [
|
||||
"bumpalo",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 2.0.118",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
@ -1378,9 +1402,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wasmparser"
|
||||
version = "0.253.0"
|
||||
version = "0.254.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "19db11f87d2486580e1e8b6f494c54df7e0566b87d0b599db843c24019667339"
|
||||
checksum = "d5769a29f799fbab136aaf65b4fe5384cd7d93fe6fc9ba0dcb6c8382a1f16e27"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"indexmap",
|
||||
@ -1514,7 +1538,7 @@ dependencies = [
|
||||
"heck",
|
||||
"indexmap",
|
||||
"prettyplease",
|
||||
"syn",
|
||||
"syn 2.0.118",
|
||||
"wasm-metadata",
|
||||
"wit-bindgen-core",
|
||||
"wit-component",
|
||||
@ -1530,7 +1554,7 @@ dependencies = [
|
||||
"prettyplease",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"syn 2.0.118",
|
||||
"wit-bindgen-core",
|
||||
"wit-bindgen-rust",
|
||||
]
|
||||
@ -1556,15 +1580,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wit-encoder"
|
||||
version = "0.253.0"
|
||||
version = "0.254.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "63b783601ee9357f78aaa12bc5cfd0cd0a2fb3d637de1f35604e14eef52ab97d"
|
||||
checksum = "c565f1f3dcf3b659d6c15052739e35937227590d7dded3d3ce274f7bd9c34d93"
|
||||
dependencies = [
|
||||
"id-arena",
|
||||
"pretty_assertions",
|
||||
"semver",
|
||||
"serde",
|
||||
"wit-parser 0.253.0",
|
||||
"wit-parser 0.254.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -1587,9 +1611,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "wit-parser"
|
||||
version = "0.253.0"
|
||||
version = "0.254.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4d997b8e5920fcbeec742b58e583325d6419a6aca617ae8075c406a61c65ba8a"
|
||||
checksum = "1655131e4f7d3f0cb141f6eca71315ca40eff0f3d4de7cff0a82bacedd8c89b4"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"hashbrown 0.17.1",
|
||||
@ -1601,7 +1625,7 @@ dependencies = [
|
||||
"serde_derive",
|
||||
"serde_json",
|
||||
"unicode-ident",
|
||||
"wasmparser 0.253.0",
|
||||
"wasmparser 0.254.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
||||
@ -16,13 +16,13 @@ serde_repr = { version = "0.1" }
|
||||
serde_json = { version = "1.0", features = ["preserve_order"] }
|
||||
serde_json5 = "0.2"
|
||||
|
||||
wit-encoder = "0.253.0"
|
||||
wit-encoder = "0.254.0"
|
||||
semver = "1.0"
|
||||
rayon = "1.12.0"
|
||||
|
||||
proc-macro2 = "1.0"
|
||||
quote = "1.0"
|
||||
syn = { version = "2.0", features = ["full", "extra-traits"] }
|
||||
syn = { version = "3.0", features = ["full", "extra-traits"] }
|
||||
|
||||
pumpkin-util = { path = "../pumpkin-util", features = ["codegen"] }
|
||||
pumpkin-nbt = { path = "../pumpkin-nbt" }
|
||||
|
||||
@ -765,7 +765,9 @@ impl ToTokens for ItemComponents {
|
||||
tokens.extend(quote! { (EnchantmentGlintOverride, &EnchantmentGlintOverrideImpl), });
|
||||
}
|
||||
if self.enchantments.is_some() {
|
||||
tokens.extend(quote! { (Enchantments, &EnchantmentsImpl { enchantment: Cow::Borrowed(&[]) }), });
|
||||
tokens.extend(
|
||||
quote! { (Enchantments, &EnchantmentsImpl { enchantment: Cow::Borrowed(&[]) }), },
|
||||
);
|
||||
}
|
||||
if self.entity_data.is_some() {
|
||||
tokens.extend(quote! { (EntityData, &EntityDataImpl), });
|
||||
@ -793,7 +795,8 @@ impl ToTokens for ItemComponents {
|
||||
}
|
||||
if let Some(model) = &self.item_model {
|
||||
let model_lit = LitStr::new(model, Span::call_site());
|
||||
tokens.extend(quote! { (ItemModel, &ItemModelImpl { id: Cow::Borrowed(#model_lit) }), });
|
||||
tokens
|
||||
.extend(quote! { (ItemModel, &ItemModelImpl { id: Cow::Borrowed(#model_lit) }), });
|
||||
}
|
||||
if self.kinetic_weapon.is_some() {
|
||||
tokens.extend(quote! { (KineticWeapon, &KineticWeaponImpl), });
|
||||
@ -870,7 +873,9 @@ impl ToTokens for ItemComponents {
|
||||
tokens.extend(quote! { (UseRemainder, &UseRemainderImpl), });
|
||||
}
|
||||
if self.writable_book_content.is_some() {
|
||||
tokens.extend(quote! { (WritableBookContent, &WritableBookContentImpl { pages: Vec::new() }), });
|
||||
tokens.extend(
|
||||
quote! { (WritableBookContent, &WritableBookContentImpl { pages: Vec::new() }), },
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -538,7 +538,9 @@ impl ToTokens for LootConditionStruct {
|
||||
.and_then(|p| p.entity_type.as_ref())
|
||||
.map(|t| match t {
|
||||
StringOrVec::String(s) => quote! { Some(#s) },
|
||||
StringOrVec::Vec(v) => v.first().map_or(quote! { None }, |s| quote! { Some(#s) }),
|
||||
StringOrVec::Vec(v) => {
|
||||
v.first().map_or(quote! { None }, |s| quote! { Some(#s) })
|
||||
}
|
||||
})
|
||||
.unwrap_or(quote! { None });
|
||||
|
||||
@ -559,7 +561,9 @@ impl ToTokens for LootConditionStruct {
|
||||
.and_then(|ench| ench.enchantments.as_ref())
|
||||
.map(|t| match t {
|
||||
StringOrVec::String(s) => quote! { Some(#s) },
|
||||
StringOrVec::Vec(v) => v.first().map_or(quote! { None }, |s| quote! { Some(#s) }),
|
||||
StringOrVec::Vec(v) => {
|
||||
v.first().map_or(quote! { None }, |s| quote! { Some(#s) })
|
||||
}
|
||||
})
|
||||
.unwrap_or(quote! { None });
|
||||
|
||||
@ -613,7 +617,9 @@ impl ToTokens for LootConditionStruct {
|
||||
.and_then(|e| e.entity_type.as_ref())
|
||||
.map(|t| match t {
|
||||
StringOrVec::String(s) => quote! { Some(#s) },
|
||||
StringOrVec::Vec(v) => v.first().map_or(quote! { None }, |s| quote! { Some(#s) }),
|
||||
StringOrVec::Vec(v) => {
|
||||
v.first().map_or(quote! { None }, |s| quote! { Some(#s) })
|
||||
}
|
||||
})
|
||||
.unwrap_or(quote! { None });
|
||||
|
||||
@ -623,7 +629,9 @@ impl ToTokens for LootConditionStruct {
|
||||
.and_then(|e| e.entity_type.as_ref())
|
||||
.map(|t| match t {
|
||||
StringOrVec::String(s) => quote! { Some(#s) },
|
||||
StringOrVec::Vec(v) => v.first().map_or(quote! { None }, |s| quote! { Some(#s) }),
|
||||
StringOrVec::Vec(v) => {
|
||||
v.first().map_or(quote! { None }, |s| quote! { Some(#s) })
|
||||
}
|
||||
})
|
||||
.unwrap_or(quote! { None });
|
||||
|
||||
@ -643,7 +651,9 @@ impl ToTokens for LootConditionStruct {
|
||||
.and_then(|p| p.biome.as_ref())
|
||||
.map(|b| match b {
|
||||
StringOrVec::String(s) => quote! { Some(#s) },
|
||||
StringOrVec::Vec(v) => v.first().map_or(quote! { None }, |s| quote! { Some(#s) }),
|
||||
StringOrVec::Vec(v) => {
|
||||
v.first().map_or(quote! { None }, |s| quote! { Some(#s) })
|
||||
}
|
||||
})
|
||||
.unwrap_or(quote! { None });
|
||||
quote! { LootCondition::LocationCheck { offset_x: #ox, offset_y: #oy, offset_z: #oz, expected_biome: #expected_biome } }
|
||||
|
||||
@ -165,7 +165,7 @@ fn collect_fields(
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn wit_name(name: String,state: &str) -> String{
|
||||
fn wit_name(name: String, state: &str) -> String {
|
||||
if state == "play" {
|
||||
name.to_kebab_case()
|
||||
} else {
|
||||
@ -180,7 +180,7 @@ fn process_struct(
|
||||
variant: &mut Variant,
|
||||
defined_cases: &mut HashSet<String>,
|
||||
) {
|
||||
let wit_name = wit_name(s.ident.to_string(),state);
|
||||
let wit_name = wit_name(s.ident.to_string(), state);
|
||||
if !defined_cases.insert(wit_name.clone()) {
|
||||
return;
|
||||
}
|
||||
@ -199,7 +199,7 @@ fn process_enum(
|
||||
variant: &mut Variant,
|
||||
defined_cases: &mut HashSet<String>,
|
||||
) {
|
||||
let enum_wit_name = wit_name(e.ident.to_string(),state);
|
||||
let enum_wit_name = wit_name(e.ident.to_string(), state);
|
||||
if !defined_cases.insert(enum_wit_name.clone()) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -43,7 +43,7 @@ pub fn build_java_mapping() -> String {
|
||||
output.push_str("}\n\n");
|
||||
|
||||
output.push_str("#[must_use]\n");
|
||||
output.push_str("pub fn deserialize_java_serverbound_packet(id: i32, payload: &[u8], version: JavaMinecraftVersion) -> Option<ServerboundPacket> {\n");
|
||||
output.push_str("pub fn deserialize_java_serverbound_packet(id: i32, mut payload: &[u8], version: JavaMinecraftVersion) -> Option<ServerboundPacket> {\n");
|
||||
output.push_str(" match id {\n");
|
||||
|
||||
for state in server_states {
|
||||
@ -715,7 +715,7 @@ fn emit_struct_output(
|
||||
));
|
||||
output.push_str(" use pumpkin_protocol::ServerPacket;\n");
|
||||
output.push_str(&format!(
|
||||
" let p = <{}::{} as pumpkin_protocol::ServerPacket>::read(&mut Cursor::new(payload), &version).ok()?;\n",
|
||||
" let p = <{}::{} as pumpkin_protocol::ServerPacket>::read(&mut payload, &version).ok()?;\n",
|
||||
rust_path_prefix, struct_name
|
||||
));
|
||||
} else {
|
||||
@ -846,7 +846,7 @@ fn process_enum(
|
||||
));
|
||||
output.push_str(" use pumpkin_protocol::ServerPacket;\n");
|
||||
output.push_str(&format!(
|
||||
" let p = <{}::{} as pumpkin_protocol::ServerPacket>::read(&mut Cursor::new(payload), &version).ok()?;\n",
|
||||
" let p = <{}::{} as pumpkin_protocol::ServerPacket>::read(&mut payload, &version).ok()?;\n",
|
||||
rust_path_prefix, enum_name
|
||||
));
|
||||
} else {
|
||||
|
||||
@ -106,7 +106,7 @@ pub fn bench_nbt(c: &mut Criterion) {
|
||||
|
||||
c.bench_function("nbt/java/deserialize/raw", |b| {
|
||||
b.iter(|| {
|
||||
let mut cursor = Cursor::new(&wrapper_bytes_java);
|
||||
let mut cursor = Cursor::new(&wrapper_bytes_java[..]);
|
||||
let mut reader = deserializer::NbtReadHelperJava::new(&mut cursor);
|
||||
Nbt::read(&mut reader).unwrap();
|
||||
});
|
||||
@ -135,7 +135,7 @@ pub fn bench_nbt(c: &mut Criterion) {
|
||||
|
||||
c.bench_function("nbt/bedrock/deserialize/raw", |b| {
|
||||
b.iter(|| {
|
||||
let mut cursor = Cursor::new(&wrapper_bytes_bedrock);
|
||||
let mut cursor = Cursor::new(&wrapper_bytes_bedrock[..]);
|
||||
let mut reader = deserializer::NbtReadHelperBedrock::new(&mut cursor);
|
||||
Nbt::read(&mut reader).unwrap();
|
||||
});
|
||||
|
||||
@ -43,7 +43,7 @@ impl NbtCompound {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn skip_content<R: NbtReadHelper>(reader: &mut R) -> Result<(), Error> {
|
||||
pub fn skip_content<'a, R: NbtReadHelper<'a>>(reader: &mut R) -> Result<(), Error> {
|
||||
loop {
|
||||
let tag_id = match reader.get_u8() {
|
||||
Ok(id) => id,
|
||||
@ -64,7 +64,7 @@ impl NbtCompound {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn deserialize_content<R: NbtReadHelper>(reader: &mut R) -> Result<Self, Error> {
|
||||
pub fn deserialize_content<'a, R: NbtReadHelper<'a>>(reader: &mut R) -> Result<Self, Error> {
|
||||
let mut compound = Self::new();
|
||||
|
||||
loop {
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
use std::borrow::Cow;
|
||||
use std::cell::RefCell;
|
||||
use std::io::{Seek, SeekFrom};
|
||||
use std::io::{Cursor, Seek, SeekFrom};
|
||||
|
||||
use crate::{
|
||||
BYTE_ARRAY_ID, BYTE_ID, COMPOUND_ID, END_ID, Error, INT_ARRAY_ID, INT_ID, LIST_ID,
|
||||
@ -25,16 +26,178 @@ pub(super) fn set_curr_visitor_seq_list_id(tag: Option<u8>) {
|
||||
});
|
||||
}
|
||||
|
||||
pub trait NbtReadHelper {
|
||||
type Reader: Read + Seek;
|
||||
pub trait NbtDataSource<'a> {
|
||||
fn read_u8(&mut self) -> Result<u8>;
|
||||
fn read_bytes(&mut self, buf: &mut [u8]) -> Result<()>;
|
||||
fn seek_relative(&mut self, offset: i64) -> Result<()>;
|
||||
fn read_string(&mut self, len: usize) -> Result<Cow<'a, str>>;
|
||||
fn read_byte_array(&mut self, len: usize) -> Result<Cow<'a, [i8]>>;
|
||||
}
|
||||
|
||||
pub struct NbtStreamReader<R>(pub R);
|
||||
|
||||
impl<'a, R: Read + Seek> NbtDataSource<'a> for NbtStreamReader<R> {
|
||||
fn read_u8(&mut self) -> Result<u8> {
|
||||
let mut buf = [0u8; 1];
|
||||
self.0.read_exact(&mut buf).map_err(Error::Incomplete)?;
|
||||
Ok(buf[0])
|
||||
}
|
||||
|
||||
fn read_bytes(&mut self, buf: &mut [u8]) -> Result<()> {
|
||||
self.0.read_exact(buf).map_err(Error::Incomplete)
|
||||
}
|
||||
|
||||
fn seek_relative(&mut self, offset: i64) -> Result<()> {
|
||||
self.0
|
||||
.seek(SeekFrom::Current(offset))
|
||||
.map_err(Error::Incomplete)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn read_string(&mut self, len: usize) -> Result<Cow<'a, str>> {
|
||||
let mut buf = vec![0u8; len];
|
||||
self.0.read_exact(&mut buf).map_err(Error::Incomplete)?;
|
||||
let string = cesu8::from_java_cesu8(&buf).map_err(|_| Error::Cesu8DecodingError)?;
|
||||
Ok(Cow::Owned(string.into_owned()))
|
||||
}
|
||||
|
||||
fn read_byte_array(&mut self, len: usize) -> Result<Cow<'a, [i8]>> {
|
||||
let mut buf = vec![0u8; len];
|
||||
self.0.read_exact(&mut buf).map_err(Error::Incomplete)?;
|
||||
let i8_buf: Vec<i8> = buf.into_iter().map(|b| b as i8).collect();
|
||||
Ok(Cow::Owned(i8_buf))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> NbtDataSource<'a> for Cursor<&'a [u8]> {
|
||||
fn read_u8(&mut self) -> Result<u8> {
|
||||
let mut buf = [0u8; 1];
|
||||
self.read_exact(&mut buf).map_err(Error::Incomplete)?;
|
||||
Ok(buf[0])
|
||||
}
|
||||
|
||||
fn read_bytes(&mut self, buf: &mut [u8]) -> Result<()> {
|
||||
self.read_exact(buf).map_err(Error::Incomplete)
|
||||
}
|
||||
|
||||
fn seek_relative(&mut self, offset: i64) -> Result<()> {
|
||||
self.seek(SeekFrom::Current(offset))
|
||||
.map_err(Error::Incomplete)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn read_string(&mut self, len: usize) -> Result<Cow<'a, str>> {
|
||||
let pos = self.position() as usize;
|
||||
let data_len = self.get_ref().len();
|
||||
if pos + len > data_len {
|
||||
return Err(Error::Incomplete(std::io::Error::new(
|
||||
std::io::ErrorKind::UnexpectedEof,
|
||||
"unexpected EOF",
|
||||
)));
|
||||
}
|
||||
self.set_position((pos + len) as u64);
|
||||
let data = self.get_ref();
|
||||
let slice = &data[pos..pos + len];
|
||||
if let Ok(s) = std::str::from_utf8(slice) {
|
||||
Ok(Cow::Borrowed(s))
|
||||
} else {
|
||||
let string = cesu8::from_java_cesu8(slice).map_err(|_| Error::Cesu8DecodingError)?;
|
||||
Ok(string)
|
||||
}
|
||||
}
|
||||
|
||||
fn read_byte_array(&mut self, len: usize) -> Result<Cow<'a, [i8]>> {
|
||||
let pos = self.position() as usize;
|
||||
let data_len = self.get_ref().len();
|
||||
if pos + len > data_len {
|
||||
return Err(Error::Incomplete(std::io::Error::new(
|
||||
std::io::ErrorKind::UnexpectedEof,
|
||||
"unexpected EOF",
|
||||
)));
|
||||
}
|
||||
self.set_position((pos + len) as u64);
|
||||
let data = self.get_ref();
|
||||
let slice = &data[pos..pos + len];
|
||||
let i8_slice = unsafe { std::slice::from_raw_parts(slice.as_ptr().cast::<i8>(), len) };
|
||||
Ok(Cow::Borrowed(i8_slice))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, S: NbtDataSource<'a> + ?Sized> NbtDataSource<'a> for &mut S {
|
||||
fn read_u8(&mut self) -> Result<u8> {
|
||||
(**self).read_u8()
|
||||
}
|
||||
fn read_bytes(&mut self, buf: &mut [u8]) -> Result<()> {
|
||||
(**self).read_bytes(buf)
|
||||
}
|
||||
fn seek_relative(&mut self, offset: i64) -> Result<()> {
|
||||
(**self).seek_relative(offset)
|
||||
}
|
||||
fn read_string(&mut self, len: usize) -> Result<Cow<'a, str>> {
|
||||
(**self).read_string(len)
|
||||
}
|
||||
fn read_byte_array(&mut self, len: usize) -> Result<Cow<'a, [i8]>> {
|
||||
(**self).read_byte_array(len)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> NbtDataSource<'a> for Cursor<Vec<u8>> {
|
||||
fn read_u8(&mut self) -> Result<u8> {
|
||||
let mut buf = [0u8; 1];
|
||||
self.read_exact(&mut buf).map_err(Error::Incomplete)?;
|
||||
Ok(buf[0])
|
||||
}
|
||||
|
||||
fn read_bytes(&mut self, buf: &mut [u8]) -> Result<()> {
|
||||
self.read_exact(buf).map_err(Error::Incomplete)
|
||||
}
|
||||
|
||||
fn seek_relative(&mut self, offset: i64) -> Result<()> {
|
||||
self.seek(SeekFrom::Current(offset))
|
||||
.map_err(Error::Incomplete)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn read_string(&mut self, len: usize) -> Result<Cow<'a, str>> {
|
||||
let pos = self.position() as usize;
|
||||
let data_len = self.get_ref().len();
|
||||
if pos + len > data_len {
|
||||
return Err(Error::Incomplete(std::io::Error::new(
|
||||
std::io::ErrorKind::UnexpectedEof,
|
||||
"unexpected EOF",
|
||||
)));
|
||||
}
|
||||
self.set_position((pos + len) as u64);
|
||||
let data = self.get_ref();
|
||||
let slice = &data[pos..pos + len];
|
||||
let string = cesu8::from_java_cesu8(slice).map_err(|_| Error::Cesu8DecodingError)?;
|
||||
Ok(Cow::Owned(string.into_owned()))
|
||||
}
|
||||
|
||||
fn read_byte_array(&mut self, len: usize) -> Result<Cow<'a, [i8]>> {
|
||||
let pos = self.position() as usize;
|
||||
let data_len = self.get_ref().len();
|
||||
if pos + len > data_len {
|
||||
return Err(Error::Incomplete(std::io::Error::new(
|
||||
std::io::ErrorKind::UnexpectedEof,
|
||||
"unexpected EOF",
|
||||
)));
|
||||
}
|
||||
self.set_position((pos + len) as u64);
|
||||
let data = self.get_ref();
|
||||
let slice = &data[pos..pos + len];
|
||||
let i8_slice = unsafe { std::slice::from_raw_parts(slice.as_ptr().cast::<i8>(), len) };
|
||||
Ok(Cow::Owned(i8_slice.to_vec()))
|
||||
}
|
||||
}
|
||||
|
||||
pub trait NbtReadHelper<'a> {
|
||||
type Reader: NbtDataSource<'a>;
|
||||
|
||||
fn reader(&mut self) -> &mut Self::Reader;
|
||||
|
||||
fn skip_bytes(&mut self, count: i64) -> Result<()> {
|
||||
self.reader()
|
||||
.seek(SeekFrom::Current(count))
|
||||
.map_err(Error::Incomplete)?;
|
||||
Ok(())
|
||||
self.reader().seek_relative(count)
|
||||
}
|
||||
fn skip_u8(&mut self) -> Result<()> {
|
||||
self.skip_bytes(1)
|
||||
@ -66,63 +229,42 @@ pub trait NbtReadHelper {
|
||||
fn get_i64(&mut self) -> Result<i64>;
|
||||
fn get_f32(&mut self) -> Result<f32>;
|
||||
fn get_f64(&mut self) -> Result<f64>;
|
||||
fn get_string(&mut self) -> Result<String>;
|
||||
fn get_string(&mut self) -> Result<Cow<'a, str>>;
|
||||
fn get_byte_array(&mut self, len: usize) -> Result<Cow<'a, [i8]>>;
|
||||
}
|
||||
|
||||
macro_rules! define_get_number_be {
|
||||
($name:ident, $type:ty) => {
|
||||
fn $name(&mut self) -> Result<$type> {
|
||||
let mut buf = [0u8; std::mem::size_of::<$type>()];
|
||||
self.reader
|
||||
.read_exact(&mut buf)
|
||||
.map_err(Error::Incomplete)?;
|
||||
|
||||
Ok(<$type>::from_be_bytes(buf))
|
||||
}
|
||||
};
|
||||
pub struct NbtReadHelperJava<D> {
|
||||
reader: D,
|
||||
}
|
||||
|
||||
macro_rules! define_get_number_le {
|
||||
($name:ident, $type:ty) => {
|
||||
fn $name(&mut self) -> Result<$type> {
|
||||
let mut buf = [0u8; std::mem::size_of::<$type>()];
|
||||
self.reader
|
||||
.read_exact(&mut buf)
|
||||
.map_err(Error::Incomplete)?;
|
||||
|
||||
Ok(<$type>::from_le_bytes(buf))
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
pub struct NbtReadHelperJava<R: Read + Seek> {
|
||||
reader: R,
|
||||
}
|
||||
|
||||
impl<R: Read + Seek> NbtReadHelperJava<R> {
|
||||
pub const fn new(r: R) -> Self {
|
||||
impl<D> NbtReadHelperJava<D> {
|
||||
pub const fn new(r: D) -> Self {
|
||||
Self { reader: r }
|
||||
}
|
||||
}
|
||||
|
||||
pub struct NbtReadHelperBedrock<R: Read + Seek> {
|
||||
reader: R,
|
||||
pub struct NbtReadHelperBedrock<D> {
|
||||
reader: D,
|
||||
}
|
||||
|
||||
impl<R: Read + Seek> NbtReadHelperBedrock<R> {
|
||||
pub const fn new(r: R) -> Self {
|
||||
impl<D> NbtReadHelperBedrock<D> {
|
||||
pub const fn new(r: D) -> Self {
|
||||
Self { reader: r }
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: Read + Seek> NbtReadHelperJava<R> {
|
||||
define_get_number_be!(get_string_len, u16);
|
||||
impl<'a, D: NbtDataSource<'a>> NbtReadHelperJava<D> {
|
||||
fn get_string_len(&mut self) -> Result<u16> {
|
||||
let mut buf = [0u8; 2];
|
||||
self.reader.read_bytes(&mut buf)?;
|
||||
Ok(u16::from_be_bytes(buf))
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: Read + Seek> NbtReadHelper for NbtReadHelperJava<R> {
|
||||
type Reader = R;
|
||||
impl<'a, D: NbtDataSource<'a>> NbtReadHelper<'a> for NbtReadHelperJava<D> {
|
||||
type Reader = D;
|
||||
|
||||
fn reader(&mut self) -> &mut R {
|
||||
fn reader(&mut self) -> &mut D {
|
||||
&mut self.reader
|
||||
}
|
||||
|
||||
@ -131,31 +273,54 @@ impl<R: Read + Seek> NbtReadHelper for NbtReadHelperJava<R> {
|
||||
self.skip_bytes(len)
|
||||
}
|
||||
|
||||
define_get_number_be!(get_u8, u8);
|
||||
define_get_number_be!(get_i8, i8);
|
||||
define_get_number_be!(get_i16, i16);
|
||||
define_get_number_be!(get_i32, i32);
|
||||
define_get_number_be!(get_i64, i64);
|
||||
define_get_number_be!(get_f32, f32);
|
||||
define_get_number_be!(get_f64, f64);
|
||||
fn get_u8(&mut self) -> Result<u8> {
|
||||
self.reader.read_u8()
|
||||
}
|
||||
fn get_i8(&mut self) -> Result<i8> {
|
||||
Ok(self.reader.read_u8()? as i8)
|
||||
}
|
||||
fn get_i16(&mut self) -> Result<i16> {
|
||||
let mut buf = [0u8; 2];
|
||||
self.reader.read_bytes(&mut buf)?;
|
||||
Ok(i16::from_be_bytes(buf))
|
||||
}
|
||||
fn get_i32(&mut self) -> Result<i32> {
|
||||
let mut buf = [0u8; 4];
|
||||
self.reader.read_bytes(&mut buf)?;
|
||||
Ok(i32::from_be_bytes(buf))
|
||||
}
|
||||
fn get_i64(&mut self) -> Result<i64> {
|
||||
let mut buf = [0u8; 8];
|
||||
self.reader.read_bytes(&mut buf)?;
|
||||
Ok(i64::from_be_bytes(buf))
|
||||
}
|
||||
fn get_f32(&mut self) -> Result<f32> {
|
||||
let mut buf = [0u8; 4];
|
||||
self.reader.read_bytes(&mut buf)?;
|
||||
Ok(f32::from_be_bytes(buf))
|
||||
}
|
||||
fn get_f64(&mut self) -> Result<f64> {
|
||||
let mut buf = [0u8; 8];
|
||||
self.reader.read_bytes(&mut buf)?;
|
||||
Ok(f64::from_be_bytes(buf))
|
||||
}
|
||||
|
||||
fn get_string(&mut self) -> Result<String> {
|
||||
fn get_string(&mut self) -> Result<Cow<'a, str>> {
|
||||
let len = self.get_string_len()? as usize;
|
||||
self.reader.read_string(len)
|
||||
}
|
||||
|
||||
let mut buf = vec![0u8; len];
|
||||
self.reader
|
||||
.read_exact(&mut buf)
|
||||
.map_err(Error::Incomplete)?;
|
||||
|
||||
let string = cesu8::from_java_cesu8(&buf).map_err(|_| Error::Cesu8DecodingError)?;
|
||||
|
||||
Ok(string.into_owned())
|
||||
fn get_byte_array(&mut self, len: usize) -> Result<Cow<'a, [i8]>> {
|
||||
self.reader.read_byte_array(len)
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: Read + Seek> NbtReadHelperBedrock<R> {
|
||||
impl<'a, D: NbtDataSource<'a>> NbtReadHelperBedrock<D> {
|
||||
fn get_u8(&mut self) -> Result<u8> {
|
||||
self.reader.read_u8()
|
||||
}
|
||||
|
||||
fn get_var_u32(&mut self) -> Result<u32> {
|
||||
// LEB128
|
||||
let mut val = 0;
|
||||
for i in 0..5 {
|
||||
let byte = self.get_u8()?;
|
||||
@ -169,12 +334,10 @@ impl<R: Read + Seek> NbtReadHelperBedrock<R> {
|
||||
|
||||
fn get_var_i32(&mut self) -> Result<i32> {
|
||||
let val = self.get_var_u32()?;
|
||||
// ZigZag
|
||||
Ok(((val >> 1) as i32) ^ -((val as i32) & 1))
|
||||
}
|
||||
|
||||
fn get_var_u64(&mut self) -> Result<u64> {
|
||||
// LEB128
|
||||
let mut val = 0;
|
||||
for i in 0..10 {
|
||||
let byte = self.get_u8()?;
|
||||
@ -188,7 +351,6 @@ impl<R: Read + Seek> NbtReadHelperBedrock<R> {
|
||||
|
||||
fn get_var_i64(&mut self) -> Result<i64> {
|
||||
let val = self.get_var_u64()?;
|
||||
// ZigZag
|
||||
Ok(((val >> 1) as i64) ^ -((val as i64) & 1))
|
||||
}
|
||||
|
||||
@ -197,67 +359,64 @@ impl<R: Read + Seek> NbtReadHelperBedrock<R> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: Read + Seek> NbtReadHelper for NbtReadHelperBedrock<R> {
|
||||
type Reader = R;
|
||||
impl<'a, D: NbtDataSource<'a>> NbtReadHelper<'a> for NbtReadHelperBedrock<D> {
|
||||
type Reader = D;
|
||||
|
||||
fn reader(&mut self) -> &mut Self::Reader {
|
||||
fn reader(&mut self) -> &mut D {
|
||||
&mut self.reader
|
||||
}
|
||||
|
||||
fn skip_i32(&mut self) -> Result<()> {
|
||||
for _ in 0..5 {
|
||||
if self.get_u8()? & 0x80 == 0 {
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
Err(Error::VarIntTooLarge)
|
||||
}
|
||||
fn skip_i64(&mut self) -> Result<()> {
|
||||
for _ in 0..10 {
|
||||
if self.get_u8()? & 0x80 == 0 {
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
Err(Error::VarLongTooLarge)
|
||||
}
|
||||
fn skip_string(&mut self) -> Result<()> {
|
||||
let len = self.get_string_len()? as i64;
|
||||
self.skip_bytes(len)
|
||||
}
|
||||
|
||||
define_get_number_le!(get_u8, u8);
|
||||
define_get_number_le!(get_i8, i8);
|
||||
define_get_number_le!(get_i16, i16);
|
||||
fn get_u8(&mut self) -> Result<u8> {
|
||||
self.reader.read_u8()
|
||||
}
|
||||
fn get_i8(&mut self) -> Result<i8> {
|
||||
Ok(self.reader.read_u8()? as i8)
|
||||
}
|
||||
fn get_i16(&mut self) -> Result<i16> {
|
||||
let mut buf = [0u8; 2];
|
||||
self.reader.read_bytes(&mut buf)?;
|
||||
Ok(i16::from_le_bytes(buf))
|
||||
}
|
||||
fn get_i32(&mut self) -> Result<i32> {
|
||||
self.get_var_i32()
|
||||
}
|
||||
fn get_i64(&mut self) -> Result<i64> {
|
||||
self.get_var_i64()
|
||||
}
|
||||
define_get_number_le!(get_f32, f32);
|
||||
define_get_number_le!(get_f64, f64);
|
||||
fn get_f32(&mut self) -> Result<f32> {
|
||||
let mut buf = [0u8; 4];
|
||||
self.reader.read_bytes(&mut buf)?;
|
||||
Ok(f32::from_le_bytes(buf))
|
||||
}
|
||||
fn get_f64(&mut self) -> Result<f64> {
|
||||
let mut buf = [0u8; 8];
|
||||
self.reader.read_bytes(&mut buf)?;
|
||||
Ok(f64::from_le_bytes(buf))
|
||||
}
|
||||
|
||||
fn get_string(&mut self) -> Result<String> {
|
||||
fn get_string(&mut self) -> Result<Cow<'a, str>> {
|
||||
let len = self.get_string_len()? as usize;
|
||||
self.reader.read_string(len)
|
||||
}
|
||||
|
||||
let mut buf = vec![0u8; len];
|
||||
self.reader
|
||||
.read_exact(&mut buf)
|
||||
.map_err(Error::Incomplete)?;
|
||||
|
||||
String::from_utf8(buf).map_err(|_| Error::Utf8DecodingError)
|
||||
fn get_byte_array(&mut self, len: usize) -> Result<Cow<'a, [i8]>> {
|
||||
self.reader.read_byte_array(len)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Deserializer<R: NbtReadHelper> {
|
||||
pub struct Deserializer<R> {
|
||||
input: R,
|
||||
tag_to_deserialize_stack: Option<u8>,
|
||||
// Yes, this breaks with recursion. Just an attempt at a sanity check
|
||||
in_list: bool,
|
||||
is_named: bool,
|
||||
}
|
||||
|
||||
impl<R: NbtReadHelper> Deserializer<R> {
|
||||
impl<R> Deserializer<R> {
|
||||
pub const fn new(input: R, is_named: bool) -> Self {
|
||||
Self {
|
||||
input,
|
||||
@ -270,28 +429,46 @@ impl<R: NbtReadHelper> Deserializer<R> {
|
||||
|
||||
/// Deserializes struct using Serde Deserializer from normal NBT
|
||||
pub fn from_bytes<'a, T: Deserialize<'a>>(r: impl Read + Seek) -> Result<T> {
|
||||
let mut deserializer = Deserializer::new(NbtReadHelperJava::new(r), true);
|
||||
let mut deserializer = Deserializer::new(NbtReadHelperJava::new(NbtStreamReader(r)), true);
|
||||
T::deserialize(&mut deserializer)
|
||||
}
|
||||
|
||||
/// Deserializes struct using Serde Deserializer from network NBT
|
||||
pub fn from_bytes_unnamed<'a, T: Deserialize<'a>>(r: impl Read + Seek) -> Result<T> {
|
||||
let mut deserializer = Deserializer::new(NbtReadHelperJava::new(r), false);
|
||||
let mut deserializer = Deserializer::new(NbtReadHelperJava::new(NbtStreamReader(r)), false);
|
||||
T::deserialize(&mut deserializer)
|
||||
}
|
||||
|
||||
/// Deserializes struct using Serde Deserializer from Bedrock network NBT
|
||||
pub fn from_bytes_bedrock<'a, T: Deserialize<'a>>(r: impl Read + Seek) -> Result<T> {
|
||||
let mut deserializer = Deserializer::new(NbtReadHelperBedrock::new(r), true);
|
||||
let mut deserializer = Deserializer::new(NbtReadHelperBedrock::new(NbtStreamReader(r)), true);
|
||||
T::deserialize(&mut deserializer)
|
||||
}
|
||||
|
||||
impl<'de, R: NbtReadHelper> de::Deserializer<'de> for &mut Deserializer<R> {
|
||||
/// Deserializes struct using Serde Deserializer from a normal NBT slice (zero-allocation)
|
||||
pub fn from_slice<'a, T: Deserialize<'a>>(slice: &'a [u8]) -> Result<T> {
|
||||
let mut deserializer = Deserializer::new(NbtReadHelperJava::new(Cursor::new(slice)), true);
|
||||
T::deserialize(&mut deserializer)
|
||||
}
|
||||
|
||||
/// Deserializes struct using Serde Deserializer from a network NBT slice (zero-allocation)
|
||||
pub fn from_slice_unnamed<'a, T: Deserialize<'a>>(slice: &'a [u8]) -> Result<T> {
|
||||
let mut deserializer = Deserializer::new(NbtReadHelperJava::new(Cursor::new(slice)), false);
|
||||
T::deserialize(&mut deserializer)
|
||||
}
|
||||
|
||||
/// Deserializes struct using Serde Deserializer from a Bedrock network NBT slice (zero-allocation)
|
||||
pub fn from_slice_bedrock<'a, T: Deserialize<'a>>(slice: &'a [u8]) -> Result<T> {
|
||||
let mut deserializer = Deserializer::new(NbtReadHelperBedrock::new(Cursor::new(slice)), true);
|
||||
T::deserialize(&mut deserializer)
|
||||
}
|
||||
|
||||
impl<'de, R: NbtReadHelper<'de>> de::Deserializer<'de> for &mut Deserializer<R> {
|
||||
type Error = Error;
|
||||
|
||||
forward_to_deserialize_any! {
|
||||
i8 i16 i32 i64 f32 f64 char str string unit unit_struct seq tuple tuple_struct
|
||||
bytes newtype_struct byte_buf
|
||||
i8 i16 i32 i64 f32 f64 char unit unit_struct seq tuple tuple_struct
|
||||
newtype_struct byte_buf
|
||||
}
|
||||
|
||||
fn deserialize_ignored_any<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
|
||||
@ -334,8 +511,6 @@ impl<'de, R: NbtReadHelper> de::Deserializer<'de> for &mut Deserializer<R> {
|
||||
return Err(Error::LargeLength(remaining_values));
|
||||
}
|
||||
|
||||
//TODO this is a bit hacky but I couldn't think of a better way
|
||||
// This flag gets auto cleared in visit_seq
|
||||
set_curr_visitor_seq_list_id(Some(list_type));
|
||||
let result = visitor.visit_seq(ListAccess {
|
||||
de: self,
|
||||
@ -353,7 +528,7 @@ impl<'de, R: NbtReadHelper> de::Deserializer<'de> for &mut Deserializer<R> {
|
||||
NbtTag::Long(value) => visitor.visit_i64::<Error>(value)?,
|
||||
NbtTag::Float(value) => visitor.visit_f32::<Error>(value)?,
|
||||
NbtTag::Double(value) => visitor.visit_f64::<Error>(value)?,
|
||||
NbtTag::String(value) => visitor.visit_string::<Error>(value.into())?,
|
||||
NbtTag::String(value) => visitor.visit_string::<Error>(value.into_string())?,
|
||||
_ => return Err(Error::SerdeError("Unreachable state reached".to_string())),
|
||||
};
|
||||
Ok(result)
|
||||
@ -378,13 +553,11 @@ impl<'de, R: NbtReadHelper> de::Deserializer<'de> for &mut Deserializer<R> {
|
||||
}
|
||||
|
||||
fn deserialize_u32<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
|
||||
// ZigZag might make this a problem for Bedrock...
|
||||
let value = self.input.get_i32()?;
|
||||
visitor.visit_i32::<Error>(value)
|
||||
}
|
||||
|
||||
fn deserialize_u64<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
|
||||
// ZigZag might make this a problem for Bedrock...
|
||||
let value = self.input.get_i64()?;
|
||||
visitor.visit_i64::<Error>(value)
|
||||
}
|
||||
@ -399,18 +572,49 @@ impl<'de, R: NbtReadHelper> de::Deserializer<'de> for &mut Deserializer<R> {
|
||||
visitor.visit_bool(false)
|
||||
}
|
||||
|
||||
fn deserialize_str<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
|
||||
match self.input.get_string()? {
|
||||
Cow::Borrowed(s) => visitor.visit_borrowed_str(s),
|
||||
Cow::Owned(s) => visitor.visit_string(s),
|
||||
}
|
||||
}
|
||||
|
||||
fn deserialize_string<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
|
||||
self.deserialize_str(visitor)
|
||||
}
|
||||
|
||||
fn deserialize_bytes<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
|
||||
let tag_id = self.tag_to_deserialize_stack.unwrap_or(BYTE_ARRAY_ID);
|
||||
if tag_id == BYTE_ARRAY_ID {
|
||||
let len = self.input.get_i32()?;
|
||||
if len < 0 {
|
||||
return Err(Error::NegativeLength(len));
|
||||
}
|
||||
let slice = self.input.get_byte_array(len as usize)?;
|
||||
let u8_slice: &'de [u8] =
|
||||
unsafe { std::slice::from_raw_parts(slice.as_ptr().cast::<u8>(), slice.len()) };
|
||||
match slice {
|
||||
Cow::Borrowed(_) => visitor.visit_borrowed_bytes(u8_slice),
|
||||
Cow::Owned(_) => visitor.visit_bytes(u8_slice),
|
||||
}
|
||||
} else {
|
||||
self.deserialize_any(visitor)
|
||||
}
|
||||
}
|
||||
|
||||
fn deserialize_enum<V: Visitor<'de>>(
|
||||
self,
|
||||
_name: &'static str,
|
||||
_variants: &'static [&'static str],
|
||||
visitor: V,
|
||||
) -> Result<V::Value> {
|
||||
let variant = self.input.get_string()?;
|
||||
visitor.visit_enum(variant.into_deserializer())
|
||||
match self.input.get_string()? {
|
||||
Cow::Borrowed(s) => visitor.visit_enum(s.into_deserializer()),
|
||||
Cow::Owned(s) => visitor.visit_enum(s.into_deserializer()),
|
||||
}
|
||||
}
|
||||
|
||||
fn deserialize_option<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
|
||||
// None is not encoded, so no need for it
|
||||
visitor.visit_some(self)
|
||||
}
|
||||
|
||||
@ -446,8 +650,7 @@ impl<'de, R: NbtReadHelper> de::Deserializer<'de> for &mut Deserializer<R> {
|
||||
}
|
||||
|
||||
fn deserialize_identifier<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
|
||||
let str = self.input.get_string()?;
|
||||
visitor.visit_string(str)
|
||||
self.deserialize_str(visitor)
|
||||
}
|
||||
|
||||
fn is_human_readable(&self) -> bool {
|
||||
@ -455,11 +658,11 @@ impl<'de, R: NbtReadHelper> de::Deserializer<'de> for &mut Deserializer<R> {
|
||||
}
|
||||
}
|
||||
|
||||
struct CompoundAccess<'a, R: NbtReadHelper> {
|
||||
struct CompoundAccess<'a, R> {
|
||||
de: &'a mut Deserializer<R>,
|
||||
}
|
||||
|
||||
impl<'de, R: NbtReadHelper> MapAccess<'de> for CompoundAccess<'_, R> {
|
||||
impl<'de, R: NbtReadHelper<'de>> MapAccess<'de> for CompoundAccess<'_, R> {
|
||||
type Error = Error;
|
||||
|
||||
fn next_key_seed<K: DeserializeSeed<'de>>(&mut self, seed: K) -> Result<Option<K::Value>> {
|
||||
@ -478,16 +681,18 @@ impl<'de, R: NbtReadHelper> MapAccess<'de> for CompoundAccess<'_, R> {
|
||||
}
|
||||
}
|
||||
|
||||
struct MapKey<'a, R: NbtReadHelper> {
|
||||
struct MapKey<'a, R> {
|
||||
de: &'a mut Deserializer<R>,
|
||||
}
|
||||
|
||||
impl<'de, R: NbtReadHelper> de::Deserializer<'de> for MapKey<'_, R> {
|
||||
impl<'de, R: NbtReadHelper<'de>> de::Deserializer<'de> for MapKey<'_, R> {
|
||||
type Error = Error;
|
||||
|
||||
fn deserialize_any<V: Visitor<'de>>(self, visitor: V) -> Result<V::Value> {
|
||||
let key = self.de.input.get_string()?;
|
||||
visitor.visit_string(key)
|
||||
match self.de.input.get_string()? {
|
||||
Cow::Borrowed(s) => visitor.visit_borrowed_str(s),
|
||||
Cow::Owned(s) => visitor.visit_string(s),
|
||||
}
|
||||
}
|
||||
|
||||
forward_to_deserialize_any! {
|
||||
@ -496,13 +701,13 @@ impl<'de, R: NbtReadHelper> de::Deserializer<'de> for MapKey<'_, R> {
|
||||
}
|
||||
}
|
||||
|
||||
struct ListAccess<'a, R: NbtReadHelper> {
|
||||
struct ListAccess<'a, R> {
|
||||
de: &'a mut Deserializer<R>,
|
||||
remaining_values: usize,
|
||||
list_type: u8,
|
||||
}
|
||||
|
||||
impl<'de, R: NbtReadHelper> SeqAccess<'de> for ListAccess<'_, R> {
|
||||
impl<'de, R: NbtReadHelper<'de>> SeqAccess<'de> for ListAccess<'_, R> {
|
||||
type Error = Error;
|
||||
|
||||
fn size_hint(&self) -> Option<usize> {
|
||||
|
||||
@ -19,7 +19,10 @@ pub mod serializer;
|
||||
pub mod tag;
|
||||
|
||||
pub use compound::NbtCompound;
|
||||
pub use deserializer::{from_bytes, from_bytes_unnamed};
|
||||
pub use deserializer::{
|
||||
from_bytes, from_bytes_bedrock, from_bytes_unnamed, from_slice, from_slice_bedrock,
|
||||
from_slice_unnamed,
|
||||
};
|
||||
pub use serializer::{to_bytes, to_bytes_named, to_bytes_unnamed};
|
||||
|
||||
// This NBT crate is inspired from CrabNBT
|
||||
@ -93,7 +96,7 @@ impl Nbt {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn read<R: NbtReadHelper>(reader: &mut R) -> Result<Self, Error> {
|
||||
pub fn read<'a, R: NbtReadHelper<'a>>(reader: &mut R) -> Result<Self, Error> {
|
||||
let tag_type_id = reader.get_u8()?;
|
||||
|
||||
if tag_type_id != COMPOUND_ID {
|
||||
@ -101,13 +104,13 @@ impl Nbt {
|
||||
}
|
||||
|
||||
Ok(Self {
|
||||
name: reader.get_string()?,
|
||||
name: reader.get_string()?.into_owned(),
|
||||
root_tag: NbtCompound::deserialize_content(reader)?,
|
||||
})
|
||||
}
|
||||
|
||||
/// Reads an NBT tag that doesn't contain the name of the root `Compound`.
|
||||
pub fn read_unnamed<R: NbtReadHelper>(reader: &mut R) -> Result<Self, Error> {
|
||||
pub fn read_unnamed<'a, R: NbtReadHelper<'a>>(reader: &mut R) -> Result<Self, Error> {
|
||||
let tag_type_id = reader.get_u8()?;
|
||||
|
||||
if tag_type_id != COMPOUND_ID {
|
||||
@ -256,6 +259,31 @@ mod test {
|
||||
string: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, PartialEq, Debug)]
|
||||
struct BorrowedTest<'a> {
|
||||
byte: i8,
|
||||
string: &'a str,
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn zero_alloc_from_slice() {
|
||||
let test = Test {
|
||||
byte: 123,
|
||||
short: 1342,
|
||||
int: 4313,
|
||||
long: 34,
|
||||
float: 1.00,
|
||||
string: "Zero alloc NBT".to_string(),
|
||||
};
|
||||
|
||||
let mut bytes = Vec::new();
|
||||
to_bytes_unnamed(&test, &mut bytes).unwrap();
|
||||
let borrowed: BorrowedTest = crate::from_slice_unnamed(&bytes).unwrap();
|
||||
|
||||
assert_eq!(borrowed.byte, 123);
|
||||
assert_eq!(borrowed.string, "Zero alloc NBT");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn simple_ser_de_unnamed() {
|
||||
let test = Test {
|
||||
|
||||
@ -175,12 +175,12 @@ impl NbtTag {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn deserialize<R: NbtReadHelper>(reader: &mut R) -> Result<Self, Error> {
|
||||
pub fn deserialize<'a, R: NbtReadHelper<'a>>(reader: &mut R) -> Result<Self, Error> {
|
||||
let tag_id = reader.get_u8()?;
|
||||
Self::deserialize_data(reader, tag_id)
|
||||
}
|
||||
|
||||
pub fn skip_data<R: NbtReadHelper>(reader: &mut R, tag_id: u8) -> Result<(), Error> {
|
||||
pub fn skip_data<'a, R: NbtReadHelper<'a>>(reader: &mut R, tag_id: u8) -> Result<(), Error> {
|
||||
match tag_id {
|
||||
END_ID => Ok(()),
|
||||
BYTE_ID => reader.skip_i8(),
|
||||
@ -239,7 +239,10 @@ impl NbtTag {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn deserialize_data<R: NbtReadHelper>(reader: &mut R, tag_id: u8) -> Result<Self, Error> {
|
||||
pub fn deserialize_data<'a, R: NbtReadHelper<'a>>(
|
||||
reader: &mut R,
|
||||
tag_id: u8,
|
||||
) -> Result<Self, Error> {
|
||||
match tag_id {
|
||||
END_ID => Ok(Self::End),
|
||||
BYTE_ID => {
|
||||
@ -283,7 +286,7 @@ impl NbtTag {
|
||||
}
|
||||
Ok(Self::ByteArray(byte_array.into()))
|
||||
}
|
||||
STRING_ID => Ok(Self::String(reader.get_string()?.into())),
|
||||
STRING_ID => Ok(Self::String(reader.get_string()?.into_owned().into())),
|
||||
LIST_ID => {
|
||||
let tag_type_id = reader.get_u8()?;
|
||||
let len = reader.get_i32()?;
|
||||
|
||||
@ -1,19 +1,60 @@
|
||||
use pumpkin_macros::packet;
|
||||
use std::borrow::Cow;
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::serial::PacketRead;
|
||||
use crate::serial::{PacketRead, PacketReadSlice, read_str_slice};
|
||||
|
||||
#[derive(Debug, PacketRead)]
|
||||
#[derive(Debug)]
|
||||
#[packet(77)]
|
||||
pub struct SCommandRequest {
|
||||
pub command: String,
|
||||
|
||||
// Command Origin
|
||||
pub command_type: String,
|
||||
pub struct SCommandRequest<'a> {
|
||||
pub command: Cow<'a, str>,
|
||||
pub command_type: Cow<'a, str>,
|
||||
pub command_uuid: Uuid,
|
||||
pub request_id: String,
|
||||
pub request_id: Cow<'a, str>,
|
||||
pub player_actor_unique_id: i64,
|
||||
|
||||
pub is_internal_source: bool,
|
||||
pub version: String,
|
||||
pub version: Cow<'a, str>,
|
||||
}
|
||||
|
||||
impl<'a> PacketReadSlice<'a> for SCommandRequest<'a> {
|
||||
fn read_slice(buf: &mut &'a [u8]) -> Result<Self, std::io::Error> {
|
||||
let command = Cow::Borrowed(read_str_slice(buf)?);
|
||||
let command_type = Cow::Borrowed(read_str_slice(buf)?);
|
||||
let command_uuid = Uuid::read_slice(buf)?;
|
||||
let request_id = Cow::Borrowed(read_str_slice(buf)?);
|
||||
let player_actor_unique_id = i64::read_slice(buf)?;
|
||||
let is_internal_source = bool::read_slice(buf)?;
|
||||
let version = Cow::Borrowed(read_str_slice(buf)?);
|
||||
Ok(Self {
|
||||
command,
|
||||
command_type,
|
||||
command_uuid,
|
||||
request_id,
|
||||
player_actor_unique_id,
|
||||
is_internal_source,
|
||||
version,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl PacketRead for SCommandRequest<'static> {
|
||||
fn read<R: std::io::Read>(reader: &mut R) -> Result<Self, std::io::Error> {
|
||||
let command = Cow::Owned(String::read(reader)?);
|
||||
let command_type = Cow::Owned(String::read(reader)?);
|
||||
let command_uuid = Uuid::read(reader)?;
|
||||
let request_id = Cow::Owned(String::read(reader)?);
|
||||
let player_actor_unique_id = i64::read(reader)?;
|
||||
let is_internal_source = bool::read(reader)?;
|
||||
let version = Cow::Owned(String::read(reader)?);
|
||||
|
||||
Ok(Self {
|
||||
command,
|
||||
command_type,
|
||||
command_uuid,
|
||||
request_id,
|
||||
player_actor_unique_id,
|
||||
is_internal_source,
|
||||
version,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,17 +1,62 @@
|
||||
use crate::codec::var_ulong::VarULong;
|
||||
use crate::serial::{PacketRead, PacketWrite};
|
||||
use crate::serial::{PacketRead, PacketReadSlice, PacketWrite, read_str_slice};
|
||||
use pumpkin_macros::packet;
|
||||
use std::borrow::Cow;
|
||||
use std::io::{Error, Write};
|
||||
|
||||
pub const EMOTE_FLAG_SERVER_SIDE: u8 = 1 << 0;
|
||||
pub const EMOTE_FLAG_MUTE_CHAT: u8 = 1 << 1;
|
||||
|
||||
#[derive(PacketRead, PacketWrite, Debug)]
|
||||
#[derive(Debug)]
|
||||
#[packet(138)]
|
||||
pub struct SEmote {
|
||||
pub struct SEmote<'a> {
|
||||
pub runtime_entity_id: VarULong,
|
||||
pub emote_id: String,
|
||||
pub emote_id: Cow<'a, str>,
|
||||
pub emote_length: u32,
|
||||
pub xuid: String,
|
||||
pub platform_id: String,
|
||||
pub xuid: Cow<'a, str>,
|
||||
pub platform_id: Cow<'a, str>,
|
||||
pub flags: u8,
|
||||
}
|
||||
|
||||
impl<'a> PacketReadSlice<'a> for SEmote<'a> {
|
||||
fn read_slice(buf: &mut &'a [u8]) -> Result<Self, Error> {
|
||||
let runtime_entity_id = VarULong::read_slice(buf)?;
|
||||
let emote_id = Cow::Borrowed(read_str_slice(buf)?);
|
||||
let emote_length = u32::read_slice(buf)?;
|
||||
let xuid = Cow::Borrowed(read_str_slice(buf)?);
|
||||
let platform_id = Cow::Borrowed(read_str_slice(buf)?);
|
||||
let flags = u8::read_slice(buf)?;
|
||||
Ok(Self {
|
||||
runtime_entity_id,
|
||||
emote_id,
|
||||
emote_length,
|
||||
xuid,
|
||||
platform_id,
|
||||
flags,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl PacketRead for SEmote<'static> {
|
||||
fn read<R: std::io::Read>(reader: &mut R) -> Result<Self, Error> {
|
||||
Ok(Self {
|
||||
runtime_entity_id: VarULong::read(reader)?,
|
||||
emote_id: Cow::Owned(String::read(reader)?),
|
||||
emote_length: u32::read(reader)?,
|
||||
xuid: Cow::Owned(String::read(reader)?),
|
||||
platform_id: Cow::Owned(String::read(reader)?),
|
||||
flags: u8::read(reader)?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl PacketWrite for SEmote<'_> {
|
||||
fn write<W: Write>(&self, writer: &mut W) -> Result<(), Error> {
|
||||
self.runtime_entity_id.write(writer)?;
|
||||
self.emote_id.as_ref().write(writer)?;
|
||||
self.emote_length.write(writer)?;
|
||||
self.xuid.as_ref().write(writer)?;
|
||||
self.platform_id.as_ref().write(writer)?;
|
||||
self.flags.write(writer)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,18 +1,30 @@
|
||||
use crate::codec::var_int::VarInt;
|
||||
use crate::serial::PacketRead;
|
||||
use crate::serial::{PacketRead, PacketReadSlice, read_str_slice};
|
||||
use pumpkin_macros::packet;
|
||||
use std::borrow::Cow;
|
||||
use std::io::{Error, Read};
|
||||
|
||||
#[derive(Debug)]
|
||||
#[packet(101)]
|
||||
pub struct SModalFormResponse {
|
||||
pub struct SModalFormResponse<'a> {
|
||||
pub form_id: VarInt,
|
||||
pub form_data: Option<String>,
|
||||
pub form_data: Option<Cow<'a, str>>,
|
||||
}
|
||||
|
||||
impl PacketRead for SModalFormResponse {
|
||||
fn read<R: Read>(reader: &mut R) -> Result<Self, Error> {
|
||||
let form_id = VarInt::read(reader)?;
|
||||
let form_data = Option::<String>::read(reader)?;
|
||||
impl<'a> PacketReadSlice<'a> for SModalFormResponse<'a> {
|
||||
fn read_slice(buf: &mut &'a [u8]) -> Result<Self, Error> {
|
||||
let form_id = VarInt::read_slice(buf)?;
|
||||
let form_data = bool::read_slice(buf)?
|
||||
.then(|| read_str_slice(buf).map(Cow::Borrowed))
|
||||
.transpose()?;
|
||||
Ok(Self { form_id, form_data })
|
||||
}
|
||||
}
|
||||
|
||||
impl PacketRead for SModalFormResponse<'static> {
|
||||
fn read<R: Read>(reader: &mut R) -> Result<Self, Error> {
|
||||
let form_id = VarInt::read(reader)?;
|
||||
let form_data = Option::<String>::read(reader)?.map(Cow::Owned);
|
||||
Ok(Self { form_id, form_data })
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,52 +1,70 @@
|
||||
use crate::{
|
||||
codec::var_uint::VarUInt,
|
||||
serial::{PacketRead, PacketWrite},
|
||||
serial::{PacketRead, PacketReadSlice, PacketWrite, read_str_slice},
|
||||
};
|
||||
use pumpkin_macros::packet;
|
||||
use std::borrow::Cow;
|
||||
use std::io::{Error, ErrorKind, Read, Write};
|
||||
|
||||
#[derive(Debug)]
|
||||
#[packet(9)]
|
||||
pub struct SText {
|
||||
pub struct SText<'a> {
|
||||
pub needs_translation: bool,
|
||||
pub r#type: TextPacketType,
|
||||
pub source_name: String,
|
||||
pub message: String,
|
||||
pub parameters: Vec<String>,
|
||||
pub xuid: String,
|
||||
pub platform_chat_id: String,
|
||||
pub filtered_message: Option<String>,
|
||||
pub source_name: Cow<'a, str>,
|
||||
pub message: Cow<'a, str>,
|
||||
pub parameters: Vec<Cow<'a, str>>,
|
||||
pub xuid: Cow<'a, str>,
|
||||
pub platform_chat_id: Cow<'a, str>,
|
||||
pub filtered_message: Option<Cow<'a, str>>,
|
||||
}
|
||||
|
||||
impl SText {
|
||||
impl SText<'_> {
|
||||
const fn get_category(&self) -> u8 {
|
||||
match self.r#type {
|
||||
TextPacketType::Raw
|
||||
| TextPacketType::Tip
|
||||
| TextPacketType::System
|
||||
| TextPacketType::JsonWhisper
|
||||
| TextPacketType::JsonAnnouncement
|
||||
| TextPacketType::Json => 0,
|
||||
|
||||
TextPacketType::Chat | TextPacketType::Whisper | TextPacketType::Announcement => 1,
|
||||
|
||||
TextPacketType::Translation | TextPacketType::Popup | TextPacketType::JukeboxPopup => 2,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl SText<'static> {
|
||||
#[must_use]
|
||||
pub fn new(message: String, source_name: String) -> Self {
|
||||
Self {
|
||||
needs_translation: false,
|
||||
r#type: TextPacketType::Chat,
|
||||
source_name,
|
||||
message: if message.is_empty() {
|
||||
source_name: Cow::Owned(source_name),
|
||||
message: Cow::Owned(if message.is_empty() {
|
||||
" ".to_string()
|
||||
} else {
|
||||
message
|
||||
},
|
||||
}),
|
||||
parameters: Vec::new(),
|
||||
xuid: String::new(),
|
||||
platform_chat_id: String::new(),
|
||||
xuid: Cow::Borrowed(""),
|
||||
platform_chat_id: Cow::Borrowed(""),
|
||||
filtered_message: None,
|
||||
}
|
||||
}
|
||||
|
||||
#[must_use]
|
||||
pub const fn translation(message: String, parameters: Vec<String>) -> Self {
|
||||
pub fn translation(message: String, parameters: Vec<String>) -> Self {
|
||||
Self {
|
||||
needs_translation: true,
|
||||
r#type: TextPacketType::Translation,
|
||||
source_name: String::new(),
|
||||
message,
|
||||
parameters,
|
||||
xuid: String::new(),
|
||||
platform_chat_id: String::new(),
|
||||
source_name: Cow::Borrowed(""),
|
||||
message: Cow::Owned(message),
|
||||
parameters: parameters.into_iter().map(Cow::Owned).collect(),
|
||||
xuid: Cow::Borrowed(""),
|
||||
platform_chat_id: Cow::Borrowed(""),
|
||||
filtered_message: None,
|
||||
}
|
||||
}
|
||||
@ -56,15 +74,15 @@ impl SText {
|
||||
Self {
|
||||
needs_translation: false,
|
||||
r#type: TextPacketType::System,
|
||||
source_name: String::new(),
|
||||
message: if message.is_empty() {
|
||||
source_name: Cow::Borrowed(""),
|
||||
message: Cow::Owned(if message.is_empty() {
|
||||
" ".to_string()
|
||||
} else {
|
||||
message
|
||||
},
|
||||
}),
|
||||
parameters: Vec::new(),
|
||||
xuid: String::new(),
|
||||
platform_chat_id: String::new(),
|
||||
xuid: Cow::Borrowed(""),
|
||||
platform_chat_id: Cow::Borrowed(""),
|
||||
filtered_message: None,
|
||||
}
|
||||
}
|
||||
@ -74,37 +92,72 @@ impl SText {
|
||||
Self {
|
||||
needs_translation: false,
|
||||
r#type: TextPacketType::Json,
|
||||
source_name: String::new(),
|
||||
message,
|
||||
source_name: Cow::Borrowed(""),
|
||||
message: Cow::Owned(message),
|
||||
parameters: Vec::new(),
|
||||
xuid: String::new(),
|
||||
platform_chat_id: String::new(),
|
||||
xuid: Cow::Borrowed(""),
|
||||
platform_chat_id: Cow::Borrowed(""),
|
||||
filtered_message: None,
|
||||
}
|
||||
}
|
||||
|
||||
const fn get_category(&self) -> u8 {
|
||||
match self.r#type {
|
||||
TextPacketType::Raw
|
||||
| TextPacketType::Tip
|
||||
| TextPacketType::System
|
||||
| TextPacketType::JsonWhisper
|
||||
| TextPacketType::JsonAnnouncement
|
||||
| TextPacketType::Json => 0, // CATEGORY_MESSAGE_ONLY
|
||||
|
||||
TextPacketType::Chat | TextPacketType::Whisper | TextPacketType::Announcement => 1, // CATEGORY_AUTHORED_MESSAGE
|
||||
|
||||
TextPacketType::Translation | TextPacketType::Popup | TextPacketType::JukeboxPopup => 2, // CATEGORY_MESSAGE_WITH_PARAMETERS
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PacketRead for SText {
|
||||
impl<'a> PacketReadSlice<'a> for SText<'a> {
|
||||
fn read_slice(buf: &mut &'a [u8]) -> Result<Self, Error> {
|
||||
let needs_translation = bool::read_slice(buf)?;
|
||||
let _category = u8::read_slice(buf)?;
|
||||
let r#type = TextPacketType::read_slice(buf)?;
|
||||
|
||||
let mut source_name = "";
|
||||
let message;
|
||||
let mut parameters: Vec<Cow<'a, str>> = Vec::new();
|
||||
|
||||
match r#type {
|
||||
TextPacketType::Chat | TextPacketType::Whisper | TextPacketType::Announcement => {
|
||||
source_name = read_str_slice(buf)?;
|
||||
message = read_str_slice(buf)?;
|
||||
}
|
||||
TextPacketType::Raw
|
||||
| TextPacketType::Tip
|
||||
| TextPacketType::System
|
||||
| TextPacketType::JsonWhisper
|
||||
| TextPacketType::Json
|
||||
| TextPacketType::JsonAnnouncement => {
|
||||
message = read_str_slice(buf)?;
|
||||
}
|
||||
TextPacketType::Translation | TextPacketType::Popup | TextPacketType::JukeboxPopup => {
|
||||
message = read_str_slice(buf)?;
|
||||
let count = VarUInt::read_slice(buf)?.0 as usize;
|
||||
for _ in 0..count {
|
||||
parameters.push(Cow::Borrowed(read_str_slice(buf)?));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let xuid = read_str_slice(buf)?;
|
||||
let platform_chat_id = read_str_slice(buf)?;
|
||||
|
||||
let filtered_message = bool::read_slice(buf)?
|
||||
.then(|| read_str_slice(buf).map(Cow::Borrowed))
|
||||
.transpose()?;
|
||||
|
||||
Ok(Self {
|
||||
needs_translation,
|
||||
r#type,
|
||||
source_name: Cow::Borrowed(source_name),
|
||||
message: Cow::Borrowed(message),
|
||||
parameters,
|
||||
xuid: Cow::Borrowed(xuid),
|
||||
platform_chat_id: Cow::Borrowed(platform_chat_id),
|
||||
filtered_message,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl PacketRead for SText<'static> {
|
||||
fn read<R: Read>(reader: &mut R) -> Result<Self, Error> {
|
||||
let needs_translation = bool::read(reader)?;
|
||||
|
||||
let _category = u8::read(reader)?;
|
||||
|
||||
let r#type = TextPacketType::read(reader)?;
|
||||
|
||||
let mut source_name = String::new();
|
||||
@ -129,7 +182,7 @@ impl PacketRead for SText {
|
||||
message = String::read(reader)?;
|
||||
let count = VarUInt::read(reader)?.0 as usize;
|
||||
for _ in 0..count {
|
||||
parameters.push(String::read(reader)?);
|
||||
parameters.push(Cow::Owned(String::read(reader)?));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -138,23 +191,23 @@ impl PacketRead for SText {
|
||||
let platform_chat_id = String::read(reader)?;
|
||||
|
||||
let filtered_message = bool::read(reader)?
|
||||
.then(|| String::read(reader))
|
||||
.then(|| String::read(reader).map(Cow::Owned))
|
||||
.transpose()?;
|
||||
|
||||
Ok(Self {
|
||||
needs_translation,
|
||||
r#type,
|
||||
source_name,
|
||||
message,
|
||||
source_name: Cow::Owned(source_name),
|
||||
message: Cow::Owned(message),
|
||||
parameters,
|
||||
xuid,
|
||||
platform_chat_id,
|
||||
xuid: Cow::Owned(xuid),
|
||||
platform_chat_id: Cow::Owned(platform_chat_id),
|
||||
filtered_message,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl PacketWrite for SText {
|
||||
impl PacketWrite for SText<'_> {
|
||||
fn write<W: Write>(&self, writer: &mut W) -> Result<(), Error> {
|
||||
self.needs_translation.write(writer)?;
|
||||
|
||||
@ -165,8 +218,8 @@ impl PacketWrite for SText {
|
||||
|
||||
match self.r#type {
|
||||
TextPacketType::Chat | TextPacketType::Whisper | TextPacketType::Announcement => {
|
||||
self.source_name.write(writer)?;
|
||||
self.message.write(writer)?;
|
||||
self.source_name.as_ref().write(writer)?;
|
||||
self.message.as_ref().write(writer)?;
|
||||
}
|
||||
TextPacketType::Raw
|
||||
| TextPacketType::Tip
|
||||
@ -174,23 +227,23 @@ impl PacketWrite for SText {
|
||||
| TextPacketType::JsonWhisper
|
||||
| TextPacketType::Json
|
||||
| TextPacketType::JsonAnnouncement => {
|
||||
self.message.write(writer)?;
|
||||
self.message.as_ref().write(writer)?;
|
||||
}
|
||||
TextPacketType::Translation | TextPacketType::Popup | TextPacketType::JukeboxPopup => {
|
||||
self.message.write(writer)?;
|
||||
self.message.as_ref().write(writer)?;
|
||||
VarUInt(self.parameters.len() as u32).write(writer)?;
|
||||
for param in &self.parameters {
|
||||
param.write(writer)?;
|
||||
param.as_ref().write(writer)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.xuid.write(writer)?;
|
||||
self.platform_chat_id.write(writer)?;
|
||||
self.xuid.as_ref().write(writer)?;
|
||||
self.platform_chat_id.as_ref().write(writer)?;
|
||||
|
||||
if let Some(msg) = &self.filtered_message {
|
||||
true.write(writer)?;
|
||||
msg.write(writer)?;
|
||||
msg.as_ref().write(writer)?;
|
||||
} else {
|
||||
false.write(writer)?;
|
||||
}
|
||||
@ -241,3 +294,23 @@ impl PacketRead for TextPacketType {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> PacketReadSlice<'a> for TextPacketType {
|
||||
fn read_slice(buf: &mut &'a [u8]) -> Result<Self, Error> {
|
||||
match u8::read_slice(buf)? {
|
||||
0 => Ok(Self::Raw),
|
||||
1 => Ok(Self::Chat),
|
||||
2 => Ok(Self::Translation),
|
||||
3 => Ok(Self::Popup),
|
||||
4 => Ok(Self::JukeboxPopup),
|
||||
5 => Ok(Self::Tip),
|
||||
6 => Ok(Self::System),
|
||||
7 => Ok(Self::Whisper),
|
||||
8 => Ok(Self::Announcement),
|
||||
9 => Ok(Self::JsonWhisper),
|
||||
10 => Ok(Self::Json),
|
||||
11 => Ok(Self::JsonAnnouncement),
|
||||
_ => Err(Error::new(ErrorKind::InvalidData, "Unknown Text Type")),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -106,16 +106,30 @@ fn read_length_prefixed_component(
|
||||
) -> Result<(DataComponent, Box<dyn DataComponentImpl>), ReadingError> {
|
||||
let id = read_component_id(read)?;
|
||||
let byte_len = read.get_var_int()?.0;
|
||||
let byte_len = byte_len
|
||||
let byte_len: usize = byte_len
|
||||
.try_into()
|
||||
.map_err(|_| ReadingError::Message("Negative component data length".into()))?;
|
||||
let component_data = read.read_boxed_slice(byte_len)?;
|
||||
|
||||
let component_impl = if id == DataComponent::CustomName {
|
||||
decode_custom_name(component_data.as_ref())?
|
||||
let component_impl = if byte_len <= 256 {
|
||||
let mut stack_buf = [0u8; 256];
|
||||
let slice = &mut stack_buf[..byte_len];
|
||||
read.read_bytes_to_buf(slice)?;
|
||||
|
||||
if id == DataComponent::CustomName {
|
||||
decode_custom_name(slice)?
|
||||
} else {
|
||||
let mut cursor = Cursor::new(slice);
|
||||
deserialize(id, &mut cursor)?
|
||||
}
|
||||
} else {
|
||||
let mut cursor = Cursor::new(component_data);
|
||||
deserialize(id, &mut cursor)?
|
||||
let mut component_data = vec![0u8; byte_len];
|
||||
read.read_bytes_to_buf(&mut component_data)?;
|
||||
if id == DataComponent::CustomName {
|
||||
decode_custom_name(component_data.as_ref())?
|
||||
} else {
|
||||
let mut cursor = Cursor::new(component_data);
|
||||
deserialize(id, &mut cursor)?
|
||||
}
|
||||
};
|
||||
|
||||
Ok((id, component_impl))
|
||||
@ -297,13 +311,11 @@ impl ItemComponentHash {
|
||||
pub fn read(read: &mut impl NetworkReadExt) -> Result<Self, ReadingError> {
|
||||
const MAX_COMPONENTS: i32 = 256;
|
||||
|
||||
let mut added = Vec::new();
|
||||
let mut removed = Vec::new();
|
||||
|
||||
let added_length = read.get_var_int()?;
|
||||
if added_length.0 < 0 || added_length.0 > MAX_COMPONENTS {
|
||||
return Err(ReadingError::Message("added_length out of bounds".into()));
|
||||
}
|
||||
let mut added = Vec::with_capacity(added_length.0 as usize);
|
||||
for _ in 0..added_length.0 {
|
||||
let component_id = read.get_var_int()?;
|
||||
let component_value = read.get_i32()?;
|
||||
@ -314,6 +326,7 @@ impl ItemComponentHash {
|
||||
if removed_length.0 < 0 || removed_length.0 > MAX_COMPONENTS {
|
||||
return Err(ReadingError::Message("removed_length out of bounds".into()));
|
||||
}
|
||||
let mut removed = Vec::with_capacity(removed_length.0 as usize);
|
||||
for _ in 0..removed_length.0 {
|
||||
let component_id = read.get_var_int()?;
|
||||
removed.push(component_id);
|
||||
|
||||
@ -16,12 +16,12 @@ use crate::{
|
||||
/// initializes the player's world view, dimension settings, and local game
|
||||
/// rules. Once received, the client begins rendering the world.
|
||||
#[java_packet(PLAY_LOGIN)]
|
||||
pub struct CLogin {
|
||||
pub struct CLogin<'a> {
|
||||
/// The unique ID assigned to the player for the current session.
|
||||
pub entity_id: i32,
|
||||
pub is_hardcore: bool,
|
||||
/// A list of all dimensions present on the server (e.g., overworld, nether, end).
|
||||
pub dimension_names: Vec<ResourceLocation>,
|
||||
pub dimension_names: &'a [ResourceLocation],
|
||||
pub max_players: VarInt,
|
||||
/// The number of chunks the client will render in each direction.
|
||||
pub view_distance: VarInt,
|
||||
@ -38,14 +38,14 @@ pub struct CLogin {
|
||||
pub enforce_secure_chat: bool,
|
||||
}
|
||||
|
||||
impl CLogin {
|
||||
impl<'a> CLogin<'a> {
|
||||
#[expect(clippy::too_many_arguments)]
|
||||
#[expect(clippy::fn_params_excessive_bools)]
|
||||
#[must_use]
|
||||
pub const fn new(
|
||||
entity_id: i32,
|
||||
is_hardcore: bool,
|
||||
dimension_names: Vec<ResourceLocation>,
|
||||
dimension_names: &'a [ResourceLocation],
|
||||
max_players: VarInt,
|
||||
view_distance: VarInt,
|
||||
simulated_distance: VarInt,
|
||||
@ -73,7 +73,7 @@ impl CLogin {
|
||||
}
|
||||
}
|
||||
|
||||
impl ClientPacket for CLogin {
|
||||
impl ClientPacket for CLogin<'_> {
|
||||
fn write_packet_data(
|
||||
&self,
|
||||
mut write: impl std::io::Write,
|
||||
@ -81,7 +81,7 @@ impl ClientPacket for CLogin {
|
||||
) -> Result<(), WritingError> {
|
||||
write.write_i32_be(self.entity_id)?;
|
||||
write.write_bool(self.is_hardcore)?;
|
||||
write.write_list(&self.dimension_names, |write, dim| write.write_string(dim))?;
|
||||
write.write_list(self.dimension_names, |write, dim| write.write_string(dim))?;
|
||||
write.write_var_int(&self.max_players)?;
|
||||
write.write_var_int(&self.view_distance)?;
|
||||
write.write_var_int(&self.simulated_distance)?;
|
||||
|
||||
@ -84,9 +84,9 @@ impl ClientPacket for CPlayerPosition {
|
||||
}
|
||||
}
|
||||
|
||||
impl ServerPacket for CPlayerPosition {
|
||||
impl<'a> ServerPacket<'a> for CPlayerPosition {
|
||||
fn read(
|
||||
mut read: impl std::io::Read,
|
||||
read: &mut &'a [u8],
|
||||
_version: &JavaMinecraftVersion,
|
||||
) -> Result<Self, crate::ser::ReadingError> {
|
||||
Ok(Self {
|
||||
|
||||
@ -191,7 +191,10 @@ impl<R: AsyncRead + Unpin> TCPNetworkDecoder<R> {
|
||||
}
|
||||
}
|
||||
|
||||
let payload = self.payload_scratch.split().freeze();
|
||||
let payload = self
|
||||
.payload_scratch
|
||||
.split_to(self.payload_scratch.len())
|
||||
.freeze();
|
||||
|
||||
Ok(RawPacket {
|
||||
id: packet_id,
|
||||
@ -456,4 +459,40 @@ mod tests {
|
||||
assert_eq!(raw_packet.payload.as_ref(), payload);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Test decoding multiple packets sequentially to verify capacity is retained for zero allocation
|
||||
#[tokio::test]
|
||||
async fn decode_multiple_packets_zero_allocation() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let packet1 = build_packet(1, b"Hello", false, None, None)?;
|
||||
let packet2 = build_packet(2, b"World", false, None, None)?;
|
||||
|
||||
let mut stream = Vec::new();
|
||||
stream.extend_from_slice(&packet1);
|
||||
stream.extend_from_slice(&packet2);
|
||||
|
||||
let mut decoder = TCPNetworkDecoder::new(stream.as_slice());
|
||||
|
||||
let p1 = decoder.get_raw_packet().await?;
|
||||
assert_eq!(p1.id, 1);
|
||||
assert_eq!(p1.payload.as_ref(), b"Hello");
|
||||
drop(p1);
|
||||
|
||||
let cap_after_p1 = decoder.payload_scratch.capacity();
|
||||
assert!(
|
||||
cap_after_p1 > 0,
|
||||
"Capacity should be allocated after first read"
|
||||
);
|
||||
|
||||
let p2 = decoder.get_raw_packet().await?;
|
||||
assert_eq!(p2.id, 2);
|
||||
assert_eq!(p2.payload.as_ref(), b"World");
|
||||
drop(p2);
|
||||
|
||||
let cap_after_p2 = decoder.payload_scratch.capacity();
|
||||
assert_eq!(
|
||||
cap_after_p2, cap_after_p1,
|
||||
"Buffer capacity should be retained and reused without new heap allocations"
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@ -204,9 +204,6 @@ impl<W: AsyncWrite + Unpin> TCPNetworkEncoder<W> {
|
||||
/// NOTE: This method does not flush. Call [`Self::flush`] to flush buffered data.
|
||||
#[allow(clippy::too_many_lines)]
|
||||
pub async fn write_packet(&mut self, packet_data: Bytes) -> Result<(), PacketEncodeError> {
|
||||
// We need to know the length of the compressed buffer and serde is not async :(
|
||||
// We need to write to a buffer here 😔
|
||||
|
||||
let data_len = packet_data.len();
|
||||
if data_len > MAX_PACKET_DATA_SIZE {
|
||||
return Err(PacketEncodeError::TooLong(data_len));
|
||||
@ -218,14 +215,13 @@ impl<W: AsyncWrite + Unpin> TCPNetworkEncoder<W> {
|
||||
))
|
||||
})?;
|
||||
|
||||
if let Some((compression_threshold, compression_level)) = self.compression {
|
||||
if data_len >= compression_threshold {
|
||||
// Pushed before data:
|
||||
// Length of (Data Length) + length of compressed (Packet ID + Data)
|
||||
// Length of uncompressed (Packet ID + Data)
|
||||
let mut header_buf = [0u8; 10];
|
||||
let mut header_cursor = std::io::Cursor::new(&mut header_buf[..]);
|
||||
|
||||
// TODO: We need the compressed length at the beginning of the packet so we need to write to
|
||||
// buf here :( Is there a magic way to find a compressed length?
|
||||
let payload_to_write: &[u8] = if let Some((compression_threshold, compression_level)) =
|
||||
self.compression
|
||||
{
|
||||
if data_len >= compression_threshold {
|
||||
self.compress_packet_data(packet_data.as_ref(), compression_level)?;
|
||||
debug_assert!(!self.compression_scratch.is_empty());
|
||||
|
||||
@ -245,24 +241,14 @@ impl<W: AsyncWrite + Unpin> TCPNetworkEncoder<W> {
|
||||
}
|
||||
|
||||
full_packet_len_var_int
|
||||
.encode_async(self.writer.as_mut().unwrap())
|
||||
.await
|
||||
.encode(&mut header_cursor)
|
||||
.map_err(|err| PacketEncodeError::Message(err.to_string()))?;
|
||||
data_len_var_int
|
||||
.encode_async(self.writer.as_mut().unwrap())
|
||||
.await
|
||||
.encode(&mut header_cursor)
|
||||
.map_err(|err| PacketEncodeError::Message(err.to_string()))?;
|
||||
self.writer
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.write_all(&self.compression_scratch)
|
||||
.await
|
||||
.map_err(|err| PacketEncodeError::Message(err.to_string()))?;
|
||||
} else {
|
||||
// Pushed before data:
|
||||
// Length of (Data Length) + length of compressed (Packet ID + Data)
|
||||
// 0 to indicate uncompressed
|
||||
|
||||
self.compression_scratch.as_slice()
|
||||
} else {
|
||||
let data_len_var_int: VarInt = 0.into();
|
||||
let full_packet_len_var_int: VarInt = (data_len_var_int.written_size() + data_len)
|
||||
.try_into()
|
||||
@ -279,24 +265,15 @@ impl<W: AsyncWrite + Unpin> TCPNetworkEncoder<W> {
|
||||
}
|
||||
|
||||
full_packet_len_var_int
|
||||
.encode_async(self.writer.as_mut().unwrap())
|
||||
.await
|
||||
.encode(&mut header_cursor)
|
||||
.map_err(|err| PacketEncodeError::Message(err.to_string()))?;
|
||||
data_len_var_int
|
||||
.encode_async(self.writer.as_mut().unwrap())
|
||||
.await
|
||||
.map_err(|err| PacketEncodeError::Message(err.to_string()))?;
|
||||
self.writer
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.write_all(&packet_data)
|
||||
.await
|
||||
.encode(&mut header_cursor)
|
||||
.map_err(|err| PacketEncodeError::Message(err.to_string()))?;
|
||||
|
||||
packet_data.as_ref()
|
||||
}
|
||||
} else {
|
||||
// Pushed before data:
|
||||
// Length of Packet ID + Data
|
||||
|
||||
let full_packet_len_var_int: VarInt = data_len_var_int;
|
||||
|
||||
let complete_serialization_length =
|
||||
@ -306,16 +283,27 @@ impl<W: AsyncWrite + Unpin> TCPNetworkEncoder<W> {
|
||||
}
|
||||
|
||||
full_packet_len_var_int
|
||||
.encode_async(self.writer.as_mut().unwrap())
|
||||
.await
|
||||
.encode(&mut header_cursor)
|
||||
.map_err(|err| PacketEncodeError::Message(err.to_string()))?;
|
||||
self.writer
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.write_all(&packet_data)
|
||||
.await
|
||||
.map_err(|err| PacketEncodeError::Message(err.to_string()))?;
|
||||
}
|
||||
|
||||
packet_data.as_ref()
|
||||
};
|
||||
|
||||
let header_len = header_cursor.position() as usize;
|
||||
let header_bytes = &header_buf[..header_len];
|
||||
let writer = self
|
||||
.writer
|
||||
.as_mut()
|
||||
.ok_or_else(|| PacketEncodeError::Message("Writer missing".into()))?;
|
||||
|
||||
writer
|
||||
.write_all(header_bytes)
|
||||
.await
|
||||
.map_err(|err| PacketEncodeError::Message(err.to_string()))?;
|
||||
writer
|
||||
.write_all(payload_to_write)
|
||||
.await
|
||||
.map_err(|err| PacketEncodeError::Message(err.to_string()))?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@ -323,7 +311,7 @@ impl<W: AsyncWrite + Unpin> TCPNetworkEncoder<W> {
|
||||
pub async fn flush(&mut self) -> Result<(), PacketEncodeError> {
|
||||
self.writer
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.ok_or_else(|| PacketEncodeError::Message("Writer missing".into()))?
|
||||
.flush()
|
||||
.await
|
||||
.map_err(|err| PacketEncodeError::Message(err.to_string()))
|
||||
|
||||
@ -3,15 +3,17 @@ use pumpkin_macros::java_packet;
|
||||
|
||||
use crate::{ServerPacket, ser::ReadingError};
|
||||
use pumpkin_util::version::JavaMinecraftVersion;
|
||||
use std::io::Read;
|
||||
|
||||
/// This packet signals to the server that the client is ready to transition
|
||||
/// from the `Configuration` state to the `Play` state.
|
||||
#[java_packet(CONFIG_FINISH_CONFIGURATION)]
|
||||
pub struct SAcknowledgeFinishConfig;
|
||||
|
||||
impl ServerPacket for SAcknowledgeFinishConfig {
|
||||
fn read(_bytebuf: impl Read, _version: &JavaMinecraftVersion) -> Result<Self, ReadingError> {
|
||||
impl<'a> ServerPacket<'a> for SAcknowledgeFinishConfig {
|
||||
fn read(
|
||||
_bytebuf: &mut &'a [u8],
|
||||
_version: &JavaMinecraftVersion,
|
||||
) -> Result<Self, ReadingError> {
|
||||
Ok(Self)
|
||||
}
|
||||
}
|
||||
|
||||
@ -5,16 +5,15 @@ use crate::VarInt;
|
||||
|
||||
use crate::{
|
||||
ServerPacket,
|
||||
ser::{NetworkReadExt, ReadingError},
|
||||
ser::{NetworkReadExt, NetworkReadSliceExt, ReadingError},
|
||||
};
|
||||
use pumpkin_util::version::JavaMinecraftVersion;
|
||||
use std::io::Read;
|
||||
|
||||
/// Sent by the client to inform the server about its local settings
|
||||
#[java_packet(CONFIG_CLIENT_INFORMATION)]
|
||||
pub struct SClientInformationConfig {
|
||||
pub struct SClientInformationConfig<'a> {
|
||||
/// The language code used by the client (e.g., "`en_us`")
|
||||
pub locale: String,
|
||||
pub locale: &'a str,
|
||||
/// The maximum number of chunks the client renders
|
||||
pub view_distance: i8,
|
||||
/// Visibility of chat messages (0: Enabled, 1: Commands Only, 2: Hidden)
|
||||
@ -31,10 +30,10 @@ pub struct SClientInformationConfig {
|
||||
pub server_listing: bool,
|
||||
}
|
||||
|
||||
impl ServerPacket for SClientInformationConfig {
|
||||
fn read(mut bytebuf: impl Read, _version: &JavaMinecraftVersion) -> Result<Self, ReadingError> {
|
||||
impl<'a> ServerPacket<'a> for SClientInformationConfig<'a> {
|
||||
fn read(bytebuf: &mut &'a [u8], _version: &JavaMinecraftVersion) -> Result<Self, ReadingError> {
|
||||
Ok(Self {
|
||||
locale: bytebuf.get_str()?.into_string(),
|
||||
locale: bytebuf.get_str_borrowed()?,
|
||||
view_distance: bytebuf.get_i8()?,
|
||||
chat_mode: bytebuf.get_var_int()?,
|
||||
chat_colors: bytebuf.get_bool()?,
|
||||
|
||||
@ -1,10 +1,11 @@
|
||||
use std::io::Read;
|
||||
|
||||
use pumpkin_data::packet::serverbound::CONFIG_COOKIE_RESPONSE;
|
||||
use pumpkin_macros::java_packet;
|
||||
use pumpkin_util::version::JavaMinecraftVersion;
|
||||
|
||||
use crate::{ReadingError, ServerPacket, ser::NetworkReadExt};
|
||||
use crate::{
|
||||
ReadingError, ServerPacket,
|
||||
ser::{NetworkReadExt, NetworkReadSliceExt},
|
||||
};
|
||||
|
||||
/// The maximum allowed size for a cookie payload (5 KiB).
|
||||
const MAX_COOKIE_LENGTH: usize = 5120;
|
||||
@ -14,19 +15,18 @@ const MAX_COOKIE_LENGTH: usize = 5120;
|
||||
/// Cookies allow servers to store small amounts of data on the client side,
|
||||
/// which can be retrieved later (e.g., for session tracking or preferences)
|
||||
#[java_packet(CONFIG_COOKIE_RESPONSE)]
|
||||
pub struct SConfigCookieResponse {
|
||||
pub struct SConfigCookieResponse<'a> {
|
||||
/// The unique identifier for the cookie being returned
|
||||
pub key: Box<str>,
|
||||
pub key: &'a str,
|
||||
/// Indicates whether a payload is attached to this response
|
||||
pub has_payload: bool,
|
||||
/// The actual data stored in the cookie. Limited to 5120 bytes
|
||||
pub payload: Option<Box<[u8]>>,
|
||||
pub payload: Option<&'a [u8]>,
|
||||
}
|
||||
|
||||
impl ServerPacket for SConfigCookieResponse {
|
||||
fn read(read: impl Read, _version: &JavaMinecraftVersion) -> Result<Self, ReadingError> {
|
||||
let mut read = read;
|
||||
let key = read.get_str()?;
|
||||
impl<'a> ServerPacket<'a> for SConfigCookieResponse<'a> {
|
||||
fn read(read: &mut &'a [u8], _version: &JavaMinecraftVersion) -> Result<Self, ReadingError> {
|
||||
let key = read.get_str_borrowed()?;
|
||||
let has_payload = read.get_bool()?;
|
||||
|
||||
if !has_payload {
|
||||
@ -42,7 +42,7 @@ impl ServerPacket for SConfigCookieResponse {
|
||||
return Err(ReadingError::TooLarge("SConfigCookieResponse".to_string()));
|
||||
}
|
||||
|
||||
let payload = read.read_boxed_slice(payload_length)?;
|
||||
let payload = read.read_slice_borrowed(payload_length)?;
|
||||
Ok(Self {
|
||||
key,
|
||||
has_payload,
|
||||
|
||||
@ -1,25 +1,22 @@
|
||||
use pumpkin_data::packet::serverbound::CONFIG_CUSTOM_CLICK_ACTION;
|
||||
use pumpkin_macros::java_packet;
|
||||
use pumpkin_util::resource_location::ResourceLocation;
|
||||
|
||||
use crate::{
|
||||
ServerPacket,
|
||||
ser::{NetworkReadExt, ReadingError},
|
||||
ser::{NetworkReadExt, NetworkReadSliceExt, ReadingError},
|
||||
};
|
||||
use pumpkin_data::packet::serverbound::CONFIG_CUSTOM_CLICK_ACTION;
|
||||
use pumpkin_macros::java_packet;
|
||||
use pumpkin_util::version::JavaMinecraftVersion;
|
||||
use std::io::Read;
|
||||
|
||||
#[java_packet(CONFIG_CUSTOM_CLICK_ACTION)]
|
||||
pub struct SCustomClickAction {
|
||||
pub action_id: ResourceLocation,
|
||||
pub payload: Option<Box<[u8]>>,
|
||||
pub struct SCustomClickAction<'a> {
|
||||
pub action_id: &'a str,
|
||||
pub payload: Option<&'a [u8]>,
|
||||
}
|
||||
|
||||
impl ServerPacket for SCustomClickAction {
|
||||
fn read(mut bytebuf: impl Read, _version: &JavaMinecraftVersion) -> Result<Self, ReadingError> {
|
||||
impl<'a> ServerPacket<'a> for SCustomClickAction<'a> {
|
||||
fn read(bytebuf: &mut &'a [u8], _version: &JavaMinecraftVersion) -> Result<Self, ReadingError> {
|
||||
Ok(Self {
|
||||
action_id: bytebuf.get_str()?.into_string(),
|
||||
payload: bytebuf.get_option(|v| v.read_remaining_to_boxed_slice(32767))?,
|
||||
action_id: bytebuf.get_str_borrowed()?,
|
||||
payload: bytebuf.get_option(|v| v.read_remaining_slice_borrowed(32767))?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@ -6,15 +6,14 @@ use crate::{
|
||||
ser::{NetworkReadExt, ReadingError},
|
||||
};
|
||||
use pumpkin_util::version::JavaMinecraftVersion;
|
||||
use std::io::Read;
|
||||
|
||||
#[java_packet(CONFIG_KEEP_ALIVE)]
|
||||
pub struct SKeepAlive {
|
||||
pub keep_alive_id: i64,
|
||||
}
|
||||
|
||||
impl ServerPacket for SKeepAlive {
|
||||
fn read(mut bytebuf: impl Read, _version: &JavaMinecraftVersion) -> Result<Self, ReadingError> {
|
||||
impl<'a> ServerPacket<'a> for SKeepAlive {
|
||||
fn read(bytebuf: &mut &'a [u8], _version: &JavaMinecraftVersion) -> Result<Self, ReadingError> {
|
||||
Ok(Self {
|
||||
keep_alive_id: bytebuf.get_i64_be()?,
|
||||
})
|
||||
|
||||
@ -8,7 +8,6 @@ use crate::{
|
||||
ser::{NetworkReadExt, ReadingError},
|
||||
};
|
||||
use pumpkin_util::version::JavaMinecraftVersion;
|
||||
use std::io::Read;
|
||||
|
||||
#[java_packet(CONFIG_SELECT_KNOWN_PACKS)]
|
||||
pub struct SKnownPacks {
|
||||
@ -16,8 +15,8 @@ pub struct SKnownPacks {
|
||||
// known_packs: &'a [KnownPack]
|
||||
}
|
||||
|
||||
impl ServerPacket for SKnownPacks {
|
||||
fn read(mut bytebuf: impl Read, _version: &JavaMinecraftVersion) -> Result<Self, ReadingError> {
|
||||
impl<'a> ServerPacket<'a> for SKnownPacks {
|
||||
fn read(bytebuf: &mut &'a [u8], _version: &JavaMinecraftVersion) -> Result<Self, ReadingError> {
|
||||
Ok(Self {
|
||||
known_pack_count: bytebuf.get_var_int()?,
|
||||
})
|
||||
|
||||
@ -1,10 +1,8 @@
|
||||
use std::io::Read;
|
||||
|
||||
use pumpkin_data::packet::serverbound::CONFIG_CUSTOM_PAYLOAD;
|
||||
use pumpkin_macros::java_packet;
|
||||
use pumpkin_util::version::JavaMinecraftVersion;
|
||||
|
||||
use crate::{ReadingError, ServerPacket, ser::NetworkReadExt};
|
||||
use crate::{ReadingError, ServerPacket, ser::NetworkReadSliceExt};
|
||||
|
||||
/// The maximum allowed size for a plugin message payload (1 MiB).
|
||||
const MAX_PAYLOAD_SIZE: usize = 1_048_576;
|
||||
@ -14,19 +12,19 @@ const MAX_PAYLOAD_SIZE: usize = 1_048_576;
|
||||
/// This allows mods, plugins, or proxy
|
||||
/// software to send proprietary data over the standard Minecraft protocol.
|
||||
#[java_packet(CONFIG_CUSTOM_PAYLOAD)]
|
||||
pub struct SPluginMessage {
|
||||
pub struct SPluginMessage<'a> {
|
||||
/// The name of the channel used to distinguish different types of messages.
|
||||
/// Example: `minecraft:brand` or `velocity:main`.
|
||||
pub channel: Box<str>,
|
||||
pub channel: &'a str,
|
||||
/// The payload sent by the client.
|
||||
pub data: Box<[u8]>,
|
||||
pub data: &'a [u8],
|
||||
}
|
||||
|
||||
impl ServerPacket for SPluginMessage {
|
||||
fn read(mut read: impl Read, _version: &JavaMinecraftVersion) -> Result<Self, ReadingError> {
|
||||
impl<'a> ServerPacket<'a> for SPluginMessage<'a> {
|
||||
fn read(read: &mut &'a [u8], _version: &JavaMinecraftVersion) -> Result<Self, ReadingError> {
|
||||
Ok(Self {
|
||||
channel: read.get_str()?,
|
||||
data: read.read_remaining_to_boxed_slice(MAX_PAYLOAD_SIZE)?,
|
||||
channel: read.get_str_borrowed()?,
|
||||
data: read.read_remaining_slice_borrowed(MAX_PAYLOAD_SIZE)?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@ -6,7 +6,6 @@ use crate::{
|
||||
ser::{NetworkReadExt, ReadingError},
|
||||
};
|
||||
use pumpkin_util::version::JavaMinecraftVersion;
|
||||
use std::io::Read;
|
||||
|
||||
use crate::VarInt;
|
||||
|
||||
@ -34,8 +33,8 @@ pub struct SConfigResourcePack {
|
||||
pub result: VarInt,
|
||||
}
|
||||
|
||||
impl ServerPacket for SConfigResourcePack {
|
||||
fn read(mut bytebuf: impl Read, _version: &JavaMinecraftVersion) -> Result<Self, ReadingError> {
|
||||
impl<'a> ServerPacket<'a> for SConfigResourcePack {
|
||||
fn read(bytebuf: &mut &'a [u8], _version: &JavaMinecraftVersion) -> Result<Self, ReadingError> {
|
||||
Ok(Self {
|
||||
uuid: bytebuf.get_uuid()?,
|
||||
result: bytebuf.get_var_int()?,
|
||||
|
||||
@ -1,5 +1,3 @@
|
||||
use std::io::Read;
|
||||
|
||||
use crate::{
|
||||
ClientPacket, ConnectionState, ReadingError, ServerPacket, VarInt, ser::NetworkReadExt,
|
||||
ser::NetworkWriteExt,
|
||||
@ -24,8 +22,8 @@ pub struct SHandShake {
|
||||
pub next_state: ConnectionState,
|
||||
}
|
||||
|
||||
impl ServerPacket for SHandShake {
|
||||
fn read(mut read: impl Read, _version: &JavaMinecraftVersion) -> Result<Self, ReadingError> {
|
||||
impl<'a> ServerPacket<'a> for SHandShake {
|
||||
fn read(read: &mut &'a [u8], _version: &JavaMinecraftVersion) -> Result<Self, ReadingError> {
|
||||
Ok(Self {
|
||||
protocol_version: read.get_var_int()?,
|
||||
server_address: read.get_str_bounded(255)?,
|
||||
|
||||
@ -1,26 +1,25 @@
|
||||
use pumpkin_data::packet::serverbound::LOGIN_COOKIE_RESPONSE;
|
||||
use pumpkin_macros::java_packet;
|
||||
use pumpkin_util::version::JavaMinecraftVersion;
|
||||
use std::io::Read;
|
||||
|
||||
use crate::{
|
||||
ServerPacket,
|
||||
ser::{NetworkReadExt, ReadingError},
|
||||
ser::{NetworkReadExt, NetworkReadSliceExt, ReadingError},
|
||||
};
|
||||
|
||||
#[java_packet(LOGIN_COOKIE_RESPONSE)]
|
||||
/// Response to a `CCookieRequest` (login) from the server.
|
||||
/// The Notchian server only accepts responses of up to 5 kiB in size.
|
||||
pub struct SLoginCookieResponse {
|
||||
pub key: Box<str>,
|
||||
pub payload: Option<Box<[u8]>>, // 5120,
|
||||
pub struct SLoginCookieResponse<'a> {
|
||||
pub key: &'a str,
|
||||
pub payload: Option<&'a [u8]>, // 5120,
|
||||
}
|
||||
|
||||
const MAX_COOKIE_LENGTH: usize = 5120;
|
||||
|
||||
impl ServerPacket for SLoginCookieResponse {
|
||||
fn read(mut read: impl Read, _version: &JavaMinecraftVersion) -> Result<Self, ReadingError> {
|
||||
let key = read.get_str()?;
|
||||
impl<'a> ServerPacket<'a> for SLoginCookieResponse<'a> {
|
||||
fn read(read: &mut &'a [u8], _version: &JavaMinecraftVersion) -> Result<Self, ReadingError> {
|
||||
let key = read.get_str_borrowed()?;
|
||||
let has_payload = read.get_bool()?;
|
||||
|
||||
if !has_payload {
|
||||
@ -33,7 +32,7 @@ impl ServerPacket for SLoginCookieResponse {
|
||||
return Err(ReadingError::TooLarge("SLoginCookieResponse".to_string()));
|
||||
}
|
||||
|
||||
let payload = read.read_boxed_slice(length)?;
|
||||
let payload = read.read_slice_borrowed(length)?;
|
||||
|
||||
Ok(Self {
|
||||
key,
|
||||
|
||||
@ -1,26 +1,36 @@
|
||||
use std::io::Read;
|
||||
|
||||
use pumpkin_data::packet::serverbound::LOGIN_KEY;
|
||||
use pumpkin_macros::java_packet;
|
||||
use pumpkin_util::version::JavaMinecraftVersion;
|
||||
|
||||
use crate::{ReadingError, ServerPacket, ser::NetworkReadExt};
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
#[java_packet(LOGIN_KEY)]
|
||||
pub struct SEncryptionResponse {
|
||||
pub shared_secret: Box<[u8]>,
|
||||
pub verify_token: Box<[u8]>,
|
||||
}
|
||||
|
||||
impl ServerPacket for SEncryptionResponse {
|
||||
fn read(mut read: impl Read, _version: &JavaMinecraftVersion) -> Result<Self, ReadingError> {
|
||||
let shared_secret_length = read.get_var_int()?.0 as usize;
|
||||
let shared_secret = read.read_boxed_slice(shared_secret_length)?;
|
||||
let verify_token_length = read.get_var_int()?.0 as usize;
|
||||
let verify_token = read.read_boxed_slice(verify_token_length)?;
|
||||
impl<'a> ServerPacket<'a> for SEncryptionResponse {
|
||||
fn read(
|
||||
mut read: &mut &'a [u8],
|
||||
_version: &JavaMinecraftVersion,
|
||||
) -> Result<Self, ReadingError> {
|
||||
let shared_secret = read_encryption_buffer(&mut read)?;
|
||||
let verify_token = read_encryption_buffer(&mut read)?;
|
||||
Ok(Self {
|
||||
shared_secret,
|
||||
verify_token,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn read_encryption_buffer(read: &mut impl NetworkReadExt) -> Result<Box<[u8]>, ReadingError> {
|
||||
let length = read.get_var_int()?.0 as usize;
|
||||
if length > 256 {
|
||||
return Err(ReadingError::Message("Encryption payload too large".into()));
|
||||
}
|
||||
let mut data = vec![0u8; length];
|
||||
read.read_bytes_to_buf(&mut data)?;
|
||||
Ok(data.into_boxed_slice())
|
||||
}
|
||||
|
||||
@ -3,14 +3,16 @@ use pumpkin_macros::java_packet;
|
||||
|
||||
use crate::{ServerPacket, ser::ReadingError};
|
||||
use pumpkin_util::version::JavaMinecraftVersion;
|
||||
use std::io::Read;
|
||||
|
||||
/// Acknowledgement to the `CLoginSuccess` packet sent by the server.
|
||||
#[java_packet(LOGIN_LOGIN_ACKNOWLEDGED)]
|
||||
pub struct SLoginAcknowledged;
|
||||
|
||||
impl ServerPacket for SLoginAcknowledged {
|
||||
fn read(_bytebuf: impl Read, _version: &JavaMinecraftVersion) -> Result<Self, ReadingError> {
|
||||
impl<'a> ServerPacket<'a> for SLoginAcknowledged {
|
||||
fn read(
|
||||
_bytebuf: &mut &'a [u8],
|
||||
_version: &JavaMinecraftVersion,
|
||||
) -> Result<Self, ReadingError> {
|
||||
Ok(Self)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,3 @@
|
||||
use std::io::Read;
|
||||
|
||||
use pumpkin_data::packet::serverbound::LOGIN_HELLO;
|
||||
use pumpkin_macros::java_packet;
|
||||
use pumpkin_util::version::JavaMinecraftVersion;
|
||||
@ -15,8 +13,8 @@ pub struct SLoginStart {
|
||||
pub uuid: uuid::Uuid,
|
||||
}
|
||||
|
||||
impl ServerPacket for SLoginStart {
|
||||
fn read(mut read: impl Read, _version: &JavaMinecraftVersion) -> Result<Self, ReadingError> {
|
||||
impl<'a> ServerPacket<'a> for SLoginStart {
|
||||
fn read(read: &mut &'a [u8], _version: &JavaMinecraftVersion) -> Result<Self, ReadingError> {
|
||||
Ok(Self {
|
||||
name: read.get_str_bounded(16)?,
|
||||
uuid: read.get_uuid()?,
|
||||
|
||||
@ -1,5 +1,3 @@
|
||||
use std::io::Read;
|
||||
|
||||
use crate::{ReadingError, ServerPacket, VarInt, ser::NetworkReadExt};
|
||||
use pumpkin_data::packet::serverbound::LOGIN_CUSTOM_QUERY_ANSWER;
|
||||
use pumpkin_macros::java_packet;
|
||||
@ -13,11 +11,11 @@ pub struct SLoginPluginResponse {
|
||||
pub data: Option<Box<[u8]>>,
|
||||
}
|
||||
|
||||
impl ServerPacket for SLoginPluginResponse {
|
||||
fn read(mut read: impl Read, _version: &JavaMinecraftVersion) -> Result<Self, ReadingError> {
|
||||
impl<'a> ServerPacket<'a> for SLoginPluginResponse {
|
||||
fn read(read: &mut &'a [u8], _version: &JavaMinecraftVersion) -> Result<Self, ReadingError> {
|
||||
Ok(Self {
|
||||
message_id: read.get_var_int()?,
|
||||
data: read.get_option(|v| v.read_remaining_to_boxed_slice(MAX_PAYLOAD_SIZE))?,
|
||||
data: read.get_option(|v| crate::ser::read_remaining_bytes(v, MAX_PAYLOAD_SIZE))?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@ -5,7 +5,6 @@ use crate::{
|
||||
use pumpkin_data::packet::serverbound::PLAY_ATTACK;
|
||||
use pumpkin_macros::java_packet;
|
||||
use pumpkin_util::version::JavaMinecraftVersion;
|
||||
use std::io::Read;
|
||||
|
||||
use crate::codec::var_int::VarInt;
|
||||
|
||||
@ -14,9 +13,9 @@ pub struct SAttack {
|
||||
pub entity_id: VarInt,
|
||||
}
|
||||
|
||||
impl ServerPacket for SAttack {
|
||||
impl<'a> ServerPacket<'a> for SAttack {
|
||||
fn read(
|
||||
mut bytebuf: impl Read,
|
||||
bytebuf: &mut &'a [u8],
|
||||
_protocol_version: &JavaMinecraftVersion,
|
||||
) -> Result<Self, ReadingError> {
|
||||
Ok(Self {
|
||||
|
||||
@ -8,7 +8,6 @@ use crate::{
|
||||
ser::{NetworkReadExt, ReadingError},
|
||||
};
|
||||
use pumpkin_util::version::JavaMinecraftVersion;
|
||||
use std::io::Read;
|
||||
|
||||
#[java_packet(PLAY_BUNDLE_ITEM_SELECTED)]
|
||||
pub struct SBundleItemSelected {
|
||||
@ -16,8 +15,8 @@ pub struct SBundleItemSelected {
|
||||
pub selected_item_index: VarInt,
|
||||
}
|
||||
|
||||
impl ServerPacket for SBundleItemSelected {
|
||||
fn read(mut bytebuf: impl Read, _version: &JavaMinecraftVersion) -> Result<Self, ReadingError> {
|
||||
impl<'a> ServerPacket<'a> for SBundleItemSelected {
|
||||
fn read(bytebuf: &mut &'a [u8], _version: &JavaMinecraftVersion) -> Result<Self, ReadingError> {
|
||||
Ok(Self {
|
||||
slot_id: bytebuf.get_var_int()?,
|
||||
selected_item_index: bytebuf.get_var_int()?,
|
||||
|
||||
@ -6,15 +6,14 @@ use pumpkin_data::packet::serverbound::PLAY_CHANGE_GAME_MODE;
|
||||
use pumpkin_macros::java_packet;
|
||||
use pumpkin_util::GameMode;
|
||||
use pumpkin_util::version::JavaMinecraftVersion;
|
||||
use std::io::Read;
|
||||
|
||||
#[java_packet(PLAY_CHANGE_GAME_MODE)]
|
||||
pub struct SChangeGameMode {
|
||||
pub game_mode: GameMode,
|
||||
}
|
||||
|
||||
impl ServerPacket for SChangeGameMode {
|
||||
fn read(mut bytebuf: impl Read, _version: &JavaMinecraftVersion) -> Result<Self, ReadingError> {
|
||||
impl<'a> ServerPacket<'a> for SChangeGameMode {
|
||||
fn read(bytebuf: &mut &'a [u8], _version: &JavaMinecraftVersion) -> Result<Self, ReadingError> {
|
||||
Ok(Self {
|
||||
game_mode: GameMode::try_from(bytebuf.get_u8()? as i8)
|
||||
.map_err(|()| crate::ser::ReadingError::Message("Invalid game mode".into()))?,
|
||||
|
||||
@ -3,20 +3,19 @@ use pumpkin_macros::java_packet;
|
||||
|
||||
use crate::{
|
||||
ServerPacket,
|
||||
ser::{NetworkReadExt, ReadingError},
|
||||
ser::{NetworkReadSliceExt, ReadingError},
|
||||
};
|
||||
use pumpkin_util::version::JavaMinecraftVersion;
|
||||
use std::io::Read;
|
||||
|
||||
#[java_packet(PLAY_CHAT_COMMAND)]
|
||||
pub struct SChatCommand {
|
||||
pub command: String,
|
||||
pub struct SChatCommand<'a> {
|
||||
pub command: &'a str,
|
||||
}
|
||||
|
||||
impl ServerPacket for SChatCommand {
|
||||
fn read(mut bytebuf: impl Read, _version: &JavaMinecraftVersion) -> Result<Self, ReadingError> {
|
||||
impl<'a> ServerPacket<'a> for SChatCommand<'a> {
|
||||
fn read(bytebuf: &mut &'a [u8], _version: &JavaMinecraftVersion) -> Result<Self, ReadingError> {
|
||||
Ok(Self {
|
||||
command: bytebuf.get_str()?.into_string(),
|
||||
command: bytebuf.get_str_borrowed()?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,3 @@
|
||||
use std::io::Read;
|
||||
|
||||
use pumpkin_data::packet::serverbound::PLAY_CHAT;
|
||||
use pumpkin_macros::java_packet;
|
||||
use pumpkin_util::version::JavaMinecraftVersion;
|
||||
@ -8,46 +6,46 @@ use crate::{
|
||||
ClientPacket, ServerPacket,
|
||||
codec::var_int::VarInt,
|
||||
ser::NetworkWriteExt,
|
||||
ser::{NetworkReadExt, ReadingError},
|
||||
ser::{NetworkReadExt, NetworkReadSliceExt, ReadingError},
|
||||
};
|
||||
|
||||
#[java_packet(PLAY_CHAT)]
|
||||
pub struct SChatMessage {
|
||||
pub message: Box<str>,
|
||||
pub struct SChatMessage<'a> {
|
||||
pub message: &'a str,
|
||||
pub timestamp: i64,
|
||||
pub salt: i64,
|
||||
pub signature: Option<Box<[u8]>>,
|
||||
pub signature: Option<&'a [u8]>,
|
||||
pub message_count: VarInt,
|
||||
pub acknowledged: Box<[u8]>, // Bitset fixed 20 bits
|
||||
pub checksum: u8, // 1.21.5 "fingerprint" checksum
|
||||
pub acknowledged: &'a [u8], // Bitset fixed 20 bits
|
||||
pub checksum: u8, // 1.21.5 "fingerprint" checksum
|
||||
}
|
||||
|
||||
impl ServerPacket for SChatMessage {
|
||||
fn read(mut read: impl Read, _version: &JavaMinecraftVersion) -> Result<Self, ReadingError> {
|
||||
impl<'a> ServerPacket<'a> for SChatMessage<'a> {
|
||||
fn read(read: &mut &'a [u8], _version: &JavaMinecraftVersion) -> Result<Self, ReadingError> {
|
||||
Ok(Self {
|
||||
message: read.get_str_bounded(256)?,
|
||||
message: read.get_str_bounded_borrowed(256)?,
|
||||
timestamp: read.get_i64_be()?,
|
||||
salt: read.get_i64_be()?,
|
||||
signature: read.get_option(|v| v.read_boxed_slice(256))?,
|
||||
signature: read.get_option(|v| v.read_slice_borrowed(256))?,
|
||||
message_count: read.get_var_int()?,
|
||||
acknowledged: read.get_fixed_bitset(20)?,
|
||||
acknowledged: read.read_slice_borrowed(3)?,
|
||||
checksum: read.get_u8()?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl ClientPacket for SChatMessage {
|
||||
impl ClientPacket for SChatMessage<'_> {
|
||||
fn write_packet_data(
|
||||
&self,
|
||||
mut write: impl std::io::Write,
|
||||
_version: &JavaMinecraftVersion,
|
||||
) -> Result<(), crate::ser::WritingError> {
|
||||
write.write_string(&self.message)?;
|
||||
write.write_string(self.message)?;
|
||||
write.write_i64_be(self.timestamp)?;
|
||||
write.write_i64_be(self.salt)?;
|
||||
write.write_option(&self.signature, |p, v| p.write_slice(v))?;
|
||||
write.write_var_int(&self.message_count)?;
|
||||
write.write_fixed_bitset(20, self.acknowledged.clone())?;
|
||||
write.write_slice(self.acknowledged)?;
|
||||
write.write_u8(self.checksum)?;
|
||||
|
||||
Ok(())
|
||||
|
||||
@ -5,15 +5,14 @@ use crate::{
|
||||
use pumpkin_data::packet::serverbound::PLAY_CHUNK_BATCH_RECEIVED;
|
||||
use pumpkin_macros::java_packet;
|
||||
use pumpkin_util::version::JavaMinecraftVersion;
|
||||
use std::io::Read;
|
||||
|
||||
#[java_packet(PLAY_CHUNK_BATCH_RECEIVED)]
|
||||
pub struct SChunkBatch {
|
||||
pub chunks_per_tick: f32,
|
||||
}
|
||||
|
||||
impl ServerPacket for SChunkBatch {
|
||||
fn read(mut bytebuf: impl Read, _version: &JavaMinecraftVersion) -> Result<Self, ReadingError> {
|
||||
impl<'a> ServerPacket<'a> for SChunkBatch {
|
||||
fn read(bytebuf: &mut &'a [u8], _version: &JavaMinecraftVersion) -> Result<Self, ReadingError> {
|
||||
Ok(Self {
|
||||
chunks_per_tick: bytebuf.get_f32_be()?,
|
||||
})
|
||||
|
||||
@ -22,8 +22,11 @@ pub struct SClickSlot {
|
||||
pub carried_item: OptionalItemStackHash,
|
||||
}
|
||||
|
||||
impl ServerPacket for SClickSlot {
|
||||
fn read(mut bytebuf: impl Read, _version: &JavaMinecraftVersion) -> Result<Self, ReadingError> {
|
||||
impl<'a> ServerPacket<'a> for SClickSlot {
|
||||
fn read(
|
||||
mut bytebuf: &mut &'a [u8],
|
||||
_version: &JavaMinecraftVersion,
|
||||
) -> Result<Self, ReadingError> {
|
||||
let sync_id = bytebuf.get_var_int()?;
|
||||
let revision = bytebuf.get_var_int()?;
|
||||
let slot = bytebuf.get_i16_be()?;
|
||||
@ -31,6 +34,11 @@ impl ServerPacket for SClickSlot {
|
||||
let mode = SlotActionType::read(&mut bytebuf)?;
|
||||
|
||||
let length_of_array = bytebuf.get_var_int()?;
|
||||
if length_of_array.0 < 0 || length_of_array.0 > 256 {
|
||||
return Err(ReadingError::Message(
|
||||
"Changed slots length out of bounds".into(),
|
||||
));
|
||||
}
|
||||
let mut array_of_changed_slots = Vec::with_capacity(length_of_array.0 as usize);
|
||||
for _ in 0..length_of_array.0 {
|
||||
array_of_changed_slots.push((
|
||||
|
||||
@ -5,7 +5,6 @@ use crate::{
|
||||
use pumpkin_data::packet::serverbound::PLAY_CLIENT_COMMAND;
|
||||
use pumpkin_macros::java_packet;
|
||||
use pumpkin_util::version::JavaMinecraftVersion;
|
||||
use std::io::Read;
|
||||
|
||||
use crate::VarInt;
|
||||
|
||||
@ -14,8 +13,8 @@ pub struct SClientCommand {
|
||||
pub action_id: VarInt,
|
||||
}
|
||||
|
||||
impl ServerPacket for SClientCommand {
|
||||
fn read(mut bytebuf: impl Read, _version: &JavaMinecraftVersion) -> Result<Self, ReadingError> {
|
||||
impl<'a> ServerPacket<'a> for SClientCommand {
|
||||
fn read(bytebuf: &mut &'a [u8], _version: &JavaMinecraftVersion) -> Result<Self, ReadingError> {
|
||||
Ok(Self {
|
||||
action_id: bytebuf.get_var_int()?,
|
||||
})
|
||||
|
||||
@ -1,17 +1,16 @@
|
||||
use crate::{
|
||||
ServerPacket,
|
||||
ser::{NetworkReadExt, ReadingError},
|
||||
ser::{NetworkReadExt, NetworkReadSliceExt, ReadingError},
|
||||
};
|
||||
use pumpkin_data::packet::serverbound::PLAY_CLIENT_INFORMATION;
|
||||
use pumpkin_macros::java_packet;
|
||||
use pumpkin_util::version::JavaMinecraftVersion;
|
||||
use std::io::Read;
|
||||
|
||||
use crate::VarInt;
|
||||
|
||||
#[java_packet(PLAY_CLIENT_INFORMATION)]
|
||||
pub struct SClientInformationPlay {
|
||||
pub locale: String, // 16
|
||||
pub struct SClientInformationPlay<'a> {
|
||||
pub locale: &'a str, // 16
|
||||
pub view_distance: i8,
|
||||
pub chat_mode: VarInt, // VarInt
|
||||
pub chat_colors: bool,
|
||||
@ -21,10 +20,10 @@ pub struct SClientInformationPlay {
|
||||
pub server_listing: bool,
|
||||
}
|
||||
|
||||
impl ServerPacket for SClientInformationPlay {
|
||||
fn read(mut bytebuf: impl Read, _version: &JavaMinecraftVersion) -> Result<Self, ReadingError> {
|
||||
impl<'a> ServerPacket<'a> for SClientInformationPlay<'a> {
|
||||
fn read(bytebuf: &mut &'a [u8], _version: &JavaMinecraftVersion) -> Result<Self, ReadingError> {
|
||||
Ok(Self {
|
||||
locale: bytebuf.get_str()?.to_string(),
|
||||
locale: bytebuf.get_str_borrowed()?,
|
||||
view_distance: bytebuf.get_i8()?,
|
||||
chat_mode: bytebuf.get_var_int()?,
|
||||
chat_colors: bytebuf.get_bool()?,
|
||||
|
||||
@ -5,7 +5,6 @@ use crate::{
|
||||
use pumpkin_data::packet::serverbound::PLAY_CONTAINER_CLOSE;
|
||||
use pumpkin_macros::java_packet;
|
||||
use pumpkin_util::version::JavaMinecraftVersion;
|
||||
use std::io::Read;
|
||||
|
||||
use crate::VarInt;
|
||||
|
||||
@ -14,8 +13,8 @@ pub struct SCloseContainer {
|
||||
pub window_id: VarInt,
|
||||
}
|
||||
|
||||
impl ServerPacket for SCloseContainer {
|
||||
fn read(mut bytebuf: impl Read, _version: &JavaMinecraftVersion) -> Result<Self, ReadingError> {
|
||||
impl<'a> ServerPacket<'a> for SCloseContainer {
|
||||
fn read(bytebuf: &mut &'a [u8], _version: &JavaMinecraftVersion) -> Result<Self, ReadingError> {
|
||||
Ok(Self {
|
||||
window_id: bytebuf.get_var_int()?,
|
||||
})
|
||||
|
||||
@ -5,22 +5,21 @@ use crate::VarInt;
|
||||
|
||||
use crate::{
|
||||
ServerPacket,
|
||||
ser::{NetworkReadExt, ReadingError},
|
||||
ser::{NetworkReadExt, NetworkReadSliceExt, ReadingError},
|
||||
};
|
||||
use pumpkin_util::version::JavaMinecraftVersion;
|
||||
use std::io::Read;
|
||||
|
||||
#[java_packet(PLAY_COMMAND_SUGGESTION)]
|
||||
pub struct SCommandSuggestion {
|
||||
pub struct SCommandSuggestion<'a> {
|
||||
pub id: VarInt,
|
||||
pub command: String,
|
||||
pub command: &'a str,
|
||||
}
|
||||
|
||||
impl ServerPacket for SCommandSuggestion {
|
||||
fn read(mut bytebuf: impl Read, _version: &JavaMinecraftVersion) -> Result<Self, ReadingError> {
|
||||
impl<'a> ServerPacket<'a> for SCommandSuggestion<'a> {
|
||||
fn read(bytebuf: &mut &'a [u8], _version: &JavaMinecraftVersion) -> Result<Self, ReadingError> {
|
||||
Ok(Self {
|
||||
id: bytebuf.get_var_int()?,
|
||||
command: bytebuf.get_str()?.into_string(),
|
||||
command: bytebuf.get_str_borrowed()?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@ -5,7 +5,6 @@ use crate::{
|
||||
use pumpkin_data::packet::serverbound::PLAY_ACCEPT_TELEPORTATION;
|
||||
use pumpkin_macros::java_packet;
|
||||
use pumpkin_util::version::JavaMinecraftVersion;
|
||||
use std::io::Read;
|
||||
|
||||
use crate::VarInt;
|
||||
|
||||
@ -14,8 +13,8 @@ pub struct SConfirmTeleport {
|
||||
pub teleport_id: VarInt,
|
||||
}
|
||||
|
||||
impl ServerPacket for SConfirmTeleport {
|
||||
fn read(mut bytebuf: impl Read, _version: &JavaMinecraftVersion) -> Result<Self, ReadingError> {
|
||||
impl<'a> ServerPacket<'a> for SConfirmTeleport {
|
||||
fn read(bytebuf: &mut &'a [u8], _version: &JavaMinecraftVersion) -> Result<Self, ReadingError> {
|
||||
Ok(Self {
|
||||
teleport_id: bytebuf.get_var_int()?,
|
||||
})
|
||||
|
||||
@ -7,7 +7,6 @@ use crate::{
|
||||
ser::{NetworkReadExt, ReadingError},
|
||||
};
|
||||
use pumpkin_util::version::JavaMinecraftVersion;
|
||||
use std::io::Read;
|
||||
|
||||
#[derive(Debug)]
|
||||
#[java_packet(PLAY_CONTAINER_BUTTON_CLICK)]
|
||||
@ -16,8 +15,8 @@ pub struct SContainerButtonClick {
|
||||
pub button_id: VarInt,
|
||||
}
|
||||
|
||||
impl ServerPacket for SContainerButtonClick {
|
||||
fn read(mut bytebuf: impl Read, _version: &JavaMinecraftVersion) -> Result<Self, ReadingError> {
|
||||
impl<'a> ServerPacket<'a> for SContainerButtonClick {
|
||||
fn read(bytebuf: &mut &'a [u8], _version: &JavaMinecraftVersion) -> Result<Self, ReadingError> {
|
||||
Ok(Self {
|
||||
window_id: bytebuf.get_var_int()?,
|
||||
button_id: bytebuf.get_var_int()?,
|
||||
|
||||
@ -1,27 +1,25 @@
|
||||
use std::io::Read;
|
||||
|
||||
use pumpkin_data::packet::serverbound::PLAY_COOKIE_RESPONSE;
|
||||
use pumpkin_macros::java_packet;
|
||||
use pumpkin_util::version::JavaMinecraftVersion;
|
||||
|
||||
use crate::{
|
||||
ServerPacket,
|
||||
ser::{NetworkReadExt, ReadingError},
|
||||
ser::{NetworkReadExt, NetworkReadSliceExt, ReadingError},
|
||||
};
|
||||
|
||||
#[java_packet(PLAY_COOKIE_RESPONSE)]
|
||||
/// Response to a `CCookieRequest` (play) from the server.
|
||||
/// The Notchian (vanilla) server only accepts responses of up to 5 KiB in size.
|
||||
pub struct SCookieResponse {
|
||||
pub key: Box<str>,
|
||||
pub payload: Option<Box<[u8]>>, // 5120,
|
||||
pub struct SCookieResponse<'a> {
|
||||
pub key: &'a str,
|
||||
pub payload: Option<&'a [u8]>, // 5120,
|
||||
}
|
||||
|
||||
const MAX_COOKIE_LENGTH: usize = 5120;
|
||||
|
||||
impl ServerPacket for SCookieResponse {
|
||||
fn read(mut read: impl Read, _version: &JavaMinecraftVersion) -> Result<Self, ReadingError> {
|
||||
let key = read.get_str()?;
|
||||
impl<'a> ServerPacket<'a> for SCookieResponse<'a> {
|
||||
fn read(read: &mut &'a [u8], _version: &JavaMinecraftVersion) -> Result<Self, ReadingError> {
|
||||
let key = read.get_str_borrowed()?;
|
||||
let has_payload = read.get_bool()?;
|
||||
|
||||
if !has_payload {
|
||||
@ -33,7 +31,7 @@ impl ServerPacket for SCookieResponse {
|
||||
return Err(ReadingError::TooLarge("SCookieResponse".to_string()));
|
||||
}
|
||||
|
||||
let payload = read.read_boxed_slice(payload_length)?;
|
||||
let payload = read.read_slice_borrowed(payload_length)?;
|
||||
|
||||
Ok(Self {
|
||||
key,
|
||||
|
||||
@ -1,24 +1,22 @@
|
||||
use crate::{
|
||||
ServerPacket,
|
||||
ser::{NetworkReadExt, ReadingError},
|
||||
ser::{NetworkReadExt, NetworkReadSliceExt, ReadingError},
|
||||
};
|
||||
use pumpkin_data::packet::serverbound::PLAY_CUSTOM_CLICK_ACTION;
|
||||
use pumpkin_macros::java_packet;
|
||||
use pumpkin_util::resource_location::ResourceLocation;
|
||||
use pumpkin_util::version::JavaMinecraftVersion;
|
||||
use std::io::Read;
|
||||
|
||||
#[java_packet(PLAY_CUSTOM_CLICK_ACTION)]
|
||||
pub struct SCustomClickAction {
|
||||
pub action_id: ResourceLocation,
|
||||
pub payload: Option<Box<[u8]>>,
|
||||
pub struct SCustomClickAction<'a> {
|
||||
pub action_id: &'a str,
|
||||
pub payload: Option<&'a [u8]>,
|
||||
}
|
||||
|
||||
impl ServerPacket for SCustomClickAction {
|
||||
fn read(mut bytebuf: impl Read, _version: &JavaMinecraftVersion) -> Result<Self, ReadingError> {
|
||||
impl<'a> ServerPacket<'a> for SCustomClickAction<'a> {
|
||||
fn read(bytebuf: &mut &'a [u8], _version: &JavaMinecraftVersion) -> Result<Self, ReadingError> {
|
||||
Ok(Self {
|
||||
action_id: bytebuf.get_str()?.to_string(),
|
||||
payload: bytebuf.get_option(|b| b.read_remaining_to_boxed_slice(32767))?,
|
||||
action_id: bytebuf.get_str_borrowed()?,
|
||||
payload: bytebuf.get_option(|b| b.read_remaining_slice_borrowed(32767))?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,10 +1,8 @@
|
||||
use std::io::Read;
|
||||
|
||||
use pumpkin_data::packet::serverbound::PLAY_CUSTOM_PAYLOAD;
|
||||
use pumpkin_macros::java_packet;
|
||||
use pumpkin_util::version::JavaMinecraftVersion;
|
||||
|
||||
use crate::{ReadingError, ServerPacket, ser::NetworkReadExt};
|
||||
use crate::{ReadingError, ServerPacket, ser::NetworkReadSliceExt};
|
||||
|
||||
/// The maximum allowed size for a play custom payload (32 KiB).
|
||||
const MAX_PAYLOAD_SIZE: usize = 32_767;
|
||||
@ -14,19 +12,19 @@ const MAX_PAYLOAD_SIZE: usize = 32_767;
|
||||
/// This allows mods, plugins, or proxy software to send proprietary data over the standard
|
||||
/// Minecraft protocol.
|
||||
#[java_packet(PLAY_CUSTOM_PAYLOAD)]
|
||||
pub struct SCustomPayload {
|
||||
pub struct SCustomPayload<'a> {
|
||||
/// The name of the channel used to distinguish different types of messages.
|
||||
/// Example: `minecraft:brand` or `voicechat:request_secret`.
|
||||
pub channel: Box<str>,
|
||||
pub channel: &'a str,
|
||||
/// The payload sent by the client.
|
||||
pub data: Box<[u8]>,
|
||||
pub data: &'a [u8],
|
||||
}
|
||||
|
||||
impl ServerPacket for SCustomPayload {
|
||||
fn read(mut read: impl Read, _version: &JavaMinecraftVersion) -> Result<Self, ReadingError> {
|
||||
impl<'a> ServerPacket<'a> for SCustomPayload<'a> {
|
||||
fn read(read: &mut &'a [u8], _version: &JavaMinecraftVersion) -> Result<Self, ReadingError> {
|
||||
Ok(Self {
|
||||
channel: read.get_str()?,
|
||||
data: read.read_remaining_to_boxed_slice(MAX_PAYLOAD_SIZE)?,
|
||||
channel: read.get_str_borrowed()?,
|
||||
data: read.read_remaining_slice_borrowed(MAX_PAYLOAD_SIZE)?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,3 @@
|
||||
use std::io::Read;
|
||||
|
||||
use pumpkin_data::packet::serverbound::PLAY_INTERACT;
|
||||
use pumpkin_macros::java_packet;
|
||||
use pumpkin_util::{math::vector3::Vector3, version::JavaMinecraftVersion};
|
||||
@ -20,8 +18,8 @@ pub struct SInteract {
|
||||
}
|
||||
|
||||
// Great job Mojang ;D
|
||||
impl ServerPacket for SInteract {
|
||||
fn read(mut read: impl Read, version: &JavaMinecraftVersion) -> Result<Self, ReadingError> {
|
||||
impl<'a> ServerPacket<'a> for SInteract {
|
||||
fn read(mut read: &mut &'a [u8], version: &JavaMinecraftVersion) -> Result<Self, ReadingError> {
|
||||
// 26.1+ removes the 'type' field and uses doubles for location
|
||||
if version >= &JavaMinecraftVersion::V_26_1 {
|
||||
let entity_id = read.get_var_int()?;
|
||||
|
||||
@ -6,7 +6,6 @@ use pumpkin_data::packet::serverbound::PLAY_JIGSAW_GENERATE;
|
||||
use pumpkin_macros::java_packet;
|
||||
use pumpkin_util::math::position::BlockPos;
|
||||
use pumpkin_util::version::JavaMinecraftVersion;
|
||||
use std::io::Read;
|
||||
|
||||
use crate::codec::var_int::VarInt;
|
||||
|
||||
@ -17,9 +16,9 @@ pub struct SJigsawGenerate {
|
||||
pub keep_jigsaws: bool,
|
||||
}
|
||||
|
||||
impl ServerPacket for SJigsawGenerate {
|
||||
impl<'a> ServerPacket<'a> for SJigsawGenerate {
|
||||
fn read(
|
||||
mut bytebuf: impl Read,
|
||||
bytebuf: &mut &'a [u8],
|
||||
_protocol_version: &JavaMinecraftVersion,
|
||||
) -> Result<Self, ReadingError> {
|
||||
Ok(Self {
|
||||
|
||||
@ -6,15 +6,14 @@ use crate::{
|
||||
ser::{NetworkReadExt, ReadingError},
|
||||
};
|
||||
use pumpkin_util::version::JavaMinecraftVersion;
|
||||
use std::io::Read;
|
||||
|
||||
#[java_packet(PLAY_KEEP_ALIVE)]
|
||||
pub struct SKeepAlive {
|
||||
pub keep_alive_id: i64,
|
||||
}
|
||||
|
||||
impl ServerPacket for SKeepAlive {
|
||||
fn read(mut bytebuf: impl Read, _version: &JavaMinecraftVersion) -> Result<Self, ReadingError> {
|
||||
impl<'a> ServerPacket<'a> for SKeepAlive {
|
||||
fn read(bytebuf: &mut &'a [u8], _version: &JavaMinecraftVersion) -> Result<Self, ReadingError> {
|
||||
Ok(Self {
|
||||
keep_alive_id: bytebuf.get_i64_be()?,
|
||||
})
|
||||
|
||||
@ -5,7 +5,6 @@ use crate::{
|
||||
use pumpkin_data::packet::serverbound::PLAY_MOVE_VEHICLE;
|
||||
use pumpkin_macros::java_packet;
|
||||
use pumpkin_util::version::JavaMinecraftVersion;
|
||||
use std::io::Read;
|
||||
|
||||
#[java_packet(PLAY_MOVE_VEHICLE)]
|
||||
pub struct SMoveVehicle {
|
||||
@ -16,9 +15,9 @@ pub struct SMoveVehicle {
|
||||
pub pitch: f32,
|
||||
}
|
||||
|
||||
impl ServerPacket for SMoveVehicle {
|
||||
impl<'a> ServerPacket<'a> for SMoveVehicle {
|
||||
fn read(
|
||||
mut bytebuf: impl Read,
|
||||
bytebuf: &mut &'a [u8],
|
||||
_protocol_version: &JavaMinecraftVersion,
|
||||
) -> Result<Self, ReadingError> {
|
||||
Ok(Self {
|
||||
|
||||
@ -6,7 +6,6 @@ use crate::{
|
||||
ser::{NetworkReadExt, ReadingError},
|
||||
};
|
||||
use pumpkin_util::version::JavaMinecraftVersion;
|
||||
use std::io::Read;
|
||||
|
||||
#[java_packet(PLAY_PADDLE_BOAT)]
|
||||
pub struct SPaddleBoat {
|
||||
@ -14,8 +13,8 @@ pub struct SPaddleBoat {
|
||||
pub right_paddle: bool,
|
||||
}
|
||||
|
||||
impl ServerPacket for SPaddleBoat {
|
||||
fn read(mut bytebuf: impl Read, _version: &JavaMinecraftVersion) -> Result<Self, ReadingError> {
|
||||
impl<'a> ServerPacket<'a> for SPaddleBoat {
|
||||
fn read(bytebuf: &mut &'a [u8], _version: &JavaMinecraftVersion) -> Result<Self, ReadingError> {
|
||||
Ok(Self {
|
||||
left_paddle: bytebuf.get_bool()?,
|
||||
right_paddle: bytebuf.get_bool()?,
|
||||
|
||||
@ -8,7 +8,6 @@ use crate::{
|
||||
ser::{NetworkReadExt, ReadingError},
|
||||
};
|
||||
use pumpkin_util::version::JavaMinecraftVersion;
|
||||
use std::io::Read;
|
||||
|
||||
#[java_packet(PLAY_PICK_ITEM_FROM_BLOCK)]
|
||||
pub struct SPickItemFromBlock {
|
||||
@ -16,8 +15,8 @@ pub struct SPickItemFromBlock {
|
||||
pub include_data: bool,
|
||||
}
|
||||
|
||||
impl ServerPacket for SPickItemFromBlock {
|
||||
fn read(mut bytebuf: impl Read, _version: &JavaMinecraftVersion) -> Result<Self, ReadingError> {
|
||||
impl<'a> ServerPacket<'a> for SPickItemFromBlock {
|
||||
fn read(bytebuf: &mut &'a [u8], _version: &JavaMinecraftVersion) -> Result<Self, ReadingError> {
|
||||
Ok(Self {
|
||||
pos: BlockPos::from_i64(bytebuf.get_i64_be()?),
|
||||
include_data: bytebuf.get_bool()?,
|
||||
@ -31,8 +30,8 @@ pub struct SPickItemFromEntity {
|
||||
pub include_data: bool,
|
||||
}
|
||||
|
||||
impl ServerPacket for SPickItemFromEntity {
|
||||
fn read(mut bytebuf: impl Read, _version: &JavaMinecraftVersion) -> Result<Self, ReadingError> {
|
||||
impl<'a> ServerPacket<'a> for SPickItemFromEntity {
|
||||
fn read(bytebuf: &mut &'a [u8], _version: &JavaMinecraftVersion) -> Result<Self, ReadingError> {
|
||||
Ok(Self {
|
||||
id: bytebuf.get_var_int()?,
|
||||
include_data: bytebuf.get_bool()?,
|
||||
|
||||
@ -6,15 +6,14 @@ use crate::{
|
||||
ser::{NetworkReadExt, ReadingError},
|
||||
};
|
||||
use pumpkin_util::version::JavaMinecraftVersion;
|
||||
use std::io::Read;
|
||||
|
||||
#[java_packet(PLAY_PING_REQUEST)]
|
||||
pub struct SPlayPingRequest {
|
||||
pub payload: i64,
|
||||
}
|
||||
|
||||
impl ServerPacket for SPlayPingRequest {
|
||||
fn read(mut bytebuf: impl Read, _version: &JavaMinecraftVersion) -> Result<Self, ReadingError> {
|
||||
impl<'a> ServerPacket<'a> for SPlayPingRequest {
|
||||
fn read(bytebuf: &mut &'a [u8], _version: &JavaMinecraftVersion) -> Result<Self, ReadingError> {
|
||||
Ok(Self {
|
||||
payload: bytebuf.get_i64_be()?,
|
||||
})
|
||||
|
||||
@ -5,7 +5,6 @@ use crate::{
|
||||
use pumpkin_data::packet::serverbound::PLAY_PLACE_RECIPE;
|
||||
use pumpkin_macros::java_packet;
|
||||
use pumpkin_util::version::JavaMinecraftVersion;
|
||||
use std::io::Read;
|
||||
|
||||
use crate::VarInt;
|
||||
|
||||
@ -16,8 +15,8 @@ pub struct SPlaceRecipe {
|
||||
pub use_max_items: bool,
|
||||
}
|
||||
|
||||
impl ServerPacket for SPlaceRecipe {
|
||||
fn read(mut bytebuf: impl Read, _version: &JavaMinecraftVersion) -> Result<Self, ReadingError> {
|
||||
impl<'a> ServerPacket<'a> for SPlaceRecipe {
|
||||
fn read(bytebuf: &mut &'a [u8], _version: &JavaMinecraftVersion) -> Result<Self, ReadingError> {
|
||||
Ok(Self {
|
||||
container_id: bytebuf.get_i8()?,
|
||||
recipe_display_id: bytebuf.get_var_int()?,
|
||||
|
||||
@ -8,15 +8,14 @@ use crate::{
|
||||
ser::{NetworkReadExt, ReadingError},
|
||||
};
|
||||
use pumpkin_util::version::JavaMinecraftVersion;
|
||||
use std::io::Read;
|
||||
|
||||
#[java_packet(PLAY_PLAYER_ABILITIES)]
|
||||
pub struct SPlayerAbilities {
|
||||
pub flags: i8,
|
||||
}
|
||||
|
||||
impl ServerPacket for SPlayerAbilities {
|
||||
fn read(mut bytebuf: impl Read, _version: &JavaMinecraftVersion) -> Result<Self, ReadingError> {
|
||||
impl<'a> ServerPacket<'a> for SPlayerAbilities {
|
||||
fn read(bytebuf: &mut &'a [u8], _version: &JavaMinecraftVersion) -> Result<Self, ReadingError> {
|
||||
Ok(Self {
|
||||
flags: bytebuf.get_i8()?,
|
||||
})
|
||||
|
||||
@ -6,7 +6,6 @@ use pumpkin_data::packet::serverbound::PLAY_PLAYER_ACTION;
|
||||
use pumpkin_macros::java_packet;
|
||||
use pumpkin_util::math::position::BlockPos;
|
||||
use pumpkin_util::version::JavaMinecraftVersion;
|
||||
use std::io::Read;
|
||||
|
||||
use crate::VarInt;
|
||||
|
||||
@ -18,9 +17,9 @@ pub struct SPlayerAction {
|
||||
pub sequence: VarInt,
|
||||
}
|
||||
|
||||
impl ServerPacket for SPlayerAction {
|
||||
impl<'a> ServerPacket<'a> for SPlayerAction {
|
||||
fn read(
|
||||
mut bytebuf: impl Read,
|
||||
bytebuf: &mut &'a [u8],
|
||||
_protocol_version: &JavaMinecraftVersion,
|
||||
) -> Result<Self, ReadingError> {
|
||||
Ok(Self {
|
||||
|
||||
@ -1,5 +1,3 @@
|
||||
use std::io::Read;
|
||||
|
||||
use pumpkin_data::packet::serverbound::PLAY_PLAYER_COMMAND;
|
||||
use pumpkin_macros::java_packet;
|
||||
use pumpkin_util::version::JavaMinecraftVersion;
|
||||
@ -33,8 +31,8 @@ pub enum Action {
|
||||
|
||||
pub struct InvalidAction;
|
||||
|
||||
impl ServerPacket for SPlayerCommand {
|
||||
fn read(mut read: impl Read, version: &JavaMinecraftVersion) -> Result<Self, ReadingError> {
|
||||
impl<'a> ServerPacket<'a> for SPlayerCommand {
|
||||
fn read(read: &mut &'a [u8], version: &JavaMinecraftVersion) -> Result<Self, ReadingError> {
|
||||
let entity_id = read.get_var_int()?;
|
||||
let action_id = read.get_var_int()?;
|
||||
let jump_boost = read.get_var_int()?;
|
||||
|
||||
@ -5,15 +5,14 @@ use crate::{
|
||||
use pumpkin_data::packet::serverbound::PLAY_MOVE_PLAYER_STATUS_ONLY;
|
||||
use pumpkin_macros::java_packet;
|
||||
use pumpkin_util::version::JavaMinecraftVersion;
|
||||
use std::io::Read;
|
||||
|
||||
#[java_packet(PLAY_MOVE_PLAYER_STATUS_ONLY)]
|
||||
pub struct SSetPlayerGround {
|
||||
pub on_ground: bool,
|
||||
}
|
||||
|
||||
impl ServerPacket for SSetPlayerGround {
|
||||
fn read(mut bytebuf: impl Read, _version: &JavaMinecraftVersion) -> Result<Self, ReadingError> {
|
||||
impl<'a> ServerPacket<'a> for SSetPlayerGround {
|
||||
fn read(bytebuf: &mut &'a [u8], _version: &JavaMinecraftVersion) -> Result<Self, ReadingError> {
|
||||
Ok(Self {
|
||||
on_ground: bytebuf.get_bool()?,
|
||||
})
|
||||
|
||||
@ -5,7 +5,6 @@ use crate::{
|
||||
use pumpkin_data::packet::serverbound::PLAY_PLAYER_INPUT;
|
||||
use pumpkin_macros::java_packet;
|
||||
use pumpkin_util::version::JavaMinecraftVersion;
|
||||
use std::io::Read;
|
||||
|
||||
#[java_packet(PLAY_PLAYER_INPUT)]
|
||||
pub struct SPlayerInput {
|
||||
@ -23,8 +22,8 @@ impl SPlayerInput {
|
||||
pub const SPRINT: i8 = 64;
|
||||
}
|
||||
|
||||
impl ServerPacket for SPlayerInput {
|
||||
fn read(mut bytebuf: impl Read, _version: &JavaMinecraftVersion) -> Result<Self, ReadingError> {
|
||||
impl<'a> ServerPacket<'a> for SPlayerInput {
|
||||
fn read(bytebuf: &mut &'a [u8], _version: &JavaMinecraftVersion) -> Result<Self, ReadingError> {
|
||||
Ok(Self {
|
||||
input: bytebuf.get_i8()?,
|
||||
})
|
||||
|
||||
@ -2,14 +2,13 @@ use crate::{ServerPacket, ser::ReadingError};
|
||||
use pumpkin_data::packet::serverbound::PLAY_PLAYER_LOADED;
|
||||
use pumpkin_macros::java_packet;
|
||||
use pumpkin_util::version::JavaMinecraftVersion;
|
||||
use std::io::Read;
|
||||
|
||||
#[java_packet(PLAY_PLAYER_LOADED)]
|
||||
pub struct SPlayerLoaded;
|
||||
|
||||
impl ServerPacket for SPlayerLoaded {
|
||||
impl<'a> ServerPacket<'a> for SPlayerLoaded {
|
||||
fn read(
|
||||
_bytebuf: impl Read,
|
||||
_bytebuf: &mut &'a [u8],
|
||||
_protocol_version: &JavaMinecraftVersion,
|
||||
) -> Result<Self, ReadingError> {
|
||||
Ok(Self)
|
||||
|
||||
@ -7,7 +7,6 @@ use crate::{
|
||||
ser::{NetworkReadExt, ReadingError},
|
||||
};
|
||||
use pumpkin_util::version::JavaMinecraftVersion;
|
||||
use std::io::Read;
|
||||
|
||||
#[java_packet(PLAY_MOVE_PLAYER_POS)]
|
||||
pub struct SPlayerPosition {
|
||||
@ -16,8 +15,8 @@ pub struct SPlayerPosition {
|
||||
pub collision: u8,
|
||||
}
|
||||
|
||||
impl ServerPacket for SPlayerPosition {
|
||||
fn read(mut bytebuf: impl Read, _version: &JavaMinecraftVersion) -> Result<Self, ReadingError> {
|
||||
impl<'a> ServerPacket<'a> for SPlayerPosition {
|
||||
fn read(bytebuf: &mut &'a [u8], _version: &JavaMinecraftVersion) -> Result<Self, ReadingError> {
|
||||
Ok(Self {
|
||||
position: Vector3::new(
|
||||
bytebuf.get_f64_be()?,
|
||||
|
||||
@ -7,7 +7,6 @@ use crate::{
|
||||
ser::{NetworkReadExt, ReadingError},
|
||||
};
|
||||
use pumpkin_util::version::JavaMinecraftVersion;
|
||||
use std::io::Read;
|
||||
|
||||
pub const FLAG_ON_GROUND: u8 = 0x01;
|
||||
pub const FLAG_IN_WALL: u8 = 0x02;
|
||||
@ -21,8 +20,8 @@ pub struct SPlayerPositionRotation {
|
||||
pub collision: u8,
|
||||
}
|
||||
|
||||
impl ServerPacket for SPlayerPositionRotation {
|
||||
fn read(mut bytebuf: impl Read, _version: &JavaMinecraftVersion) -> Result<Self, ReadingError> {
|
||||
impl<'a> ServerPacket<'a> for SPlayerPositionRotation {
|
||||
fn read(bytebuf: &mut &'a [u8], _version: &JavaMinecraftVersion) -> Result<Self, ReadingError> {
|
||||
Ok(Self {
|
||||
position: Vector3::new(
|
||||
bytebuf.get_f64_be()?,
|
||||
|
||||
@ -5,7 +5,6 @@ use crate::{
|
||||
use pumpkin_data::packet::serverbound::PLAY_MOVE_PLAYER_ROT;
|
||||
use pumpkin_macros::java_packet;
|
||||
use pumpkin_util::version::JavaMinecraftVersion;
|
||||
use std::io::Read;
|
||||
|
||||
#[java_packet(PLAY_MOVE_PLAYER_ROT)]
|
||||
pub struct SPlayerRotation {
|
||||
@ -14,8 +13,8 @@ pub struct SPlayerRotation {
|
||||
pub ground: bool,
|
||||
}
|
||||
|
||||
impl ServerPacket for SPlayerRotation {
|
||||
fn read(mut bytebuf: impl Read, _version: &JavaMinecraftVersion) -> Result<Self, ReadingError> {
|
||||
impl<'a> ServerPacket<'a> for SPlayerRotation {
|
||||
fn read(bytebuf: &mut &'a [u8], _version: &JavaMinecraftVersion) -> Result<Self, ReadingError> {
|
||||
Ok(Self {
|
||||
yaw: bytebuf.get_f32_be()?,
|
||||
pitch: bytebuf.get_f32_be()?,
|
||||
|
||||
@ -1,5 +1,3 @@
|
||||
use std::io::Read;
|
||||
|
||||
use pumpkin_data::packet::serverbound::PLAY_CHAT_SESSION_UPDATE;
|
||||
use pumpkin_macros::java_packet;
|
||||
use pumpkin_util::version::JavaMinecraftVersion;
|
||||
@ -18,22 +16,24 @@ pub struct SPlayerSession {
|
||||
pub key_signature: Box<[u8]>,
|
||||
}
|
||||
|
||||
impl ServerPacket for SPlayerSession {
|
||||
fn read(mut read: impl Read, _version: &JavaMinecraftVersion) -> Result<Self, ReadingError> {
|
||||
impl<'a> ServerPacket<'a> for SPlayerSession {
|
||||
fn read(read: &mut &'a [u8], _version: &JavaMinecraftVersion) -> Result<Self, ReadingError> {
|
||||
let session_id = read.get_uuid()?;
|
||||
let expires_at = read.get_i64_be()?;
|
||||
|
||||
let public_key_length = read.get_var_int()?.0 as usize;
|
||||
let public_key = read.read_boxed_slice(public_key_length)?;
|
||||
let mut public_key = vec![0u8; public_key_length];
|
||||
read.read_bytes_to_buf(&mut public_key)?;
|
||||
|
||||
let key_signature_length = read.get_var_int()?.0 as usize;
|
||||
let key_signature = read.read_boxed_slice(key_signature_length)?;
|
||||
let mut key_signature = vec![0u8; key_signature_length];
|
||||
read.read_bytes_to_buf(&mut key_signature)?;
|
||||
|
||||
Ok(Self {
|
||||
session_id,
|
||||
expires_at,
|
||||
public_key,
|
||||
key_signature,
|
||||
public_key: public_key.into_boxed_slice(),
|
||||
key_signature: key_signature.into_boxed_slice(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@ -5,7 +5,6 @@ use crate::{
|
||||
use pumpkin_data::packet::serverbound::PLAY_RECIPE_BOOK_CHANGE_SETTINGS;
|
||||
use pumpkin_macros::java_packet;
|
||||
use pumpkin_util::version::JavaMinecraftVersion;
|
||||
use std::io::Read;
|
||||
|
||||
use crate::VarInt;
|
||||
|
||||
@ -16,8 +15,8 @@ pub struct SRecipeBookChangeSettings {
|
||||
pub is_filtering: bool,
|
||||
}
|
||||
|
||||
impl ServerPacket for SRecipeBookChangeSettings {
|
||||
fn read(mut bytebuf: impl Read, _version: &JavaMinecraftVersion) -> Result<Self, ReadingError> {
|
||||
impl<'a> ServerPacket<'a> for SRecipeBookChangeSettings {
|
||||
fn read(bytebuf: &mut &'a [u8], _version: &JavaMinecraftVersion) -> Result<Self, ReadingError> {
|
||||
Ok(Self {
|
||||
book_type: bytebuf.get_var_int()?,
|
||||
is_open: bytebuf.get_bool()?,
|
||||
|
||||
@ -5,7 +5,6 @@ use crate::{
|
||||
use pumpkin_data::packet::serverbound::PLAY_RECIPE_BOOK_SEEN_RECIPE;
|
||||
use pumpkin_macros::java_packet;
|
||||
use pumpkin_util::version::JavaMinecraftVersion;
|
||||
use std::io::Read;
|
||||
|
||||
use crate::VarInt;
|
||||
|
||||
@ -14,8 +13,8 @@ pub struct SRecipeBookSeenRecipe {
|
||||
pub recipe_display_id: VarInt,
|
||||
}
|
||||
|
||||
impl ServerPacket for SRecipeBookSeenRecipe {
|
||||
fn read(mut bytebuf: impl Read, _version: &JavaMinecraftVersion) -> Result<Self, ReadingError> {
|
||||
impl<'a> ServerPacket<'a> for SRecipeBookSeenRecipe {
|
||||
fn read(bytebuf: &mut &'a [u8], _version: &JavaMinecraftVersion) -> Result<Self, ReadingError> {
|
||||
Ok(Self {
|
||||
recipe_display_id: bytebuf.get_var_int()?,
|
||||
})
|
||||
|
||||
@ -1,22 +1,21 @@
|
||||
use crate::{
|
||||
ServerPacket,
|
||||
ser::{NetworkReadExt, ReadingError},
|
||||
ser::{NetworkReadSliceExt, ReadingError},
|
||||
};
|
||||
use pumpkin_data::packet::serverbound::PLAY_RENAME_ITEM;
|
||||
use pumpkin_macros::java_packet;
|
||||
use pumpkin_util::version::JavaMinecraftVersion;
|
||||
use std::io::Read;
|
||||
|
||||
#[derive(Debug)]
|
||||
#[java_packet(PLAY_RENAME_ITEM)]
|
||||
pub struct SRenameItem {
|
||||
pub item_name: String,
|
||||
pub struct SRenameItem<'a> {
|
||||
pub item_name: &'a str,
|
||||
}
|
||||
|
||||
impl ServerPacket for SRenameItem {
|
||||
fn read(mut bytebuf: impl Read, _version: &JavaMinecraftVersion) -> Result<Self, ReadingError> {
|
||||
impl<'a> ServerPacket<'a> for SRenameItem<'a> {
|
||||
fn read(bytebuf: &mut &'a [u8], _version: &JavaMinecraftVersion) -> Result<Self, ReadingError> {
|
||||
Ok(Self {
|
||||
item_name: bytebuf.get_str_bounded(32767)?.into_string(),
|
||||
item_name: bytebuf.get_str_bounded_borrowed(32767)?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,12 +1,11 @@
|
||||
use crate::{
|
||||
ServerPacket,
|
||||
ser::{NetworkReadExt, ReadingError},
|
||||
ser::{NetworkReadExt, NetworkReadSliceExt, ReadingError},
|
||||
};
|
||||
use pumpkin_data::packet::serverbound::PLAY_SEEN_ADVANCEMENTS;
|
||||
use pumpkin_macros::java_packet;
|
||||
use pumpkin_util::identifier::Identifier;
|
||||
use pumpkin_util::version::JavaMinecraftVersion;
|
||||
use std::io::Read;
|
||||
|
||||
#[derive(Debug)]
|
||||
#[java_packet(PLAY_SEEN_ADVANCEMENTS)]
|
||||
@ -15,14 +14,14 @@ pub enum SSeenAdvancement {
|
||||
CloseTab,
|
||||
}
|
||||
|
||||
impl ServerPacket for SSeenAdvancement {
|
||||
fn read(mut bytebuf: impl Read, _version: &JavaMinecraftVersion) -> Result<Self, ReadingError> {
|
||||
impl<'a> ServerPacket<'a> for SSeenAdvancement {
|
||||
fn read(bytebuf: &mut &'a [u8], _version: &JavaMinecraftVersion) -> Result<Self, ReadingError> {
|
||||
let action = bytebuf.get_var_int()?;
|
||||
match action.0 {
|
||||
0 => {
|
||||
let id_str = bytebuf.get_str()?;
|
||||
let id_str = bytebuf.get_str_borrowed()?;
|
||||
let id =
|
||||
Identifier::parse(&id_str).map_err(|e| ReadingError::Message(e.to_string()))?;
|
||||
Identifier::parse(id_str).map_err(|e| ReadingError::Message(e.to_string()))?;
|
||||
Ok(Self::OpenTab(id))
|
||||
}
|
||||
1 => Ok(Self::CloseTab),
|
||||
|
||||
@ -8,15 +8,14 @@ use crate::{
|
||||
ser::{NetworkReadExt, ReadingError},
|
||||
};
|
||||
use pumpkin_util::version::JavaMinecraftVersion;
|
||||
use std::io::Read;
|
||||
|
||||
#[java_packet(PLAY_SELECT_TRADE)]
|
||||
pub struct SSelectTrade {
|
||||
pub selected_slot: VarInt,
|
||||
}
|
||||
|
||||
impl ServerPacket for SSelectTrade {
|
||||
fn read(mut bytebuf: impl Read, _version: &JavaMinecraftVersion) -> Result<Self, ReadingError> {
|
||||
impl<'a> ServerPacket<'a> for SSelectTrade {
|
||||
fn read(bytebuf: &mut &'a [u8], _version: &JavaMinecraftVersion) -> Result<Self, ReadingError> {
|
||||
Ok(Self {
|
||||
selected_slot: bytebuf.get_var_int()?,
|
||||
})
|
||||
|
||||
@ -5,7 +5,6 @@ use crate::{
|
||||
use pumpkin_data::packet::serverbound::PLAY_SET_BEACON;
|
||||
use pumpkin_macros::java_packet;
|
||||
use pumpkin_util::version::JavaMinecraftVersion;
|
||||
use std::io::Read;
|
||||
|
||||
use crate::codec::var_int::VarInt;
|
||||
|
||||
@ -15,8 +14,8 @@ pub struct SSetBeacon {
|
||||
pub secondary_effect: Option<VarInt>,
|
||||
}
|
||||
|
||||
impl ServerPacket for SSetBeacon {
|
||||
fn read(mut bytebuf: impl Read, _version: &JavaMinecraftVersion) -> Result<Self, ReadingError> {
|
||||
impl<'a> ServerPacket<'a> for SSetBeacon {
|
||||
fn read(bytebuf: &mut &'a [u8], _version: &JavaMinecraftVersion) -> Result<Self, ReadingError> {
|
||||
Ok(Self {
|
||||
primary_effect: bytebuf.get_option(NetworkReadExt::get_var_int)?,
|
||||
secondary_effect: bytebuf.get_option(NetworkReadExt::get_var_int)?,
|
||||
|
||||
@ -1,19 +1,18 @@
|
||||
use crate::{
|
||||
ServerPacket,
|
||||
ser::{NetworkReadExt, ReadingError},
|
||||
ser::{NetworkReadExt, NetworkReadSliceExt, ReadingError},
|
||||
};
|
||||
use pumpkin_data::packet::serverbound::PLAY_SET_COMMAND_BLOCK;
|
||||
use pumpkin_macros::java_packet;
|
||||
use pumpkin_util::math::position::BlockPos;
|
||||
use pumpkin_util::version::JavaMinecraftVersion;
|
||||
use std::io::Read;
|
||||
|
||||
use crate::codec::var_int::VarInt;
|
||||
|
||||
#[java_packet(PLAY_SET_COMMAND_BLOCK)]
|
||||
pub struct SSetCommandBlock {
|
||||
pub struct SSetCommandBlock<'a> {
|
||||
pub pos: BlockPos,
|
||||
pub command: String,
|
||||
pub command: &'a str,
|
||||
pub mode: VarInt,
|
||||
|
||||
/// Operation mode flags
|
||||
@ -23,11 +22,11 @@ pub struct SSetCommandBlock {
|
||||
pub flags: i8,
|
||||
}
|
||||
|
||||
impl ServerPacket for SSetCommandBlock {
|
||||
fn read(mut bytebuf: impl Read, _version: &JavaMinecraftVersion) -> Result<Self, ReadingError> {
|
||||
impl<'a> ServerPacket<'a> for SSetCommandBlock<'a> {
|
||||
fn read(bytebuf: &mut &'a [u8], _version: &JavaMinecraftVersion) -> Result<Self, ReadingError> {
|
||||
Ok(Self {
|
||||
pos: BlockPos::from_i64(bytebuf.get_i64_be()?),
|
||||
command: bytebuf.get_str_bounded(32767)?.into_string(),
|
||||
command: bytebuf.get_str_bounded_borrowed(32767)?,
|
||||
mode: bytebuf.get_var_int()?,
|
||||
flags: bytebuf.get_i8()?,
|
||||
})
|
||||
|
||||
@ -14,9 +14,9 @@ pub struct SSetCreativeSlot {
|
||||
pub clicked_item: ItemStackSerializer<'static>,
|
||||
}
|
||||
|
||||
impl ServerPacket for SSetCreativeSlot {
|
||||
impl<'a> ServerPacket<'a> for SSetCreativeSlot {
|
||||
fn read(
|
||||
mut read: impl std::io::Read,
|
||||
mut read: &mut &'a [u8],
|
||||
_version: &JavaMinecraftVersion,
|
||||
) -> Result<Self, ReadingError> {
|
||||
let slot = read.get_i16_be()?;
|
||||
|
||||
@ -5,15 +5,14 @@ use crate::{
|
||||
use pumpkin_data::packet::serverbound::PLAY_SET_CARRIED_ITEM;
|
||||
use pumpkin_macros::java_packet;
|
||||
use pumpkin_util::version::JavaMinecraftVersion;
|
||||
use std::io::Read;
|
||||
|
||||
#[java_packet(PLAY_SET_CARRIED_ITEM)]
|
||||
pub struct SSetHeldItem {
|
||||
pub slot: i16,
|
||||
}
|
||||
|
||||
impl ServerPacket for SSetHeldItem {
|
||||
fn read(mut bytebuf: impl Read, _version: &JavaMinecraftVersion) -> Result<Self, ReadingError> {
|
||||
impl<'a> ServerPacket<'a> for SSetHeldItem {
|
||||
fn read(bytebuf: &mut &'a [u8], _version: &JavaMinecraftVersion) -> Result<Self, ReadingError> {
|
||||
Ok(Self {
|
||||
slot: bytebuf.get_i16_be()?,
|
||||
})
|
||||
|
||||
@ -1,36 +1,35 @@
|
||||
use crate::{
|
||||
ServerPacket,
|
||||
ser::{NetworkReadExt, ReadingError},
|
||||
ser::{NetworkReadExt, NetworkReadSliceExt, ReadingError},
|
||||
};
|
||||
use pumpkin_data::packet::serverbound::PLAY_SET_JIGSAW_BLOCK;
|
||||
use pumpkin_macros::java_packet;
|
||||
use pumpkin_util::math::position::BlockPos;
|
||||
use pumpkin_util::version::JavaMinecraftVersion;
|
||||
use std::io::Read;
|
||||
|
||||
use crate::codec::var_int::VarInt;
|
||||
|
||||
#[java_packet(PLAY_SET_JIGSAW_BLOCK)]
|
||||
pub struct SSetJigsawBlock {
|
||||
pub struct SSetJigsawBlock<'a> {
|
||||
pub pos: BlockPos,
|
||||
pub name: String,
|
||||
pub target: String,
|
||||
pub pool: String,
|
||||
pub final_state: String,
|
||||
pub joint: String,
|
||||
pub name: &'a str,
|
||||
pub target: &'a str,
|
||||
pub pool: &'a str,
|
||||
pub final_state: &'a str,
|
||||
pub joint: &'a str,
|
||||
pub selection_priority: VarInt,
|
||||
pub placement_priority: VarInt,
|
||||
}
|
||||
|
||||
impl ServerPacket for SSetJigsawBlock {
|
||||
fn read(mut bytebuf: impl Read, _version: &JavaMinecraftVersion) -> Result<Self, ReadingError> {
|
||||
impl<'a> ServerPacket<'a> for SSetJigsawBlock<'a> {
|
||||
fn read(bytebuf: &mut &'a [u8], _version: &JavaMinecraftVersion) -> Result<Self, ReadingError> {
|
||||
Ok(Self {
|
||||
pos: BlockPos::from_i64(bytebuf.get_i64_be()?),
|
||||
name: bytebuf.get_str_bounded(32767)?.into_string(),
|
||||
target: bytebuf.get_str_bounded(32767)?.into_string(),
|
||||
pool: bytebuf.get_str_bounded(32767)?.into_string(),
|
||||
final_state: bytebuf.get_str_bounded(32767)?.into_string(),
|
||||
joint: bytebuf.get_str_bounded(32767)?.into_string(),
|
||||
name: bytebuf.get_str_bounded_borrowed(32767)?,
|
||||
target: bytebuf.get_str_bounded_borrowed(32767)?,
|
||||
pool: bytebuf.get_str_bounded_borrowed(32767)?,
|
||||
final_state: bytebuf.get_str_bounded_borrowed(32767)?,
|
||||
joint: bytebuf.get_str_bounded_borrowed(32767)?,
|
||||
selection_priority: bytebuf.get_var_int()?,
|
||||
placement_priority: bytebuf.get_var_int()?,
|
||||
})
|
||||
|
||||
@ -4,24 +4,27 @@ use pumpkin_util::math::position::BlockPos;
|
||||
|
||||
use crate::{
|
||||
ServerPacket,
|
||||
ser::{NetworkReadExt, ReadingError},
|
||||
ser::{NetworkReadExt, NetworkReadSliceExt, ReadingError},
|
||||
};
|
||||
use pumpkin_util::version::JavaMinecraftVersion;
|
||||
use std::io::Read;
|
||||
|
||||
#[java_packet(PLAY_SET_TEST_BLOCK)]
|
||||
pub struct SSetTestBlock {
|
||||
pub struct SSetTestBlock<'a> {
|
||||
pub position: BlockPos,
|
||||
pub mode: TestBlockMode,
|
||||
pub message: String,
|
||||
pub message: &'a str,
|
||||
}
|
||||
|
||||
impl ServerPacket for SSetTestBlock {
|
||||
fn read(mut bytebuf: impl Read, _version: &JavaMinecraftVersion) -> Result<Self, ReadingError> {
|
||||
impl<'a> ServerPacket<'a> for SSetTestBlock<'a> {
|
||||
fn read(
|
||||
mut bytebuf: &mut &'a [u8],
|
||||
_version: &JavaMinecraftVersion,
|
||||
) -> Result<Self, ReadingError> {
|
||||
Ok(Self {
|
||||
position: BlockPos::from_i64(bytebuf.get_i64_be()?),
|
||||
mode: TestBlockMode::read(&mut bytebuf)?,
|
||||
message: bytebuf.get_str()?.into_string(),
|
||||
message: bytebuf.get_str_borrowed()?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@ -5,7 +5,6 @@ use crate::{
|
||||
use pumpkin_data::packet::serverbound::PLAY_SWING;
|
||||
use pumpkin_macros::java_packet;
|
||||
use pumpkin_util::version::JavaMinecraftVersion;
|
||||
use std::io::Read;
|
||||
|
||||
use crate::VarInt;
|
||||
|
||||
@ -14,8 +13,8 @@ pub struct SSwingArm {
|
||||
pub hand: VarInt,
|
||||
}
|
||||
|
||||
impl ServerPacket for SSwingArm {
|
||||
fn read(mut bytebuf: impl Read, _version: &JavaMinecraftVersion) -> Result<Self, ReadingError> {
|
||||
impl<'a> ServerPacket<'a> for SSwingArm {
|
||||
fn read(bytebuf: &mut &'a [u8], _version: &JavaMinecraftVersion) -> Result<Self, ReadingError> {
|
||||
Ok(Self {
|
||||
hand: bytebuf.get_var_int()?,
|
||||
})
|
||||
|
||||
@ -5,16 +5,15 @@ use crate::{
|
||||
use pumpkin_data::packet::serverbound::PLAY_TELEPORT_TO_ENTITY;
|
||||
use pumpkin_macros::java_packet;
|
||||
use pumpkin_util::version::JavaMinecraftVersion;
|
||||
use std::io::Read;
|
||||
|
||||
#[java_packet(PLAY_TELEPORT_TO_ENTITY)]
|
||||
pub struct STeleportToEntity {
|
||||
pub target: uuid::Uuid,
|
||||
}
|
||||
|
||||
impl ServerPacket for STeleportToEntity {
|
||||
impl<'a> ServerPacket<'a> for STeleportToEntity {
|
||||
fn read(
|
||||
mut bytebuf: impl Read,
|
||||
bytebuf: &mut &'a [u8],
|
||||
_protocol_version: &JavaMinecraftVersion,
|
||||
) -> Result<Self, ReadingError> {
|
||||
Ok(Self {
|
||||
|
||||
@ -12,18 +12,18 @@ use pumpkin_util::version::JavaMinecraftVersion;
|
||||
use std::io::Read;
|
||||
|
||||
#[java_packet(PLAY_TEST_INSTANCE_BLOCK_ACTION)]
|
||||
pub struct STestInstanceBlockAction {
|
||||
pub struct STestInstanceBlockAction<'a> {
|
||||
pub pos: BlockPos,
|
||||
pub action: TestInstanceBlockAction,
|
||||
pub data: TestInstanceBlockData,
|
||||
pub data: TestInstanceBlockData<'a>,
|
||||
}
|
||||
|
||||
impl ServerPacket for STestInstanceBlockAction {
|
||||
fn read(mut bytebuf: impl Read, _version: &JavaMinecraftVersion) -> Result<Self, ReadingError> {
|
||||
impl<'a> ServerPacket<'a> for STestInstanceBlockAction<'a> {
|
||||
fn read(bytebuf: &mut &'a [u8], _version: &JavaMinecraftVersion) -> Result<Self, ReadingError> {
|
||||
Ok(Self {
|
||||
pos: BlockPos::from_i64(bytebuf.get_i64_be()?),
|
||||
action: TestInstanceBlockAction::read(&mut bytebuf)?,
|
||||
data: TestInstanceBlockData::read(&mut bytebuf)?,
|
||||
action: TestInstanceBlockAction::read(bytebuf)?,
|
||||
data: TestInstanceBlockData::read(bytebuf)?,
|
||||
})
|
||||
}
|
||||
}
|
||||
@ -72,18 +72,18 @@ impl VarIntVector3 {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct TestInstanceBlockData {
|
||||
pub test: Option<String>,
|
||||
pub struct TestInstanceBlockData<'a> {
|
||||
pub test: Option<&'a str>,
|
||||
pub size: VarIntVector3,
|
||||
pub rotation: pumpkin_data::block_rotation::Rotation,
|
||||
pub ignore_entities: bool,
|
||||
pub status: TestInstanceBlockStatus,
|
||||
pub error_message: Option<String>,
|
||||
pub error_message: Option<&'a str>,
|
||||
}
|
||||
|
||||
impl TestInstanceBlockData {
|
||||
fn read(bytebuf: &mut impl Read) -> Result<Self, ReadingError> {
|
||||
let test = bytebuf.get_option(|b| b.get_str().map(String::from))?;
|
||||
impl<'a> TestInstanceBlockData<'a> {
|
||||
fn read(bytebuf: &mut &'a [u8]) -> Result<Self, ReadingError> {
|
||||
let test = bytebuf.get_option(crate::ser::NetworkReadSliceExt::get_str_borrowed)?;
|
||||
let size = VarIntVector3::read(bytebuf)?;
|
||||
let rotation = match bytebuf.get_var_int()?.0 {
|
||||
0 => pumpkin_data::block_rotation::Rotation::None,
|
||||
@ -104,7 +104,8 @@ impl TestInstanceBlockData {
|
||||
));
|
||||
}
|
||||
};
|
||||
let error_message = bytebuf.get_option(|b| b.get_str().map(String::from))?;
|
||||
let error_message =
|
||||
bytebuf.get_option(crate::ser::NetworkReadSliceExt::get_str_borrowed)?;
|
||||
|
||||
Ok(Self {
|
||||
test,
|
||||
|
||||
@ -1,35 +1,33 @@
|
||||
use std::io::Read;
|
||||
|
||||
use pumpkin_data::packet::serverbound::PLAY_SIGN_UPDATE;
|
||||
use pumpkin_macros::java_packet;
|
||||
use pumpkin_util::{math::position::BlockPos, version::JavaMinecraftVersion};
|
||||
|
||||
use crate::{
|
||||
ServerPacket,
|
||||
ser::{NetworkReadExt, ReadingError},
|
||||
ser::{NetworkReadExt, NetworkReadSliceExt, ReadingError},
|
||||
};
|
||||
|
||||
#[java_packet(PLAY_SIGN_UPDATE)]
|
||||
pub struct SUpdateSign {
|
||||
pub struct SUpdateSign<'a> {
|
||||
pub location: BlockPos,
|
||||
pub is_front_text: bool,
|
||||
pub line_1: Box<str>,
|
||||
pub line_2: Box<str>,
|
||||
pub line_3: Box<str>,
|
||||
pub line_4: Box<str>,
|
||||
pub line_1: &'a str,
|
||||
pub line_2: &'a str,
|
||||
pub line_3: &'a str,
|
||||
pub line_4: &'a str,
|
||||
}
|
||||
|
||||
const MAX_LINE_LENGTH: usize = 386;
|
||||
|
||||
impl ServerPacket for SUpdateSign {
|
||||
fn read(mut read: impl Read, _version: &JavaMinecraftVersion) -> Result<Self, ReadingError> {
|
||||
impl<'a> ServerPacket<'a> for SUpdateSign<'a> {
|
||||
fn read(read: &mut &'a [u8], _version: &JavaMinecraftVersion) -> Result<Self, ReadingError> {
|
||||
Ok(Self {
|
||||
location: BlockPos::from_i64(read.get_i64_be()?),
|
||||
is_front_text: read.get_bool()?,
|
||||
line_1: read.get_str_bounded(MAX_LINE_LENGTH)?,
|
||||
line_2: read.get_str_bounded(MAX_LINE_LENGTH)?,
|
||||
line_3: read.get_str_bounded(MAX_LINE_LENGTH)?,
|
||||
line_4: read.get_str_bounded(MAX_LINE_LENGTH)?,
|
||||
line_1: read.get_str_bounded_borrowed(MAX_LINE_LENGTH)?,
|
||||
line_2: read.get_str_bounded_borrowed(MAX_LINE_LENGTH)?,
|
||||
line_3: read.get_str_bounded_borrowed(MAX_LINE_LENGTH)?,
|
||||
line_4: read.get_str_bounded_borrowed(MAX_LINE_LENGTH)?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@ -5,7 +5,6 @@ use crate::{
|
||||
use pumpkin_data::packet::serverbound::PLAY_USE_ITEM;
|
||||
use pumpkin_macros::java_packet;
|
||||
use pumpkin_util::version::JavaMinecraftVersion;
|
||||
use std::io::Read;
|
||||
|
||||
use crate::VarInt;
|
||||
|
||||
@ -18,9 +17,9 @@ pub struct SUseItem {
|
||||
pub pitch: f32,
|
||||
}
|
||||
|
||||
impl ServerPacket for SUseItem {
|
||||
impl<'a> ServerPacket<'a> for SUseItem {
|
||||
fn read(
|
||||
mut bytebuf: impl Read,
|
||||
bytebuf: &mut &'a [u8],
|
||||
_protocol_version: &JavaMinecraftVersion,
|
||||
) -> Result<Self, ReadingError> {
|
||||
Ok(Self {
|
||||
|
||||
@ -6,7 +6,6 @@ use pumpkin_data::packet::serverbound::PLAY_USE_ITEM_ON;
|
||||
use pumpkin_macros::java_packet;
|
||||
use pumpkin_util::math::{position::BlockPos, vector3::Vector3};
|
||||
use pumpkin_util::version::JavaMinecraftVersion;
|
||||
use std::io::Read;
|
||||
|
||||
use crate::VarInt;
|
||||
|
||||
@ -21,8 +20,8 @@ pub struct SUseItemOn {
|
||||
pub sequence: VarInt,
|
||||
}
|
||||
|
||||
impl ServerPacket for SUseItemOn {
|
||||
fn read(mut bytebuf: impl Read, _version: &JavaMinecraftVersion) -> Result<Self, ReadingError> {
|
||||
impl<'a> ServerPacket<'a> for SUseItemOn {
|
||||
fn read(bytebuf: &mut &'a [u8], _version: &JavaMinecraftVersion) -> Result<Self, ReadingError> {
|
||||
Ok(Self {
|
||||
hand: bytebuf.get_var_int()?,
|
||||
position: BlockPos::from_i64(bytebuf.get_i64_be()?),
|
||||
|
||||
@ -5,7 +5,6 @@ use crate::{
|
||||
use pumpkin_data::packet::serverbound::STATUS_PING_REQUEST;
|
||||
use pumpkin_macros::java_packet;
|
||||
use pumpkin_util::version::JavaMinecraftVersion;
|
||||
use std::io::Read;
|
||||
|
||||
/// Sent by the client to measure the round-trip time (latency) to the server.
|
||||
///
|
||||
@ -16,9 +15,9 @@ pub struct SStatusPingRequest {
|
||||
pub payload: i64,
|
||||
}
|
||||
|
||||
impl ServerPacket for SStatusPingRequest {
|
||||
impl<'a> ServerPacket<'a> for SStatusPingRequest {
|
||||
fn read(
|
||||
mut bytebuf: impl Read,
|
||||
bytebuf: &mut &'a [u8],
|
||||
_protocol_version: &JavaMinecraftVersion,
|
||||
) -> Result<Self, ReadingError> {
|
||||
Ok(Self {
|
||||
|
||||
@ -2,7 +2,6 @@ use crate::{ServerPacket, ser::ReadingError};
|
||||
use pumpkin_data::packet::serverbound::STATUS_STATUS_REQUEST;
|
||||
use pumpkin_macros::java_packet;
|
||||
use pumpkin_util::version::JavaMinecraftVersion;
|
||||
use std::io::Read;
|
||||
|
||||
/// Sent by the client to request the server's current status information.
|
||||
///
|
||||
@ -11,9 +10,9 @@ use std::io::Read;
|
||||
#[java_packet(STATUS_STATUS_REQUEST)]
|
||||
pub struct SStatusRequest;
|
||||
|
||||
impl ServerPacket for SStatusRequest {
|
||||
impl<'a> ServerPacket<'a> for SStatusRequest {
|
||||
fn read(
|
||||
_bytebuf: impl Read,
|
||||
_bytebuf: &mut &'a [u8],
|
||||
_protocol_version: &JavaMinecraftVersion,
|
||||
) -> Result<Self, ReadingError> {
|
||||
Ok(Self)
|
||||
|
||||
@ -253,8 +253,8 @@ pub trait ClientPacket: MultiVersionJavaPacket {
|
||||
) -> Result<(), WritingError>;
|
||||
}
|
||||
|
||||
pub trait ServerPacket: MultiVersionJavaPacket + Sized {
|
||||
fn read(read: impl Read, version: &JavaMinecraftVersion) -> Result<Self, ReadingError>;
|
||||
pub trait ServerPacket<'a>: MultiVersionJavaPacket + Sized {
|
||||
fn read(read: &mut &'a [u8], version: &JavaMinecraftVersion) -> Result<Self, ReadingError>;
|
||||
}
|
||||
|
||||
pub trait BClientPacket: Packet {
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
use core::str;
|
||||
use std::borrow::Cow;
|
||||
use std::io::{Read, Write};
|
||||
|
||||
use crate::{
|
||||
@ -61,34 +62,40 @@ pub trait NetworkReadExt {
|
||||
fn get_i128_be(&mut self) -> Result<i128, ReadingError>;
|
||||
fn get_u128_be(&mut self) -> Result<u128, ReadingError>;
|
||||
|
||||
#[inline]
|
||||
fn get_i16(&mut self) -> Result<i16, ReadingError> {
|
||||
self.get_i16_be()
|
||||
}
|
||||
#[inline]
|
||||
fn get_u16(&mut self) -> Result<u16, ReadingError> {
|
||||
self.get_u16_be()
|
||||
}
|
||||
#[inline]
|
||||
fn get_i32(&mut self) -> Result<i32, ReadingError> {
|
||||
self.get_i32_be()
|
||||
}
|
||||
#[inline]
|
||||
fn get_u32(&mut self) -> Result<u32, ReadingError> {
|
||||
self.get_u32_be()
|
||||
}
|
||||
#[inline]
|
||||
fn get_i64(&mut self) -> Result<i64, ReadingError> {
|
||||
self.get_i64_be()
|
||||
}
|
||||
#[inline]
|
||||
fn get_u64(&mut self) -> Result<u64, ReadingError> {
|
||||
self.get_u64_be()
|
||||
}
|
||||
#[inline]
|
||||
fn get_f32(&mut self) -> Result<f32, ReadingError> {
|
||||
self.get_f32_be()
|
||||
}
|
||||
#[inline]
|
||||
fn get_f64(&mut self) -> Result<f64, ReadingError> {
|
||||
self.get_f64_be()
|
||||
}
|
||||
|
||||
fn read_boxed_slice(&mut self, count: usize) -> Result<Box<[u8]>, ReadingError>;
|
||||
|
||||
fn read_remaining_to_boxed_slice(&mut self, bound: usize) -> Result<Box<[u8]>, ReadingError>;
|
||||
fn read_bytes_to_buf(&mut self, buf: &mut [u8]) -> Result<(), ReadingError>;
|
||||
|
||||
fn get_bool(&mut self) -> Result<bool, ReadingError>;
|
||||
fn get_var_int(&mut self) -> Result<VarInt, ReadingError>;
|
||||
@ -96,23 +103,154 @@ pub trait NetworkReadExt {
|
||||
fn get_var_long(&mut self) -> Result<VarLong, ReadingError>;
|
||||
fn get_var_ulong(&mut self) -> Result<VarULong, ReadingError>;
|
||||
fn get_str_bounded(&mut self, bound: usize) -> Result<Box<str>, ReadingError>;
|
||||
fn get_str(&mut self) -> Result<Box<str>, ReadingError>;
|
||||
#[inline]
|
||||
fn get_str(&mut self) -> Result<Box<str>, ReadingError> {
|
||||
self.get_str_bounded(i32::MAX as usize)
|
||||
}
|
||||
fn get_uuid(&mut self) -> Result<uuid::Uuid, ReadingError>;
|
||||
fn get_fixed_bitset(&mut self, bits: usize) -> Result<FixedBitSet, ReadingError>;
|
||||
|
||||
#[inline]
|
||||
fn get_option<G>(
|
||||
&mut self,
|
||||
parse: impl FnOnce(&mut Self) -> Result<G, ReadingError>,
|
||||
) -> Result<Option<G>, ReadingError>;
|
||||
) -> Result<Option<G>, ReadingError> {
|
||||
if self.get_bool()? {
|
||||
Ok(Some(parse(self)?))
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn get_list<G>(
|
||||
&mut self,
|
||||
parse: impl Fn(&mut Self) -> Result<G, ReadingError>,
|
||||
) -> Result<Vec<G>, ReadingError>;
|
||||
) -> Result<Vec<G>, ReadingError> {
|
||||
const MAX_LIST_SIZE: usize = 65536;
|
||||
|
||||
let len = self.get_var_int()?.0 as usize;
|
||||
if len > MAX_LIST_SIZE {
|
||||
return Err(ReadingError::TooLarge(format!(
|
||||
"List length {len} exceeds limit"
|
||||
)));
|
||||
}
|
||||
let mut list = Vec::with_capacity(len);
|
||||
for _ in 0..len {
|
||||
list.push(parse(self)?);
|
||||
}
|
||||
Ok(list)
|
||||
}
|
||||
}
|
||||
|
||||
pub trait NetworkReadSliceExt<'a> {
|
||||
fn get_str_borrowed(&mut self) -> Result<&'a str, ReadingError>;
|
||||
fn get_str_bounded_borrowed(&mut self, bound: usize) -> Result<&'a str, ReadingError>;
|
||||
fn read_slice_borrowed(&mut self, count: usize) -> Result<&'a [u8], ReadingError>;
|
||||
fn read_remaining_slice_borrowed(&mut self, bound: usize) -> Result<&'a [u8], ReadingError>;
|
||||
|
||||
#[inline]
|
||||
fn read_cow_slice_borrowed(&mut self, count: usize) -> Result<Cow<'a, [u8]>, ReadingError> {
|
||||
Ok(Cow::Borrowed(self.read_slice_borrowed(count)?))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn read_remaining_to_cow_slice_borrowed(
|
||||
&mut self,
|
||||
bound: usize,
|
||||
) -> Result<Cow<'a, [u8]>, ReadingError> {
|
||||
Ok(Cow::Borrowed(self.read_remaining_slice_borrowed(bound)?))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn get_cow_str_borrowed(&mut self) -> Result<Cow<'a, str>, ReadingError> {
|
||||
self.get_cow_str_bounded_borrowed(i32::MAX as usize)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn get_cow_str_bounded_borrowed(&mut self, bound: usize) -> Result<Cow<'a, str>, ReadingError> {
|
||||
Ok(Cow::Borrowed(self.get_str_bounded_borrowed(bound)?))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> NetworkReadSliceExt<'a> for &'a [u8] {
|
||||
#[inline]
|
||||
fn read_slice_borrowed(&mut self, count: usize) -> Result<&'a [u8], ReadingError> {
|
||||
if self.len() < count {
|
||||
return Err(ReadingError::Incomplete(format!(
|
||||
"EOF, Tried to read {count} bytes but only {} bytes left",
|
||||
self.len()
|
||||
)));
|
||||
}
|
||||
let (head, tail) = self.split_at(count);
|
||||
*self = tail;
|
||||
Ok(head)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn read_remaining_slice_borrowed(&mut self, bound: usize) -> Result<&'a [u8], ReadingError> {
|
||||
if self.len() > bound {
|
||||
return Err(ReadingError::TooLarge(
|
||||
"Read remaining too long".to_string(),
|
||||
));
|
||||
}
|
||||
let slice = *self;
|
||||
*self = &[];
|
||||
Ok(slice)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn get_str_bounded_borrowed(&mut self, bound: usize) -> Result<&'a str, ReadingError> {
|
||||
let bytes_len = self.get_var_uint()?.0 as usize;
|
||||
|
||||
let maximum_utf8_bytes = bound.saturating_mul(3);
|
||||
if bytes_len > maximum_utf8_bytes {
|
||||
return Err(ReadingError::TooLarge(format!(
|
||||
"string has too many bytes ({bytes_len} > {maximum_utf8_bytes})"
|
||||
)));
|
||||
}
|
||||
|
||||
let bytes = self.read_slice_borrowed(bytes_len)?;
|
||||
let string =
|
||||
std::str::from_utf8(bytes).map_err(|e| ReadingError::Message(e.to_string()))?;
|
||||
|
||||
if string.encode_utf16().nth(bound).is_some() {
|
||||
return Err(ReadingError::TooLarge(format!(
|
||||
"string has too many UTF-16 characters (more than the maximum limit {bound})"
|
||||
)));
|
||||
}
|
||||
|
||||
Ok(string)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn get_str_borrowed(&mut self) -> Result<&'a str, ReadingError> {
|
||||
self.get_str_bounded_borrowed(i32::MAX as usize)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, R: NetworkReadSliceExt<'a> + ?Sized> NetworkReadSliceExt<'a> for &mut R {
|
||||
#[inline]
|
||||
fn get_str_borrowed(&mut self) -> Result<&'a str, ReadingError> {
|
||||
(**self).get_str_borrowed()
|
||||
}
|
||||
#[inline]
|
||||
fn get_str_bounded_borrowed(&mut self, bound: usize) -> Result<&'a str, ReadingError> {
|
||||
(**self).get_str_bounded_borrowed(bound)
|
||||
}
|
||||
#[inline]
|
||||
fn read_slice_borrowed(&mut self, count: usize) -> Result<&'a [u8], ReadingError> {
|
||||
(**self).read_slice_borrowed(count)
|
||||
}
|
||||
#[inline]
|
||||
fn read_remaining_slice_borrowed(&mut self, bound: usize) -> Result<&'a [u8], ReadingError> {
|
||||
(**self).read_remaining_slice_borrowed(bound)
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! get_number_be {
|
||||
($name:ident, $type:ty) => {
|
||||
#[inline]
|
||||
fn $name(&mut self) -> Result<$type, ReadingError> {
|
||||
let mut buf = [0u8; std::mem::size_of::<$type>()];
|
||||
self.read_exact(&mut buf)
|
||||
@ -137,58 +275,38 @@ impl<R: Read> NetworkReadExt for R {
|
||||
get_number_be!(get_f32_be, f32);
|
||||
get_number_be!(get_f64_be, f64);
|
||||
|
||||
fn read_boxed_slice(&mut self, length: usize) -> Result<Box<[u8]>, ReadingError> {
|
||||
// Increase this to at least 2MB to handle larger Bedrock batches
|
||||
const MAX_SLICE_LENGTH: usize = 2 * 1024 * 1024; // 2MB
|
||||
if !(0..=MAX_SLICE_LENGTH).contains(&length) {
|
||||
return Err(ReadingError::Message(format!(
|
||||
"read_boxed_slice: length {length} out of bounds"
|
||||
)));
|
||||
}
|
||||
let mut buf = vec![0u8; length];
|
||||
self.read_exact(&mut buf)
|
||||
.map_err(|err| ReadingError::Incomplete(err.to_string()))?;
|
||||
|
||||
Ok(buf.into())
|
||||
}
|
||||
|
||||
fn read_remaining_to_boxed_slice(&mut self, bound: usize) -> Result<Box<[u8]>, ReadingError> {
|
||||
let mut return_buf = Vec::new();
|
||||
|
||||
// Take one extra byte to check for exceeding bound
|
||||
self.take(bound as u64 + 1)
|
||||
.read_to_end(&mut return_buf)
|
||||
.map_err(|err| ReadingError::Incomplete(err.to_string()))?;
|
||||
|
||||
if return_buf.len() > bound {
|
||||
return Err(ReadingError::TooLarge(
|
||||
"Read remaining too long".to_string(),
|
||||
));
|
||||
}
|
||||
|
||||
Ok(return_buf.into_boxed_slice())
|
||||
#[inline]
|
||||
fn read_bytes_to_buf(&mut self, buf: &mut [u8]) -> Result<(), ReadingError> {
|
||||
self.read_exact(buf)
|
||||
.map_err(|err| ReadingError::Incomplete(err.to_string()))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn get_bool(&mut self) -> Result<bool, ReadingError> {
|
||||
let byte = self.get_u8()?;
|
||||
Ok(byte != 0)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn get_var_int(&mut self) -> Result<VarInt, ReadingError> {
|
||||
VarInt::decode(self)
|
||||
}
|
||||
#[inline]
|
||||
fn get_var_uint(&mut self) -> Result<VarUInt, ReadingError> {
|
||||
VarUInt::decode(self)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn get_var_long(&mut self) -> Result<VarLong, ReadingError> {
|
||||
VarLong::decode(self)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn get_var_ulong(&mut self) -> Result<VarULong, ReadingError> {
|
||||
VarULong::decode(self)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn get_str_bounded(&mut self, bound: usize) -> Result<Box<str>, ReadingError> {
|
||||
let bytes_len = self.get_var_uint()?.0 as usize;
|
||||
|
||||
@ -203,24 +321,39 @@ impl<R: Read> NetworkReadExt for R {
|
||||
)));
|
||||
}
|
||||
|
||||
let data = self.read_boxed_slice(bytes_len)?;
|
||||
let string =
|
||||
std::str::from_utf8(&data).map_err(|e| ReadingError::Message(e.to_string()))?;
|
||||
if bytes_len <= 128 {
|
||||
let mut stack_buf = [0u8; 128];
|
||||
let slice = &mut stack_buf[..bytes_len];
|
||||
self.read_exact(slice)
|
||||
.map_err(|err| ReadingError::Incomplete(err.to_string()))?;
|
||||
|
||||
// Next, if we're able to find the (bound + 1)th UTF-16 character, the string is too big.
|
||||
if string.encode_utf16().nth(bound).is_some() {
|
||||
return Err(ReadingError::TooLarge(format!(
|
||||
"string has too many UTF-16 characters (more than the maximum limit {bound})"
|
||||
)));
|
||||
let string =
|
||||
std::str::from_utf8(slice).map_err(|e| ReadingError::Message(e.to_string()))?;
|
||||
|
||||
if string.encode_utf16().nth(bound).is_some() {
|
||||
return Err(ReadingError::TooLarge(format!(
|
||||
"string has too many UTF-16 characters (more than the maximum limit {bound})"
|
||||
)));
|
||||
}
|
||||
|
||||
Ok(string.into())
|
||||
} else {
|
||||
let mut data = vec![0u8; bytes_len];
|
||||
self.read_bytes_to_buf(&mut data)?;
|
||||
let string =
|
||||
std::str::from_utf8(&data).map_err(|e| ReadingError::Message(e.to_string()))?;
|
||||
|
||||
if string.encode_utf16().nth(bound).is_some() {
|
||||
return Err(ReadingError::TooLarge(format!(
|
||||
"string has too many UTF-16 characters (more than the maximum limit {bound})"
|
||||
)));
|
||||
}
|
||||
|
||||
Ok(string.into())
|
||||
}
|
||||
|
||||
Ok(string.into())
|
||||
}
|
||||
|
||||
fn get_str(&mut self) -> Result<Box<str>, ReadingError> {
|
||||
self.get_str_bounded(i32::MAX as usize)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn get_uuid(&mut self) -> Result<uuid::Uuid, ReadingError> {
|
||||
let mut bytes = [0u8; 16];
|
||||
self.read_exact(&mut bytes)
|
||||
@ -228,40 +361,31 @@ impl<R: Read> NetworkReadExt for R {
|
||||
Ok(uuid::Uuid::from_bytes(bytes))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn get_fixed_bitset(&mut self, bits: usize) -> Result<FixedBitSet, ReadingError> {
|
||||
let bytes = self.read_boxed_slice(bits.div_ceil(8))?;
|
||||
Ok(bytes)
|
||||
let byte_count = bits.div_ceil(8);
|
||||
let mut bytes = vec![0u8; byte_count];
|
||||
self.read_bytes_to_buf(&mut bytes)?;
|
||||
Ok(bytes.into_boxed_slice())
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn read_remaining_bytes(read: &mut impl Read, bound: usize) -> Result<Box<[u8]>, ReadingError> {
|
||||
let mut return_buf = Vec::with_capacity(bound.min(1024));
|
||||
|
||||
// Take one extra byte to check for exceeding bound
|
||||
read.take(bound as u64 + 1)
|
||||
.read_to_end(&mut return_buf)
|
||||
.map_err(|err| ReadingError::Incomplete(err.to_string()))?;
|
||||
|
||||
if return_buf.len() > bound {
|
||||
return Err(ReadingError::TooLarge(
|
||||
"Read remaining too long".to_string(),
|
||||
));
|
||||
}
|
||||
|
||||
fn get_option<G>(
|
||||
&mut self,
|
||||
parse: impl FnOnce(&mut Self) -> Result<G, ReadingError>,
|
||||
) -> Result<Option<G>, ReadingError> {
|
||||
if self.get_bool()? {
|
||||
Ok(Some(parse(self)?))
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
|
||||
fn get_list<G>(
|
||||
&mut self,
|
||||
parse: impl Fn(&mut Self) -> Result<G, ReadingError>,
|
||||
) -> Result<Vec<G>, ReadingError> {
|
||||
const MAX_LIST_SIZE: usize = 65536;
|
||||
|
||||
let len = self.get_var_int()?.0 as usize;
|
||||
if len > MAX_LIST_SIZE {
|
||||
return Err(ReadingError::TooLarge(format!(
|
||||
"List length {len} exceeds limit"
|
||||
)));
|
||||
}
|
||||
let mut list = Vec::with_capacity(len);
|
||||
for _ in 0..len {
|
||||
list.push(parse(self)?);
|
||||
}
|
||||
Ok(list)
|
||||
}
|
||||
Ok(return_buf.into_boxed_slice())
|
||||
}
|
||||
|
||||
pub trait NetworkWriteExt {
|
||||
|
||||
@ -240,3 +240,162 @@ impl<T: PacketRead> PacketRead for Option<T> {
|
||||
bool::read(reader)?.then(|| T::read(reader)).transpose()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> crate::serial::PacketReadSlice<'a> for bool {
|
||||
fn read_slice(buf: &mut &'a [u8]) -> Result<Self, Error> {
|
||||
if buf.is_empty() {
|
||||
return Err(Error::new(ErrorKind::UnexpectedEof, "expected bool byte"));
|
||||
}
|
||||
let b = buf[0];
|
||||
*buf = &buf[1..];
|
||||
Ok(b != 0)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> crate::serial::PacketReadSlice<'a> for u8 {
|
||||
fn read_slice(buf: &mut &'a [u8]) -> Result<Self, Error> {
|
||||
if buf.is_empty() {
|
||||
return Err(Error::new(ErrorKind::UnexpectedEof, "expected u8"));
|
||||
}
|
||||
let b = buf[0];
|
||||
*buf = &buf[1..];
|
||||
Ok(b)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> crate::serial::PacketReadSlice<'a> for i8 {
|
||||
fn read_slice(buf: &mut &'a [u8]) -> Result<Self, Error> {
|
||||
u8::read_slice(buf).map(|b| b as Self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> crate::serial::PacketReadSlice<'a> for i16 {
|
||||
fn read_slice(buf: &mut &'a [u8]) -> Result<Self, Error> {
|
||||
if buf.len() < 2 {
|
||||
return Err(Error::new(ErrorKind::UnexpectedEof, "expected i16"));
|
||||
}
|
||||
let (bytes, rest) = buf.split_at(2);
|
||||
*buf = rest;
|
||||
Ok(Self::from_le_bytes(bytes.try_into().unwrap()))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> crate::serial::PacketReadSlice<'a> for i32 {
|
||||
fn read_slice(buf: &mut &'a [u8]) -> Result<Self, Error> {
|
||||
if buf.len() < 4 {
|
||||
return Err(Error::new(ErrorKind::UnexpectedEof, "expected i32"));
|
||||
}
|
||||
let (bytes, rest) = buf.split_at(4);
|
||||
*buf = rest;
|
||||
Ok(Self::from_le_bytes(bytes.try_into().unwrap()))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> crate::serial::PacketReadSlice<'a> for i64 {
|
||||
fn read_slice(buf: &mut &'a [u8]) -> Result<Self, Error> {
|
||||
if buf.len() < 8 {
|
||||
return Err(Error::new(ErrorKind::UnexpectedEof, "expected i64"));
|
||||
}
|
||||
let (bytes, rest) = buf.split_at(8);
|
||||
*buf = rest;
|
||||
Ok(Self::from_le_bytes(bytes.try_into().unwrap()))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> crate::serial::PacketReadSlice<'a> for u16 {
|
||||
fn read_slice(buf: &mut &'a [u8]) -> Result<Self, Error> {
|
||||
if buf.len() < 2 {
|
||||
return Err(Error::new(ErrorKind::UnexpectedEof, "expected u16"));
|
||||
}
|
||||
let (bytes, rest) = buf.split_at(2);
|
||||
*buf = rest;
|
||||
Ok(Self::from_le_bytes(bytes.try_into().unwrap()))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> crate::serial::PacketReadSlice<'a> for u32 {
|
||||
fn read_slice(buf: &mut &'a [u8]) -> Result<Self, Error> {
|
||||
if buf.len() < 4 {
|
||||
return Err(Error::new(ErrorKind::UnexpectedEof, "expected u32"));
|
||||
}
|
||||
let (bytes, rest) = buf.split_at(4);
|
||||
*buf = rest;
|
||||
Ok(Self::from_le_bytes(bytes.try_into().unwrap()))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> crate::serial::PacketReadSlice<'a> for u64 {
|
||||
fn read_slice(buf: &mut &'a [u8]) -> Result<Self, Error> {
|
||||
if buf.len() < 8 {
|
||||
return Err(Error::new(ErrorKind::UnexpectedEof, "expected u64"));
|
||||
}
|
||||
let (bytes, rest) = buf.split_at(8);
|
||||
*buf = rest;
|
||||
Ok(Self::from_le_bytes(bytes.try_into().unwrap()))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> crate::serial::PacketReadSlice<'a> for f32 {
|
||||
fn read_slice(buf: &mut &'a [u8]) -> Result<Self, Error> {
|
||||
if buf.len() < 4 {
|
||||
return Err(Error::new(ErrorKind::UnexpectedEof, "expected f32"));
|
||||
}
|
||||
let (bytes, rest) = buf.split_at(4);
|
||||
*buf = rest;
|
||||
Ok(Self::from_le_bytes(bytes.try_into().unwrap()))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> crate::serial::PacketReadSlice<'a> for f64 {
|
||||
fn read_slice(buf: &mut &'a [u8]) -> Result<Self, Error> {
|
||||
if buf.len() < 8 {
|
||||
return Err(Error::new(ErrorKind::UnexpectedEof, "expected f64"));
|
||||
}
|
||||
let (bytes, rest) = buf.split_at(8);
|
||||
*buf = rest;
|
||||
Ok(Self::from_le_bytes(bytes.try_into().unwrap()))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> crate::serial::PacketReadSlice<'a> for &'a str {
|
||||
fn read_slice(buf: &mut &'a [u8]) -> Result<Self, Error> {
|
||||
crate::serial::read_str_slice(buf)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: crate::serial::PacketReadSlice<'a>> crate::serial::PacketReadSlice<'a> for Option<T> {
|
||||
fn read_slice(buf: &mut &'a [u8]) -> Result<Self, Error> {
|
||||
bool::read_slice(buf)?
|
||||
.then(|| T::read_slice(buf))
|
||||
.transpose()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> crate::serial::PacketReadSlice<'a> for uuid::Uuid {
|
||||
fn read_slice(buf: &mut &'a [u8]) -> Result<Self, Error> {
|
||||
if buf.len() < 16 {
|
||||
return Err(Error::new(ErrorKind::UnexpectedEof, "expected Uuid"));
|
||||
}
|
||||
let (bytes, rest) = buf.split_at(16);
|
||||
*buf = rest;
|
||||
Ok(Self::from_bytes(bytes.try_into().unwrap()))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> crate::serial::PacketReadSlice<'a> for crate::codec::var_int::VarInt {
|
||||
fn read_slice(buf: &mut &'a [u8]) -> Result<Self, Error> {
|
||||
Self::read(buf)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> crate::serial::PacketReadSlice<'a> for crate::codec::var_uint::VarUInt {
|
||||
fn read_slice(buf: &mut &'a [u8]) -> Result<Self, Error> {
|
||||
Self::read(buf)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> crate::serial::PacketReadSlice<'a> for crate::codec::var_ulong::VarULong {
|
||||
fn read_slice(buf: &mut &'a [u8]) -> Result<Self, Error> {
|
||||
Self::read(buf)
|
||||
}
|
||||
}
|
||||
|
||||
@ -16,3 +16,32 @@ pub trait PacketRead: Sized {
|
||||
Err(Error::other("Not implemented"))
|
||||
}
|
||||
}
|
||||
|
||||
pub trait PacketReadSlice<'a>: Sized {
|
||||
fn read_slice(buf: &mut &'a [u8]) -> Result<Self, Error>;
|
||||
}
|
||||
|
||||
pub(crate) fn read_str_slice<'a>(buf: &mut &'a [u8]) -> Result<&'a str, Error> {
|
||||
use crate::codec::var_uint::VarUInt;
|
||||
use std::io::ErrorKind;
|
||||
|
||||
const MAX_STRING_LENGTH: usize = 32767;
|
||||
|
||||
let len = VarUInt::read(buf)?.0 as usize;
|
||||
if len > MAX_STRING_LENGTH {
|
||||
return Err(Error::new(
|
||||
ErrorKind::InvalidData,
|
||||
format!("String length {len} exceeds maximum of {MAX_STRING_LENGTH}"),
|
||||
));
|
||||
}
|
||||
if len > buf.len() {
|
||||
return Err(Error::new(
|
||||
ErrorKind::UnexpectedEof,
|
||||
"Not enough bytes for string",
|
||||
));
|
||||
}
|
||||
let (str_bytes, rest) = buf.split_at(len);
|
||||
*buf = rest;
|
||||
std::str::from_utf8(str_bytes)
|
||||
.map_err(|_| Error::new(ErrorKind::InvalidData, "Invalid UTF-8 sequence"))
|
||||
}
|
||||
|
||||
@ -124,6 +124,13 @@ impl PacketWrite for String {
|
||||
}
|
||||
}
|
||||
|
||||
impl PacketWrite for str {
|
||||
fn write<W: Write>(&self, writer: &mut W) -> Result<(), Error> {
|
||||
VarUInt(self.len() as _).write(writer)?;
|
||||
writer.write_all(self.as_bytes())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: PacketWrite> PacketWrite for Vector3<T> {
|
||||
fn write<W: Write>(&self, writer: &mut W) -> Result<(), Error> {
|
||||
self.x.write(writer)?;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user