perf: ditch serde because its slower

i rather trade performance and compile time over convenience
This commit is contained in:
Alexander Medvedev 2026-07-19 18:07:37 +02:00
parent 712bb96d3e
commit e0117ab559
175 changed files with 3995 additions and 3093 deletions

101
Cargo.lock generated
View File

@ -120,7 +120,7 @@ checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn", "syn 2.0.118",
] ]
[[package]] [[package]]
@ -213,9 +213,9 @@ checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06"
[[package]] [[package]]
name = "bitflags" name = "bitflags"
version = "2.13.0" version = "2.13.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4388bee8683e3d04af747c73422af53102d2bd24d9eadb6cbc100baef4b43f8" checksum = "b588b76d00fde79687d7646a9b5bdf3cc0f655e0bbd080335a95d7e96f3587da"
[[package]] [[package]]
name = "block-buffer" name = "block-buffer"
@ -485,7 +485,7 @@ version = "3.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "faf9468729b8cbcea668e36183cb69d317348c2e08e994829fb56ebfdfbaac34" checksum = "faf9468729b8cbcea668e36183cb69d317348c2e08e994829fb56ebfdfbaac34"
dependencies = [ dependencies = [
"windows-sys 0.61.2", "windows-sys 0.52.0",
] ]
[[package]] [[package]]
@ -1047,7 +1047,7 @@ checksum = "1ac70aa55017e108007fbaf5aa0f54b021c98f92ff8af59d42eda9da96e3dd4f"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn", "syn 2.0.118",
] ]
[[package]] [[package]]
@ -1131,7 +1131,7 @@ dependencies = [
"once_cell", "once_cell",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn", "syn 2.0.118",
] ]
[[package]] [[package]]
@ -1147,7 +1147,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb"
dependencies = [ dependencies = [
"libc", "libc",
"windows-sys 0.61.2", "windows-sys 0.52.0",
] ]
[[package]] [[package]]
@ -1300,7 +1300,7 @@ checksum = "e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn", "syn 2.0.118",
] ]
[[package]] [[package]]
@ -2159,7 +2159,7 @@ version = "0.50.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5"
dependencies = [ dependencies = [
"windows-sys 0.61.2", "windows-sys 0.59.0",
] ]
[[package]] [[package]]
@ -2186,7 +2186,7 @@ checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn", "syn 2.0.118",
] ]
[[package]] [[package]]
@ -2360,7 +2360,7 @@ dependencies = [
"pest_meta", "pest_meta",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn", "syn 2.0.118",
] ]
[[package]] [[package]]
@ -2403,7 +2403,7 @@ dependencies = [
"phf_shared", "phf_shared",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn", "syn 2.0.118",
] ]
[[package]] [[package]]
@ -2432,7 +2432,7 @@ checksum = "c96395f0a926bc13b1c17622aaddda1ecb55d49c8f1bf9777e4d877800a43f8b"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn", "syn 2.0.118",
] ]
[[package]] [[package]]
@ -2520,7 +2520,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"syn", "syn 2.0.118",
] ]
[[package]] [[package]]
@ -2600,7 +2600,7 @@ dependencies = [
"itertools 0.14.0", "itertools 0.14.0",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn", "syn 2.0.118",
] ]
[[package]] [[package]]
@ -2632,7 +2632,7 @@ checksum = "5a7ac85c0bb3fb351f10d531230aaa5e366b46d7c4e5328e5f02801d6dac1165"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn", "syn 2.0.118",
] ]
[[package]] [[package]]
@ -2701,7 +2701,7 @@ dependencies = [
"proc-macro-error2", "proc-macro-error2",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn", "syn 3.0.0",
] ]
[[package]] [[package]]
@ -2759,7 +2759,7 @@ dependencies = [
"proc-macro-error2", "proc-macro-error2",
"pumpkin-data", "pumpkin-data",
"quote", "quote",
"syn", "syn 3.0.0",
] ]
[[package]] [[package]]
@ -2835,7 +2835,7 @@ dependencies = [
"serde", "serde",
"serde_json", "serde_json",
"sha2 0.11.0", "sha2 0.11.0",
"syn", "syn 3.0.0",
"thiserror 2.0.18", "thiserror 2.0.18",
"tokio", "tokio",
"ureq", "ureq",
@ -3085,7 +3085,7 @@ dependencies = [
"errno", "errno",
"libc", "libc",
"linux-raw-sys", "linux-raw-sys",
"windows-sys 0.61.2", "windows-sys 0.52.0",
] ]
[[package]] [[package]]
@ -3230,7 +3230,7 @@ checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn", "syn 2.0.118",
] ]
[[package]] [[package]]
@ -3265,7 +3265,7 @@ checksum = "175ee3e80ae9982737ca543e96133087cbd9a485eecc3bc4de9c1a37b47ea59c"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn", "syn 2.0.118",
] ]
[[package]] [[package]]
@ -3398,7 +3398,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "52d1cfed4120b4d927bf7c0f86d2087a4a7d6027c906d9f9d525a80573b9be51" checksum = "52d1cfed4120b4d927bf7c0f86d2087a4a7d6027c906d9f9d525a80573b9be51"
dependencies = [ dependencies = [
"libc", "libc",
"windows-sys 0.61.2", "windows-sys 0.60.2",
] ]
[[package]] [[package]]
@ -3455,6 +3455,17 @@ dependencies = [
"unicode-ident", "unicode-ident",
] ]
[[package]]
name = "syn"
version = "3.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f2fac314a64dc9a36e61a9eb4261a5e9bbfbc922b27e518af97bc32b926cf967"
dependencies = [
"proc-macro2",
"quote",
"unicode-ident",
]
[[package]] [[package]]
name = "sync_wrapper" name = "sync_wrapper"
version = "1.0.2" version = "1.0.2"
@ -3469,7 +3480,7 @@ checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn", "syn 2.0.118",
] ]
[[package]] [[package]]
@ -3507,7 +3518,7 @@ dependencies = [
"fastrand", "fastrand",
"once_cell", "once_cell",
"rustix", "rustix",
"windows-sys 0.61.2", "windows-sys 0.52.0",
] ]
[[package]] [[package]]
@ -3545,7 +3556,7 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn", "syn 2.0.118",
] ]
[[package]] [[package]]
@ -3556,7 +3567,7 @@ checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn", "syn 2.0.118",
] ]
[[package]] [[package]]
@ -3622,9 +3633,9 @@ dependencies = [
[[package]] [[package]]
name = "tokio" name = "tokio"
version = "1.52.3" version = "1.53.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8fc7f01b389ac15039e4dc9531aa973a135d7a4135281b12d7c1bc79fd57fffe" checksum = "d988bcd52dbe076d3d46903332f58c912b87a2c49b1428419a5845154762ffee"
dependencies = [ dependencies = [
"bytes", "bytes",
"libc", "libc",
@ -3645,7 +3656,7 @@ checksum = "385a6cb71ab9ab790c5fe8d67f1645e6c450a7ce006a33de03daa956cf70a496"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn", "syn 2.0.118",
] ]
[[package]] [[package]]
@ -3835,7 +3846,7 @@ checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn", "syn 2.0.118",
] ]
[[package]] [[package]]
@ -3998,9 +4009,9 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821"
[[package]] [[package]]
name = "uuid" name = "uuid"
version = "1.23.4" version = "1.24.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bf80a72845275afea99e7f2b434723d3bc7e38470fcd1c7ed39a599c73319a53" checksum = "bf3923a6f5c4c6382e0b653c4117f48d631ea17f38ed86e2a828e6f7412f5239"
dependencies = [ dependencies = [
"getrandom 0.4.3", "getrandom 0.4.3",
"js-sys", "js-sys",
@ -4078,7 +4089,7 @@ dependencies = [
"bumpalo", "bumpalo",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn", "syn 2.0.118",
"wasm-bindgen-shared", "wasm-bindgen-shared",
] ]
@ -4262,7 +4273,7 @@ dependencies = [
"anyhow", "anyhow",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn", "syn 2.0.118",
"wasmtime-internal-component-util", "wasmtime-internal-component-util",
"wasmtime-internal-wit-bindgen", "wasmtime-internal-wit-bindgen",
"wit-parser 0.251.0", "wit-parser 0.251.0",
@ -4370,7 +4381,7 @@ checksum = "e747f4a074699ba1b4e4d841fb263f9b7df5bd1555181c4752bf5990d21ba676"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn", "syn 2.0.118",
] ]
[[package]] [[package]]
@ -4490,7 +4501,7 @@ version = "0.1.11"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22"
dependencies = [ dependencies = [
"windows-sys 0.61.2", "windows-sys 0.52.0",
] ]
[[package]] [[package]]
@ -4552,7 +4563,7 @@ checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn", "syn 2.0.118",
] ]
[[package]] [[package]]
@ -4563,7 +4574,7 @@ checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn", "syn 2.0.118",
] ]
[[package]] [[package]]
@ -4826,7 +4837,7 @@ dependencies = [
"heck", "heck",
"indexmap", "indexmap",
"prettyplease", "prettyplease",
"syn", "syn 2.0.118",
"wasm-metadata", "wasm-metadata",
"wit-bindgen-core", "wit-bindgen-core",
"wit-component", "wit-component",
@ -4842,7 +4853,7 @@ dependencies = [
"prettyplease", "prettyplease",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn", "syn 2.0.118",
"wit-bindgen-core", "wit-bindgen-core",
"wit-bindgen-rust", "wit-bindgen-rust",
] ]
@ -4946,7 +4957,7 @@ checksum = "de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn", "syn 2.0.118",
"synstructure", "synstructure",
] ]
@ -4967,7 +4978,7 @@ checksum = "e2e817b7b52d0c7358d3246da9d69935ebb18116b2b102b4230dac079b4862f5"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn", "syn 2.0.118",
] ]
[[package]] [[package]]
@ -4987,7 +4998,7 @@ checksum = "11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn", "syn 2.0.118",
"synstructure", "synstructure",
] ]
@ -5027,7 +5038,7 @@ checksum = "625dc425cab0dca6dc3c3319506e6593dcb08a9f387ea3b284dbd52a92c40555"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn", "syn 2.0.118",
] ]
[[package]] [[package]]

View File

@ -98,8 +98,8 @@ strip = false
[workspace.dependencies] [workspace.dependencies]
serde_json5 = "0.2.1" serde_json5 = "0.2.1"
tokio = { version = "1.52", default-features = false } tokio = { version = "1.53", default-features = false }
syn = { version = "2.0", default-features = false, features = ["printing"] } syn = { version = "3.0", default-features = false, features = ["full", "parsing", "printing", "proc-macro", "clone-impls", "derive"] }
thiserror = { version = "2.0", default-features = false } thiserror = { version = "2.0", default-features = false }
@ -110,7 +110,7 @@ futures = { version = "0.3", default-features = false, features = ["executor"] }
rayon = { version = "1.12", default-features = false } rayon = { version = "1.12", default-features = false }
crossbeam = { version = "0.8", default-features = false, features = ["std"] } crossbeam = { version = "0.8", default-features = false, features = ["std"] }
uuid = { version = "1.23", default-features = false, features = ["serde", "v3", "v4", "std"] } uuid = { version = "1.24", default-features = false, features = ["serde", "v3", "v4", "std"] }
serde = { version = "1.0", default-features = false, features = ["derive", "std"] } serde = { version = "1.0", default-features = false, features = ["derive", "std"] }
serde_repr = { version = "0.1", default-features = false } serde_repr = { version = "0.1", default-features = false }
serde_json = { version = "1.0", default-features = false, features = ["std"] } serde_json = { version = "1.0", default-features = false, features = ["std"] }
@ -120,7 +120,7 @@ proc-macro-error2 = { version = "2", default-features = false }
aes = { version = "0.9", default-features = false } aes = { version = "0.9", default-features = false }
async-compression = { version = "0.4.42", 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.22.1", default-features = false, features = ["std"] }
bitflags = { version = "2.13.0", default-features = false, features = ["std"] } bitflags = { version = "2.13.1", default-features = false, features = ["std"] }
cesu8 = { version = "1.1", default-features = false } cesu8 = { version = "1.1", default-features = false }
cfb8 = { version = "0.9", default-features = false } cfb8 = { version = "0.9", default-features = false }
ctr = { version = "0.10.1", default-features = false } ctr = { version = "0.10.1", default-features = false }

View File

@ -17,9 +17,9 @@ pumpkin-data = { workspace = true, features = ["packet", "item_id_remap", "entit
pumpkin-macros.workspace = true pumpkin-macros.workspace = true
pumpkin-world.workspace = true pumpkin-world.workspace = true
pumpkin-util.workspace = true pumpkin-util.workspace = true
serde = { workspace = true, features = ["derive"] }
uuid.workspace = true uuid.workspace = true
serde.workspace = true
thiserror.workspace = true thiserror.workspace = true
tokio = { workspace = true, features = ["net"] } tokio = { workspace = true, features = ["net"] }
bytes.workspace = true bytes.workspace = true

View File

@ -1,8 +1,6 @@
use std::io::Read; use std::io::Read;
use std::io::Write; use std::io::Write;
use serde::{Serialize, Serializer};
use crate::ReadingError; use crate::ReadingError;
use crate::WritingError; use crate::WritingError;
use crate::ser::NetworkReadExt; use crate::ser::NetworkReadExt;
@ -34,11 +32,3 @@ impl BitSet {
Ok(Self(array.into_boxed_slice())) Ok(Self(array.into_boxed_slice()))
} }
} }
impl Serialize for BitSet {
fn serialize<S: Serializer>(&self, _serializer: S) -> Result<S::Ok, S::Error> {
Err(serde::ser::Error::custom(
"BitSet serialization not implemented",
))
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
use crate::VarInt; use crate::VarInt;
use crate::codec::data_component::{deserialize, serialize}; use crate::codec::data_component::{deserialize, serialize};
use crate::ser::{NetworkReadExt, ReadingError, WritingError, deserializer, serializer}; use crate::ser::{NetworkReadExt, NetworkWriteExt, ReadingError, WritingError};
use pumpkin_data::data_component::DataComponent; use pumpkin_data::data_component::DataComponent;
use pumpkin_data::data_component_impl::{CustomNameImpl, DataComponentImpl}; use pumpkin_data::data_component_impl::{CustomNameImpl, DataComponentImpl};
use pumpkin_data::item::Item; use pumpkin_data::item::Item;
@ -9,13 +9,8 @@ use pumpkin_data::item_stack::ItemStack;
use pumpkin_nbt::tag::NbtTag; use pumpkin_nbt::tag::NbtTag;
use pumpkin_util::text::TextComponent; use pumpkin_util::text::TextComponent;
use pumpkin_util::version::JavaMinecraftVersion; use pumpkin_util::version::JavaMinecraftVersion;
use serde::ser::SerializeStruct;
use serde::{
Deserialize, Serialize, Serializer,
de::{self, DeserializeSeed, SeqAccess},
};
use std::borrow::Cow; use std::borrow::Cow;
use std::io::{Cursor, Read}; use std::io::Cursor;
#[derive(Clone)] #[derive(Clone)]
pub struct ItemStackSerializer<'a>(pub Cow<'a, ItemStack>); pub struct ItemStackSerializer<'a>(pub Cow<'a, ItemStack>);
@ -35,67 +30,52 @@ fn item_component_counts(stack: &ItemStack) -> (u8, u8) {
(to_add, to_remove) (to_add, to_remove)
} }
fn serialize_any_item_stack_with_id<S: Serializer>( fn serialize_any_item_stack_with_id(
stack: &ItemStack, stack: &ItemStack,
item_id: u16, item_id: u16,
is_template: bool, is_template: bool,
serializer: S, write: &mut impl NetworkWriteExt,
) -> Result<S::Ok, S::Error> { ) -> Result<(), WritingError> {
if stack.is_empty() { if stack.is_empty() {
VarInt(0).serialize(serializer) write.put_var_int(&VarInt(0))
} else { } else {
let (to_add, to_remove) = item_component_counts(stack); let (to_add, to_remove) = item_component_counts(stack);
let mut seq = serializer.serialize_struct("", 0)?;
if is_template { if is_template {
seq.serialize_field("", &VarInt::from(item_id))?; write.put_var_int(&VarInt::from(item_id))?;
seq.serialize_field("", &VarInt::from(stack.item_count))?; write.put_var_int(&VarInt::from(stack.item_count))?;
} else { } else {
seq.serialize_field("", &VarInt::from(stack.item_count))?; write.put_var_int(&VarInt::from(stack.item_count))?;
seq.serialize_field("", &VarInt::from(item_id))?; write.put_var_int(&VarInt::from(item_id))?;
} }
seq.serialize_field::<VarInt>("", &VarInt::from(to_add))?; write.put_var_int(&VarInt::from(to_add))?;
seq.serialize_field::<VarInt>("", &VarInt::from(to_remove))?; write.put_var_int(&VarInt::from(to_remove))?;
for (id, data) in &stack.patch { for (id, data) in &stack.patch {
if let Some(data) = data { if let Some(data) = data {
seq.serialize_field::<VarInt>("", &VarInt::from(id.to_id()))?; write.put_var_int(&VarInt::from(id.to_id()))?;
serialize(*id, data.as_ref(), &mut seq)?; serialize(*id, data.as_ref(), write)?;
} }
} }
for (id, data) in &stack.patch { for (id, data) in &stack.patch {
if data.is_none() { if data.is_none() {
seq.serialize_field::<VarInt>("", &VarInt::from(id.to_id()))?; write.put_var_int(&VarInt::from(id.to_id()))?;
} }
} }
seq.end() Ok(())
} }
} }
fn serialize_item_stack_with_id<S: Serializer>(
fn serialize_item_stack_with_id(
stack: &ItemStack, stack: &ItemStack,
item_id: u16, item_id: u16,
serializer: S, write: &mut impl NetworkWriteExt,
) -> Result<S::Ok, S::Error> { ) -> Result<(), WritingError> {
serialize_any_item_stack_with_id(stack, item_id, false, serializer) serialize_any_item_stack_with_id(stack, item_id, false, write)
} }
struct ComponentAccess<R: Read> { fn read_component_id(read: &mut impl NetworkReadExt) -> Result<DataComponent, ReadingError> {
deserializer: deserializer::Deserializer<R>,
}
impl<'de, R: Read> SeqAccess<'de> for ComponentAccess<R> {
type Error = ReadingError;
fn next_element_seed<T: DeserializeSeed<'de>>(
&mut self,
seed: T,
) -> Result<Option<T::Value>, Self::Error> {
seed.deserialize(&mut self.deserializer).map(Some)
}
}
fn read_component_id(read: &mut impl Read) -> Result<DataComponent, ReadingError> {
let id_val = read.get_var_int()?.0; let id_val = read.get_var_int()?.0;
let id_u8 = id_val let id_u8 = id_val
.try_into() .try_into()
@ -122,7 +102,7 @@ fn decode_custom_name(component_data: &[u8]) -> Result<Box<dyn DataComponentImpl
} }
fn read_length_prefixed_component( fn read_length_prefixed_component(
read: &mut impl Read, read: &mut impl NetworkReadExt,
) -> Result<(DataComponent, Box<dyn DataComponentImpl>), ReadingError> { ) -> Result<(DataComponent, Box<dyn DataComponentImpl>), ReadingError> {
let id = read_component_id(read)?; let id = read_component_id(read)?;
let byte_len = read.get_var_int()?.0; let byte_len = read.get_var_int()?.0;
@ -134,91 +114,66 @@ fn read_length_prefixed_component(
let component_impl = if id == DataComponent::CustomName { let component_impl = if id == DataComponent::CustomName {
decode_custom_name(component_data.as_ref())? decode_custom_name(component_data.as_ref())?
} else { } else {
let cursor = Cursor::new(component_data); let mut cursor = Cursor::new(component_data);
let mut access = ComponentAccess { deserialize(id, &mut cursor)?
deserializer: deserializer::Deserializer::new(cursor),
};
deserialize(id, &mut access)?
}; };
Ok((id, component_impl)) Ok((id, component_impl))
} }
impl<'de> Deserialize<'de> for ItemStackSerializer<'static> { impl ItemStackSerializer<'_> {
fn deserialize<D: de::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> { pub fn read(
struct Visitor; read: &mut impl NetworkReadExt,
impl<'de> de::Visitor<'de> for Visitor { ) -> Result<ItemStackSerializer<'static>, ReadingError> {
type Value = ItemStackSerializer<'static>;
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
formatter.write_str("a valid Slot encoded in a byte sequence")
}
fn visit_seq<A: SeqAccess<'de>>(self, mut seq: A) -> Result<Self::Value, A::Error> {
const MAX_COMPONENTS: i32 = 256; const MAX_COMPONENTS: i32 = 256;
let item_count = seq let item_count = read.get_var_int()?;
.next_element::<VarInt>()?
.ok_or_else(|| de::Error::custom("Failed to decode VarInt"))?;
if item_count.0 == 0 { if item_count.0 == 0 {
return Ok(ItemStackSerializer(Cow::Borrowed(ItemStack::EMPTY))); return Ok(ItemStackSerializer(Cow::Borrowed(ItemStack::EMPTY)));
} }
let item_id = seq let item_id = read.get_var_int()?;
.next_element::<VarInt>()? let num_to_add = read.get_var_int()?.0;
.ok_or_else(|| de::Error::custom("No item id VarInt!"))?; let num_to_remove = read.get_var_int()?.0;
let num_to_add = seq.next_element::<VarInt>()?.map_or(0, |v| v.0);
let num_to_remove = seq.next_element::<VarInt>()?.map_or(0, |v| v.0);
if num_to_add < 0 || num_to_remove < 0 { if num_to_add < 0 || num_to_remove < 0 {
return Err(de::Error::custom("Negative component count")); return Err(ReadingError::Message("Negative component count".into()));
} }
let total_components = num_to_add let total_components = num_to_add
.checked_add(num_to_remove) .checked_add(num_to_remove)
.ok_or_else(|| de::Error::custom("Component count overflow"))?; .ok_or_else(|| ReadingError::Message("Component count overflow".into()))?;
if total_components > MAX_COMPONENTS { if total_components > MAX_COMPONENTS {
return Err(de::Error::custom("Too many components in ItemStack patch")); return Err(ReadingError::Message(
"Too many components in ItemStack patch".into(),
));
} }
let mut patch = Vec::with_capacity((num_to_add + num_to_remove) as usize); let mut patch = Vec::with_capacity((num_to_add + num_to_remove) as usize);
for _ in 0..num_to_add { for _ in 0..num_to_add {
let id_val = seq let id_val = read.get_var_int()?.0;
.next_element::<VarInt>()? let id = DataComponent::try_from_id(id_val as u8)
.ok_or_else(|| de::Error::custom("Missing component ID"))? .ok_or_else(|| ReadingError::Message(format!("Unknown component ID: {id_val}")))?;
.0;
let id = DataComponent::try_from_id(id_val as u8).ok_or_else(|| {
de::Error::custom(format!("Unknown component ID: {id_val}"))
})?;
// Minecraft protocol sends a byte length for the component data here let _byte_len = read.get_var_int()?;
let _byte_len = seq
.next_element::<VarInt>()?
.ok_or_else(|| de::Error::custom("No data len VarInt!"))?;
let component_impl = deserialize(id, &mut seq)?;
let component_impl = deserialize(id, read)?;
patch.push((id, Some(component_impl))); patch.push((id, Some(component_impl)));
} }
for _ in 0..num_to_remove { for _ in 0..num_to_remove {
let id_val = seq let id_val = read.get_var_int()?.0;
.next_element::<VarInt>()?
.ok_or_else(|| de::Error::custom("Missing remove component ID"))?
.0;
let id = DataComponent::try_from_id(id_val as u8) let id = DataComponent::try_from_id(id_val as u8)
.ok_or_else(|| de::Error::custom("Unknown component ID"))?; .ok_or_else(|| ReadingError::Message("Unknown component ID".into()))?;
patch.push((id, None)); patch.push((id, None));
} }
let item_id_u16: u16 = item_id let item_id_u16: u16 = item_id
.0 .0
.try_into() .try_into()
.map_err(|_| de::Error::custom("Invalid item id!"))?; .map_err(|_| ReadingError::Message("Invalid item id!".into()))?;
Ok(ItemStackSerializer(Cow::Owned( Ok(ItemStackSerializer(Cow::Owned(
ItemStack::new_with_component( ItemStack::new_with_component(
@ -228,20 +183,13 @@ impl<'de> Deserialize<'de> for ItemStackSerializer<'static> {
), ),
))) )))
} }
}
deserializer.deserialize_seq(Visitor)
}
}
impl Serialize for ItemStackSerializer<'_> { pub fn write(&self, write: &mut impl NetworkWriteExt) -> Result<(), WritingError> {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> { serialize_item_stack_with_id(self.0.as_ref(), self.0.item.id, write)
serialize_item_stack_with_id(self.0.as_ref(), self.0.item.id, serializer)
} }
}
impl ItemStackSerializer<'_> {
pub fn read_length_prefixed_optional( pub fn read_length_prefixed_optional(
mut read: impl Read, read: &mut impl NetworkReadExt,
) -> Result<ItemStackSerializer<'static>, ReadingError> { ) -> Result<ItemStackSerializer<'static>, ReadingError> {
const MAX_COMPONENTS: i32 = 256; const MAX_COMPONENTS: i32 = 256;
@ -275,12 +223,12 @@ impl ItemStackSerializer<'_> {
let mut patch = Vec::with_capacity(total_components as usize); let mut patch = Vec::with_capacity(total_components as usize);
for _ in 0..num_to_add { for _ in 0..num_to_add {
let (id, component_impl) = read_length_prefixed_component(&mut read)?; let (id, component_impl) = read_length_prefixed_component(read)?;
patch.push((id, Some(component_impl))); patch.push((id, Some(component_impl)));
} }
for _ in 0..num_to_remove { for _ in 0..num_to_remove {
patch.push((read_component_id(&mut read)?, None)); patch.push((read_component_id(read)?, None));
} }
let item_id_u16 = item_id let item_id_u16 = item_id
@ -299,12 +247,11 @@ impl ItemStackSerializer<'_> {
pub fn write_with_version( pub fn write_with_version(
&self, &self,
write: impl std::io::Write, write: &mut impl NetworkWriteExt,
version: &JavaMinecraftVersion, version: &JavaMinecraftVersion,
) -> Result<(), WritingError> { ) -> Result<(), WritingError> {
let remapped_item_id = remap_item_id_for_version(self.0.item.id, *version); let remapped_item_id = remap_item_id_for_version(self.0.item.id, *version);
let mut network_serializer = serializer::Serializer::new(write); serialize_item_stack_with_id(self.0.as_ref(), remapped_item_id, write)
serialize_item_stack_with_id(self.0.as_ref(), remapped_item_id, &mut network_serializer)
} }
#[must_use] #[must_use]
@ -346,6 +293,49 @@ pub struct ItemComponentHash {
pub removed: Vec<VarInt>, pub removed: Vec<VarInt>,
} }
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()));
}
for _ in 0..added_length.0 {
let component_id = read.get_var_int()?;
let component_value = read.get_i32()?;
added.push((component_id, component_value));
}
let removed_length = read.get_var_int()?;
if removed_length.0 < 0 || removed_length.0 > MAX_COMPONENTS {
return Err(ReadingError::Message("removed_length out of bounds".into()));
}
for _ in 0..removed_length.0 {
let component_id = read.get_var_int()?;
removed.push(component_id);
}
Ok(Self { added, removed })
}
pub fn write(&self, write: &mut impl NetworkWriteExt) -> Result<(), WritingError> {
write.put_var_int(&VarInt::from(self.added.len() as i32))?;
for (id, val) in &self.added {
write.put_var_int(id)?;
write.put_i32(*val)?;
}
write.put_var_int(&VarInt::from(self.removed.len() as i32))?;
for id in &self.removed {
write.put_var_int(id)?;
}
Ok(())
}
}
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct ItemStackHash { pub struct ItemStackHash {
item_id: VarInt, item_id: VarInt,
@ -353,7 +343,39 @@ pub struct ItemStackHash {
components: ItemComponentHash, components: ItemComponentHash,
} }
#[derive(Debug, Clone)]
pub struct OptionalItemStackHash(pub Option<ItemStackHash>);
impl OptionalItemStackHash { impl OptionalItemStackHash {
pub fn read(read: &mut impl NetworkReadExt) -> Result<Self, ReadingError> {
let is_some = read.get_bool()?;
if is_some {
let item_id = read.get_var_int()?;
let count = read.get_var_int()?;
let components = ItemComponentHash::read(read)?;
Ok(Self(Some(ItemStackHash {
item_id,
count,
components,
})))
} else {
Ok(Self(None))
}
}
pub fn write(&self, write: &mut impl NetworkWriteExt) -> Result<(), WritingError> {
if let Some(hash) = &self.0 {
write.put_bool(true)?;
write.put_var_int(&hash.item_id)?;
write.put_var_int(&hash.count)?;
hash.components.write(write)?;
} else {
write.put_bool(false)?;
}
Ok(())
}
#[must_use] #[must_use]
pub fn hash_equals(&self, other: &ItemStack) -> bool { pub fn hash_equals(&self, other: &ItemStack) -> bool {
if let Some(hash) = &self.0 { if let Some(hash) = &self.0 {
@ -404,121 +426,26 @@ impl OptionalItemStackHash {
} }
} }
#[derive(Debug, Clone)]
pub struct OptionalItemStackHash(pub Option<ItemStackHash>);
impl<'de> Deserialize<'de> for OptionalItemStackHash {
fn deserialize<D: de::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
struct Visitor;
impl<'de> de::Visitor<'de> for Visitor {
type Value = OptionalItemStackHash;
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
formatter.write_str("a valid Slot encoded in a byte sequence")
}
fn visit_seq<A: SeqAccess<'de>>(self, mut seq: A) -> Result<Self::Value, A::Error> {
let is_some = seq
.next_element::<bool>()?
.ok_or(de::Error::custom("No is some bool!"))?;
if is_some {
let item_id = seq
.next_element::<VarInt>()?
.ok_or(de::Error::custom("No item id VarInt!"))?;
let count = seq
.next_element::<VarInt>()?
.ok_or(de::Error::custom("No item count VarInt!"))?;
let hashed_components = seq
.next_element::<ItemComponentHash>()?
.ok_or(de::Error::custom("No item component hash!"))?;
let item_stack_hash = ItemStackHash {
item_id,
count,
components: hashed_components,
};
Ok(OptionalItemStackHash(Some(item_stack_hash)))
} else {
Ok(OptionalItemStackHash(None))
}
}
}
deserializer.deserialize_seq(Visitor)
}
}
impl<'de> Deserialize<'de> for ItemComponentHash {
fn deserialize<D: de::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
struct Visitor;
impl<'de> de::Visitor<'de> for Visitor {
type Value = ItemComponentHash;
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
formatter.write_str("a valid Slot encoded in a byte sequence")
}
fn visit_seq<A: SeqAccess<'de>>(self, mut seq: A) -> Result<Self::Value, A::Error> {
const MAX_COMPONENTS: i32 = 256;
let mut added = Vec::new();
let mut removed = Vec::new();
let added_length = seq
.next_element::<VarInt>()?
.ok_or(de::Error::custom("No added length VarInt!"))?;
if added_length.0 < 0 || added_length.0 > MAX_COMPONENTS {
return Err(de::Error::custom("added_length out of bounds"));
}
for _ in 0..added_length.0 {
let component_id = seq
.next_element::<VarInt>()?
.ok_or(de::Error::custom("No component id VarInt!"))?;
let component_value = seq
.next_element::<i32>()?
.ok_or(de::Error::custom("No component value i32!"))?;
added.push((component_id, component_value));
}
let removed_length = seq
.next_element::<VarInt>()?
.ok_or(de::Error::custom("No removed length VarInt!"))?;
if removed_length.0 < 0 || removed_length.0 > MAX_COMPONENTS {
return Err(de::Error::custom("removed_length out of bounds"));
}
for _ in 0..removed_length.0 {
let component_id = seq
.next_element::<VarInt>()?
.ok_or(de::Error::custom("No component id VarInt!"))?;
removed.push(component_id);
}
Ok(ItemComponentHash { added, removed })
}
}
deserializer.deserialize_seq(Visitor)
}
}
pub struct ItemStackTemplateSerializer<'a>(pub Cow<'a, ItemStack>); pub struct ItemStackTemplateSerializer<'a>(pub Cow<'a, ItemStack>);
impl ItemStackTemplateSerializer<'_> { impl ItemStackTemplateSerializer<'_> {
pub fn write_with_version( pub fn write_with_version(
&self, &self,
write: impl std::io::Write, write: &mut impl NetworkWriteExt,
version: &JavaMinecraftVersion, version: &JavaMinecraftVersion,
) -> Result<(), WritingError> { ) -> Result<(), WritingError> {
let remapped_item_id = remap_item_id_for_version(self.0.item.id, *version); let remapped_item_id = remap_item_id_for_version(self.0.item.id, *version);
let mut network_serializer = serializer::Serializer::new(write);
serialize_any_item_stack_with_id( serialize_any_item_stack_with_id(
self.0.as_ref(), self.0.as_ref(),
remapped_item_id, remapped_item_id,
*version >= JavaMinecraftVersion::V_26_1, *version >= JavaMinecraftVersion::V_26_1,
&mut network_serializer, write,
) )
} }
pub fn write(&self, write: &mut impl NetworkWriteExt) -> Result<(), WritingError> {
serialize_any_item_stack_with_id(self.0.as_ref(), self.0.item.id, true, write)
}
} }
impl From<ItemStack> for ItemStackTemplateSerializer<'_> { impl From<ItemStack> for ItemStackTemplateSerializer<'_> {
@ -526,12 +453,3 @@ impl From<ItemStack> for ItemStackTemplateSerializer<'_> {
ItemStackTemplateSerializer(Cow::Owned(item)) ItemStackTemplateSerializer(Cow::Owned(item))
} }
} }
impl Serialize for ItemStackTemplateSerializer<'_> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serialize_any_item_stack_with_id(self.0.as_ref(), self.0.item.id, true, serializer)
}
}

View File

@ -1,51 +1,65 @@
use serde::{Serialize, Serializer};
pub struct Le64(pub i64); pub struct Le64(pub i64);
impl Serialize for Le64 { impl Le64 {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> { pub fn write(
serializer.serialize_bytes(&self.0.to_le_bytes()) &self,
write: &mut impl crate::ser::NetworkWriteExt,
) -> Result<(), crate::ser::WritingError> {
write.write_slice(&self.0.to_le_bytes())
} }
} }
pub struct Le32(pub i32); pub struct Le32(pub i32);
impl Serialize for Le32 { impl Le32 {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> { pub fn write(
serializer.serialize_bytes(&self.0.to_le_bytes()) &self,
write: &mut impl crate::ser::NetworkWriteExt,
) -> Result<(), crate::ser::WritingError> {
write.write_slice(&self.0.to_le_bytes())
} }
} }
pub struct Le16(pub i16); pub struct Le16(pub i16);
impl Serialize for Le16 { impl Le16 {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> { pub fn write(
serializer.serialize_bytes(&self.0.to_le_bytes()) &self,
write: &mut impl crate::ser::NetworkWriteExt,
) -> Result<(), crate::ser::WritingError> {
write.write_slice(&self.0.to_le_bytes())
} }
} }
// Unsigned
pub struct LeU64(pub u64); pub struct LeU64(pub u64);
impl Serialize for LeU64 { impl LeU64 {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> { pub fn write(
serializer.serialize_bytes(&self.0.to_le_bytes()) &self,
write: &mut impl crate::ser::NetworkWriteExt,
) -> Result<(), crate::ser::WritingError> {
write.write_slice(&self.0.to_le_bytes())
} }
} }
pub struct LeU32(pub u32); pub struct LeU32(pub u32);
impl Serialize for LeU32 { impl LeU32 {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> { pub fn write(
serializer.serialize_bytes(&self.0.to_le_bytes()) &self,
write: &mut impl crate::ser::NetworkWriteExt,
) -> Result<(), crate::ser::WritingError> {
write.write_slice(&self.0.to_le_bytes())
} }
} }
pub struct LeU16(pub u16); pub struct LeU16(pub u16);
impl Serialize for LeU16 { impl LeU16 {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> { pub fn write(
serializer.serialize_bytes(&self.0.to_le_bytes()) &self,
write: &mut impl crate::ser::NetworkWriteExt,
) -> Result<(), crate::ser::WritingError> {
write.write_slice(&self.0.to_le_bytes())
} }
} }

View File

@ -1,16 +1,9 @@
use std::fmt::Formatter;
use pumpkin_util::math::vector3::Vector3; use pumpkin_util::math::vector3::Vector3;
use crate::{ use crate::{
VarInt, VarInt,
ser::{NetworkWriteExt, ReadingError, WritingError}, ser::{NetworkWriteExt, ReadingError, WritingError},
}; };
use serde::{
Deserializer, Serialize,
de::{self, Visitor},
ser::Serializer,
};
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
pub struct LpVector3d(pub Vector3<f64>); pub struct LpVector3d(pub Vector3<f64>);
@ -153,42 +146,6 @@ fn from_long(quantized: i64, scale: f64) -> f64 {
(normalized / 0.5) * scale (normalized / 0.5) * scale
} }
impl Serialize for LpVector3d {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
let mut buf = Vec::new();
self.write(&mut buf)
.map_err(|e| serde::ser::Error::custom(e.to_string()))?;
serializer.serialize_bytes(&buf)
}
}
impl<'de> de::Deserialize<'de> for LpVector3d {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
struct VelocityVisitor;
impl Visitor<'_> for VelocityVisitor {
type Value = LpVector3d;
fn expecting(&self, formatter: &mut Formatter) -> std::fmt::Result {
formatter.write_str("a byte array representing bit-packed velocity")
}
fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E>
where
E: de::Error,
{
let mut cursor = std::io::Cursor::new(v);
LpVector3d::read(&mut cursor).map_err(de::Error::custom)
}
}
deserializer.deserialize_bytes(VelocityVisitor)
}
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::{LpVector3d, encode_legacy_velocity_component}; use super::{LpVector3d, encode_legacy_velocity_component};

View File

@ -1,14 +1,11 @@
use serde::{Serialize, Serializer};
use crate::codec::var_int::VarInt;
#[derive(Debug, Clone, Copy)]
pub struct OptionalInt(pub Option<i32>); pub struct OptionalInt(pub Option<i32>);
impl Serialize for OptionalInt { impl OptionalInt {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> { pub fn write(
// Vanilla logic: empty is 0, otherwise value + 1 &self,
write: &mut impl crate::ser::NetworkWriteExt,
) -> Result<(), crate::ser::WritingError> {
let val = self.0.map_or(0, |id| id + 1); let val = self.0.map_or(0, |id| id + 1);
VarInt(val).serialize(serializer) write.write_var_int(&crate::codec::var_int::VarInt(val))
} }
} }

View File

@ -1,10 +1,9 @@
use pumpkin_data::recipes::RecipeCategoryTypes; use pumpkin_data::recipes::RecipeCategoryTypes;
use serde::Serialize;
use pumpkin_data::item::Item; use pumpkin_data::item::Item;
use pumpkin_data::tag::Taggable; use pumpkin_data::tag::Taggable;
#[derive(Clone, Debug, Serialize)] #[derive(Clone, Debug)]
pub enum OwnedRecipeIngredient { pub enum OwnedRecipeIngredient {
Simple(String), Simple(String),
Tagged(String), Tagged(String),
@ -30,14 +29,14 @@ impl OwnedRecipeIngredient {
} }
} }
#[derive(Clone, Debug, Serialize)] #[derive(Clone, Debug)]
pub struct OwnedRecipeResult { pub struct OwnedRecipeResult {
pub item_id: String, pub item_id: String,
pub count: u8, pub count: u8,
// TODO: Add components/enchantments if needed for the display result // TODO: Add components/enchantments if needed for the display result
} }
#[derive(Clone, Debug, Serialize)] #[derive(Clone, Debug)]
pub enum OwnedCraftingRecipe { pub enum OwnedCraftingRecipe {
Shaped { Shaped {
category: RecipeCategoryTypes, category: RecipeCategoryTypes,
@ -55,7 +54,7 @@ pub enum OwnedCraftingRecipe {
}, },
} }
#[derive(Clone, Debug, Serialize)] #[derive(Clone, Debug)]
pub struct OwnedCookingRecipe { pub struct OwnedCookingRecipe {
pub recipe_id: String, pub recipe_id: String,
pub category: RecipeCategoryTypes, pub category: RecipeCategoryTypes,
@ -66,7 +65,7 @@ pub struct OwnedCookingRecipe {
pub result: OwnedRecipeResult, pub result: OwnedRecipeResult,
} }
#[derive(Clone, Debug, Serialize)] #[derive(Clone, Debug)]
pub enum OwnedCookingRecipeType { pub enum OwnedCookingRecipeType {
Blasting(OwnedCookingRecipe), Blasting(OwnedCookingRecipe),
Smelting(OwnedCookingRecipe), Smelting(OwnedCookingRecipe),
@ -74,7 +73,7 @@ pub enum OwnedCookingRecipeType {
CampfireCooking(OwnedCookingRecipe), CampfireCooking(OwnedCookingRecipe),
} }
#[derive(Clone, Debug, Serialize)] #[derive(Clone, Debug)]
pub enum DynamicRecipe { pub enum DynamicRecipe {
Crafting(OwnedCraftingRecipe), Crafting(OwnedCraftingRecipe),
Cooking(OwnedCookingRecipeType), Cooking(OwnedCookingRecipeType),

View File

@ -4,11 +4,6 @@ use std::{
ops::Deref, ops::Deref,
}; };
use bytes::BufMut;
use serde::{
Deserialize, Deserializer, Serialize, Serializer,
de::{SeqAccess, Visitor},
};
use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt}; use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt};
use crate::{ use crate::{
@ -153,53 +148,6 @@ impl Deref for VarInt {
} }
} }
impl Serialize for VarInt {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
let mut value = self.0 as u32;
let mut buf = Vec::new();
while value > 0x7F {
buf.put_u8(value as u8 | 0x80);
value >>= 7;
}
buf.put_u8(value as u8);
serializer.serialize_bytes(&buf)
}
}
impl<'de> Deserialize<'de> for VarInt {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
struct VarIntVisitor;
impl<'de> Visitor<'de> for VarIntVisitor {
type Value = VarInt;
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
formatter.write_str("a valid VarInt encoded in a byte sequence")
}
fn visit_seq<A: SeqAccess<'de>>(self, mut seq: A) -> Result<Self::Value, A::Error> {
let mut val = 0;
for i in 0..VarInt::MAX_SIZE.get() {
if let Some(byte) = seq.next_element::<u8>()? {
val |= (i32::from(byte) & 0b0111_1111) << (i * 7);
if byte & 0b1000_0000 == 0 {
return Ok(VarInt(val));
}
} else {
break;
}
}
Err(serde::de::Error::custom("VarInt was too large"))
}
}
deserializer.deserialize_seq(VarIntVisitor)
}
}
impl PacketWrite for VarInt { impl PacketWrite for VarInt {
fn write<W: Write>(&self, writer: &mut W) -> Result<(), Error> { fn write<W: Write>(&self, writer: &mut W) -> Result<(), Error> {
let mut val = ((self.0 << 1) ^ (self.0 >> 31)) as u32; let mut val = ((self.0 << 1) ^ (self.0 >> 31)) as u32;

View File

@ -4,11 +4,6 @@ use std::{
ops::Deref, ops::Deref,
}; };
use serde::{
Deserialize, Deserializer, Serialize, Serializer,
de::{self, SeqAccess, Visitor},
};
use crate::{ use crate::{
WritingError, WritingError,
ser::{NetworkReadExt, NetworkWriteExt, ReadingError}, ser::{NetworkReadExt, NetworkWriteExt, ReadingError},
@ -92,53 +87,6 @@ impl Deref for VarLong {
} }
} }
impl Serialize for VarLong {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
let mut value = self.0 as u64;
let mut buf = Vec::new();
while value > 0x7F {
buf.push(value as u8 | 0x80);
value >>= 7;
}
buf.push(value as u8);
serializer.serialize_bytes(&buf)
}
}
impl<'de> Deserialize<'de> for VarLong {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
struct VarLongVisitor;
impl<'de> Visitor<'de> for VarLongVisitor {
type Value = VarLong;
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
formatter.write_str("a valid VarInt encoded in a byte sequence")
}
fn visit_seq<A: SeqAccess<'de>>(self, mut seq: A) -> Result<Self::Value, A::Error> {
let mut val = 0;
for i in 0..VarLong::MAX_SIZE.get() {
if let Some(byte) = seq.next_element::<u8>()? {
val |= (i64::from(byte) & 0b0111_1111) << (i * 7);
if byte & 0b1000_0000 == 0 {
return Ok(VarLong(val));
}
} else {
break;
}
}
Err(de::Error::custom("VarInt was too large"))
}
}
deserializer.deserialize_seq(VarLongVisitor)
}
}
impl PacketRead for VarLong { impl PacketRead for VarLong {
fn read<R: Read>(reader: &mut R) -> Result<Self, Error> { fn read<R: Read>(reader: &mut R) -> Result<Self, Error> {
let mut val: u64 = 0; let mut val: u64 = 0;

View File

@ -3,11 +3,6 @@ use std::{
num::NonZeroUsize, num::NonZeroUsize,
}; };
use bytes::BufMut;
use serde::{
Deserialize, Deserializer, Serialize, Serializer,
de::{SeqAccess, Visitor},
};
use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt}; use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt};
use crate::{ use crate::{
@ -136,53 +131,6 @@ gen_from!(u64);
gen_from!(isize); gen_from!(isize);
gen_from!(usize); gen_from!(usize);
impl Serialize for VarUInt {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
let mut value = self.0;
let mut buf = Vec::with_capacity(5);
while value > 0x7F {
buf.put_u8(value as u8 | 0x80);
value >>= 7;
}
buf.put_u8(value as u8);
serializer.serialize_bytes(&buf)
}
}
impl<'de> Deserialize<'de> for VarUInt {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
struct VarIntVisitor;
impl<'de> Visitor<'de> for VarIntVisitor {
type Value = VarUInt;
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
formatter.write_str("a valid VarInt encoded in a byte sequence")
}
fn visit_seq<A: SeqAccess<'de>>(self, mut seq: A) -> Result<Self::Value, A::Error> {
let mut val = 0;
for i in 0..VarUInt::MAX_SIZE.get() {
if let Some(byte) = seq.next_element::<u8>()? {
val |= (u32::from(byte) & 0b0111_1111) << (i * 7);
if byte & 0b1000_0000 == 0 {
return Ok(VarUInt(val));
}
} else {
break;
}
}
Err(serde::de::Error::custom("VarInt was too large"))
}
}
deserializer.deserialize_seq(VarIntVisitor)
}
}
impl PacketWrite for VarUInt { impl PacketWrite for VarUInt {
fn write<W: Write>(&self, writer: &mut W) -> Result<(), Error> { fn write<W: Write>(&self, writer: &mut W) -> Result<(), Error> {
let mut val = self.0; let mut val = self.0;

View File

@ -4,11 +4,6 @@ use std::{
ops::Deref, ops::Deref,
}; };
use serde::{
Deserialize, Deserializer, Serialize, Serializer,
de::{self, SeqAccess, Visitor},
};
use crate::{ use crate::{
WritingError, WritingError,
ser::{NetworkReadExt, NetworkWriteExt, ReadingError}, ser::{NetworkReadExt, NetworkWriteExt, ReadingError},
@ -115,53 +110,6 @@ impl Deref for VarULong {
} }
} }
impl Serialize for VarULong {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
let mut value = self.0;
let mut buf = Vec::new();
while value > 0x7F {
buf.push(value as u8 | 0x80);
value >>= 7;
}
buf.push(value as u8);
serializer.serialize_bytes(&buf)
}
}
impl<'de> Deserialize<'de> for VarULong {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
struct VarLongVisitor;
impl<'de> Visitor<'de> for VarLongVisitor {
type Value = VarULong;
fn expecting(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
formatter.write_str("a valid VarInt encoded in a byte sequence")
}
fn visit_seq<A: SeqAccess<'de>>(self, mut seq: A) -> Result<Self::Value, A::Error> {
let mut val = 0;
for i in 0..VarULong::MAX_SIZE.get() {
if let Some(byte) = seq.next_element::<u8>()? {
val |= (u64::from(byte) & 0b0111_1111) << (i * 7);
if byte & 0b1000_0000 == 0 {
return Ok(VarULong(val));
}
} else {
break;
}
}
Err(de::Error::custom("VarInt was too large"))
}
}
deserializer.deserialize_seq(VarLongVisitor)
}
}
impl PacketWrite for VarULong { impl PacketWrite for VarULong {
fn write<W: Write>(&self, writer: &mut W) -> Result<(), Error> { fn write<W: Write>(&self, writer: &mut W) -> Result<(), Error> {
let mut x = self.0; let mut x = self.0;

View File

@ -1,14 +1,15 @@
use pumpkin_util::text::TextComponent; use pumpkin_util::text::TextComponent;
use pumpkin_macros::java_packet; use pumpkin_macros::java_packet;
use serde::Serialize;
use pumpkin_data::packet::clientbound::CONFIG_RESOURCE_PACK_PUSH; use pumpkin_data::packet::clientbound::CONFIG_RESOURCE_PACK_PUSH;
#[derive(Serialize)] use crate::ClientPacket;
use crate::ser::NetworkWriteExt;
use pumpkin_util::version::JavaMinecraftVersion;
#[java_packet(CONFIG_RESOURCE_PACK_PUSH)] #[java_packet(CONFIG_RESOURCE_PACK_PUSH)]
pub struct CConfigAddResourcePack<'a> { pub struct CConfigAddResourcePack<'a> {
#[serde(with = "uuid::serde::compact")]
pub uuid: &'a uuid::Uuid, pub uuid: &'a uuid::Uuid,
pub url: &'a str, pub url: &'a str,
pub hash: &'a str, // max 40 pub hash: &'a str, // max 40
@ -34,3 +35,23 @@ impl<'a> CConfigAddResourcePack<'a> {
} }
} }
} }
impl ClientPacket for CConfigAddResourcePack<'_> {
fn write_packet_data(
&self,
mut write: impl std::io::Write,
_version: &JavaMinecraftVersion,
) -> Result<(), crate::ser::WritingError> {
write.write_uuid(self.uuid)?;
write.write_string(self.url)?;
write.write_string(self.hash)?;
write.write_bool(self.forced)?;
if let Some(_prompt) = &self.prompt_message {
write.write_bool(true)?;
// TODO
} else {
write.write_bool(false)?;
}
Ok(())
}
}

View File

@ -1,8 +1,9 @@
use pumpkin_data::packet::clientbound::CONFIG_CLEAR_DIALOG; use pumpkin_data::packet::clientbound::CONFIG_CLEAR_DIALOG;
use pumpkin_macros::java_packet; use pumpkin_macros::java_packet;
use serde::Serialize;
#[derive(Serialize)] use crate::ClientPacket;
use pumpkin_util::version::JavaMinecraftVersion;
#[java_packet(CONFIG_CLEAR_DIALOG)] #[java_packet(CONFIG_CLEAR_DIALOG)]
pub struct CConfigClearDialog; pub struct CConfigClearDialog;
@ -18,3 +19,13 @@ impl Default for CConfigClearDialog {
Self::new() Self::new()
} }
} }
impl ClientPacket for CConfigClearDialog {
fn write_packet_data(
&self,
_write: impl std::io::Write,
_version: &JavaMinecraftVersion,
) -> Result<(), crate::ser::WritingError> {
Ok(())
}
}

View File

@ -1,8 +1,10 @@
use pumpkin_data::packet::clientbound::CONFIG_DISCONNECT; use pumpkin_data::packet::clientbound::CONFIG_DISCONNECT;
use pumpkin_macros::java_packet; use pumpkin_macros::java_packet;
use serde::Deserialize;
#[derive(serde::Serialize, Deserialize)] use crate::ClientPacket;
use crate::ser::NetworkWriteExt;
use pumpkin_util::version::JavaMinecraftVersion;
#[java_packet(CONFIG_DISCONNECT)] #[java_packet(CONFIG_DISCONNECT)]
pub struct CConfigDisconnect<'a> { pub struct CConfigDisconnect<'a> {
pub reason: &'a str, pub reason: &'a str,
@ -14,3 +16,14 @@ impl<'a> CConfigDisconnect<'a> {
Self { reason } Self { reason }
} }
} }
impl ClientPacket for CConfigDisconnect<'_> {
fn write_packet_data(
&self,
mut write: impl std::io::Write,
_version: &JavaMinecraftVersion,
) -> Result<(), crate::ser::WritingError> {
write.write_string(self.reason)?;
Ok(())
}
}

View File

@ -2,7 +2,10 @@ use pumpkin_data::packet::clientbound::CONFIG_COOKIE_REQUEST;
use pumpkin_macros::java_packet; use pumpkin_macros::java_packet;
use pumpkin_util::resource_location::ResourceLocation; use pumpkin_util::resource_location::ResourceLocation;
#[derive(serde::Serialize)] use crate::ClientPacket;
use crate::ser::NetworkWriteExt;
use pumpkin_util::version::JavaMinecraftVersion;
#[java_packet(CONFIG_COOKIE_REQUEST)] #[java_packet(CONFIG_COOKIE_REQUEST)]
/// Requests a cookie that was previously stored. /// Requests a cookie that was previously stored.
pub struct CCookieRequest<'a> { pub struct CCookieRequest<'a> {
@ -15,3 +18,14 @@ impl<'a> CCookieRequest<'a> {
Self { key } Self { key }
} }
} }
impl ClientPacket for CCookieRequest<'_> {
fn write_packet_data(
&self,
mut write: impl std::io::Write,
_version: &JavaMinecraftVersion,
) -> Result<(), crate::ser::WritingError> {
write.write_string(self.key)?;
Ok(())
}
}

View File

@ -1,7 +1,18 @@
use pumpkin_data::packet::clientbound::CONFIG_FINISH_CONFIGURATION; use pumpkin_data::packet::clientbound::CONFIG_FINISH_CONFIGURATION;
use pumpkin_macros::java_packet; use pumpkin_macros::java_packet;
use serde::Serialize;
#[derive(Serialize)] use crate::ClientPacket;
use pumpkin_util::version::JavaMinecraftVersion;
#[java_packet(CONFIG_FINISH_CONFIGURATION)] #[java_packet(CONFIG_FINISH_CONFIGURATION)]
pub struct CFinishConfig; pub struct CFinishConfig;
impl ClientPacket for CFinishConfig {
fn write_packet_data(
&self,
_write: impl std::io::Write,
_version: &JavaMinecraftVersion,
) -> Result<(), crate::ser::WritingError> {
Ok(())
}
}

View File

@ -1,10 +1,11 @@
use pumpkin_data::packet::clientbound::CONFIG_SELECT_KNOWN_PACKS; use pumpkin_data::packet::clientbound::CONFIG_SELECT_KNOWN_PACKS;
use pumpkin_macros::java_packet; use pumpkin_macros::java_packet;
use serde::Serialize;
use crate::ClientPacket;
use crate::KnownPack; use crate::KnownPack;
use crate::ser::NetworkWriteExt;
use pumpkin_util::version::JavaMinecraftVersion;
#[derive(Serialize)]
#[java_packet(CONFIG_SELECT_KNOWN_PACKS)] #[java_packet(CONFIG_SELECT_KNOWN_PACKS)]
pub struct CKnownPacks<'a> { pub struct CKnownPacks<'a> {
pub known_packs: &'a [KnownPack<'a>], pub known_packs: &'a [KnownPack<'a>],
@ -16,3 +17,17 @@ impl<'a> CKnownPacks<'a> {
Self { known_packs } Self { known_packs }
} }
} }
impl ClientPacket for CKnownPacks<'_> {
fn write_packet_data(
&self,
mut write: impl std::io::Write,
_version: &JavaMinecraftVersion,
) -> Result<(), crate::ser::WritingError> {
write.write_var_int(&crate::VarInt(self.known_packs.len() as i32))?;
for pack in self.known_packs {
pack.write(&mut write)?;
}
Ok(())
}
}

View File

@ -1,9 +1,11 @@
use crate::Link; use crate::Link;
use pumpkin_data::packet::clientbound::CONFIG_SERVER_LINKS; use pumpkin_data::packet::clientbound::CONFIG_SERVER_LINKS;
use pumpkin_macros::java_packet; use pumpkin_macros::java_packet;
use serde::Serialize;
#[derive(Serialize)] use crate::ClientPacket;
use crate::ser::NetworkWriteExt;
use pumpkin_util::version::JavaMinecraftVersion;
#[java_packet(CONFIG_SERVER_LINKS)] #[java_packet(CONFIG_SERVER_LINKS)]
pub struct CConfigServerLinks<'a> { pub struct CConfigServerLinks<'a> {
pub links: &'a [Link<'a>], pub links: &'a [Link<'a>],
@ -15,3 +17,17 @@ impl<'a> CConfigServerLinks<'a> {
Self { links } Self { links }
} }
} }
impl ClientPacket for CConfigServerLinks<'_> {
fn write_packet_data(
&self,
mut write: impl std::io::Write,
_version: &JavaMinecraftVersion,
) -> Result<(), crate::ser::WritingError> {
write.write_var_int(&crate::VarInt(self.links.len() as i32))?;
for link in self.links {
link.write(&mut write)?;
}
Ok(())
}
}

View File

@ -2,9 +2,10 @@ use crate::IdOr;
use crate::java::client::dialog::DialogNBT; use crate::java::client::dialog::DialogNBT;
use pumpkin_data::packet::clientbound::CONFIG_SHOW_DIALOG; use pumpkin_data::packet::clientbound::CONFIG_SHOW_DIALOG;
use pumpkin_macros::java_packet; use pumpkin_macros::java_packet;
use serde::Serialize;
#[derive(Serialize)] use crate::ClientPacket;
use pumpkin_util::version::JavaMinecraftVersion;
#[java_packet(CONFIG_SHOW_DIALOG)] #[java_packet(CONFIG_SHOW_DIALOG)]
pub struct CConfigShowDialog<'a> { pub struct CConfigShowDialog<'a> {
pub dialog: IdOr<DialogNBT<'a>>, pub dialog: IdOr<DialogNBT<'a>>,
@ -16,3 +17,15 @@ impl<'a> CConfigShowDialog<'a> {
Self { dialog } Self { dialog }
} }
} }
impl ClientPacket for CConfigShowDialog<'_> {
fn write_packet_data(
&self,
mut write: impl std::io::Write,
version: &JavaMinecraftVersion,
) -> Result<(), crate::ser::WritingError> {
self.dialog
.write(&mut write, |w, dialog| dialog.write_packet_data(w, version))?;
Ok(())
}
}

View File

@ -2,7 +2,10 @@ use pumpkin_data::packet::clientbound::CONFIG_STORE_COOKIE;
use pumpkin_macros::java_packet; use pumpkin_macros::java_packet;
use pumpkin_util::resource_location::ResourceLocation; use pumpkin_util::resource_location::ResourceLocation;
#[derive(serde::Serialize)] use crate::ClientPacket;
use crate::ser::NetworkWriteExt;
use pumpkin_util::version::JavaMinecraftVersion;
#[java_packet(CONFIG_STORE_COOKIE)] #[java_packet(CONFIG_STORE_COOKIE)]
/// Stores some arbitrary data on the client, which persists between server transfers. /// Stores some arbitrary data on the client, which persists between server transfers.
/// The Notchian (vanilla) client only accepts cookies of up to 5 KiB in size. /// The Notchian (vanilla) client only accepts cookies of up to 5 KiB in size.
@ -17,3 +20,16 @@ impl<'a> CStoreCookie<'a> {
Self { key, payload } Self { key, payload }
} }
} }
impl ClientPacket for CStoreCookie<'_> {
fn write_packet_data(
&self,
mut write: impl std::io::Write,
_version: &JavaMinecraftVersion,
) -> Result<(), crate::ser::WritingError> {
write.write_string(self.key)?;
write.write_var_int(&crate::VarInt(self.payload.len() as i32))?;
write.write_all(self.payload)?;
Ok(())
}
}

View File

@ -1,9 +1,11 @@
use crate::VarInt; use crate::VarInt;
use pumpkin_data::packet::clientbound::CONFIG_TRANSFER; use pumpkin_data::packet::clientbound::CONFIG_TRANSFER;
use pumpkin_macros::java_packet; use pumpkin_macros::java_packet;
use serde::Serialize;
#[derive(Serialize)] use crate::ClientPacket;
use crate::ser::NetworkWriteExt;
use pumpkin_util::version::JavaMinecraftVersion;
#[java_packet(CONFIG_TRANSFER)] #[java_packet(CONFIG_TRANSFER)]
pub struct CTransfer<'a> { pub struct CTransfer<'a> {
pub host: &'a str, pub host: &'a str,
@ -16,3 +18,15 @@ impl<'a> CTransfer<'a> {
Self { host, port } Self { host, port }
} }
} }
impl ClientPacket for CTransfer<'_> {
fn write_packet_data(
&self,
mut write: impl std::io::Write,
_version: &JavaMinecraftVersion,
) -> Result<(), crate::ser::WritingError> {
write.write_string(self.host)?;
write.write_var_int(self.port)?;
Ok(())
}
}

View File

@ -1,7 +1,8 @@
use pumpkin_util::text::TextComponent; use pumpkin_util::text::TextComponent;
use serde::Serialize;
#[derive(Serialize)] use crate::ser::NetworkWriteExt;
use pumpkin_util::version::JavaMinecraftVersion;
pub struct DialogNBT<'a>(pub DialogNBTSource<'a>); pub struct DialogNBT<'a>(pub DialogNBTSource<'a>);
impl<'a> DialogNBT<'a> { impl<'a> DialogNBT<'a> {
@ -14,70 +15,67 @@ impl<'a> DialogNBT<'a> {
pub const fn from_nbt(compound: &'a pumpkin_nbt::compound::NbtCompound) -> Self { pub const fn from_nbt(compound: &'a pumpkin_nbt::compound::NbtCompound) -> Self {
Self(DialogNBTSource::Nbt(compound)) Self(DialogNBTSource::Nbt(compound))
} }
#[allow(clippy::todo)]
pub fn write_packet_data(
&self,
mut write: impl std::io::Write,
_version: &JavaMinecraftVersion,
) -> Result<(), crate::ser::WritingError> {
match &self.0 {
DialogNBTSource::Struct(_dialog) => {
todo!("Serialize Dialog to NbtCompound manually")
}
DialogNBTSource::Nbt(nbt) => {
let tag = pumpkin_nbt::tag::NbtTag::Compound((*nbt).clone());
write.write_nbt(tag)?;
Ok(())
}
}
}
} }
#[derive(Serialize)]
#[serde(untagged)]
pub enum DialogNBTSource<'a> { pub enum DialogNBTSource<'a> {
Struct(&'a Dialog), Struct(&'a Dialog),
Nbt(&'a pumpkin_nbt::compound::NbtCompound), Nbt(&'a pumpkin_nbt::compound::NbtCompound),
} }
#[derive(Serialize)]
pub struct Dialog { pub struct Dialog {
pub r#type: String, pub r#type: String,
pub title: TextComponent, pub title: TextComponent,
#[serde(skip_serializing_if = "Vec::is_empty")]
pub body: Vec<DialogBody>, pub body: Vec<DialogBody>,
#[serde(skip_serializing_if = "Vec::is_empty")]
pub inputs: Vec<DialogInput>, pub inputs: Vec<DialogInput>,
#[serde(skip_serializing_if = "Vec::is_empty")]
pub buttons: Vec<ActionButton>, pub buttons: Vec<ActionButton>,
#[serde(skip_serializing_if = "Vec::is_empty")]
pub links: Vec<DialogLink>, pub links: Vec<DialogLink>,
#[serde(skip_serializing_if = "Option::is_none")]
pub exit_action: Option<DialogAction>, pub exit_action: Option<DialogAction>,
#[serde(skip_serializing_if = "Option::is_none")]
pub after_action: Option<String>, pub after_action: Option<String>,
pub can_close_with_escape: bool, pub can_close_with_escape: bool,
#[serde(skip_serializing_if = "Option::is_none")]
pub external_title: Option<TextComponent>, pub external_title: Option<TextComponent>,
} }
#[derive(Serialize)]
#[serde(tag = "type", rename_all = "snake_case")]
pub enum DialogBody { pub enum DialogBody {
#[serde(rename = "minecraft:plain_message")]
PlainMessage { contents: TextComponent }, PlainMessage { contents: TextComponent },
#[serde(rename = "minecraft:item")]
Item { item: i32 }, // TODO: ItemStack serialization to NBT Item { item: i32 }, // TODO: ItemStack serialization to NBT
} }
#[derive(Serialize)]
#[serde(tag = "type", rename_all = "snake_case")]
pub enum DialogInput { pub enum DialogInput {
#[serde(rename = "minecraft:boolean")]
Boolean { Boolean {
label: TextComponent, label: TextComponent,
default_value: bool, default_value: bool,
}, },
#[serde(rename = "minecraft:text")]
Text { Text {
label: TextComponent, label: TextComponent,
placeholder: TextComponent, placeholder: TextComponent,
default_value: String, default_value: String,
}, },
#[serde(rename = "minecraft:number_range")]
NumberRange { NumberRange {
label: TextComponent, label: TextComponent,
min: f32, min: f32,
max: f32, max: f32,
initial: f32, initial: f32,
step: f32, step: f32,
#[serde(skip_serializing_if = "Option::is_none")]
label_format: Option<String>, label_format: Option<String>,
}, },
#[serde(rename = "minecraft:single_option")]
SingleOption { SingleOption {
label: TextComponent, label: TextComponent,
options: Vec<TextComponent>, options: Vec<TextComponent>,
@ -85,30 +83,23 @@ pub enum DialogInput {
}, },
} }
#[derive(Serialize)]
pub struct ActionButton { pub struct ActionButton {
pub text: TextComponent, pub text: TextComponent,
#[serde(skip_serializing_if = "Option::is_none")]
pub tooltip: Option<TextComponent>, pub tooltip: Option<TextComponent>,
#[serde(skip_serializing_if = "Option::is_none")]
pub width: Option<u32>, pub width: Option<u32>,
pub action: DialogAction, pub action: DialogAction,
} }
#[derive(Serialize)]
#[serde(tag = "type", rename_all = "snake_case")]
pub enum DialogAction { pub enum DialogAction {
#[serde(rename = "minecraft:open_url")] OpenUrl {
OpenUrl { url: String }, url: String,
#[serde(rename = "minecraft:custom")] },
Custom { Custom {
id: String, id: String,
#[serde(skip_serializing_if = "Option::is_none")]
payload: Option<Vec<u8>>, payload: Option<Vec<u8>>,
}, },
} }
#[derive(Serialize)]
pub struct DialogLink { pub struct DialogLink {
pub label: crate::Label, pub label: crate::Label,
pub url: String, pub url: String,

View File

@ -1,13 +1,15 @@
use pumpkin_data::packet::clientbound::LOGIN_COOKIE_REQUEST; use pumpkin_data::packet::clientbound::LOGIN_COOKIE_REQUEST;
use pumpkin_macros::java_packet; use pumpkin_macros::java_packet;
use pumpkin_util::resource_location::ResourceLocation; use pumpkin_util::resource_location::ResourceLocation;
use serde::Serialize;
use crate::ClientPacket;
use crate::ser::NetworkWriteExt;
use pumpkin_util::version::JavaMinecraftVersion;
/// Sent by the server to retrieve a previously stored cookie from the client. /// Sent by the server to retrieve a previously stored cookie from the client.
/// ///
/// This occurs during the login phase, allowing the server to identify /// This occurs during the login phase, allowing the server to identify
/// returning players or retrieve session data stored during a previous visit. /// returning players or retrieve session data stored during a previous visit.
#[derive(Serialize)]
#[java_packet(LOGIN_COOKIE_REQUEST)] #[java_packet(LOGIN_COOKIE_REQUEST)]
pub struct CLoginCookieRequest<'a> { pub struct CLoginCookieRequest<'a> {
/// The unique identifier of the cookie being requested. /// The unique identifier of the cookie being requested.
@ -20,3 +22,14 @@ impl<'a> CLoginCookieRequest<'a> {
Self { key } Self { key }
} }
} }
impl ClientPacket for CLoginCookieRequest<'_> {
fn write_packet_data(
&self,
mut write: impl std::io::Write,
_version: &JavaMinecraftVersion,
) -> Result<(), crate::ser::WritingError> {
write.write_string(self.key)?;
Ok(())
}
}

View File

@ -1,13 +1,15 @@
use pumpkin_data::packet::clientbound::LOGIN_HELLO; use pumpkin_data::packet::clientbound::LOGIN_HELLO;
use pumpkin_macros::java_packet; use pumpkin_macros::java_packet;
use serde::{Deserialize, Serialize};
use crate::ClientPacket;
use crate::ser::NetworkWriteExt;
use pumpkin_util::version::JavaMinecraftVersion;
/// Sent by the server to initiate the encryption handshake. /// Sent by the server to initiate the encryption handshake.
/// ///
/// This packet provides the client with the server's public key and a /// This packet provides the client with the server's public key and a
/// verification token, allowing the client to generate a shared secret /// verification token, allowing the client to generate a shared secret
/// for secure communication. /// for secure communication.
#[derive(Serialize, Deserialize)]
#[java_packet(LOGIN_HELLO)] #[java_packet(LOGIN_HELLO)]
pub struct CEncryptionRequest<'a> { pub struct CEncryptionRequest<'a> {
/// The server's ID string. In modern Minecraft, this is usually /// The server's ID string. In modern Minecraft, this is usually
@ -39,3 +41,19 @@ impl<'a> CEncryptionRequest<'a> {
} }
} }
} }
impl ClientPacket for CEncryptionRequest<'_> {
fn write_packet_data(
&self,
mut write: impl std::io::Write,
_version: &JavaMinecraftVersion,
) -> Result<(), crate::ser::WritingError> {
write.write_string(self.server_id)?;
write.write_var_int(&crate::VarInt(self.public_key.len() as i32))?;
write.write_all(self.public_key)?;
write.write_var_int(&crate::VarInt(self.verify_token.len() as i32))?;
write.write_all(self.verify_token)?;
write.write_bool(self.should_authenticate)?;
Ok(())
}
}

View File

@ -1,12 +1,14 @@
use pumpkin_data::packet::clientbound::LOGIN_LOGIN_DISCONNECT; use pumpkin_data::packet::clientbound::LOGIN_LOGIN_DISCONNECT;
use pumpkin_macros::java_packet; use pumpkin_macros::java_packet;
use serde::{Deserialize, Serialize};
use crate::ClientPacket;
use crate::ser::NetworkWriteExt;
use pumpkin_util::version::JavaMinecraftVersion;
/// Sent by the server to reject a login attempt or kick a player during the login phase /// Sent by the server to reject a login attempt or kick a player during the login phase
/// ///
/// This is used for reasons such as the server being full, the player being banned, /// This is used for reasons such as the server being full, the player being banned,
/// or version mismatches. After this packet is sent, the connection is closed. /// or version mismatches. After this packet is sent, the connection is closed.
#[derive(Serialize, Deserialize)]
#[java_packet(LOGIN_LOGIN_DISCONNECT)] #[java_packet(LOGIN_LOGIN_DISCONNECT)]
pub struct CLoginDisconnect { pub struct CLoginDisconnect {
/// A JSON-encoded chat component explaining why the player was disconnected. /// A JSON-encoded chat component explaining why the player was disconnected.
@ -19,3 +21,14 @@ impl CLoginDisconnect {
Self { json_reason } Self { json_reason }
} }
} }
impl ClientPacket for CLoginDisconnect {
fn write_packet_data(
&self,
mut write: impl std::io::Write,
_version: &JavaMinecraftVersion,
) -> Result<(), crate::ser::WritingError> {
write.write_string(&self.json_reason)?;
Ok(())
}
}

View File

@ -1,6 +1,5 @@
use pumpkin_data::packet::clientbound::{LOGIN_GAME_PROFILE, LOGIN_LOGIN_FINISHED}; use pumpkin_data::packet::clientbound::{LOGIN_GAME_PROFILE, LOGIN_LOGIN_FINISHED};
use pumpkin_util::version::JavaMinecraftVersion; use pumpkin_util::version::JavaMinecraftVersion;
use serde::Serialize;
use crate::{ClientPacket, Property, packet::MultiVersionJavaPacket, ser::NetworkWriteExt}; use crate::{ClientPacket, Property, packet::MultiVersionJavaPacket, ser::NetworkWriteExt};
@ -60,10 +59,7 @@ impl ClientPacket for CLoginSuccess<'_> {
) -> Result<(), crate::ser::WritingError> { ) -> Result<(), crate::ser::WritingError> {
write.write_uuid(self.uuid)?; write.write_uuid(self.uuid)?;
write.write_string(self.username)?; write.write_string(self.username)?;
write.write_list(self.properties, |write, property| { write.write_list(self.properties, |write, property| property.write(write))?;
let mut serializer = crate::ser::serializer::Serializer::new(write);
property.serialize(&mut serializer)
})?;
if version < &JavaMinecraftVersion::V_1_21_2 { if version < &JavaMinecraftVersion::V_1_21_2 {
write.write_bool(self.strict_error_handling)?; write.write_bool(self.strict_error_handling)?;
} else if version >= &JavaMinecraftVersion::V_26_2 { } else if version >= &JavaMinecraftVersion::V_26_2 {

View File

@ -1,14 +1,15 @@
use pumpkin_data::packet::clientbound::LOGIN_LOGIN_COMPRESSION; use pumpkin_data::packet::clientbound::LOGIN_LOGIN_COMPRESSION;
use pumpkin_macros::java_packet; use pumpkin_macros::java_packet;
use serde::{Deserialize, Serialize};
use crate::ClientPacket;
use crate::VarInt; use crate::VarInt;
use crate::ser::NetworkWriteExt;
use pumpkin_util::version::JavaMinecraftVersion;
/// Sent by the server to enable network compression for all subsequent packets. /// Sent by the server to enable network compression for all subsequent packets.
/// ///
/// Once this packet is sent, both the server and the client must compress any /// Once this packet is sent, both the server and the client must compress any
/// packet with a size equal to or greater than the specified threshold. /// packet with a size equal to or greater than the specified threshold.
#[derive(Serialize, Deserialize)]
#[java_packet(LOGIN_LOGIN_COMPRESSION)] #[java_packet(LOGIN_LOGIN_COMPRESSION)]
pub struct CSetCompression { pub struct CSetCompression {
/// The packet size threshold (in bytes) at which compression is applied. /// The packet size threshold (in bytes) at which compression is applied.
@ -24,3 +25,14 @@ impl CSetCompression {
Self { threshold } Self { threshold }
} }
} }
impl ClientPacket for CSetCompression {
fn write_packet_data(
&self,
mut write: impl std::io::Write,
_version: &JavaMinecraftVersion,
) -> Result<(), crate::ser::WritingError> {
write.write_var_int(&self.threshold)?;
Ok(())
}
}

View File

@ -1,14 +1,13 @@
use crate::ClientPacket;
use crate::VarInt;
use crate::ser::NetworkWriteExt;
use pumpkin_data::packet::clientbound::PLAY_BLOCK_CHANGED_ACK; use pumpkin_data::packet::clientbound::PLAY_BLOCK_CHANGED_ACK;
use pumpkin_macros::java_packet; use pumpkin_macros::java_packet;
use serde::{Deserialize, Serialize}; use pumpkin_util::version::JavaMinecraftVersion;
use crate::VarInt;
/// Sent by the server to acknowledge a sequence of block changes initiated by the client. /// Sent by the server to acknowledge a sequence of block changes initiated by the client.
/// ///
/// This packet is critical for preventing "ghost blocks" and synchronization issues. /// This packet is critical for preventing "ghost blocks" and synchronization issues.
/// It tells the client that the server has processed all actions up to a specific point. /// It tells the client that the server has processed all actions up to a specific point.
#[derive(Serialize, Deserialize)]
#[java_packet(PLAY_BLOCK_CHANGED_ACK)] #[java_packet(PLAY_BLOCK_CHANGED_ACK)]
pub struct CAcknowledgeBlockChange { pub struct CAcknowledgeBlockChange {
/// The ID of the last sequence processed by the server. /// The ID of the last sequence processed by the server.
@ -25,3 +24,14 @@ impl CAcknowledgeBlockChange {
Self { sequence_id } Self { sequence_id }
} }
} }
impl ClientPacket for CAcknowledgeBlockChange {
fn write_packet_data(
&self,
mut write: impl std::io::Write,
_version: &JavaMinecraftVersion,
) -> Result<(), crate::ser::WritingError> {
write.write_var_int(&self.sequence_id)?;
Ok(())
}
}

View File

@ -1,15 +1,15 @@
use pumpkin_data::packet::clientbound::PLAY_SET_ACTION_BAR_TEXT; use pumpkin_data::packet::clientbound::PLAY_SET_ACTION_BAR_TEXT;
use pumpkin_util::text::TextComponent; use pumpkin_util::text::TextComponent;
use crate::ClientPacket;
use crate::ser::NetworkWriteExt;
use pumpkin_macros::java_packet; use pumpkin_macros::java_packet;
use serde::Serialize; use pumpkin_util::version::JavaMinecraftVersion;
/// Updates the text displayed above the player's hotbar (the Action Bar). /// Updates the text displayed above the player's hotbar (the Action Bar).
/// ///
/// Unlike chat messages, Action Bar text is transient and generally used for /// Unlike chat messages, Action Bar text is transient and generally used for
/// non-critical status information like "Now entering: Wilderness" or /// non-critical status information like "Now entering: Wilderness" or
/// mana/stamina counters. /// mana/stamina counters.
#[derive(Serialize)]
#[java_packet(PLAY_SET_ACTION_BAR_TEXT)] #[java_packet(PLAY_SET_ACTION_BAR_TEXT)]
pub struct CActionBar<'a> { pub struct CActionBar<'a> {
/// The text component to be displayed. /// The text component to be displayed.
@ -22,3 +22,14 @@ impl<'a> CActionBar<'a> {
Self { action_bar } Self { action_bar }
} }
} }
impl ClientPacket for CActionBar<'_> {
fn write_packet_data(
&self,
mut write: impl std::io::Write,
_version: &JavaMinecraftVersion,
) -> Result<(), crate::ser::WritingError> {
write.write_slice(&self.action_bar.encode())?;
Ok(())
}
}

View File

@ -1,17 +1,41 @@
use pumpkin_data::packet::clientbound::PLAY_AWARD_STATS; use pumpkin_data::packet::clientbound::PLAY_AWARD_STATS;
use pumpkin_macros::java_packet; use pumpkin_macros::java_packet;
use crate::ClientPacket;
use crate::codec::var_int::VarInt; use crate::codec::var_int::VarInt;
use crate::ser::NetworkWriteExt;
use pumpkin_util::version::JavaMinecraftVersion;
#[derive(serde::Serialize)]
#[java_packet(PLAY_AWARD_STATS)] #[java_packet(PLAY_AWARD_STATS)]
pub struct CAwardStats<'a> { pub struct CAwardStats<'a> {
pub stats: &'a [Statistic], pub stats: &'a [Statistic],
} }
#[derive(serde::Serialize)]
pub struct Statistic { pub struct Statistic {
pub category_id: VarInt, pub category_id: VarInt,
pub statistic_id: VarInt, pub statistic_id: VarInt,
pub value: VarInt, pub value: VarInt,
} }
impl Statistic {
pub fn write(&self, mut write: impl std::io::Write) -> Result<(), crate::ser::WritingError> {
write.write_var_int(&self.category_id)?;
write.write_var_int(&self.statistic_id)?;
write.write_var_int(&self.value)?;
Ok(())
}
}
impl ClientPacket for CAwardStats<'_> {
fn write_packet_data(
&self,
mut write: impl std::io::Write,
_version: &JavaMinecraftVersion,
) -> Result<(), crate::ser::WritingError> {
write.write_var_int(&VarInt(self.stats.len() as i32))?;
for stat in self.stats {
stat.write(&mut write)?;
}
Ok(())
}
}

View File

@ -1,16 +1,16 @@
use pumpkin_data::packet::clientbound::PLAY_BLOCK_DESTRUCTION; use pumpkin_data::packet::clientbound::PLAY_BLOCK_DESTRUCTION;
use pumpkin_util::math::position::BlockPos; use pumpkin_util::math::position::BlockPos;
use pumpkin_macros::java_packet; use crate::ClientPacket;
use serde::Serialize;
use crate::VarInt; use crate::VarInt;
use crate::ser::NetworkWriteExt;
use pumpkin_macros::java_packet;
use pumpkin_util::version::JavaMinecraftVersion;
/// Updates the visual "breaking" progress of a block for all clients. /// Updates the visual "breaking" progress of a block for all clients.
/// ///
/// This packet controls the overlay of cracks that appear on a block when /// This packet controls the overlay of cracks that appear on a block when
/// it is being mined. It is often used to show other players' mining progress. /// it is being mined. It is often used to show other players' mining progress.
#[derive(Serialize)]
#[java_packet(PLAY_BLOCK_DESTRUCTION)] #[java_packet(PLAY_BLOCK_DESTRUCTION)]
pub struct CSetBlockDestroyStage { pub struct CSetBlockDestroyStage {
/// A unique ID for this destruction instance. Usually the miner's Entity ID. /// A unique ID for this destruction instance. Usually the miner's Entity ID.
@ -33,3 +33,16 @@ impl CSetBlockDestroyStage {
} }
} }
} }
impl ClientPacket for CSetBlockDestroyStage {
fn write_packet_data(
&self,
mut write: impl std::io::Write,
_version: &JavaMinecraftVersion,
) -> Result<(), crate::ser::WritingError> {
write.write_var_int(&self.entity_id)?;
write.write_block_pos(&self.location)?;
write.write_i8(self.destroy_stage)?;
Ok(())
}
}

View File

@ -1,16 +1,16 @@
use pumpkin_data::packet::clientbound::PLAY_BLOCK_EVENT; use pumpkin_data::packet::clientbound::PLAY_BLOCK_EVENT;
use pumpkin_util::math::position::BlockPos; use pumpkin_util::math::position::BlockPos;
use pumpkin_macros::java_packet; use crate::ClientPacket;
use serde::Serialize;
use crate::VarInt; use crate::VarInt;
use crate::ser::NetworkWriteExt;
use pumpkin_macros::java_packet;
use pumpkin_util::version::JavaMinecraftVersion;
/// Triggers a physical block animation or sound effect. /// Triggers a physical block animation or sound effect.
/// ///
/// This is used for simple block interactions that don't necessarily change /// This is used for simple block interactions that don't necessarily change
/// NBT data, such as chests opening/closing, pistons extending, or note blocks playing. /// NBT data, such as chests opening/closing, pistons extending, or note blocks playing.
#[derive(Serialize)]
#[java_packet(PLAY_BLOCK_EVENT)] #[java_packet(PLAY_BLOCK_EVENT)]
pub struct CBlockEvent { pub struct CBlockEvent {
/// The coordinates where the event occurs. /// The coordinates where the event occurs.
@ -40,3 +40,17 @@ impl CBlockEvent {
} }
} }
} }
impl ClientPacket for CBlockEvent {
fn write_packet_data(
&self,
mut write: impl std::io::Write,
_version: &JavaMinecraftVersion,
) -> Result<(), crate::ser::WritingError> {
write.write_block_pos(&self.location)?;
write.write_u8(self.action_id)?;
write.write_u8(self.action_parameter)?;
write.write_var_int(&self.block_type)?;
Ok(())
}
}

View File

@ -1,15 +1,15 @@
use crate::ClientPacket;
use crate::VarInt;
use crate::ser::NetworkWriteExt;
use pumpkin_data::packet::clientbound::PLAY_SET_CHUNK_CACHE_CENTER; use pumpkin_data::packet::clientbound::PLAY_SET_CHUNK_CACHE_CENTER;
use pumpkin_macros::java_packet; use pumpkin_macros::java_packet;
use serde::Serialize; use pumpkin_util::version::JavaMinecraftVersion;
use crate::VarInt;
/// Updates the center of the player's loaded chunk radius (the "view center"). /// Updates the center of the player's loaded chunk radius (the "view center").
/// ///
/// This packet tells the client which chunk coordinate it should use as the /// This packet tells the client which chunk coordinate it should use as the
/// focal point for loading and unloading chunks. It is typically sent when /// focal point for loading and unloading chunks. It is typically sent when
/// a player moves across a chunk boundary. /// a player moves across a chunk boundary.
#[derive(Serialize)]
#[java_packet(PLAY_SET_CHUNK_CACHE_CENTER)] #[java_packet(PLAY_SET_CHUNK_CACHE_CENTER)]
pub struct CCenterChunk { pub struct CCenterChunk {
/// The X coordinate of the center chunk. /// The X coordinate of the center chunk.
@ -17,3 +17,15 @@ pub struct CCenterChunk {
/// The Z coordinate of the center chunk. /// The Z coordinate of the center chunk.
pub chunk_z: VarInt, pub chunk_z: VarInt,
} }
impl ClientPacket for CCenterChunk {
fn write_packet_data(
&self,
mut write: impl std::io::Write,
_version: &JavaMinecraftVersion,
) -> Result<(), crate::ser::WritingError> {
write.write_var_int(&self.chunk_x)?;
write.write_var_int(&self.chunk_z)?;
Ok(())
}
}

View File

@ -1,13 +1,14 @@
use crate::ClientPacket;
use crate::ser::NetworkWriteExt;
use pumpkin_data::packet::clientbound::PLAY_CHANGE_DIFFICULTY; use pumpkin_data::packet::clientbound::PLAY_CHANGE_DIFFICULTY;
use pumpkin_macros::java_packet; use pumpkin_macros::java_packet;
use serde::Serialize; use pumpkin_util::version::JavaMinecraftVersion;
/// Notifies the client of a change in the world's difficulty level or lock status. /// Notifies the client of a change in the world's difficulty level or lock status.
/// ///
/// This updates the client's internal state, which affects certain UI elements /// This updates the client's internal state, which affects certain UI elements
/// and client-side behavior (though actual game logic like mob damage is /// and client-side behavior (though actual game logic like mob damage is
/// primarily handled by the server). /// primarily handled by the server).
#[derive(Serialize)]
#[java_packet(PLAY_CHANGE_DIFFICULTY)] #[java_packet(PLAY_CHANGE_DIFFICULTY)]
pub struct CChangeDifficulty { pub struct CChangeDifficulty {
/// The current difficulty level of the world. /// The current difficulty level of the world.
@ -28,3 +29,15 @@ impl CChangeDifficulty {
Self { difficulty, locked } Self { difficulty, locked }
} }
} }
impl ClientPacket for CChangeDifficulty {
fn write_packet_data(
&self,
mut write: impl std::io::Write,
_version: &JavaMinecraftVersion,
) -> Result<(), crate::ser::WritingError> {
write.write_u8(self.difficulty)?;
write.write_bool(self.locked)?;
Ok(())
}
}

View File

@ -1,15 +1,15 @@
use crate::ClientPacket;
use crate::codec::var_int::VarInt;
use crate::ser::NetworkWriteExt;
use pumpkin_data::packet::clientbound::PLAY_CHUNK_BATCH_FINISHED; use pumpkin_data::packet::clientbound::PLAY_CHUNK_BATCH_FINISHED;
use pumpkin_macros::java_packet; use pumpkin_macros::java_packet;
use serde::Serialize; use pumpkin_util::version::JavaMinecraftVersion;
use crate::codec::var_int::VarInt;
/// Notifies the client that the server has finished sending a batch of chunks. /// Notifies the client that the server has finished sending a batch of chunks.
/// ///
/// Introduced in modern protocol versions to optimize world loading, this packet /// Introduced in modern protocol versions to optimize world loading, this packet
/// allows the client to acknowledge the receipt of a group of chunks, helping /// allows the client to acknowledge the receipt of a group of chunks, helping
/// the server regulate the flow of data and prevent network congestion. /// the server regulate the flow of data and prevent network congestion.
#[derive(Serialize)]
#[java_packet(PLAY_CHUNK_BATCH_FINISHED)] #[java_packet(PLAY_CHUNK_BATCH_FINISHED)]
pub struct CChunkBatchEnd { pub struct CChunkBatchEnd {
/// The number of chunks sent in the batch that just finished. /// The number of chunks sent in the batch that just finished.
@ -24,3 +24,14 @@ impl CChunkBatchEnd {
} }
} }
} }
impl ClientPacket for CChunkBatchEnd {
fn write_packet_data(
&self,
mut write: impl std::io::Write,
_version: &JavaMinecraftVersion,
) -> Result<(), crate::ser::WritingError> {
write.write_var_int(&self.batch_size)?;
Ok(())
}
}

View File

@ -1,13 +1,22 @@
use crate::ClientPacket;
use pumpkin_data::packet::clientbound::PLAY_CHUNK_BATCH_START; use pumpkin_data::packet::clientbound::PLAY_CHUNK_BATCH_START;
use pumpkin_macros::java_packet; use pumpkin_macros::java_packet;
use serde::Serialize; use pumpkin_util::version::JavaMinecraftVersion;
/// Signals the beginning of a new batch of chunk data packets. /// Signals the beginning of a new batch of chunk data packets.
/// ///
/// This packet initiates a synchronized chunk loading sequence. In modern /// This packet initiates a synchronized chunk loading sequence. In modern
/// protocol versions, the server must wrap chunk data transmissions between /// protocol versions, the server must wrap chunk data transmissions between
/// a `Start` and `End` packet to manage client-side backpressure and /// a `Start` and `End` packet to manage client-side backpressure and
/// network throughput. /// network throughput.
#[derive(Serialize)]
#[java_packet(PLAY_CHUNK_BATCH_START)] #[java_packet(PLAY_CHUNK_BATCH_START)]
pub struct CChunkBatchStart; pub struct CChunkBatchStart;
impl ClientPacket for CChunkBatchStart {
fn write_packet_data(
&self,
_write: impl std::io::Write,
_version: &JavaMinecraftVersion,
) -> Result<(), crate::ser::WritingError> {
Ok(())
}
}

View File

@ -1,8 +1,7 @@
use crate::ClientPacket;
use pumpkin_data::packet::clientbound::PLAY_CLEAR_DIALOG; use pumpkin_data::packet::clientbound::PLAY_CLEAR_DIALOG;
use pumpkin_macros::java_packet; use pumpkin_macros::java_packet;
use serde::Serialize; use pumpkin_util::version::JavaMinecraftVersion;
#[derive(Serialize)]
#[java_packet(PLAY_CLEAR_DIALOG)] #[java_packet(PLAY_CLEAR_DIALOG)]
pub struct CPlayClearDialog; pub struct CPlayClearDialog;
@ -18,3 +17,13 @@ impl Default for CPlayClearDialog {
Self::new() Self::new()
} }
} }
impl ClientPacket for CPlayClearDialog {
fn write_packet_data(
&self,
_write: impl std::io::Write,
_version: &JavaMinecraftVersion,
) -> Result<(), crate::ser::WritingError> {
Ok(())
}
}

View File

@ -1,12 +1,12 @@
use crate::ClientPacket;
use crate::ser::NetworkWriteExt;
use pumpkin_data::packet::clientbound::PLAY_CLEAR_TITLES; use pumpkin_data::packet::clientbound::PLAY_CLEAR_TITLES;
use pumpkin_macros::java_packet; use pumpkin_macros::java_packet;
use serde::Serialize; use pumpkin_util::version::JavaMinecraftVersion;
/// Removes any currently displayed Title or Subtitle from the player's screen. /// Removes any currently displayed Title or Subtitle from the player's screen.
/// ///
/// This packet is used to immediately hide titles that are currently in their /// This packet is used to immediately hide titles that are currently in their
/// "stay" or "fade-out" phases. /// "stay" or "fade-out" phases.
#[derive(Serialize)]
#[java_packet(PLAY_CLEAR_TITLES)] #[java_packet(PLAY_CLEAR_TITLES)]
pub struct CClearTitle { pub struct CClearTitle {
/// If true, the client also resets the title timings (fade-in, stay, fade-out) /// If true, the client also resets the title timings (fade-in, stay, fade-out)
@ -23,3 +23,14 @@ impl CClearTitle {
Self { reset } Self { reset }
} }
} }
impl ClientPacket for CClearTitle {
fn write_packet_data(
&self,
mut write: impl std::io::Write,
_version: &JavaMinecraftVersion,
) -> Result<(), crate::ser::WritingError> {
write.write_bool(self.reset)?;
Ok(())
}
}

View File

@ -1,15 +1,15 @@
use crate::ClientPacket;
use crate::VarInt;
use crate::ser::NetworkWriteExt;
use pumpkin_data::packet::clientbound::PLAY_CONTAINER_CLOSE; use pumpkin_data::packet::clientbound::PLAY_CONTAINER_CLOSE;
use pumpkin_macros::java_packet; use pumpkin_macros::java_packet;
use serde::Serialize; use pumpkin_util::version::JavaMinecraftVersion;
use crate::VarInt;
/// Notifies the client that a container (inventory, chest, etc.) has been closed. /// Notifies the client that a container (inventory, chest, etc.) has been closed.
/// ///
/// This is used by the server to force the player's UI to shut, for example, /// This is used by the server to force the player's UI to shut, for example,
/// if the player moves too far away from a chest or if an NPC's trade window /// if the player moves too far away from a chest or if an NPC's trade window
/// is invalidated. /// is invalidated.
#[derive(Serialize)]
#[java_packet(PLAY_CONTAINER_CLOSE)] #[java_packet(PLAY_CONTAINER_CLOSE)]
pub struct CCloseContainer { pub struct CCloseContainer {
/// The ID of the container window to close. /// The ID of the container window to close.
@ -24,3 +24,14 @@ impl CCloseContainer {
Self { sync_id: window_id } Self { sync_id: window_id }
} }
} }
impl ClientPacket for CCloseContainer {
fn write_packet_data(
&self,
mut write: impl std::io::Write,
_version: &JavaMinecraftVersion,
) -> Result<(), crate::ser::WritingError> {
write.write_var_int(&self.sync_id)?;
Ok(())
}
}

View File

@ -1,15 +1,15 @@
use crate::ClientPacket;
use crate::VarInt;
use crate::ser::NetworkWriteExt;
use pumpkin_data::packet::clientbound::PLAY_PLAYER_COMBAT_KILL; use pumpkin_data::packet::clientbound::PLAY_PLAYER_COMBAT_KILL;
use pumpkin_macros::java_packet; use pumpkin_macros::java_packet;
use pumpkin_util::text::TextComponent; use pumpkin_util::text::TextComponent;
use serde::Serialize; use pumpkin_util::version::JavaMinecraftVersion;
use crate::VarInt;
/// Notifies the client that a player has died. /// Notifies the client that a player has died.
/// ///
/// This packet is responsible for triggering the death screen on the client /// This packet is responsible for triggering the death screen on the client
/// and displaying the death message in the chat for the deceased player. /// and displaying the death message in the chat for the deceased player.
#[derive(Serialize)]
#[java_packet(PLAY_PLAYER_COMBAT_KILL)] #[java_packet(PLAY_PLAYER_COMBAT_KILL)]
pub struct CCombatDeath<'a> { pub struct CCombatDeath<'a> {
/// The Entity ID of the player who died. /// The Entity ID of the player who died.
@ -24,3 +24,15 @@ impl<'a> CCombatDeath<'a> {
Self { player_id, message } Self { player_id, message }
} }
} }
impl ClientPacket for CCombatDeath<'_> {
fn write_packet_data(
&self,
mut write: impl std::io::Write,
_version: &JavaMinecraftVersion,
) -> Result<(), crate::ser::WritingError> {
write.write_var_int(&self.player_id)?;
write.write_slice(&self.message.encode())?;
Ok(())
}
}

View File

@ -1,16 +1,16 @@
use crate::ClientPacket;
use crate::VarInt;
use crate::ser::NetworkWriteExt;
use pumpkin_data::packet::clientbound::PLAY_COMMAND_SUGGESTIONS; use pumpkin_data::packet::clientbound::PLAY_COMMAND_SUGGESTIONS;
use pumpkin_macros::java_packet; use pumpkin_macros::java_packet;
use pumpkin_util::text::TextComponent; use pumpkin_util::text::TextComponent;
use serde::Serialize; use pumpkin_util::version::JavaMinecraftVersion;
use crate::VarInt;
/// Sent by the server to provide a list of "tab-completion" suggestions. /// Sent by the server to provide a list of "tab-completion" suggestions.
/// ///
/// This packet responds to a client's request for help with commands, /// This packet responds to a client's request for help with commands,
/// appearing as a scrollable list of options while the player is typing /// appearing as a scrollable list of options while the player is typing
/// in the chat bar. /// in the chat bar.
#[derive(Serialize)]
#[java_packet(PLAY_COMMAND_SUGGESTIONS)] #[java_packet(PLAY_COMMAND_SUGGESTIONS)]
pub struct CCommandSuggestions { pub struct CCommandSuggestions {
/// The unique ID of the request this response is for. /// The unique ID of the request this response is for.
@ -44,7 +44,7 @@ impl CCommandSuggestions {
} }
} }
#[derive(PartialEq, Eq, Hash, Debug, Serialize)] #[derive(PartialEq, Eq, Hash, Debug)]
pub struct CommandSuggestion { pub struct CommandSuggestion {
pub suggestion: String, pub suggestion: String,
pub tooltip: Option<TextComponent>, pub tooltip: Option<TextComponent>,
@ -58,4 +58,32 @@ impl CommandSuggestion {
tooltip, tooltip,
} }
} }
pub fn write(&self, mut write: impl std::io::Write) -> Result<(), crate::ser::WritingError> {
write.write_string(&self.suggestion)?;
if let Some(tooltip) = &self.tooltip {
write.write_bool(true)?;
write.write_slice(&tooltip.encode())?;
} else {
write.write_bool(false)?;
}
Ok(())
}
}
impl ClientPacket for CCommandSuggestions {
fn write_packet_data(
&self,
mut write: impl std::io::Write,
_version: &JavaMinecraftVersion,
) -> Result<(), crate::ser::WritingError> {
write.write_var_int(&self.id)?;
write.write_var_int(&self.start)?;
write.write_var_int(&self.length)?;
write.write_var_int(&VarInt(self.matches.len() as i32))?;
for match_ in &self.matches {
match_.write(&mut write)?;
}
Ok(())
}
} }

View File

@ -1,14 +1,15 @@
use crate::ClientPacket;
use crate::ser::NetworkWriteExt;
use pumpkin_data::packet::clientbound::PLAY_COOKIE_REQUEST; use pumpkin_data::packet::clientbound::PLAY_COOKIE_REQUEST;
use pumpkin_macros::java_packet; use pumpkin_macros::java_packet;
use pumpkin_util::resource_location::ResourceLocation; use pumpkin_util::resource_location::ResourceLocation;
use serde::Serialize; use pumpkin_util::version::JavaMinecraftVersion;
/// Sent by the server to request a "cookie" (stored data) from the client. /// Sent by the server to request a "cookie" (stored data) from the client.
/// ///
/// Introduced in modern Minecraft versions, cookies allow servers to store /// Introduced in modern Minecraft versions, cookies allow servers to store
/// small amounts of persistent data on the client side that can be retrieved /// small amounts of persistent data on the client side that can be retrieved
/// even across different server instances or sub-servers in a network. /// even across different server instances or sub-servers in a network.
#[derive(Serialize)]
#[java_packet(PLAY_COOKIE_REQUEST)] #[java_packet(PLAY_COOKIE_REQUEST)]
pub struct CPlayCookieRequest<'a> { pub struct CPlayCookieRequest<'a> {
/// The unique identifier (namespace:path) of the cookie to retrieve. /// The unique identifier (namespace:path) of the cookie to retrieve.
@ -21,3 +22,14 @@ impl<'a> CPlayCookieRequest<'a> {
Self { key } Self { key }
} }
} }
impl ClientPacket for CPlayCookieRequest<'_> {
fn write_packet_data(
&self,
mut write: impl std::io::Write,
_version: &JavaMinecraftVersion,
) -> Result<(), crate::ser::WritingError> {
write.write_string(self.key)?;
Ok(())
}
}

View File

@ -1,9 +1,10 @@
use crate::ClientPacket;
use crate::VarInt;
use crate::ser::NetworkWriteExt;
use pumpkin_data::packet::clientbound::PLAY_DAMAGE_EVENT; use pumpkin_data::packet::clientbound::PLAY_DAMAGE_EVENT;
use pumpkin_macros::java_packet; use pumpkin_macros::java_packet;
use pumpkin_util::math::vector3::Vector3; use pumpkin_util::math::vector3::Vector3;
use serde::Serialize; use pumpkin_util::version::JavaMinecraftVersion;
use crate::VarInt;
/// Notifies the client that an entity has taken damage. /// Notifies the client that an entity has taken damage.
/// ///
@ -11,7 +12,6 @@ use crate::VarInt;
/// directional knockback visuals, and sound effects. It provides the client /// directional knockback visuals, and sound effects. It provides the client
/// with specific details about the damage source to ensure the visual feedback /// with specific details about the damage source to ensure the visual feedback
/// matches the cause. /// matches the cause.
#[derive(Serialize)]
#[java_packet(PLAY_DAMAGE_EVENT)] #[java_packet(PLAY_DAMAGE_EVENT)]
pub struct CDamageEvent { pub struct CDamageEvent {
/// The Entity ID of the entity taking damage. /// The Entity ID of the entity taking damage.
@ -48,3 +48,25 @@ impl CDamageEvent {
} }
} }
} }
impl ClientPacket for CDamageEvent {
fn write_packet_data(
&self,
mut write: impl std::io::Write,
_version: &JavaMinecraftVersion,
) -> Result<(), crate::ser::WritingError> {
write.write_var_int(&self.entity_id)?;
write.write_var_int(&self.source_type_id)?;
write.write_var_int(&self.source_cause_id)?;
write.write_var_int(&self.source_direct_id)?;
if let Some(pos) = &self.source_position {
write.write_bool(true)?;
write.write_f64(pos.x)?;
write.write_f64(pos.y)?;
write.write_f64(pos.z)?;
} else {
write.write_bool(false)?;
}
Ok(())
}
}

View File

@ -1,15 +1,16 @@
use pumpkin_data::packet::clientbound::PLAY_DISCONNECT; use pumpkin_data::packet::clientbound::PLAY_DISCONNECT;
use pumpkin_util::text::TextComponent; use pumpkin_util::text::TextComponent;
use crate::ClientPacket;
use crate::ser::NetworkWriteExt;
use pumpkin_macros::java_packet; use pumpkin_macros::java_packet;
use serde::Serialize; use pumpkin_util::version::JavaMinecraftVersion;
/// Forces the client to disconnect from the server while in the "Play" state. /// Forces the client to disconnect from the server while in the "Play" state.
/// ///
/// This packet displays the provided reason to the player on a dedicated /// This packet displays the provided reason to the player on a dedicated
/// disconnection screen. It is used for kicks, server shutdowns, or when /// disconnection screen. It is used for kicks, server shutdowns, or when
/// a player is banned. /// a player is banned.
#[derive(Serialize)]
#[java_packet(PLAY_DISCONNECT)] #[java_packet(PLAY_DISCONNECT)]
pub struct CPlayDisconnect<'a> { pub struct CPlayDisconnect<'a> {
/// The message shown to the player explaining why they were disconnected. /// The message shown to the player explaining why they were disconnected.
@ -23,3 +24,14 @@ impl<'a> CPlayDisconnect<'a> {
Self { reason } Self { reason }
} }
} }
impl ClientPacket for CPlayDisconnect<'_> {
fn write_packet_data(
&self,
mut write: impl std::io::Write,
_version: &JavaMinecraftVersion,
) -> Result<(), crate::ser::WritingError> {
write.write_slice(&self.reason.encode())?;
Ok(())
}
}

View File

@ -1,17 +1,17 @@
use pumpkin_data::packet::clientbound::PLAY_DISGUISED_CHAT; use pumpkin_data::packet::clientbound::PLAY_DISGUISED_CHAT;
use pumpkin_macros::java_packet;
use pumpkin_util::text::TextComponent; use pumpkin_util::text::TextComponent;
use pumpkin_macros::java_packet; use crate::ClientPacket;
use serde::Serialize;
use crate::VarInt; use crate::VarInt;
use crate::ser::NetworkWriteExt;
use pumpkin_util::version::JavaMinecraftVersion;
/// Sends a chat message that is not cryptographically signed by a player. /// Sends a chat message that is not cryptographically signed by a player.
/// ///
/// Introduced to support server-side "disguised" identities (like /say or NPC chat), /// Introduced to support server-side "disguised" identities (like /say or NPC chat),
/// this packet bypasses the player-to-player chat signing requirements while /// this packet bypasses the player-to-player chat signing requirements while
/// still allowing the client to format the message using the standard chat registry. /// still allowing the client to format the message using the standard chat registry.
#[derive(Serialize)]
#[java_packet(PLAY_DISGUISED_CHAT)] #[java_packet(PLAY_DISGUISED_CHAT)]
pub struct CDisguisedChatMessage<'a> { pub struct CDisguisedChatMessage<'a> {
/// The raw content of the message. /// The raw content of the message.
@ -41,3 +41,22 @@ impl<'a> CDisguisedChatMessage<'a> {
} }
} }
} }
impl ClientPacket for CDisguisedChatMessage<'_> {
fn write_packet_data(
&self,
mut write: impl std::io::Write,
_version: &JavaMinecraftVersion,
) -> Result<(), crate::ser::WritingError> {
write.write_slice(&self.message.encode())?;
write.write_var_int(&self.chat_type)?;
write.write_slice(&self.sender_name.encode())?;
if let Some(target) = self.target_name {
write.write_bool(true)?;
write.write_slice(&target.encode())?;
} else {
write.write_bool(false)?;
}
Ok(())
}
}

View File

@ -1,17 +1,17 @@
use crate::ClientPacket;
use crate::VarInt;
use crate::ser::NetworkWriteExt;
use pumpkin_data::{ use pumpkin_data::{
packet::clientbound::PLAY_SET_DISPLAY_OBJECTIVE, scoreboard::ScoreboardDisplaySlot, packet::clientbound::PLAY_SET_DISPLAY_OBJECTIVE, scoreboard::ScoreboardDisplaySlot,
}; };
use pumpkin_macros::java_packet; use pumpkin_macros::java_packet;
use serde::Serialize; use pumpkin_util::version::JavaMinecraftVersion;
use crate::VarInt;
/// Instructs the client to display a specific scoreboard objective in a given slot. /// Instructs the client to display a specific scoreboard objective in a given slot.
/// ///
/// This packet is the final step in showing a scoreboard to a player. After /// This packet is the final step in showing a scoreboard to a player. After
/// an objective is created and populated with scores, this packet "maps" /// an objective is created and populated with scores, this packet "maps"
/// that objective to a visual location like the sidebar or the player list. /// that objective to a visual location like the sidebar or the player list.
#[derive(Serialize)]
#[java_packet(PLAY_SET_DISPLAY_OBJECTIVE)] #[java_packet(PLAY_SET_DISPLAY_OBJECTIVE)]
pub struct CDisplayObjective { pub struct CDisplayObjective {
/// The display slot/position for the objective. /// The display slot/position for the objective.
@ -30,3 +30,15 @@ impl CDisplayObjective {
} }
} }
} }
impl ClientPacket for CDisplayObjective {
fn write_packet_data(
&self,
mut write: impl std::io::Write,
_version: &JavaMinecraftVersion,
) -> Result<(), crate::ser::WritingError> {
write.write_var_int(&self.position)?;
write.write_string(&self.score_name)?;
Ok(())
}
}

View File

@ -1,14 +1,14 @@
use crate::ClientPacket;
use crate::VarInt;
use crate::ser::NetworkWriteExt;
use pumpkin_data::packet::clientbound::PLAY_ANIMATE; use pumpkin_data::packet::clientbound::PLAY_ANIMATE;
use pumpkin_macros::java_packet; use pumpkin_macros::java_packet;
use serde::Serialize; use pumpkin_util::version::JavaMinecraftVersion;
use crate::VarInt;
/// Triggers a specific animation for an entity that is visible to the client. /// Triggers a specific animation for an entity that is visible to the client.
/// ///
/// This is primarily used for player-driven animations like swinging an arm /// This is primarily used for player-driven animations like swinging an arm
/// or showing damage, but it can apply to other entities as well. /// or showing damage, but it can apply to other entities as well.
#[derive(Serialize)]
#[java_packet(PLAY_ANIMATE)] #[java_packet(PLAY_ANIMATE)]
pub struct CEntityAnimation { pub struct CEntityAnimation {
/// The Entity ID of the entity performing the animation. /// The Entity ID of the entity performing the animation.
@ -28,6 +28,18 @@ impl CEntityAnimation {
} }
} }
impl ClientPacket for CEntityAnimation {
fn write_packet_data(
&self,
mut write: impl std::io::Write,
_version: &JavaMinecraftVersion,
) -> Result<(), crate::ser::WritingError> {
write.write_var_int(&self.entity_id)?;
write.write_u8(self.animation)?;
Ok(())
}
}
#[derive(Debug)] #[derive(Debug)]
pub enum Animation { pub enum Animation {
SwingMainArm, SwingMainArm,

View File

@ -7,13 +7,22 @@ use pumpkin_data::{
}; };
use pumpkin_macros::java_packet; use pumpkin_macros::java_packet;
use pumpkin_util::version::JavaMinecraftVersion; use pumpkin_util::version::JavaMinecraftVersion;
use serde::Serialize;
use crate::{ use crate::{
ClientPacket, VarInt, ClientPacket, VarInt,
ser::{NetworkWriteExt, WritingError, serializer}, ser::{NetworkWriteExt, WritingError},
}; };
pub trait MetadataSerializer {
fn write_metadata(&self, writer: &mut impl std::io::Write) -> Result<(), WritingError>;
}
impl<T: MetadataSerializer + ?Sized> MetadataSerializer for &T {
fn write_metadata(&self, writer: &mut impl std::io::Write) -> Result<(), WritingError> {
(*self).write_metadata(writer)
}
}
/// Updates the "Data Tracker" values for an entity. /// Updates the "Data Tracker" values for an entity.
/// ///
/// Entity Metadata (or `DataWatchers`) controls persistent visual states that /// Entity Metadata (or `DataWatchers`) controls persistent visual states that
@ -41,17 +50,13 @@ impl CSetEntityMetadata {
impl ClientPacket for CSetEntityMetadata { impl ClientPacket for CSetEntityMetadata {
fn write_packet_data( fn write_packet_data(
&self, &self,
write: impl Write, mut write: impl Write,
_version: &JavaMinecraftVersion, _version: &JavaMinecraftVersion,
) -> Result<(), WritingError> { ) -> Result<(), WritingError> {
let mut write = write;
// 1. Entity ID // 1. Entity ID
write.write_var_int(&self.entity_id)?; write.write_var_int(&self.entity_id)?;
write write.write_slice(&self.metadata)
.write_all(&self.metadata)
.map_err(WritingError::IoError)
} }
} }
@ -73,10 +78,10 @@ impl<T> Metadata<T> {
pub fn write<W: std::io::Write>( pub fn write<W: std::io::Write>(
&self, &self,
mut writer: W, mut writer: W,
version: &pumpkin_util::version::JavaMinecraftVersion, version: &JavaMinecraftVersion,
) -> Result<(), WritingError> ) -> Result<(), WritingError>
where where
T: Serialize, T: MetadataSerializer,
{ {
let resolved_index = self.index.get(version); let resolved_index = self.index.get(version);
@ -95,12 +100,7 @@ impl<T> Metadata<T> {
if self.r#type == MetaDataType::BLOCK_STATE { if self.r#type == MetaDataType::BLOCK_STATE {
let mut serialized_value = Vec::new(); let mut serialized_value = Vec::new();
{ self.value.write_metadata(&mut serialized_value)?;
let mut serializer = serializer::Serializer::new(&mut serialized_value);
self.value
.serialize(&mut serializer)
.map_err(|e| WritingError::Serde(e.to_string()))?;
};
let mut cursor = Cursor::new(serialized_value); let mut cursor = Cursor::new(serialized_value);
let decoded_state = VarInt::decode(&mut cursor).map_err(|e| { let decoded_state = VarInt::decode(&mut cursor).map_err(|e| {
@ -115,12 +115,7 @@ impl<T> Metadata<T> {
if self.r#type == MetaDataType::ITEM_STACK { if self.r#type == MetaDataType::ITEM_STACK {
let mut serialized_value = Vec::new(); let mut serialized_value = Vec::new();
{ self.value.write_metadata(&mut serialized_value)?;
let mut serializer = serializer::Serializer::new(&mut serialized_value);
self.value
.serialize(&mut serializer)
.map_err(|e| WritingError::Serde(e.to_string()))?;
};
let mut cursor = Cursor::new(serialized_value); let mut cursor = Cursor::new(serialized_value);
let item_count = VarInt::decode(&mut cursor).map_err(|e| { let item_count = VarInt::decode(&mut cursor).map_err(|e| {
@ -138,18 +133,134 @@ impl<T> Metadata<T> {
writer.write_var_int(&VarInt(i32::from(remapped_id)))?; writer.write_var_int(&VarInt(i32::from(remapped_id)))?;
let remainder_start = cursor.position() as usize; let remainder_start = cursor.position() as usize;
let inner = cursor.into_inner(); let inner = cursor.into_inner();
writer.write_all(&inner[remainder_start..]).map_err(|e| { writer.write_slice(&inner[remainder_start..])?;
WritingError::Message(format!("Failed to write item stack remainder: {e}"))
})?;
} }
return Ok(()); return Ok(());
} }
let mut serializer = serializer::Serializer::new(&mut writer); self.value.write_metadata(&mut writer)?;
self.value
.serialize(&mut serializer)
.map_err(|e| WritingError::Serde(e.to_string()))?;
Ok(()) Ok(())
} }
} }
impl MetadataSerializer for bool {
fn write_metadata(&self, writer: &mut impl std::io::Write) -> Result<(), WritingError> {
writer.write_bool(*self)
}
}
impl MetadataSerializer for i8 {
fn write_metadata(&self, writer: &mut impl std::io::Write) -> Result<(), WritingError> {
writer.write_i8(*self)
}
}
impl MetadataSerializer for u8 {
fn write_metadata(&self, writer: &mut impl std::io::Write) -> Result<(), WritingError> {
writer.write_u8(*self)
}
}
impl MetadataSerializer for i16 {
fn write_metadata(&self, writer: &mut impl std::io::Write) -> Result<(), WritingError> {
writer.write_i16(*self)
}
}
impl MetadataSerializer for u16 {
fn write_metadata(&self, writer: &mut impl std::io::Write) -> Result<(), WritingError> {
writer.write_u16(*self)
}
}
impl MetadataSerializer for i32 {
fn write_metadata(&self, writer: &mut impl std::io::Write) -> Result<(), WritingError> {
writer.write_i32(*self)
}
}
impl MetadataSerializer for u32 {
fn write_metadata(&self, writer: &mut impl std::io::Write) -> Result<(), WritingError> {
writer.write_u32(*self)
}
}
impl MetadataSerializer for f32 {
fn write_metadata(&self, writer: &mut impl std::io::Write) -> Result<(), WritingError> {
writer.write_f32(*self)
}
}
impl MetadataSerializer for VarInt {
fn write_metadata(&self, writer: &mut impl std::io::Write) -> Result<(), WritingError> {
writer.write_var_int(self)
}
}
impl MetadataSerializer for String {
fn write_metadata(&self, writer: &mut impl std::io::Write) -> Result<(), WritingError> {
writer.write_string(self)
}
}
impl MetadataSerializer for pumpkin_util::text::TextComponent {
fn write_metadata(&self, writer: &mut impl std::io::Write) -> Result<(), WritingError> {
writer.write_slice(&self.encode())
}
}
impl MetadataSerializer for Option<pumpkin_util::text::TextComponent> {
fn write_metadata(&self, writer: &mut impl std::io::Write) -> Result<(), WritingError> {
if let Some(text) = self {
writer.write_bool(true)?;
writer.write_slice(&text.encode())?;
} else {
writer.write_bool(false)?;
}
Ok(())
}
}
impl MetadataSerializer for crate::codec::item_stack_seralizer::ItemStackSerializer<'_> {
fn write_metadata(&self, writer: &mut impl std::io::Write) -> Result<(), WritingError> {
self.write(writer)
}
}
impl MetadataSerializer for Option<String> {
fn write_metadata(&self, writer: &mut impl std::io::Write) -> Result<(), WritingError> {
if let Some(s) = self {
writer.write_bool(true)?;
writer.write_string(s)?;
} else {
writer.write_bool(false)?;
}
Ok(())
}
}
impl MetadataSerializer for pumpkin_util::math::position::BlockPos {
fn write_metadata(&self, writer: &mut impl std::io::Write) -> Result<(), WritingError> {
writer.write_block_pos(self)
}
}
impl MetadataSerializer for Option<pumpkin_util::math::position::BlockPos> {
fn write_metadata(&self, writer: &mut impl std::io::Write) -> Result<(), WritingError> {
if let Some(pos) = self {
writer.write_bool(true)?;
writer.write_block_pos(pos)?;
} else {
writer.write_bool(false)?;
}
Ok(())
}
}
impl MetadataSerializer for crate::codec::optional_int::OptionalInt {
fn write_metadata(&self, writer: &mut impl std::io::Write) -> Result<(), WritingError> {
let val = self.0.map_or(0, |id| id + 1);
writer.write_var_int(&VarInt(val))
}
}

View File

@ -1,9 +1,10 @@
use crate::ClientPacket;
use crate::VarInt;
use crate::ser::NetworkWriteExt;
use pumpkin_data::packet::clientbound::PLAY_ENTITY_POSITION_SYNC; use pumpkin_data::packet::clientbound::PLAY_ENTITY_POSITION_SYNC;
use pumpkin_macros::java_packet; use pumpkin_macros::java_packet;
use pumpkin_util::math::vector3::Vector3; use pumpkin_util::math::vector3::Vector3;
use serde::Serialize; use pumpkin_util::version::JavaMinecraftVersion;
use crate::VarInt;
/// Updates the exact position, rotation, and velocity of an entity. /// Updates the exact position, rotation, and velocity of an entity.
/// ///
@ -14,7 +15,6 @@ use crate::VarInt;
/// Note: This packet must NOT be used for the player receiving the packet or /// Note: This packet must NOT be used for the player receiving the packet or
/// any entity the player is currently riding. /// any entity the player is currently riding.
#[java_packet(PLAY_ENTITY_POSITION_SYNC)] #[java_packet(PLAY_ENTITY_POSITION_SYNC)]
#[derive(Serialize)]
pub struct CEntityPositionSync { pub struct CEntityPositionSync {
/// The Entity ID of the entity being moved. /// The Entity ID of the entity being moved.
pub entity_id: VarInt, pub entity_id: VarInt,
@ -51,3 +51,23 @@ impl CEntityPositionSync {
} }
} }
} }
impl ClientPacket for CEntityPositionSync {
fn write_packet_data(
&self,
mut write: impl std::io::Write,
_version: &JavaMinecraftVersion,
) -> Result<(), crate::ser::WritingError> {
write.write_var_int(&self.entity_id)?;
write.write_f64(self.position.x)?;
write.write_f64(self.position.y)?;
write.write_f64(self.position.z)?;
write.write_f64(self.delta.x)?;
write.write_f64(self.delta.y)?;
write.write_f64(self.delta.z)?;
write.write_f32(self.yaw)?;
write.write_f32(self.pitch)?;
write.write_bool(self.on_ground)?;
Ok(())
}
}

View File

@ -65,12 +65,15 @@ impl ClientPacket for CEntitySoundEffect {
IdOr::Value(value) => IdOr::Value(value.clone()), IdOr::Value(value) => IdOr::Value(value.clone()),
}; };
write.write_serialize(&sound_event)?; crate::IdOr::<crate::SoundEvent>::write(&sound_event, &mut write, |w, e| {
write.write_serialize(&self.sound_category)?; w.write_string(&e.sound_name)?;
write.write_serialize(&self.entity_id)?; w.write_option(&e.range, |w2, r| w2.write_f32(*r))
write.write_serialize(&self.volume)?; })?;
write.write_serialize(&self.pitch)?; write.write_var_int(&self.sound_category)?;
write.write_serialize(&self.seed) write.write_var_int(&self.entity_id)?;
write.write_f32(self.volume)?;
write.write_f32(self.pitch)?;
write.write_i64(self.seed)
} }
} }

View File

@ -1,6 +1,9 @@
use pumpkin_data::packet::clientbound::PLAY_ENTITY_EVENT; use pumpkin_data::packet::clientbound::PLAY_ENTITY_EVENT;
use pumpkin_macros::java_packet; use pumpkin_macros::java_packet;
use serde::{Deserialize, Serialize};
use crate::ClientPacket;
use crate::ser::NetworkWriteExt;
use pumpkin_util::version::JavaMinecraftVersion;
/// Sends a status update for a specific entity. /// Sends a status update for a specific entity.
/// ///
@ -8,7 +11,6 @@ use serde::{Deserialize, Serialize};
/// warrant a complex packet of their own. It primarily handles visual /// warrant a complex packet of their own. It primarily handles visual
/// and logical state triggers, such as tool breaking, totem usage, /// and logical state triggers, such as tool breaking, totem usage,
/// or sheep shearing. /// or sheep shearing.
#[derive(Serialize, Deserialize)]
#[java_packet(PLAY_ENTITY_EVENT)] #[java_packet(PLAY_ENTITY_EVENT)]
pub struct CEntityStatus { pub struct CEntityStatus {
/// The Entity ID of the entity affected by the status change. /// The Entity ID of the entity affected by the status change.
@ -27,3 +29,15 @@ impl CEntityStatus {
} }
} }
} }
impl ClientPacket for CEntityStatus {
fn write_packet_data(
&self,
mut write: impl std::io::Write,
_version: &JavaMinecraftVersion,
) -> Result<(), crate::ser::WritingError> {
write.write_i32_be(self.entity_id)?;
write.write_i8(self.entity_status)?;
Ok(())
}
}

View File

@ -1,16 +1,17 @@
use pumpkin_data::packet::clientbound::PLAY_EXPLODE; use pumpkin_data::packet::clientbound::PLAY_EXPLODE;
use pumpkin_macros::java_packet; use pumpkin_macros::java_packet;
use pumpkin_util::math::vector3::Vector3; use pumpkin_util::math::vector3::Vector3;
use serde::Serialize;
use crate::ClientPacket;
use crate::ser::NetworkWriteExt;
use crate::{IdOr, SoundEvent, codec::var_int::VarInt}; use crate::{IdOr, SoundEvent, codec::var_int::VarInt};
use pumpkin_util::version::JavaMinecraftVersion;
/// Notifies the client that an explosion has occurred. /// Notifies the client that an explosion has occurred.
/// ///
/// This is a high-level packet that handles the visual, auditory, and physical /// This is a high-level packet that handles the visual, auditory, and physical
/// effects of an explosion in a single call. It triggers the explosion particles, /// effects of an explosion in a single call. It triggers the explosion particles,
/// plays the sound at the source, and applies knockback to the player. /// plays the sound at the source, and applies knockback to the player.
#[derive(Serialize)]
#[java_packet(PLAY_EXPLODE)] #[java_packet(PLAY_EXPLODE)]
pub struct CExplosion { pub struct CExplosion {
/// The center coordinates of the explosion. /// The center coordinates of the explosion.
@ -54,3 +55,34 @@ impl CExplosion {
} }
} }
} }
impl ClientPacket for CExplosion {
fn write_packet_data(
&self,
mut write: impl std::io::Write,
_version: &JavaMinecraftVersion,
) -> Result<(), crate::ser::WritingError> {
write.write_f64_be(self.center.x)?;
write.write_f64_be(self.center.y)?;
write.write_f64_be(self.center.z)?;
write.write_f32_be(self.radius)?;
write.write_i32_be(self.block_count)?;
write.write_option(&self.knockback, |w, k| {
w.write_f64_be(k.x)?;
w.write_f64_be(k.y)?;
w.write_f64_be(k.z)?;
Ok(())
})?;
write.write_var_int(&self.particle)?;
match &self.sound {
IdOr::Id(id) => write.write_var_int(&VarInt((*id + 1) as i32))?,
IdOr::Value(event) => {
write.write_var_int(&VarInt(0))?;
write.write_string(&event.sound_name)?;
write.write_option(&event.range, |w, r| w.write_f32_be(*r))?;
}
}
write.write_var_int(&self.block_particles_pool_size)?;
Ok(())
}
}

View File

@ -1,13 +1,15 @@
use pumpkin_data::packet::clientbound::PLAY_GAME_EVENT; use pumpkin_data::packet::clientbound::PLAY_GAME_EVENT;
use pumpkin_macros::java_packet; use pumpkin_macros::java_packet;
use serde::{Deserialize, Serialize};
use crate::ClientPacket;
use crate::ser::NetworkWriteExt;
use pumpkin_util::version::JavaMinecraftVersion;
/// Updates the game state or triggers specific environmental changes. /// Updates the game state or triggers specific environmental changes.
/// ///
/// This packet is the primary way the server communicates global or /// This packet is the primary way the server communicates global or
/// context-specific transitions, such as changing the weather, /// context-specific transitions, such as changing the weather,
/// altering the player's gamemode, or displaying the credits. /// altering the player's gamemode, or displaying the credits.
#[derive(Serialize, Deserialize)]
#[java_packet(PLAY_GAME_EVENT)] #[java_packet(PLAY_GAME_EVENT)]
pub struct CGameEvent { pub struct CGameEvent {
/// The ID of the event type. /// The ID of the event type.
@ -43,3 +45,15 @@ pub enum GameEvent {
LimitedCrafting, LimitedCrafting,
StartWaitingChunks, StartWaitingChunks,
} }
impl ClientPacket for CGameEvent {
fn write_packet_data(
&self,
mut write: impl std::io::Write,
_version: &JavaMinecraftVersion,
) -> Result<(), crate::ser::WritingError> {
write.write_u8(self.event)?;
write.write_f32_be(self.value)?;
Ok(())
}
}

View File

@ -1,8 +1,10 @@
use pumpkin_data::packet::clientbound::PLAY_ROTATE_HEAD; use pumpkin_data::packet::clientbound::PLAY_ROTATE_HEAD;
use pumpkin_macros::java_packet; use pumpkin_macros::java_packet;
use serde::{Deserialize, Serialize};
use crate::ClientPacket;
use crate::VarInt; use crate::VarInt;
use crate::ser::NetworkWriteExt;
use pumpkin_util::version::JavaMinecraftVersion;
/// Rotates an entity's head to a specific yaw. /// Rotates an entity's head to a specific yaw.
/// ///
@ -10,7 +12,6 @@ use crate::VarInt;
/// While standard movement packets update the body, this packet is /// While standard movement packets update the body, this packet is
/// required to make an entity (like a player or a mob) look in a /// required to make an entity (like a player or a mob) look in a
/// specific direction without necessarily turning its entire body. /// specific direction without necessarily turning its entire body.
#[derive(Serialize, Deserialize)]
#[java_packet(PLAY_ROTATE_HEAD)] #[java_packet(PLAY_ROTATE_HEAD)]
pub struct CHeadRot { pub struct CHeadRot {
/// The Entity ID of the entity whose head is rotating. /// The Entity ID of the entity whose head is rotating.
@ -28,3 +29,15 @@ impl CHeadRot {
} }
} }
} }
impl ClientPacket for CHeadRot {
fn write_packet_data(
&self,
mut write: impl std::io::Write,
_version: &JavaMinecraftVersion,
) -> Result<(), crate::ser::WritingError> {
write.write_var_int(&self.entity_id)?;
write.write_u8(self.head_yaw)?;
Ok(())
}
}

View File

@ -1,15 +1,16 @@
use pumpkin_data::packet::clientbound::PLAY_HURT_ANIMATION; use pumpkin_data::packet::clientbound::PLAY_HURT_ANIMATION;
use pumpkin_macros::java_packet; use pumpkin_macros::java_packet;
use serde::{Deserialize, Serialize};
use crate::ClientPacket;
use crate::VarInt; use crate::VarInt;
use crate::ser::NetworkWriteExt;
use pumpkin_util::version::JavaMinecraftVersion;
/// Triggers the "hurt" visual effect on an entity. /// Triggers the "hurt" visual effect on an entity.
/// ///
/// This packet causes the entity to turn red and perform a directional /// This packet causes the entity to turn red and perform a directional
/// camera shake or model tilt. It is typically sent immediately after /// camera shake or model tilt. It is typically sent immediately after
/// an entity's health is reduced. /// an entity's health is reduced.
#[derive(Serialize, Deserialize)]
#[java_packet(PLAY_HURT_ANIMATION)] #[java_packet(PLAY_HURT_ANIMATION)]
pub struct CHurtAnimation { pub struct CHurtAnimation {
/// The Entity ID of the entity that was hurt. /// The Entity ID of the entity that was hurt.
@ -25,3 +26,15 @@ impl CHurtAnimation {
Self { entity_id, yaw } Self { entity_id, yaw }
} }
} }
impl ClientPacket for CHurtAnimation {
fn write_packet_data(
&self,
mut write: impl std::io::Write,
_version: &JavaMinecraftVersion,
) -> Result<(), crate::ser::WritingError> {
write.write_var_int(&self.entity_id)?;
write.write_f32_be(self.yaw)?;
Ok(())
}
}

View File

@ -1,15 +1,16 @@
use pumpkin_data::packet::clientbound::PLAY_INITIALIZE_BORDER; use pumpkin_data::packet::clientbound::PLAY_INITIALIZE_BORDER;
use pumpkin_macros::java_packet; use pumpkin_macros::java_packet;
use serde::Serialize;
use crate::ClientPacket;
use crate::ser::NetworkWriteExt;
use crate::{VarInt, codec::var_long::VarLong}; use crate::{VarInt, codec::var_long::VarLong};
use pumpkin_util::version::JavaMinecraftVersion;
/// Fully initializes the world border for the client. /// Fully initializes the world border for the client.
/// ///
/// This packet is sent when a player joins the world or changes dimensions. /// This packet is sent when a player joins the world or changes dimensions.
/// It synchronizes the current position, size, and all warning parameters /// It synchronizes the current position, size, and all warning parameters
/// to ensure the client-side visual barrier matches the server's authority. /// to ensure the client-side visual barrier matches the server's authority.
#[derive(Serialize)]
#[java_packet(PLAY_INITIALIZE_BORDER)] #[java_packet(PLAY_INITIALIZE_BORDER)]
pub struct CInitializeWorldBorder { pub struct CInitializeWorldBorder {
/// The X coordinate of the center of the world border. /// The X coordinate of the center of the world border.
@ -57,3 +58,21 @@ impl CInitializeWorldBorder {
} }
} }
} }
impl ClientPacket for CInitializeWorldBorder {
fn write_packet_data(
&self,
mut write: impl std::io::Write,
_version: &JavaMinecraftVersion,
) -> Result<(), crate::ser::WritingError> {
write.write_f64_be(self.x)?;
write.write_f64_be(self.z)?;
write.write_f64_be(self.old_diameter)?;
write.write_f64_be(self.new_diameter)?;
write.write_var_long(&self.speed)?;
write.write_var_int(&self.portal_teleport_boundary)?;
write.write_var_int(&self.warning_blocks)?;
write.write_var_int(&self.warning_time)?;
Ok(())
}
}

View File

@ -2,9 +2,11 @@ use pumpkin_data::packet::clientbound::PLAY_COOLDOWN;
use crate::codec::var_int::VarInt; use crate::codec::var_int::VarInt;
use pumpkin_macros::java_packet; use pumpkin_macros::java_packet;
use serde::Serialize;
#[derive(Serialize)] use crate::ClientPacket;
use crate::ser::NetworkWriteExt;
use pumpkin_util::version::JavaMinecraftVersion;
#[java_packet(PLAY_COOLDOWN)] #[java_packet(PLAY_COOLDOWN)]
pub struct CItemCooldown { pub struct CItemCooldown {
pub group: String, pub group: String,
@ -17,3 +19,15 @@ impl CItemCooldown {
Self { group, cooldown } Self { group, cooldown }
} }
} }
impl ClientPacket for CItemCooldown {
fn write_packet_data(
&self,
mut write: impl std::io::Write,
_version: &JavaMinecraftVersion,
) -> Result<(), crate::ser::WritingError> {
write.write_string(&self.group)?;
write.write_var_int(&self.cooldown)?;
Ok(())
}
}

View File

@ -1,6 +1,9 @@
use pumpkin_data::packet::clientbound::PLAY_KEEP_ALIVE; use pumpkin_data::packet::clientbound::PLAY_KEEP_ALIVE;
use pumpkin_macros::java_packet; use pumpkin_macros::java_packet;
use serde::{Deserialize, Serialize};
use crate::ClientPacket;
use crate::ser::NetworkWriteExt;
use pumpkin_util::version::JavaMinecraftVersion;
/// Maintains the connection and measures latency (ping) between client and server. /// Maintains the connection and measures latency (ping) between client and server.
/// ///
@ -8,7 +11,6 @@ use serde::{Deserialize, Serialize};
/// The client must respond with the exact same ID. If the server does not receive /// The client must respond with the exact same ID. If the server does not receive
/// a response within a timeout period (usually 30 seconds), it will disconnect /// a response within a timeout period (usually 30 seconds), it will disconnect
/// the player with a "Timed Out" message. /// the player with a "Timed Out" message.
#[derive(Serialize, Deserialize)]
#[java_packet(PLAY_KEEP_ALIVE)] #[java_packet(PLAY_KEEP_ALIVE)]
pub struct CKeepAlive { pub struct CKeepAlive {
/// A unique random identifier for this specific keep-alive request. /// A unique random identifier for this specific keep-alive request.
@ -22,3 +24,14 @@ impl CKeepAlive {
Self { keep_alive_id } Self { keep_alive_id }
} }
} }
impl ClientPacket for CKeepAlive {
fn write_packet_data(
&self,
mut write: impl std::io::Write,
_version: &JavaMinecraftVersion,
) -> Result<(), crate::ser::WritingError> {
write.write_i64_be(self.keep_alive_id)?;
Ok(())
}
}

View File

@ -1,11 +1,13 @@
use pumpkin_data::packet::clientbound::PLAY_MERCHANT_OFFERS; use pumpkin_data::packet::clientbound::PLAY_MERCHANT_OFFERS;
use pumpkin_macros::java_packet; use pumpkin_macros::java_packet;
use serde::{Deserialize, Serialize};
use crate::ClientPacket;
use crate::VarInt; use crate::VarInt;
use crate::codec::item_stack_seralizer::ItemStackSerializer; use crate::codec::item_stack_seralizer::ItemStackSerializer;
use crate::ser::NetworkWriteExt;
use pumpkin_util::version::JavaMinecraftVersion;
#[derive(Serialize, Deserialize, Clone)] #[derive(Clone)]
pub struct MerchantOffer { pub struct MerchantOffer {
pub base_cost_a: ItemStackSerializer<'static>, // TODO: item cost pub base_cost_a: ItemStackSerializer<'static>, // TODO: item cost
pub output: ItemStackSerializer<'static>, pub output: ItemStackSerializer<'static>,
@ -19,7 +21,28 @@ pub struct MerchantOffer {
pub demand: i32, pub demand: i32,
} }
#[derive(Serialize)] impl MerchantOffer {
fn write(
&self,
mut write: impl std::io::Write,
version: JavaMinecraftVersion,
) -> Result<(), crate::ser::WritingError> {
self.base_cost_a.write_with_version(&mut write, &version)?;
self.output.write_with_version(&mut write, &version)?;
write.write_option(&self.cost_b, |w, cost_b| {
cost_b.write_with_version(w, &version)
})?;
write.write_bool(self.is_disabled)?;
write.write_i32_be(self.uses)?;
write.write_i32_be(self.max_uses)?;
write.write_i32_be(self.xp)?;
write.write_i32_be(self.special_price)?;
write.write_f32_be(self.price_multiplier)?;
write.write_i32_be(self.demand)?;
Ok(())
}
}
#[java_packet(PLAY_MERCHANT_OFFERS)] #[java_packet(PLAY_MERCHANT_OFFERS)]
pub struct CMerchantOffers { pub struct CMerchantOffers {
pub window_id: VarInt, pub window_id: VarInt,
@ -50,3 +73,22 @@ impl CMerchantOffers {
} }
} }
} }
impl ClientPacket for CMerchantOffers {
fn write_packet_data(
&self,
mut write: impl std::io::Write,
version: &JavaMinecraftVersion,
) -> Result<(), crate::ser::WritingError> {
write.write_var_int(&self.window_id)?;
write.write_var_int(&VarInt(self.offers.len() as i32))?;
for offer in &self.offers {
offer.write(&mut write, *version)?;
}
write.write_var_int(&self.villager_level)?;
write.write_var_int(&self.experience)?;
write.write_bool(self.is_regular_villager)?;
write.write_bool(self.can_restock)?;
Ok(())
}
}

View File

@ -2,9 +2,11 @@ use pumpkin_data::packet::clientbound::PLAY_OPEN_SCREEN;
use pumpkin_util::text::TextComponent; use pumpkin_util::text::TextComponent;
use pumpkin_macros::java_packet; use pumpkin_macros::java_packet;
use serde::Serialize;
use crate::ClientPacket;
use crate::VarInt; use crate::VarInt;
use crate::ser::NetworkWriteExt;
use pumpkin_util::version::JavaMinecraftVersion;
/// Instructs the client to open a specific type of GUI (inventory, chest, etc.). /// Instructs the client to open a specific type of GUI (inventory, chest, etc.).
/// ///
@ -12,7 +14,6 @@ use crate::VarInt;
/// or when a command/plugin forces an interface to open. It establishes a /// or when a command/plugin forces an interface to open. It establishes a
/// `sync_id` which must be used in all subsequent "Set Slot" or "Click Slot" /// `sync_id` which must be used in all subsequent "Set Slot" or "Click Slot"
/// packets to ensure the server and client are talking about the same window. /// packets to ensure the server and client are talking about the same window.
#[derive(Serialize)]
#[java_packet(PLAY_OPEN_SCREEN)] #[java_packet(PLAY_OPEN_SCREEN)]
pub struct COpenScreen<'a> { pub struct COpenScreen<'a> {
/// A unique identifier for the current window session. /// A unique identifier for the current window session.
@ -40,3 +41,18 @@ impl<'a> COpenScreen<'a> {
} }
} }
} }
impl ClientPacket for COpenScreen<'_> {
fn write_packet_data(
&self,
mut write: impl std::io::Write,
_version: &JavaMinecraftVersion,
) -> Result<(), crate::ser::WritingError> {
write.write_var_int(&self.sync_id)?;
write.write_var_int(&self.window_type)?;
// Write the text component as JSON string
let buf = self.window_title.encode();
write.write_slice(&buf)?;
Ok(())
}
}

View File

@ -1,14 +1,16 @@
use pumpkin_data::packet::clientbound::PLAY_OPEN_SIGN_EDITOR; use pumpkin_data::packet::clientbound::PLAY_OPEN_SIGN_EDITOR;
use pumpkin_macros::java_packet; use pumpkin_macros::java_packet;
use pumpkin_util::math::position::BlockPos; use pumpkin_util::math::position::BlockPos;
use serde::Serialize;
use crate::ClientPacket;
use crate::ser::NetworkWriteExt;
use pumpkin_util::version::JavaMinecraftVersion;
/// Opens the sign text input screen for the client. /// Opens the sign text input screen for the client.
/// ///
/// This packet is sent by the server to force the client to show the /// This packet is sent by the server to force the client to show the
/// sign editing interface. This usually happens immediately after a /// sign editing interface. This usually happens immediately after a
/// player places a sign or interacts with an existing one (if allowed). /// player places a sign or interacts with an existing one (if allowed).
#[derive(Serialize)]
#[java_packet(PLAY_OPEN_SIGN_EDITOR)] #[java_packet(PLAY_OPEN_SIGN_EDITOR)]
pub struct COpenSignEditor { pub struct COpenSignEditor {
/// The world coordinates of the sign block to be edited. /// The world coordinates of the sign block to be edited.
@ -27,3 +29,15 @@ impl COpenSignEditor {
} }
} }
} }
impl ClientPacket for COpenSignEditor {
fn write_packet_data(
&self,
mut write: impl std::io::Write,
_version: &JavaMinecraftVersion,
) -> Result<(), crate::ser::WritingError> {
write.write_block_pos(&self.location)?;
write.write_bool(self.is_front_text)?;
Ok(())
}
}

View File

@ -1,9 +1,11 @@
use pumpkin_data::packet::clientbound::PLAY_PONG_RESPONSE; use pumpkin_data::packet::clientbound::PLAY_PONG_RESPONSE;
use pumpkin_macros::java_packet; use pumpkin_macros::java_packet;
use serde::{Deserialize, Serialize};
use crate::ClientPacket;
use crate::ser::NetworkWriteExt;
use pumpkin_util::version::JavaMinecraftVersion;
/// Responds to a client-initiated ping request to synchronize game state. /// Responds to a client-initiated ping request to synchronize game state.
#[derive(Serialize, Deserialize)]
#[java_packet(PLAY_PONG_RESPONSE)] #[java_packet(PLAY_PONG_RESPONSE)]
pub struct CPingResponse { pub struct CPingResponse {
/// The unique identifier sent by the client in the initial Ping packet. /// The unique identifier sent by the client in the initial Ping packet.
@ -17,3 +19,14 @@ impl CPingResponse {
Self { payload } Self { payload }
} }
} }
impl ClientPacket for CPingResponse {
fn write_packet_data(
&self,
mut write: impl std::io::Write,
_version: &JavaMinecraftVersion,
) -> Result<(), crate::ser::WritingError> {
write.write_i64_be(self.payload)?;
Ok(())
}
}

View File

@ -1,13 +1,15 @@
use pumpkin_data::packet::clientbound::PLAY_PLAYER_ABILITIES; use pumpkin_data::packet::clientbound::PLAY_PLAYER_ABILITIES;
use pumpkin_macros::java_packet; use pumpkin_macros::java_packet;
use serde::Serialize;
use crate::ClientPacket;
use crate::ser::NetworkWriteExt;
use pumpkin_util::version::JavaMinecraftVersion;
/// Updates the player's movement and interaction abilities. /// Updates the player's movement and interaction abilities.
/// ///
/// This packet informs the client about the player's state (flying, invulnerable) /// This packet informs the client about the player's state (flying, invulnerable)
/// and sets the movement speeds. While the client applies these visuals, /// and sets the movement speeds. While the client applies these visuals,
/// the server must still validate these states to prevent cheating. /// the server must still validate these states to prevent cheating.
#[derive(Serialize)]
#[java_packet(PLAY_PLAYER_ABILITIES)] #[java_packet(PLAY_PLAYER_ABILITIES)]
pub struct CPlayerAbilities { pub struct CPlayerAbilities {
/// A bitmask of player states. /// A bitmask of player states.
@ -34,3 +36,16 @@ impl CPlayerAbilities {
} }
} }
} }
impl ClientPacket for CPlayerAbilities {
fn write_packet_data(
&self,
mut write: impl std::io::Write,
_version: &JavaMinecraftVersion,
) -> Result<(), crate::ser::WritingError> {
write.write_i8(self.flags)?;
write.write_f32_be(self.flying_speed)?;
write.write_f32_be(self.field_of_view)?;
Ok(())
}
}

View File

@ -107,7 +107,9 @@ impl ClientPacket for CPlayerInfoUpdate<'_> {
PlayerAction::UpdateListed(listed) => p.write_bool(*listed)?, PlayerAction::UpdateListed(listed) => p.write_bool(*listed)?,
PlayerAction::UpdateLatency(latency) => p.write_var_int(latency)?, PlayerAction::UpdateLatency(latency) => p.write_var_int(latency)?,
PlayerAction::UpdateDisplayName(display_name) => { PlayerAction::UpdateDisplayName(display_name) => {
p.write_option(display_name, crate::ser::NetworkWriteExt::write_serialize)?; p.write_option(display_name, |w, text_component| {
w.write_slice(&text_component.encode())
})?;
} }
PlayerAction::UpdateListOrder(order) => p.write_var_int(order)?, PlayerAction::UpdateListOrder(order) => p.write_var_int(order)?,
} }

View File

@ -1,19 +1,18 @@
use pumpkin_data::packet::clientbound::PLAY_PLAYER_INFO_REMOVE; use pumpkin_data::packet::clientbound::PLAY_PLAYER_INFO_REMOVE;
use pumpkin_macros::java_packet; use pumpkin_macros::java_packet;
use serde::{Serialize, ser::SerializeSeq};
use crate::ClientPacket;
use crate::VarInt;
use crate::ser::NetworkWriteExt;
use pumpkin_util::version::JavaMinecraftVersion;
/// Sent by the server to remove one or more players from the client's player list (tab list). /// Sent by the server to remove one or more players from the client's player list (tab list).
/// ///
/// This packet is typically used when a player leaves the server or becomes invisible /// This packet is typically used when a player leaves the server or becomes invisible
/// to the recipient (e.g., moving out of tracking range). /// to the recipient (e.g., moving out of tracking range).
#[derive(Serialize)]
#[java_packet(PLAY_PLAYER_INFO_REMOVE)] #[java_packet(PLAY_PLAYER_INFO_REMOVE)]
pub struct CRemovePlayerInfo<'a> { pub struct CRemovePlayerInfo<'a> {
/// A list of UUIDs corresponding to the players that should be removed. /// A list of UUIDs corresponding to the players that should be removed.
///
/// The field uses a custom serializer to format the UUIDs according to the
/// Minecraft protocol's VarInt-prefixed array format.
#[serde(serialize_with = "serialize_slice_uuids")]
pub players: &'a [uuid::Uuid], pub players: &'a [uuid::Uuid],
} }
@ -24,13 +23,16 @@ impl<'a> CRemovePlayerInfo<'a> {
} }
} }
fn serialize_slice_uuids<S: serde::Serializer>( impl ClientPacket for CRemovePlayerInfo<'_> {
uuids: &[uuid::Uuid], fn write_packet_data(
serializer: S, &self,
) -> Result<S::Ok, S::Error> { mut write: impl std::io::Write,
let mut seq = serializer.serialize_seq(Some(uuids.len()))?; _version: &JavaMinecraftVersion,
for uuid in uuids { ) -> Result<(), crate::ser::WritingError> {
seq.serialize_element(uuid.as_bytes())?; write.write_var_int(&VarInt(self.players.len() as i32))?;
for uuid in self.players {
write.write_uuid(uuid)?;
}
Ok(())
} }
seq.end()
} }

View File

@ -1,14 +1,15 @@
use pumpkin_data::packet::clientbound::PLAY_REMOVE_ENTITIES; use pumpkin_data::packet::clientbound::PLAY_REMOVE_ENTITIES;
use pumpkin_macros::java_packet; use pumpkin_macros::java_packet;
use serde::Serialize;
use crate::ClientPacket;
use crate::VarInt; use crate::VarInt;
use crate::ser::NetworkWriteExt;
use pumpkin_util::version::JavaMinecraftVersion;
/// Sent by the server to instruct the client to remove (despawn) one or more entities. /// Sent by the server to instruct the client to remove (despawn) one or more entities.
/// ///
/// This is typically sent when an entity leaves the player's tracking range, /// This is typically sent when an entity leaves the player's tracking range,
/// is killed, or is otherwise removed from the world. /// is killed, or is otherwise removed from the world.
#[derive(Serialize)]
#[java_packet(PLAY_REMOVE_ENTITIES)] #[java_packet(PLAY_REMOVE_ENTITIES)]
pub struct CRemoveEntities<'a> { pub struct CRemoveEntities<'a> {
/// A list of entity IDs to be removed. /// A list of entity IDs to be removed.
@ -21,3 +22,17 @@ impl<'a> CRemoveEntities<'a> {
Self { entity_ids } Self { entity_ids }
} }
} }
impl ClientPacket for CRemoveEntities<'_> {
fn write_packet_data(
&self,
mut write: impl std::io::Write,
_version: &JavaMinecraftVersion,
) -> Result<(), crate::ser::WritingError> {
write.write_var_int(&VarInt(self.entity_ids.len() as i32))?;
for id in self.entity_ids {
write.write_var_int(id)?;
}
Ok(())
}
}

View File

@ -1,9 +1,11 @@
use crate::codec::var_int::VarInt; use crate::codec::var_int::VarInt;
use pumpkin_data::packet::clientbound::PLAY_REMOVE_MOB_EFFECT; use pumpkin_data::packet::clientbound::PLAY_REMOVE_MOB_EFFECT;
use pumpkin_macros::java_packet; use pumpkin_macros::java_packet;
use serde::Serialize;
#[derive(Serialize)] use crate::ClientPacket;
use crate::ser::NetworkWriteExt;
use pumpkin_util::version::JavaMinecraftVersion;
#[java_packet(PLAY_REMOVE_MOB_EFFECT)] #[java_packet(PLAY_REMOVE_MOB_EFFECT)]
pub struct CRemoveMobEffect { pub struct CRemoveMobEffect {
pub entity_id: VarInt, pub entity_id: VarInt,
@ -19,3 +21,15 @@ impl CRemoveMobEffect {
} }
} }
} }
impl ClientPacket for CRemoveMobEffect {
fn write_packet_data(
&self,
mut write: impl std::io::Write,
_version: &JavaMinecraftVersion,
) -> Result<(), crate::ser::WritingError> {
write.write_var_int(&self.entity_id)?;
write.write_var_int(&self.effect_id)?;
Ok(())
}
}

View File

@ -1,8 +1,10 @@
use pumpkin_data::packet::clientbound::PLAY_RESET_SCORE; use pumpkin_data::packet::clientbound::PLAY_RESET_SCORE;
use pumpkin_macros::java_packet; use pumpkin_macros::java_packet;
use serde::Serialize;
#[derive(Serialize)] use crate::ClientPacket;
use crate::ser::NetworkWriteExt;
use pumpkin_util::version::JavaMinecraftVersion;
#[java_packet(PLAY_RESET_SCORE)] #[java_packet(PLAY_RESET_SCORE)]
pub struct CResetScore { pub struct CResetScore {
pub entity_name: String, pub entity_name: String,
@ -18,3 +20,15 @@ impl CResetScore {
} }
} }
} }
impl ClientPacket for CResetScore {
fn write_packet_data(
&self,
mut write: impl std::io::Write,
_version: &JavaMinecraftVersion,
) -> Result<(), crate::ser::WritingError> {
write.write_string(&self.entity_name)?;
write.write_option(&self.objective_name, |w, obj| w.write_string(obj))?;
Ok(())
}
}

View File

@ -1,9 +1,11 @@
use pumpkin_data::packet::clientbound::PLAY_SELECT_ADVANCEMENTS_TAB; use pumpkin_data::packet::clientbound::PLAY_SELECT_ADVANCEMENTS_TAB;
use pumpkin_macros::java_packet; use pumpkin_macros::java_packet;
use pumpkin_util::identifier::Identifier; use pumpkin_util::identifier::Identifier;
use serde::Serialize;
#[derive(Serialize)] use crate::ClientPacket;
use crate::ser::NetworkWriteExt;
use pumpkin_util::version::JavaMinecraftVersion;
#[java_packet(PLAY_SELECT_ADVANCEMENTS_TAB)] #[java_packet(PLAY_SELECT_ADVANCEMENTS_TAB)]
pub struct CSelectAdvancementsTab { pub struct CSelectAdvancementsTab {
pub tab_id: Option<Identifier>, pub tab_id: Option<Identifier>,
@ -15,3 +17,14 @@ impl CSelectAdvancementsTab {
Self { tab_id } Self { tab_id }
} }
} }
impl ClientPacket for CSelectAdvancementsTab {
fn write_packet_data(
&self,
mut write: impl std::io::Write,
_version: &JavaMinecraftVersion,
) -> Result<(), crate::ser::WritingError> {
write.write_option(&self.tab_id, |w, id| w.write_string(&id.to_string()))?;
Ok(())
}
}

View File

@ -1,9 +1,7 @@
use crate::Link; use crate::Link;
use pumpkin_data::packet::clientbound::PLAY_SERVER_LINKS; use pumpkin_data::packet::clientbound::PLAY_SERVER_LINKS;
use pumpkin_macros::java_packet; use pumpkin_macros::java_packet;
use serde::Serialize;
#[derive(Serialize)]
#[java_packet(PLAY_SERVER_LINKS)] #[java_packet(PLAY_SERVER_LINKS)]
pub struct CPlayServerLinks<'a> { pub struct CPlayServerLinks<'a> {
pub links: &'a [Link<'a>], pub links: &'a [Link<'a>],

View File

@ -1,8 +1,10 @@
use pumpkin_data::packet::clientbound::PLAY_SET_BORDER_CENTER; use pumpkin_data::packet::clientbound::PLAY_SET_BORDER_CENTER;
use pumpkin_macros::java_packet; use pumpkin_macros::java_packet;
use serde::Serialize;
#[derive(Serialize)] use crate::ClientPacket;
use crate::ser::NetworkWriteExt;
use pumpkin_util::version::JavaMinecraftVersion;
#[java_packet(PLAY_SET_BORDER_CENTER)] #[java_packet(PLAY_SET_BORDER_CENTER)]
pub struct CSetBorderCenter { pub struct CSetBorderCenter {
pub x: f64, pub x: f64,
@ -15,3 +17,15 @@ impl CSetBorderCenter {
Self { x, z } Self { x, z }
} }
} }
impl ClientPacket for CSetBorderCenter {
fn write_packet_data(
&self,
mut write: impl std::io::Write,
_version: &JavaMinecraftVersion,
) -> Result<(), crate::ser::WritingError> {
write.write_f64_be(self.x)?;
write.write_f64_be(self.z)?;
Ok(())
}
}

View File

@ -1,10 +1,11 @@
use pumpkin_data::packet::clientbound::PLAY_SET_BORDER_LERP_SIZE; use pumpkin_data::packet::clientbound::PLAY_SET_BORDER_LERP_SIZE;
use pumpkin_macros::java_packet; use pumpkin_macros::java_packet;
use serde::Serialize;
use crate::ClientPacket;
use crate::codec::var_long::VarLong; use crate::codec::var_long::VarLong;
use crate::ser::NetworkWriteExt;
use pumpkin_util::version::JavaMinecraftVersion;
#[derive(Serialize)]
#[java_packet(PLAY_SET_BORDER_LERP_SIZE)] #[java_packet(PLAY_SET_BORDER_LERP_SIZE)]
pub struct CSetBorderLerpSize { pub struct CSetBorderLerpSize {
pub old_diameter: f64, pub old_diameter: f64,
@ -22,3 +23,16 @@ impl CSetBorderLerpSize {
} }
} }
} }
impl ClientPacket for CSetBorderLerpSize {
fn write_packet_data(
&self,
mut write: impl std::io::Write,
_version: &JavaMinecraftVersion,
) -> Result<(), crate::ser::WritingError> {
write.write_f64_be(self.old_diameter)?;
write.write_f64_be(self.new_diameter)?;
write.write_var_long(&self.speed)?;
Ok(())
}
}

View File

@ -1,8 +1,10 @@
use pumpkin_data::packet::clientbound::PLAY_SET_BORDER_SIZE; use pumpkin_data::packet::clientbound::PLAY_SET_BORDER_SIZE;
use pumpkin_macros::java_packet; use pumpkin_macros::java_packet;
use serde::Serialize;
#[derive(Serialize)] use crate::ClientPacket;
use crate::ser::NetworkWriteExt;
use pumpkin_util::version::JavaMinecraftVersion;
#[java_packet(PLAY_SET_BORDER_SIZE)] #[java_packet(PLAY_SET_BORDER_SIZE)]
pub struct CSetBorderSize { pub struct CSetBorderSize {
pub diameter: f64, pub diameter: f64,
@ -14,3 +16,14 @@ impl CSetBorderSize {
Self { diameter } Self { diameter }
} }
} }
impl ClientPacket for CSetBorderSize {
fn write_packet_data(
&self,
mut write: impl std::io::Write,
_version: &JavaMinecraftVersion,
) -> Result<(), crate::ser::WritingError> {
write.write_f64_be(self.diameter)?;
Ok(())
}
}

View File

@ -1,10 +1,11 @@
use pumpkin_data::packet::clientbound::PLAY_SET_BORDER_WARNING_DELAY; use pumpkin_data::packet::clientbound::PLAY_SET_BORDER_WARNING_DELAY;
use pumpkin_macros::java_packet; use pumpkin_macros::java_packet;
use serde::Serialize;
use crate::ClientPacket;
use crate::VarInt; use crate::VarInt;
use crate::ser::NetworkWriteExt;
use pumpkin_util::version::JavaMinecraftVersion;
#[derive(Serialize)]
#[java_packet(PLAY_SET_BORDER_WARNING_DELAY)] #[java_packet(PLAY_SET_BORDER_WARNING_DELAY)]
pub struct CSetBorderWarningDelay { pub struct CSetBorderWarningDelay {
pub warning_time: VarInt, pub warning_time: VarInt,
@ -16,3 +17,14 @@ impl CSetBorderWarningDelay {
Self { warning_time } Self { warning_time }
} }
} }
impl ClientPacket for CSetBorderWarningDelay {
fn write_packet_data(
&self,
mut write: impl std::io::Write,
_version: &JavaMinecraftVersion,
) -> Result<(), crate::ser::WritingError> {
write.write_var_int(&self.warning_time)?;
Ok(())
}
}

View File

@ -1,10 +1,11 @@
use pumpkin_data::packet::clientbound::PLAY_SET_BORDER_WARNING_DISTANCE; use pumpkin_data::packet::clientbound::PLAY_SET_BORDER_WARNING_DISTANCE;
use pumpkin_macros::java_packet; use pumpkin_macros::java_packet;
use serde::Serialize;
use crate::ClientPacket;
use crate::VarInt; use crate::VarInt;
use crate::ser::NetworkWriteExt;
use pumpkin_util::version::JavaMinecraftVersion;
#[derive(Serialize)]
#[java_packet(PLAY_SET_BORDER_WARNING_DISTANCE)] #[java_packet(PLAY_SET_BORDER_WARNING_DISTANCE)]
pub struct CSetBorderWarningDistance { pub struct CSetBorderWarningDistance {
pub warning_blocks: VarInt, pub warning_blocks: VarInt,
@ -16,3 +17,14 @@ impl CSetBorderWarningDistance {
Self { warning_blocks } Self { warning_blocks }
} }
} }
impl ClientPacket for CSetBorderWarningDistance {
fn write_packet_data(
&self,
mut write: impl std::io::Write,
_version: &JavaMinecraftVersion,
) -> Result<(), crate::ser::WritingError> {
write.write_var_int(&self.warning_blocks)?;
Ok(())
}
}

View File

@ -1,10 +1,10 @@
use pumpkin_data::packet::clientbound::PLAY_SET_CAMERA; use pumpkin_data::packet::clientbound::PLAY_SET_CAMERA;
use pumpkin_util::version::JavaMinecraftVersion; use pumpkin_util::version::JavaMinecraftVersion;
use serde::Serialize;
use crate::ClientPacket;
use crate::ser::NetworkWriteExt;
use crate::{VarInt, packet::MultiVersionJavaPacket}; use crate::{VarInt, packet::MultiVersionJavaPacket};
#[derive(Serialize)]
pub struct CSetCamera { pub struct CSetCamera {
pub camera_id: VarInt, pub camera_id: VarInt,
} }
@ -16,6 +16,17 @@ impl CSetCamera {
} }
} }
impl ClientPacket for CSetCamera {
fn write_packet_data(
&self,
mut write: impl std::io::Write,
_version: &JavaMinecraftVersion,
) -> Result<(), crate::ser::WritingError> {
write.write_var_int(&self.camera_id)?;
Ok(())
}
}
impl MultiVersionJavaPacket for CSetCamera { impl MultiVersionJavaPacket for CSetCamera {
fn to_id(version: JavaMinecraftVersion) -> i32 { fn to_id(version: JavaMinecraftVersion) -> i32 {
PLAY_SET_CAMERA.to_id(version) PLAY_SET_CAMERA.to_id(version)

View File

@ -1,10 +1,11 @@
use pumpkin_data::packet::clientbound::PLAY_CONTAINER_SET_DATA; use pumpkin_data::packet::clientbound::PLAY_CONTAINER_SET_DATA;
use pumpkin_macros::java_packet; use pumpkin_macros::java_packet;
use serde::Serialize;
use crate::ClientPacket;
use crate::VarInt; use crate::VarInt;
use crate::ser::NetworkWriteExt;
use pumpkin_util::version::JavaMinecraftVersion;
#[derive(Serialize)]
#[java_packet(PLAY_CONTAINER_SET_DATA)] #[java_packet(PLAY_CONTAINER_SET_DATA)]
pub struct CSetContainerProperty { pub struct CSetContainerProperty {
pub window_id: VarInt, pub window_id: VarInt,
@ -22,3 +23,16 @@ impl CSetContainerProperty {
} }
} }
} }
impl ClientPacket for CSetContainerProperty {
fn write_packet_data(
&self,
mut write: impl std::io::Write,
_version: &JavaMinecraftVersion,
) -> Result<(), crate::ser::WritingError> {
write.write_var_int(&self.window_id)?;
write.write_i16(self.property)?;
write.write_i16(self.value)?;
Ok(())
}
}

View File

@ -22,9 +22,9 @@ impl<'a> CSetCursorItem<'a> {
impl ClientPacket for CSetCursorItem<'_> { impl ClientPacket for CSetCursorItem<'_> {
fn write_packet_data( fn write_packet_data(
&self, &self,
write: impl Write, mut write: impl Write,
version: &JavaMinecraftVersion, version: &JavaMinecraftVersion,
) -> Result<(), WritingError> { ) -> Result<(), WritingError> {
self.stack.write_with_version(write, version) self.stack.write_with_version(&mut write, version)
} }
} }

View File

@ -1,10 +1,11 @@
use pumpkin_data::packet::clientbound::PLAY_SET_EXPERIENCE; use pumpkin_data::packet::clientbound::PLAY_SET_EXPERIENCE;
use pumpkin_macros::java_packet; use pumpkin_macros::java_packet;
use serde::Serialize;
use crate::ClientPacket;
use crate::VarInt; use crate::VarInt;
use crate::ser::NetworkWriteExt;
use pumpkin_util::version::JavaMinecraftVersion;
#[derive(Serialize)]
#[java_packet(PLAY_SET_EXPERIENCE)] #[java_packet(PLAY_SET_EXPERIENCE)]
pub struct CSetExperience { pub struct CSetExperience {
pub progress: f32, pub progress: f32,
@ -22,3 +23,16 @@ impl CSetExperience {
} }
} }
} }
impl ClientPacket for CSetExperience {
fn write_packet_data(
&self,
mut write: impl std::io::Write,
_version: &JavaMinecraftVersion,
) -> Result<(), crate::ser::WritingError> {
write.write_f32(self.progress)?;
write.write_var_int(&self.level)?;
write.write_var_int(&self.total_experience)?;
Ok(())
}
}

View File

@ -1,10 +1,11 @@
use pumpkin_data::packet::clientbound::PLAY_SET_HEALTH; use pumpkin_data::packet::clientbound::PLAY_SET_HEALTH;
use pumpkin_macros::java_packet; use pumpkin_macros::java_packet;
use serde::Serialize;
use crate::ClientPacket;
use crate::VarInt; use crate::VarInt;
use crate::ser::NetworkWriteExt;
use pumpkin_util::version::JavaMinecraftVersion;
#[derive(Serialize)]
#[java_packet(PLAY_SET_HEALTH)] #[java_packet(PLAY_SET_HEALTH)]
pub struct CSetHealth { pub struct CSetHealth {
pub health: f32, pub health: f32,
@ -22,3 +23,16 @@ impl CSetHealth {
} }
} }
} }
impl ClientPacket for CSetHealth {
fn write_packet_data(
&self,
mut write: impl std::io::Write,
_version: &JavaMinecraftVersion,
) -> Result<(), crate::ser::WritingError> {
write.write_f32(self.health)?;
write.write_var_int(&self.food)?;
write.write_f32(self.food_saturation)?;
Ok(())
}
}

View File

@ -1,10 +1,10 @@
use pumpkin_data::packet::clientbound::{PLAY_SET_CARRIED_ITEM, PLAY_SET_HELD_SLOT}; use pumpkin_data::packet::clientbound::{PLAY_SET_CARRIED_ITEM, PLAY_SET_HELD_SLOT};
use pumpkin_util::version::JavaMinecraftVersion; use pumpkin_util::version::JavaMinecraftVersion;
use serde::Serialize;
use crate::ClientPacket;
use crate::packet::MultiVersionJavaPacket; use crate::packet::MultiVersionJavaPacket;
use crate::ser::NetworkWriteExt;
#[derive(Serialize)]
pub struct CSetSelectedSlot { pub struct CSetSelectedSlot {
pub slot: i8, pub slot: i8,
} }
@ -16,6 +16,17 @@ impl CSetSelectedSlot {
} }
} }
impl ClientPacket for CSetSelectedSlot {
fn write_packet_data(
&self,
mut write: impl std::io::Write,
_version: &JavaMinecraftVersion,
) -> Result<(), crate::ser::WritingError> {
write.write_i8(self.slot)?;
Ok(())
}
}
impl MultiVersionJavaPacket for CSetSelectedSlot { impl MultiVersionJavaPacket for CSetSelectedSlot {
fn to_id(version: JavaMinecraftVersion) -> i32 { fn to_id(version: JavaMinecraftVersion) -> i32 {
if version >= JavaMinecraftVersion::V_1_21_2 { if version >= JavaMinecraftVersion::V_1_21_2 {

View File

@ -1,10 +1,11 @@
use pumpkin_data::packet::clientbound::PLAY_SET_PASSENGERS; use pumpkin_data::packet::clientbound::PLAY_SET_PASSENGERS;
use pumpkin_macros::java_packet; use pumpkin_macros::java_packet;
use serde::Serialize;
use crate::ClientPacket;
use crate::VarInt; use crate::VarInt;
use crate::ser::NetworkWriteExt;
use pumpkin_util::version::JavaMinecraftVersion;
#[derive(Serialize)]
#[java_packet(PLAY_SET_PASSENGERS)] #[java_packet(PLAY_SET_PASSENGERS)]
pub struct CSetPassengers<'a> { pub struct CSetPassengers<'a> {
pub entity_id: VarInt, pub entity_id: VarInt,
@ -20,3 +21,18 @@ impl<'a> CSetPassengers<'a> {
} }
} }
} }
impl ClientPacket for CSetPassengers<'_> {
fn write_packet_data(
&self,
mut write: impl std::io::Write,
_version: &JavaMinecraftVersion,
) -> Result<(), crate::ser::WritingError> {
write.write_var_int(&self.entity_id)?;
write.write_var_int(&crate::VarInt(self.passengers.len() as i32))?;
for passenger in self.passengers {
write.write_var_int(passenger)?;
}
Ok(())
}
}

View File

@ -29,6 +29,6 @@ impl ClientPacket for CSetPlayerInventory<'_> {
) -> Result<(), WritingError> { ) -> Result<(), WritingError> {
let mut write = write; let mut write = write;
write.write_var_int(&self.slot)?; write.write_var_int(&self.slot)?;
self.item.write_with_version(write, version) self.item.write_with_version(&mut write, version)
} }
} }

View File

@ -1,10 +1,11 @@
use pumpkin_data::packet::clientbound::PLAY_SET_TITLE_TEXT; use pumpkin_data::packet::clientbound::PLAY_SET_TITLE_TEXT;
use pumpkin_util::text::TextComponent; use pumpkin_util::text::TextComponent;
use crate::ClientPacket;
use crate::ser::NetworkWriteExt;
use pumpkin_macros::java_packet; use pumpkin_macros::java_packet;
use serde::Serialize; use pumpkin_util::version::JavaMinecraftVersion;
#[derive(Serialize)]
#[java_packet(PLAY_SET_TITLE_TEXT)] #[java_packet(PLAY_SET_TITLE_TEXT)]
pub struct CTitleText<'a> { pub struct CTitleText<'a> {
pub title: &'a TextComponent, pub title: &'a TextComponent,
@ -16,3 +17,14 @@ impl<'a> CTitleText<'a> {
Self { title } Self { title }
} }
} }
impl ClientPacket for CTitleText<'_> {
fn write_packet_data(
&self,
mut write: impl std::io::Write,
_version: &JavaMinecraftVersion,
) -> Result<(), crate::ser::WritingError> {
write.write_slice(&self.title.encode())?;
Ok(())
}
}

View File

@ -1,9 +1,10 @@
use pumpkin_data::packet::clientbound::PLAY_SET_TITLES_ANIMATION; use pumpkin_data::packet::clientbound::PLAY_SET_TITLES_ANIMATION;
use crate::ClientPacket;
use crate::ser::NetworkWriteExt;
use pumpkin_macros::java_packet; use pumpkin_macros::java_packet;
use serde::Serialize; use pumpkin_util::version::JavaMinecraftVersion;
#[derive(Serialize)]
#[java_packet(PLAY_SET_TITLES_ANIMATION)] #[java_packet(PLAY_SET_TITLES_ANIMATION)]
pub struct CTitleAnimation { pub struct CTitleAnimation {
pub fade_in_ticks: i32, pub fade_in_ticks: i32,
@ -21,3 +22,16 @@ impl CTitleAnimation {
} }
} }
} }
impl ClientPacket for CTitleAnimation {
fn write_packet_data(
&self,
mut write: impl std::io::Write,
_version: &JavaMinecraftVersion,
) -> Result<(), crate::ser::WritingError> {
write.write_i32_be(self.fade_in_ticks)?;
write.write_i32_be(self.stay_ticks)?;
write.write_i32_be(self.fade_out_ticks)?;
Ok(())
}
}

View File

@ -1,10 +1,9 @@
use crate::IdOr;
use crate::java::client::dialog::DialogNBT; use crate::java::client::dialog::DialogNBT;
use crate::{ClientPacket, IdOr, ser::WritingError};
use pumpkin_data::packet::clientbound::PLAY_SHOW_DIALOG; use pumpkin_data::packet::clientbound::PLAY_SHOW_DIALOG;
use pumpkin_macros::java_packet; use pumpkin_macros::java_packet;
use serde::Serialize; use pumpkin_util::version::JavaMinecraftVersion;
#[derive(Serialize)]
#[java_packet(PLAY_SHOW_DIALOG)] #[java_packet(PLAY_SHOW_DIALOG)]
pub struct CPlayShowDialog<'a> { pub struct CPlayShowDialog<'a> {
pub dialog: IdOr<DialogNBT<'a>>, pub dialog: IdOr<DialogNBT<'a>>,
@ -16,3 +15,14 @@ impl<'a> CPlayShowDialog<'a> {
Self { dialog } Self { dialog }
} }
} }
impl ClientPacket for CPlayShowDialog<'_> {
fn write_packet_data(
&self,
mut write: impl std::io::Write,
version: &JavaMinecraftVersion,
) -> Result<(), WritingError> {
self.dialog
.write(&mut write, |w, value| value.write_packet_data(w, version))
}
}

View File

@ -55,12 +55,17 @@ impl ClientPacket for CSoundEffect {
IdOr::Value(value) => IdOr::Value(value.clone()), IdOr::Value(value) => IdOr::Value(value.clone()),
}; };
write.write_serialize(&sound_event)?; crate::IdOr::<crate::SoundEvent>::write(&sound_event, &mut write, |w, e| {
write.write_serialize(&self.sound_category)?; w.write_string(&e.sound_name)?;
write.write_serialize(&self.position)?; w.write_option(&e.range, |w2, r| w2.write_f32_be(*r))
write.write_serialize(&self.volume)?; })?;
write.write_serialize(&self.pitch)?; write.write_var_int(&self.sound_category)?;
write.write_serialize(&self.seed) write.write_i32_be(self.position.x * 8)?;
write.write_i32_be(self.position.y * 8)?;
write.write_i32_be(self.position.z * 8)?;
write.write_f32_be(self.volume)?;
write.write_f32_be(self.pitch)?;
write.write_i64_be(self.seed as i64)
} }
} }

View File

@ -1,11 +1,13 @@
use pumpkin_data::packet::clientbound::PLAY_STORE_COOKIE; use pumpkin_data::packet::clientbound::PLAY_STORE_COOKIE;
use pumpkin_macros::java_packet; use pumpkin_macros::java_packet;
use pumpkin_util::resource_location::ResourceLocation; use pumpkin_util::resource_location::ResourceLocation;
use serde::Serialize;
use crate::ClientPacket;
use crate::ser::NetworkWriteExt;
use pumpkin_util::version::JavaMinecraftVersion;
/// Stores some arbitrary data on the client, which persists between server transfers. /// Stores some arbitrary data on the client, which persists between server transfers.
/// The Notchian client only accepts cookies of up to 5 kiB in size. /// The Notchian client only accepts cookies of up to 5 kiB in size.
#[derive(Serialize)]
#[java_packet(PLAY_STORE_COOKIE)] #[java_packet(PLAY_STORE_COOKIE)]
pub struct CStoreCookie<'a> { pub struct CStoreCookie<'a> {
pub key: &'a ResourceLocation, pub key: &'a ResourceLocation,
@ -18,3 +20,18 @@ impl<'a> CStoreCookie<'a> {
Self { key, payload } Self { key, payload }
} }
} }
impl ClientPacket for CStoreCookie<'_> {
fn write_packet_data(
&self,
mut write: impl std::io::Write,
_version: &JavaMinecraftVersion,
) -> Result<(), crate::ser::WritingError> {
write.write_string(self.key)?;
write.write_var_int(&crate::VarInt(self.payload.len() as i32))?;
write
.write_all(self.payload)
.map_err(|_| crate::ser::WritingError::Message("IO Error".into()))?;
Ok(())
}
}

View File

@ -2,9 +2,11 @@ use pumpkin_data::packet::clientbound::PLAY_SET_SUBTITLE_TEXT;
use pumpkin_util::text::TextComponent; use pumpkin_util::text::TextComponent;
use pumpkin_macros::java_packet; use pumpkin_macros::java_packet;
use serde::Serialize;
#[derive(Serialize)] use crate::ClientPacket;
use crate::ser::NetworkWriteExt;
use pumpkin_util::version::JavaMinecraftVersion;
#[java_packet(PLAY_SET_SUBTITLE_TEXT)] #[java_packet(PLAY_SET_SUBTITLE_TEXT)]
pub struct CSubtitle<'a> { pub struct CSubtitle<'a> {
pub subtitle: &'a TextComponent, pub subtitle: &'a TextComponent,
@ -16,3 +18,14 @@ impl<'a> CSubtitle<'a> {
Self { subtitle } Self { subtitle }
} }
} }
impl ClientPacket for CSubtitle<'_> {
fn write_packet_data(
&self,
mut write: impl std::io::Write,
_version: &JavaMinecraftVersion,
) -> Result<(), crate::ser::WritingError> {
write.write_slice(&self.subtitle.encode())?;
Ok(())
}
}

View File

@ -2,9 +2,11 @@ use pumpkin_data::packet::clientbound::PLAY_SYSTEM_CHAT;
use pumpkin_util::text::TextComponent; use pumpkin_util::text::TextComponent;
use pumpkin_macros::java_packet; use pumpkin_macros::java_packet;
use serde::Serialize;
#[derive(Serialize)] use crate::ClientPacket;
use crate::ser::NetworkWriteExt;
use pumpkin_util::version::JavaMinecraftVersion;
#[java_packet(PLAY_SYSTEM_CHAT)] #[java_packet(PLAY_SYSTEM_CHAT)]
pub struct CSystemChatMessage<'a> { pub struct CSystemChatMessage<'a> {
pub content: &'a TextComponent, pub content: &'a TextComponent,
@ -17,3 +19,15 @@ impl<'a> CSystemChatMessage<'a> {
Self { content, overlay } Self { content, overlay }
} }
} }
impl ClientPacket for CSystemChatMessage<'_> {
fn write_packet_data(
&self,
mut write: impl std::io::Write,
_version: &JavaMinecraftVersion,
) -> Result<(), crate::ser::WritingError> {
write.write_slice(&self.content.encode())?;
write.write_bool(self.overlay)?;
Ok(())
}
}

View File

@ -1,10 +1,12 @@
use pumpkin_data::packet::clientbound::PLAY_TAB_LIST; use pumpkin_data::packet::clientbound::PLAY_TAB_LIST;
use pumpkin_macros::java_packet; use pumpkin_macros::java_packet;
use pumpkin_util::text::TextComponent; use pumpkin_util::text::TextComponent;
use serde::Serialize;
use crate::ClientPacket;
use crate::ser::NetworkWriteExt;
use pumpkin_util::version::JavaMinecraftVersion;
/// Updates the header and footer of the player list (Tab List). /// Updates the header and footer of the player list (Tab List).
#[derive(Serialize)]
#[java_packet(PLAY_TAB_LIST)] #[java_packet(PLAY_TAB_LIST)]
pub struct CTabList<'a> { pub struct CTabList<'a> {
/// The text to be displayed at the top of the player list. /// The text to be displayed at the top of the player list.
@ -19,3 +21,15 @@ impl<'a> CTabList<'a> {
Self { header, footer } Self { header, footer }
} }
} }
impl ClientPacket for CTabList<'_> {
fn write_packet_data(
&self,
mut write: impl std::io::Write,
_version: &JavaMinecraftVersion,
) -> Result<(), crate::ser::WritingError> {
write.write_slice(&self.header.encode())?;
write.write_slice(&self.footer.encode())?;
Ok(())
}
}

View File

@ -1,9 +1,11 @@
use crate::VarInt; use crate::VarInt;
use pumpkin_data::packet::clientbound::PLAY_TAKE_ITEM_ENTITY; use pumpkin_data::packet::clientbound::PLAY_TAKE_ITEM_ENTITY;
use pumpkin_macros::java_packet; use pumpkin_macros::java_packet;
use serde::Serialize;
#[derive(Serialize)] use crate::ClientPacket;
use crate::ser::NetworkWriteExt;
use pumpkin_util::version::JavaMinecraftVersion;
#[java_packet(PLAY_TAKE_ITEM_ENTITY)] #[java_packet(PLAY_TAKE_ITEM_ENTITY)]
pub struct CTakeItemEntity { pub struct CTakeItemEntity {
/// The entity id of the item entity. /// The entity id of the item entity.
@ -24,3 +26,16 @@ impl CTakeItemEntity {
} }
} }
} }
impl ClientPacket for CTakeItemEntity {
fn write_packet_data(
&self,
mut write: impl std::io::Write,
_version: &JavaMinecraftVersion,
) -> Result<(), crate::ser::WritingError> {
write.write_var_int(&self.entity_id)?;
write.write_var_int(&self.collector_entity_id)?;
write.write_var_int(&self.stack_amount)?;
Ok(())
}
}

View File

@ -1,8 +1,10 @@
use pumpkin_data::packet::clientbound::PLAY_TICKING_STATE; use pumpkin_data::packet::clientbound::PLAY_TICKING_STATE;
use pumpkin_macros::java_packet; use pumpkin_macros::java_packet;
use serde::Serialize;
#[derive(Serialize)] use crate::ClientPacket;
use crate::ser::NetworkWriteExt;
use pumpkin_util::version::JavaMinecraftVersion;
#[java_packet(PLAY_TICKING_STATE)] #[java_packet(PLAY_TICKING_STATE)]
pub struct CTickingState { pub struct CTickingState {
pub tick_rate: f32, pub tick_rate: f32,
@ -18,3 +20,15 @@ impl CTickingState {
} }
} }
} }
impl ClientPacket for CTickingState {
fn write_packet_data(
&self,
mut write: impl std::io::Write,
_version: &JavaMinecraftVersion,
) -> Result<(), crate::ser::WritingError> {
write.write_f32_be(self.tick_rate)?;
write.write_bool(self.is_frozen)?;
Ok(())
}
}

View File

@ -1,10 +1,11 @@
use pumpkin_data::packet::clientbound::PLAY_TICKING_STEP; use pumpkin_data::packet::clientbound::PLAY_TICKING_STEP;
use pumpkin_macros::java_packet; use pumpkin_macros::java_packet;
use serde::Serialize;
use crate::ClientPacket;
use crate::VarInt; use crate::VarInt;
use crate::ser::NetworkWriteExt;
use pumpkin_util::version::JavaMinecraftVersion;
#[derive(Serialize)]
#[java_packet(PLAY_TICKING_STEP)] #[java_packet(PLAY_TICKING_STEP)]
pub struct CTickingStep { pub struct CTickingStep {
pub tick_steps: VarInt, pub tick_steps: VarInt,
@ -16,3 +17,14 @@ impl CTickingStep {
Self { tick_steps } Self { tick_steps }
} }
} }
impl ClientPacket for CTickingStep {
fn write_packet_data(
&self,
mut write: impl std::io::Write,
_version: &JavaMinecraftVersion,
) -> Result<(), crate::ser::WritingError> {
write.write_var_int(&self.tick_steps)?;
Ok(())
}
}

View File

@ -1,9 +1,10 @@
use crate::ClientPacket;
use crate::VarInt; use crate::VarInt;
use crate::ser::NetworkWriteExt;
use pumpkin_data::packet::clientbound::PLAY_TRANSFER; use pumpkin_data::packet::clientbound::PLAY_TRANSFER;
use pumpkin_macros::java_packet; use pumpkin_macros::java_packet;
use serde::{Deserialize, Serialize}; use pumpkin_util::version::JavaMinecraftVersion;
#[derive(Serialize, Deserialize)]
#[java_packet(PLAY_TRANSFER)] #[java_packet(PLAY_TRANSFER)]
pub struct CTransfer<'a> { pub struct CTransfer<'a> {
pub host: &'a str, pub host: &'a str,
@ -16,3 +17,15 @@ impl<'a> CTransfer<'a> {
Self { host, port } Self { host, port }
} }
} }
impl ClientPacket for CTransfer<'_> {
fn write_packet_data(
&self,
mut write: impl std::io::Write,
_version: &JavaMinecraftVersion,
) -> Result<(), crate::ser::WritingError> {
write.write_string(self.host)?;
write.write_var_int(&self.port)?;
Ok(())
}
}

View File

@ -1,8 +1,10 @@
use pumpkin_data::packet::clientbound::PLAY_FORGET_LEVEL_CHUNK; use pumpkin_data::packet::clientbound::PLAY_FORGET_LEVEL_CHUNK;
use pumpkin_macros::java_packet; use pumpkin_macros::java_packet;
use serde::Serialize;
#[derive(Serialize)] use crate::ClientPacket;
use crate::ser::NetworkWriteExt;
use pumpkin_util::version::JavaMinecraftVersion;
#[java_packet(PLAY_FORGET_LEVEL_CHUNK)] #[java_packet(PLAY_FORGET_LEVEL_CHUNK)]
pub struct CUnloadChunk { pub struct CUnloadChunk {
pub z: i32, pub z: i32,
@ -15,3 +17,15 @@ impl CUnloadChunk {
Self { z, x } Self { z, x }
} }
} }
impl ClientPacket for CUnloadChunk {
fn write_packet_data(
&self,
mut write: impl std::io::Write,
_version: &JavaMinecraftVersion,
) -> Result<(), crate::ser::WritingError> {
write.write_i32_be(self.z)?;
write.write_i32_be(self.x)?;
Ok(())
}
}

View File

@ -1,82 +1,18 @@
use crate::codec::item_stack_seralizer::ItemStackTemplateSerializer;
use crate::codec::var_int::VarInt; use crate::codec::var_int::VarInt;
use pumpkin_data::Advancement; use pumpkin_data::Advancement;
use pumpkin_data::advancement_data::{AdvancementDisplay, AdvancementProgressData}; use pumpkin_data::advancement_data::AdvancementProgressData;
use pumpkin_data::packet::clientbound::PLAY_UPDATE_ADVANCEMENTS; use pumpkin_data::packet::clientbound::PLAY_UPDATE_ADVANCEMENTS;
use pumpkin_macros::java_packet; use pumpkin_macros::java_packet;
use pumpkin_util::identifier::Identifier; use pumpkin_util::identifier::Identifier;
use serde::ser::SerializeStruct;
use serde::{Serialize, Serializer, ser::SerializeSeq};
fn serialize_advancements<S: Serializer>( use crate::ClientPacket;
advancements: &[&'static Advancement], use crate::ser::NetworkWriteExt;
serializer: S, use pumpkin_util::version::JavaMinecraftVersion;
) -> Result<S::Ok, S::Error> {
let mut seq = serializer.serialize_seq(Some(advancements.len()))?;
for adv in advancements {
seq.serialize_element(&AdvancementSer(adv))?;
}
seq.end()
}
pub struct AdvancementSer<'a>(pub &'a Advancement);
impl Serialize for AdvancementSer<'_> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let adv = self.0;
let mut state = serializer.serialize_struct("Advancement", 5)?;
state.serialize_field("id", &adv.id.to_string())?;
state.serialize_field("parent", &adv.parent.clone().map(|p| p.to_string()))?;
if let Some(display) = adv.display {
state.serialize_field("display", &Some(DisplaySerializer(display)))?;
} else {
state.serialize_field("display", &None::<&DisplaySerializer>)?;
}
state.serialize_field("requirements", adv.requirements)?;
state.serialize_field("send_telemetry", &adv.send_telemetry)?;
state.end()
}
}
pub struct DisplaySerializer<'a>(pub &'a AdvancementDisplay);
impl Serialize for DisplaySerializer<'_> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let display = self.0;
let mut state = serializer.serialize_struct("AdvancementDisplay", 8)?;
state.serialize_field("title", &display.get_title())?;
state.serialize_field("description", &display.get_description())?;
state.serialize_field(
"icon",
&ItemStackTemplateSerializer::from(display.item_icon.clone()),
)?;
state.serialize_field("frame_type", &VarInt(display.frame_type as i32))?;
let flags = (display.has_background() as i32)
| ((display.show_toast as i32) << 1)
| ((display.hidden as i32) << 2);
state.serialize_field("flags", &flags)?;
if let Some(bg) = display.background_texture {
state.serialize_field("background_texture", bg)?;
}
state.serialize_field("x", &display.x)?;
state.serialize_field("y", &display.y)?;
state.end()
}
}
#[derive(Serialize)]
#[java_packet(PLAY_UPDATE_ADVANCEMENTS)] #[java_packet(PLAY_UPDATE_ADVANCEMENTS)]
#[allow(unused)] #[allow(unused)]
pub struct CUpdateAdvancements { pub struct CUpdateAdvancements {
pub reset: bool, pub reset: bool,
#[serde(serialize_with = "serialize_advancements")]
pub added: Vec<&'static Advancement>, pub added: Vec<&'static Advancement>,
pub removed: Vec<Identifier>, pub removed: Vec<Identifier>,
pub progress: Vec<AdvancementProgressData>, pub progress: Vec<AdvancementProgressData>,
@ -102,3 +38,82 @@ impl CUpdateAdvancements {
} }
} }
} }
impl ClientPacket for CUpdateAdvancements {
#[allow(clippy::unimplemented)]
fn write_packet_data(
&self,
mut write: impl std::io::Write,
_version: &JavaMinecraftVersion,
) -> Result<(), crate::ser::WritingError> {
write.write_bool(self.reset)?;
write.write_var_int(&VarInt(self.added.len() as i32))?;
for adv in &self.added {
write.write_string(&adv.id.to_string())?;
let has_parent = adv.parent.is_some();
write.write_bool(has_parent)?;
if let Some(ref p) = adv.parent {
write.write_string(&p.to_string())?;
}
let has_display = adv.display.is_some();
write.write_bool(has_display)?;
if let Some(display) = adv.display {
write.write_slice(&display.get_title().encode())?;
write.write_slice(&display.get_description().encode())?;
// Item icon
// TODO: serialize item_icon (ItemStack)
unimplemented!("Item serialization is not yet implemented without serde");
/*
write.write_var_int(&VarInt(display.frame_type as i32))?;
let flags = (display.has_background() as i32)
| ((display.show_toast as i32) << 1)
| ((display.hidden as i32) << 2);
write.write_i32_be(flags)?;
if let Some(bg) = display.background_texture {
write.write_string(bg)?;
}
write.write_f32_be(display.x)?;
write.write_f32_be(display.y)?;
*/
}
write.write_var_int(&VarInt(adv.requirements.len() as i32))?;
for req in adv.requirements {
write.write_var_int(&VarInt(req.len() as i32))?;
for r in *req {
write.write_string(r)?;
}
}
write.write_bool(adv.send_telemetry)?;
}
write.write_var_int(&VarInt(self.removed.len() as i32))?;
for rem in &self.removed {
write.write_string(&rem.to_string())?;
}
write.write_var_int(&VarInt(self.progress.len() as i32))?;
for prog in &self.progress {
write.write_string(&prog.id.to_string())?;
write.write_var_int(&VarInt(prog.progress.len() as i32))?;
for crit in &prog.progress {
write.write_string(&crit.criterion_id)?;
let has_date = crit.achieve_date.is_some();
write.write_bool(has_date)?;
if let Some(date) = crit.achieve_date {
write.write_i64_be(date)?;
}
}
}
write.write_bool(self.show_advancements)?;
Ok(())
}
}

Some files were not shown because too many files have changed in this diff Show More