diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 12d2293c..bc7445f6 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,4 +1,4 @@ -on: [push, pull_request] +on: [ push, pull_request ] name: Continuous integration @@ -63,4 +63,3 @@ jobs: - uses: actions-rs/cargo@v1 with: command: clippy - args: -- -D warnings diff --git a/.gitignore b/.gitignore index 3554dac6..4f895f59 100644 --- a/.gitignore +++ b/.gitignore @@ -10,8 +10,16 @@ target/ # More information here https://doc.rust-lang.org/cargo/guide/cargo-toml-vs-cargo-lock.html Cargo.lock +# Profiler logs +*.opt + # These are backup files generated by rustfmt **/*.rs.bk # MSVC Windows builds of rustc generate these, which store debugging information -*.pdb \ No newline at end of file +*.pdb + +*.bin + +# This is a little hack to allow the tests to be ran and not have a merge conflict +crates/level/test_level/ \ No newline at end of file diff --git a/Cargo.toml b/Cargo.toml index 6e334cb9..0b628b2b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,26 +4,51 @@ version = "0.1.0" edition = "2021" [workspace] -members = [ "crates/*" ] +members = ["crates/*"] [dependencies] bedrockrs_core = { path = "crates/core" } bedrockrs_shared = { path = "crates/shared" } +bedrockrs_macros = { path = "crates/macros", optional = true } + +bedrockrs_addon = { path = "crates/addon", optional = true } + +bedrockrs_form = { path = "crates/form", optional = true } + bedrockrs_proto = { path = "crates/proto", optional = true } bedrockrs_proto_core = { path = "crates/proto_core", optional = true } -bedrockrs_proto_macros = { path = "crates/proto_macros", optional = true } -bedrockrs_addon = { path = "crates/addon", optional = true } +bedrockrs_server = { path = "crates/server", optional = true } + +bedrockrs_level = {path = "crates/level", optional = true} + +[dev-dependencies] +tokio = { version = "1.40", features = ["full"] } + +nbtx = { git = "https://github.com/bedrock-crustaceans/nbtx" } +uuid = { version = "1.11.0", features = ["v4"] } -bedrockrs_form = { path = "crates/form" } -bedrockrs_world = { path = "crates/world", optional = true } -bedrockrs_paletted_storage = { path = "crates/paletted_storage", optional = true } +fern = { version = "0.7", features = ["colored"] } +log = "0.4" +chrono = "0.4" [features] -full = ["addon", "proto", "world"] addon = ["dep:bedrockrs_addon"] -proto = ["dep:bedrockrs_proto", "dep:bedrockrs_proto_core", "dep:bedrockrs_proto_macros"] -world = ["dep:bedrockrs_world", "dep:bedrockrs_paletted_storage"] +proto = ["dep:bedrockrs_proto","dep:bedrockrs_proto_core","dep:bedrockrs_macros",] +level = ["dep:bedrockrs_level"] +full = ["addon", "level", "proto", "server"] +form = ["dep:bedrockrs_form"] +server = ["dep:bedrockrs_server", "proto", "level", "form"] + +[[example]] +name = "proto_server" +path = "examples/proto/server.rs" +required-features = ["proto"] + +[[example]] +name = "proto_parsing" +path = "examples/proto_parsing.rs" +required-features = ["proto"] diff --git a/README.md b/README.md index 82624446..9ea84139 100644 --- a/README.md +++ b/README.md @@ -1,42 +1,101 @@ # bedrock-rs -_Universal toolkit for MCBE in Rust_ +**_Universal Toolkit for Minecraft Bedrock Edition in Rust_** -An easy-to-use universal library for Minecraft Bedrock written in Rust, that aims to provide: +**bedrock-rs** is a comprehensive and user-friendly library written in Rust, designed to provide a universal solution for working with Minecraft Bedrock Edition. This project offers: -- [X] Standards -- [X] Common implementations -- [X] An easy-to-use api +- **Standards:** Adhering to best practices and conventions. +- **Common Implementations:** Reusable components for various Minecraft Bedrock needs. +- **Easy-to-Use API:** Streamlined interfaces to make development efficient and enjoyable. -We also have a community discord, feel free to join it to learn more about our future and get help when needed: https://discord.com/invite/VCVcrvt3JC +Join our growing community on Discord to learn more about the project’s future, seek support, or collaborate with others: +**[Join our Discord](https://discord.com/invite/VCVcrvt3JC)** -## Crates: +--- -- [Core](https://github.com/Adrian8115/bedrock-rs/tree/main/crates/core): - - Provides common base datatypes. +## Crates -- [Shared](https://github.com/Adrian8115/bedrock-rs/tree/main/crates/shared): - - Shared datatypes that can use derive macros defined in other crates. +To maintain modularity and scalability, **bedrock-rs** is divided into multiple crates. Each crate focuses on a specific functionality, making it easier to use and manage. All crates are accessible through the primary `bedrockrs` crate. Additionally, the library offers a variety of optional features you can enable to suit your needs. -- [Proto](https://github.com/Adrian8115/bedrock-rs/tree/main/crates/proto): - - Full implementation of the Bedrock protocol. - - Support for both Server and Client side intended. - - Built-in login procedure. +### Crate Breakdown: -- [World](https://github.com/Adrian8115/bedrock-rs/tree/main/crates/world): - - Implementation of the Bedrock level format using our own `leveldb` bindings for mojangs leveldb fork. +- [`bedrockrs::shared`](crates/shared) + - [X] Shared data types used across other crates. + - [X] Support for deriving macros defined in other modules. -- [Addons](https://github.com/Adrian8115/bedrock-rs/tree/main/crates/addon): - - Datatypes defining the structure of Addons. - - Serialization and Deserialization of addons. +- [`bedrockrs::form`](crates/form) + - [X] Implementation of the JSON form format used by Minecraft Bedrock Edition. -- [Form](https://github.com/Adrian8115/bedrock-rs/tree/main/crates/form): - - Implementation of the JSON form format used in Minecraft Bedrock. +- [`bedrockrs::addon`](crates/addon) + - [X] Datatypes for defining Minecraft Addon structures. + - [X] Serialization and deserialization support for Addons. + - [X] A programmatic approach to creating Addons easily. -## Contributing: +- [`bedrockrs::proto`](crates/proto) + - [X] Complete implementation of the Minecraft Bedrock protocol. + - [X] Support for both server-side and client-side operations. + - [X] Multi-protocol compatibility for handling multiple versions seamlessly. -Feel free to join in at any time. Your contributions are highly valued, and a big thank you to all who participate. We -recommend getting acquainted with the bedrock-rs codebase. Whether it's tackling existing issues, adding new features, -or even introducing entirely fresh modules, your creativity is welcome. +- [`bedrockrs::level`](crates/level) + - [X] Data structures for managing Minecraft Bedrock levels. + - [X] Implementation of Bedrock’s level format using Rust’s LevelDB. -(If you like this library, remember to give bedrockrs a Star!) +- [`bedrockrs::server`](/crates/server) + - [X] A lightweight foundation for Minecraft Bedrock server software. + - [X] Built-in support for multi-protocol handling. + - [X] Asynchronous architecture powered by Tokio. + +--- + +## Features + +- **Modular Architecture:** Enable only the features you need for your project. +- **Multi-Protocol Support:** Work with different protocol versions effortlessly. +- **Cross-Platform Compatibility:** Designed to work seamlessly across platforms. +- **Lightweight and Efficient:** Built with Rust’s performance and safety features. + +--- + +## Getting Started + +To use **bedrock-rs** in your Rust project, add the following to your `Cargo.toml`: +```toml +[dependencies] +bedrockrs = { git = "https://github.com/bedrock-crustaceans/bedrock-rs.git", features = ["full"] } +``` + +Refer to the individual crate documentation for details on specific modules and features. + +We also plan to release bedrock-rs on [crates.io](https://crates.io) in the future. + +--- + +## Contributors + +A huge thank you to all the amazing individuals who have contributed to **bedrock-rs**! Your time, effort, and expertise are what make this project possible. + +[![Contributors](https://contrib.rocks/image?repo=bedrock-crustaceans/bedrock-rs)](https://github.com/bedrock-crustaceans/bedrock-rs/graphs/contributors) + +Whether it’s fixing bugs, implementing features, or providing feedback, every contribution helps shape the future of this library. We appreciate each and every one of you! + +Want to join this incredible group? Check out our Contributing Guide and make your mark on the project. + +--- + +## Contributing + +We welcome contributions of all kinds! Whether you're fixing bugs, adding new features, or proposing entirely new modules, your efforts are highly appreciated. Here’s how you can get involved: + +1. **Get Familiar with the Codebase:** Explore the existing modules and documentation. +2. **Pick an Issue:** Check out the repository’s issue tracker for tasks you can work on. +3. **Add Your Touch:** Feel free to innovate and bring new ideas to the table. + +For guidance or collaboration, feel free to connect with the community on Discord. + +If you find **bedrock-rs** helpful, don’t forget to give the repository a ⭐ on GitHub. + +--- + +## License + +**bedrock-rs** is open-source software licensed under the [Apache-2.0 License](LICENSE). diff --git a/crates/addon/Cargo.toml b/crates/addon/Cargo.toml index b1e0bbe8..04f7a032 100644 --- a/crates/addon/Cargo.toml +++ b/crates/addon/Cargo.toml @@ -4,13 +4,16 @@ version = "0.1.0" edition = "2021" [dependencies] -bedrockrs_core = { path = "../core" } - uuid = { version = "1.8", features = ["serde"] } semver = { version = "1.0", features = ["serde"] } + image = "0.25" -thiserror = "1.0" + +vek = "0.17" +thiserror = "2.0" + serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" json_comments = "0.2" + walkdir = "2.5" diff --git a/crates/addon/src/behavior/mod.rs b/crates/addon/src/behavior/mod.rs index b00365c4..63f220e4 100644 --- a/crates/addon/src/behavior/mod.rs +++ b/crates/addon/src/behavior/mod.rs @@ -53,7 +53,7 @@ impl Addon for BehaviorPack { let blocks_path = path.join("blocks"); let mut blocks = HashMap::new(); - // If dir exists read all blocks + // If dir exists, read all blocks if blocks_path.is_dir() { 'blocks_walk: for blocks_entry in WalkDir::new(&blocks_path).into_iter().filter(|v| { if let Ok(v) = v { @@ -88,7 +88,7 @@ impl Addon for BehaviorPack { let items_path = path.join("items"); let mut items = HashMap::new(); - // If dir exists read all items + // If dir exists, read all items if items_path.is_dir() { 'items_walk: for items_entry in WalkDir::new(&items_path).into_iter().filter(|v| { if let Ok(v) = v { @@ -177,14 +177,14 @@ impl Addon for BehaviorPack { }) } - fn export(path: impl AsRef) -> Result + fn export(_path: impl AsRef) -> Result where Self: Sized, { unimplemented!() } - fn merge(addons: Vec) -> Self + fn merge(_addons: Vec) -> Self where Self: Sized, { diff --git a/crates/addon/src/language/code.rs b/crates/addon/src/language/code.rs index a5873771..234ce341 100644 --- a/crates/addon/src/language/code.rs +++ b/crates/addon/src/language/code.rs @@ -1,24 +1,10 @@ -use std::fmt::{Debug, Formatter}; +use std::fmt::Debug; -use bedrockrs_core::Vec2; use serde::{Deserialize, Serialize}; -#[derive(Serialize, Deserialize, Clone)] +#[derive(Serialize, Deserialize, Debug, Clone)] #[serde(untagged)] pub enum LanguageCode { VanillaCode(String), - CustomCode(Vec2), -} - -impl Debug for LanguageCode { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - match self { - LanguageCode::VanillaCode(v) => { - write!(f, "VanillaCode({v})") - } - LanguageCode::CustomCode(v) => { - write!(f, "CustomCode([{}, {}])", v.x, v.y) - } - } - } + CustomCode((String, String)), } diff --git a/crates/addon/src/language/mod.rs b/crates/addon/src/language/mod.rs index 01e863ef..c4c01062 100644 --- a/crates/addon/src/language/mod.rs +++ b/crates/addon/src/language/mod.rs @@ -32,7 +32,7 @@ impl Languages { for language in languages_file { let language_code = match language { LanguageCode::VanillaCode(v) => v, - LanguageCode::CustomCode(v) => v.x, + LanguageCode::CustomCode(v) => v.1, }; let language_path = languages_path.join(format!("{language_code}.lang")); diff --git a/crates/addon/src/manifest.rs b/crates/addon/src/manifest.rs index 7131d4c5..0e57e76c 100644 --- a/crates/addon/src/manifest.rs +++ b/crates/addon/src/manifest.rs @@ -1,4 +1,3 @@ -use bedrockrs_core::Vec3; use serde::{Deserialize, Serialize}; use uuid::Uuid; @@ -40,9 +39,9 @@ pub struct AddonManifestHeader { /// For resource packs, an optional string that specifies whether this resource pack can be used across the game or at an individual world level. Valid values are "world", which specifies that a pack is only addable in the context of a world "global", which means that a pack is only addable across the game, and "any" which indicates that a pack can apply either across the game or to a specific world. If not specified, this is interpreted as "any". pub pack_scope: Option, /// This is the version of the base game your world template requires, specified as [majorVersion, minorVersion, revision]. We use this to determine what version of the base game resource and behavior packs to apply when your content is used. (world template manifest JSON only) - pub base_game_version: Option>, + pub base_game_version: Option<[u32; 3]>, /// This is the minimum version of the game that this pack was written for. This is a required field for resource and behavior packs. This helps the game identify whether any backwards compatibility is needed for your pack. You should always use the highest version currently available when creating packs. - pub min_engine_version: Option>, + pub min_engine_version: Option<[u32; 3]>, } /// Section containing information regarding the type of content that is being brought in. @@ -76,7 +75,7 @@ pub struct AddonManifestDependency { /// Section containing the metadata about the file such as authors and licensing information. #[derive(Serialize, Deserialize, Debug, Clone)] pub struct AddonManifestMetadata { - /// Name of the author(s) of the pack. + /// Name of the pack authors. pub authors: Option>, /// The license of the pack. pub license: Option, diff --git a/crates/addon/src/resource/mod.rs b/crates/addon/src/resource/mod.rs index 6f5c9557..16c08652 100644 --- a/crates/addon/src/resource/mod.rs +++ b/crates/addon/src/resource/mod.rs @@ -41,14 +41,14 @@ impl Addon for ResourcePack { }) } - fn export(path: impl AsRef) -> Result + fn export(_path: impl AsRef) -> Result where Self: Sized, { unimplemented!() } - fn merge(addons: Vec) -> Self + fn merge(_addons: Vec) -> Self where Self: Sized, { diff --git a/crates/addon/src/version.rs b/crates/addon/src/version.rs index fda88dc6..daf3ef56 100644 --- a/crates/addon/src/version.rs +++ b/crates/addon/src/version.rs @@ -1,21 +1,11 @@ -use std::fmt::{Debug, Formatter}; +use std::fmt::Debug; -use bedrockrs_core::Vec3; use serde::{Deserialize, Serialize}; /// A version used in Addons that is either a Vector [a, b, c] or SemVer String. -#[derive(Serialize, Deserialize, Clone)] +#[derive(Serialize, Deserialize, Clone, Debug)] #[serde(untagged)] pub enum AddonSemanticVersion { - Vector(Vec3), + Vector([u32; 3]), SemVer(semver::Version), } - -impl Debug for AddonSemanticVersion { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - match self { - AddonSemanticVersion::Vector(v) => f.debug_list().entries([v.x, v.y, v.z]).finish(), - AddonSemanticVersion::SemVer(v) => v.fmt(f), - } - } -} diff --git a/crates/core/Cargo.toml b/crates/core/Cargo.toml index a236f41e..ffdf71d8 100644 --- a/crates/core/Cargo.toml +++ b/crates/core/Cargo.toml @@ -4,10 +4,3 @@ version = "0.1.0" edition = "2021" [dependencies] -uuid = { version = "1.8", features = ["v4"] } - -bytes = "1.6" -byteorder = "1.5" -varint-rs = "2.2" - -serde = "1.0" diff --git a/crates/core/src/int/be.rs b/crates/core/src/int/be.rs deleted file mode 100644 index 5f651002..00000000 --- a/crates/core/src/int/be.rs +++ /dev/null @@ -1,86 +0,0 @@ -use std::fmt::{Debug, Formatter}; -use std::io::{self, Read, Write}; - -use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt}; - -#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq)] -#[repr(transparent)] -pub struct BE { - num: T, -} - -impl Debug for BE { - #[inline] - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - write!(f, "{:?}", self.num) - } -} - -impl BE { - #[inline] - pub fn new(num: T) -> Self { - Self { num } - } - - #[inline] - pub fn into_inner(self) -> T { - self.num - } -} - -macro_rules! impl_be { - ($type:ty, $read_fn_name:ident, $write_fn_name:ident) => { - impl BE<$type> { - #[inline] - pub fn read(reader: &mut R) -> io::Result { - let num = reader.$read_fn_name::()?; - Ok(BE::new(num)) - } - - #[inline] - pub fn write(&self, writer: &mut W) -> io::Result<()> { - writer.$write_fn_name::(self.num)?; - Ok(()) - } - } - }; -} - -impl BE { - pub fn read(reader: &mut R) -> io::Result { - let num = reader.read_u8()?; - Ok(BE::new(num)) - } - - pub fn write(&self, writer: &mut W) -> io::Result<()> { - writer.write_u8(self.num)?; - Ok(()) - } -} - -impl BE { - pub fn read(reader: &mut R) -> io::Result { - let num = reader.read_i8()?; - Ok(BE::new(num)) - } - - pub fn write(&self, writer: &mut W) -> io::Result<()> { - writer.write_i8(self.num)?; - Ok(()) - } -} - -impl_be!(u16, read_u16, write_u16); -impl_be!(i16, read_i16, write_i16); - -impl_be!(u32, read_u32, write_u32); -impl_be!(i32, read_i32, write_i32); - -impl_be!(u64, read_u64, write_u64); -impl_be!(i64, read_i64, write_i64); - -impl_be!(u128, read_u128, write_u128); -impl_be!(i128, read_i128, write_i128); - -impl_be!(f32, read_f32, write_f32); -impl_be!(f64, read_f64, write_f64); diff --git a/crates/core/src/int/le.rs b/crates/core/src/int/le.rs deleted file mode 100644 index ad7a8856..00000000 --- a/crates/core/src/int/le.rs +++ /dev/null @@ -1,86 +0,0 @@ -use std::fmt::{Debug, Formatter}; -use std::io::{self, Read, Write}; - -use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; - -#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq)] -#[repr(transparent)] -pub struct LE { - num: T, -} - -impl Debug for LE { - #[inline] - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - write!(f, "{:?}", self.num) - } -} - -impl LE { - #[inline] - pub fn new(num: T) -> Self { - Self { num } - } - - #[inline] - pub fn into_inner(self) -> T { - self.num - } -} - -macro_rules! impl_le { - ($type:ty, $read_fn_name:ident, $write_fn_name:ident) => { - impl LE<$type> { - #[inline] - pub fn read(reader: &mut R) -> io::Result { - let num = reader.$read_fn_name::()?; - Ok(LE::new(num)) - } - - #[inline] - pub fn write(&self, writer: &mut W) -> io::Result<()> { - writer.$write_fn_name::(self.num)?; - Ok(()) - } - } - }; -} - -impl LE { - pub fn read(reader: &mut R) -> io::Result { - let num = reader.read_u8()?; - Ok(LE::new(num)) - } - - pub fn write(&self, writer: &mut W) -> io::Result<()> { - writer.write_u8(self.num)?; - Ok(()) - } -} - -impl LE { - pub fn read(reader: &mut R) -> io::Result { - let num = reader.read_i8()?; - Ok(LE::new(num)) - } - - pub fn write(&self, writer: &mut W) -> io::Result<()> { - writer.write_i8(self.num)?; - Ok(()) - } -} - -impl_le!(u16, read_u16, write_u16); -impl_le!(i16, read_i16, write_i16); - -impl_le!(u32, read_u32, write_u32); -impl_le!(i32, read_i32, write_i32); - -impl_le!(u64, read_u64, write_u64); -impl_le!(i64, read_i64, write_i64); - -impl_le!(u128, read_u128, write_u128); -impl_le!(i128, read_i128, write_i128); - -impl_le!(f32, read_f32, write_f32); -impl_le!(f64, read_f64, write_f64); diff --git a/crates/core/src/int/mod.rs b/crates/core/src/int/mod.rs deleted file mode 100644 index 85158d80..00000000 --- a/crates/core/src/int/mod.rs +++ /dev/null @@ -1,7 +0,0 @@ -pub use be::*; -pub use le::*; -pub use var::*; - -pub mod be; -pub mod le; -pub mod var; diff --git a/crates/core/src/int/var.rs b/crates/core/src/int/var.rs deleted file mode 100644 index 394cc48d..00000000 --- a/crates/core/src/int/var.rs +++ /dev/null @@ -1,60 +0,0 @@ -use std::fmt::{Debug, Formatter}; -use std::io; -use std::io::{Read, Write}; - -use varint_rs::{VarintReader, VarintWriter}; - -#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq)] -#[repr(transparent)] -pub struct VAR { - num: T, -} - -impl Debug for VAR { - #[inline] - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - write!(f, "{:?}", self.num) - } -} - -impl VAR { - #[inline] - pub fn new(num: T) -> Self { - Self { num } - } - - #[inline] - pub fn into_inner(self) -> T { - self.num - } -} - -macro_rules! impl_var { - ($type:ty, $read_fn_name:ident, $write_fn_name:ident) => { - impl VAR<$type> { - #[inline] - pub fn read(reader: &mut R) -> io::Result { - let num = reader.$read_fn_name()?; - Ok(VAR::new(num)) - } - - #[inline] - pub fn write(&self, writer: &mut W) -> io::Result<()> { - writer.$write_fn_name(self.num)?; - Ok(()) - } - } - }; -} - -impl_var!(u16, read_u16_varint, write_u16_varint); -impl_var!(i16, read_i16_varint, write_i16_varint); - -impl_var!(u32, read_u32_varint, write_u32_varint); -impl_var!(i32, read_i32_varint, write_i32_varint); - -impl_var!(u64, read_u64_varint, write_u64_varint); -impl_var!(i64, read_i64_varint, write_i64_varint); - -impl_var!(u128, read_u128_varint, write_u128_varint); -impl_var!(i128, read_i128_varint, write_i128_varint); diff --git a/crates/core/src/lib.rs b/crates/core/src/lib.rs index c76f8fe2..8b137891 100644 --- a/crates/core/src/lib.rs +++ b/crates/core/src/lib.rs @@ -1,5 +1 @@ -pub use vec::vec2::Vec2; -pub use vec::vec3::Vec3; -pub mod int; -pub mod vec; diff --git a/crates/core/src/vec/mod.rs b/crates/core/src/vec/mod.rs deleted file mode 100644 index 84df29d5..00000000 --- a/crates/core/src/vec/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ -pub mod vec2; -pub mod vec3; diff --git a/crates/core/src/vec/vec2.rs b/crates/core/src/vec/vec2.rs deleted file mode 100644 index 70666662..00000000 --- a/crates/core/src/vec/vec2.rs +++ /dev/null @@ -1,199 +0,0 @@ -use std::ops::{ - Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Rem, RemAssign, Sub, SubAssign, -}; - -use crate::int::{BE, LE, VAR}; -use serde::{Deserialize, Deserializer, Serialize, Serializer}; - -#[derive(Debug, Copy, Clone, Eq, PartialEq)] -pub struct Vec2 { - pub x: T, - pub y: T, -} - -impl> Add for Vec2 { - type Output = Self; - - #[inline] - fn add(self, rhs: Self) -> Self::Output { - Self { - x: self.x + rhs.x, - y: self.y + rhs.y, - } - } -} - -impl AddAssign for Vec2 { - #[inline] - fn add_assign(&mut self, rhs: Self) { - self.x += rhs.x; - self.y += rhs.y; - } -} - -impl> Sub for Vec2 { - type Output = Self; - - #[inline] - fn sub(self, rhs: Self) -> Self::Output { - Self { - x: self.x - rhs.x, - y: self.y - rhs.y, - } - } -} - -impl SubAssign for Vec2 { - #[inline] - fn sub_assign(&mut self, rhs: Self) { - self.x -= rhs.x; - self.y -= rhs.y; - } -} - -impl> Mul for Vec2 { - type Output = Self; - - #[inline] - fn mul(self, rhs: Self) -> Self::Output { - Self { - x: self.x * rhs.x, - y: self.y * rhs.y, - } - } -} - -impl MulAssign for Vec2 { - #[inline] - fn mul_assign(&mut self, rhs: Self) { - self.x *= rhs.x; - self.y *= rhs.y; - } -} - -impl> Div for Vec2 { - type Output = Self; - - #[inline] - fn div(self, rhs: Self) -> Self::Output { - Self { - x: self.x / rhs.x, - y: self.y / rhs.y, - } - } -} - -impl DivAssign for Vec2 { - #[inline] - fn div_assign(&mut self, rhs: Self) { - self.x /= rhs.x; - self.y /= rhs.y; - } -} - -impl> Rem for Vec2 { - type Output = Self; - - #[inline] - fn rem(self, rhs: Self) -> Self::Output { - Self { - x: self.x % rhs.x, - y: self.y % rhs.y, - } - } -} - -impl RemAssign for Vec2 { - #[inline] - fn rem_assign(&mut self, rhs: Self) { - self.x %= rhs.x; - self.y %= rhs.y; - } -} - -impl> Neg for Vec2 { - type Output = Self; - - #[inline] - fn neg(self) -> Self::Output { - Self { - x: -self.x, - y: -self.y, - } - } -} - -// Serde - -impl Serialize for Vec2 { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - <[&T; 2]>::serialize(&[&self.x, &self.y], serializer) - } -} - -impl<'de, T: Deserialize<'de>> Deserialize<'de> for Vec2 { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - let [x, y] = <[T; 2]>::deserialize(deserializer)?; - - Ok(Self { x, y }) - } -} - -impl Vec2 { - // LE - #[inline] - pub fn to_le(self) -> Vec2> { - Vec2 { - x: LE::new(self.x), - y: LE::new(self.y), - } - } - - #[inline] - pub fn from_le(le: Vec2>) -> Vec2 { - Vec2 { - x: le.x.into_inner(), - y: le.y.into_inner(), - } - } - - // BE - #[inline] - pub fn to_be(self) -> Vec2> { - Vec2 { - x: BE::new(self.x), - y: BE::new(self.y), - } - } - - #[inline] - pub fn from_be(be: Vec2>) -> Vec2 { - Vec2 { - x: be.x.into_inner(), - y: be.y.into_inner(), - } - } - - // VAR - #[inline] - pub fn to_var(self) -> Vec2> { - Vec2 { - x: VAR::new(self.x), - y: VAR::new(self.y), - } - } - - #[inline] - pub fn from_var(var: Vec2>) -> Vec2 { - Vec2 { - x: var.x.into_inner(), - y: var.y.into_inner(), - } - } -} diff --git a/crates/core/src/vec/vec3.rs b/crates/core/src/vec/vec3.rs deleted file mode 100644 index b877d5bc..00000000 --- a/crates/core/src/vec/vec3.rs +++ /dev/null @@ -1,217 +0,0 @@ -use std::ops::{ - Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Rem, RemAssign, Sub, SubAssign, -}; - -use crate::int::{BE, LE, VAR}; -use serde::{Deserialize, Deserializer, Serialize, Serializer}; - -#[derive(Debug, Copy, Clone, Eq, PartialEq)] -pub struct Vec3 { - pub x: T, - pub y: T, - pub z: T, -} - -impl> Add for Vec3 { - type Output = Self; - - #[inline] - fn add(self, rhs: Self) -> Self::Output { - Self { - x: self.x + rhs.x, - y: self.y + rhs.y, - z: self.z + rhs.z, - } - } -} - -impl AddAssign for Vec3 { - #[inline] - fn add_assign(&mut self, rhs: Self) { - self.x += rhs.x; - self.y += rhs.y; - self.z += rhs.z; - } -} - -impl> Sub for Vec3 { - type Output = Self; - - #[inline] - fn sub(self, rhs: Self) -> Self::Output { - Self { - x: self.x - rhs.x, - y: self.y - rhs.y, - z: self.z - rhs.z, - } - } -} - -impl SubAssign for Vec3 { - #[inline] - fn sub_assign(&mut self, rhs: Self) { - self.x -= rhs.x; - self.y -= rhs.y; - self.z -= rhs.z; - } -} - -impl> Mul for Vec3 { - type Output = Self; - - #[inline] - fn mul(self, rhs: Self) -> Self::Output { - Self { - x: self.x * rhs.x, - y: self.y * rhs.y, - z: self.z * rhs.z, - } - } -} - -impl MulAssign for Vec3 { - #[inline] - fn mul_assign(&mut self, rhs: Self) { - self.x *= rhs.x; - self.y *= rhs.y; - self.z *= rhs.z; - } -} - -impl> Div for Vec3 { - type Output = Self; - - #[inline] - fn div(self, rhs: Self) -> Self::Output { - Self { - x: self.x / rhs.x, - y: self.y / rhs.y, - z: self.z / rhs.z, - } - } -} - -impl DivAssign for Vec3 { - #[inline] - fn div_assign(&mut self, rhs: Self) { - self.x /= rhs.x; - self.y /= rhs.y; - self.z /= rhs.z; - } -} - -impl> Rem for Vec3 { - type Output = Self; - - #[inline] - fn rem(self, rhs: Self) -> Self::Output { - Self { - x: self.x % rhs.x, - y: self.y % rhs.y, - z: self.z % rhs.z, - } - } -} - -impl RemAssign for Vec3 { - #[inline] - fn rem_assign(&mut self, rhs: Self) { - self.x %= rhs.x; - self.y %= rhs.y; - self.z %= rhs.z; - } -} - -impl> Neg for Vec3 { - type Output = Self; - - #[inline] - fn neg(self) -> Self::Output { - Self { - x: -self.x, - y: -self.y, - z: -self.z, - } - } -} - -// Serde - -impl Serialize for Vec3 { - fn serialize(&self, serializer: S) -> Result - where - S: Serializer, - { - <[&T; 3]>::serialize(&[&self.x, &self.y, &self.z], serializer) - } -} - -impl<'de, T: Deserialize<'de>> Deserialize<'de> for Vec3 { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - let [x, y, z] = <[T; 3]>::deserialize(deserializer)?; - - Ok(Self { x, y, z }) - } -} - -impl Vec3 { - // LE - #[inline] - pub fn to_le(self) -> Vec3> { - Vec3 { - x: LE::new(self.x), - y: LE::new(self.y), - z: LE::new(self.z), - } - } - - #[inline] - pub fn from_le(le: Vec3>) -> Vec3 { - Vec3 { - x: le.x.into_inner(), - y: le.y.into_inner(), - z: le.z.into_inner(), - } - } - - // BE - #[inline] - pub fn to_be(self) -> Vec3> { - Vec3 { - x: BE::new(self.x), - y: BE::new(self.y), - z: BE::new(self.z), - } - } - - #[inline] - pub fn from_be(be: Vec3>) -> Vec3 { - Vec3 { - x: be.x.into_inner(), - y: be.y.into_inner(), - z: be.z.into_inner(), - } - } - - // VAR - #[inline] - pub fn to_var(self) -> Vec3> { - Vec3 { - x: VAR::new(self.x), - y: VAR::new(self.y), - z: VAR::new(self.z), - } - } - - #[inline] - pub fn from_var(var: Vec3>) -> Vec3 { - Vec3 { - x: var.x.into_inner(), - y: var.y.into_inner(), - z: var.z.into_inner(), - } - } -} diff --git a/crates/form/Cargo.toml b/crates/form/Cargo.toml index 7cdbf3e8..6389b5c2 100644 --- a/crates/form/Cargo.toml +++ b/crates/form/Cargo.toml @@ -4,7 +4,7 @@ version = "0.1.0" edition = "2021" [dependencies] -thiserror = "1.0" +thiserror = "2.0" serde_json = "1.0" serde = { version = "1.0", features = ["derive"] } diff --git a/crates/level/Cargo.toml b/crates/level/Cargo.toml new file mode 100644 index 00000000..d16d195c --- /dev/null +++ b/crates/level/Cargo.toml @@ -0,0 +1,34 @@ +[package] +name = "bedrockrs_level" +version = "0.1.0" +edition = "2021" + +[dependencies] +bedrockrs_core = { path = "../core" } +bedrockrs_shared = { path = "../shared" } + +nbtx = { git = "https://github.com/bedrock-crustaceans/nbtx" } + +thiserror = "1.x" +byteorder = "1.x" +uuid = { version = "1.x", features = ["v4"] } +bytemuck = { version = "1.19.x", features = ["must_cast"] } +len-trait = "0.6.x" +concat-idents = "1.x.x" +serde = "1.x.x" +rusty-leveldb = "3.x.x" +miniz_oxide = "0.x.x" +vek = "0.17" + +[dev-dependencies] +rand = "0.8" + +[profile.release] +debug = true + +[[test]] +name = "api_test" +required-features = ["default-impl"] + +[features] +default-impl = [] diff --git a/crates/level/src/level/chunk.rs b/crates/level/src/level/chunk.rs new file mode 100644 index 00000000..110cb9e4 --- /dev/null +++ b/crates/level/src/level/chunk.rs @@ -0,0 +1,536 @@ +use crate::level::level::LevelModificationProvider; +use crate::level::sub_chunk::SubChunkTrait; +use crate::level::world_block::WorldBlockTrait; +use bedrockrs_shared::world::dimension::Dimension; +use std::fmt::Debug; +use thiserror::Error; +use vek::{Vec2, Vec3}; + +/// Specifies the type of filter used when filling a region in the world. +/// +/// # Type Parameters +/// - `UserBlockType`: A block type that implements the `WorldBlockTrait`. +pub enum FillFilter { + /// Fills the entire region unconditionally, overwriting all blocks. + Blanket, + + /// Replaces only the blocks that match the specified type. + /// + /// # Parameters + /// - `UserBlockType`: The block type to be replaced. + Replace(UserBlockType), + + /// Avoids overwriting blocks that match the specified type. + /// + /// # Parameters + /// - `UserBlockType`: The block type to avoid. + Avoid(UserBlockType), + + /// Uses a custom precedence function to determine whether a block should be replaced. + /// + /// # Parameters + /// - A boxed function with the following parameters: + /// - `&UserBlockType`: The current block being evaluated. + /// - `Vec3`: The local coordinates of the block within the chunk. + /// - `Vec2`: The world-space XZ coordinates of the chunk. + /// - `i8`: The subchunk y. + /// + /// # Returns + /// - `bool`: `true` to allow replacing the block, `false` to skip it. + Precedence(Box, Vec2, i8) -> bool>), +} + +#[derive(Error, Debug)] +pub enum FillError { + #[error("Attempted to fill Subchunk {0} and got none back")] + MissingSubchunk(i8), + #[error("Attempted to read block at x: {0}, y {1}, z: {2} and got None")] + BlockIndexDidntReturn(u8, u8, u8), +} + +pub trait LevelChunkTrait: Sized +where + >::UserSubchunk: SubChunkTrait, + >::UserBlock: WorldBlockTrait, + ::UserSubChunkType: SubChunkTrait, + <>::UserSubchunk as SubChunkTrait>::BlockType: + WorldBlockTrait, +{ + type UserLevel; // = UserLevel; + type UserBlock; // = UserLevel::UserBlockType; + type UserSubchunk; // = UserLevel::UserSubChunkType; + type UserState; // = UserLevel::UserState; + type Err; + + /// Loads the chunk from the world based on the specified min and max subchunk indices, + /// XZ coordinates, and dimension. + /// + /// # Parameters + /// - `min_max`: Minimum and maximum subchunk indices. + /// - `xz`: The XZ coordinate of the chunk in the world. + /// - `dim`: The dimension where the chunk resides. + /// - `level`: The level data to load the chunk into. + /// + /// # Returns + /// - `Ok(Self)`: The loaded chunk. + /// - `Err(Self::Err)`: An error occurred during loading. + fn load_from_world( + min_max: Vec2, + xz: Vec2, + dim: Dimension, + level: &mut Self::UserLevel, + ) -> Result; + + /// Writes the chunk back into the world, optionally overriding its position and dimension. + /// + /// # Parameters + /// - `level`: The level data where the chunk will be written. + /// - `xz_override`: Optional override for the chunk's XZ coordinates. + /// - `dim_override`: Optional override for the chunk's dimension. + /// + /// # Returns + /// - `Ok(())`: Successfully written to the world. + /// - `Err(Self::Err)`: An error occurred during writing. + fn write_to_world( + self, + level: &mut Self::UserLevel, + xz_override: Option>, + dim_override: Option, + ) -> Result<(), Self::Err>; + + /// Retrieves a mutable reference to the block at the specified XZ and Y coordinates within the chunk. + /// + /// # Parameters + /// - `xz`: The XZ coordinate of the block within the chunk. + /// - `y`: The Y coordinate of the block. + /// + /// # Returns + /// - `Some(&mut Self::UserBlock)`: A mutable reference to the block if it exists. + /// - `None`: No block exists at the specified coordinates. + fn get_block_at_mut(&mut self, xz: Vec2, y: i16) -> Option<&mut Self::UserBlock>; + + /// Retrieves an immutable reference to the block at the specified XZ and Y coordinates within the chunk. + /// + /// # Parameters + /// - `xz`: The XZ coordinate of the block within the chunk. + /// - `y`: The Y coordinate of the block. + /// + /// # Returns + /// - `Some(&Self::UserBlock)`: An immutable reference to the block if it exists. + /// - `None`: No block exists at the specified coordinates. + fn get_block_at(&self, xz: Vec2, y: i16) -> Option<&Self::UserBlock>; + + /// Sets the block at the specified XZ and Y coordinates within the chunk. + /// + /// # Parameters + /// - `block`: The block to set. + /// - `xz`: The XZ coordinate of the block within the chunk. + /// - `y`: The Y coordinate of the block. + /// + /// # Returns + /// - `Ok(())`: Successfully set the block. + /// - `Err(Self::UserSubchunk::Err)`: An error occurred while setting the block. + fn set_block_at( + &mut self, + block: Self::UserBlock, + xz: Vec2, + y: i16, + ) -> Result<(), ::Err>; + + /// Returns the minimum and maximum subchunk indices for this chunk. + /// + /// # Returns + /// - `Vec2`: A vector containing the minimum and maximum subchunk indices. + fn min_max(&self) -> Vec2; + + /// Retrieves an immutable reference to the subchunk at the specified Y index. + /// + /// # Parameters + /// - `y`: The Y index of the subchunk. + /// + /// # Returns + /// - `Some(&Self::UserSubchunk)`: An immutable reference to the subchunk if it exists. + /// - `None`: No subchunk exists at the specified index. + fn get_subchunk(&self, y: i8) -> Option<&Self::UserSubchunk>; + + /// Retrieves a mutable reference to the subchunk at the specified Y index. + /// + /// # Parameters + /// - `y`: The Y index of the subchunk. + /// + /// # Returns + /// - `Some(&mut Self::UserSubchunk)`: A mutable reference to the subchunk if it exists. + /// - `None`: No subchunk exists at the specified index. + fn get_subchunk_mut(&mut self, y: i8) -> Option<&mut Self::UserSubchunk>; + + /// Gets the position of the chunk in world space as XZ coordinates. + /// + /// # Returns + /// - `Vec2`: The chunk's position in world space. + fn pos(&self) -> Vec2; +} + +#[cfg(feature = "default-impl")] +pub mod default_impl { + use super::*; + use crate::level::file_interface::RawWorldTrait; + use crate::level::level::LevelError; + use crate::level::sub_chunk::{SubChunkDecoder, SubChunkTrait}; + use crate::level::world_block::WorldBlockTrait; + use std::marker::PhantomData; + use std::mem::MaybeUninit; + use std::ops::{Deref, DerefMut}; + use std::slice::{Iter, IterMut}; + use std::vec::Vec; + + #[allow(dead_code)] + pub struct LevelChunk< + UserState, + UserSubChunkType, + UserLevelInterface: LevelModificationProvider, + > { + bounds: Vec2, + xz: Vec2, + dim: Dimension, + sections: Vec, + phantom_data: PhantomData, + _phantom_data: PhantomData, + } + + impl Deref + for LevelChunk + { + type Target = Vec; + fn deref(&self) -> &Self::Target { + &self.sections + } + } + + impl DerefMut + for LevelChunk + { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.sections + } + } + + impl< + UserState, + UserBlockType: WorldBlockTrait, + UserSubChunkType: SubChunkTrait, + UserLevelInterface: LevelModificationProvider, + > LevelChunk + { + // This function computes the true index of a subchunk in the section array. + // E.g., with a bounds of -4 to 20 subchunks in size if a raw_index of -4 is passed in it will perform + // -4 + 4 equaling 0 meaning the true index of a subchunk at y -4 is 0; this logic extends to any y level + // y 2 would do 2 + 4 meaning the true index of a subchunk at y 2 is 6 + fn true_index(min_max: Vec2, raw_index: i8) -> i8 { + #[cfg(debug_assertions)] + if raw_index < min_max.x || raw_index > min_max.y { + panic!("Y out of bounds"); + } + raw_index + min_max.x.abs() + } + + // The need for this function comes from the fact that when subchunks are in -y the y index is inverted. + // This means that 20 -9 20 is near the bottom of the subchunk were as 20 9 20 is near the top of the subchunk (this is assuming we are using world space coords). + // The Y can be thought more of as an offset from the base. + // The base in this context is 0 if the subchunk is positive y and 16 if the subchunk is negative + fn real_y(raw: i8) -> i8 { + if raw >= 0 { + raw + } else { + 16 + raw + // This looks a little confusing so ill explain. + // raw is a negative number, meaning 16 + raw is basically 16 - abs(raw) + } + } + + /// Returns an iterator over all subchunks in this chunk, ordered from low to high. + /// + /// # Returns + /// - `Iter<'_, UserSubChunkType>`: An iterator over the subchunks. + pub fn iter(&self) -> Iter<'_, UserSubChunkType> { + self.sections.iter() + } + + /// Returns a mutable iterator over all subchunks in this chunk, ordered from low to high. + /// + /// # Returns + /// - `IterMut<'_, UserSubChunkType>`: A mutable iterator over the subchunks. + pub fn iter_mut(&mut self) -> IterMut<'_, UserSubChunkType> { + self.sections.iter_mut() + } + + /// Fetches an immutable reference to the subchunk at the specified Y level. + /// + /// # Parameters + /// - `idx`: The Y level of the desired subchunk. + /// + /// # Returns + /// - `Some(&UserSubChunkType)`: An immutable reference to the subchunk if it exists. + /// - `None`: No subchunk exists at the given Y level. + pub fn get_subchunk(&self, idx: i8) -> Option<&UserSubChunkType> { + self.sections + .get(Self::true_index(self.bounds, idx) as usize) + } + + /// Fetches a mutable reference to the subchunk at the specified Y level. + /// + /// # Parameters + /// - `idx`: The Y level of the desired subchunk. + /// + /// # Returns + /// - `Some(&mut UserSubChunkType)`: A mutable reference to the subchunk if it exists. + /// - `None`: No subchunk exists at the given Y level. + pub fn get_subchunk_mut(&mut self, idx: i8) -> Option<&mut UserSubChunkType> { + self.sections + .get_mut(Self::true_index(self.bounds, idx) as usize) + } + + /// Sets the subchunk at the specified Y level. + /// + /// # Parameters + /// - `y`: The Y level where the subchunk will be set. + /// - `chnk`: The subchunk to set at the specified Y level. + pub fn set_subchunk(&mut self, y: i8, mut chnk: UserSubChunkType) { + chnk.set_y(y); + self[Self::real_y(y) as usize] = chnk; + } + + /// Creates a new chunk filled with empty subchunks. + /// + /// # Parameters + /// - `xz`: The XZ coordinates of the chunk in world space. + /// - `min_max`: The minimum and maximum subchunk indices. + /// - `dim`: The dimension where the chunk resides. + /// - `state`: The state object used to create empty subchunks. + /// + /// # Returns + /// - `Self`: A new chunk with empty subchunks. + pub fn empty( + xz: Vec2, + min_max: Vec2, + dim: Dimension, + state: &mut UserState, + ) -> Self { + let ret_subchunks = (min_max.x..min_max.y) + .map(|y| UserSubChunkType::empty(y, state)) + .collect::>(); + Self { + xz, + bounds: min_max, + sections: ret_subchunks, + dim, + phantom_data: PhantomData, + _phantom_data: PhantomData, + } + } + } + + impl< + UserState, + UserBlockType: WorldBlockTrait, + UserSubChunkType: SubChunkTrait, + UserLevelInterface: LevelModificationProvider< + UserBlockType = UserBlockType, + UserState = UserState, + UserSubChunkType = UserSubChunkType, + Error = LevelError<<::UserWorldInterface as RawWorldTrait>::Err, + <::UserSubChunkDecoder as SubChunkDecoder>::Err, + ::Err,>, + >, + > LevelChunk + where + ::UserWorldInterface: RawWorldTrait, + ::UserSubChunkDecoder: SubChunkDecoder, + ::UserBlockType: WorldBlockTrait, + ::Err: Debug, + <::UserWorldInterface as RawWorldTrait>::Err: Debug, + <::UserSubChunkDecoder as SubChunkDecoder>::Err: Debug, + { + /// Fills the entire chunk with the specified block, applying the given `FillFilter`. + /// + /// # Parameters + /// - `block`: The block to fill the chunk with. + /// - `filter`: The filter defining the conditions for filling blocks. + /// + /// # Returns + /// - `Ok(&mut Self)`: Successfully filled the chunk. + /// - `Err(FillError)`: An error occurred, such as a missing subchunk or invalid block index. + /// + /// # Errors + /// - `FillError::MissingSubchunk(y_level)`: Subchunk at the specified Y level is missing. + /// - `FillError::BlockIndexDidntReturn(x, y, z)`: Block index is invalid or did not return a block. + /// + /// # Behavior + /// Iterates through all blocks in all subchunks, applying the `FillFilter`: + /// - `Blanket`: Fills all blocks unconditionally. + /// - `Replace(mask)`: Replaces only blocks matching the given mask. + /// - `Avoid(mask)`: Fills blocks that do not match the mask. + /// - `Precedence(func)`: Uses a custom function to determine if a block should be replaced. + + pub fn fill_chunk(&mut self, block: UserBlockType, filter: FillFilter) -> Result<&mut Self, FillError> { + let pos = self.pos(); + for y_level in self.bounds.x..self.bounds.y { + let subchunk = self.get_subchunk_mut(y_level) + .ok_or(FillError::MissingSubchunk(y_level))?; + for z in 0..16u8 { + for y in 0..16u8 { + for x in 0..16u8 { + let blk = subchunk + .get_block((x, y, z).into()) + .ok_or(FillError::BlockIndexDidntReturn(x, y, z))?; + if match &filter { + FillFilter::Blanket => true, + FillFilter::Replace(mask) => + mask == blk, + FillFilter::Avoid(mask) => mask != blk, + FillFilter::Precedence(func) => { + func(blk, (x, y, z).into(), pos, subchunk.get_y()) + } + } { + subchunk.set_block((x, y, z).into(), block.clone()).unwrap() + } + } + } + } + } + Ok(self) + } + } + impl< + UserState, + UserBlockType: WorldBlockTrait, + UserSubChunkType: SubChunkTrait, + UserLevelInterface: LevelModificationProvider< + UserBlockType = UserBlockType, + UserState = UserState, + UserSubChunkType = UserSubChunkType, + Error = LevelError<<::UserWorldInterface as RawWorldTrait>::Err, + <::UserSubChunkDecoder as SubChunkDecoder>::Err, + ::Err,>, + >, + > LevelChunkTrait for LevelChunk + where + ::UserWorldInterface: RawWorldTrait, + ::UserSubChunkDecoder: SubChunkDecoder, + ::UserBlockType: WorldBlockTrait, + ::Err: Debug, + <::UserWorldInterface as RawWorldTrait>::Err: Debug, + <::UserSubChunkDecoder as SubChunkDecoder>::Err: Debug, + { + type UserLevel = UserLevelInterface; + type UserBlock = UserBlockType; + type UserSubchunk = UserSubChunkType; + type UserState = UserState; + type Err = LevelError< + ::Err, + ::Err, + ::Err, + >; + + fn load_from_world( + min_max: Vec2, + xz: Vec2, + dim: Dimension, + level: &mut Self::UserLevel, + ) -> Result { + let mut subchunk_list: Vec> = (min_max.x..min_max.y) + .map(|_| MaybeUninit::uninit() ) + .collect(); + for y in min_max.x..min_max.y { + let subchunk = level.get_sub_chunk(xz, y, dim); + match subchunk { + Ok(subchunk) => { + let idx = Self::true_index(min_max, y) as usize; + subchunk_list[idx].write(subchunk); + } + Err(err) => { + for r in min_max.x..y { + // Safety: We are only dropping subchunks which came before this one meaning they have to be init + unsafe { + subchunk_list[Self::true_index(min_max, r) as usize] + .assume_init_drop(); + } + } + return Err(err); + } + } + } + // Safety: Since `MaybeUninit` is a ZST the ABI of the two types is the same + Ok(Self { + bounds: min_max, + xz, + dim, + sections: unsafe { std::mem::transmute(subchunk_list) }, + phantom_data: PhantomData, + _phantom_data: PhantomData + }) + } + + fn write_to_world( + self, + level: &mut Self::UserLevel, + xz_override: Option>, + dim_override: Option, + ) -> Result<(), Self::Err> { + for sub_chnk in self.sections { + level.set_subchunk( + xz_override.unwrap_or(self.xz), + sub_chnk.get_y(), + dim_override.unwrap_or(self.dim), + sub_chnk, + )?; + } + Ok(()) + } + + fn get_block_at_mut(&mut self, xz: Vec2, y: i16) -> Option<&mut Self::UserBlock> { + self.sections + .get_mut(Self::true_index(self.bounds, (y / 16) as i8) as usize)? + .get_block_mut((xz.x, Self::real_y((y / 16) as i8) as u8, xz.y).into()) + } + + fn get_block_at(&self, xz: Vec2, y: i16) -> Option<&Self::UserBlock> { + self.sections + .get(Self::true_index(self.bounds, (y / 16) as i8) as usize)? + .get_block((xz.x, Self::real_y((y / 16) as i8) as u8, xz.y).into()) + } + + fn set_block_at( + &mut self, + block: Self::UserBlock, + xz: Vec2, + y: i16, + ) -> Result<(), ::Err> { + self.sections + .get_mut(Self::true_index(self.bounds, (y / 16) as i8) as usize) + .unwrap() /*TODO: Figure out a way to report this error back to the user*/ + .set_block( + (xz.x, Self::real_y((y / 16) as i8) as u8, xz.y).into(), + block, + ) + } + + fn min_max(&self) -> Vec2 { + self.bounds + } + + fn get_subchunk(&self, y: i8) -> Option<&Self::UserSubchunk> { + self.sections.get(Self::true_index(self.bounds, y) as usize) + } + + fn get_subchunk_mut(&mut self, y: i8) -> Option<&mut Self::UserSubchunk> { + self.sections + .get_mut(Self::true_index(self.bounds, y) as usize) + } + + fn pos(&self) -> Vec2 { + self.xz + } + + + } +} diff --git a/crates/level/src/level/chunk_cache.rs b/crates/level/src/level/chunk_cache.rs new file mode 100644 index 00000000..c341cd0f --- /dev/null +++ b/crates/level/src/level/chunk_cache.rs @@ -0,0 +1,27 @@ +use bedrockrs_shared::world::dimension::Dimension; +use vek::Vec2; + +#[derive(Debug, PartialEq, Hash, Eq, Clone)] +pub struct SubchunkCacheKey { + pub xz: Vec2, + pub y: i8, + pub dim: Dimension, +} + +#[derive(Debug, PartialEq, Hash, Eq, Clone)] +pub struct ChunkCacheKey { + xz: Vec2, + sequence_id: usize, +} + +impl SubchunkCacheKey { + pub fn new(xz: Vec2, y: i8, dim: Dimension) -> Self { + Self { xz, y, dim } + } +} + +impl ChunkCacheKey { + pub fn new(xz: Vec2, sequence_id: usize) -> Self { + Self { xz, sequence_id } + } +} diff --git a/crates/level/src/level/db_interface/bedrock_key.rs b/crates/level/src/level/db_interface/bedrock_key.rs new file mode 100644 index 00000000..c7afcea3 --- /dev/null +++ b/crates/level/src/level/db_interface/bedrock_key.rs @@ -0,0 +1,77 @@ +use crate::level::db_interface::db::LevelDBKey; +use crate::level::db_interface::key_level::KeyTypeTag; +use bedrockrs_shared::world::dimension::Dimension; +use byteorder::{LittleEndian, WriteBytesExt}; +use std::io::Cursor; +use vek::Vec2; + +#[derive(Debug)] +pub struct ChunkKey { + xz: Vec2, + dim: Dimension, + key_type: KeyTypeTag, + y_index: Option, +} + +impl ChunkKey { + pub fn new_subchunk(xz: Vec2, dim: Dimension, y_index: i8) -> Self { + Self { + xz, + dim, + key_type: KeyTypeTag::SubChunkPrefix, + y_index: Some(y_index), + } + } + + pub fn chunk_marker(xz: Vec2, dim: Dimension) -> Self { + Self { + xz, + dim, + key_type: KeyTypeTag::Version, + y_index: None, + } + } + + pub fn data3d(xz: Vec2, dim: Dimension) -> Self { + Self { + xz, + dim, + key_type: KeyTypeTag::Data3D, + y_index: None, + } + } +} + +impl LevelDBKey for ChunkKey { + fn estimate_size(&self) -> usize { + let mut size = std::mem::size_of::>(); + if self.dim != Dimension::Overworld { + size += std::mem::size_of::(); + } + size += 1; // For the key_type + if let Some(_) = self.y_index { + size += 1; + } + size + } + + fn write_key(&self, buffer: &mut Cursor<&mut [u8]>) { + buffer + .write_i32::(self.xz.x) + .expect("This should never fail"); + buffer + .write_i32::(self.xz.y) + .expect("This should never fail"); + if self.dim != Dimension::Overworld { + buffer + .write_i32::(self.dim as i32) + .expect("This should never fail"); + } + buffer + .write_u8(self.key_type.to_byte()) + .expect("This should never fail"); + if let Some(val) = self.y_index { + buffer.write_i8(val).expect("This should never fail"); + } + } +} diff --git a/crates/level/src/level/db_interface/db.rs b/crates/level/src/level/db_interface/db.rs new file mode 100644 index 00000000..17de799a --- /dev/null +++ b/crates/level/src/level/db_interface/db.rs @@ -0,0 +1,6 @@ +use std::io::Cursor; + +pub trait LevelDBKey { + fn estimate_size(&self) -> usize; + fn write_key(&self, buffer: &mut Cursor<&mut [u8]>); +} diff --git a/crates/level/src/level/db_interface/key_level.rs b/crates/level/src/level/db_interface/key_level.rs new file mode 100644 index 00000000..9c2d44a0 --- /dev/null +++ b/crates/level/src/level/db_interface/key_level.rs @@ -0,0 +1,91 @@ +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub enum KeyTypeTag { + Data3D = 43, // 2B "+" Heightmap (256x2 bytes) + Version = 44, // 2C "," 1 byte version + Data2D = 45, // 2D "-" Heightmap (256x2 bytes) + + Data2DLegacy = 46, // 2E "." Heightmap (256x2 bytes) + // 2D biomes (256x4 bytes) + // Each entry of the biome array contains a biome ID in the first byte, and the final 3 bytes are red/green/blue respectively. No longer written since v1.0.0. + SubChunkPrefix = 47, // 2F "/" Subchunk version (1 byte), version-dependent data + // Terrain for a 16×16×16 subchunk + LegacyTerrain = 48, // 30 "0" Block IDs (32768 bytes) + // Block meta (32768 nibbles) + // Block sky light (32768 nibbles) + // Block light (32768 nibbles) + // Heightmap (256x1 bytes) + // 2D biomes (256x4 bytes) + // Data ordered in XZY order, unlike Java. + // No longer written since v1.0.0. + // Biomes are IDs plus RGB colours similar to Data2DLegacy. + BlockEntity = 49, // 31 "1" List of NBT compound roots + // Block entity data (little-endian NBT) + Entity = 50, // 32 "2" List of NBT compound roots + // Entity data (little-endian NBT) + PendingTicks = 51, // 33 "3" List of NBT compound roots + // Pending tick data (little-endian NBT) + LegacyBlockExtraData = 52, // 34 "4" Entry count (4 bytes) + // Entries: Key (4 bytes), Value (2 bytes). + // Array of blocks that appear in the same place as other blocks. + // Used for grass appearing inside snow layers prior to v1.2.13. + // No longer written as of v1.2.13. + BiomeState = 53, // 35 "5" Biome palette with 25 entries. Biome IDs written as integers. + + FinalizedState = 54, // 36 "6" 4 bytes (32-bit little endian integer) + + ConversionData = 55, // 37 "7" No longer used + + BorderBlocks = 56, // 38 "8" Education Edition feature + + HardcodedSpawners = 57, // 39 "9" Bounding boxes for structure spawns stored in binary format + + RandomTicks = 58, // 3A ":" List of NBT compound roots + // Random tick data (little-endian NBT) + Checksums = 59, // 3B ";" xxHash checksums of other chunk records. No longer written as of v1.18.0. + + MetaDataHash = 61, // 3D "=" Metadata hash + + GeneratedPreCavesAndCliffsBlending = 62, // 3E ">" Not used + + BlendingBiomeHeight = 63, // 3F "?" Not used + + BlendingData = 64, // 40 "@" Blending data + + ActorDigestVersion = 65, // 41 "A" Actor digest version + + LegacyVersion = 118, // 76 "v" 1 byte; moved to Version in v1.16.100 +} + +impl KeyTypeTag { + pub fn from_byte(byte: u8) -> Option { + match byte { + 43 => Some(KeyTypeTag::Data3D), + 44 => Some(KeyTypeTag::Version), + 45 => Some(KeyTypeTag::Data2D), + 46 => Some(KeyTypeTag::Data2DLegacy), + 47 => Some(KeyTypeTag::SubChunkPrefix), + 48 => Some(KeyTypeTag::LegacyTerrain), + 49 => Some(KeyTypeTag::BlockEntity), + 50 => Some(KeyTypeTag::Entity), + 51 => Some(KeyTypeTag::PendingTicks), + 52 => Some(KeyTypeTag::LegacyBlockExtraData), + 53 => Some(KeyTypeTag::BiomeState), + 54 => Some(KeyTypeTag::FinalizedState), + 55 => Some(KeyTypeTag::ConversionData), + 56 => Some(KeyTypeTag::BorderBlocks), + 57 => Some(KeyTypeTag::HardcodedSpawners), + 58 => Some(KeyTypeTag::RandomTicks), + 59 => Some(KeyTypeTag::Checksums), + 61 => Some(KeyTypeTag::MetaDataHash), + 62 => Some(KeyTypeTag::GeneratedPreCavesAndCliffsBlending), + 63 => Some(KeyTypeTag::BlendingBiomeHeight), + 64 => Some(KeyTypeTag::BlendingData), + 65 => Some(KeyTypeTag::ActorDigestVersion), + 118 => Some(KeyTypeTag::LegacyVersion), + _ => None, + } + } + pub fn to_byte(&self) -> u8 { + *self as u8 + } +} diff --git a/crates/level/src/level/db_interface/mod.rs b/crates/level/src/level/db_interface/mod.rs new file mode 100644 index 00000000..cd74e340 --- /dev/null +++ b/crates/level/src/level/db_interface/mod.rs @@ -0,0 +1,4 @@ +pub mod bedrock_key; +pub mod db; +pub mod key_level; +pub mod rusty; diff --git a/crates/level/src/level/db_interface/rusty.rs b/crates/level/src/level/db_interface/rusty.rs new file mode 100644 index 00000000..4ee00137 --- /dev/null +++ b/crates/level/src/level/db_interface/rusty.rs @@ -0,0 +1,258 @@ +use crate::level::db_interface::bedrock_key::ChunkKey; +use crate::level::db_interface::db::LevelDBKey; +use crate::level::db_interface::key_level::KeyTypeTag; +use crate::level::file_interface::RawWorldTrait; +use bedrockrs_shared::world::dimension::Dimension; +use byteorder::{LittleEndian, ReadBytesExt}; +use miniz_oxide::deflate::{compress_to_vec, compress_to_vec_zlib, CompressionLevel}; +use miniz_oxide::inflate::{decompress_to_vec, decompress_to_vec_zlib}; +use rusty_leveldb::compressor::NoneCompressor; +use rusty_leveldb::{Compressor, CompressorList, LdbIterator, Options, Status, WriteBatch, DB}; +use std::collections::HashSet; +use std::io::Cursor; +use std::marker::PhantomData; +use std::path::Path; +use std::rc::Rc; +use thiserror::Error; +use vek::Vec2; + +struct ZlibCompressor(u8); + +impl ZlibCompressor { + pub fn new(level: u8) -> Self { + assert!(level <= 10); + Self(level) + } +} + +impl Compressor for ZlibCompressor { + fn encode(&self, block: Vec) -> rusty_leveldb::Result> { + Ok(compress_to_vec_zlib(&block, self.0)) + } + + fn decode(&self, block: Vec) -> rusty_leveldb::Result> { + decompress_to_vec_zlib(&block).map_err(|e| rusty_leveldb::Status { + code: rusty_leveldb::StatusCode::CompressionError, + err: e.to_string(), + }) + } +} + +struct RawZlibCompressor(u8); + +impl RawZlibCompressor { + pub fn new(level: u8) -> Self { + assert!(level <= 10); + Self(level) + } +} +impl Compressor for RawZlibCompressor { + fn encode(&self, block: Vec) -> rusty_leveldb::Result> { + Ok(compress_to_vec(&block, self.0)) + } + + fn decode(&self, block: Vec) -> rusty_leveldb::Result> { + decompress_to_vec(&block).map_err(|e| rusty_leveldb::Status { + code: rusty_leveldb::StatusCode::CompressionError, + err: e.to_string(), + }) + } +} + +pub fn mcpe_options(compression_level: u8) -> Options { + let mut opt = Options::default(); + let mut list = CompressorList::new(); + list.set_with_id(0, NoneCompressor {}); + list.set_with_id(2, ZlibCompressor::new(compression_level)); + list.set_with_id(4, RawZlibCompressor::new(compression_level)); + opt.compressor_list = Rc::new(list); + opt.compressor = 4; + opt +} +const COMPRESSION_LEVEL: u8 = CompressionLevel::DefaultLevel as u8; + +pub struct RustyDBInterface { + db: DB, + phantom_data: PhantomData, +} + +#[derive(Debug, Error)] +pub enum DBError { + #[error("Rusty DB: {0}")] + DatabaseError(#[from] Status), +} + +impl RustyDBInterface { + fn build_key_batch(subchunk_batch_info: Vec, data: &mut Vec) -> WriteBatch { + let count = subchunk_batch_info + .iter() + .map(|ele| ele.estimate_size()) + .sum(); + data.resize(count, 0); + + let mut buff: Cursor<&mut [u8]> = Cursor::new(data); + + let mut batch = WriteBatch::default(); + + for key in subchunk_batch_info { + let start = buff.position(); + + key.write_key(&mut buff); + + let end = buff.position(); + + let whole = buff.get_ref(); + + batch.put(&whole[start as usize..end as usize], &[]); + } + batch + } + + pub fn get_key(&mut self, chunk_info: ChunkKey) -> Option> { + self.db.get(&Self::build_key(&chunk_info)) + } +} + +impl RawWorldTrait for RustyDBInterface { + type Err = DBError; + type UserState = UserState; + + fn set_subchunk_raw( + &mut self, + chunk_info: ChunkKey, + chunk_bytes: &[u8], + _: &mut Self::UserState, + ) -> Result<(), Self::Err> { + let mut batch = WriteBatch::default(); + batch.put(&Self::build_key(&chunk_info), chunk_bytes); + Ok(self.db.write(batch, false)?) + } + + fn get_subchunk_raw( + &mut self, + chunk_info: ChunkKey, + _: &mut Self::UserState, + ) -> Result>, Self::Err> { + Ok(self.db.get(&Self::build_key(&chunk_info))) + } + + fn chunk_exists( + &mut self, + chunk_info: ChunkKey, + _: &mut Self::UserState, + ) -> Result { + Ok(self.db.get(&Self::build_key(&chunk_info)).is_some()) + } + + fn write_subchunk_batch( + &mut self, + subchunk_batch_info: Vec<(ChunkKey, Vec)>, + _: &mut Self::UserState, + ) -> Result<(), Self::Err> { + let mut data: Vec = vec![ + 0; + subchunk_batch_info + .iter() + .map(|(info, _)| info.estimate_size()) + .sum() + ]; + let mut buff: Cursor<&mut [u8]> = Cursor::new(&mut data); + let mut batch = WriteBatch::default(); + for (key, _) in &subchunk_batch_info { + let start = buff.position(); + + key.write_key(&mut buff); + + let end = buff.position(); + + let whole = buff.get_ref(); + + batch.put(&whole[start as usize..end as usize], &[]); + } + Ok(self.db.write(batch, false)?) + } + + fn write_subchunk_marker_batch( + &mut self, + subchunk_batch_info: Vec, + _: &mut Self::UserState, + ) -> Result<(), Self::Err> { + let mut data: Vec = Vec::new(); + let batch = Self::build_key_batch(subchunk_batch_info, &mut data); + Ok(self.db.write(batch, false)?) + } + + fn exist_chunk( + &mut self, + chunk_info: ChunkKey, + state: &mut Self::UserState, + ) -> Result<(), Self::Err> { + Ok(self.set_subchunk_raw(chunk_info, &[], state)?) + } + + fn build_key(key: &ChunkKey) -> Vec { + let mut key_bytes: Vec = vec![0; key.estimate_size()]; + let mut buff: Cursor<&mut [u8]> = Cursor::new(&mut key_bytes); + key.write_key(&mut buff); + key_bytes + } + + fn new( + path: Box, + create_if_missing: bool, + _: &mut Self::UserState, + ) -> Result { + let mut opts = mcpe_options(COMPRESSION_LEVEL); + opts.create_if_missing = create_if_missing; + let db = DB::open(path, opts)?; + Ok(Self { + db, + phantom_data: PhantomData, + }) + } + + fn generated_chunks( + &mut self, + _: &mut Self::UserState, + ) -> Result)>, Self::Err> { + let mut out_set = HashSet::new(); + + let mut iter = self.db.new_iter()?; + + loop { + let mut key = Vec::new(); + let data = &mut Vec::new(); + + iter.current(&mut key, data); + let len = key.len(); + let mut cursor = Cursor::new(&mut key); + + if len == 9 || len == 13 { + // Does a little hack to make sure it isn't reading a key that it doesn't want to + if cursor.get_ref().get(len - 1) == Some(&KeyTypeTag::Version.to_byte()) { + let x = cursor + .read_i32::() + .expect("This should never fail"); + + let y = cursor + .read_i32::() + .expect("This should never fail"); + + let dim = if len == 13 { + cursor + .read_i32::() + .expect("This should never fail") + .into() + } else { + Dimension::Overworld + }; + out_set.insert((dim, (x, y).into())); + } + } + if !iter.advance() { + break; + } + } + Ok(out_set) + } +} diff --git a/crates/level/src/level/file_interface.rs b/crates/level/src/level/file_interface.rs new file mode 100644 index 00000000..376e919c --- /dev/null +++ b/crates/level/src/level/file_interface.rs @@ -0,0 +1,86 @@ +use crate::level::db_interface::bedrock_key::ChunkKey; +use bedrockrs_shared::world::dimension::Dimension; +use std::collections::HashSet; +use std::ops::Range; +use std::path::Path; +use vek::Vec2; + +pub struct DatabaseBatchHolder { + collective: Vec, + key_range: Range, + data_range: Range, +} + +impl DatabaseBatchHolder { + pub fn new(collective: Vec, key_range: Range, data_range: Range) -> Self { + Self { + collective, + key_range, + data_range, + } + } + + pub fn key(&self) -> &[u8] { + &self.collective[self.key_range.clone()] + } + + pub fn data(&self) -> &[u8] { + &self.collective[self.data_range.clone()] + } +} + +pub trait RawWorldTrait: Sized { + type Err; + + type UserState; + + fn set_subchunk_raw( + &mut self, + chunk_info: ChunkKey, + chunk_bytes: &[u8], + state: &mut Self::UserState, + ) -> Result<(), Self::Err>; + + fn get_subchunk_raw( + &mut self, + chunk_info: ChunkKey, + state: &mut Self::UserState, + ) -> Result>, Self::Err>; + + fn chunk_exists( + &mut self, + chunk_info: ChunkKey, + state: &mut Self::UserState, + ) -> Result; + + fn write_subchunk_batch( + &mut self, + subchunk_batch_info: Vec<(ChunkKey, Vec)>, + state: &mut Self::UserState, + ) -> Result<(), Self::Err>; + + fn write_subchunk_marker_batch( + &mut self, + subchunk_batch_info: Vec, + state: &mut Self::UserState, + ) -> Result<(), Self::Err>; + + fn exist_chunk( + &mut self, + chunk_info: ChunkKey, + state: &mut Self::UserState, + ) -> Result<(), Self::Err>; + + fn build_key(key: &ChunkKey) -> Vec; + + fn new( + path: Box, + create_if_missing: bool, + state: &mut Self::UserState, + ) -> Result; + + fn generated_chunks( + &mut self, + state: &mut Self::UserState, + ) -> Result)>, Self::Err>; +} diff --git a/crates/level/src/level/level.rs b/crates/level/src/level/level.rs new file mode 100644 index 00000000..dfab8791 --- /dev/null +++ b/crates/level/src/level/level.rs @@ -0,0 +1,492 @@ +use crate::level::chunk::LevelChunkTrait; +use crate::level::chunk_cache::SubchunkCacheKey; +use crate::level::db_interface::bedrock_key::ChunkKey; +use crate::level::file_interface::RawWorldTrait; +use crate::level::sub_chunk::{SubChunkDecoder, SubChunkTrait}; +use crate::level::world_block::WorldBlockTrait; +use crate::level_try; +use crate::types::clear_cache::ClearCacheContainer; +use bedrockrs_shared::world::dimension::Dimension; +use std::collections::hash_set::Iter; +use std::collections::HashSet; +use std::fmt::Debug; +use std::io::Cursor; +use std::marker::PhantomData; +use std::path::Path; +use thiserror::Error; +use vek::Vec2; + +/// This is used when filtering chunks. +/// `ChunkSelectionFilter::Dimension` is used to just check if the dimension is the same. +/// `ChunkSelectionFilter::Filter` is used to perform more complex logic on the chunk to detect if it should be included +pub enum ChunkSelectionFilter { + Dimension(Dimension), + Filter(Box) -> bool>), +} + +/// This is used when filtering subchunks. +/// +/// `SubchunkSelectionFilter::Dimension` is used to just check if the dimension is the same. +/// +/// `SubchunkSelectionFilter::Filter` +/// is used to perform more complex logic on the chunk to detect if it should be included +pub enum SubchunkSelectionFilter { + Dimension(Dimension), + Filter(Box) -> bool>), +} + +impl ChunkSelectionFilter { + pub fn poll(&mut self, chunk_dim: Dimension, pos: Vec2) -> bool { + match self { + ChunkSelectionFilter::Dimension(dim) => dim == &chunk_dim, + ChunkSelectionFilter::Filter(func) => func(chunk_dim, pos), + } + } +} + +#[derive(Error, Debug)] +pub enum LevelError { + #[error(transparent)] + DatabaseError(DataBaseError), + #[error(transparent)] + SubChunkDecodeError(SubChunkDecodeError), + #[error(transparent)] + SubChunkError(SubChunkError), +} + +pub struct ClosedLevel; + +#[allow(dead_code)] +pub struct Level< + UserState, + UserWorldInterface: RawWorldTrait, + UserBlockType: WorldBlockTrait, + UserSubChunkType: SubChunkTrait, + UserSubChunkDecoder: SubChunkDecoder, +> { + db: UserWorldInterface, + state: UserState, + rw_cache: bool, + cached_sub_chunks: ClearCacheContainer, + chunk_existence: HashSet<(Dimension, Vec2)>, + _block_type_marker: PhantomData, + _decoder_marker: PhantomData, +} + +#[allow(dead_code)] +impl< + UserState, + UserWorldInterface: RawWorldTrait, + UserBlockType: WorldBlockTrait, + UserSubChunkType: SubChunkTrait, + UserSubChunkDecoder: SubChunkDecoder, + > Level +where + ::Err: Debug, + ::Err: Debug, + ::Err: Debug, +{ + /// Simple function used to open the world + pub fn open( + path: Box, + create_db_if_missing: bool, + rw_cache: bool, + mut state: UserState, + ) -> Result< + Self, + LevelError, + > { + let db = level_try!(DatabaseError, { + let val = UserWorldInterface::new(path.clone(), create_db_if_missing, &mut state); + if val.is_ok() { + Ok(val.unwrap()) + } else { + UserWorldInterface::new( + { + let mut buff = path.into_path_buf(); + buff.push("db"); + buff.into_boxed_path() + }, + create_db_if_missing, + &mut state, + ) + } + }); + let mut this = Self { + db, + state, + rw_cache, + cached_sub_chunks: ClearCacheContainer::with_threshold(1024), + chunk_existence: HashSet::new(), + _block_type_marker: PhantomData, + _decoder_marker: PhantomData, + }; + this.chunk_existence = level_try!(DatabaseError, this.db.generated_chunks(&mut this.state)); + Ok(this) + } + + /// # Safety + /// This function is marked as `unsafe` because it allows the caller to bypass the caching systems. + /// If modifications are made directly to the underlying database, the cache may become desynchronized, + /// potentially leading to inconsistent. + /// + /// # When Safe to Use + /// It is safe to use this function if you can guarantee that no information held in the cache + /// will be modified or invalidated by your changes. + pub unsafe fn underlying_world_interface(&mut self) -> &mut UserWorldInterface { + &mut self.db + } + + /// Checks if a given chunk exists + pub fn chunk_exists(&mut self, xz: Vec2, dimension: Dimension) -> bool { + self.chunk_existence.contains(&(dimension, xz)) + } + + /// Must call before destruction + pub fn close(mut self) { + self.cull().unwrap(); + } + + /// Returns all chunks (in the form of its key) that exist in the world + pub fn existence_chunks(&self) -> Iter<'_, (Dimension, Vec2)> { + self.chunk_existence.iter() + } + + /// Fetches all chunk keys that satisfy the filter's constraints + pub fn get_chunk_keys(&mut self, mut filter: ChunkSelectionFilter) -> Vec> { + self.chunk_existence + .iter() + .filter_map(|(chunk_dim, pos)| { + if filter.poll(chunk_dim.clone(), *pos) { + Some(*pos) + } else { + None + } + }) + .collect() + } + + /// Fetches all chunks that satisfy the filter + pub fn get_chunks>( + &mut self, + mut filter: ChunkSelectionFilter, + min_max: Vec2, + ) -> Result, T::Err> { + let positions: Vec<_> = self + .chunk_existence + .iter() + .filter_map(|(chunk_dim, pos)| { + if filter.poll(*chunk_dim, *pos) { + Some((*chunk_dim, *pos)) + } else { + None + } + }) + .collect(); + + positions + .into_iter() + .map(|(dim, pos)| T::load_from_world(min_max, pos, dim, self)) + .collect() + } + + /// Fetches a subchunk at a given xyz and dimension + pub fn get_sub_chunk( + &mut self, + xz: Vec2, + y: i8, + dim: Dimension, + ) -> Result< + UserSubChunkType, + LevelError, + > { + if self.rw_cache { + if let Some(chunk) = self + .cached_sub_chunks + .get(&SubchunkCacheKey::new(xz, y, dim)) + { + return Ok(chunk.state_clone(&mut self.state)); + } + } + let raw_bytes = level_try!( + DatabaseError, + self.db + .get_subchunk_raw(ChunkKey::new_subchunk(xz, dim, y), &mut self.state) + ); + let out = match raw_bytes { + None => Ok::< + (i8, Option), + LevelError< + UserWorldInterface::Err, + UserSubChunkDecoder::Err, + UserSubChunkType::Err, + >, + >((y, None)), + Some(bytes) => { + if bytes.len() < 100 { + // This happens when there is no layers + let out = (y, None); + Ok(out) + } else { + let mut bytes = Cursor::new(bytes); + let data = level_try!( + SubChunkDecodeError, + UserSubChunkDecoder::decode_bytes_as_chunk(&mut bytes, &mut self.state) + ); + let out = ( + y, + Some(level_try!( + SubChunkError, + UserSubChunkType::decode_from_raw(data, &mut self.state) + )), + ); + Ok(out) + } + } + }?; + if self.rw_cache { + if let Some(data) = &out.1 { + let new = data.state_clone(&mut self.state); + self.cached_sub_chunks + .insert(SubchunkCacheKey::new(xz, y, dim), new); + } + } + if let None = &out.1 { + Ok(UserSubChunkType::empty(out.0, self.state())) + } else { + Ok(out.1.unwrap()) + } + } + + /// Sets a subchunk at the given xyz and dimension + pub fn set_sub_chunk( + &mut self, + data: UserSubChunkType, + xz: Vec2, + y: i8, + dim: Dimension, + ) -> Result< + (), + LevelError, + > { + if self.rw_cache { + self.cached_sub_chunks + .insert(SubchunkCacheKey::new(xz, y, dim), data); + level_try!(SubChunkDecodeError, self.perform_flush()); + } else { + let raw = level_try!( + SubChunkDecodeError, + UserSubChunkDecoder::write_as_bytes( + level_try!(SubChunkError, data.to_raw(y, &mut self.state)), + false, + &mut self.state, + ) + ); + let key = ChunkKey::new_subchunk(xz, dim, y); + level_try!( + DatabaseError, + self.db.set_subchunk_raw(key, &raw, &mut self.state) + ); + self.handle_exist(xz, dim); + } + Ok(()) + } + + /// Sets a whole chunk in the saved position of the chunk and the saved dimension. + /// `xz_override` lets the xz position be replaced if copying the chunk + /// `dim_override` lets the dimension of the chunk be changed if copying the chunk + pub fn set_chunk>( + &mut self, + chnk: UserChunkType, + xz_override: Option>, + dim_override: Option, + ) -> Result<(), UserChunkType::Err> { + chnk.write_to_world(self, xz_override, dim_override) + } + + /// Fetches a chunk from the world at the given xz and dimension and with the given bounds + /// ### Note: + /// `min_max` is the min and max subchunks not blocks + pub fn get_chunk< + UserChunkType: LevelChunkTrait< + Self, + UserLevel = Self, + Err = LevelError< + UserWorldInterface::Err, + UserSubChunkDecoder::Err, + UserSubChunkType::Err, + >, + >, + >( + &mut self, + min_max: Vec2, + xz: Vec2, + dim: Dimension, + ) -> Result { + UserChunkType::load_from_world(min_max, xz, dim, self) + } + + fn handle_exist(&mut self, xz: Vec2, dim: Dimension) { + self.chunk_existence.insert((dim, xz)); + } + + fn perform_flush(&mut self) -> Result<(), UserSubChunkDecoder::Err> { + let mut batch_info: Vec<(ChunkKey, Vec)> = Vec::new(); + let mut exist_info: Vec = Vec::new(); + self.cached_sub_chunks.cull(|user_key, data| { + let raw = UserSubChunkDecoder::write_as_bytes( + data.to_raw(user_key.y, &mut self.state).unwrap(), + false, + &mut self.state, + )?; + let key = ChunkKey::new_subchunk(user_key.xz, user_key.dim, user_key.y); + + batch_info.push((key, raw)); + exist_info.push(ChunkKey::chunk_marker(user_key.xz, user_key.dim)); + Ok(()) + })?; + if !batch_info.is_empty() { + self.db + .write_subchunk_batch(batch_info, &mut self.state) + .unwrap() + } + if !exist_info.is_empty() { + self.db + .write_subchunk_marker_batch(exist_info, &mut self.state) + .unwrap() + } + Ok(()) + } + + fn cull(&mut self) -> Result<(), UserSubChunkDecoder::Err> { + let mut batch_info: Vec<(ChunkKey, Vec)> = Vec::new(); + let mut exist_info: Vec = Vec::new(); + self.cached_sub_chunks.clear(|user_key, data| { + let raw = UserSubChunkDecoder::write_as_bytes( + data.to_raw(user_key.y, &mut self.state).unwrap(), + false, + &mut self.state, + )?; + let key = ChunkKey::new_subchunk(user_key.xz, user_key.dim, user_key.y); + + batch_info.push((key, raw)); + exist_info.push(ChunkKey::chunk_marker(user_key.xz, user_key.dim)); + Ok(()) + })?; + if !batch_info.is_empty() { + self.db + .write_subchunk_batch(batch_info, &mut self.state) + .unwrap() + } + if !exist_info.is_empty() { + self.db + .write_subchunk_marker_batch(exist_info, &mut self.state) + .unwrap() + } + Ok(()) + } +} + +pub trait LevelModificationProvider { + type UserState; + type UserWorldInterface; + type UserBlockType; + type UserSubChunkType; + type UserSubChunkDecoder; + type Error; + + fn get_sub_chunk( + &mut self, + xz: Vec2, + y: i8, + dim: Dimension, + ) -> Result; + + fn set_subchunk( + &mut self, + xz: Vec2, + y: i8, + dim: Dimension, + chnk: Self::UserSubChunkType, + ) -> Result<(), Self::Error>; + + fn state(&mut self) -> &mut Self::UserState; + fn chunk_exists(&mut self, xz: Vec2, dimension: Dimension) -> bool; +} + +impl< + UserState, + UserWorldInterface: RawWorldTrait, + UserBlockType: WorldBlockTrait, + UserSubChunkType: SubChunkTrait, + UserSubChunkDecoder: SubChunkDecoder, + > LevelModificationProvider + for Level +where + ::Err: Debug, + ::Err: Debug, + ::Err: Debug, +{ + type UserState = UserState; + type UserWorldInterface = UserWorldInterface; + type UserBlockType = UserBlockType; + type UserSubChunkType = UserSubChunkType; + type UserSubChunkDecoder = UserSubChunkDecoder; + type Error = + LevelError; + + fn get_sub_chunk( + &mut self, + xz: Vec2, + y: i8, + dim: Dimension, + ) -> Result { + self.get_sub_chunk(xz, y, dim) + } + + fn set_subchunk( + &mut self, + xz: Vec2, + y: i8, + dim: Dimension, + chnk: Self::UserSubChunkType, + ) -> Result<(), Self::Error> { + self.set_sub_chunk(chnk, xz, y, dim) + } + + fn state(&mut self) -> &mut Self::UserState { + &mut self.state + } + + fn chunk_exists(&mut self, xz: Vec2, dimension: Dimension) -> bool { + self.chunk_exists(xz, dimension) + } +} + +#[cfg(feature = "default-impl")] +pub mod default_impl { + use super::*; + use crate::level::chunk::default_impl::LevelChunk; + use crate::level::db_interface::rusty::RustyDBInterface; + use crate::level::sub_chunk::default_impl::{SubChunk, SubChunkDecoderImpl}; + use crate::level::world_block::default_impl::WorldBlock; + + pub struct BedrockState {} + pub type RawInterface = RustyDBInterface; + pub type BedrockWorldBlock = WorldBlock; + pub type BedrockSubChunk = SubChunk; + pub type BedrockSubChunkDecoder = SubChunkDecoderImpl; + pub type BedrockLevel = Level< + BedrockState, + RawInterface, + BedrockWorldBlock, + BedrockSubChunk, + BedrockSubChunkDecoder, + >; + pub type BedrockChunk = LevelChunk; + pub type BedrockLevelError = LevelError< + ::Err, + ::Err, + ::Err, + >; +} diff --git a/crates/level/src/level/mod.rs b/crates/level/src/level/mod.rs new file mode 100644 index 00000000..866ee024 --- /dev/null +++ b/crates/level/src/level/mod.rs @@ -0,0 +1,7 @@ +pub mod chunk; +pub mod chunk_cache; +pub mod db_interface; +pub mod file_interface; +pub mod level; +pub mod sub_chunk; +pub mod world_block; diff --git a/crates/level/src/level/sub_chunk.rs b/crates/level/src/level/sub_chunk.rs new file mode 100644 index 00000000..65d4d8c8 --- /dev/null +++ b/crates/level/src/level/sub_chunk.rs @@ -0,0 +1,465 @@ +use std::io::Cursor; +use vek::Vec3; +pub type BlockLayer = (Box<[u16; 4096]>, Vec); + +#[allow(dead_code)] +pub struct SubchunkTransitionalData { + y_level: i8, + data_version: u8, + layers: Vec>, +} + +impl SubchunkTransitionalData { + pub fn new(y_level: i8, layer_count: usize) -> Self { + Self { + y_level, + data_version: 9, + layers: Vec::with_capacity(layer_count), + } + } + + pub fn new_layer(&mut self, data: (Box<[u16; 4096]>, Vec)) { + self.layers.push(data); + } +} + +/// The trait which any decoder implementation must implement +pub trait SubChunkDecoder { + type Err; + type BlockType; + type UserState; + + /// This function is responsible for decoding a stream of raw bytes into the intermediate structure used for creating subchunks + fn decode_bytes_as_chunk( + bytes: &mut Cursor>, + state: &mut Self::UserState, + ) -> Result, Self::Err>; + + /// This function is responsible + /// for encoding the raw block data into a vector of bytes which the database layer can then save. + fn write_as_bytes( + chunk_state: SubchunkTransitionalData, + network: bool, + state: &mut Self::UserState, + ) -> Result, Self::Err>; +} + +/// The main trait that any subchunk type must implement +pub trait SubChunkTrait: Sized { + type Err; + type BlockType; + type UserState; + + /// This must create a valid empty state for the subchunk. + /// This may be just an empty optional, or it may be defaulting to air + fn empty(y_index: i8, state: &mut Self::UserState) -> Self; + + /// This must create a valid "full" state for the subchunk from the transitional data + fn decode_from_raw( + data: SubchunkTransitionalData, + state: &mut Self::UserState, + ) -> Result; + + /// This must create a transitional state from the current subchunk information + fn to_raw( + &self, + y_level: i8, + state: &mut Self::UserState, + ) -> Result, Self::Err>; + + /// Gets the block at the current position on the active layer + fn get_block(&self, xyz: Vec3) -> Option<&Self::BlockType>; + /// Gets the block at the current position on the active layer + fn get_block_mut(&mut self, xyz: Vec3) -> Option<&mut Self::BlockType>; + /// Sets the block at the current position on the active layer + fn set_block(&mut self, xyz: Vec3, block: Self::BlockType) -> Result<(), Self::Err>; + + /// Gets the active layer + fn get_active_layer(&self) -> u8; + /// Sets the active layer + fn set_active_layer(&mut self, idx: u8); + + /// This generates a new empty sublayer for the subchunk. This may only apply to bedrock, and if so, just unimplement this function + fn add_sub_layer(&mut self, state: &mut Self::UserState); + /// This returns the count of all sublayers + fn get_sub_layer_count(&self) -> usize; + + /// Gets the subchunk Y + fn get_y(&self) -> i8; + /// Sets the subchunk Y + fn set_y(&mut self, y: i8) -> i8; + + /// This is used as a replacement for the normal clone functions. It allows access to the state + fn state_clone(&self, state: &mut Self::UserState) -> Self; + + /// This returns if the subchunk is just air if so nothing is written to the database if this isn't desired behavior just always return false + fn is_empty(&self) -> bool; +} + +#[cfg(feature = "default-impl")] +pub mod default_impl { + use super::*; + use crate::level::world_block::{BlockTransitionalState, WorldBlockTrait}; + use crate::types::miner::idx_3_to_1; + use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; + use nbtx::NbtError; + use std::io::{Cursor, Seek, SeekFrom, Write}; + use std::marker::PhantomData; + use std::mem::MaybeUninit; + use thiserror::Error; + + pub struct SubChunkDecoderImpl { + _block_marker: PhantomData, + _state_marker: PhantomData, + } + + #[derive(Debug, Error)] + pub enum SubChunkDecoderError { + #[error("Missing Subchunk Version")] + SubChunkVersion, + #[error("Unknown Subchunk Version: {0}")] + UnknownVersion(u8), + #[error("Failed To Read Layer Count")] + LayerError, + #[error("Failed To Read Y Index")] + IndexError, + #[error("Failed To Read Palette Type")] + PaletteError, + #[error("Failed To Read Index Word")] + WordError, + #[error("Failed To Read Palette Count")] + PaletteCountError, + #[error("Failed To Slice NBT")] + SliceError, + #[error("Binary Error: {0}")] + BinaryError(#[from] std::io::Error), + #[error("NBT Error: {0}")] + NBTError(#[from] NbtError), + } + + impl, UserState> SubChunkDecoder + for SubChunkDecoderImpl + { + type Err = SubChunkDecoderError; + type BlockType = UserBlockType; + type UserState = UserState; + + fn decode_bytes_as_chunk( + bytes: &mut Cursor>, + state: &mut Self::UserState, + ) -> Result, Self::Err> { + let version = bytes.read_u8()?; + if version != 8 && version != 9 { + return Err(SubChunkDecoderError::UnknownVersion(version)); + } + + let storage_layer_count = bytes.read_u8()?; + let y_index = bytes.read_i8()?; + + let mut transitiondata = + SubchunkTransitionalData::new(y_index, storage_layer_count as usize); + + for _ in 0..storage_layer_count { + let palette_type = bytes.read_u8()?; + let network = palette_type & 0x1 == 1; + let bits_per_block = palette_type >> 1; + let blocks_per_word = 32 / bits_per_block; + let word_count = (4096 + (blocks_per_word as i32) - 1) / (blocks_per_word as i32); + let mask = (1 << bits_per_block) - 1; + let mut pos = 0usize; + let mut block_indices = Box::new([0u16; 4096]); + + for _ in 0..word_count { + let mut word = bytes.read_u32::()?; + for _ in 0..blocks_per_word { + let index: u16 = (word & mask) as u16; + if pos == 4096 { + break; + } + block_indices[pos] = index; + word >>= bits_per_block; + pos += 1; + } + } + + let palette_count = bytes.read_u32::()?; + let mut blocks = Vec::with_capacity(palette_count as usize); + for _ in 0_usize..palette_count as usize { + let position = bytes.position(); + let cursor = &mut Cursor::new(&bytes.get_mut()[position as usize..]); + + if network { + blocks.push(Self::BlockType::from_transition( + nbtx::from_bytes::( + cursor, + )?, + state, + )); + } else { + blocks.push(Self::BlockType::from_transition( + nbtx::from_bytes::(cursor)?, + state, + )); + } + let pos = cursor.position(); + bytes.seek(SeekFrom::Start(pos))?; + } + transitiondata.new_layer((block_indices, blocks)); + } + Ok(transitiondata) + } + + // TODO: Handle 0, 2, 3, 4 ,5 ,6 7, also handle 1 + fn write_as_bytes( + chunk_state: SubchunkTransitionalData, + network: bool, + state: &mut Self::UserState, + ) -> Result, Self::Err> { + let mut buffer = Cursor::>::new(vec![]); + buffer.write_u8(chunk_state.data_version)?; + buffer.write_u8(chunk_state.layers.len() as u8)?; + buffer.write_i8(chunk_state.y_level)?; + for layer in chunk_state.layers { + let bits_per_block = bits_needed_to_store(layer.1.len() as u32); + buffer.write_u8(bits_per_block << (1 + (network as u8)))?; + + let mut current_word = 0u32; + let mut bits_written = 0; + layer.0.iter().try_for_each(|element| { + let element = *element as u32; + if bits_written + bits_per_block > 32 { + buffer.write_u32::(current_word)?; + current_word = 0; + bits_written = 0; + } + + current_word = current_word + (element << bits_written); + bits_written += bits_per_block; + Ok::<(), std::io::Error>(()) + })?; + if bits_written != 0 { + buffer.write_u32::(current_word)?; + } + buffer.write_u32::(layer.1.len() as u32)?; + for blk in layer.1 { + if network { + buffer.write(&nbtx::to_net_bytes(&blk.into_transition(state))?)? + } else { + buffer.write(&nbtx::to_le_bytes(&blk.into_transition(state))?)? + }; + } + } + Ok(buffer.into_inner()) + } + } + + pub struct SubChunk { + blocks: Vec>, + y_index: i8, + active_layer: u8, + is_empty: bool, + _state_tag: PhantomData, + } + + impl, UserState> + SubChunk + { + pub fn force_non_empty(&mut self) { + self.is_empty = false; + } + + pub fn force_empty(&mut self) { + self.is_empty = false; + } + + pub fn replace(&mut self, other: Self) { + self.blocks = other.blocks; + self.y_index = other.y_index; + self.active_layer = other.active_layer; + self.is_empty = other.is_empty; + } + } + #[derive(Debug, Error)] + pub enum SubChunkError { + #[error("Failed To Get Layer: {0}")] + LayerError(u8), + } + + impl, UserState> SubChunkTrait + for SubChunk + { + type Err = SubChunkError; + type BlockType = UserBlockType; + type UserState = UserState; + + fn empty(y_index: i8, state: &mut Self::UserState) -> Self { + let mut val = Self { + blocks: Vec::with_capacity(1), + y_index, + active_layer: 0, + is_empty: true, + _state_tag: PhantomData, + }; + val.blocks.push(Box::new(std::array::from_fn(|_| { + Self::BlockType::air(state) + }))); + val + } + + fn decode_from_raw( + data: SubchunkTransitionalData, + _: &mut Self::UserState, + ) -> Result { + let mut layers: Vec; 4096]>> = (0..data.layers.len()) + .map(|_| Box::new([const { MaybeUninit::uninit() }; 4096])) + .collect(); + for (layer_index, (indices, blocks)) in data.layers.into_iter().enumerate() { + let layer: &mut Box<[MaybeUninit; 4096]> = &mut layers[layer_index]; + for whole_index in 0..4096usize { + layer[whole_index].write(Self::BlockType::from_other( + &blocks[indices[whole_index] as usize], + )); + } + } + Ok(Self { + blocks: unsafe { std::mem::transmute(layers) }, + y_index: data.y_level, + active_layer: 0, + is_empty: false, + _state_tag: PhantomData, + }) + } + + fn to_raw( + &self, + y_level: i8, + _: &mut Self::UserState, + ) -> Result, Self::Err> { + let mut layers: Vec> = + Vec::with_capacity(self.blocks.len()); + for layer in 0..self.blocks.len() { + layers.push(self.encode_single_layer(layer)); + } + Ok(SubchunkTransitionalData { + layers, + data_version: 9, // TODO: Change this to be configurable + y_level, + }) + } + + fn get_block(&self, xyz: Vec3) -> Option<&Self::BlockType> { + let layer: &[Self::BlockType; 4096] = self.blocks.get(self.active_layer as usize)?; + layer.get(idx_3_to_1::(xyz, 16u8, 16u8)) + } + + fn get_block_mut(&mut self, xyz: Vec3) -> Option<&mut Self::BlockType> { + let layer: &mut [Self::BlockType; 4096] = + self.blocks.get_mut(self.active_layer as usize)?; + layer.get_mut(idx_3_to_1::(xyz, 16u8, 16u8)) + } + + fn set_block(&mut self, xyz: Vec3, block: Self::BlockType) -> Result<(), Self::Err> { + let layer: &mut [Self::BlockType; 4096] = self + .blocks + .get_mut(self.active_layer as usize) + .ok_or(SubChunkError::LayerError(self.active_layer))?; + layer[idx_3_to_1::(xyz, 16u8, 16u8)] = block; + self.is_empty = false; + Ok(()) + } + fn get_active_layer(&self) -> u8 { + self.active_layer + } + + fn set_active_layer(&mut self, idx: u8) { + if idx as usize >= self.blocks.len() { + panic!( + "Selected subchunk index outside of valid range!, Layer Count: {}", + self.blocks.len() + ) + } + self.active_layer = idx; + } + + fn add_sub_layer(&mut self, state: &mut Self::UserState) { + self.blocks.push(Box::new(std::array::from_fn(|_| { + Self::BlockType::air(state) + }))); + } + + fn get_sub_layer_count(&self) -> usize { + self.blocks.len() + } + + fn get_y(&self) -> i8 { + self.y_index + } + + fn set_y(&mut self, y: i8) -> i8 { + self.y_index = y; + self.y_index + } + + fn state_clone(&self, _: &mut Self::UserState) -> Self { + Self { + blocks: self.blocks.clone(), + y_index: self.y_index, + active_layer: self.active_layer, + is_empty: self.is_empty, + _state_tag: PhantomData, + } + } + + fn is_empty(&self) -> bool { + self.is_empty + } + } + + impl, UserState> + SubChunk + { + fn encode_single_layer(&self, layer_override: usize) -> BlockLayer { + let mut indices = Box::new([0u16; 4096]); + let mut unique_block_array = Vec::new(); + let layer = &self.blocks[layer_override]; + for z in 0..16u8 { + for y in 0..16u8 { + for x in 0..16u8 { + let current_block = &layer[idx_3_to_1((x, y, z).into(), 16, 16)]; + if let Some(index) = unique_block_array + .iter() + .position(|ele| ele == current_block) + { + indices[idx_3_to_1((x, y, z).into(), 16, 16)] = index as u16; + } else { + unique_block_array.push(current_block.clone()); + indices[idx_3_to_1((x, y, z).into(), 16, 16)] = + (unique_block_array.len() - 1) as u16; + } + } + } + } + (indices, unique_block_array) + } + } + + impl Clone for SubChunk { + fn clone(&self) -> Self { + Self { + active_layer: self.active_layer, + _state_tag: PhantomData, + blocks: self.blocks.clone(), + is_empty: self.is_empty, + y_index: self.y_index.clone(), + } + } + } +} + +fn bits_needed_to_store(val: u32) -> u8 { + if val == 0 { + 1 + } else { + (32 - val.leading_zeros()) as u8 + } +} diff --git a/crates/level/src/level/world_block.rs b/crates/level/src/level/world_block.rs new file mode 100644 index 00000000..bd14019a --- /dev/null +++ b/crates/level/src/level/world_block.rs @@ -0,0 +1,104 @@ +use serde::{Deserialize, Serialize}; +use std::collections::HashMap; + +#[derive(Debug, Serialize, Deserialize, PartialEq, Clone)] +#[serde(untagged)] +pub enum BlockStateValue { + String(String), + Bool(bool), + Int(i32), +} + +#[derive(Debug, PartialEq, Serialize, Deserialize, Clone)] +pub struct BlockTransitionalState { + name: String, + states: HashMap, +} + +pub trait WorldBlockTrait: Clone + PartialEq { + type UserState; + fn from_transition(value: BlockTransitionalState, state: &mut Self::UserState) -> Self; + fn into_transition(self, state: &mut Self::UserState) -> BlockTransitionalState; + + fn get_id(&self) -> &str; + fn air(state: &mut Self::UserState) -> Self; + fn from_other(other: &Self) -> Self { + other.clone() + } +} + +#[cfg(feature = "default-impl")] +pub mod default_impl { + use super::*; + use std::fmt::Formatter; + use std::marker::PhantomData; + + pub struct WorldBlock { + id: String, + pub states: HashMap, + _state_marker: PhantomData, + } + + impl WorldBlock { + pub fn new(id: String) -> Self { + Self { + id, + states: HashMap::new(), + _state_marker: PhantomData, + } + } + } + + impl<'a, UserState> PartialEq for WorldBlock { + fn eq(&self, other: &Self) -> bool { + self.id == other.id && self.states == other.states + } + } + + impl WorldBlockTrait for WorldBlock { + type UserState = UserState; + + fn from_transition(value: BlockTransitionalState, _: &mut Self::UserState) -> Self { + Self { + id: value.name.clone(), + states: value.states.clone(), + _state_marker: PhantomData, + } + } + + fn into_transition(self, _: &mut Self::UserState) -> BlockTransitionalState { + BlockTransitionalState { + name: self.id, + states: self.states, + } + } + + fn get_id(&self) -> &str { + &self.id + } + + fn air(_: &mut Self::UserState) -> Self { + Self { + id: String::from("minecraft:air"), + states: HashMap::new(), + _state_marker: PhantomData, + } + } + } + + impl std::fmt::Debug for WorldBlock { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "WorldBlock(ID: {}, States: {:?})", self.id, self.states) + } + } + + impl std::clone::Clone for WorldBlock { + fn clone(&self) -> Self { + Self { + id: self.id.clone(), + states: self.states.clone(), + _state_marker: PhantomData, + } + } + } +} diff --git a/crates/level/src/lib.rs b/crates/level/src/lib.rs new file mode 100644 index 00000000..615351ff --- /dev/null +++ b/crates/level/src/lib.rs @@ -0,0 +1,4 @@ +extern crate core; + +pub mod level; +mod types; diff --git a/crates/level/src/types/clear_cache.rs b/crates/level/src/types/clear_cache.rs new file mode 100644 index 00000000..ef931789 --- /dev/null +++ b/crates/level/src/types/clear_cache.rs @@ -0,0 +1,110 @@ +use std::collections::HashMap; +use std::hash::Hash; + +#[derive(Debug, PartialEq)] +struct ClearCacheContainerValue { + internal: CachedValue, + sequence_id: usize, +} + +impl ClearCacheContainerValue { + pub fn new(internal: CachedValue, sequence_id: usize) -> Self { + Self { + internal, + sequence_id, + } + } +} + +pub struct ClearCacheContainer { + sequence_id: usize, + pub clear_threshold: usize, + cache_information: HashMap>, +} + +#[allow(dead_code)] +impl ClearCacheContainer { + pub fn new() -> Self { + Self { + sequence_id: 0, + clear_threshold: 2048, + cache_information: HashMap::new(), + } + } + + pub fn with_threshold(clear_threshold: usize) -> Self { + Self { + sequence_id: 0, + clear_threshold, + cache_information: HashMap::new(), + } + } + + pub fn get(&self, key: &KeyType) -> Option<&CachedValue> { + Some(&self.cache_information.get(key)?.internal) + } + + pub fn insert(&mut self, key: KeyType, val: CachedValue) { + let idx = self.next_seq(); + let _ = self + .cache_information + .insert(key, ClearCacheContainerValue::new(val, idx)); // Drops the old value + } + + pub fn is_cached(&self, key: &KeyType) -> bool { + self.get(key).map_or_else(|| false, |_| true) + } + + pub fn len(&self) -> usize { + self.cache_information.len() + } + + pub fn seq_id(&self) -> usize { + self.sequence_id + } + + fn next_seq(&mut self) -> usize { + self.sequence_id += 1; + self.sequence_id - 1 + } + + pub fn cull Result<(), E>>( + &mut self, + mut on_culled: F, + ) -> Result<(), E> { + if self.sequence_id != 0 && self.sequence_id % self.clear_threshold != 0 { + return Ok(()); + } + let max_distance = self.clear_threshold / 10; // This grabs the maximum distance the seq ID can be and still be kept in the cache + let dropped_keys = self + .cache_information + .iter() + .filter_map(|(key, val)| { + if self.sequence_id - val.sequence_id > max_distance { + Some(key.clone()) + } else { + None + } + }) + .collect::>(); + + { + for key in dropped_keys { + let information = self.cache_information.remove(&key).unwrap(); + on_culled(key, information.internal)?; + } + } + + Ok(()) + } + + pub fn clear Result<(), E>>( + &mut self, + mut on_culled: F, + ) -> Result<(), E> { + for (key, val) in self.cache_information.drain() { + on_culled(key, val.internal)?; + } + Ok(()) + } +} diff --git a/crates/level/src/types/miner.rs b/crates/level/src/types/miner.rs new file mode 100644 index 00000000..d4cdc147 --- /dev/null +++ b/crates/level/src/types/miner.rs @@ -0,0 +1,29 @@ +use vek::Vec3; + +#[allow(dead_code)] +pub fn idx_3_to_1>(vec: Vec3, width: T, height: T) -> usize +where + usize: From, +{ + (usize::from(vec.x) + + usize::from(vec.y) * usize::from(width) + + usize::from(vec.z) * usize::from(width) * usize::from(height)) + .into() +} + +#[allow(dead_code)] +pub fn in_bounds(min: T, max: T, val: T) -> bool { + val >= min && val <= max +} + +#[macro_export] +macro_rules! level_try { + ($name:ident, $expr:expr $(,)?) => { + match $expr { + Ok(val) => val, + Err(err) => { + return Err($crate::level::level::LevelError::$name(err)); + } + } + }; +} diff --git a/crates/level/src/types/mod.rs b/crates/level/src/types/mod.rs new file mode 100644 index 00000000..eb00f4af --- /dev/null +++ b/crates/level/src/types/mod.rs @@ -0,0 +1,2 @@ +pub mod clear_cache; +pub mod miner; diff --git a/crates/level/test_level/LOCK b/crates/level/test_level/LOCK new file mode 100644 index 00000000..e69de29b diff --git a/crates/level/test_level/LOG b/crates/level/test_level/LOG new file mode 100644 index 00000000..e69de29b diff --git a/crates/level/test_level/db/000010.ldb b/crates/level/test_level/db/000010.ldb new file mode 100644 index 00000000..43519829 Binary files /dev/null and b/crates/level/test_level/db/000010.ldb differ diff --git a/crates/level/test_level/db/000012.log b/crates/level/test_level/db/000012.log new file mode 100644 index 00000000..cd74e4a1 Binary files /dev/null and b/crates/level/test_level/db/000012.log differ diff --git a/crates/level/test_level/db/000013.ldb b/crates/level/test_level/db/000013.ldb new file mode 100644 index 00000000..35c27dd4 Binary files /dev/null and b/crates/level/test_level/db/000013.ldb differ diff --git a/crates/level/test_level/db/CURRENT b/crates/level/test_level/db/CURRENT new file mode 100644 index 00000000..875cf233 --- /dev/null +++ b/crates/level/test_level/db/CURRENT @@ -0,0 +1 @@ +MANIFEST-000007 diff --git a/crates/level/test_level/db/LOCK b/crates/level/test_level/db/LOCK new file mode 100644 index 00000000..e69de29b diff --git a/crates/level/test_level/db/LOG b/crates/level/test_level/db/LOG new file mode 100644 index 00000000..a69bbc2d --- /dev/null +++ b/crates/level/test_level/db/LOG @@ -0,0 +1,7 @@ +Recovered manifest with next_file=12 manifest_num=11 log_num=9 prev_log_num=0 last_seq=662 +reusing manifest "./test_level\\db\\MANIFEST-000007" +Recovering log file "\\\\?\\G:\\Projects\\rust\\bedrockrs\\crates\\level\\test_level\\db\\000009.log" +reusing log file "\\\\?\\G:\\Projects\\rust\\bedrockrs\\crates\\level\\test_level\\db\\000009.log" +Start write of L0 table 000013 +L0 table 000013 has 1748199 bytes +Deleting file type=Log num=9 diff --git a/crates/level/test_level/db/LOG.old b/crates/level/test_level/db/LOG.old new file mode 100644 index 00000000..00980fef --- /dev/null +++ b/crates/level/test_level/db/LOG.old @@ -0,0 +1,4 @@ +Recovered manifest with next_file=12 manifest_num=11 log_num=9 prev_log_num=0 last_seq=662 +reusing manifest "C:\\Users\\Duckos\\AppData\\Roaming\\.minecraft_bedrock\\installations\\Duckos\\Latest Release\\packageData\\minecraftWorlds\\0Vhz00QYds0=\\db\\MANIFEST-000007" +Recovering log file "\\\\?\\C:\\Users\\Duckos\\AppData\\Roaming\\.minecraft_bedrock\\installations\\Duckos\\Latest Release\\packageData\\minecraftWorlds\\0Vhz00QYds0=\\db\\000009.log" +reusing log file "\\\\?\\C:\\Users\\Duckos\\AppData\\Roaming\\.minecraft_bedrock\\installations\\Duckos\\Latest Release\\packageData\\minecraftWorlds\\0Vhz00QYds0=\\db\\000009.log" diff --git a/crates/level/test_level/db/MANIFEST-000007 b/crates/level/test_level/db/MANIFEST-000007 new file mode 100644 index 00000000..238dd33d Binary files /dev/null and b/crates/level/test_level/db/MANIFEST-000007 differ diff --git a/crates/level/test_level/level.dat b/crates/level/test_level/level.dat new file mode 100644 index 00000000..8625f613 Binary files /dev/null and b/crates/level/test_level/level.dat differ diff --git a/crates/level/test_level/levelname.txt b/crates/level/test_level/levelname.txt new file mode 100644 index 00000000..b953ea65 --- /dev/null +++ b/crates/level/test_level/levelname.txt @@ -0,0 +1 @@ +My World \ No newline at end of file diff --git a/crates/level/test_level/world_icon.jpeg b/crates/level/test_level/world_icon.jpeg new file mode 100644 index 00000000..a1bfcdfe Binary files /dev/null and b/crates/level/test_level/world_icon.jpeg differ diff --git a/crates/level/tests/api_test.rs b/crates/level/tests/api_test.rs new file mode 100644 index 00000000..fe7d9658 --- /dev/null +++ b/crates/level/tests/api_test.rs @@ -0,0 +1,61 @@ +use bedrockrs_level::level::chunk::{FillFilter, LevelChunkTrait}; +use bedrockrs_level::level::level::default_impl::*; +use bedrockrs_level::level::level::ChunkSelectionFilter; +use bedrockrs_shared::world::dimension::Dimension; +use std::path::Path; + +#[cfg(feature = "default-impl")] +#[test] +fn world_test( +) -> Result<(), BedrockLevelError> { + let wld_path = "./test_level"; + + println!("Loading World"); + + let mut level = BedrockLevel::open( + Box::from(Path::new(wld_path)), + false, + false, + BedrockState {}, + )?; + + println!("Collecting Chunks"); + let chunks = level.get_chunk_keys(ChunkSelectionFilter::Dimension(Dimension::Overworld)); + + println!("Collected {} Chunks!", chunks.len()); + + let blks = [ + BedrockWorldBlock::new("minecraft:iron_block".to_string()), + BedrockWorldBlock::new("minecraft:diamond_block".to_string()), + ]; + let len = chunks.len(); + + println!("Filling Chunks"); + for (idx, key) in chunks.into_iter().enumerate() { + let mut chunk = BedrockChunk::empty( + key, + (-4, 20).into(), + Dimension::Overworld, + &mut BedrockState {}, + ); + + for blk in &blks { + chunk + .fill_chunk( + blk.clone(), + FillFilter::Precedence(Box::new(|_, _, _, _| rand::random::() > 0.5)), + ) + .expect("Fill failed"); + } + + chunk.write_to_world(&mut level, None, None)?; + + if idx % (len / 10 + 1) == 0 { + println!("Wrote {idx} out of {len} chunks!"); + } + } + + level.close(); + + Ok(()) +} diff --git a/crates/proto_macros/Cargo.toml b/crates/macros/Cargo.toml similarity index 84% rename from crates/proto_macros/Cargo.toml rename to crates/macros/Cargo.toml index a57be7a8..1807facd 100644 --- a/crates/proto_macros/Cargo.toml +++ b/crates/macros/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "bedrockrs_proto_macros" +name = "bedrockrs_macros" version = "0.1.0" edition = "2021" diff --git a/crates/macros/src/attr.rs b/crates/macros/src/attr.rs new file mode 100644 index 00000000..cf518bb0 --- /dev/null +++ b/crates/macros/src/attr.rs @@ -0,0 +1,130 @@ +use quote::ToTokens; +use syn::{Attribute, Error, GenericArgument, PathArguments, Type}; + +#[derive(Clone)] +pub enum ProtoCodecEndianness { + Le, + Be, + Var, +} + +#[derive(Default)] +pub struct ProtoCodecFlags { + pub endianness: Option, + pub vec_endianness: Option, + pub vec_repr: Option, + pub enum_endianness: Option, + pub enum_repr: Option, + pub nbt: bool, + pub str: bool, +} + +macro_rules! endianness { + ($name:ident, $attr:ident, $flags:ident) => { + $attr.parse_nested_meta(|meta| { + // We disallow overwriting it later down the line + if let Some(_) = $flags.$name { + return Err(meta.error(format!("{} can not be overwritten", stringify!($name)))); + } + + // #[endianness(le)] + if meta.path.is_ident("le") { + $flags.$name = Some(ProtoCodecEndianness::Le); + return Ok(()); + } + + // #[endianness(be)] + if meta.path.is_ident("be") { + $flags.$name = Some(ProtoCodecEndianness::Be); + return Ok(()); + } + + // #[endianness(var)] + if meta.path.is_ident("var") { + $flags.$name = Some(ProtoCodecEndianness::Var); + return Ok(()); + } + + Err(meta.error(format!("unrecognized {}", stringify!($name)))) + })?; + }; +} + +macro_rules! repr { + ($name:ident, $attr:ident, $flags:ident) => { + $attr.parse_nested_meta(|meta| { + // We disallow overwriting it later down the line + if let Some(_) = $flags.$name { + return Err(meta.error(format!("{} can not be overwritten", stringify!($name)))); + }; + + $flags.$name = if let Some(v) = meta.path.get_ident() { + Some(Type::Verbatim(v.clone().to_token_stream())) + } else { + return Err(meta.error(format!("Missing integer type in {}", stringify!($name)))); + }; + + Ok(()) + })?; + }; +} + +pub fn get_attrs(attrs: &[Attribute]) -> Result { + let mut flags = ProtoCodecFlags::default(); + + for attr in attrs { + if attr.path().is_ident("endianness") { + endianness!(endianness, attr, flags); + continue; + } + + if attr.path().is_ident("vec_endianness") { + endianness!(vec_endianness, attr, flags); + continue; + } + + if attr.path().is_ident("vec_repr") { + repr!(vec_repr, attr, flags); + continue; + } + + if attr.path().is_ident("enum_endianness") { + endianness!(enum_endianness, attr, flags); + continue; + } + + if attr.path().is_ident("enum_repr") { + repr!(enum_repr, attr, flags); + continue; + } + + if attr.path().is_ident("nbt") { + flags.nbt = true; + continue; + } + + if attr.path().is_ident("str") { + flags.str = true; + continue; + } + } + + Ok(flags) +} + +pub fn extract_inner_type_from_vec(ty: &Type) -> Option<&Type> { + if let Type::Path(type_path) = ty { + if let Some(last_segment) = type_path.path.segments.last() { + if last_segment.ident == "Vec" { + if let PathArguments::AngleBracketed(ref generics) = last_segment.arguments { + if generics.args.len() == 1 { + if let Some(GenericArgument::Type(inner_type)) = generics.args.first() { + return Some(inner_type); + } + } + } + } + } + } + None +} diff --git a/crates/macros/src/de.rs b/crates/macros/src/de.rs new file mode 100644 index 00000000..8ebcfd5b --- /dev/null +++ b/crates/macros/src/de.rs @@ -0,0 +1,181 @@ +use crate::attr::{extract_inner_type_from_vec, get_attrs, ProtoCodecEndianness}; +use proc_macro2::{Ident, Span, TokenStream}; +use quote::quote; +use syn::{Attribute, DataEnum, DataStruct, Field, Fields, Type}; + +fn build_de_instance(endianness: Option, f_type: &Type) -> TokenStream { + match endianness { + None => { + quote! { <#f_type as ::bedrockrs_proto_core::ProtoCodec>::proto_deserialize(stream)? } + } + Some(ProtoCodecEndianness::Le) => { + quote! { <#f_type as ::bedrockrs_proto_core::ProtoCodecLE>::proto_deserialize(stream)? } + } + Some(ProtoCodecEndianness::Be) => { + quote! { <#f_type as ::bedrockrs_proto_core::ProtoCodecBE>::proto_deserialize(stream)? } + } + Some(ProtoCodecEndianness::Var) => { + quote! { <#f_type as ::bedrockrs_proto_core::ProtoCodecVAR>::proto_deserialize(stream)? } + } + } +} + +fn build_de_field(fields: &[&Field]) -> TokenStream { + let code = fields + .iter() + .enumerate() + .map(|(i, f)| { + let name = f.ident.clone().unwrap_or(Ident::new(&format!("e{i}"), Span::call_site())); + let ty = f.ty.clone(); + let flags = get_attrs(f.attrs.as_slice()).expect("Error while getting attrs"); + + if let Some(repr) = flags.vec_repr { + let vec_des = build_de_instance(flags.vec_endianness, &repr); + let inner_ty = extract_inner_type_from_vec(&ty).expect("Failed to get inner Vec type").clone(); + let des = build_de_instance(flags.endianness, &inner_ty); + + return quote! { + let #name = { + let len: #repr = #vec_des; + + let mut vec = Vec::with_capacity(len.try_into()?); + + for _ in 0..len { + vec.push(#des); + }; + + vec + }; + }; + } + + if flags.nbt { + return quote! { + let #name: #ty = ::nbtx::from_bytes::<::nbtx::NetworkLittleEndian, _>(stream)?; + }; + } + + if flags.str { + return quote! { + let #name: #ty = { + let string = ::proto_deserialize(stream)?; + let str = string.as_str(); + #ty::try_from(str)? + }; + }; + } + + let des = build_de_instance(flags.endianness, &ty); + + quote! { + let #name: #ty = #des; + } + }); + + quote! { + #(#code)* + } +} + +fn build_de_fields(fields: Fields) -> (TokenStream, Option) { + let i_fields = match fields { + Fields::Named(ref v) => Some(v.named.iter().clone()), + Fields::Unnamed(ref v) => Some(v.unnamed.iter().clone()), + Fields::Unit => None, + }; + + let de = if let Some(i_fields) = i_fields { + build_de_field(Vec::from_iter(i_fields).as_slice()) + } else { + quote! {} + }; + + let ctor_fields = match fields { + Fields::Named(ref v) => { + let ctor = v.named.iter().enumerate().map(|(i, f)| { + f.ident + .clone() + .unwrap_or(Ident::new(&format!("e{i}"), Span::call_site())) + }); + + Some(quote! { {#(#ctor),*} }) + } + Fields::Unnamed(ref v) => { + let ctor = v.unnamed.iter().enumerate().map(|(i, f)| { + f.ident + .clone() + .unwrap_or(Ident::new(&format!("e{i}"), Span::call_site())) + }); + + Some(quote! { (#(#ctor),*) }) + } + Fields::Unit => None, + }; + + (de, ctor_fields) +} + +pub fn build_de_struct(data_struct: &DataStruct) -> TokenStream { + let (de, ctor_fields) = build_de_fields(data_struct.fields.clone()); + + if let Some(ctor) = ctor_fields { + quote! { + #de + let val = Self #ctor; + } + } else { + quote! { + #de + let val = Self; + } + } +} + +pub fn build_de_enum(data_enum: &DataEnum, attrs: &[Attribute], name: Ident) -> TokenStream { + let flags = get_attrs(attrs).expect("Error while getting attrs"); + + if let (Some(repr), endian) = (flags.enum_repr, flags.enum_endianness) { + let enum_type_de = build_de_instance(endian, &repr); + + let variants = data_enum.variants.iter().map(|var| { + let desc = var + .discriminant + .clone() + .unwrap_or_else(|| panic!("Missing discriminant for {:?}", var.ident)) + .1; + + let name = var.ident.clone(); + let (de, ctor_fields) = build_de_fields(var.fields.clone()); + + if let Some(ctor) = ctor_fields { + quote! { + #desc => { + #de + + Self::#name #ctor + } + } + } else { + quote! { + #desc => { + #de + + Self::#name + } + } + } + }); + + // We need to find a solution for what happens when an enum type is not found + quote! { + let enum_type = #enum_type_de; + + let val = match enum_type { + #(#variants),* + _ => { return Err(bedrockrs_proto_core::error::ProtoCodecError::InvalidEnumID(format!("{enum_type:?}"), stringify!(#name))) }, + }; + } + } else { + panic!("Missing attr `enum_repr` or `enum_endianness` on enum") + } +} diff --git a/crates/proto_macros/src/lib.rs b/crates/macros/src/lib.rs similarity index 71% rename from crates/proto_macros/src/lib.rs rename to crates/macros/src/lib.rs index dc9a309a..c6dfdde7 100644 --- a/crates/proto_macros/src/lib.rs +++ b/crates/macros/src/lib.rs @@ -1,16 +1,27 @@ -use de::proto_build_de_enum; -use de::proto_build_de_struct; +use crate::de::{build_de_enum, build_de_struct}; +use crate::ser::{build_ser_enum, build_ser_struct}; use quote::quote; -use ser::proto_build_ser_enum; -use ser::proto_build_ser_struct; use std::collections::HashMap; use syn::parse::{Parse, ParseStream}; use syn::{parse_macro_input, Data, DeriveInput, Lit, Token}; +mod attr; mod de; mod ser; - -#[proc_macro_derive(ProtoCodec, attributes(len_repr, enum_repr))] +mod size; + +#[proc_macro_derive( + ProtoCodec, + attributes( + endianness, + vec_endianness, + vec_repr, + enum_endianness, + enum_repr, + nbt, + str + ) +)] pub fn proto_codec_derive(item: proc_macro::TokenStream) -> proc_macro::TokenStream { let input = parse_macro_input!(item as DeriveInput); @@ -19,54 +30,39 @@ pub fn proto_codec_derive(item: proc_macro::TokenStream) -> proc_macro::TokenStr let generics = input.generics; let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); - let expanded = match input.data { - Data::Struct(struct_data) => { - let ser = proto_build_ser_struct(&struct_data); - let de = proto_build_de_struct(&struct_data); - - quote! { - impl #impl_generics ::bedrockrs_proto_core::ProtoCodec for #name #ty_generics #where_clause { - fn proto_serialize(&self, stream: &mut Vec) -> Result<(), ::bedrockrs_proto_core::error::ProtoCodecError> where Self: Sized { - #[cfg(debug_assertions)] - ::log::trace!("ProtoSerialize: {}", stringify!(#name)); - #ser - Ok(()) - } - - fn proto_deserialize(stream: &mut ::std::io::Cursor<&[u8]>) -> Result where Self: Sized { - #[cfg(debug_assertions)] - ::log::trace!("ProtoDeserialize: {}", stringify!(#name)); - Ok(Self{ - #de - }) - } - } - } + let (ser, de) = match input.data { + Data::Struct(v) => (build_ser_struct(&v), build_de_struct(&v)), + Data::Enum(v) => ( + build_ser_enum(&v, input.attrs.as_slice()), + build_de_enum(&v, input.attrs.as_slice(), name.clone()), + ), + Data::Union(_) => { + return proc_macro::TokenStream::from(quote! { + compile_error!("ProtoCodec derive macro only supports structs and enums") + }) } - Data::Enum(enum_data) => { - let ser = proto_build_ser_enum(&enum_data, &input.attrs, &name); - let de = proto_build_de_enum(&enum_data, &input.attrs, &name); + }; - quote! { - impl #impl_generics ::bedrockrs_proto_core::ProtoCodec for #name #ty_generics #where_clause { - fn proto_serialize(&self, stream: &mut Vec) -> Result<(), ::bedrockrs_proto_core::error::ProtoCodecError> where Self: Sized { - #ser - Ok(()) - } + let expanded = quote! { + impl #impl_generics ::bedrockrs_proto_core::ProtoCodec for #name #ty_generics #where_clause { + fn proto_serialize(&self, stream: &mut Vec) -> Result<(), ::bedrockrs_proto_core::error::ProtoCodecError> where Self: Sized { + #[cfg(debug_assertions)] + ::log::trace!("ProtoSerialize: {}", stringify!(#name)); + #ser + Ok(()) + } - fn proto_deserialize(stream: &mut ::std::io::Cursor<&[u8]>) -> Result where Self: Sized { + fn proto_deserialize(stream: &mut ::std::io::Cursor<&[u8]>) -> Result where Self: Sized { + #[cfg(debug_assertions)] + ::log::trace!("ProtoDeserialize: {}", stringify!(#name)); + #de + Ok(val) + } - Ok({#de}) - } - } + fn get_size_prediction(&self) -> usize { + 1 } } - Data::Union(_) => { - // Unions are not supported - panic!( - "ProtoCodec derive macro only supports named/unnamed structs, got union: {name:?}." - ) - } }; proc_macro::TokenStream::from(expanded) @@ -106,8 +102,8 @@ impl Parse for GamepacketInput { Ok(Self { id: id.clone(), - compress: map.remove("compress").and_then(|v| Some(v.clone())), - encrypt: map.remove("encrypt").and_then(|v| Some(v.clone())), + compress: map.remove("compress"), + encrypt: map.remove("encrypt"), }) } } @@ -217,6 +213,15 @@ pub fn gamepackets(input: proc_macro::TokenStream) -> proc_macro::TokenStream { } }); + let size_prediction = args.packets.clone(); + let size_prediction = size_prediction.iter().map(|(name, value)| { + if let Some(v) = value { + quote! { GamePackets::#name(pk) => <#v as ::bedrockrs_proto_core::GamePacket>::get_size_prediction(pk), } + } else { + quote! { GamePackets::#name() => { todo!("impl GamePackets::{}", stringify!(name)); }, } + } + }); + let ser = args.packets.clone(); let ser = ser.iter().map(|(name, value)| { if let Some(v) = value { @@ -241,7 +246,7 @@ pub fn gamepackets(input: proc_macro::TokenStream) -> proc_macro::TokenStream { match stream.write_all(buf.as_slice()) { Ok(_) => {}, - Err(err) => return Err(::bedrockrs_proto_core::error::ProtoCodecError::IOError(::std::sync::Arc::new(err))), + Err(err) => return Err(::bedrockrs_proto_core::error::ProtoCodecError::IOError(err)), }; }, } @@ -275,20 +280,23 @@ pub fn gamepackets(input: proc_macro::TokenStream) -> proc_macro::TokenStream { #(#variants)* } - impl GamePackets { - pub fn compress(&self) -> bool { + impl ::bedrockrs_proto_core::GamePacketsAll for GamePackets { + #[inline] + fn compress(&self) -> bool { match self { #(#compress)* }; } - pub fn encrypt(&self) -> bool { + #[inline] + fn encrypt(&self) -> bool { match self { #(#encrypt)* }; } - pub fn pk_serialize(&self, stream: &mut Vec, subclient_sender_id: SubClientID, subclient_target_id: SubClientID) -> Result<(), ::bedrockrs_proto_core::error::ProtoCodecError> { + #[inline] + fn pk_serialize(&self, stream: &mut Vec, subclient_sender_id: SubClientID, subclient_target_id: SubClientID) -> Result<(), ::bedrockrs_proto_core::error::ProtoCodecError> { match self { #(#ser)* }; @@ -296,7 +304,8 @@ pub fn gamepackets(input: proc_macro::TokenStream) -> proc_macro::TokenStream { Ok(()) } - pub fn pk_deserialize(stream: &mut Cursor<&[u8]>) -> Result<(GamePackets, SubClientID, SubClientID), ::bedrockrs_proto_core::error::ProtoCodecError> { + #[inline] + fn pk_deserialize(stream: &mut Cursor<&[u8]>) -> Result<(GamePackets, SubClientID, SubClientID), ::bedrockrs_proto_core::error::ProtoCodecError> { let (_length, gamepacket_id, subclient_sender_id, subclient_target_id) = match read_gamepacket_header(stream) { Ok(val) => val, Err(err) => return Err(err), @@ -311,6 +320,15 @@ pub fn gamepackets(input: proc_macro::TokenStream) -> proc_macro::TokenStream { Ok((gamepacket, subclient_sender_id, subclient_target_id)) } + + #[inline] + fn get_size_prediction(&self) -> usize { + let len = match self { + #(#size_prediction)* + }; + + len + get_gamepacket_header_size_prediction() + } } }; diff --git a/crates/macros/src/ser.rs b/crates/macros/src/ser.rs new file mode 100644 index 00000000..979cecae --- /dev/null +++ b/crates/macros/src/ser.rs @@ -0,0 +1,186 @@ +use crate::attr::{extract_inner_type_from_vec, get_attrs, ProtoCodecEndianness}; +use proc_macro2::{Ident, Span, TokenStream}; +use quote::quote; +use syn::{Attribute, DataEnum, DataStruct, Field, Fields, Type}; + +fn build_ser_instance( + endianness: Option, + f_type: &Type, + f_name: TokenStream, +) -> TokenStream { + match endianness { + None => { + quote! { <#f_type as ::bedrockrs_proto_core::ProtoCodec>::proto_serialize(&#f_name, stream)? } + } + Some(ProtoCodecEndianness::Le) => { + quote! { <#f_type as ::bedrockrs_proto_core::ProtoCodecLE>::proto_serialize(&#f_name, stream)? } + } + Some(ProtoCodecEndianness::Be) => { + quote! { <#f_type as ::bedrockrs_proto_core::ProtoCodecBE>::proto_serialize(&#f_name, stream)? } + } + Some(ProtoCodecEndianness::Var) => { + quote! { <#f_type as ::bedrockrs_proto_core::ProtoCodecVAR>::proto_serialize(&#f_name, stream)? } + } + } +} + +fn build_ser_field( + fields: &[&Field], + f_prefix: Option, + vec_by_ref: bool, +) -> TokenStream { + let code = fields + .iter() + .enumerate() + .map(|(i, f)| { + let name = f.ident.clone().unwrap_or(Ident::new(&format!("e{i}"), Span::call_site())); + let final_name = if let Some(prefix) = &f_prefix { + quote! { #prefix.#name } + } else { + quote! { #name } + }; + + let ty = f.ty.clone(); + let flags = get_attrs(f.attrs.as_slice()).expect("Error while getting attrs"); + + if let Some(repr) = flags.vec_repr { + let vec_ser = build_ser_instance(flags.vec_endianness, &repr, quote! { len }); + let inner_ty = extract_inner_type_from_vec(&ty).expect("Failed to get inner Vec type").clone(); + let ser = build_ser_instance(flags.endianness, &inner_ty, quote! { i }); + + let vec_prefix = if vec_by_ref { + quote! { & } + } else { + quote! {} + }; + + return quote! { + { + let len: #repr = #final_name.len().try_into()?; + + #vec_ser; + + for i in #vec_prefix #final_name { + #ser; + }; + }; + }; + } + + if flags.nbt { + return quote! { + ::nbtx::to_bytes_in::<::nbtx::NetworkLittleEndian>(stream, &#final_name)?; + }; + } + + if flags.str { + return quote! { + ::proto_serialize(&ToString::to_string(&#final_name), stream)?; + }; + } + + let ser = build_ser_instance(flags.endianness, &ty, final_name); + + quote! { + #ser; + } + }); + + quote! { + #(#code)* + } +} + +fn build_ser_fields( + fields: Fields, + f_prefix: Option, + vec_by_ref: bool, +) -> (TokenStream, Option) { + let i_fields = match fields { + Fields::Named(ref v) => Some(v.named.iter().clone()), + Fields::Unnamed(ref v) => Some(v.unnamed.iter().clone()), + Fields::Unit => None, + }; + + let ser = if let Some(i_fields) = i_fields { + build_ser_field(Vec::from_iter(i_fields).as_slice(), f_prefix, vec_by_ref) + } else { + quote! {} + }; + + let fields = match fields { + Fields::Named(ref v) => { + let ctor = v.named.iter().enumerate().map(|(i, f)| { + f.ident + .clone() + .unwrap_or(Ident::new(&format!("e{i}"), Span::call_site())) + }); + + Some(quote! { {#(#ctor),*} }) + } + Fields::Unnamed(ref v) => { + let ctor = v.unnamed.iter().enumerate().map(|(i, f)| { + f.ident + .clone() + .unwrap_or(Ident::new(&format!("e{i}"), Span::call_site())) + }); + + Some(quote! { (#(#ctor),*) }) + } + Fields::Unit => None, + }; + + (ser, fields) +} + +pub fn build_ser_struct(data_struct: &DataStruct) -> TokenStream { + let (ser, _) = build_ser_fields(data_struct.fields.clone(), Some(quote! { self }), true); + + quote! { + #ser + } +} + +pub fn build_ser_enum(data_enum: &DataEnum, attrs: &[Attribute]) -> TokenStream { + let flags = get_attrs(attrs).expect("Error while getting attrs"); + + if let (Some(repr), endian) = (flags.enum_repr, flags.enum_endianness) { + let variants = data_enum.variants.iter().map(|var| { + let desc = var + .discriminant + .clone() + .unwrap_or_else(|| panic!("Missing discriminant for {:?}", var.ident)) + .1; + + let enum_type_ser = build_ser_instance(endian.clone(), &repr, quote! {#desc}); + let name = var.ident.clone(); + let (ser, fields) = build_ser_fields(var.fields.clone(), None, false); + + if let Some(fields) = fields { + quote! { + Self::#name #fields => { + #enum_type_ser; + + #ser + } + } + } else { + quote! { + Self::#name => { + #enum_type_ser; + + #ser + } + } + } + }); + + quote! { + match self { + #(#variants),* + } + } + } else { + panic!("Missing attr `enum_repr` or `enum_endianness` on enum") + } +} diff --git a/crates/macros/src/size.rs b/crates/macros/src/size.rs new file mode 100644 index 00000000..8b137891 --- /dev/null +++ b/crates/macros/src/size.rs @@ -0,0 +1 @@ + diff --git a/crates/paletted_storage/Cargo.toml b/crates/paletted_storage/Cargo.toml deleted file mode 100644 index b3a021f3..00000000 --- a/crates/paletted_storage/Cargo.toml +++ /dev/null @@ -1,11 +0,0 @@ -[package] -name = "bedrockrs_paletted_storage" -version = "0.1.0" -edition = "2021" - -[dependencies] -bedrockrs_core = { path = "../core" } - -nbtx = { git = "https://github.com/bedrock-crustaceans/nbtx" } - -byteorder = "1.5" diff --git a/crates/paletted_storage/src/lib.rs b/crates/paletted_storage/src/lib.rs deleted file mode 100644 index 1974d2f7..00000000 --- a/crates/paletted_storage/src/lib.rs +++ /dev/null @@ -1,117 +0,0 @@ -use std::io::Cursor; - -use bedrockrs_core::int::LE; -use byteorder::ReadBytesExt; - -#[derive(Debug, Clone)] -pub struct PalettedStorage { - pub blocks: [u32; 4096], - pub palette: Vec, -} - -impl PalettedStorage { - // https://www.reddit.com/r/technicalminecraft/comments/x3pzb7/bedrock_leveldb_subchunk_format/ - // I have no idea how this actually works tbh - pub fn decode(cur: &mut Cursor<&[u8]>) -> PalettedStorage { - let mut out = PalettedStorage { - blocks: [0; 4096], - palette: Vec::new(), - }; - let palette_type = cur.read_u8().expect("Missing palette type"); - let network = palette_type & 1; - let bits_per_block = palette_type >> 1; - if bits_per_block == 0 { - return out; - } - let blocks_per_word = 32 / bits_per_block; - let num_words: i32 = - (4096 + Into::::into(blocks_per_word) - 1) / Into::::into(blocks_per_word); - let mask = (1 << bits_per_block) - 1; // assume 2s complement - - let mut pos = 0; - for _ in 0..num_words { - let mut word = LE::::read(cur).expect("Missing word").into_inner(); - for _ in 0..blocks_per_word { - let val = word & mask; - if pos == 4096 { - break; - } - out.blocks[pos] = val; - word = word >> bits_per_block; - pos += 1; - } - } - - let palette_count = LE::::read(cur) - .expect("Missing palette count") - .into_inner(); - - for _ in 0..palette_count { - match network { - 0 => { - out.palette.push( - todo!(), // NbtTag::nbt_deserialize::(cur) - // .expect("Bad NBT Tag in palette") - // .1, - ); - } - _ => { - out.palette.push( - todo!(), // NbtTag::nbt_deserialize::(cur) - // .expect("Bad NBT Tag in palette") - // .1, - ); - } - } - } - - return out; - } - - pub fn encode(&self, network: bool) -> Vec { - let mut out = Vec::new(); - let palette_type: u8 = network.into(); - let bits_per_block = bits_needed_to_store(self.palette.len() as u32); - - let combined = ((bits_per_block << 1) as u8) + palette_type; - - out.push(combined); - - let mut current_word = 0u32; - let mut bits_written = 0; - - for block in self.blocks { - if bits_written + bits_per_block > 32 { - out.extend_from_slice(¤t_word.to_le_bytes()); - current_word = 0; - bits_written = 0; - } - - current_word = current_word + (block << bits_written); - bits_written += bits_per_block; - } - - if bits_written != 0 { - out.extend_from_slice(¤t_word.to_le_bytes()); - } - - out.extend((self.palette.len() as i32).to_le_bytes()); - - for nbt in &self.palette { - if network { - nbtx::to_net_bytes_in(&mut out, &nbt).unwrap() - } else { - nbtx::to_le_bytes_in(&mut out, &nbt).unwrap() - } - } - - out - } -} - -fn bits_needed_to_store(n: u32) -> u32 { - if n == 0 { - return 1; // Edge case: 0 requires 1 bit to represent - } - (32 - n.leading_zeros()) as u32 -} diff --git a/crates/proto/Cargo.toml b/crates/proto/Cargo.toml index 1e608777..8fee5b3d 100644 --- a/crates/proto/Cargo.toml +++ b/crates/proto/Cargo.toml @@ -4,27 +4,27 @@ version = "0.1.0" edition = "2021" [dependencies] -bedrockrs_core = { path = "../core" } bedrockrs_shared = { path = "../shared" } bedrockrs_proto_core = { path = "../proto_core" } -bedrockrs_proto_macros = { path = "../proto_macros" } +bedrockrs_macros = { path = "../macros" } bedrockrs_addon = { path = "../addon" } nbtx = { git = "https://github.com/bedrock-crustaceans/nbtx" } -xuid = "1.0.0" +xuid = "1.0" + +byteorder = "1.5" +varint-rs = "2.2" log = "0.4" -thiserror = "1.0" -dyn-clone = "1.0" +vek = "0.17" +thiserror = "2.0" jsonwebtoken = "9.3" -ring = { version = "0.17" } rand = "0.8" base64 = "0.22" -uuid = { version = "1.10", features = ["v4"] } +uuid = { version = "1.11", features = ["v4"] } serde_json = "1.0" -rak-rs = { version = "0.3", default-features = false, features = ["async_tokio", "mcpe"] } -tokio = { version = "1.38", features = ["full"] } +tokio = { version = "1.40", features = ["full"] } flate2 = "1.0" snap = "1.1" @@ -32,3 +32,6 @@ snap = "1.1" x509-cert = "0.2" bitflags = "2.6.0" +serde = { version = "1.0", features = ["derive"] } + +rak-rs = { version = "0.3", default-features = false, features = ["async_tokio", "mcpe"] } diff --git a/crates/proto/src/codec.rs b/crates/proto/src/codec.rs new file mode 100644 index 00000000..8f749ad5 --- /dev/null +++ b/crates/proto/src/codec.rs @@ -0,0 +1,119 @@ +use crate::compression::Compression; +use crate::encryption::Encryption; +use crate::helper::ProtoHelper; +use bedrockrs_proto_core::error::ProtoCodecError; +use bedrockrs_proto_core::sub_client::SubClientID; +use bedrockrs_proto_core::GamePacketsAll; +use std::io::Cursor; + +pub fn encode_gamepackets( + gamepackets: &[T::GamePacketType], + compression: Option<&Compression>, + encryption: Option<&mut Encryption>, +) -> Result, ProtoCodecError> { + log::trace!("Encoding gamepackets"); + + let mut gamepacket_stream = batch_gamepackets::(gamepackets)?; + gamepacket_stream = compress_gamepackets::(gamepacket_stream, compression)?; + gamepacket_stream = encrypt_gamepackets::(gamepacket_stream, encryption)?; + + Ok(gamepacket_stream) +} + +pub fn decode_gamepackets( + mut gamepacket_stream: Vec, + compression: Option<&Compression>, + encryption: Option<&mut Encryption>, +) -> Result, ProtoCodecError> { + log::trace!("Decoding gamepackets"); + + gamepacket_stream = decrypt_gamepackets::(gamepacket_stream, encryption)?; + gamepacket_stream = decompress_gamepackets::(gamepacket_stream, compression)?; + let gamepackets = separate_gamepackets::(gamepacket_stream)?; + + Ok(gamepackets) +} + +fn batch_gamepackets( + gamepackets: &[T::GamePacketType], +) -> Result, ProtoCodecError> { + let gamepacket_stream_size = gamepackets + .iter() + .map(T::GamePacketType::get_size_prediction) + .sum::(); + + // Create a Vector with the predicted size + let mut gamepacket_stream = Vec::with_capacity(gamepacket_stream_size); + + // Batch all gamepackets together + gamepackets.iter().try_for_each(|gamepacket| { + gamepacket.pk_serialize( + &mut gamepacket_stream, + SubClientID::PrimaryClient, + SubClientID::PrimaryClient, + ) + })?; + + Ok(gamepacket_stream) +} + +fn separate_gamepackets( + gamepacket_stream: Vec, +) -> Result, ProtoCodecError> { + let mut gamepacket_stream = Cursor::new(gamepacket_stream.as_slice()); + let mut gamepackets = vec![]; + + loop { + if gamepacket_stream.position() == gamepacket_stream.get_ref().len() as u64 { + break; + } + + gamepackets.push(T::GamePacketType::pk_deserialize(&mut gamepacket_stream)?.0); + } + + Ok(gamepackets) +} + +pub fn compress_gamepackets( + mut gamepacket_stream: Vec, + compression: Option<&Compression>, +) -> Result, ProtoCodecError> { + if let Some(compression) = compression { + gamepacket_stream = compression.compress(gamepacket_stream)?; + } + + Ok(gamepacket_stream) +} + +pub fn decompress_gamepackets( + mut gamepacket_stream: Vec, + compression: Option<&Compression>, +) -> Result, ProtoCodecError> { + if let Some(compression) = compression { + gamepacket_stream = compression.decompress(gamepacket_stream)?; + } + + Ok(gamepacket_stream) +} + +pub fn encrypt_gamepackets( + mut gamepacket_stream: Vec, + encryption: Option<&mut Encryption>, +) -> Result, ProtoCodecError> { + if let Some(encryption) = encryption { + gamepacket_stream = encryption.encrypt(gamepacket_stream)?; + } + + Ok(gamepacket_stream) +} + +pub fn decrypt_gamepackets( + mut gamepacket_stream: Vec, + encryption: Option<&mut Encryption>, +) -> Result, ProtoCodecError> { + if let Some(encryption) = encryption { + gamepacket_stream = encryption.decrypt(gamepacket_stream)?; + } + + Ok(gamepacket_stream) +} diff --git a/crates/proto/src/compression.rs b/crates/proto/src/compression.rs index 65774d5d..1ef3303e 100644 --- a/crates/proto/src/compression.rs +++ b/crates/proto/src/compression.rs @@ -1,10 +1,12 @@ -use std::io; -use std::io::Write; -use std::sync::Arc; +use bedrockrs_proto_core::error::CompressionError; +use byteorder::{ReadBytesExt, WriteBytesExt}; +use flate2::Compression as CompressionLevel; +use flate2::{read::DeflateDecoder, write::DeflateEncoder}; +use snap::{read::FrameDecoder as SnapDecoder, write::FrameEncoder as SnapEncoder}; +use std::io::{Cursor, Read, Write}; +use std::mem::size_of; -use crate::error::CompressionError; - -#[derive(Clone)] +#[derive(Debug, Clone)] pub enum Compression { Zlib { threshold: u16, @@ -24,109 +26,118 @@ pub enum Compression { } impl Compression { - /// Used for identifying the compression method used by a given packet - #[inline] - pub const fn id_u8(&self) -> u8 { - match self { - Compression::Zlib { .. } => 0x00, - Compression::Snappy { .. } => 0x01, - Compression::None => u8::MAX, - } - } + const ID_ZLIB: u8 = 0; + const ID_SNAPPY: u8 = 1; + const ID_NONE: u8 = u8::MAX; - /// Used in the NetworkSettingsPacket to identify which - /// CompressionMethod should be used + /// Used in the [NetworkSettingsPacket](crate::version::v729::packets::network_settings::NetworkSettingsPacket) + /// to identify which Compression should be used for the Connection. #[inline] pub const fn id_u16(&self) -> u16 { match self { - Compression::Zlib { .. } => 0x0000, - Compression::Snappy { .. } => 0x0001, + Compression::Zlib { .. } => 0, + Compression::Snappy { .. } => 1, Compression::None => u16::MAX, } } - /// Specifies if functions like [`Self::compress`] and [`Self::decompress`] need to be used. - /// This is needed for optimizing compression. - #[inline] - pub const fn needed(&self) -> bool { - match self { - Compression::Zlib { .. } => true, - Compression::Snappy { .. } => true, - Compression::None => false, - } - } - /// Get the compression threshold of the Compression. #[inline] pub fn threshold(&self) -> u16 { match self { Compression::Zlib { threshold, .. } => *threshold, - Compression::Snappy { threshold, .. } => *threshold, + Compression::Snappy { threshold } => *threshold, Compression::None => 0, } } /// Compress the given uncompressed src stream into the given dst stream - /// with the compressed data + /// with the compressed data. #[inline] - pub fn compress(&self, src: &[u8], dst: &mut Vec) -> Result<(), CompressionError> { - match self { + pub fn compress(&self, src: Vec) -> Result, CompressionError> { + // Add one extra byte for the compression method id + let mut dst = Vec::with_capacity(src.len() + size_of::()); + + if self.threshold() as usize >= src.len() { + dst.write_u8(Self::ID_NONE)?; + dst.write_all(src.as_slice())?; + + return Ok(dst); + } + + let dst = match self { Compression::Zlib { - threshold: _, - compression_level, + compression_level, .. } => { - let mut encoder = flate2::write::DeflateEncoder::new( - dst, - flate2::Compression::new(*compression_level as u32), - ); + dst.write_u8(Self::ID_ZLIB)?; + + let mut encoder = + DeflateEncoder::new(dst, CompressionLevel::new(*compression_level as u32)); + + encoder + .write_all(src.as_slice()) + .map_err(|err| CompressionError::ZlibError(Box::new(err)))?; encoder - .write_all(src) - .map_err(|e| CompressionError::ZlibError(Arc::new(e))) + .finish() + .map_err(|err| CompressionError::ZlibError(Box::new(err)))? } Compression::Snappy { .. } => { - let mut encoder = snap::write::FrameEncoder::new(dst); + dst.write_u8(Self::ID_SNAPPY)?; + + let mut encoder = SnapEncoder::new(dst); + + encoder + .write_all(src.as_slice()) + .map_err(CompressionError::SnappyError)?; encoder - .write_all(src) - .map_err(|e| CompressionError::SnappyError(Arc::new(e))) + .into_inner() + .map_err(|err| CompressionError::SnappyError(err.into_error()))? } Compression::None => { - // unnecessary copying, this fn shouldn't be called when `compression_needed` returns false - dst.write_all(src) - .map_err(|e| CompressionError::IOError(Arc::new(e))) + // Compression method id for No Compression + dst.write_u8(Self::ID_NONE)?; + dst.write_all(src.as_slice())?; + + dst } - } + }; + + Ok(dst) } /// Decompress the given compressed src stream into the given dst stream /// with the decompressed data #[inline] - pub fn decompress(&self, src: &[u8], dst: &mut Vec) -> Result<(), CompressionError> { - match self { - Compression::Zlib { .. } => { - let mut decoder = flate2::read::DeflateDecoder::new(src); + pub fn decompress(&self, mut src: Vec) -> Result, CompressionError> { + let mut stream = Cursor::new(src.as_slice()); - match io::copy(&mut decoder, dst) { - Ok(_) => Ok(()), - Err(e) => Err(CompressionError::ZlibError(Arc::new(e))), - } - } - Compression::Snappy { .. } => { - let mut decoder = snap::read::FrameDecoder::new(src); + let compression_method = stream.read_u8()?; - match io::copy(&mut decoder, dst) { - Ok(_) => Ok(()), - Err(e) => Err(CompressionError::SnappyError(Arc::new(e))), - } + src.drain(..1); + + let dst = match compression_method { + Self::ID_ZLIB => { + let mut dst = Vec::with_capacity(src.len()); + + let mut decoder = DeflateDecoder::new(src.as_slice()); + decoder.read_to_end(&mut dst)?; + + dst } - Compression::None => { - // unnecessary copying, this fn shouldn't be called when `compression_needed` returns false - match dst.write_all(src) { - Ok(_) => Ok(()), - Err(e) => Err(CompressionError::IOError(Arc::new(e))), - } + Self::ID_SNAPPY => { + let mut dst = Vec::with_capacity(src.len()); + + let mut decoder = SnapDecoder::new(src.as_slice()); + decoder.read_to_end(&mut dst)?; + + dst } - } + Self::ID_NONE => src, + other => return Err(CompressionError::UnknownCompressionMethod(other)), + }; + + Ok(dst) } } diff --git a/crates/proto/src/connection.rs b/crates/proto/src/connection.rs deleted file mode 100644 index 815dd024..00000000 --- a/crates/proto/src/connection.rs +++ /dev/null @@ -1,530 +0,0 @@ -use std::future::Future; -use std::io::{Cursor, Write}; -use std::sync::Arc; -use std::time::Duration; - -use bedrockrs_core::int::LE; -use tokio::select; -use tokio::sync::{broadcast, watch}; -use tokio::time::interval; - -use crate::compression::Compression; -use crate::encryption::Encryption; -use crate::error::ConnectionError; -use crate::gamepackets::GamePackets; -use crate::sub_client::SubClientID; -use crate::transport_layer::TransportLayerConnection; - -pub struct Connection { - /// Represents the connections internal transport layer, this allows using different - /// transport layers with the client or proxies, this can improve performance. - connection: TransportLayerConnection, - /// Represents the connections' compression, the compression gets initialized in the - /// login process. - pub compression: Option, - /// Represents the connections encryption, the encryption gets initialized in the - /// login process, if encryption is allowed. - pub encryption: Option, - pub cache_supported: bool, -} - -impl Connection { - pub fn from_transport_conn(conn: TransportLayerConnection) -> Self { - Self { - connection: conn, - compression: None, - encryption: None, - cache_supported: false, - } - } - - pub async fn send(&mut self, gamepackets: &[GamePackets]) -> Result<(), ConnectionError> { - let mut pk_stream = vec![]; - - // Batch all gamepackets together - for game_packet in gamepackets { - // Write gamepacket - game_packet - .pk_serialize( - &mut pk_stream, - SubClientID::PrimaryClient, - SubClientID::PrimaryClient, - ) - .map_err(ConnectionError::ProtoCodecError)? - } - - // Compress the data depending on compression method - let compressed_stream = match &self.compression { - Some(compression) => { - let mut compressed_stream = vec![]; - - LE::new(compression.id_u8()) - .write(&mut compressed_stream) - .map_err(|e| ConnectionError::IOError(Arc::new(e)))?; - - // TODO: Overflow checking - if compression.needed() && pk_stream.len() as u16 > compression.threshold() { - compression - .compress(pk_stream.as_slice(), &mut compressed_stream) - .map_err(ConnectionError::CompressError)?; - } else { - compressed_stream - .write(pk_stream.as_slice()) - .map_err(|e| ConnectionError::IOError(Arc::new(e)))?; - }; - - compressed_stream - } - // If no compression is set none copy the packet stream - None => pk_stream, - }; - - // Encrypt the compressed data - let encrypted_stream = match &self.encryption { - Some(encryption) => { - todo!("Encrypt the data (after compression)") - } - None => compressed_stream, - }; - - // Send the data - self.connection - .send(&Cursor::new(&encrypted_stream)) - .await - .map_err(ConnectionError::TransportError) - } - - pub async fn send_raw(&mut self, data: &[u8]) -> Result<(), ConnectionError> { - // Send the data - match self.connection.send(&Cursor::new(data)).await { - Ok(_) => {} - Err(e) => return Err(ConnectionError::TransportError(e)), - } - - Ok(()) - } - - pub async fn recv(&mut self) -> Result, ConnectionError> { - let mut stream = vec![]; - - // Receive data and turn it into cursor - match self.connection.recv(&mut stream).await { - Ok(_) => {} - Err(e) => return Err(ConnectionError::TransportError(e)), - }; - - let stream = Cursor::new(stream.as_slice()); - - let mut decrypted_stream = match &self.encryption { - Some(encryption) => { - todo!("Decrypt the data (before decompression)") - } - None => stream, - }; - - let mut decompressed_stream = vec![]; - - // Decompress data - let mut decompressed_stream = match &self.compression { - Some(compression) => { - match LE::::read(&mut decrypted_stream) { - Ok(v) => { - if v.into_inner() != compression.id_u8() { - // TODO: Handle invalid compression method - } - } - Err(_) => {} - }; - - let pos = decrypted_stream.position() as usize; - - compression - .decompress( - &decrypted_stream.into_inner()[pos..], - &mut decompressed_stream, - ) - .map_err(|e| ConnectionError::CompressError(e))?; - - Cursor::new(decompressed_stream.as_slice()) - } - None => decrypted_stream, - }; - - let mut gamepackets = vec![]; - - // Read gamepacket loop - 'gamepacket_read: loop { - // Deserialize gamepacket - match GamePackets::pk_deserialize(&mut decompressed_stream) { - Ok(v) => gamepackets.push(v.0), - Err(e) => return Err(ConnectionError::ProtoCodecError(e)), - }; - - // Is at the end of batched packet data cursor - // TODO: Overflow checking - if decompressed_stream.position() == decompressed_stream.get_ref().len() as u64 { - break 'gamepacket_read; - } - } - - Ok(gamepackets) - } - - pub async fn recv_raw(&mut self) -> Result, ConnectionError> { - let mut stream = vec![]; - - // Send the data - match self.connection.recv(&mut stream).await { - Ok(_) => {} - Err(e) => return Err(ConnectionError::TransportError(e)), - } - - Ok(stream) - } - - pub async fn close(self) { - self.connection.close().await; - } - - pub async fn into_shard( - mut self, - flush_interval: Duration, - packet_buffer_size: usize, - ) -> ConnectionShard { - let (shard_pk_sender, mut task_pk_receiver) = - broadcast::channel::(packet_buffer_size); - let (task_pk_sender, shard_pk_receiver) = - broadcast::channel::>(packet_buffer_size); - - let (shard_flush_request_sender, mut task_flush_request_receiver) = watch::channel(()); - let (task_flush_complete_sender, mut shard_flush_complete_receiver) = watch::channel(()); - - let (shard_close_sender, mut task_close_receiver) = watch::channel(()); - - let (shard_compression_sender, mut task_compression_receiver) = - watch::channel(self.compression.clone()); - let (shard_compression_request_sender, mut task_compression_request_receiver) = - watch::channel(()); - let (mut task_compression_sender, shard_compression_receiver) = - watch::channel(self.compression.clone()); - - let (shard_encryption_sender, mut task_encryption_receiver) = - watch::channel(self.encryption.clone()); - let (shard_encryption_request_sender, mut task_encryption_request_receiver) = - watch::channel(()); - let (mut task_encryption_sender, shard_encryption_receiver) = - watch::channel(self.encryption.clone()); - - let (shard_cache_supported_sender, mut task_cache_supported_receiver) = - watch::channel(self.cache_supported.clone()); - let (shard_cache_supported_request_sender, mut task_cache_supported_request_receiver) = - watch::channel(()); - let (mut task_cache_supported_sender, shard_cache_supported_receiver) = - watch::channel(self.cache_supported.clone()); - - tokio::spawn(async move { - let mut flush_interval = interval(flush_interval); - let mut send_buffer = vec![]; - - 'select_loop: loop { - select! { - _ = task_close_receiver.changed() => { - break 'select_loop - } - res = task_compression_receiver.changed() => { - if let Err(_) = res { - break 'select_loop - } - - self.compression = task_compression_receiver.borrow_and_update().to_owned(); - } - res = task_encryption_receiver.changed() => { - if let Err(_) = res { - break 'select_loop - } - - self.encryption = task_encryption_receiver.borrow_and_update().to_owned(); - } - res = task_cache_supported_receiver.changed() => { - if let Err(_) = res { - break 'select_loop - } - - self.cache_supported = task_cache_supported_receiver.borrow_and_update().to_owned(); - } - res = task_compression_request_receiver.changed() => { - if let Err(_) = res { - break 'select_loop - } - - if let Err(_) = task_compression_sender.send(self.compression.clone()) { - break 'select_loop - } - } - res = task_encryption_request_receiver.changed() => { - if let Err(_) = res { - break 'select_loop - } - - if let Err(_) = task_encryption_sender.send(self.encryption.clone()) { - break 'select_loop - } - } - res = task_cache_supported_request_receiver.changed() => { - if let Err(_) = res { - break 'select_loop - } - - if let Err(_) = task_cache_supported_sender.send(self.cache_supported.clone()) { - break 'select_loop - } - } - res = self.recv() => { - match res { - Ok(pks) => { - for pk in pks { - if task_pk_sender.send(Ok(pk)).is_err() { - break 'select_loop - } - } - } - Err(e) => { - if task_pk_sender.send(Err(e)).is_err() { - break 'select_loop - } - } - } - } - res = task_pk_receiver.recv() => { - if res.is_err() { - break 'select_loop - } - - match res { - Ok(pk) => { send_buffer.push(pk); } - Err(e) => { break 'select_loop } - }; - } - res = task_flush_request_receiver.changed() => { - if res.is_err() { - break 'select_loop - } - - if !send_buffer.is_empty() { - if let Err(_) = self.send(send_buffer.as_slice()).await { - break 'select_loop - } - - if task_flush_complete_sender.send(()).is_err() { - break 'select_loop - } - - send_buffer = vec![]; - } - } - _ = flush_interval.tick() => { - if !send_buffer.is_empty() { - if (self.send(send_buffer.as_slice()).await).is_err() { - break 'select_loop - } - - send_buffer = vec![]; - } - } - } - } - - self.connection.close().await; - }); - - ConnectionShard { - pk_sender: shard_pk_sender, - pk_receiver: shard_pk_receiver, - - flush_sender: shard_flush_request_sender, - flush_receiver: shard_flush_complete_receiver, - - close_sender: shard_close_sender, - - compression_sender: shard_compression_sender, - compression_request_sender: shard_compression_request_sender, - compression_receiver: shard_compression_receiver, - - encryption_sender: shard_encryption_sender, - encryption_request_sender: shard_encryption_request_sender, - encryption_receiver: shard_encryption_receiver, - - cache_supported_sender: shard_cache_supported_sender, - cache_supported_request_sender: shard_cache_supported_request_sender, - cache_supported_receiver: shard_cache_supported_receiver, - } - } -} - -pub struct ConnectionShard { - pk_sender: broadcast::Sender, - pk_receiver: broadcast::Receiver>, - - flush_sender: watch::Sender<()>, - flush_receiver: watch::Receiver<()>, - - close_sender: watch::Sender<()>, - - compression_sender: watch::Sender>, - compression_request_sender: watch::Sender<()>, - compression_receiver: watch::Receiver>, - - encryption_sender: watch::Sender>, - encryption_request_sender: watch::Sender<()>, - encryption_receiver: watch::Receiver>, - - cache_supported_sender: watch::Sender, - cache_supported_request_sender: watch::Sender<()>, - cache_supported_receiver: watch::Receiver, -} - -impl ConnectionShard { - pub async fn send(&mut self, pk: GamePackets) -> Result<(), ConnectionError> { - match self.pk_sender.send(pk) { - Ok(_) => Ok(()), - Err(_) => Err(ConnectionError::ConnectionClosed), - } - } - - pub async fn recv(&mut self) -> Result { - match self.pk_receiver.recv().await { - Ok(pk) => pk, - Err(_) => Err(ConnectionError::ConnectionClosed), - } - } - - pub async fn flush(&mut self) -> Result<(), ConnectionError> { - match self.flush_sender.send(()) { - Ok(_) => {} - Err(_) => return Err(ConnectionError::ConnectionClosed), - } - - match self.flush_receiver.changed().await { - Ok(_) => Ok(()), - Err(_) => Err(ConnectionError::ConnectionClosed), - } - } - - pub async fn close(mut self) -> Result<(), ConnectionError> { - match self.flush().await { - Ok(_) => {} - Err(e) => return Err(e), - } - - match self.close_sender.send(()) { - Ok(_) => { /* has been closed successfully */ } - Err(_) => { /* has already been closed */ } - }; - - Ok(()) - } - - pub async fn set_compression( - &mut self, - compression: Option, - ) -> Result<(), ConnectionError> { - match self.compression_sender.send(compression) { - Ok(_) => Ok(()), - Err(_) => Err(ConnectionError::ConnectionClosed), - } - } - - pub async fn get_compression(&mut self) -> Result, ConnectionError> { - match self.compression_request_sender.send(()) { - Ok(_) => {} - Err(_) => return Err(ConnectionError::ConnectionClosed), - }; - - match self.compression_receiver.changed().await { - Ok(_) => Ok(self - .compression_receiver - .borrow_and_update() - .clone() - .to_owned()), - Err(_) => Err(ConnectionError::ConnectionClosed), - } - } - - pub async fn set_encryption( - &mut self, - encryption: Option, - ) -> Result<(), ConnectionError> { - match self.encryption_sender.send(encryption) { - Ok(_) => Ok(()), - Err(_) => Err(ConnectionError::ConnectionClosed), - } - } - - pub async fn get_encryption(&mut self) -> Result, ConnectionError> { - match self.encryption_request_sender.send(()) { - Ok(_) => {} - Err(_) => return Err(ConnectionError::ConnectionClosed), - }; - - match self.encryption_receiver.changed().await { - Ok(_) => Ok(self - .encryption_receiver - .borrow_and_update() - .clone() - .to_owned()), - Err(_) => Err(ConnectionError::ConnectionClosed), - } - } - - pub async fn set_cache_supported( - &mut self, - cache_supported: bool, - ) -> Result<(), ConnectionError> { - match self.cache_supported_sender.send(cache_supported) { - Ok(_) => Ok(()), - Err(_) => Err(ConnectionError::ConnectionClosed), - } - } - - pub async fn get_cache_supported(&mut self) -> Result { - match self.cache_supported_request_sender.send(()) { - Ok(_) => {} - Err(_) => return Err(ConnectionError::ConnectionClosed), - }; - - match self.cache_supported_receiver.changed().await { - Ok(_) => Ok(self - .cache_supported_receiver - .borrow_and_update() - .clone() - .to_owned()), - Err(_) => Err(ConnectionError::ConnectionClosed), - } - } -} - -impl Clone for ConnectionShard { - fn clone(&self) -> Self { - Self { - pk_sender: self.pk_sender.clone(), - pk_receiver: self.pk_receiver.resubscribe(), - - flush_sender: self.flush_sender.clone(), - flush_receiver: self.flush_receiver.clone(), - - close_sender: self.close_sender.clone(), - - compression_sender: self.compression_sender.clone(), - compression_request_sender: self.compression_request_sender.clone(), - compression_receiver: self.compression_receiver.clone(), - - encryption_sender: self.encryption_sender.clone(), - encryption_request_sender: self.compression_request_sender.clone(), - encryption_receiver: self.encryption_receiver.clone(), - - cache_supported_sender: self.cache_supported_sender.clone(), - cache_supported_request_sender: self.cache_supported_request_sender.clone(), - cache_supported_receiver: self.cache_supported_receiver.clone(), - } - } -} diff --git a/crates/proto/src/connection/mod.rs b/crates/proto/src/connection/mod.rs new file mode 100644 index 00000000..5158cfc2 --- /dev/null +++ b/crates/proto/src/connection/mod.rs @@ -0,0 +1,74 @@ +pub mod shard; + +use crate::codec::{decode_gamepackets, encode_gamepackets}; +use crate::compression::Compression; +use crate::encryption::Encryption; +use crate::error::ConnectionError; +use crate::helper::ProtoHelper; +use crate::transport::TransportLayerConnection; + +pub struct Connection { + /// Represents the Connection's internal transport layer, which may vary + transport_layer: TransportLayerConnection, + /// Represents the Connection's Compression, the compression gets initialized in the + /// login process + pub compression: Option, + /// Represents the connections encryption, the encryption gets initialized in the + /// login process, if encryption is enabled + pub encryption: Option, +} + +impl Connection { + pub(crate) fn from_transport_conn(transport_layer: TransportLayerConnection) -> Self { + Self { + transport_layer, + compression: None, + encryption: None, + } + } + + pub async fn send( + &mut self, + gamepackets: &[T::GamePacketType], + ) -> Result<(), ConnectionError> { + let gamepacket_stream = encode_gamepackets::( + gamepackets, + self.compression.as_ref(), + self.encryption.as_mut(), + )?; + + self.transport_layer.send(&gamepacket_stream).await?; + + Ok(()) + } + + pub async fn send_raw(&mut self, data: &[u8]) -> Result<(), ConnectionError> { + self.transport_layer.send(data).await?; + + Ok(()) + } + + pub async fn recv( + &mut self, + ) -> Result, ConnectionError> { + let gamepacket_stream = self.transport_layer.recv().await?; + + let gamepackets = decode_gamepackets::( + gamepacket_stream, + self.compression.as_ref(), + self.encryption.as_mut(), + )?; + + Ok(gamepackets) + } + + pub async fn recv_raw(&mut self) -> Result, ConnectionError> { + let stream = self.transport_layer.recv().await?; + + Ok(stream) + } + + pub async fn close(self) { + self.transport_layer.close().await; + } +} diff --git a/crates/proto/src/connection/shard/arc.rs b/crates/proto/src/connection/shard/arc.rs new file mode 100644 index 00000000..532d097d --- /dev/null +++ b/crates/proto/src/connection/shard/arc.rs @@ -0,0 +1,70 @@ +use crate::connection::Connection; +use crate::error::ConnectionError; +use crate::helper::ProtoHelper; +use std::collections::VecDeque; +use std::sync::Arc; +use tokio::sync::RwLock; + +pub fn shard(connection: Connection) -> ConnectionShared { + ConnectionShared:: { + connection: Arc::new(RwLock::new(connection)), + queue_send: Arc::new(RwLock::new(Vec::new())), + queue_recv: Arc::new(RwLock::new(VecDeque::new())), + } +} + +#[derive(Clone)] +pub struct ConnectionShared { + connection: Arc>, + queue_send: Arc>>, + queue_recv: Arc>>, +} + +impl ConnectionShared { + pub async fn write(&mut self, gamepacket: T::GamePacketType) -> Result<(), ConnectionError> { + let mut queue_send = self.queue_send.write().await; + + queue_send.push(gamepacket); + + Ok(()) + } + + pub async fn read(&mut self) -> Option { + let mut queue_recv = self.queue_recv.write().await; + + queue_recv.pop_front() + } + + pub async fn read_all(&mut self) -> Vec { + let mut queue_recv = self.queue_recv.write().await; + queue_recv.make_contiguous(); + queue_recv.drain(..).collect::>() + } + + pub async fn send(&mut self) -> Result<(), ConnectionError> { + let mut gamepackets = self.queue_send.write().await; + let mut conn = self.connection.write().await; + + conn.send::(gamepackets.as_slice()).await?; + + gamepackets.clear(); + + Ok(()) + } + + pub async fn recv(&mut self) -> Result<(), ConnectionError> { + let mut conn = self.connection.write().await; + + let gamepackets = conn.recv::().await?; + + if !gamepackets.is_empty() { + let mut queue_recv = self.queue_recv.write().await; + + for gamepacket in gamepackets { + queue_recv.push_back(gamepacket); + } + } + + Ok(()) + } +} diff --git a/crates/proto/src/connection/shard/mod.rs b/crates/proto/src/connection/shard/mod.rs new file mode 100644 index 00000000..35edc04e --- /dev/null +++ b/crates/proto/src/connection/shard/mod.rs @@ -0,0 +1,2 @@ +pub mod arc; +pub mod task; diff --git a/crates/proto/src/connection/shard/task.rs b/crates/proto/src/connection/shard/task.rs new file mode 100644 index 00000000..2918989e --- /dev/null +++ b/crates/proto/src/connection/shard/task.rs @@ -0,0 +1,208 @@ +use crate::compression::Compression; +use crate::connection::Connection; +use crate::encryption::Encryption; +use crate::error::ConnectionError; +use crate::helper::ProtoHelper; +use tokio::select; +use tokio::sync::watch::Ref; +use tokio::sync::{mpsc, watch}; +use tokio::time::Interval; + +pub async fn shard<'t, T: ProtoHelper + Send + Sync + 't>( + mut connection: Connection, + // TODO: Look into making flush_interval optional + _flush_interval: Interval, + gamepacket_buffer_size: usize, +) -> (ConnectionShardSender, ConnectionShardReceiver) +where + ::GamePacketType: Send + Sync + 'static, +{ + let (gamepacket_tx_task, gamepacket_rx_shard) = mpsc::channel(gamepacket_buffer_size); + let (gamepacket_tx_shard, mut gamepacket_rx_task) = mpsc::channel(gamepacket_buffer_size); + let (close_tx, mut close_rx) = watch::channel(()); + let (flush_tx, mut flush_rx) = watch::channel(()); + let (compression_tx, mut compression_rx) = watch::channel(None); + let (encryption_tx, mut encryption_rx) = watch::channel(None); + + let shards = ( + ConnectionShardSender { + gamepacket_sender: gamepacket_tx_shard, + close_sender: close_tx.clone(), + flush_sender: flush_tx, + compression_sender: compression_tx.clone(), + compression_receiver: compression_rx.clone(), + encryption_sender: encryption_tx.clone(), + encryption_receiver: encryption_rx.clone(), + }, + ConnectionShardReceiver { + gamepacket_receiver: gamepacket_rx_shard, + close_sender: close_tx.clone(), + compression_receiver: compression_rx.clone(), + encryption_receiver: encryption_rx.clone(), + }, + ); + + tokio::spawn(async move { + let mut gamepackets = Vec::with_capacity(gamepacket_buffer_size); + 'select: loop { + select! { + _ = close_rx.changed() => { + break 'select; + }, + res = flush_rx.changed() => { + if res.is_err() { + break 'select; + } + + connection.send::(gamepackets.as_slice()).await.unwrap(); + //println!("Sent {gamepackets:#?}"); + gamepackets.clear(); + }, + res = connection.recv::() => { + match res { + Ok(gamepackets) => for gamepacket in gamepackets { + //println!("Received {gamepacket:#?}"); + gamepacket_tx_task.send(Ok(gamepacket)).await.unwrap(); + }, + Err(err) => gamepacket_tx_task.send(Err(err)).await.unwrap(), + } + }, + res = gamepacket_rx_task.recv() => { + match res { + Some(gamepacket) => gamepackets.push(gamepacket), + None => break 'select, + } + }, + res = compression_rx.changed() => { + if res.is_err() { + break 'select; + } + + connection.compression = compression_rx.borrow().clone(); + }, + res = encryption_rx.changed() => { + if res.is_err() { + break 'select; + } + + connection.encryption = encryption_rx.borrow().clone(); + } + } + } + }); + + shards +} + +#[derive(Debug, Clone)] +pub struct ConnectionShardSender { + gamepacket_sender: mpsc::Sender, + + close_sender: watch::Sender<()>, + + flush_sender: watch::Sender<()>, + + compression_sender: watch::Sender>, + compression_receiver: watch::Receiver>, + + encryption_sender: watch::Sender>, + encryption_receiver: watch::Receiver>, +} + +impl ConnectionShardSender { + pub async fn send(&mut self, packet: T::GamePacketType) -> Result<(), ConnectionError> { + self.gamepacket_sender + .send(packet) + .await + .map_err(|_| ConnectionError::ConnectionClosed)?; + Ok(()) + } + + pub async fn flush(&mut self) -> Result<(), ConnectionError> { + self.flush_sender + .send(()) + .map_err(|_| ConnectionError::ConnectionClosed)?; + Ok(()) + } + + pub fn get_compression(&mut self) -> Result, ConnectionError> { + Ok(self.compression_receiver.borrow().clone()) + } + + pub fn get_compression_ref(&mut self) -> Result>, ConnectionError> { + Ok(self.compression_receiver.borrow()) + } + + pub fn set_compression( + &mut self, + compression: Option, + ) -> Result<(), ConnectionError> { + self.compression_sender + .send(compression) + .map_err(|_| ConnectionError::ConnectionClosed)?; + Ok(()) + } + + pub fn get_encryption(&mut self) -> Result, ConnectionError> { + Ok(self.encryption_receiver.borrow().clone()) + } + + pub fn get_encryption_ref(&mut self) -> Result>, ConnectionError> { + Ok(self.encryption_receiver.borrow()) + } + + pub fn set_encryption( + &mut self, + encryption: Option, + ) -> Result<(), ConnectionError> { + self.encryption_sender + .send(encryption) + .map_err(|_| ConnectionError::ConnectionClosed)?; + Ok(()) + } + + pub async fn close(self) { + // Already closed if Error occurs + let _ = self.close_sender.send(()); + } +} + +#[derive(Debug)] +pub struct ConnectionShardReceiver { + pub(crate) gamepacket_receiver: mpsc::Receiver>, + + pub(crate) close_sender: watch::Sender<()>, + + pub(crate) compression_receiver: watch::Receiver>, + pub(crate) encryption_receiver: watch::Receiver>, +} + +impl ConnectionShardReceiver { + pub async fn recv(&mut self) -> Result { + self.gamepacket_receiver + .recv() + .await + .unwrap_or_else(|| Err(ConnectionError::ConnectionClosed)) + } + + pub fn get_compression(&mut self) -> Result, ConnectionError> { + Ok(self.compression_receiver.borrow().clone()) + } + + pub fn get_compression_ref(&mut self) -> Result>, ConnectionError> { + Ok(self.compression_receiver.borrow()) + } + + pub fn get_encryption(&mut self) -> Result, ConnectionError> { + Ok(self.encryption_receiver.borrow().clone()) + } + + pub fn get_encryption_ref(&mut self) -> Result>, ConnectionError> { + Ok(self.encryption_receiver.borrow()) + } + + pub async fn close(self) { + // Already closed if Error occurs + let _ = self.close_sender.send(()); + } +} diff --git a/crates/proto/src/encryption.rs b/crates/proto/src/encryption.rs index a8825de9..9bf5e305 100644 --- a/crates/proto/src/encryption.rs +++ b/crates/proto/src/encryption.rs @@ -1,4 +1,6 @@ -#[derive(Clone)] +use bedrockrs_proto_core::error::EncryptionError; + +#[derive(Debug, Clone)] pub struct Encryption { send_counter: u64, buf: [u8; 8], @@ -10,15 +12,15 @@ impl Encryption { unimplemented!() } - pub fn decrypt(&mut self, data: &Vec) -> Vec { + pub fn decrypt(&mut self, _src: Vec) -> Result, EncryptionError> { unimplemented!() } - pub fn encrypt(&mut self, data: &Vec) -> Vec { + pub fn encrypt(&mut self, _src: Vec) -> Result, EncryptionError> { unimplemented!() } - pub fn verify(&mut self, data: &Vec) -> Result<(), ()> { + pub fn verify(&mut self, _src: &[u8]) -> Result<(), EncryptionError> { unimplemented!() } } diff --git a/crates/proto/src/error.rs b/crates/proto/src/error.rs index e3490534..34d6c782 100644 --- a/crates/proto/src/error.rs +++ b/crates/proto/src/error.rs @@ -1,15 +1,10 @@ use io::Error as IOError; -use std::error::Error; use std::io; -use std::sync::Arc; use bedrockrs_proto_core::error::ProtoCodecError; -use rak_rs::connection::queue::SendQueueError; -use rak_rs::connection::RecvError; -use rak_rs::error::server::ServerError; use thiserror::Error; -use crate::info::RAKNET_GAME_PACKET_ID; +use crate::info::RAKNET_GAMEPACKET_ID; #[derive(Error, Debug)] pub enum ListenerError { @@ -23,64 +18,44 @@ pub enum ListenerError { TransportListenerError(#[from] TransportLayerError), } -#[derive(Error, Debug, Clone)] +#[derive(Error, Debug)] pub enum ConnectionError { - #[error("IO Error: {0}")] - IOError(#[from] Arc), - #[error("Proto Codec Error: {0}")] + #[error("ProtoCodec Error: {0}")] ProtoCodecError(#[from] ProtoCodecError), #[error("Connection Closed")] ConnectionClosed, #[error("Transport Error: {0}")] - TransportError(TransportLayerError), - #[error("Compression Error: {0}")] - CompressError(CompressionError), - #[error("Invalid RakNet Header, expected: {RAKNET_GAME_PACKET_ID}, got: {0}")] - InvalidRakNetHeader(u8), - #[error("Unknown Compression method, got: {0}")] - UnknownCompressionMethod(u8), - #[error("Wrong Compression method")] - WrongCompressionMethod(u8), -} - -#[derive(Error, Debug, Clone)] -pub enum CompressionError { - #[error("Zlib Error: {0}")] - ZlibError(#[from] Arc), - #[error("Snappy Error: {0}")] - SnappyError(#[from] Arc), + TransportError(#[from] TransportLayerError), #[error("IO Error: {0}")] - IOError(Arc), + IOError(#[from] IOError), } #[derive(Error, Debug)] -pub enum LoginError { - #[error("Connection Error: {0}")] - ConnectionError(#[from] ConnectionError), - #[error("Login aborted, reason: {reason}")] - Abort { reason: String }, - #[error("Wrong protocol version (client: {client}, server: {server:?})")] - WrongProtocolVersion { client: i32, server: Vec }, - #[error("Format Error: {0}")] - FormatError(String), -} - -#[derive(Error, Debug, Clone)] pub enum TransportLayerError { #[error("IO Error: {0}")] - IOError(#[from] Arc), - #[error("Raknet UDP Error: {0}")] - RaknetUDPError(#[from] RaknetError), + IOError(#[from] IOError), + #[error("RakNet Error: {0}")] + RakNetError(#[from] RakNetError), + #[error("Quic Error: {0}")] + QuicError(#[from] QuicError), } #[derive(Error, Debug, Clone)] -pub enum RaknetError { - #[error("Error while Receive: {0}")] - RecvError(#[from] RecvError), - #[error("Error while Send: {0}")] - SendError(SendQueueError), +pub enum RakNetError { + #[error("Receive Error: {0}")] + RecvError(#[from] rak_rs::connection::RecvError), + #[error("Send Error: {0}")] + SendError(#[from] rak_rs::connection::queue::SendQueueError), #[error("Server Error: {0}")] - ServerError(#[from] ServerError), + ServerError(#[from] rak_rs::error::server::ServerError), + #[error("Invalid RakNet Header (expected: {RAKNET_GAMEPACKET_ID}, got: {0})")] + InvalidRakNetHeader(u8), #[error("Format Error: {0}")] - FormatError(String), + FormatError(&'static str), +} + +#[derive(Error, Debug, Clone)] +pub enum QuicError { + // #[error("Stream Error: {0}")] + // StreamError(s2n_quic::stream::Error), } diff --git a/crates/proto/src/helper.rs b/crates/proto/src/helper.rs new file mode 100644 index 00000000..bfa649e3 --- /dev/null +++ b/crates/proto/src/helper.rs @@ -0,0 +1,5 @@ +use bedrockrs_proto_core::GamePacketsAll; + +pub trait ProtoHelper { + type GamePacketType: GamePacketsAll + Send; +} diff --git a/crates/proto/src/info.rs b/crates/proto/src/info.rs index b58d01a4..6913a831 100644 --- a/crates/proto/src/info.rs +++ b/crates/proto/src/info.rs @@ -1,6 +1,5 @@ -pub const RAKNET_GAME_PACKET_ID: u8 = 0xfe; -pub const PROTOCOL_VERSION: i32 = 685; -pub const MINECRAFT_EDITION_MOTD: &'static str = "MCPE"; +pub const RAKNET_GAMEPACKET_ID: u8 = 0xfe; +pub const MINECRAFT_EDITION_MOTD: &str = "MCPE"; pub const MAGIC: [u8; 16] = [ 0x00, 0xff, 0xff, 0x0, 0xfe, 0xfe, 0xfe, 0xfe, 0xfd, 0xfd, 0xfd, 0xfd, 0x12, 0x34, 0x56, 0x78, diff --git a/crates/proto/src/lib.rs b/crates/proto/src/lib.rs index 1bf699cc..41ede19d 100644 --- a/crates/proto/src/lib.rs +++ b/crates/proto/src/lib.rs @@ -1,14 +1,13 @@ -extern crate core; - +pub mod codec; pub mod compression; pub mod connection; pub mod encryption; pub mod error; -pub mod gamepackets; +mod helper; pub mod info; pub mod listener; -pub mod login; -pub mod packets; -mod sub_client; -pub mod transport_layer; -pub mod types; +pub mod transport; +mod version; + +pub use helper::*; +pub use version::*; diff --git a/crates/proto/src/listener.rs b/crates/proto/src/listener.rs index 773871e0..15d25490 100644 --- a/crates/proto/src/listener.rs +++ b/crates/proto/src/listener.rs @@ -2,15 +2,16 @@ use core::net::SocketAddr; use rak_rs::mcpe::motd::Gamemode; use rak_rs::Motd; -use rand::RngCore; +use rand::random; use crate::connection::Connection; -use crate::error::{ListenerError, RaknetError, TransportLayerError}; -use crate::info::{MINECRAFT_EDITION_MOTD, PROTOCOL_VERSION}; -use crate::transport_layer::TransportLaterListener; +use crate::error::{ListenerError, RakNetError, TransportLayerError}; +use crate::info::MINECRAFT_EDITION_MOTD; +use crate::transport::TransportLayerListener; +use crate::version::v729::info::PROTOCOL_VERSION; pub struct Listener { - listener: TransportLaterListener, + listener: TransportLayerListener, name: String, sub_name: String, player_max: u32, @@ -29,23 +30,16 @@ impl Listener { socket_addr: SocketAddr, nintendo_limited: bool, ) -> Result { - // Bind the Raknet Listener - let rak_listener = rak_rs::Listener::bind(socket_addr).await; - - // Check for success - let mut rak_listener = match rak_listener { - Ok(v) => v, - Err(e) => { - return Err(ListenerError::TransportListenerError( - TransportLayerError::RaknetUDPError(RaknetError::ServerError(e)), - )); - } - }; + let mut rak_listener = rak_rs::Listener::bind(socket_addr).await.map_err(|err| { + ListenerError::TransportListenerError(TransportLayerError::RakNetError( + RakNetError::ServerError(err), + )) + })?; // generate a random guid - let guid: u64 = rand::thread_rng().next_u64(); + let guid: u64 = random::(); - // Setup the motd + // Set up the motd rak_listener.motd = Motd { edition: String::from(MINECRAFT_EDITION_MOTD), version: display_version, @@ -62,7 +56,7 @@ impl Listener { }; Ok(Self { - listener: TransportLaterListener::RaknetUDP(rak_listener), + listener: TransportLayerListener::RakNet(rak_listener), name, sub_name, player_max, @@ -73,17 +67,17 @@ impl Listener { } pub async fn start(&mut self) -> Result<(), ListenerError> { - match self.listener.start().await { - Ok(_) => Ok(()), - Err(e) => Err(ListenerError::TransportListenerError(e)), - } + self.listener.start().await?; + Ok(()) + } + + pub async fn stop(&mut self) -> Result<(), ListenerError> { + self.listener.stop().await?; + Ok(()) } pub async fn accept(&mut self) -> Result { - let rak_conn = match self.listener.accept().await { - Ok(c) => c, - Err(e) => return Err(ListenerError::TransportListenerError(e)), - }; + let rak_conn = self.listener.accept().await?; Ok(Connection::from_transport_conn(rak_conn)) } diff --git a/crates/proto/src/login/add_actor.rs b/crates/proto/src/login/add_actor.rs deleted file mode 100644 index 5295fee2..00000000 --- a/crates/proto/src/login/add_actor.rs +++ /dev/null @@ -1,63 +0,0 @@ -use bedrockrs_core::{int::LE, Vec2, Vec3}; -use bedrockrs_shared::{actor_runtime_id::ActorRuntimeID, actor_unique_id::ActorUniqueID}; - -use crate::{ - connection::ConnectionShard, - error::LoginError, - gamepackets::GamePackets, - packets::add_actor::AddActorPacket, - types::{ - actor_type::ActorType, - property_sync_data::{FloatEntriesList, IntEntriesList, PropertySyncData}, - }, -}; - -use super::provider::LoginProviderServer; - -pub async fn add_actor( - conn: &mut ConnectionShard, - provider: &mut impl LoginProviderServer, -) -> Result<(), LoginError> { - ////////////////////////////////////// - // todo: AddActorPacket - ////////////////////////////////////// - - let add_actor = AddActorPacket { - target_actor_id: ActorUniqueID(610), - target_runtime_id: ActorRuntimeID(403), - actor_type: ActorType::Pig.to_string(), - position: Vec3 { - x: LE::new(4.0), - y: LE::new(8.0), - z: LE::new(7.0), - }, - velocity: Vec3 { - x: LE::new(4.0), - y: LE::new(8.0), - z: LE::new(7.0), - }, - rotation: Vec2 { - x: LE::new(270.0), - y: LE::new(90.0), - }, - y_head_rotation: LE::new(45.0), - y_body_rotation: LE::new(90.0), - attributes: vec![], - actor_data: vec![], - synced_properties: PropertySyncData { - int: IntEntriesList { entries: vec![] }, - float: FloatEntriesList { entries: vec![] }, - }, - actor_links: vec![], - }; - - conn.send(GamePackets::AddEntity(add_actor)) - .await - .map_err(|e| LoginError::ConnectionError(e))?; - - conn.flush() - .await - .map_err(|e| LoginError::ConnectionError(e))?; - - Ok(()) -} diff --git a/crates/proto/src/login/handle.rs b/crates/proto/src/login/handle.rs deleted file mode 100644 index b1bb1d5f..00000000 --- a/crates/proto/src/login/handle.rs +++ /dev/null @@ -1,35 +0,0 @@ -use crate::connection::{Connection, ConnectionShard}; -use crate::error::LoginError; -use crate::login::handshake::handshake; -use crate::login::login::login; -use crate::login::network_settings::network_settings; -use crate::login::packs::packs; -use crate::login::play_status::play_status_login; -use crate::login::provider::{LoginProviderClient, LoginProviderServer}; -use crate::login::start_game::start_game; - -use super::set_title::set_title; - -pub async fn login_to_server( - conn: &mut ConnectionShard, - mut provider: impl LoginProviderServer, -) -> Result<(), LoginError> { - network_settings(conn, &mut provider).await?; - - login(conn, &mut provider).await?; - play_status_login(conn, &mut provider).await?; - - handshake(conn, &mut provider).await?; - - packs(conn, &mut provider).await?; - - start_game(conn, &mut provider).await?; - Ok(()) -} - -pub async fn login_to_client( - conn: &mut Connection, - provider: impl LoginProviderClient, -) -> Result<(), LoginError> { - todo!() -} diff --git a/crates/proto/src/login/handshake.rs b/crates/proto/src/login/handshake.rs deleted file mode 100644 index 8b03e08c..00000000 --- a/crates/proto/src/login/handshake.rs +++ /dev/null @@ -1,14 +0,0 @@ -use crate::connection::ConnectionShard; -use crate::error::LoginError; -use crate::login::provider::LoginProviderServer; - -pub async fn handshake( - conn: &mut ConnectionShard, - provider: &mut impl LoginProviderServer, -) -> Result<(), LoginError> { - if !provider.encryption_enabled() { - return Ok(()); - }; - - todo!("impl the handshake") -} diff --git a/crates/proto/src/login/login.rs b/crates/proto/src/login/login.rs deleted file mode 100644 index bb61f8b1..00000000 --- a/crates/proto/src/login/login.rs +++ /dev/null @@ -1,36 +0,0 @@ -use crate::connection::ConnectionShard; -use crate::error::LoginError; -use crate::gamepackets::GamePackets; -use crate::login::provider::{LoginProviderServer, LoginProviderStatus}; - -pub async fn login( - conn: &mut ConnectionShard, - provider: &mut impl LoginProviderServer, -) -> Result<(), LoginError> { - ////////////////////////////////////// - // Login Packet - ////////////////////////////////////// - - let mut login = match conn.recv().await { - Ok(GamePackets::Login(pk)) => pk, - Ok(other) => { - return Err(LoginError::FormatError(format!( - "Expected Login packet, got: {other:?}" - ))) - } - Err(e) => return Err(LoginError::ConnectionError(e)), - }; - - match provider.on_login_pk(&mut login) { - LoginProviderStatus::ContinueLogin => {} - LoginProviderStatus::AbortLogin { reason } => { - return Err(LoginError::Abort { reason }); - } - }; - - if provider.auth_enabled() { - todo!("impl xbox auth with data from login pk") - }; - - Ok(()) -} diff --git a/crates/proto/src/login/mod.rs b/crates/proto/src/login/mod.rs deleted file mode 100644 index 2145c0f3..00000000 --- a/crates/proto/src/login/mod.rs +++ /dev/null @@ -1,12 +0,0 @@ -pub use handle::*; - -mod add_actor; -pub mod handle; -mod handshake; -mod login; -mod network_settings; -mod packs; -mod play_status; -pub mod provider; -mod set_title; -mod start_game; diff --git a/crates/proto/src/login/network_settings.rs b/crates/proto/src/login/network_settings.rs deleted file mode 100644 index ca6cae17..00000000 --- a/crates/proto/src/login/network_settings.rs +++ /dev/null @@ -1,75 +0,0 @@ -use bedrockrs_core::int::LE; - -use crate::connection::ConnectionShard; -use crate::error::LoginError; -use crate::gamepackets::GamePackets; -use crate::login::provider::{LoginProviderServer, LoginProviderStatus}; -use crate::packets::network_settings::NetworkSettingsPacket; - -pub async fn network_settings( - conn: &mut ConnectionShard, - provider: &mut impl LoginProviderServer, -) -> Result<(), LoginError> { - ////////////////////////////////////// - // Network Settings Request Packet - ////////////////////////////////////// - - let mut network_settings_request = match conn.recv().await { - Ok(GamePackets::NetworkSettingsRequest(pk)) => pk, - Ok(other) => { - return Err(LoginError::FormatError(format!( - "Expected RequestNetworkSettings packet, got: {other:?}" - ))) - } - Err(e) => return Err(LoginError::ConnectionError(e)), - }; - - match provider.on_network_settings_request_pk(&mut network_settings_request) { - LoginProviderStatus::ContinueLogin => {} - LoginProviderStatus::AbortLogin { reason } => { - return Err(LoginError::Abort { reason }); - } - }; - - ////////////////////////////////////// - // Network Settings Packet - ////////////////////////////////////// - - let compression = provider.compression(); - - let mut network_settings = NetworkSettingsPacket { - compression_threshold: LE::new(compression.threshold()), - compression_algorithm: LE::new(compression.id_u16()), - // TODO What do these 3 fields do? - client_throttle_enabled: false, - client_throttle_threshold: 0, - client_throttle_scalar: LE::new(0.0), - }; - - match provider.on_network_settings_pk(&mut network_settings) { - LoginProviderStatus::ContinueLogin => {} - LoginProviderStatus::AbortLogin { reason } => { - return Err(LoginError::Abort { reason }); - } - }; - - match conn - .send(GamePackets::NetworkSettings(network_settings)) - .await - { - Ok(_) => {} - Err(e) => return Err(LoginError::ConnectionError(e)), - } - - match conn.flush().await { - Ok(_) => {} - Err(e) => return Err(LoginError::ConnectionError(e)), - } - - match conn.set_compression(Some(compression)).await { - Ok(_) => {} - Err(e) => return Err(LoginError::ConnectionError(e)), - }; - - Ok(()) -} diff --git a/crates/proto/src/login/packs.rs b/crates/proto/src/login/packs.rs deleted file mode 100644 index 15864e9c..00000000 --- a/crates/proto/src/login/packs.rs +++ /dev/null @@ -1,172 +0,0 @@ -use crate::connection::ConnectionShard; -use crate::error::LoginError; -use crate::gamepackets::GamePackets; -use crate::login::provider::packs::LoginProviderPacks; -use crate::login::provider::{LoginProviderServer, LoginProviderStatus}; -use crate::packets::resource_packs_info::ResourcePacksInfoPacket; -use crate::packets::resource_packs_stack::ResourcePacksStackPacket; -use crate::types::base_game_version::BaseGameVersion; -use crate::types::experiments::Experiments; - -pub async fn packs( - conn: &mut ConnectionShard, - provider: &mut impl LoginProviderServer, -) -> Result<(), LoginError> { - match provider.packs() { - LoginProviderPacks::CDN { - behavior_packs, - resource_packs, - cdn_urls, - } => { - ////////////////////////////////////// - // Resource Packs Info Packet - ////////////////////////////////////// - - // TODO impl this - let mut resource_packs_info = ResourcePacksInfoPacket { - resource_pack_required: false, - has_addon_packs: false, - has_scripts: false, - force_server_packs_enabled: false, - behavior_packs: vec![], - resource_packs: vec![], - cdn_urls: cdn_urls.clone(), - }; - - match provider.on_resource_packs_info_pk(&mut resource_packs_info) { - LoginProviderStatus::ContinueLogin => {} - LoginProviderStatus::AbortLogin { reason } => { - return Err(LoginError::Abort { reason }); - } - }; - - match conn - .send(GamePackets::ResourcePacksInfo(resource_packs_info)) - .await - { - Ok(_) => {} - Err(e) => return Err(LoginError::ConnectionError(e)), - }; - - match conn.flush().await { - Ok(_) => {} - Err(e) => return Err(LoginError::ConnectionError(e)), - }; - - ////////////////////////////////////// - // Resource Pack Client Response - // (/Client Cache Status Packet) - ////////////////////////////////////// - - match conn.recv().await { - Ok(GamePackets::ClientCacheStatus(mut client_cache_status)) => { - match provider.on_client_cache_status_pk(&mut client_cache_status) { - LoginProviderStatus::ContinueLogin => {} - LoginProviderStatus::AbortLogin { reason } => { - return Err(LoginError::Abort { reason }); - } - }; - - if let Err(e) = conn.set_cache_supported(client_cache_status.cache_supported).await { - return Err(LoginError::ConnectionError(e)); - } - - match conn.recv().await { - Ok(GamePackets::ResourcePackClientResponse(mut resource_pack_client_response)) => { - match provider.on_resource_packs_response_pk(&mut resource_pack_client_response) { - LoginProviderStatus::ContinueLogin => {} - LoginProviderStatus::AbortLogin { reason } => { - return Err(LoginError::Abort { reason }); - } - }; - } - Ok(other) => { - return Err(LoginError::FormatError(format!( - "Expected ClientCacheStatus or ResourcePackClientResponse packet, got: {other:?}" - ))) - } - Err(e) => { return Err(LoginError::ConnectionError(e)) } - } - } - Ok(GamePackets::ResourcePackClientResponse(mut resource_pack_client_response)) => { - match provider.on_resource_packs_response_pk(&mut resource_pack_client_response) { - LoginProviderStatus::ContinueLogin => {} - LoginProviderStatus::AbortLogin { reason } => { - return Err(LoginError::Abort { reason }); - } - }; - } - Ok(other) => { - return Err(LoginError::FormatError(format!( - "Expected ClientCacheStatus or ResourcePackClientResponse packet, got: {other:?}" - ))) - } - Err(e) => { return Err(LoginError::ConnectionError(e)) } - } - - ////////////////////////////////////// - // Resource Packs Stack Packet - ////////////////////////////////////// - - // TODO impl this - let mut resource_packs_stack = ResourcePacksStackPacket { - texture_pack_required: false, - addons: vec![], - texture_packs: vec![], - base_game_version: BaseGameVersion(String::from("1.0")), - experiments: Experiments { - experiments: vec![], - ever_toggled: false, - }, - include_editor_packs: false, - }; - - match provider.on_resource_packs_stack_pk(&mut resource_packs_stack) { - LoginProviderStatus::ContinueLogin => {} - LoginProviderStatus::AbortLogin { reason } => { - return Err(LoginError::Abort { reason }); - } - }; - - match conn - .send(GamePackets::ResourcePackStack(resource_packs_stack)) - .await - { - Ok(_) => {} - Err(e) => return Err(LoginError::ConnectionError(e)), - }; - - match conn.flush().await { - Ok(_) => {} - Err(e) => return Err(LoginError::ConnectionError(e)), - }; - - ////////////////////////////////////// - // Resource Pack Client Response - ////////////////////////////////////// - - match conn.recv().await { - Ok(GamePackets::ResourcePackClientResponse(mut resource_pack_client_response)) => { - match provider.on_resource_packs_response_pk(&mut resource_pack_client_response) - { - LoginProviderStatus::ContinueLogin => {} - LoginProviderStatus::AbortLogin { reason } => { - return Err(LoginError::Abort { reason }); - } - }; - } - Ok(other) => { - return Err(LoginError::FormatError(format!( - "Expected ResourcePackClientResponse packet, got: {other:?}" - ))) - } - Err(e) => return Err(LoginError::ConnectionError(e)), - } - } - LoginProviderPacks::DirectNetworkTransfer { .. } => { - todo!("impl LoginProviderbedrockrs_addon::DirectNetworkTransfer in login process") - } - }; - - Ok(()) -} diff --git a/crates/proto/src/login/play_status.rs b/crates/proto/src/login/play_status.rs deleted file mode 100644 index ad70cbea..00000000 --- a/crates/proto/src/login/play_status.rs +++ /dev/null @@ -1,38 +0,0 @@ -use crate::connection::ConnectionShard; -use crate::error::LoginError; -use crate::gamepackets::GamePackets; -use crate::login::provider::{LoginProviderServer, LoginProviderStatus}; -use crate::packets::play_status::PlayStatusPacket; -use crate::types::play_status::PlayStatusType; - -pub async fn play_status_login( - conn: &mut ConnectionShard, - provider: &mut impl LoginProviderServer, -) -> Result<(), LoginError> { - ////////////////////////////////////// - // Play Status Packet (Login) - ////////////////////////////////////// - - let mut play_status = PlayStatusPacket { - status: PlayStatusType::LoginSuccess, - }; - - match provider.on_play_status_pk(&mut play_status) { - LoginProviderStatus::ContinueLogin => {} - LoginProviderStatus::AbortLogin { reason } => { - return Err(LoginError::Abort { reason }); - } - }; - - match conn.send(GamePackets::PlayStatus(play_status)).await { - Ok(_) => {} - Err(e) => return Err(LoginError::ConnectionError(e)), - } - - match conn.flush().await { - Ok(_) => {} - Err(e) => return Err(LoginError::ConnectionError(e)), - }; - - Ok(()) -} diff --git a/crates/proto/src/login/provider/default.rs b/crates/proto/src/login/provider/default.rs deleted file mode 100644 index 717a9970..00000000 --- a/crates/proto/src/login/provider/default.rs +++ /dev/null @@ -1,90 +0,0 @@ -use crate::compression::Compression; -use crate::login::provider::packs::LoginProviderPacks; -use crate::login::provider::{LoginProviderServer, LoginProviderStatus}; -use crate::packets::client_cache_status::ClientCacheStatusPacket; -use crate::packets::login::LoginPacket; -use crate::packets::network_settings::NetworkSettingsPacket; -use crate::packets::network_settings_request::NetworkSettingsRequestPacket; -use crate::packets::play_status::PlayStatusPacket; -use crate::packets::resource_packs_info::ResourcePacksInfoPacket; -use crate::packets::resource_packs_response::ResourcePacksResponsePacket; -use crate::packets::resource_packs_stack::ResourcePacksStackPacket; - -pub struct DefaultLoginProvider { - packs: LoginProviderPacks, -} - -impl DefaultLoginProvider { - pub fn new() -> Self { - Self { - packs: LoginProviderPacks::CDN { - behavior_packs: vec![], - resource_packs: vec![], - cdn_urls: vec![], - }, - } - } -} - -impl Default for DefaultLoginProvider { - fn default() -> Self { - Self::new() - } -} - -impl LoginProviderServer for DefaultLoginProvider { - fn compression(&self) -> Compression { - Compression::None - } - fn encryption_enabled(&self) -> bool { - false - } - - fn auth_enabled(&self) -> bool { - false - } - - fn packs(&self) -> &LoginProviderPacks { - &self.packs - } - - fn on_network_settings_request_pk( - &mut self, - pk: &mut NetworkSettingsRequestPacket, - ) -> LoginProviderStatus { - LoginProviderStatus::ContinueLogin - } - - fn on_network_settings_pk(&mut self, pk: &mut NetworkSettingsPacket) -> LoginProviderStatus { - LoginProviderStatus::ContinueLogin - } - - fn on_login_pk(&mut self, pk: &mut LoginPacket) -> LoginProviderStatus { - LoginProviderStatus::ContinueLogin - } - - fn on_play_status_pk(&mut self, pk: &mut PlayStatusPacket) -> LoginProviderStatus { - LoginProviderStatus::ContinueLogin - } - fn on_resource_packs_info_pk( - &mut self, - pk: &mut ResourcePacksInfoPacket, - ) -> LoginProviderStatus { - LoginProviderStatus::ContinueLogin - } - fn on_resource_packs_stack_pk( - &mut self, - pk: &mut ResourcePacksStackPacket, - ) -> LoginProviderStatus { - LoginProviderStatus::ContinueLogin - } - fn on_resource_packs_response_pk( - &mut self, - pk: &mut ResourcePacksResponsePacket, - ) -> LoginProviderStatus { - LoginProviderStatus::ContinueLogin - } - fn on_client_cache_status_pk(&self, pk: &mut ClientCacheStatusPacket) -> LoginProviderStatus { - LoginProviderStatus::ContinueLogin - } -} diff --git a/crates/proto/src/login/provider/mod.rs b/crates/proto/src/login/provider/mod.rs deleted file mode 100644 index b781ef1d..00000000 --- a/crates/proto/src/login/provider/mod.rs +++ /dev/null @@ -1,9 +0,0 @@ -pub use bedrockrs_addon::*; -pub use default::*; -pub use provider::*; -pub use status::*; - -pub mod default; -pub mod packs; -pub mod provider; -pub mod status; diff --git a/crates/proto/src/login/provider/packs.rs b/crates/proto/src/login/provider/packs.rs deleted file mode 100644 index 081f7c2c..00000000 --- a/crates/proto/src/login/provider/packs.rs +++ /dev/null @@ -1,16 +0,0 @@ -use bedrockrs_addon::behavior::BehaviorPack; -use bedrockrs_addon::resource::ResourcePack; - -use crate::types::pack_url::PackURL; - -pub enum LoginProviderPacks { - CDN { - behavior_packs: Vec, - resource_packs: Vec, - cdn_urls: Vec, - }, - DirectNetworkTransfer { - behavior_packs: Vec, - resource_packs: Vec, - }, -} diff --git a/crates/proto/src/login/provider/provider.rs b/crates/proto/src/login/provider/provider.rs deleted file mode 100644 index ff09a251..00000000 --- a/crates/proto/src/login/provider/provider.rs +++ /dev/null @@ -1,58 +0,0 @@ -use crate::compression::Compression; -use crate::login::provider::packs::LoginProviderPacks; -use crate::login::provider::status::LoginProviderStatus; -use crate::packets::client_cache_status::ClientCacheStatusPacket; -use crate::packets::login::LoginPacket; -use crate::packets::network_settings::NetworkSettingsPacket; -use crate::packets::network_settings_request::NetworkSettingsRequestPacket; -use crate::packets::play_status::PlayStatusPacket; -use crate::packets::resource_packs_info::ResourcePacksInfoPacket; -use crate::packets::resource_packs_response::ResourcePacksResponsePacket; -use crate::packets::resource_packs_stack::ResourcePacksStackPacket; - -pub trait LoginProviderServer { - fn compression(&self) -> Compression; - fn encryption_enabled(&self) -> bool; - fn auth_enabled(&self) -> bool; - - fn packs(&self) -> &LoginProviderPacks; - - fn on_network_settings_request_pk( - &mut self, - _pk: &mut NetworkSettingsRequestPacket, - ) -> LoginProviderStatus { - LoginProviderStatus::ContinueLogin - } - fn on_network_settings_pk(&mut self, _pk: &mut NetworkSettingsPacket) -> LoginProviderStatus { - LoginProviderStatus::ContinueLogin - } - fn on_login_pk(&mut self, _pk: &mut LoginPacket) -> LoginProviderStatus { - LoginProviderStatus::ContinueLogin - } - fn on_play_status_pk(&mut self, _pk: &mut PlayStatusPacket) -> LoginProviderStatus { - LoginProviderStatus::ContinueLogin - } - fn on_resource_packs_info_pk( - &mut self, - _pk: &mut ResourcePacksInfoPacket, - ) -> LoginProviderStatus { - LoginProviderStatus::ContinueLogin - } - fn on_resource_packs_stack_pk( - &mut self, - _pk: &mut ResourcePacksStackPacket, - ) -> LoginProviderStatus { - LoginProviderStatus::ContinueLogin - } - fn on_resource_packs_response_pk( - &mut self, - _pk: &mut ResourcePacksResponsePacket, - ) -> LoginProviderStatus { - LoginProviderStatus::ContinueLogin - } - fn on_client_cache_status_pk(&self, _pk: &mut ClientCacheStatusPacket) -> LoginProviderStatus { - LoginProviderStatus::ContinueLogin - } -} - -pub trait LoginProviderClient {} diff --git a/crates/proto/src/login/provider/status.rs b/crates/proto/src/login/provider/status.rs deleted file mode 100644 index 328d988c..00000000 --- a/crates/proto/src/login/provider/status.rs +++ /dev/null @@ -1,4 +0,0 @@ -pub enum LoginProviderStatus { - ContinueLogin, - AbortLogin { reason: String }, -} diff --git a/crates/proto/src/login/set_title.rs b/crates/proto/src/login/set_title.rs deleted file mode 100644 index f169754d..00000000 --- a/crates/proto/src/login/set_title.rs +++ /dev/null @@ -1,42 +0,0 @@ -use xuid::Xuid; -use bedrockrs_core::int::VAR; - -use crate::connection::ConnectionShard; -use crate::error::LoginError; -use crate::gamepackets::GamePackets; -use crate::login::provider::{LoginProviderServer, LoginProviderStatus}; -use crate::packets::play_status::PlayStatusPacket; -use crate::packets::set_title::SetTitlePacket; -use crate::types::play_status::PlayStatusType; -use crate::types::title_type::TitleType; - -pub async fn set_title( - conn: &mut ConnectionShard, - provider: &mut impl LoginProviderServer, -) -> Result<(), LoginError> { - ////////////////////////////////////// - // Set Title - ////////////////////////////////////// - - let set_title = SetTitlePacket { - title_type: TitleType::Title, - title_text: String::from("hello_text"), - fade_in_time: VAR::new(500), - stay_time: VAR::new(500), - fade_out_time: VAR::new(500), - xuid: Xuid::from(123456789), - platform_online_id: String::from("hello_platform_online_id"), - }; - - match conn.send(GamePackets::SetTitle(set_title)).await { - Ok(_) => {} - Err(e) => return Err(LoginError::ConnectionError(e)), - } - - match conn.flush().await { - Ok(_) => {} - Err(e) => return Err(LoginError::ConnectionError(e)), - }; - - Ok(()) -} diff --git a/crates/proto/src/login/start_game.rs b/crates/proto/src/login/start_game.rs deleted file mode 100644 index d84805b9..00000000 --- a/crates/proto/src/login/start_game.rs +++ /dev/null @@ -1,160 +0,0 @@ -use bedrockrs_core::int::{LE, VAR}; -use bedrockrs_core::{Vec2, Vec3}; -use std::collections::HashMap; -use uuid::Uuid; - -use bedrockrs_shared::actor_runtime_id::ActorRuntimeID; -use bedrockrs_shared::actor_unique_id::ActorUniqueID; -use bedrockrs_shared::world::difficulty::Difficulty; -use bedrockrs_shared::world::dimension::Dimension; -use bedrockrs_shared::world::gamemode::Gamemode; -use bedrockrs_shared::world::generator_type::GeneratorType; - -use crate::connection::ConnectionShard; -use crate::error::LoginError; -use crate::gamepackets::GamePackets; -use crate::login::provider::LoginProviderServer; -use crate::packets::play_status::PlayStatusPacket; -use crate::packets::start_game::StartGamePacket; -use crate::types::base_game_version::BaseGameVersion; -use crate::types::block_pos::BlockPos; -use crate::types::chat_restriction_level::ChatRestrictionLevel; -use crate::types::edu_shared_uri_resource::EduSharedResourceUri; -use crate::types::experiments::Experiments; -use crate::types::level_settings::LevelSettings; -use crate::types::network_permissions::NetworkPermissions; -use crate::types::play_status::PlayStatusType; -use crate::types::player_movement_mode::PlayerMovementMode; -use crate::types::player_movement_settings::PlayerMovementSettings; -use crate::types::spawn_biome_type::SpawnBiomeType; -use crate::types::spawn_settings::SpawnSettings; -use bedrockrs_shared::world::editor_world_type::EditorWorldType; - -pub async fn start_game( - conn: &mut ConnectionShard, - provider: &mut impl LoginProviderServer, -) -> Result<(), LoginError> { - ////////////////////////////////////// - // Start Game Packet - ////////////////////////////////////// - - let start_game = StartGamePacket { - target_actor_id: ActorUniqueID(609), - target_runtime_id: ActorRuntimeID(402), - gamemode: Gamemode::Creative, - position: Vec3 { - x: LE::new(4.0), - y: LE::new(6.0), - z: LE::new(7.0), - }, - rotation: Vec2 { - x: LE::new(270.0), - y: LE::new(90.0), - }, - settings: LevelSettings { - seed: LE::new(777777777777), - spawn_settings: SpawnSettings { - biome_type: SpawnBiomeType::Default, - user_defined_biome_name: String::from("RandomBiome"), - dimension: Dimension::Overworld, - }, - generator_type: GeneratorType::Overworld, - gamemode: Gamemode::Creative, - hardcore: false, - difficulty: Difficulty::Peaceful, - default_spawn_block: BlockPos { - x: VAR::new(100), - y: VAR::new(200), - z: VAR::new(300), - }, - achievements_disabled: true, - editor_world_type: EditorWorldType::NotEditor, - created_in_editor: false, - exported_from_editor: false, - day_cycle_stop_time: VAR::new(2000), - // TODO: Turn into enum - education_edition_offer: VAR::new(0), - education_features: false, - education_product_id: String::from(""), - rain_level: LE::new(300.0), - lightning_level: LE::new(400.0), - platform_locked_content: false, - multiplayer_intended: true, - lan_broadcasting_intended: true, - // TOD: Turn into enum - broadcasting_settings_xbox_live: VAR::new(2), - broadcasting_settings_platform: VAR::new(2), - commands_enabled: true, - texture_pack_required: false, - gamerules: vec![], - experiments: Experiments { - experiments: vec![], - ever_toggled: false, - }, - bonus_chest: false, - start_with_map: false, - player_permission: VAR::new(3), - server_chunk_tick_radius: LE::new(4), - locked_behavior_packs: false, - locked_resource_packs: false, - from_locked_template: false, - msa_gamertags_only: false, - from_template: false, - is_template_locked_settings: false, - only_spawn_v1_villagers: false, - persona_disabled: false, - custom_skins_disabled: false, - emote_chat_muted: false, - base_game_version: BaseGameVersion(String::from("1.21.0")), - limited_world_width: LE::new(16), - limited_world_depth: LE::new(16), - new_nether: true, - edu_shared_uri_resource: EduSharedResourceUri { - button_name: String::from(""), - link_uri: String::from(""), - }, - force_experimental_gameplay: true, - chat_restriction_level: ChatRestrictionLevel::None, - disable_player_interactions: false, - server_id: String::from(""), - world_id: String::from(""), - scenario_id: String::from(""), - }, - level_id: String::from("UmFuZG9tIFdvcmxk"), - level_name: String::from("Random World"), - template_content_identity: String::new(), - trial: false, - movement_settings: PlayerMovementSettings { - authority_mode: PlayerMovementMode::Client, - rewind_history_size: VAR::new(3200), - server_authoritative_block_breaking: false, - }, - current_level_time: LE::new(9000), - enchantment_seed: VAR::new(99000), - block_properties: vec![], - items: vec![], - multiplayer_correlation_id: String::from("c5d3d2cc-27fd-4221-9de6-d22c4d423d53"), - enable_item_stack_net_manager: false, - server_version: String::from("1.19.2"), - player_property_data: nbtx::Value::Compound(HashMap::new()), - block_type_registry_checksum: LE::new(0), - world_template_id: Uuid::nil(), - enable_clientside_world_generation: false, - use_block_network_id_hashes: true, - network_permission: NetworkPermissions { - server_auth_sound_enabled: false, - }, - }; - - conn.send(GamePackets::StartGame(start_game)) - .await - .map_err(LoginError::ConnectionError)?; - conn.send(GamePackets::PlayStatus(PlayStatusPacket { - status: PlayStatusType::PlayerSpawn, - })) - .await - .map_err(LoginError::ConnectionError)?; - conn.flush().await.map_err(LoginError::ConnectionError)?; - - Ok(()) -} diff --git a/crates/proto/src/packets/add_player.rs b/crates/proto/src/packets/add_player.rs deleted file mode 100644 index f4bda42b..00000000 --- a/crates/proto/src/packets/add_player.rs +++ /dev/null @@ -1,29 +0,0 @@ -use crate::types::ability_data::AbilityData; -use crate::types::actor_link::ActorLink; -use crate::types::network_item_stack_descriptor::NetworkItemStackDescriptor; -use crate::types::property_sync_data::PropertySyncData; -use bedrockrs_core::int::{LE, VAR}; -use bedrockrs_core::Vec3; -use bedrockrs_proto_macros::{gamepacket, ProtoCodec}; -use bedrockrs_shared::actor_runtime_id::ActorRuntimeID; -use bedrockrs_shared::world::gamemode::Gamemode; -use uuid::Uuid; - -#[gamepacket(id = 12)] -#[derive(ProtoCodec, Debug, Clone)] -pub struct AddPlayerPacket { - uuid: Uuid, - name: String, - runtime_id: ActorRuntimeID, - platform_chat_id: String, - position: Vec3>, - velocity: Vec3>, - rotation: Vec3>, - carried_item: NetworkItemStackDescriptor, - gamemode: Gamemode, - // TODO: Impl SyncedActorDataEntityWrapper - synced_properties: PropertySyncData, - abilities: AbilityData, - #[len_repr(VAR::)] - links: Vec, -} diff --git a/crates/proto/src/packets/boss_event.rs b/crates/proto/src/packets/boss_event.rs deleted file mode 100644 index 1ed3b669..00000000 --- a/crates/proto/src/packets/boss_event.rs +++ /dev/null @@ -1,10 +0,0 @@ -use crate::types::event_type::BossEventType; -use bedrockrs_proto_macros::{gamepacket, ProtoCodec}; -use bedrockrs_shared::actor_unique_id::ActorUniqueID; - -#[gamepacket(id = 74)] -#[derive(ProtoCodec, Debug, Clone)] -pub struct BossEventPacket { - actor_id: ActorUniqueID, - event_type: BossEventType, -} diff --git a/crates/proto/src/packets/change_dimension.rs b/crates/proto/src/packets/change_dimension.rs deleted file mode 100644 index 7da197c7..00000000 --- a/crates/proto/src/packets/change_dimension.rs +++ /dev/null @@ -1,13 +0,0 @@ -use bedrockrs_core::int::LE; -use bedrockrs_core::Vec3; -use bedrockrs_proto_macros::{gamepacket, ProtoCodec}; -use bedrockrs_shared::world::dimension::Dimension; - -#[gamepacket(id = 61)] -#[derive(ProtoCodec, Debug, Clone)] -pub struct ChangeDimensionPacket { - dimension: Dimension, - pos: Vec3>, - respawn: bool, - loading_screen: Option>, -} diff --git a/crates/proto/src/packets/chunk_publisher_update.rs b/crates/proto/src/packets/chunk_publisher_update.rs deleted file mode 100644 index 1da20866..00000000 --- a/crates/proto/src/packets/chunk_publisher_update.rs +++ /dev/null @@ -1,13 +0,0 @@ -use crate::types::block_pos::BlockPos; -use crate::types::chunk_pos::ChunkPos; -use bedrockrs_core::int::{VAR, LE}; -use bedrockrs_proto_macros::{gamepacket, ProtoCodec}; - -#[gamepacket(id = 121)] -#[derive(ProtoCodec, Debug, Clone)] -pub struct ChunkPublisherUpdatePacket { - pub position: BlockPos, - pub radius: VAR, - #[len_repr(LE::)] - pub saved_chunks: Vec, -} diff --git a/crates/proto/src/packets/chunk_radius_updated.rs b/crates/proto/src/packets/chunk_radius_updated.rs deleted file mode 100644 index 96760017..00000000 --- a/crates/proto/src/packets/chunk_radius_updated.rs +++ /dev/null @@ -1,8 +0,0 @@ -use bedrockrs_core::int::{LE, VAR}; -use bedrockrs_proto_macros::{gamepacket, ProtoCodec}; - -#[gamepacket(id = 70)] -#[derive(ProtoCodec, Debug, Clone)] -pub struct ChunkRadiusUpdatedPacket { - pub chunk_radius: VAR, -} diff --git a/crates/proto/src/packets/command_request.rs b/crates/proto/src/packets/command_request.rs deleted file mode 100644 index d227e89b..00000000 --- a/crates/proto/src/packets/command_request.rs +++ /dev/null @@ -1,13 +0,0 @@ -use bedrockrs_core::int::VAR; -use bedrockrs_proto_macros::{gamepacket, ProtoCodec}; - -use crate::types::command_origin_data::CommandOriginData; - -#[gamepacket(id = 77)] -#[derive(ProtoCodec, Debug, Clone)] -pub struct CommandRequestPacket { - command: String, - command_origin: CommandOriginData, - is_internal_source: bool, - version: VAR, -} diff --git a/crates/proto/src/packets/container_close.rs b/crates/proto/src/packets/container_close.rs deleted file mode 100644 index 02b85dcb..00000000 --- a/crates/proto/src/packets/container_close.rs +++ /dev/null @@ -1,11 +0,0 @@ -use bedrockrs_proto_macros::{gamepacket, ProtoCodec}; - -use crate::types::container_type::ContainerType; - -#[gamepacket(id = 47)] -#[derive(ProtoCodec, Debug, Clone)] -pub struct ContainerClosePacket { - container_id: u8, - container_type: ContainerType, - server_initiated_close: bool, -} diff --git a/crates/proto/src/packets/correct_player_move_prediction.rs b/crates/proto/src/packets/correct_player_move_prediction.rs deleted file mode 100644 index 60f37922..00000000 --- a/crates/proto/src/packets/correct_player_move_prediction.rs +++ /dev/null @@ -1,12 +0,0 @@ -use bedrockrs_core::{int::LE, Vec3}; -use bedrockrs_proto_macros::{gamepacket, ProtoCodec}; - -#[gamepacket(id = 161)] -#[derive(ProtoCodec, Debug, Clone)] -pub struct CorrectPlayerMovePredictionPacket { - pub prediction_type: u8, - pub pos: Vec3>, - pub pos_delta: Vec3>, - pub on_ground: bool, - pub tick: LE, -} diff --git a/crates/proto/src/packets/emote_list.rs b/crates/proto/src/packets/emote_list.rs deleted file mode 100644 index 64963fa9..00000000 --- a/crates/proto/src/packets/emote_list.rs +++ /dev/null @@ -1,12 +0,0 @@ -use bedrockrs_core::int::VAR; -use bedrockrs_proto_macros::{gamepacket, ProtoCodec}; -use bedrockrs_shared::actor_runtime_id::ActorRuntimeID; -use uuid::Uuid; - -#[gamepacket(id = 152)] -#[derive(ProtoCodec, Debug, Clone)] -pub struct EmoteListPacket { - runtime_id: ActorRuntimeID, - #[len_repr(VAR::)] - emote_piece_ids: Vec, -} diff --git a/crates/proto/src/packets/inventory_content.rs b/crates/proto/src/packets/inventory_content.rs deleted file mode 100644 index e46f4042..00000000 --- a/crates/proto/src/packets/inventory_content.rs +++ /dev/null @@ -1,12 +0,0 @@ -use bedrockrs_core::int::VAR; -use bedrockrs_proto_macros::{gamepacket, ProtoCodec}; - -use crate::types::network_item_stack_descriptor::NetworkItemStackDescriptor; - -#[gamepacket(id = 49)] -#[derive(ProtoCodec, Debug, Clone)] -pub struct InventoryContentPacket { - pub inventory_id: VAR, - #[len_repr(VAR::)] - pub slots: Vec, -} diff --git a/crates/proto/src/packets/level_chunk.rs b/crates/proto/src/packets/level_chunk.rs deleted file mode 100644 index fec219ed..00000000 --- a/crates/proto/src/packets/level_chunk.rs +++ /dev/null @@ -1,64 +0,0 @@ -use crate::types::chunk_pos::ChunkPos; -use bedrockrs_core::int::{LE, VAR}; -use bedrockrs_proto_core::error::ProtoCodecError; -use bedrockrs_proto_core::ProtoCodec; -use bedrockrs_proto_macros::gamepacket; - -#[gamepacket(id = 58)] -#[derive(Debug, Clone)] -pub struct LevelChunkPacket { - pub chunk_position: ChunkPos, - pub dimension_id: VAR, - pub sub_chunk_count: VAR, - pub cache_enabled: bool, - pub serialized_chunk_data: Vec, - pub client_needs_to_request_subchunks: bool, - pub client_request_subchunk_limit: VAR, -} - -impl ProtoCodec for LevelChunkPacket { - fn proto_serialize( - &self, - stream: &mut Vec, - ) -> Result<(), bedrockrs_proto_core::error::ProtoCodecError> { - self.chunk_position.proto_serialize(stream)?; - self.dimension_id.proto_serialize(stream)?; - - if !self.client_needs_to_request_subchunks { - self.sub_chunk_count.proto_serialize(stream)?; - } else { - if !(self.client_request_subchunk_limit.into_inner() < 0) { - VAR::::new(u32::MAX - 1).proto_serialize(stream)?; - self.client_request_subchunk_limit.proto_serialize(stream)?; - } else { - VAR::::new(u32::MAX).proto_serialize(stream)?; - } - } - - self.cache_enabled.proto_serialize(stream)?; - if self.cache_enabled { - // todo: implement sending with cached blobs. - unimplemented!() - } - - let len = self - .serialized_chunk_data - .len() - .try_into() - .map_err(ProtoCodecError::FromIntError)?; - - VAR::::new(len).proto_serialize(stream)?; - - stream.extend_from_slice(&self.serialized_chunk_data); - - println!("finish"); - - Ok(()) - } - - fn proto_deserialize( - stream: &mut std::io::Cursor<&[u8]>, - ) -> Result { - unreachable!() - } -} diff --git a/crates/proto/src/packets/loading_screen.rs b/crates/proto/src/packets/loading_screen.rs deleted file mode 100644 index dff7c04e..00000000 --- a/crates/proto/src/packets/loading_screen.rs +++ /dev/null @@ -1,10 +0,0 @@ -use bedrockrs_core::int::LE; -use bedrockrs_proto_macros::{gamepacket, ProtoCodec}; -use crate::types::loading_screen_action::LoadingScreenAction; - -#[gamepacket(id = 312)] -#[derive(ProtoCodec, Debug, Clone)] -pub struct LoadingScreenPacket { - screen_action: LoadingScreenAction, - screen_id: Option>, -} diff --git a/crates/proto/src/packets/login.rs b/crates/proto/src/packets/login.rs deleted file mode 100644 index a7a3a1d0..00000000 --- a/crates/proto/src/packets/login.rs +++ /dev/null @@ -1,11 +0,0 @@ -use bedrockrs_core::int::BE; -use bedrockrs_proto_macros::{gamepacket, ProtoCodec}; - -use crate::types::connection_request::ConnectionRequest; - -#[gamepacket(id = 1)] -#[derive(ProtoCodec, Debug, Clone)] -pub struct LoginPacket { - pub client_network_version: BE, - pub connection_request: ConnectionRequest, -} diff --git a/crates/proto/src/packets/mob_equipment.rs b/crates/proto/src/packets/mob_equipment.rs deleted file mode 100644 index 3741f7bb..00000000 --- a/crates/proto/src/packets/mob_equipment.rs +++ /dev/null @@ -1,14 +0,0 @@ -use bedrockrs_core::int::VAR; -use bedrockrs_proto_macros::{gamepacket, ProtoCodec}; - -use crate::types::network_item_stack_descriptor::NetworkItemStackDescriptor; - -#[gamepacket(id = 31)] -#[derive(ProtoCodec, Debug, Clone)] -pub struct MobEquipmentPacket { - pub runtime_id: VAR, - pub item_stack_descriptor: NetworkItemStackDescriptor, - pub slot: u8, - pub selected_slot: u8, - pub container: u8, -} diff --git a/crates/proto/src/packets/network_settings_request.rs b/crates/proto/src/packets/network_settings_request.rs deleted file mode 100644 index 540d49bd..00000000 --- a/crates/proto/src/packets/network_settings_request.rs +++ /dev/null @@ -1,8 +0,0 @@ -use bedrockrs_core::int::BE; -use bedrockrs_proto_macros::{gamepacket, ProtoCodec}; - -#[gamepacket(id = 193)] -#[derive(ProtoCodec, Debug, Copy, Clone)] -pub struct NetworkSettingsRequestPacket { - pub client_network_version: BE, -} diff --git a/crates/proto/src/packets/packet_violation_warning.rs b/crates/proto/src/packets/packet_violation_warning.rs deleted file mode 100644 index 38e9b755..00000000 --- a/crates/proto/src/packets/packet_violation_warning.rs +++ /dev/null @@ -1,11 +0,0 @@ -use bedrockrs_core::int::VAR; -use bedrockrs_proto_macros::{gamepacket, ProtoCodec}; - -#[gamepacket(id = 156)] -#[derive(ProtoCodec, Debug, Clone)] -pub struct PacketViolationWarningPacket { - pub kind: VAR, - pub severity: VAR, - pub violating_packet_id: VAR, - pub context: String, -} diff --git a/crates/proto/src/packets/player_disconnect.rs b/crates/proto/src/packets/player_disconnect.rs deleted file mode 100644 index 86762cb9..00000000 --- a/crates/proto/src/packets/player_disconnect.rs +++ /dev/null @@ -1,52 +0,0 @@ -use std::io::Cursor; - -use crate::types::disconnect_reason::DisconnectReason; -use bedrockrs_proto_core::error::ProtoCodecError; -use bedrockrs_proto_core::ProtoCodec; -use bedrockrs_proto_macros::gamepacket; - -#[gamepacket(id = 5)] -#[derive(Debug, Clone)] -pub struct DisconnectPlayerPacket { - /// Seems to have no effect on the message being shown. - /// It is just for telemetry. - pub reason: DisconnectReason, - pub message: Option, -} - -// ProtoCodec -impl ProtoCodec for DisconnectPlayerPacket { - fn proto_serialize(&self, buf: &mut Vec) -> Result<(), ProtoCodecError> - where - Self: Sized, - { - self.reason.proto_serialize(buf)?; - - if let Some(text) = &self.message { - bool::proto_serialize(&false, buf)?; - text.proto_serialize(buf)?; - } else { - // Skip message - bool::proto_serialize(&true, buf)?; - } - - Ok(()) - } - - fn proto_deserialize(cursor: &mut Cursor<&[u8]>) -> Result - where - Self: Sized, - { - let reason = DisconnectReason::proto_deserialize(cursor)?; - - // Read if the message should be skipped - let skip_message = bool::proto_deserialize(cursor)?; - - let message = match skip_message { - true => None, - false => Some(String::proto_deserialize(cursor)?), - }; - - Ok(Self { reason, message }) - } -} diff --git a/crates/proto/src/packets/player_hotbar.rs b/crates/proto/src/packets/player_hotbar.rs deleted file mode 100644 index 7758fd86..00000000 --- a/crates/proto/src/packets/player_hotbar.rs +++ /dev/null @@ -1,12 +0,0 @@ -use crate::types::container_id::ContainerID; -use bedrockrs_core::int::VAR; -use bedrockrs_proto_core::ProtoCodec; -use bedrockrs_proto_macros::{gamepacket, ProtoCodec}; - -#[gamepacket(id = 48)] -#[derive(ProtoCodec, Debug, Clone)] -pub struct PlayerHotbarPacket { - pub selected_slot: VAR, - pub container_id: ContainerID, - pub should_select_slot: bool, -} diff --git a/crates/proto/src/packets/player_transfer.rs b/crates/proto/src/packets/player_transfer.rs deleted file mode 100644 index 37927dcb..00000000 --- a/crates/proto/src/packets/player_transfer.rs +++ /dev/null @@ -1,9 +0,0 @@ -use bedrockrs_core::int::LE; -use bedrockrs_proto_macros::{gamepacket, gamepackets, ProtoCodec}; - -#[gamepacket(id = 85)] -#[derive(ProtoCodec, Debug, Clone)] -pub struct TransferPlayerPacket { - addr: String, - port: LE, -} diff --git a/crates/proto/src/packets/resource_packs_info.rs b/crates/proto/src/packets/resource_packs_info.rs deleted file mode 100644 index 6e88f441..00000000 --- a/crates/proto/src/packets/resource_packs_info.rs +++ /dev/null @@ -1,23 +0,0 @@ -use bedrockrs_core::int::LE; -use bedrockrs_core::int::VAR; -use bedrockrs_proto_core::ProtoCodec; -use bedrockrs_proto_macros::{gamepacket, ProtoCodec}; - -use crate::types::pack_info_behavior::BehaviorPackInfoType; -use crate::types::pack_info_resource::ResourcePackInfoType; -use crate::types::pack_url::PackURL; - -#[gamepacket(id = 6)] -#[derive(Debug, Clone, ProtoCodec)] -pub struct ResourcePacksInfoPacket { - pub resource_pack_required: bool, - pub has_addon_packs: bool, - pub has_scripts: bool, - pub force_server_packs_enabled: bool, - #[len_repr(LE::)] - pub behavior_packs: Vec, - #[len_repr(LE::)] - pub resource_packs: Vec, - #[len_repr(VAR::)] - pub cdn_urls: Vec, -} diff --git a/crates/proto/src/packets/resource_packs_stack.rs b/crates/proto/src/packets/resource_packs_stack.rs deleted file mode 100644 index aa72e243..00000000 --- a/crates/proto/src/packets/resource_packs_stack.rs +++ /dev/null @@ -1,19 +0,0 @@ -use bedrockrs_core::int::VAR; -use bedrockrs_proto_macros::{gamepacket, ProtoCodec}; - -use crate::types::base_game_version::BaseGameVersion; -use crate::types::experiments::Experiments; -use crate::types::resource_packs_stack_pack::ResourcePacksStackPack; - -#[gamepacket(id = 7)] -#[derive(Debug, Clone, ProtoCodec)] -pub struct ResourcePacksStackPacket { - pub texture_pack_required: bool, - #[len_repr(VAR::)] - pub addons: Vec, - #[len_repr(VAR::)] - pub texture_packs: Vec, - pub base_game_version: BaseGameVersion, - pub experiments: Experiments, - pub include_editor_packs: bool, -} diff --git a/crates/proto/src/packets/respawn.rs b/crates/proto/src/packets/respawn.rs deleted file mode 100644 index 726915c1..00000000 --- a/crates/proto/src/packets/respawn.rs +++ /dev/null @@ -1,13 +0,0 @@ -use crate::types::respawn_state::RespawnState; -use bedrockrs_core::int::LE; -use bedrockrs_core::Vec3; -use bedrockrs_proto_macros::{gamepacket, ProtoCodec}; -use bedrockrs_shared::actor_runtime_id::ActorRuntimeID; - -#[gamepacket(id = 45)] -#[derive(ProtoCodec, Debug, Clone)] -pub struct RespawnPacket { - position: Vec3>, - state: RespawnState, - runtime_id: ActorRuntimeID, -} diff --git a/crates/proto/src/packets/server_player_post_move_position.rs b/crates/proto/src/packets/server_player_post_move_position.rs deleted file mode 100644 index d80c0e09..00000000 --- a/crates/proto/src/packets/server_player_post_move_position.rs +++ /dev/null @@ -1,8 +0,0 @@ -use bedrockrs_core::{int::LE, Vec3}; -use bedrockrs_proto_macros::{gamepacket, ProtoCodec}; - -#[gamepacket(id = 18)] -#[derive(ProtoCodec, Debug, Clone)] -pub struct ServerPlayerPostMovePositionPacket { - pos: Vec3>, -} diff --git a/crates/proto/src/packets/set_difficulty.rs b/crates/proto/src/packets/set_difficulty.rs deleted file mode 100644 index 031572fb..00000000 --- a/crates/proto/src/packets/set_difficulty.rs +++ /dev/null @@ -1,8 +0,0 @@ -use bedrockrs_proto_macros::{gamepacket, ProtoCodec}; -use bedrockrs_shared::world::difficulty::Difficulty; - -#[gamepacket(id = 60)] -#[derive(ProtoCodec, Debug, Clone)] -pub struct SetDifficultyPacket { - difficulty: Difficulty, -} diff --git a/crates/proto/src/packets/set_player_gamemode.rs b/crates/proto/src/packets/set_player_gamemode.rs deleted file mode 100644 index 98cf9a23..00000000 --- a/crates/proto/src/packets/set_player_gamemode.rs +++ /dev/null @@ -1,8 +0,0 @@ -use bedrockrs_proto_macros::{gamepacket, ProtoCodec}; -use bedrockrs_shared::world::gamemode::Gamemode; - -#[gamepacket(id = 62)] -#[derive(ProtoCodec, Debug, Clone)] -pub struct SetPlayerGamemode { - gamemode: Gamemode, -} diff --git a/crates/proto/src/packets/set_time.rs b/crates/proto/src/packets/set_time.rs deleted file mode 100644 index d03f2382..00000000 --- a/crates/proto/src/packets/set_time.rs +++ /dev/null @@ -1,8 +0,0 @@ -use bedrockrs_core::int::VAR; -use bedrockrs_proto_macros::{gamepacket, ProtoCodec}; - -#[gamepacket(id = 10)] -#[derive(ProtoCodec, Debug, Clone)] -pub struct SetTimePacket { - pub time: VAR, -} diff --git a/crates/proto/src/packets/set_title.rs b/crates/proto/src/packets/set_title.rs deleted file mode 100644 index b7675bf9..00000000 --- a/crates/proto/src/packets/set_title.rs +++ /dev/null @@ -1,17 +0,0 @@ -use xuid::Xuid; -use bedrockrs_core::int::VAR; -use bedrockrs_proto_macros::{gamepacket, ProtoCodec}; - -use crate::types::title_type::TitleType; - -#[gamepacket(id = 88)] -#[derive(ProtoCodec, Debug, Clone)] -pub struct SetTitlePacket { - pub title_type: TitleType, - pub title_text: String, - pub fade_in_time: VAR, - pub stay_time: VAR, - pub fade_out_time: VAR, - pub xuid: Xuid, - pub platform_online_id: String, -} diff --git a/crates/proto/src/packets/show_credits.rs b/crates/proto/src/packets/show_credits.rs deleted file mode 100644 index e9018cd3..00000000 --- a/crates/proto/src/packets/show_credits.rs +++ /dev/null @@ -1,10 +0,0 @@ -use crate::types::credits_state::CreditsState; -use bedrockrs_proto_macros::{gamepacket, ProtoCodec}; -use bedrockrs_shared::actor_runtime_id::ActorRuntimeID; - -#[gamepacket(id = 75)] -#[derive(ProtoCodec, Debug, Clone)] -pub struct ShowCreditsPacket { - actor_id: ActorRuntimeID, - credits_state: CreditsState, -} diff --git a/crates/proto/src/packets/start_game.rs b/crates/proto/src/packets/start_game.rs deleted file mode 100644 index 194e61b6..00000000 --- a/crates/proto/src/packets/start_game.rs +++ /dev/null @@ -1,47 +0,0 @@ -use bedrockrs_core::int::{LE, VAR}; -use bedrockrs_core::{Vec2, Vec3}; -use bedrockrs_proto_macros::{gamepacket, ProtoCodec}; -use uuid::Uuid; - -use bedrockrs_shared::actor_runtime_id::ActorRuntimeID; -use bedrockrs_shared::actor_unique_id::ActorUniqueID; -use bedrockrs_shared::world::gamemode::Gamemode; - -use crate::types::level_settings::LevelSettings; -use crate::types::network_permissions::NetworkPermissions; -use crate::types::player_movement_settings::PlayerMovementSettings; - -#[gamepacket(id = 11)] -#[derive(ProtoCodec, Debug, Clone)] -pub struct StartGamePacket { - pub target_actor_id: ActorUniqueID, - pub target_runtime_id: ActorRuntimeID, - pub gamemode: Gamemode, - pub position: Vec3>, - pub rotation: Vec2>, - pub settings: LevelSettings, - pub level_id: String, - pub level_name: String, - pub template_content_identity: String, - pub trial: bool, - pub movement_settings: PlayerMovementSettings, - pub current_level_time: LE, - pub enchantment_seed: VAR, - // TODO Add real value - #[len_repr(VAR::)] - pub block_properties: Vec, - // TODO Add real value - #[len_repr(VAR::)] - pub items: Vec, - pub multiplayer_correlation_id: String, - pub enable_item_stack_net_manager: bool, - pub server_version: String, - // TODO: This can now be a concrete type rather than an NBT value. - // How should we do this with the ProtoCodec macro? - pub player_property_data: nbtx::Value, - pub block_type_registry_checksum: LE, - pub world_template_id: Uuid, - pub enable_clientside_world_generation: bool, - pub use_block_network_id_hashes: bool, - pub network_permission: NetworkPermissions, -} diff --git a/crates/proto/src/packets/text_message.rs b/crates/proto/src/packets/text_message.rs deleted file mode 100644 index 3c2c5505..00000000 --- a/crates/proto/src/packets/text_message.rs +++ /dev/null @@ -1,234 +0,0 @@ -use crate::types::text_message_data::TextMessageData; -use bedrockrs_core::int::VAR; -use bedrockrs_proto_core::error::ProtoCodecError; -use bedrockrs_proto_core::ProtoCodec; -use bedrockrs_proto_macros::gamepacket; -use std::io::Cursor; -use xuid::Xuid; - -#[gamepacket(id = 9)] -#[derive(Debug, Clone)] -pub struct TextMessagePacket { - pub message_type: TextMessageData, - pub localize: bool, - pub sender_xuid: Xuid, - pub platform_id: String, - pub filtered_message: String, -} - -impl ProtoCodec for TextMessagePacket { - fn proto_serialize(&self, stream: &mut Vec) -> Result<(), ProtoCodecError> { - let message_type: u8 = match self.message_type { - TextMessageData::Raw(_) => 0, - TextMessageData::Chat { .. } => 1, - TextMessageData::Translate { .. } => 2, - TextMessageData::Popup { .. } => 3, - TextMessageData::JukeboxPopup { .. } => 4, - TextMessageData::Tip(_) => 5, - TextMessageData::SystemMessage(_) => 6, - TextMessageData::Whisper { .. } => 7, - TextMessageData::Announcement { .. } => 8, - TextMessageData::TextObjectWhisper(_) => 9, - TextMessageData::TextObject(_) => 10, - TextMessageData::TextObjectAnnouncement(_) => 11, - }; - - message_type.proto_serialize(stream)?; - self.localize.proto_serialize(stream)?; - - match &self.message_type { - TextMessageData::Raw(message) => { - message.proto_serialize(stream)?; - } - TextMessageData::Chat { - player_name, - message, - } => { - player_name.proto_serialize(stream)?; - message.proto_serialize(stream)?; - } - TextMessageData::Translate { - message, - parameters, - } => { - message.proto_serialize(stream)?; - - let len = VAR::::new( - Vec::len(¶meters) - .try_into() - .map_err(ProtoCodecError::FromIntError)?, - ); - len.proto_serialize(stream)?; - - for parameter in parameters { - parameter.proto_serialize(stream)?; - } - } - TextMessageData::Popup { - message, - parameters, - } => { - message.proto_serialize(stream)?; - - let len = VAR::::new( - Vec::len(¶meters) - .try_into() - .map_err(ProtoCodecError::FromIntError)?, - ); - len.proto_serialize(stream)?; - - for parameter in parameters { - parameter.proto_serialize(stream)?; - } - } - TextMessageData::JukeboxPopup { - message, - parameters, - } => { - message.proto_serialize(stream)?; - - let len = VAR::::new( - Vec::len(¶meters) - .try_into() - .map_err(ProtoCodecError::FromIntError)?, - ); - len.proto_serialize(stream)?; - - for parameter in parameters { - parameter.proto_serialize(stream)?; - } - } - TextMessageData::Tip(message) => { - message.proto_serialize(stream)?; - } - TextMessageData::SystemMessage(message) => { - message.proto_serialize(stream)?; - } - TextMessageData::Whisper { - player_name, - message, - } => { - player_name.proto_serialize(stream)?; - message.proto_serialize(stream)?; - } - TextMessageData::Announcement { - player_name, - message, - } => { - player_name.proto_serialize(stream)?; - message.proto_serialize(stream)?; - } - TextMessageData::TextObjectWhisper(message) => { - message.proto_serialize(stream)?; - } - TextMessageData::TextObject(message) => { - message.proto_serialize(stream)?; - } - TextMessageData::TextObjectAnnouncement(message) => { - message.proto_serialize(stream)?; - } - }; - - self.sender_xuid.proto_serialize(stream)?; - self.platform_id.proto_serialize(stream)?; - self.filtered_message.proto_serialize(stream)?; - - Ok(()) - } - - fn proto_deserialize(stream: &mut Cursor<&[u8]>) -> Result { - let message_type = u8::proto_deserialize(stream)?; - let localize = bool::proto_deserialize(stream)?; - - let message_type = match message_type { - 0 => TextMessageData::Raw(String::proto_deserialize(stream)?), - 1 => TextMessageData::Chat { - player_name: String::proto_deserialize(stream)?, - message: String::proto_deserialize(stream)?, - }, - 2 => { - let message = String::proto_deserialize(stream)?; - - let len = VAR::::proto_deserialize(stream)?.into_inner(); - let mut parameters = Vec::with_capacity(match len.try_into() { - Ok(v) => v, - Err(e) => return Err(ProtoCodecError::FromIntError(e)), - }); - - for _ in 0..len { - parameters.push(String::proto_deserialize(stream)?); - } - - TextMessageData::Translate { - message, - parameters, - } - } - 3 => { - let message = String::proto_deserialize(stream)?; - - let len = VAR::::proto_deserialize(stream)?.into_inner(); - let mut parameters = - Vec::with_capacity(len.try_into().map_err(ProtoCodecError::FromIntError)?); - - for _ in 0..len { - parameters.push(String::proto_deserialize(stream)?); - } - - TextMessageData::Popup { - message, - parameters, - } - } - 4 => { - let message = String::proto_deserialize(stream)?; - - let len = VAR::::proto_deserialize(stream)?.into_inner(); - let mut parameters = Vec::with_capacity(match len.try_into() { - Ok(v) => v, - Err(e) => return Err(ProtoCodecError::FromIntError(e)), - }); - - for _ in 0..len { - parameters.push(String::proto_deserialize(stream)?); - } - - TextMessageData::JukeboxPopup { - message, - parameters, - } - } - 5 => TextMessageData::Tip(String::proto_deserialize(stream)?), - 6 => TextMessageData::SystemMessage(String::proto_deserialize(stream)?), - 7 => TextMessageData::Whisper { - player_name: String::proto_deserialize(stream)?, - message: String::proto_deserialize(stream)?, - }, - 8 => TextMessageData::Announcement { - player_name: String::proto_deserialize(stream)?, - message: String::proto_deserialize(stream)?, - }, - 9 => TextMessageData::TextObjectWhisper(String::proto_deserialize(stream)?), - 10 => TextMessageData::TextObject(String::proto_deserialize(stream)?), - 11 => TextMessageData::TextObjectAnnouncement(String::proto_deserialize(stream)?), - other => { - return Err(ProtoCodecError::InvalidEnumID( - format!("{other:?}"), - String::from("TextMessageData"), - )); - } - }; - - let sender_xuid = Xuid::proto_deserialize(stream)?; - let platform_id = String::proto_deserialize(stream)?; - let filtered_message = String::proto_deserialize(stream)?; - - Ok(Self { - message_type, - localize, - sender_xuid, - platform_id, - filtered_message, - }) - } -} diff --git a/crates/proto/src/sub_client.rs b/crates/proto/src/sub_client.rs deleted file mode 100644 index 282d686b..00000000 --- a/crates/proto/src/sub_client.rs +++ /dev/null @@ -1,35 +0,0 @@ -use bedrockrs_core::int::LE; -use bedrockrs_proto_core::error::ProtoCodecError; -use bedrockrs_proto_macros::ProtoCodec; - -#[derive(Debug, Clone)] -pub enum SubClientID { - PrimaryClient, - Client2, - Client3, - Client4, -} - -impl SubClientID { - pub fn proto_from(val: u8) -> Result { - match val { - 0 => Ok(SubClientID::PrimaryClient), - 1 => Ok(SubClientID::Client2), - 2 => Ok(SubClientID::Client3), - 3 => Ok(SubClientID::Client4), - other => Err(ProtoCodecError::InvalidEnumID( - format!("{other:?}"), - String::from("SubClientID"), - )), - } - } - - pub fn proto_to(&self) -> u8 { - match self { - SubClientID::PrimaryClient => 0, - SubClientID::Client2 => 1, - SubClientID::Client3 => 2, - SubClientID::Client4 => 3, - } - } -} diff --git a/crates/proto/src/transport/connection.rs b/crates/proto/src/transport/connection.rs new file mode 100644 index 00000000..562527c0 --- /dev/null +++ b/crates/proto/src/transport/connection.rs @@ -0,0 +1,70 @@ +use crate::error::{RakNetError, TransportLayerError}; +use crate::info::RAKNET_GAMEPACKET_ID; +use byteorder::{ReadBytesExt, WriteBytesExt}; +use std::io::{Cursor, Write}; + +pub enum TransportLayerConnection { + RakNet(rak_rs::connection::Connection), + // TOOD NetherNet(nethernet::connection::Connection), + // TODO Quic(s2n_quic::stream::BidirectionalStream), + // TODO Tcp(net::TcpStream), +} + +impl TransportLayerConnection { + pub async fn send(&mut self, stream: &[u8]) -> Result<(), TransportLayerError> { + match self { + Self::RakNet(conn) => { + // 1 = RAKNET_GAMEPACKET_ID size + let mut str = Vec::with_capacity(stream.len() + 1); + + // TODO Find out a way to avoid copying of the entire buffer + str.write_u8(RAKNET_GAMEPACKET_ID)?; + str.write_all(stream)?; + + // TODO Find out if immediate: true should be used + conn.send(str.as_slice(), true) + .await + .map_err(|err| TransportLayerError::RakNetError(RakNetError::SendError(err)))?; + } + } + + Ok(()) + } + + pub async fn recv(&mut self) -> Result, TransportLayerError> { + let stream = match self { + Self::RakNet(conn) => { + let stream = conn + .recv() + .await + .map_err(|e| TransportLayerError::RakNetError(RakNetError::RecvError(e)))?; + + let mut stream = Cursor::new(stream); + + // Read the RakNet Packet ID + let raknet_packet_id = stream.read_u8()?; + + if raknet_packet_id != RAKNET_GAMEPACKET_ID { + return Err(TransportLayerError::RakNetError( + RakNetError::InvalidRakNetHeader(raknet_packet_id), + )); + }; + + let mut stream = stream.into_inner(); + stream.drain(..1); + + stream + } + }; + + Ok(stream) + } + + pub async fn close(self) { + match self { + Self::RakNet(conn) => { + conn.close().await; + } + } + } +} diff --git a/crates/proto/src/transport/listener.rs b/crates/proto/src/transport/listener.rs new file mode 100644 index 00000000..b0d26548 --- /dev/null +++ b/crates/proto/src/transport/listener.rs @@ -0,0 +1,45 @@ +use crate::error::{RakNetError, TransportLayerError}; +use crate::transport::TransportLayerConnection; + +pub enum TransportLayerListener { + RakNet(rak_rs::Listener), + // TODO NetherNet(...), + // TODO Quic(s2n_quic::server::Server), + // TODO Tcp(...), +} + +impl TransportLayerListener { + pub async fn start(&mut self) -> Result<(), TransportLayerError> { + match self { + Self::RakNet(listener) => listener + .start() + .await + .map_err(|err| TransportLayerError::RakNetError(RakNetError::ServerError(err)))?, + }; + + Ok(()) + } + + pub async fn stop(&mut self) -> Result<(), TransportLayerError> { + match self { + Self::RakNet(listener) => listener + .stop() + .await + .map_err(|err| TransportLayerError::RakNetError(RakNetError::ServerError(err)))?, + } + + Ok(()) + } + + pub async fn accept(&mut self) -> Result { + let conn = match self { + Self::RakNet(listener) => { + TransportLayerConnection::RakNet(listener.accept().await.map_err(|err| { + TransportLayerError::RakNetError(RakNetError::ServerError(err)) + })?) + } + }; + + Ok(conn) + } +} diff --git a/crates/proto/src/transport_layer/mod.rs b/crates/proto/src/transport/mod.rs similarity index 56% rename from crates/proto/src/transport_layer/mod.rs rename to crates/proto/src/transport/mod.rs index e7077647..e5b3490d 100644 --- a/crates/proto/src/transport_layer/mod.rs +++ b/crates/proto/src/transport/mod.rs @@ -3,8 +3,3 @@ pub use listener::*; pub mod connection; pub mod listener; - -pub enum TransportLayerType { - RaknetUDP, - NetherNet, -} diff --git a/crates/proto/src/transport_layer/connection.rs b/crates/proto/src/transport_layer/connection.rs deleted file mode 100644 index 8dde6013..00000000 --- a/crates/proto/src/transport_layer/connection.rs +++ /dev/null @@ -1,78 +0,0 @@ -use bedrockrs_core::int::LE; -use std::io::{Cursor, Write}; -use std::sync::Arc; - -use crate::error::{RaknetError, TransportLayerError}; -use crate::info::RAKNET_GAME_PACKET_ID; - -pub enum TransportLayerConnection { - RaknetUDP(rak_rs::connection::Connection), - // TOOD NetherNet(nethernet::connection::Connection), - // TODO Quic(s2n_quic::connection::Connection), - // TODO Tcp(net::TcpStream),\ -} - -impl TransportLayerConnection { - pub async fn send(&mut self, stream: &Cursor<&[u8]>) -> Result<(), TransportLayerError> { - match self { - TransportLayerConnection::RaknetUDP(conn) => { - let mut final_stream = vec![]; - - LE::::write(&LE::new(RAKNET_GAME_PACKET_ID), &mut final_stream) - .map_err(|e| TransportLayerError::IOError(Arc::new(e)))?; - - final_stream - .write_all(stream.get_ref()) - .map_err(|e| TransportLayerError::IOError(Arc::new(e)))?; - - // TODO Find out if immediate: true should be used - conn.send(final_stream.as_slice(), true) - .await - .map_err(|e| TransportLayerError::RaknetUDPError(RaknetError::SendError(e))) - } - } - } - - pub async fn recv(&mut self, stream: &mut Vec) -> Result<(), TransportLayerError> { - match self { - TransportLayerConnection::RaknetUDP(conn) => { - let mut recv_stream = conn - .recv() - .await - .map_err(|e| TransportLayerError::RaknetUDPError(RaknetError::RecvError(e)))?; - - let mut recv_stream = Cursor::new(recv_stream.as_slice()); - - match LE::::read(&mut recv_stream) - .map_err(|e| TransportLayerError::IOError(Arc::new(e)))? - .into_inner() - { - RAKNET_GAME_PACKET_ID => {} - other => { - return Err(TransportLayerError::RaknetUDPError( - RaknetError::FormatError(format!( - "Expected RakNet Game Packet ID ({:?}), got: {:?}", - RAKNET_GAME_PACKET_ID, other - )), - )); - } - }; - - Ok(stream - .write_all(recv_stream.into_inner()) - .map_err(|e| TransportLayerError::IOError(Arc::new(e)))?) - } - } - } - - pub async fn close(self) { - match self { - TransportLayerConnection::RaknetUDP(conn) => { - conn.close().await; - } - _ => { - todo!() - } - } - } -} diff --git a/crates/proto/src/transport_layer/listener.rs b/crates/proto/src/transport_layer/listener.rs deleted file mode 100644 index 500283b3..00000000 --- a/crates/proto/src/transport_layer/listener.rs +++ /dev/null @@ -1,37 +0,0 @@ -use crate::error::{RaknetError, TransportLayerError}; -use crate::transport_layer::TransportLayerConnection; - -pub enum TransportLaterListener { - RaknetUDP(rak_rs::Listener), - NetherNet(/* TODO */), -} - -impl TransportLaterListener { - pub async fn start(&mut self) -> Result<(), TransportLayerError> { - match self { - TransportLaterListener::RaknetUDP(listener) => match listener.start().await { - Ok(_) => Ok(()), - Err(e) => Err(TransportLayerError::RaknetUDPError( - RaknetError::ServerError(e), - )), - }, - _ => { - todo!() - } - } - } - - pub async fn accept(&mut self) -> Result { - match self { - TransportLaterListener::RaknetUDP(listener) => match listener.accept().await { - Ok(conn) => Ok(TransportLayerConnection::RaknetUDP(conn)), - Err(e) => Err(TransportLayerError::RaknetUDPError( - RaknetError::ServerError(e), - )), - }, - _ => { - todo!() - } - } - } -} diff --git a/crates/proto/src/types/actor_link.rs b/crates/proto/src/types/actor_link.rs deleted file mode 100644 index 903ed2f3..00000000 --- a/crates/proto/src/types/actor_link.rs +++ /dev/null @@ -1,14 +0,0 @@ -use bedrockrs_core::int::VAR; -use bedrockrs_proto_macros::ProtoCodec; -use bedrockrs_shared::actor_unique_id::ActorUniqueID; - -use super::actor_link_type::ActorLinkType; - -#[derive(ProtoCodec, Debug, Clone)] -pub struct ActorLink { - actor_unique_id_a: ActorUniqueID, - actor_unique_id_b: ActorUniqueID, - link_type: ActorLinkType, - immediate: bool, - passenger_seat_id: bool, -} diff --git a/crates/proto/src/types/attribute.rs b/crates/proto/src/types/attribute.rs deleted file mode 100644 index 09a8e1b7..00000000 --- a/crates/proto/src/types/attribute.rs +++ /dev/null @@ -1,10 +0,0 @@ -use bedrockrs_core::int::{LE, VAR}; -use bedrockrs_proto_macros::ProtoCodec; - -#[derive(ProtoCodec, Debug, Clone)] -pub struct Attribute { - pub name: String, - pub min: LE, - pub current: LE, - pub max: LE, -} diff --git a/crates/proto/src/types/base_game_version.rs b/crates/proto/src/types/base_game_version.rs deleted file mode 100644 index 37d9505f..00000000 --- a/crates/proto/src/types/base_game_version.rs +++ /dev/null @@ -1,6 +0,0 @@ -use bedrockrs_proto_core::ProtoCodec; -use bedrockrs_proto_macros::ProtoCodec; - -#[derive(ProtoCodec, Debug, Clone)] -#[repr(transparent)] -pub struct BaseGameVersion(pub String); diff --git a/crates/proto/src/types/block_action.rs b/crates/proto/src/types/block_action.rs deleted file mode 100644 index c05155b5..00000000 --- a/crates/proto/src/types/block_action.rs +++ /dev/null @@ -1 +0,0 @@ -pub struct BlockAction {} diff --git a/crates/proto/src/types/block_pos.rs b/crates/proto/src/types/block_pos.rs deleted file mode 100644 index 0c211867..00000000 --- a/crates/proto/src/types/block_pos.rs +++ /dev/null @@ -1,19 +0,0 @@ -use bedrockrs_core::int::VAR; -use bedrockrs_proto_macros::ProtoCodec; - -#[derive(ProtoCodec, Debug, Clone)] -pub struct BlockPos { - pub x: VAR, - pub y: VAR, - pub z: VAR, -} - -impl BlockPos { - pub fn new(x: i32, y: u32, z: i32) -> BlockPos { - Self { - x: VAR::new(x), - y: VAR::new(y), - z: VAR::new(z), - } - } -} diff --git a/crates/proto/src/types/chat_restriction_level.rs b/crates/proto/src/types/chat_restriction_level.rs deleted file mode 100644 index 75f1e0e7..00000000 --- a/crates/proto/src/types/chat_restriction_level.rs +++ /dev/null @@ -1,10 +0,0 @@ -use bedrockrs_core::int::LE; -use bedrockrs_proto_macros::ProtoCodec; - -#[derive(ProtoCodec, Debug, Clone)] -#[enum_repr(LE::)] -pub enum ChatRestrictionLevel { - None = 0x00, - Dropped = 0x01, - Disabled = 0x02, -} diff --git a/crates/proto/src/types/chunk_pos.rs b/crates/proto/src/types/chunk_pos.rs deleted file mode 100644 index e72400b2..00000000 --- a/crates/proto/src/types/chunk_pos.rs +++ /dev/null @@ -1,17 +0,0 @@ -use bedrockrs_core::int::{LE, VAR}; -use bedrockrs_proto_macros::ProtoCodec; - -#[derive(ProtoCodec, Debug, Clone)] -pub struct ChunkPos { - pub x: VAR, - pub z: VAR, -} - -impl ChunkPos { - pub fn new(x: i32, z: i32) -> Self { - ChunkPos { - x: VAR::::new(x), - z: VAR::::new(z), - } - } -} diff --git a/crates/proto/src/types/container_type.rs b/crates/proto/src/types/container_type.rs deleted file mode 100644 index d3d0a4a0..00000000 --- a/crates/proto/src/types/container_type.rs +++ /dev/null @@ -1,46 +0,0 @@ -use bedrockrs_core::int::BE; -use bedrockrs_proto_macros::ProtoCodec; - -#[derive(ProtoCodec, Debug, Copy, Clone, Eq, PartialEq)] -#[enum_repr(BE::)] -pub enum ContainerType { - NONE = -9, - INVENTORY = -1, - CONTAINER = 0, - WORKBENCH = 1, - FURNACE = 2, - ENCHANTMENT = 3, - BREWING_STAND = 4, - ANVIL = 5, - DISPENSER = 6, - DROPPER = 7, - HOPPER = 8, - CAULDRON = 9, - MINECART_CHEST = 10, - MINECART_HOPPER = 11, - HORSE = 12, - BEACON = 13, - STRUCTURE_EDITOR = 14, - TRADE = 15, - COMMAND_BLOCK = 16, - JUKEBOX = 17, - ARMOR = 18, - HAND = 19, - COMPOUND_CREATOR = 20, - ELEMENT_CONSTRUCTOR = 21, - MATERIAL_REDUCER = 22, - LAB_TABLE = 23, - LOOM = 24, - LECTERN = 25, - GRINDSTONE = 26, - BLAST_FURNACE = 27, - SMOKER = 28, - STONECUTTER = 29, - CARTOGRAPHY = 30, - HUD = 31, - JIGSAW_EDITOR = 32, - SMITHING_TABLE = 33, - CHEST_BOAT = 34, - DECORATED_POT = 35, - CRAFTER = 36, -} diff --git a/crates/proto/src/types/data_item.rs b/crates/proto/src/types/data_item.rs deleted file mode 100644 index a27a1746..00000000 --- a/crates/proto/src/types/data_item.rs +++ /dev/null @@ -1,41 +0,0 @@ -use bedrockrs_core::{ - int::{LE, VAR}, - Vec3, -}; -use bedrockrs_proto_core::ProtoCodec; -use bedrockrs_proto_macros::ProtoCodec; -use std::collections::HashMap; - -#[derive(ProtoCodec, Debug, Clone)] -pub struct DataItem { - pub id: VAR, - pub value: DataItemValue, -} - -#[derive(Debug, Clone)] -pub enum DataItemValue { - ValByte(u8), - ValShort(i16), - ValInt(i32), - ValFloat(f32), - ValString(String), - ValCompoundTag(HashMap), - ValPos(Vec3>), - ValInt64(LE), - ValVec3(Vec3>), -} - -impl ProtoCodec for DataItemValue { - fn proto_serialize( - &self, - stream: &mut Vec, - ) -> Result<(), bedrockrs_proto_core::error::ProtoCodecError> { - unimplemented!() - } - - fn proto_deserialize( - stream: &mut std::io::Cursor<&[u8]>, - ) -> Result { - unimplemented!() - } -} diff --git a/crates/proto/src/types/event_type.rs b/crates/proto/src/types/event_type.rs deleted file mode 100644 index 774c25d4..00000000 --- a/crates/proto/src/types/event_type.rs +++ /dev/null @@ -1,178 +0,0 @@ -use bedrockrs_core::int::{LE, VAR}; -use bedrockrs_proto_core::error::ProtoCodecError; -use bedrockrs_proto_core::ProtoCodec; -use bedrockrs_proto_macros::ProtoCodec; -use bedrockrs_shared::actor_unique_id::ActorUniqueID; -use std::io::Cursor; - -#[derive(Debug, Clone)] -pub enum BossEventType { - Add { - name: String, - health_percentage: LE, - darken_screen: LE, - color: VAR, - overlay: VAR, - }, - PlayerAdded { - actor_id: ActorUniqueID, - }, - Remove, - PlayerRemoved { - actor_id: ActorUniqueID, - }, - UpdatePercent { - health_percentage: LE, - }, - UpdateName { - name: String, - }, - UpdateProperties { - darken_screen: LE, - color: VAR, - overlay: VAR, - }, - UpdateStyle { - color: VAR, - overlay: VAR, - }, - Query { - actor_id: ActorUniqueID, - }, -} - -impl ProtoCodec for BossEventType { - fn proto_serialize(&self, buf: &mut Vec) -> Result<(), ProtoCodecError> { - match self { - BossEventType::Add { - name, - health_percentage, - darken_screen, - color, - overlay, - } => { - VAR::new(0).proto_serialize(buf)?; - - name.proto_serialize(buf)?; - health_percentage.proto_serialize(buf)?; - darken_screen.proto_serialize(buf)?; - color.proto_serialize(buf)?; - overlay.proto_serialize(buf)?; - } - BossEventType::PlayerAdded { actor_id } => { - VAR::new(1).proto_serialize(buf)?; - - actor_id.proto_serialize(buf)?; - } - BossEventType::Remove => VAR::new(2).proto_serialize(buf)?, - BossEventType::PlayerRemoved { actor_id } => { - VAR::new(3).proto_serialize(buf)?; - - actor_id.proto_serialize(buf)?; - } - BossEventType::UpdatePercent { health_percentage } => { - VAR::new(4).proto_serialize(buf)?; - - health_percentage.proto_serialize(buf)?; - } - BossEventType::UpdateName { name } => { - VAR::new(5).proto_serialize(buf)?; - - name.proto_serialize(buf)?; - } - BossEventType::UpdateProperties { - darken_screen, - color, - overlay, - } => { - VAR::new(6).proto_serialize(buf)?; - - darken_screen.proto_serialize(buf)?; - color.proto_serialize(buf)?; - overlay.proto_serialize(buf)?; - } - BossEventType::UpdateStyle { color, overlay } => { - VAR::new(7).proto_serialize(buf)?; - - color.proto_serialize(buf)?; - overlay.proto_serialize(buf)?; - } - BossEventType::Query { actor_id } => { - VAR::new(8).proto_serialize(buf)?; - - actor_id.proto_serialize(buf)?; - } - }; - - Ok(()) - } - - fn proto_deserialize(buf: &mut Cursor<&[u8]>) -> Result { - Ok(match VAR::::proto_deserialize(buf)?.into_inner() { - 0 => { - let name = String::proto_deserialize(buf)?; - let health_percentage = LE::::proto_deserialize(buf)?; - let darken_screen = LE::::proto_deserialize(buf)?; - let color = VAR::::proto_deserialize(buf)?; - let overlay = VAR::::proto_deserialize(buf)?; - - BossEventType::Add { - name, - health_percentage, - darken_screen, - color, - overlay, - } - } - 1 => { - let actor_id = ActorUniqueID::proto_deserialize(buf)?; - - BossEventType::PlayerAdded { actor_id } - } - 2 => BossEventType::Remove, - 3 => { - let actor_id = ActorUniqueID::proto_deserialize(buf)?; - - BossEventType::PlayerRemoved { actor_id } - } - 4 => { - let health_percentage = LE::::proto_deserialize(buf)?; - - BossEventType::UpdatePercent { health_percentage } - } - 5 => { - let name = String::proto_deserialize(buf)?; - - BossEventType::UpdateName { name } - } - 6 => { - let darken_screen = LE::::proto_deserialize(buf)?; - let color = VAR::::proto_deserialize(buf)?; - let overlay = VAR::::proto_deserialize(buf)?; - - BossEventType::UpdateProperties { - darken_screen, - color, - overlay, - } - } - 7 => { - let color = VAR::::proto_deserialize(buf)?; - let overlay = VAR::::proto_deserialize(buf)?; - - BossEventType::UpdateStyle { color, overlay } - } - 8 => { - let actor_id = ActorUniqueID::proto_deserialize(buf)?; - - BossEventType::Query { actor_id } - } - other => { - return Err(ProtoCodecError::InvalidEnumID( - format!("{other:?}"), - String::from("BossEventType"), - )); - } - }) - } -} diff --git a/crates/proto/src/types/gamerule.rs b/crates/proto/src/types/gamerule.rs deleted file mode 100644 index 6b8a7c30..00000000 --- a/crates/proto/src/types/gamerule.rs +++ /dev/null @@ -1,60 +0,0 @@ -use bedrockrs_core::int::{LE, VAR}; -use bedrockrs_proto_core::error::ProtoCodecError; -use bedrockrs_proto_core::ProtoCodec; -use bedrockrs_proto_macros::ProtoCodec; -use std::io::Cursor; -use std::sync::Arc; - -#[derive(ProtoCodec, Debug, Clone)] -pub struct GameRule { - name: String, - editable: bool, - value: GameRuleValue, -} - -#[derive(Debug, Clone)] -pub enum GameRuleValue { - Bool(bool), - VarU32(u32), - F32(f32), -} - -impl ProtoCodec for GameRuleValue { - fn proto_serialize(&self, stream: &mut Vec) -> Result<(), ProtoCodecError> { - let int = VAR::::new(match self { - GameRuleValue::Bool(bool) => { - bool.proto_serialize(stream)?; - 1 - } - GameRuleValue::VarU32(v) => { - VAR::::new(*v) - .write(stream) - .map_err(|e| ProtoCodecError::IOError(Arc::new(e)))?; - 2 - } - GameRuleValue::F32(v) => { - LE::::new(*v) - .write(stream) - .map_err(|e| ProtoCodecError::IOError(Arc::new(e)))?; - 3 - } - }); - - int.write(stream) - .map_err(|e| ProtoCodecError::IOError(Arc::new(e))) - } - - fn proto_deserialize(stream: &mut Cursor<&[u8]>) -> Result { - Ok(match VAR::::proto_deserialize(stream)?.into_inner() { - 1 => GameRuleValue::Bool(bool::proto_deserialize(stream)?), - 2 => GameRuleValue::VarU32(VAR::::proto_deserialize(stream)?.into_inner()), - 3 => GameRuleValue::F32(LE::::proto_deserialize(stream)?.into_inner()), - other => { - return Err(ProtoCodecError::InvalidEnumID( - format!("{other:?}"), - String::from("GameRuleValue"), - )); - } - }) - } -} diff --git a/crates/proto/src/types/interaction_model.rs b/crates/proto/src/types/interaction_model.rs deleted file mode 100644 index 52fb4761..00000000 --- a/crates/proto/src/types/interaction_model.rs +++ /dev/null @@ -1,10 +0,0 @@ -use bedrockrs_core::int::VAR; -use bedrockrs_proto_macros::ProtoCodec; - -#[derive(ProtoCodec, Debug, Clone)] -#[enum_repr(VAR::)] -pub enum InteractionModel { - Touch = 0, - Crosshair = 1, - Classic = 2, -} diff --git a/crates/proto/src/types/item_stack_net_id_variant.rs b/crates/proto/src/types/item_stack_net_id_variant.rs deleted file mode 100644 index f39bcb74..00000000 --- a/crates/proto/src/types/item_stack_net_id_variant.rs +++ /dev/null @@ -1,6 +0,0 @@ -use bedrockrs_core::int::VAR; -use bedrockrs_proto_macros::ProtoCodec; -#[derive(ProtoCodec, Debug, Clone)] -pub struct ItemStackNetIdVariant { - pub raw_id: VAR, -} diff --git a/crates/proto/src/types/network_item_stack_descriptor.rs b/crates/proto/src/types/network_item_stack_descriptor.rs deleted file mode 100644 index 6f5445d6..00000000 --- a/crates/proto/src/types/network_item_stack_descriptor.rs +++ /dev/null @@ -1,78 +0,0 @@ -use bedrockrs_core::int::{LE, VAR}; -use bedrockrs_proto_core::ProtoCodec; - -use super::item_stack_net_id_variant::ItemStackNetIdVariant; - -#[derive(Debug, Clone)] -pub enum NetworkItemStackDescriptor { - Invalid { - id: VAR, - }, - Valid { - id: VAR, - stack_size: LE, - aux_value: LE, - include_net_id: bool, - include_net_id_data: Option, - block_runtime_id: VAR, - user_data_buffer: String, - }, -} -impl ProtoCodec for NetworkItemStackDescriptor { - fn proto_serialize( - &self, - stream: &mut Vec, - ) -> Result<(), bedrockrs_proto_core::error::ProtoCodecError> { - match self { - NetworkItemStackDescriptor::Invalid { id } => id.proto_serialize(stream)?, - NetworkItemStackDescriptor::Valid { - id, - stack_size, - aux_value, - include_net_id, - include_net_id_data, - block_runtime_id, - user_data_buffer, - } => { - id.proto_serialize(stream)?; - stack_size.proto_serialize(stream)?; - aux_value.proto_serialize(stream)?; - include_net_id.proto_serialize(stream)?; - include_net_id_data.proto_serialize(stream)?; - block_runtime_id.proto_serialize(stream)?; - user_data_buffer.proto_serialize(stream)?; - } - }; - - Ok(()) - } - - fn proto_deserialize( - stream: &mut std::io::Cursor<&[u8]>, - ) -> Result { - let id = VAR::::proto_deserialize(stream)?; - if id.into_inner() == 0 { - Ok(Self::Invalid { id }) - } else { - let stack_size = LE::::proto_deserialize(stream)?; - let aux_value = LE::::proto_deserialize(stream)?; - let include_net_id = bool::proto_deserialize(stream)?; - - let include_net_id_data = if include_net_id { - Some(ItemStackNetIdVariant::proto_deserialize(stream)?) - } else { - None - }; - - Ok(Self::Valid { - id, - stack_size, - aux_value, - include_net_id, - include_net_id_data, - block_runtime_id: VAR::::proto_deserialize(stream)?, - user_data_buffer: String::proto_deserialize(stream)?, - }) - } - } -} diff --git a/crates/proto/src/types/network_permissions.rs b/crates/proto/src/types/network_permissions.rs deleted file mode 100644 index 60e9a53c..00000000 --- a/crates/proto/src/types/network_permissions.rs +++ /dev/null @@ -1,6 +0,0 @@ -use bedrockrs_proto_macros::ProtoCodec; - -#[derive(ProtoCodec, Debug, Clone)] -pub struct NetworkPermissions { - pub server_auth_sound_enabled: bool, -} diff --git a/crates/proto/src/types/pack_info_behavior.rs b/crates/proto/src/types/pack_info_behavior.rs deleted file mode 100644 index 953e4d92..00000000 --- a/crates/proto/src/types/pack_info_behavior.rs +++ /dev/null @@ -1,13 +0,0 @@ -use bedrockrs_core::int::LE; -use bedrockrs_proto_macros::ProtoCodec; - -#[derive(ProtoCodec, Debug, Clone)] -pub struct BehaviorPackInfoType { - id: String, - version: String, - size: LE, - content_key: String, - sub_pack_name: String, - content_identify: String, - has_scripts: bool, -} diff --git a/crates/proto/src/types/pack_info_resource.rs b/crates/proto/src/types/pack_info_resource.rs deleted file mode 100644 index 1ae2bb7a..00000000 --- a/crates/proto/src/types/pack_info_resource.rs +++ /dev/null @@ -1,14 +0,0 @@ -use bedrockrs_core::int::LE; -use bedrockrs_proto_macros::ProtoCodec; - -#[derive(ProtoCodec, Debug, Clone)] -pub struct ResourcePackInfoType { - id: String, - version: String, - size: LE, - content_key: String, - sub_pack_name: String, - content_identify: String, - has_scripts: bool, - ray_tracing_capable: bool, -} diff --git a/crates/proto/src/types/player_movement_settings.rs b/crates/proto/src/types/player_movement_settings.rs deleted file mode 100644 index 2da740c5..00000000 --- a/crates/proto/src/types/player_movement_settings.rs +++ /dev/null @@ -1,11 +0,0 @@ -use bedrockrs_core::int::VAR; -use bedrockrs_proto_macros::ProtoCodec; - -use crate::types::player_movement_mode::PlayerMovementMode; - -#[derive(ProtoCodec, Debug, Clone)] -pub struct PlayerMovementSettings { - pub authority_mode: PlayerMovementMode, - pub rewind_history_size: VAR, - pub server_authoritative_block_breaking: bool, -} diff --git a/crates/proto/src/types/spawn_biome_type.rs b/crates/proto/src/types/spawn_biome_type.rs deleted file mode 100644 index 7db0b113..00000000 --- a/crates/proto/src/types/spawn_biome_type.rs +++ /dev/null @@ -1,14 +0,0 @@ -use std::io::Cursor; -use std::sync::Arc; - -use bedrockrs_core::int::LE; -use bedrockrs_proto_core::error::ProtoCodecError; -use bedrockrs_proto_core::ProtoCodec; -use bedrockrs_proto_macros::ProtoCodec; - -#[derive(ProtoCodec, Debug, Clone)] -#[enum_repr(LE::)] -pub enum SpawnBiomeType { - Default = 0, - UserDefined = 1, -} diff --git a/crates/proto/src/types/text_message_data.rs b/crates/proto/src/types/text_message_data.rs deleted file mode 100644 index 264dfdbe..00000000 --- a/crates/proto/src/types/text_message_data.rs +++ /dev/null @@ -1,33 +0,0 @@ -#[derive(Debug, Clone)] -pub enum TextMessageData { - Raw(String), - Chat { - player_name: String, - message: String, - }, - Translate { - message: String, - parameters: Vec, - }, - Popup { - message: String, - parameters: Vec, - }, - JukeboxPopup { - message: String, - parameters: Vec, - }, - Tip(String), - SystemMessage(String), - Whisper { - player_name: String, - message: String, - }, - Announcement { - player_name: String, - message: String, - }, - TextObjectWhisper(String), - TextObject(String), - TextObjectAnnouncement(String), -} diff --git a/crates/proto/src/version/mod.rs b/crates/proto/src/version/mod.rs new file mode 100644 index 00000000..87fb7919 --- /dev/null +++ b/crates/proto/src/version/mod.rs @@ -0,0 +1,8 @@ +pub mod v662; +pub mod v671; +pub mod v685; +pub mod v686; +pub mod v712; +pub mod v729; +pub mod v748; +pub mod v766; diff --git a/crates/proto/src/version/v662/enums/abilities_index.rs b/crates/proto/src/version/v662/enums/abilities_index.rs new file mode 100644 index 00000000..6a7a3807 --- /dev/null +++ b/crates/proto/src/version/v662/enums/abilities_index.rs @@ -0,0 +1,29 @@ +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +#[enum_repr(i32)] +#[enum_endianness(var)] +#[repr(i32)] +pub enum AbilitiesIndex { + Invalid = -1, + Build = 0, + Mine = 1, + DoorsAndSwitches = 2, + OpenContainers = 3, + AttackPlayers = 4, + AttackMobs = 5, + OperatorCommands = 6, + Teleport = 7, + Invulnerable = 8, + Flying = 9, + MayFly = 10, + Instabuild = 11, + Lightning = 12, + FlySpeed = 13, + WalkSpeed = 14, + Muted = 15, + WorldBuilder = 16, + NoClip = 17, + PrivilegedBuilder = 18, + AbilityCount = 19, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/enums/actor_block_sync_message_id.rs b/crates/proto/src/version/v662/enums/actor_block_sync_message_id.rs new file mode 100644 index 00000000..4300bf34 --- /dev/null +++ b/crates/proto/src/version/v662/enums/actor_block_sync_message_id.rs @@ -0,0 +1,12 @@ +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +#[enum_repr(u64)] +#[enum_endianness(var)] +#[repr(u64)] +pub enum ActorBlockSyncMessageID { + NONE = 0, + CREATE = 1, + DESTROY = 2, +} + diff --git a/crates/proto/src/version/v662/enums/actor_damage_cause.rs b/crates/proto/src/version/v662/enums/actor_damage_cause.rs new file mode 100644 index 00000000..20a3931f --- /dev/null +++ b/crates/proto/src/version/v662/enums/actor_damage_cause.rs @@ -0,0 +1,44 @@ +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +#[enum_repr(i32)] +#[enum_endianness(var)] +#[repr(i32)] +pub enum ActorDamageCause { + None = -1, + Override = 0, + Contact = 1, + EntityAttack = 2, + Projectile = 3, + Suffocation = 4, + Fall = 5, + Fire = 6, + FireTick = 7, + Lava = 8, + Drowning = 9, + BlockExplosion = 10, + EntityExplosion = 11, + Void = 12, + SelfDestruct = 13, + Magic = 14, + Wither = 15, + Starve = 16, + Anvil = 17, + Thorns = 18, + FallingBlock = 19, + Piston = 20, + FlyIntoWall = 21, + Magma = 22, + Fireworks = 23, + Lightning = 24, + Charging = 25, + Temperature = 26, + Freezing = 27, + Stalactite = 28, + Stalagmite = 29, + RamAttack = 30, + SonicBoom = 31, + Campfire = 32, + SoulCampfire = 33, + All = 34, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/enums/actor_data_ids.rs b/crates/proto/src/version/v662/enums/actor_data_ids.rs new file mode 100644 index 00000000..4d559801 --- /dev/null +++ b/crates/proto/src/version/v662/enums/actor_data_ids.rs @@ -0,0 +1,134 @@ +pub enum ActorDataIDs { + Reserved0 = 0, + StructuralIntegrity = 1, + Variant = 2, + ColorIndex = 3, + Name = 4, + Owner = 5, + Target = 6, + AirSupply = 7, + EffectColor = 8, + EffectAmbience = 9, + Reserved010 = 10, + Hurt = 11, + HurtDir = 12, + RowTimeLeft = 13, + RowTimeRight = 14, + Value = 15, + DisplayTileRuntimeId = 16, + DisplayOffset = 17, + CustomDisplay = 18, + Swell = 19, + OldSwell = 20, + SwellDir = 21, + ChargeAmount = 22, + CarryBlockRuntimeId = 23, + ClientEvent = 24, + UsingItem = 25, + PlayerFlags = 26, + PlayerIndex = 27, + BedPosition = 28, + XPower = 29, + YPower = 30, + ZPower = 31, + AuxPower = 32, + FishX = 33, + FishZ = 34, + FishAngle = 35, + AuxValueData = 36, + LeashHolder = 37, + Reserved038 = 38, + HasNpc = 39, + NpcData = 40, + Actions = 41, + AirSupplyMax = 42, + MarkVariant = 43, + ContainerType = 44, + ContainerSize = 45, + ContainerStrengthModifier = 46, + BlockTarget = 47, + Inv = 48, + TargetA = 49, + TargetB = 50, + TargetC = 51, + AerialAttack = 52, + Reserved053 = 53, + Reserved054 = 54, + FuseTime = 55, + Reserved056 = 56, + SeatLockPassengerRotation = 57, + SeatLockPassengerRotationDegrees = 58, + SeatRotationOffset = 59, + SeatRotationOffsetDegrees = 60, + DataRadius = 61, + DataWaiting = 62, + DataParticle = 63, + PeekId = 64, + AttachFace = 65, + Attached = 66, + AttachPos = 67, + TradeTarget = 68, + Career = 69, + HasCommandBlock = 70, + CommandName = 71, + LastCommandOutput = 72, + TrackCommandOutput = 73, + Reserved074 = 74, + Strength = 75, + StrengthMax = 76, + DataSpellCastingColor = 77, + DataLifetimeTicks = 78, + PoseIndex = 79, + DataTickOffset = 80, + NametagAlwaysShow = 81, + Color2Index = 82, + NameAuthor = 83, + Score = 84, + BalloonAnchor = 85, + PuffedState = 86, + BubbleTime = 87, + Agent = 88, + SittingAmount = 89, + SittingAmountPrevious = 90, + EatingCounter = 91, + Reserved092 = 92, + LayingAmount = 93, + LayingAmountPrevious = 94, + DataDuration = 95, + DataSpawnTime = 96, + DataChangeRate = 97, + DataChangeOnPickup = 98, + DataPickupCount = 99, + InteractText = 100, + TradeTier = 101, + MaxTradeTier = 102, + TradeExperience = 103, + SkinId = 104, + SpawningFrames = 105, + CommandBlockTickDelay = 106, + CommandBlockExecuteOnFirstTick = 107, + AmbientSoundInterval = 108, + AmbientSoundIntervalRange = 109, + AmbientSoundEventName = 110, + FallDamageMultiplier = 111, + NameRawText = 112, + CanRideTarget = 113, + LowTierCuredTradeDiscount = 114, + HighTierCuredTradeDiscount = 115, + NearbyCuredTradeDiscount = 116, + NearbyCuredDiscountTimeStamp = 117, + Hitbox = 118, + IsBuoyant = 119, + FreezingEffectStrength = 120, + BuoyancyData = 121, + GoatHornCount = 122, + BaseRuntimeId = 123, + MovementSoundDistanceOffset = 124, + HeartbeatIntervalTicks = 125, + HeartbeatSoundEvent = 126, + PlayerLastDeathPos = 127, + PlayerLastDeathDimension = 128, + PlayerHasDied = 129, + CollisionBox = 130, + Count = 131, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/enums/actor_event.rs b/crates/proto/src/version/v662/enums/actor_event.rs new file mode 100644 index 00000000..9b8b9db4 --- /dev/null +++ b/crates/proto/src/version/v662/enums/actor_event.rs @@ -0,0 +1,65 @@ +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +#[enum_repr(i8)] +#[repr(i8)] +pub enum ActorEvent { + None = 0, + Jump = 1, + Hurt = 2, + Death = 3, + StartAttacking = 4, + StopAttacking = 5, + TamingFailed = 6, + TamingSucceeded = 7, + ShakeWetness = 8, + EatGrass = 10, + FishhookBubble = 11, + FishhookFishpos = 12, + FishhookHooktime = 13, + FishhookTease = 14, + SquidFleeing = 15, + ZombieConverting = 16, + PlayAmbient = 17, + SpawnAlive = 18, + StartOfferFlower = 19, + StopOfferFlower = 20, + LoveHearts = 21, + VillagerAngry = 22, + VillagerHappy = 23, + WitchHatMagic = 24, + FireworksExplode = 25, + InLoveHearts = 26, + SilverfishMergeAnim = 27, + GuardianAttackSound = 28, + DrinkPotion = 29, + ThrowPotion = 30, + PrimeTntcart = 31, + PrimeCreeper = 32, + AirSupply = 33, + AddPlayerLevels = 34, + GuardianMiningFatigue = 35, + AgentSwingArm = 36, + DragonStartDeathAnim = 37, + GroundDust = 38, + Shake = 39, + Feed = 57, + BabyAge = 60, + InstantDeath = 61, + NotifyTrade = 62, + LeashDestroyed = 63, + CaravanUpdated = 64, + TalismanActivate = 65, + UpdateStructureFeature = 66, + PlayerSpawnedMob = 67, + Puke = 68, + UpdateStackSize = 69, + StartSwimming = 70, + BalloonPop = 71, + TreasureHunt = 72, + SummonAgent = 73, + FinishedChargingItem = 74, + ActorGrowUp = 76, + VibrationDetected = 77, + DrinkMilk = 78, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/enums/actor_flags.rs b/crates/proto/src/version/v662/enums/actor_flags.rs new file mode 100644 index 00000000..3f51f359 --- /dev/null +++ b/crates/proto/src/version/v662/enums/actor_flags.rs @@ -0,0 +1,122 @@ +pub enum ActorFlags { + Unknown = -1, + OnFire = 0, + Sneaking = 1, + Riding = 2, + Sprinting = 3, + UsingItem = 4, + Invisible = 5, + Tempted = 6, + InLove = 7, + Saddled = 8, + Powered = 9, + Ignited = 10, + Baby = 11, + Converting = 12, + Critical = 13, + CanShowName = 14, + AlwaysShowName = 15, + NoAI = 16, + Silent = 17, + WallClimbing = 18, + CanClimb = 19, + CanSwim = 20, + CanFly = 21, + CanWalk = 22, + Resting = 23, + Sitting = 24, + Angry = 25, + Interested = 26, + Charged = 27, + Tamed = 28, + Orphaned = 29, + Leashed = 30, + Sheared = 31, + Gliding = 32, + Elder = 33, + Moving = 34, + Breathing = 35, + Chested = 36, + Stackable = 37, + ShowBottom = 38, + Standing = 39, + Shaking = 40, + Idling = 41, + Casting = 42, + Charging = 43, + WasdControlled = 44, + CanPowerJump = 45, + CanDash = 46, + Lingering = 47, + HasCollision = 48, + HasGravity = 49, + FireImmune = 50, + Dancing = 51, + Enchanted = 52, + ReturnTrident = 53, + ContainerIsPrivate = 54, + IsTransforming = 55, + DamageNearbyMobs = 56, + Swimming = 57, + Bribed = 58, + IsPregnant = 59, + LayingEgg = 60, + PassengerCanPick = 61, + TransitionSitting = 62, + Eating = 63, + LayingDown = 64, + Sneezing = 65, + Trusting = 66, + Rolling = 67, + Scared = 68, + InScaffolding = 69, + OverScaffolding = 70, + DescendThroughBlock = 71, + Blocking = 72, + TransitionBlocking = 73, + BlockedUsingShield = 74, + BlockedUsingDamagedShield = 75, + Sleeping = 76, + WantsToWake = 77, + TradeInterest = 78, + DoorBreaker = 79, + BreakingObstruction = 80, + DoorOpener = 81, + IsIllagerCaptain = 82, + Stunned = 83, + Roaring = 84, + DelayedAttack = 85, + IsAvoidingMobs = 86, + IsAvoidingBlock = 87, + FacingTargetToRangeAttack = 88, + HiddenWhenInvisible = 89, + IsInUi = 90, + Stalking = 91, + Emoting = 92, + Celebrating = 93, + Admiring = 94, + CelebratingSpecial = 95, + OutOfControl = 96, + RamAttack = 97, + PlayingDead = 98, + InAscendableBlock = 99, + OverDescendableBlock = 100, + Croaking = 101, + EatMob = 102, + JumpGoalJump = 103, + Emerging = 104, + Sniffing = 105, + Digging = 106, + SonicBoom = 107, + HasDashCooldown = 108, + PushTowardsClosestSpace = 109, + Scenting = 110, + Rising = 111, + FeelingHappy = 112, + Searching = 113, + Crawling = 114, + TimerFlag1 = 115, + TimerFlag2 = 116, + TimerFlag3 = 117, + Count = 118, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/enums/actor_link_type.rs b/crates/proto/src/version/v662/enums/actor_link_type.rs new file mode 100644 index 00000000..84923007 --- /dev/null +++ b/crates/proto/src/version/v662/enums/actor_link_type.rs @@ -0,0 +1,10 @@ +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +#[enum_repr(i8)] +#[repr(i8)] +pub enum ActorLinkType { + None = 0, + Riding = 1, + Passenger = 2, +} diff --git a/crates/proto/src/version/v662/enums/actor_type.rs b/crates/proto/src/version/v662/enums/actor_type.rs new file mode 100644 index 00000000..03c3612f --- /dev/null +++ b/crates/proto/src/version/v662/enums/actor_type.rs @@ -0,0 +1,311 @@ +use bedrockrs_macros::ProtoCodec; + +mod flags { + pub const UNDEFINED: i32 = 1; + pub const TYPE_MASK: i32 = 0x000000ff; + pub const MOB: i32 = 0x00000100; + pub const PATHFINDER_MOB: i32 = 0x00000200 | MOB; + pub const MONSTER: i32 = 0x00000800 | PATHFINDER_MOB; + pub const ANIMAL: i32 = 0x00001000 | PATHFINDER_MOB; + pub const TAMABLE_ANIMAL: i32 = 0x00004000 | ANIMAL; + pub const AMBIENT: i32 = 0x00008000 | MOB; + pub const UNDEAD_MOB: i32 = 0x00010000 | MONSTER; + pub const ZOMBIE_MONSTER: i32 = 0x00020000 | UNDEAD_MOB; + pub const ARTHROPOD: i32 = 0x00040000 | MONSTER; + pub const MINECART: i32 = 0x00080000; + pub const SKELETONMONSTER: i32 = 0x00100000 | UNDEAD_MOB; + pub const EQUINEANIMAL: i32 = 0x00200000 | TAMABLE_ANIMAL; + pub const PROJECTILE: i32 = 0x00400000; + pub const ABSTRACTARROW: i32 = 0x00800000; + pub const WATERANIMAL: i32 = 0x00002000 | PATHFINDER_MOB; + pub const VILLAGERBASE: i32 = 0x01000000 | PATHFINDER_MOB; + pub const CHICKEN: i32 = 10 | ANIMAL; + pub const COW: i32 = 11 | ANIMAL; + pub const PIG: i32 = 12 | ANIMAL; + pub const SHEEP: i32 = 13 | ANIMAL; + pub const WOLF: i32 = 14 | TAMABLE_ANIMAL; + pub const VILLAGER: i32 = 15 | VILLAGERBASE; + pub const MUSHROOMCOW: i32 = 16 | ANIMAL; + pub const SQUID: i32 = 17 | WATERANIMAL; + pub const RABBIT: i32 = 18 | ANIMAL; + pub const BAT: i32 = 19 | AMBIENT; + pub const IRONGOLEM: i32 = 20 | PATHFINDER_MOB; + pub const SNOWGOLEM: i32 = 21 | PATHFINDER_MOB; + pub const OCELOT: i32 = 22 | TAMABLE_ANIMAL; + pub const HORSE: i32 = 23 | EQUINEANIMAL; + pub const POLARBEAR: i32 = 28 | ANIMAL; + pub const LLAMA: i32 = 29 | ANIMAL; + pub const PARROT: i32 = 30 | TAMABLE_ANIMAL; + pub const DOLPHIN: i32 = 31 | WATERANIMAL; + pub const DONKEY: i32 = 24 | EQUINEANIMAL; + pub const MULE: i32 = 25 | EQUINEANIMAL; + pub const SKELETONHORSE: i32 = 26 | EQUINEANIMAL | UNDEAD_MOB; + pub const ZOMBIEHORSE: i32 = 27 | EQUINEANIMAL | UNDEAD_MOB; + pub const ZOMBIE: i32 = 32 | ZOMBIE_MONSTER; + pub const CREEPER: i32 = 33 | MONSTER; + pub const SKELETON: i32 = 34 | SKELETONMONSTER; + pub const SPIDER: i32 = 35 | ARTHROPOD; + pub const PIGZOMBIE: i32 = 36 | UNDEAD_MOB; + pub const SLIME: i32 = 37 | MONSTER; + pub const ENDERMAN: i32 = 38 | MONSTER; + pub const SILVERFISH: i32 = 39 | ARTHROPOD; + pub const CAVESPIDER: i32 = 40 | ARTHROPOD; + pub const GHAST: i32 = 41 | MONSTER; + pub const LAVASLIME: i32 = 42 | MONSTER; + pub const BLAZE: i32 = 43 | MONSTER; + pub const ZOMBIEVILLAGER: i32 = 44 | ZOMBIE_MONSTER; + pub const WITCH: i32 = 45 | MONSTER; + pub const STRAY: i32 = 46 | SKELETONMONSTER; + pub const HUSK: i32 = 47 | ZOMBIE_MONSTER; + pub const WITHERSKELETON: i32 = 48 | SKELETONMONSTER; + pub const GUARDIAN: i32 = 49 | MONSTER; + pub const ELDERGUARDIAN: i32 = 50 | MONSTER; + pub const NPC: i32 = 51 | MOB; + pub const WITHERBOSS: i32 = 52 | UNDEAD_MOB; + pub const DRAGON: i32 = 53 | MONSTER; + pub const SHULKER: i32 = 54 | MONSTER; + pub const ENDERMITE: i32 = 55 | ARTHROPOD; + pub const AGENT: i32 = 56 | MOB; + pub const VINDICATOR: i32 = 57 | MONSTER; + pub const PHANTOM: i32 = 58 | UNDEAD_MOB; + pub const ILLAGERBEAST: i32 = 59 | MONSTER; + pub const ARMORSTAND: i32 = 61 | MOB; + pub const TRIPODCAMERA: i32 = 62 | MOB; + pub const PLAYER: i32 = 63 | MOB; + pub const ITEMENTITY: i32 = 64; + pub const PRIMEDTNT: i32 = 65; + pub const FALLINGBLOCK: i32 = 66; + pub const MOVINGBLOCK: i32 = 67; + pub const EXPERIENCEPOTION: i32 = 68 | PROJECTILE; + pub const EXPERIENCE: i32 = 69; + pub const EYEOFENDER: i32 = 70; + pub const ENDERCRYSTAL: i32 = 71; + pub const FIREWORKSROCKET: i32 = 72; + pub const TRIDENT: i32 = 73 | PROJECTILE | ABSTRACTARROW; + pub const TURTLE: i32 = 74 | ANIMAL; + pub const CAT: i32 = 75 | TAMABLE_ANIMAL; + pub const SHULKERBULLET: i32 = 76 | PROJECTILE; + pub const FISHINGHOOK: i32 = 77; + pub const CHALKBOARD: i32 = 78; + pub const DRAGONFIREBALL: i32 = 79 | PROJECTILE; + pub const ARROW: i32 = 80 | PROJECTILE | ABSTRACTARROW; + pub const SNOWBALL: i32 = 81 | PROJECTILE; + pub const THROWNEGG: i32 = 82 | PROJECTILE; + pub const PAINTING: i32 = 83; + pub const LARGEFIREBALL: i32 = 85 | PROJECTILE; + pub const THROWNPOTION: i32 = 86 | PROJECTILE; + pub const ENDERPEARL: i32 = 87 | PROJECTILE; + pub const LEASHKNOT: i32 = 88; + pub const WITHERSKULL: i32 = 89 | PROJECTILE; + pub const BOATRIDEABLE: i32 = 90; + pub const WITHERSKULLDANGEROUS: i32 = 91 | PROJECTILE; + pub const LIGHTNINGBOLT: i32 = 93; + pub const SMALLFIREBALL: i32 = 94 | PROJECTILE; + pub const AREAEFFECTCLOUD: i32 = 95; + pub const LINGERINGPOTION: i32 = 101 | PROJECTILE; + pub const LLAMASPIT: i32 = 102 | PROJECTILE; + pub const EVOCATIONFANG: i32 = 103 | PROJECTILE; + pub const EVOCATIONILLAGER: i32 = 104 | MONSTER; + pub const VEX: i32 = 105 | MONSTER; + pub const MINECARTRIDEABLE: i32 = 84 | MINECART; + pub const MINECARTHOPPER: i32 = 96 | MINECART; + pub const MINECARTTNT: i32 = 97 | MINECART; + pub const MINECARTCHEST: i32 = 98 | MINECART; + pub const MINECARTFURNACE: i32 = 99 | MINECART; + pub const MINECARTCOMMANDBLOCK: i32 = 100 | MINECART; + pub const ICEBOMB: i32 = 106 | PROJECTILE; + pub const BALLOON: i32 = 107; + pub const PUFFERFISH: i32 = 108 | WATERANIMAL; + pub const SALMON: i32 = 109 | WATERANIMAL; + pub const DROWNED: i32 = 110 | ZOMBIE_MONSTER; + pub const TROPICALFISH: i32 = 111 | WATERANIMAL; + pub const FISH: i32 = 112 | WATERANIMAL; + pub const PANDA: i32 = 113 | ANIMAL; + pub const PILLAGER: i32 = 114 | MONSTER; + pub const VILLAGERV2: i32 = 115 | VILLAGERBASE; + pub const ZOMBIEVILLAGERV2: i32 = 116 | ZOMBIE_MONSTER; + pub const SHIELD: i32 = 117; + pub const WANDERINGTRADER: i32 = 118 | PATHFINDER_MOB; + pub const LECTERN: i32 = 119; + pub const ELDERGUARDIANGHOST: i32 = 120 | MONSTER; + pub const FOX: i32 = 121 | ANIMAL; + pub const BEE: i32 = 122 | MOB; + pub const PIGLIN: i32 = 123 | MOB; + pub const HOGLIN: i32 = 124 | ANIMAL; + pub const STRIDER: i32 = 125 | ANIMAL; + pub const ZOGLIN: i32 = 126 | UNDEAD_MOB; + pub const PIGLINBRUTE: i32 = 127 | MOB; + pub const GOAT: i32 = 128 | ANIMAL; + pub const GLOWSQUID: i32 = 129 | WATERANIMAL; + pub const AXOLOTL: i32 = 130 | ANIMAL; + pub const WARDEN: i32 = 131 | MONSTER; + pub const FROG: i32 = 132 | ANIMAL; + pub const TADPOLE: i32 = 133 | WATERANIMAL; + pub const ALLAY: i32 = 134 | MOB; + pub const CHESTBOATRIDEABLE: i32 = 136 | BOATRIDEABLE; + pub const TRADERLLAMA: i32 = 137 | LLAMA; + pub const CAMEL: i32 = 138 | ANIMAL; + pub const SNIFFER: i32 = 139 | ANIMAL; + pub const BREEZE: i32 = 140 | MONSTER; + pub const BREEZEWINDCHARGEPROJECTILE: i32 = 141 | PROJECTILE; + pub const ARMADILLO: i32 = 142 | ANIMAL; + pub const WINDCHARGEPROJECTILE: i32 = 143 | PROJECTILE; + pub const BOGGED: i32 = 144 | SKELETONMONSTER; +} + +#[derive(ProtoCodec, Clone, Debug)] +#[enum_repr(i32)] +#[enum_endianness(var)] +#[repr(i32)] +pub enum ActorType { + Undefined = flags::UNDEFINED, + TypeMask = flags::TYPE_MASK, + Mob = flags::MOB, + PathfinderMob = flags::PATHFINDER_MOB, + Monster = flags::MONSTER, + Animal = flags::ANIMAL, + TamableAnimal = flags::TAMABLE_ANIMAL, + Ambient = flags::AMBIENT, + UndeadMob = flags::UNDEAD_MOB, + ZombieMonster = flags::ZOMBIE_MONSTER, + Arthropod = flags::ARTHROPOD, + Minecart = flags::MINECART, + SkeletonMonster = flags::SKELETONMONSTER, + EquineAnimal = flags::EQUINEANIMAL, + Projectile = flags::PROJECTILE, + AbstractArrow = flags::ABSTRACTARROW, + WaterAnimal = flags::WATERANIMAL, + VillagerBase = flags::VILLAGERBASE, + Chicken = flags::CHICKEN, + Cow = flags::COW, + Pig = flags::PIG, + Sheep = flags::SHEEP, + Wolf = flags::WOLF, + Villager = flags::VILLAGER, + MushroomCow = flags::MUSHROOMCOW, + Squid = flags::SQUID, + Rabbit = flags::RABBIT, + Bat = flags::BAT, + IronGolem = flags::IRONGOLEM, + SnowGolem = flags::SNOWGOLEM, + Ocelot = flags::OCELOT, + Horse = flags::HORSE, + PolarBear = flags::POLARBEAR, + Llama = flags::LLAMA, + Parrot = flags::PARROT, + Dolphin = flags::DOLPHIN, + Donkey = flags::DONKEY, + Mule = flags::MULE, + SkeletonHorse = flags::SKELETONHORSE, + ZombieHorse = flags::ZOMBIEHORSE, + Zombie = flags::ZOMBIE, + Creeper = flags::CREEPER, + Skeleton = flags::SKELETON, + Spider = flags::SPIDER, + PigZombie = flags::PIGZOMBIE, + Slime = flags::SLIME, + EnderMan = flags::ENDERMAN, + Silverfish = flags::SILVERFISH, + CaveSpider = flags::CAVESPIDER, + Ghast = flags::GHAST, + LavaSlime = flags::LAVASLIME, + Blaze = flags::BLAZE, + ZombieVillager = flags::ZOMBIEVILLAGER, + Witch = flags::WITCH, + Stray = flags::STRAY, + Husk = flags::HUSK, + WitherSkeleton = flags::WITHERSKELETON, + Guardian = flags::GUARDIAN, + ElderGuardian = flags::ELDERGUARDIAN, + Npc = flags::NPC, + WitherBoss = flags::WITHERBOSS, + Dragon = flags::DRAGON, + Shulker = flags::SHULKER, + Endermite = flags::ENDERMITE, + Agent = flags::AGENT, + Vindicator = flags::VINDICATOR, + Phantom = flags::PHANTOM, + IllagerBeast = flags::ILLAGERBEAST, + ArmorStand = flags::ARMORSTAND, + TripodCamera = flags::TRIPODCAMERA, + Player = flags::PLAYER, + ItemEntity = flags::ITEMENTITY, + PrimedTnt = flags::PRIMEDTNT, + FallingBlock = flags::FALLINGBLOCK, + MovingBlock = flags::MOVINGBLOCK, + ExperiencePotion = flags::EXPERIENCEPOTION, + Experience = flags::EXPERIENCE, + EyeOfEnder = flags::EYEOFENDER, + EnderCrystal = flags::ENDERCRYSTAL, + FireworksRocket = flags::FIREWORKSROCKET, + Trident = flags::TRIDENT, + Turtle = flags::TURTLE, + Cat = flags::CAT, + ShulkerBullet = flags::SHULKERBULLET, + FishingHook = flags::FISHINGHOOK, + Chalkboard = flags::CHALKBOARD, + DragonFireball = flags::DRAGONFIREBALL, + Arrow = flags::ARROW, + Snowball = flags::SNOWBALL, + ThrownEgg = flags::THROWNEGG, + Painting = flags::PAINTING, + LargeFireball = flags::LARGEFIREBALL, + ThrownPotion = flags::THROWNPOTION, + Enderpearl = flags::ENDERPEARL, + LeashKnot = flags::LEASHKNOT, + WitherSkull = flags::WITHERSKULL, + BoatRideable = flags::BOATRIDEABLE, + WitherSkullDangerous = flags::WITHERSKULLDANGEROUS, + LightningBolt = flags::LIGHTNINGBOLT, + SmallFireball = flags::SMALLFIREBALL, + AreaEffectCloud = flags::AREAEFFECTCLOUD, + LingeringPotion = flags::LINGERINGPOTION, + LlamaSpit = flags::LLAMASPIT, + EvocationFang = flags::EVOCATIONFANG, + EvocationIllager = flags::EVOCATIONILLAGER, + Vex = flags::VEX, + MinecartRideable = flags::MINECARTRIDEABLE, + MinecartHopper = flags::MINECARTHOPPER, + MinecartTNT = flags::MINECARTTNT, + MinecartChest = flags::MINECARTCHEST, + MinecartFurnace = flags::MINECARTFURNACE, + MinecartCommandBlock = flags::MINECARTCOMMANDBLOCK, + IceBomb = flags::ICEBOMB, + Balloon = flags::BALLOON, + Pufferfish = flags::PUFFERFISH, + Salmon = flags::SALMON, + Drowned = flags::DROWNED, + Tropicalfish = flags::TROPICALFISH, + Fish = flags::FISH, + Panda = flags::PANDA, + Pillager = flags::PILLAGER, + VillagerV2 = flags::VILLAGERV2, + ZombieVillagerV2 = flags::ZOMBIEVILLAGERV2, + Shield = flags::SHIELD, + WanderingTrader = flags::WANDERINGTRADER, + Lectern = flags::LECTERN, + ElderGuardianGhost = flags::ELDERGUARDIANGHOST, + Fox = flags::FOX, + Bee = flags::BEE, + Piglin = flags::PIGLIN, + Hoglin = flags::HOGLIN, + Strider = flags::STRIDER, + Zoglin = flags::ZOGLIN, + PiglinBrute = flags::PIGLINBRUTE, + Goat = flags::GOAT, + GlowSquid = flags::GLOWSQUID, + Axolotl = flags::AXOLOTL, + Warden = flags::WARDEN, + Frog = flags::FROG, + Tadpole = flags::TADPOLE, + Allay = flags::ALLAY, + ChestBoatRideable = flags::CHESTBOATRIDEABLE, + TraderLlama = flags::TRADERLLAMA, + Camel = flags::CAMEL, + Sniffer = flags::SNIFFER, + Breeze = flags::BREEZE, + BreezeWindChargeProjectile = flags::BREEZEWINDCHARGEPROJECTILE, + Armadillo = flags::ARMADILLO, + WindChargeProjectile = flags::WINDCHARGEPROJECTILE, + Bogged = flags::BOGGED, +} diff --git a/crates/proto/src/version/v662/enums/agent_action_type.rs b/crates/proto/src/version/v662/enums/agent_action_type.rs new file mode 100644 index 00000000..efa31bf6 --- /dev/null +++ b/crates/proto/src/version/v662/enums/agent_action_type.rs @@ -0,0 +1,26 @@ +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +#[enum_repr(i32)] +#[enum_endianness(le)] +#[repr(i32)] +pub enum AgentActionType { + Attack = 1, + Collect = 2, + Destroy = 3, + DetectRedstone = 4, + DetectObstacle = 5, + Drop = 6, + DropAll = 7, + Inspect = 8, + InspectData = 9, + InspectItemCount = 10, + InspectItemDetail = 11, + InspectItemSpace = 12, + Interact = 13, + Move = 14, + PlaceBlock = 15, + Till = 16, + TransferItemTo = 17, + Turn = 18, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/enums/animation_mode.rs b/crates/proto/src/version/v662/enums/animation_mode.rs new file mode 100644 index 00000000..531cbdaa --- /dev/null +++ b/crates/proto/src/version/v662/enums/animation_mode.rs @@ -0,0 +1,10 @@ +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +#[enum_repr(i8)] +#[repr(i8)] +pub enum AnimationMode { + None = 0, + Layers = 1, + Blocks = 2, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/enums/attribute_modifier_operation.rs b/crates/proto/src/version/v662/enums/attribute_modifier_operation.rs new file mode 100644 index 00000000..edd85c33 --- /dev/null +++ b/crates/proto/src/version/v662/enums/attribute_modifier_operation.rs @@ -0,0 +1,18 @@ +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug, Eq, PartialEq)] +#[enum_repr(i32)] +#[enum_endianness(le)] +#[repr(i32)] +pub enum AttributeModifierOperation { + Addition = 0, + MultiplyBase = 1, + MultiplyTotal = 2, + Cap = 3, + TotalOperations = 4, +} + +impl AttributeModifierOperation { + pub const OPERATION_INVALID: AttributeModifierOperation = AttributeModifierOperation::TotalOperations; +} + diff --git a/crates/proto/src/version/v662/enums/attribute_operands.rs b/crates/proto/src/version/v662/enums/attribute_operands.rs new file mode 100644 index 00000000..1fcb10a6 --- /dev/null +++ b/crates/proto/src/version/v662/enums/attribute_operands.rs @@ -0,0 +1,16 @@ +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug, Eq, PartialEq)] +#[enum_repr(i32)] +#[enum_endianness(le)] +#[repr(i32)] +pub enum AttributeOperands { + Min = 0, + Max = 1, + Current = 2, + TotalOperands = 3, +} + +impl AttributeOperands { + pub const OPERAND_INVALID: AttributeOperands = AttributeOperands::TotalOperands; +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/enums/book_edit_action.rs b/crates/proto/src/version/v662/enums/book_edit_action.rs new file mode 100644 index 00000000..49b53b70 --- /dev/null +++ b/crates/proto/src/version/v662/enums/book_edit_action.rs @@ -0,0 +1,29 @@ +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +#[enum_repr(i8)] +#[repr(i8)] +pub enum BookEditAction { + ReplacePage { + page_index: i8, + text_a: String, + text_b: String, + } = 0, + AddPage { + page_index: i8, + text_a: String, + text_b: String, + } = 1, + DeletePage { + page_index: i8, + } = 2, + SwapPages { + page_index_a: i8, + page_index_b: i8, + } = 3, + Finalize { + text_a: String, + text_b: String, + xuid: String, + } = 4, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/enums/boss_event_update_type.rs b/crates/proto/src/version/v662/enums/boss_event_update_type.rs new file mode 100644 index 00000000..5861c95c --- /dev/null +++ b/crates/proto/src/version/v662/enums/boss_event_update_type.rs @@ -0,0 +1,47 @@ +use crate::version::v662::types::ActorUniqueID; +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +#[enum_repr(i32)] +#[enum_endianness(le)] +#[repr(i32)] +pub enum BossEventUpdateType { + Add { + name: String, + #[endianness(le)] + health_percent: f32, + #[endianness(le)] + darken_screen: u16, + } = 0, + PlayerAdded { + player_id: ActorUniqueID, + } = 1, + Remove = 2, + PlayerRemoved { + player_id: ActorUniqueID, + } = 3, + UpdatePercent { + #[endianness(le)] + health_percent: f32, + } = 4, + UpdateName { + name: String, + } = 5, + UpdateProperties { + #[endianness(le)] + darken_screen: u16, + #[endianness(var)] + color: u32, + #[endianness(var)] + overlay: u32, + } = 6, + UpdateStyle { + #[endianness(var)] + color: u32, + #[endianness(var)] + overlay: u32, + } = 7, + Query { + player_id: ActorUniqueID, + } = 8, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/enums/build_platform.rs b/crates/proto/src/version/v662/enums/build_platform.rs new file mode 100644 index 00000000..041421f7 --- /dev/null +++ b/crates/proto/src/version/v662/enums/build_platform.rs @@ -0,0 +1,25 @@ +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +#[enum_repr(i32)] +#[enum_endianness(le)] +#[repr(i32)] +pub enum BuildPlatform { + Google = 1, + IOS = 2, + OSX = 3, + Amazon = 4, + GearVR = 5, + UWP = 7, + Win32 = 8, + Dedicated = 9, + #[deprecated] TvOs = 10, + Sony = 11, + /// PlayStation + Nx = 12, + /// Nintendo Switch + Xbox = 13, + #[deprecated] WindowsPhone = 14, + Linux = 15, + Unknown = -1, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/enums/camera_shake_action.rs b/crates/proto/src/version/v662/enums/camera_shake_action.rs new file mode 100644 index 00000000..1083fd32 --- /dev/null +++ b/crates/proto/src/version/v662/enums/camera_shake_action.rs @@ -0,0 +1,9 @@ +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +#[enum_repr(i8)] +#[repr(i8)] +pub enum CameraShakeAction { + Add = 0, + Stop = 1, +} diff --git a/crates/proto/src/version/v662/enums/camera_shake_type.rs b/crates/proto/src/version/v662/enums/camera_shake_type.rs new file mode 100644 index 00000000..ab36213a --- /dev/null +++ b/crates/proto/src/version/v662/enums/camera_shake_type.rs @@ -0,0 +1,9 @@ +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +#[enum_repr(i8)] +#[repr(i8)] +pub enum CameraShakeType { + Positional = 0, + Rotational = 1, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/enums/chat_restriction_level.rs b/crates/proto/src/version/v662/enums/chat_restriction_level.rs new file mode 100644 index 00000000..560736b7 --- /dev/null +++ b/crates/proto/src/version/v662/enums/chat_restriction_level.rs @@ -0,0 +1,10 @@ +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +#[enum_repr(i8)] +#[repr(i8)] +pub enum ChatRestrictionLevel { + None = 0, + Dropped = 1, + Disabled = 2, +} diff --git a/crates/proto/src/version/v662/enums/client_play_mode.rs b/crates/proto/src/version/v662/enums/client_play_mode.rs new file mode 100644 index 00000000..9dfc90e9 --- /dev/null +++ b/crates/proto/src/version/v662/enums/client_play_mode.rs @@ -0,0 +1,18 @@ +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +#[enum_repr(u32)] +#[enum_endianness(var)] +#[repr(u32)] +pub enum ClientPlayMode { + Normal = 0, + Teaser = 1, + Screen = 2, + Viewer = 3, + Reality = 4, + Placement = 5, + LivingRoom = 6, + ExitLevel = 7, + ExitLevelLivingRoom = 8, + NumModes = 9, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/enums/code_builder_storage.rs b/crates/proto/src/version/v662/enums/code_builder_storage.rs new file mode 100644 index 00000000..38934ad3 --- /dev/null +++ b/crates/proto/src/version/v662/enums/code_builder_storage.rs @@ -0,0 +1,19 @@ +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +#[enum_repr(i8)] +#[repr(i8)] +pub enum CodeBuilderStorageCategory { + None = 0, + CodeStatus = 1, + Instantiation = 2, +} +#[derive(ProtoCodec, Clone, Debug)] +#[enum_repr(i8)] +#[repr(i8)] +pub enum CodeBuilderStorageOperation { + None = 0, + Get = 1, + Set = 2, + Reset = 3, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/enums/command_block_mode.rs b/crates/proto/src/version/v662/enums/command_block_mode.rs new file mode 100644 index 00000000..b7bd00a0 --- /dev/null +++ b/crates/proto/src/version/v662/enums/command_block_mode.rs @@ -0,0 +1,11 @@ +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +#[enum_repr(u32)] +#[enum_endianness(var)] +#[repr(u32)] +pub enum CommandBlockMode { + Normal = 0, + Chain = 2, + Repeating = 1, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/enums/command_origin_type.rs b/crates/proto/src/version/v662/enums/command_origin_type.rs new file mode 100644 index 00000000..73cefb63 --- /dev/null +++ b/crates/proto/src/version/v662/enums/command_origin_type.rs @@ -0,0 +1,24 @@ +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +#[enum_repr(u32)] +#[enum_endianness(var)] +#[repr(u32)] +pub enum CommandOriginType { + Player = 0, + CommandBlock = 1, + MinecartCommandBlock = 2, + DevConsole(#[endianness(var)] i64) = 3, + Test(#[endianness(var)] i64) = 4, + AutomationPlayer = 5, + ClientAutomation = 6, + DedicatedServer = 7, + Entity = 8, + Virtual = 9, + GameArgument = 10, + EntityServer = 11, + Precompiled = 12, + GameDirectorEntityServer = 13, + Scripting = 14, + ExecuteContext = 15, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/enums/command_output_type.rs b/crates/proto/src/version/v662/enums/command_output_type.rs new file mode 100644 index 00000000..f1ff7cb5 --- /dev/null +++ b/crates/proto/src/version/v662/enums/command_output_type.rs @@ -0,0 +1,12 @@ +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +#[enum_repr(i8)] +#[repr(i8)] +pub enum CommandOutputType { + None = 0, + LastOutput = 1, + Silent = 2, + AllOutput = 3, + DataSet(String) = 4, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/enums/command_parameter_option.rs b/crates/proto/src/version/v662/enums/command_parameter_option.rs new file mode 100644 index 00000000..918245dd --- /dev/null +++ b/crates/proto/src/version/v662/enums/command_parameter_option.rs @@ -0,0 +1,7 @@ +/// Bitflags for AvailableCommand's ParameterDataEntry's options +pub enum CommandParameterOption { + None = 0, + EnumAutocompleteExpansion = 0x01, + HasSemanticConstraint = 0x02, + EnumAsChainedCommand = 0x04, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/enums/command_permission_level.rs b/crates/proto/src/version/v662/enums/command_permission_level.rs new file mode 100644 index 00000000..c59a248e --- /dev/null +++ b/crates/proto/src/version/v662/enums/command_permission_level.rs @@ -0,0 +1,13 @@ +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +#[enum_repr(i8)] +#[repr(i8)] +pub enum CommandPermissionLevel { + Any = 0, + GameDirectors = 1, + Admin = 2, + Host = 3, + Owner = 4, + Internal = 5, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/enums/complex_inventory_transaction_type.rs b/crates/proto/src/version/v662/enums/complex_inventory_transaction_type.rs new file mode 100644 index 00000000..35b33db2 --- /dev/null +++ b/crates/proto/src/version/v662/enums/complex_inventory_transaction_type.rs @@ -0,0 +1,13 @@ +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +#[enum_repr(u32)] +#[enum_endianness(var)] +#[repr(u32)] +pub enum ComplexInventoryTransactionType { + NormalTransaction = 0, + InventoryMismatch = 1, + ItemUseTransaction = 2, + ItemUseOnEntityTransaction = 3, + ItemReleaseTransaction = 4, +} \ No newline at end of file diff --git a/crates/proto/src/types/disconnect_reason.rs b/crates/proto/src/version/v662/enums/connection_fail_reason.rs similarity index 86% rename from crates/proto/src/types/disconnect_reason.rs rename to crates/proto/src/version/v662/enums/connection_fail_reason.rs index 66d083f5..59081df9 100644 --- a/crates/proto/src/types/disconnect_reason.rs +++ b/crates/proto/src/version/v662/enums/connection_fail_reason.rs @@ -1,9 +1,10 @@ -use bedrockrs_core::int::VAR; -use bedrockrs_proto_macros::ProtoCodec; +use bedrockrs_macros::ProtoCodec; -#[derive(ProtoCodec, Debug, Clone)] -#[enum_repr(VAR::)] -pub enum DisconnectReason { +#[derive(ProtoCodec, Clone, Debug)] +#[enum_repr(i32)] +#[enum_endianness(var)] +#[repr(i32)] +pub enum ConnectionFailReason { Unknown = 0, CantConnectNoInternet = 1, NoPermissions = 2, @@ -66,14 +67,16 @@ pub enum DisconnectReason { IncompatiblePack = 59, OutOfStorage = 60, InvalidLevel = 61, - DisconnectPacket_DEPRECATED = 62, + #[deprecated] + DisconnectPacket = 62, BlockMismatch = 63, InvalidHeights = 64, InvalidWidths = 65, ConnectionLost = 66, ZombieConnection = 67, Shutdown = 68, - ReasonNotSet_DEPRECATED = 69, + #[deprecated] + ReasonNotSet = 69, LoadingStateTimeout = 70, ResourcePackLoadingFailed = 71, SearchingForSessionLoadingScreenFailed = 72, @@ -93,7 +96,7 @@ pub enum DisconnectReason { NetherNetNegotiationTimeout = 86, NetherNetInactivityTimeout = 87, StaleConnectionBeingReplaced = 88, - RealmsSessionNotFound_DEPRECATED = 89, + RealmsSessionNotFound = 89, BadPacket = 90, NetherNetFailedToCreateOffer = 91, NetherNetFailedToCreateAnswer = 92, @@ -113,11 +116,4 @@ pub enum DisconnectReason { RequestServerShutdown = 106, ClientGameSetupCancelled = 107, ClientGameSetupFailed = 108, - NoVenue = 109, - NetherNetSignalingSignInFailed = 110, - SessionAccessDenied = 111, - ServiceSignInIssue = 112, - NetherNetNoSignalingChannel = 113, - NetherNetNotLoggedIn = 114, - NetherNetClientSignalingError = 115, } diff --git a/crates/proto/src/version/v662/enums/container_enum_name.rs b/crates/proto/src/version/v662/enums/container_enum_name.rs new file mode 100644 index 00000000..d4d06464 --- /dev/null +++ b/crates/proto/src/version/v662/enums/container_enum_name.rs @@ -0,0 +1,70 @@ +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +#[enum_repr(i8)] +#[repr(i8)] +pub enum ContainerName { + AnvilInputContainer = 0, + AnvilMaterialContainer = 1, + AnvilResultPreviewContainer = 2, + SmithingTableInputContainer = 3, + SmithingTableMaterialContainer = 4, + SmithingTableResultPreviewContainer = 5, + ArmorContainer = 6, + LevelEntityContainer = 7, + BeaconPaymentContainer = 8, + BrewingStandInputContainer = 9, + BrewingStandResultContainer = 10, + BrewingStandFuelContainer = 11, + CombinedHotbarAndInventoryContainer = 12, + CraftingInputContainer = 13, + CraftingOutputPreviewContainer = 14, + RecipeConstructionContainer = 15, + RecipeNatureContainer = 16, + RecipeItemsContainer = 17, + RecipeSearchContainer = 18, + RecipeSearchBarContainer = 19, + RecipeEquipmentContainer = 20, + RecipeBookContainer = 21, + EnchantingInputContainer = 22, + EnchantingMaterialContainer = 23, + FurnaceFuelContainer = 24, + FurnaceIngredientContainer = 25, + FurnaceResultContainer = 26, + HorseEquipContainer = 27, + HotbarContainer = 28, + InventoryContainer = 29, + ShulkerBoxContainer = 30, + TradeIngredient1Container = 31, + TradeIngredient2Container = 32, + TradeResultPreviewContainer = 33, + OffhandContainer = 34, + CompoundCreatorInput = 35, + CompoundCreatorOutputPreview = 36, + ElementConstructorOutputPreview = 37, + MaterialReducerInput = 38, + MaterialReducerOutput = 39, + LabTableInput = 40, + LoomInputContainer = 41, + LoomDyeContainer = 42, + LoomMaterialContainer = 43, + LoomResultPreviewContainer = 44, + BlastFurnaceIngredientContainer = 45, + SmokerIngredientContainer = 46, + Trade2Ingredient1Container = 47, + Trade2Ingredient2Container = 48, + Trade2ResultPreviewContainer = 49, + GrindstoneInputContainer = 50, + GrindstoneAdditionalContainer = 51, + GrindstoneResultPreviewContainer = 52, + StonecutterInputContainer = 53, + StonecutterResultPreviewContainer = 54, + CartographyInputContainer = 55, + CartographyAdditionalContainer = 56, + CartographyResultPreviewContainer = 57, + BarrelContainer = 58, + CursorContainer = 59, + CreatedOutputContainer = 60, + SmithingTableTemplateContainer = 61, + CrafterLevelEntityContainer = 62, +} diff --git a/crates/proto/src/version/v662/enums/container_id.rs b/crates/proto/src/version/v662/enums/container_id.rs new file mode 100644 index 00000000..b701872a --- /dev/null +++ b/crates/proto/src/version/v662/enums/container_id.rs @@ -0,0 +1,15 @@ +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +#[enum_repr(i8)] +#[repr(i8)] +pub enum ContainerID { + None = -1, + Inventory = 0, + First = 1, + Last = 100, + Offhand = 119, + Armor = 120, + SelectionSlots = 122, + PlayerOnlyUI = 124, +} diff --git a/crates/proto/src/version/v662/enums/container_type.rs b/crates/proto/src/version/v662/enums/container_type.rs new file mode 100644 index 00000000..9d2ab7ac --- /dev/null +++ b/crates/proto/src/version/v662/enums/container_type.rs @@ -0,0 +1,46 @@ +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +#[enum_repr(i8)] +#[repr(i8)] +pub enum ContainerType { + None = -9, + Inventory = -1, + Container = 0, + Workbench = 1, + Furnace = 2, + Enchantment = 3, + BrewingStand = 4, + Anvil = 5, + Dispenser = 6, + Dropper = 7, + Hopper = 8, + Cauldron = 9, + MinecartChest = 10, + MinecartHopper = 11, + Horse = 12, + Beacon = 13, + StructureEditor = 14, + Trade = 15, + CommandBlock = 16, + Jukebox = 17, + Armor = 18, + Hand = 19, + CompoundCreator = 20, + ElementConstructor = 21, + MaterialReducer = 22, + LabTable = 23, + Loom = 24, + Lectern = 25, + Grindstone = 26, + BlastFurnace = 27, + Smoker = 28, + StoneCutter = 29, + Cartography = 30, + Hud = 31, + JigsawEditor = 32, + SmithingTable = 33, + ChestBoat = 34, + DecoratedPot = 35, + Crafter = 36, +} diff --git a/crates/proto/src/version/v662/enums/crafting_data_entry_type.rs b/crates/proto/src/version/v662/enums/crafting_data_entry_type.rs new file mode 100644 index 00000000..3217ec7e --- /dev/null +++ b/crates/proto/src/version/v662/enums/crafting_data_entry_type.rs @@ -0,0 +1,64 @@ +use crate::version::v662::types::{NetworkItemInstanceDescriptor, ShapedChemistryRecipe, ShapedRecipe, ShapelessRecipe, ShulkerBoxRecipe, SmithingTransformRecipe, SmithingTrimRecipe}; +use bedrockrs_macros::ProtoCodec; +use uuid::Uuid; + +#[derive(ProtoCodec, Clone, Debug)] +#[enum_repr(i32)] +#[enum_endianness(var)] +#[repr(i32)] +pub enum CraftingDataEntryType { + ShapelessRecipe { + shapeless_recipe: ShapelessRecipe, + #[endianness(var)] + net_id: i32, + } = 0, + ShapedRecipe { + shaped_recipe: ShapedRecipe, + #[endianness(var)] + net_id: i32, + } = 1, + FurnaceRecipe { + #[endianness(var)] + item_data: i32, + result_item: NetworkItemInstanceDescriptor, + recipe_tag: String, + } = 2, + FurnaceAuxRecipe { + #[endianness(var)] + item_data: i32, + #[endianness(var)] + auxiliary_item_data: i32, + result_item: NetworkItemInstanceDescriptor, + recipe_tag: String, + } = 3, + MultiRecipe { + multi_recipe: Uuid, + #[endianness(var)] + net_id: i32, + } = 4, + ShulkerBoxRecipe { + shulker_box_recipe: ShulkerBoxRecipe, + #[endianness(var)] + net_id: i32, + } = 5, + ShapelessChemistryRecipe { + shapeless_chemistry_recipe: ShapelessRecipe, + #[endianness(var)] + net_id: i32, + } = 6, + ShapedChemistryRecipe { + shaped_chemistry_recipe: ShapedChemistryRecipe, + #[endianness(var)] + net_id: i32, + } = 7, + SmithingTransformRecipe { + smithing_transform_recipe: SmithingTransformRecipe, + #[endianness(var)] + net_id: i32, + } = 8, + SmithingTrimRecipe { + smithing_trim_recipe: SmithingTrimRecipe, + #[endianness(var)] + net_id: i32, + } = 9, +} diff --git a/crates/proto/src/version/v662/enums/crafting_type.rs b/crates/proto/src/version/v662/enums/crafting_type.rs new file mode 100644 index 00000000..62fe4bbd --- /dev/null +++ b/crates/proto/src/version/v662/enums/crafting_type.rs @@ -0,0 +1,5 @@ +#[deprecated] +pub enum CraftingType { + Inventory = 0, + Crafting = 1, +} diff --git a/crates/proto/src/version/v662/enums/data_item_type.rs b/crates/proto/src/version/v662/enums/data_item_type.rs new file mode 100644 index 00000000..86b2e400 --- /dev/null +++ b/crates/proto/src/version/v662/enums/data_item_type.rs @@ -0,0 +1,18 @@ +use crate::version::v662::types::BlockPos; +use bedrockrs_macros::ProtoCodec; +use vek::Vec3; + +#[derive(ProtoCodec, Clone, Debug)] +#[enum_repr(i8)] +#[repr(i8)] +pub enum DataItemType { + Byte(i8) = 0, + Short(#[endianness(le)] i16) = 1, + Int(#[endianness(var)] i32) = 2, + Float(#[endianness(le)] f32) = 3, + String(String) = 4, + NBT(#[nbt] nbtx::Value) = 5, + Pos(BlockPos) = 6, + Int64(#[endianness(var)] i64) = 7, + Vec3(#[endianness(le)] Vec3) = 8, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/enums/difficulty.rs b/crates/proto/src/version/v662/enums/difficulty.rs new file mode 100644 index 00000000..eeff09fd --- /dev/null +++ b/crates/proto/src/version/v662/enums/difficulty.rs @@ -0,0 +1,14 @@ +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +#[enum_repr(i32)] +#[enum_endianness(var)] +#[repr(i32)] +pub enum Difficulty { + Peaceful = 0, + Easy = 1, + Normal = 2, + Hard = 3, + Count = 4, + Unknown = 5, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/enums/easing_type.rs b/crates/proto/src/version/v662/enums/easing_type.rs new file mode 100644 index 00000000..813f2dcb --- /dev/null +++ b/crates/proto/src/version/v662/enums/easing_type.rs @@ -0,0 +1,41 @@ +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +#[enum_repr(u8)] +#[repr(u8)] +pub enum EasingType { + Linear = 0, + Spring = 1, + InQuad = 2, + OutQuad = 3, + InOutQuad = 4, + InCubic = 5, + OutCubic = 6, + InOutCubic = 7, + InQuart = 8, + OutQuart = 9, + InOutQuart = 10, + InQuint = 11, + OutQuint = 12, + InOutQuint = 13, + InSine = 14, + OutSine = 15, + InOutSine = 16, + InExpo = 17, + OutExpo = 18, + InOutExpo = 19, + InCirc = 20, + OutCirc = 21, + InOutCirc = 22, + InBounce = 23, + OutBounce = 24, + InOutBounce = 25, + InBack = 26, + OutBack = 27, + InOutBack = 28, + InElastic = 29, + OutElastic = 30, + InOutElastic = 31, + Count = 32, + Invalid = 33, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/enums/editor_world_type.rs b/crates/proto/src/version/v662/enums/editor_world_type.rs new file mode 100644 index 00000000..1f60b2b8 --- /dev/null +++ b/crates/proto/src/version/v662/enums/editor_world_type.rs @@ -0,0 +1,11 @@ +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +#[enum_repr(i32)] +#[enum_endianness(var)] +#[repr(i32)] +pub enum EditorWorldType { + NonEditor = 0, + EditorProject = 1, + EditorTestLevel = 2, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/enums/education_edition_offer.rs b/crates/proto/src/version/v662/enums/education_edition_offer.rs new file mode 100644 index 00000000..07caa09d --- /dev/null +++ b/crates/proto/src/version/v662/enums/education_edition_offer.rs @@ -0,0 +1,11 @@ +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +#[enum_repr(i32)] +#[enum_endianness(var)] +#[repr(i32)] +pub enum EducationEditionOffer { + None = 0, + RestOfWorld = 1, + #[deprecated] China = 2, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/enums/enchant_type.rs b/crates/proto/src/version/v662/enums/enchant_type.rs new file mode 100644 index 00000000..bfdc8691 --- /dev/null +++ b/crates/proto/src/version/v662/enums/enchant_type.rs @@ -0,0 +1,47 @@ +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +#[enum_repr(i8)] +#[repr(i8)] +pub enum EnchantType { + ArmorAll = 0, + ArmorFire = 1, + ArmorFall = 2, + ArmorExplosive = 3, + ArmorProjectile = 4, + ArmorThorns = 5, + WaterBreath = 6, + WaterSpeed = 7, + WaterAffinity = 8, + WeaponDamage = 9, + WeaponUndead = 10, + WeaponArthropod = 11, + WeaponKnockback = 12, + WeaponFire = 13, + WeaponLoot = 14, + MiningEfficiency = 15, + MiningSilkTouch = 16, + MiningDurability = 17, + MiningLoot = 18, + BowDamage = 19, + BowKnockback = 20, + BowFire = 21, + BowInfinity = 22, + FishingLoot = 23, + FishingLure = 24, + FrostWalker = 25, + Mending = 26, + CurseBinding = 27, + CurseVanishing = 28, + TridentImpaling = 29, + TridentRiptide = 30, + TridentLoyalty = 31, + TridentChanneling = 32, + CrossbowMultishot = 33, + CrossbowPiercing = 34, + CrossbowQuickCharge = 35, + SoulSpeed = 36, + SwiftSneak = 37, + NumEnchantments = 38, + InvalidEnchantment = 39, +} diff --git a/crates/proto/src/version/v662/enums/game_publish_setting.rs b/crates/proto/src/version/v662/enums/game_publish_setting.rs new file mode 100644 index 00000000..0971e604 --- /dev/null +++ b/crates/proto/src/version/v662/enums/game_publish_setting.rs @@ -0,0 +1,13 @@ +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +#[enum_repr(i32)] +#[enum_endianness(var)] +#[repr(i32)] +pub enum GamePublishSetting { + NoMultiPlay = 0, + InviteOnly = 1, + FriendsOnly = 2, + FriendsOfFriends = 3, + Public = 4, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/enums/game_type.rs b/crates/proto/src/version/v662/enums/game_type.rs new file mode 100644 index 00000000..39d052b3 --- /dev/null +++ b/crates/proto/src/version/v662/enums/game_type.rs @@ -0,0 +1,18 @@ +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +#[enum_repr(i32)] +#[enum_endianness(var)] +#[repr(i32)] +pub enum GameType { + Undefined = -1, + Survival = 0, + Creative = 1, + Adventure = 2, + Default = 5, + Spectator = 6, +} + +impl GameType { + pub const WORLD_DEFAULT: GameType = GameType::Survival; +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/enums/generator_type.rs b/crates/proto/src/version/v662/enums/generator_type.rs new file mode 100644 index 00000000..08aad998 --- /dev/null +++ b/crates/proto/src/version/v662/enums/generator_type.rs @@ -0,0 +1,15 @@ +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +#[enum_repr(i32)] +#[enum_endianness(var)] +#[repr(i32)] +pub enum GeneratorType { + Legacy = 0, + Overworld = 1, + Flat = 2, + Nether = 3, + TheEnd = 4, + Void = 5, + Undefined = 6, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/enums/hud_element.rs b/crates/proto/src/version/v662/enums/hud_element.rs new file mode 100644 index 00000000..1ccf37af --- /dev/null +++ b/crates/proto/src/version/v662/enums/hud_element.rs @@ -0,0 +1,19 @@ +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +#[enum_repr(i32)] +#[enum_endianness(var)] +pub enum HudElement { + PaperDoll = 0, + Armor = 1, + ToolTips = 2, + TouchControls = 3, + Crosshair = 4, + HotBar = 5, + Health = 6, + ProgressBar = 7, + Hunger = 8, + AirBubbles = 9, + HorseHealth = 10, + Count = 11, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/enums/hud_visibility.rs b/crates/proto/src/version/v662/enums/hud_visibility.rs new file mode 100644 index 00000000..8518ec1f --- /dev/null +++ b/crates/proto/src/version/v662/enums/hud_visibility.rs @@ -0,0 +1,10 @@ +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +#[enum_repr(i32)] +#[enum_endianness(var)] +pub enum HudVisibility { + Hide = 0, + Reset = 1, + Count = 2, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/enums/identity_definition_type.rs b/crates/proto/src/version/v662/enums/identity_definition_type.rs new file mode 100644 index 00000000..9556cfde --- /dev/null +++ b/crates/proto/src/version/v662/enums/identity_definition_type.rs @@ -0,0 +1,19 @@ +use crate::version::v662::types::ActorUniqueID; +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +#[enum_repr(i8)] +#[repr(i8)] +pub enum IdentityDefinitionType { + Invalid = 0, + Player { + #[endianness(var)] + player_unique_id: i64, + } = 1, + Entity { + actor_id: ActorUniqueID, + } = 2, + FakePlayer { + fake_player_name: String, + } = 3, +} diff --git a/crates/proto/src/version/v662/enums/input_mode.rs b/crates/proto/src/version/v662/enums/input_mode.rs new file mode 100644 index 00000000..1461969a --- /dev/null +++ b/crates/proto/src/version/v662/enums/input_mode.rs @@ -0,0 +1,14 @@ +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +#[enum_repr(u32)] +#[enum_endianness(var)] +#[repr(u32)] +pub enum InputMode { + Undefined = 0, + Mouse = 1, + Touch = 2, + GamePad = 3, + MotionController = 4, + Count = 5, +} diff --git a/crates/proto/src/version/v662/enums/inventory_layout.rs b/crates/proto/src/version/v662/enums/inventory_layout.rs new file mode 100644 index 00000000..c82cb7bd --- /dev/null +++ b/crates/proto/src/version/v662/enums/inventory_layout.rs @@ -0,0 +1,13 @@ +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +#[enum_repr(i32)] +#[enum_endianness(var)] +#[repr(i32)] +pub enum InventoryLayout { + None = 0, + Survival = 1, + RecipeBook = 2, + Creative = 3, + Count = 4, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/enums/inventory_left_tab_index.rs b/crates/proto/src/version/v662/enums/inventory_left_tab_index.rs new file mode 100644 index 00000000..46d61a68 --- /dev/null +++ b/crates/proto/src/version/v662/enums/inventory_left_tab_index.rs @@ -0,0 +1,16 @@ +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +#[enum_repr(i32)] +#[enum_endianness(var)] +#[repr(i32)] +pub enum InventoryLeftTabIndex { + None = 0, + RecipeConstruction = 1, + RecipeEquipment = 2, + RecipeItems = 3, + RecipeNature = 4, + RecipeSearch = 5, + Survival = 6, + Count = 7, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/enums/inventory_right_tab_index.rs b/crates/proto/src/version/v662/enums/inventory_right_tab_index.rs new file mode 100644 index 00000000..92ae6a43 --- /dev/null +++ b/crates/proto/src/version/v662/enums/inventory_right_tab_index.rs @@ -0,0 +1,13 @@ +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +#[enum_repr(i32)] +#[enum_endianness(var)] +#[repr(i32)] +pub enum InventoryRightTabIndex { + None = 0, + FullScreen = 1, + Crafting = 2, + Armor = 3, + Count = 4, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/enums/inventory_source_flags.rs b/crates/proto/src/version/v662/enums/inventory_source_flags.rs new file mode 100644 index 00000000..025f8e5b --- /dev/null +++ b/crates/proto/src/version/v662/enums/inventory_source_flags.rs @@ -0,0 +1,6 @@ +/// UNUSED +#[derive(Clone, Debug)] +pub enum InventorySourceFlags { + NoFlag = 0, + WorldInteractionRandom = 1, +} diff --git a/crates/proto/src/version/v662/enums/inventory_source_type.rs b/crates/proto/src/version/v662/enums/inventory_source_type.rs new file mode 100644 index 00000000..f959e9a5 --- /dev/null +++ b/crates/proto/src/version/v662/enums/inventory_source_type.rs @@ -0,0 +1,15 @@ +use crate::version::v662::enums::ContainerID; +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +#[enum_repr(u32)] +#[enum_endianness(var)] +#[repr(u32)] +pub enum InventorySourceType { + InvalidInventory = u32::MAX, + ContainerInventory(ContainerID) = 0, + GlobalInventory = 1, + WorldInteraction(#[endianness(var)] u32) = 2, + CreativeInventory = 3, + NonImplementedFeatureTODO = 99999, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/enums/item_descriptor_internal_type.rs b/crates/proto/src/version/v662/enums/item_descriptor_internal_type.rs new file mode 100644 index 00000000..1c9ad050 --- /dev/null +++ b/crates/proto/src/version/v662/enums/item_descriptor_internal_type.rs @@ -0,0 +1,13 @@ +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +#[enum_repr(i8)] +#[repr(i8)] +pub enum ItemDescriptorInternalType { + Invalid = 0, + Default = 1, + Molang = 2, + ItemTag = 3, + Deferred = 4, + ComplexAlias = 5, +} diff --git a/crates/proto/src/version/v662/enums/item_release_inventory_transaction_type.rs b/crates/proto/src/version/v662/enums/item_release_inventory_transaction_type.rs new file mode 100644 index 00000000..bd9c4c98 --- /dev/null +++ b/crates/proto/src/version/v662/enums/item_release_inventory_transaction_type.rs @@ -0,0 +1,6 @@ +/// UNUSED +#[derive(Clone, Debug)] +pub enum ItemReleaseInventoryTransactionType { + Release = 0, + Use = 1, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/enums/item_stack_net_result.rs b/crates/proto/src/version/v662/enums/item_stack_net_result.rs new file mode 100644 index 00000000..9e518ba7 --- /dev/null +++ b/crates/proto/src/version/v662/enums/item_stack_net_result.rs @@ -0,0 +1,80 @@ +use crate::version::v662::types::ItemStackResponseContainerInfo; +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +#[enum_repr(i8)] +#[repr(i8)] +pub enum ItemStackNetResult { + Success( + #[vec_repr(u32)] + #[vec_endianness(var)] + Vec, + ) = 0, + Error = 1, + InvalidRequestActionType = 2, + ActionRequestNotAllowed = 3, + ScreenHandlerEndRequestFailed = 4, + ItemRequestActionHandlerCommitFailed = 5, + InvalidRequestCraftActionType = 6, + InvalidCraftRequest = 7, + InvalidCraftRequestScreen = 8, + InvalidCraftResult = 9, + InvalidCraftResultIndex = 10, + InvalidCraftResultItem = 11, + InvalidItemNetId = 12, + MissingCreatedOutputContainer = 13, + FailedToSetCreatedItemOutputSlot = 14, + RequestAlreadyInProgress = 15, + FailedToInitSparseContainer = 16, + ResultTransferFailed = 17, + ExpectedItemSlotNotFullyConsumed = 18, + ExpectedAnywhereItemNotFullyConsumed = 19, + ItemAlreadyConsumedFromSlot = 20, + ConsumedTooMuchFromSlot = 21, + MismatchSlotExpectedConsumedItem = 22, + MismatchSlotExpectedConsumedItemNetIdVariant = 23, + FailedToMatchExpectedSlotConsumedItem = 24, + FailedToMatchExpectedAllowedAnywhereConsumedItem = 25, + ConsumedItemOutOfAllowedSlotRange = 26, + ConsumedItemNotAllowed = 27, + PlayerNotInCreativeMode = 28, + InvalidExperimentalRecipeRequest = 29, + FailedToCraftCreative = 30, + FailedToGetLevelRecipe = 31, + FailedToFindRecipeByNetId = 32, + MismatchedCraftingSize = 33, + MissingInputSparseContainer = 34, + MismatchedRecipeForInputGridItems = 35, + EmptyCraftResults = 36, + FailedToEnchant = 37, + MissingInputItem = 38, + InsufficientPlayerLevelToEnchant = 39, + MissingMaterialItem = 40, + MissingActor = 41, + UnknownPrimaryEffect = 42, + PrimaryEffectOutOfRange = 43, + PrimaryEffectUnavailable = 44, + SecondaryEffectOutOfRange = 45, + SecondaryEffectUnavailable = 46, + DstContainerEqualToCreatedOutputContainer = 47, + DstContainerAndSlotEqualToSrcContainerAndSlot = 48, + FailedToValidateSrcSlot = 49, + FailedToValidateDstSlot = 50, + InvalidAdjustedAmount = 51, + InvalidItemSetType = 52, + InvalidTransferAmount = 53, + CannotSwapItem = 54, + CannotPlaceItem = 55, + UnhandledItemSetType = 56, + InvalidRemovedAmount = 57, + InvalidRegion = 58, + CannotDropItem = 59, + CannotDestroyItem = 60, + InvalidSourceContainer = 61, + ItemNotConsumed = 62, + InvalidNumCrafts = 63, + InvalidCraftResultStackSize = 64, + CannotRemoveItem = 65, + CannotConsumeItem = 66, + ScreenStackError = 67, +} diff --git a/crates/proto/src/version/v662/enums/item_stack_request_action_type.rs b/crates/proto/src/version/v662/enums/item_stack_request_action_type.rs new file mode 100644 index 00000000..a96b3342 --- /dev/null +++ b/crates/proto/src/version/v662/enums/item_stack_request_action_type.rs @@ -0,0 +1,31 @@ +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +#[enum_repr(i8)] +#[repr(i8)] +pub enum ItemStackRequestActionType { + Take = 0, + Place = 1, + Swap = 2, + Drop = 3, + Destroy = 4, + Consume = 5, + Create = 6, + PlaceInItemContainer = 7, + TakeFromItemContainer = 8, + ScreenLabTableCombine = 9, + ScreenBeaconPayment = 10, + ScreenHUDMineBlock = 11, + CraftRecipe = 12, + CraftRecipeAuto = 13, + CraftCreative = 14, + CraftRecipeOptional = 15, + CraftRepairAndDisenchant = 16, + CraftLoom = 17, + #[deprecated = "Ask Tylaing"] CraftNonImplemented = 18, + #[deprecated = "Ask Tylaing"] CraftResults = 19, + Ifdef = 20, + TestIntrastructureEnabled = 21, + Test = 22, + Endif = 23, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/enums/item_use_inventory_transaction_type.rs b/crates/proto/src/version/v662/enums/item_use_inventory_transaction_type.rs new file mode 100644 index 00000000..b9babd7f --- /dev/null +++ b/crates/proto/src/version/v662/enums/item_use_inventory_transaction_type.rs @@ -0,0 +1,11 @@ +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +#[enum_repr(u32)] +#[enum_endianness(var)] +#[repr(u32)] +pub enum ItemUseInventoryTransactionType { + Place = 0, + Use = 1, + Destroy = 2, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/enums/item_use_method.rs b/crates/proto/src/version/v662/enums/item_use_method.rs new file mode 100644 index 00000000..74f863d2 --- /dev/null +++ b/crates/proto/src/version/v662/enums/item_use_method.rs @@ -0,0 +1,25 @@ +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +#[enum_repr(i32)] +#[enum_endianness(var)] +#[repr(i32)] +pub enum ItemUseMethod { + Unknown = -1, + EquipArmor = 0, + Eat = 1, + Attack = 2, + Consume = 3, + Throw = 4, + Shoot = 5, + Place = 6, + FillBottle = 7, + FillBucket = 8, + PourBucket = 9, + UseTool = 10, + Interact = 11, + Retrieved = 12, + Dyed = 13, + Traded = 14, + BrushingCompleted = 15, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/enums/item_use_on_actor_inventory_transaction_type.rs b/crates/proto/src/version/v662/enums/item_use_on_actor_inventory_transaction_type.rs new file mode 100644 index 00000000..1824703c --- /dev/null +++ b/crates/proto/src/version/v662/enums/item_use_on_actor_inventory_transaction_type.rs @@ -0,0 +1,7 @@ +/// UNUSED +#[derive(Clone, Debug)] +pub enum ItemUseOnActorInventoryTransactionType { + Interact = 0, + Attack = 1, + ItemInteract = 2, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/enums/lab_table_reaction_type.rs b/crates/proto/src/version/v662/enums/lab_table_reaction_type.rs new file mode 100644 index 00000000..d6f05c91 --- /dev/null +++ b/crates/proto/src/version/v662/enums/lab_table_reaction_type.rs @@ -0,0 +1,20 @@ +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +#[enum_repr(i8)] +#[repr(i8)] +pub enum LabTableReactionType { + None = 0, + IceBomb = 1, + Bleach = 2, + ElephantToothpaste = 3, + Fertilizer = 4, + HeatBlock = 5, + MagnesiumSalts = 6, + MiscFire = 7, + MiscExplosion = 8, + MiscLava = 9, + MiscMystical = 10, + MiscSmoke = 11, + MiscLargeSmoke = 12, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/enums/lesson_action.rs b/crates/proto/src/version/v662/enums/lesson_action.rs new file mode 100644 index 00000000..a83c4e4b --- /dev/null +++ b/crates/proto/src/version/v662/enums/lesson_action.rs @@ -0,0 +1,11 @@ +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +#[enum_repr(i32)] +#[enum_endianness(var)] +#[repr(i32)] +pub enum LessonAction { + Start = 0, + Complete = 1, + Restart = 2, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/enums/level_event.rs b/crates/proto/src/version/v662/enums/level_event.rs new file mode 100644 index 00000000..113123ad --- /dev/null +++ b/crates/proto/src/version/v662/enums/level_event.rs @@ -0,0 +1,136 @@ +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +#[enum_repr(i32)] +#[enum_endianness(var)] +#[repr(i32)] +pub enum LevelEvent { + _9800 = 3617, + Undefined = 0, + SoundClick = 1000, + SoundClickFail = 1001, + SoundLaunch = 1002, + SoundOpenDoor = 1003, + SoundFizz = 1004, + SoundFuse = 1005, + SoundPlayRecording = 1006, + SoundGhastWarning = 1007, + SoundGhastFireball = 1008, + SoundBlazeFireball = 1009, + SoundZombieWoodenDoor = 1010, + SoundZombieDoorCrash = 1012, + SoundZombieInfected = 1016, + SoundZombieConverted = 1017, + SoundEndermanTeleport = 1018, + SoundAnvilBroken = 1020, + SoundAnvilUsed = 1021, + SoundAnvilLand = 1022, + SoundInfinityArrowPickup = 1030, + SoundTeleportEnderPearl = 1032, + SoundAddItem = 1040, + SoundItemFrameBreak = 1041, + SoundItemFramePlace = 1042, + SoundItemFrameRemoveItem = 1043, + SoundItemFrameRotateItem = 1044, + SoundExperienceOrbPickup = 1051, + SoundTotemUsed = 1052, + SoundArmorStandBreak = 1060, + SoundArmorStandHit = 1061, + SoundArmorStandLand = 1062, + SoundArmorStandPlace = 1063, + SoundPointedDripstoneLand = 1064, + SoundDyeUsed = 1065, + SoundInkSacUsed = 1066, + SoundAmethystResonate = 1067, + QueueCustomMusic = 1900, + PlayCustomMusic = 1901, + StopCustomMusic = 1902, + SetMusicVolume = 1903, + ParticlesShoot = 2000, + ParticlesDestroyBlock = 2001, + ParticlesPotionSplash = 2002, + ParticlesEyeOfEnderDeath = 2003, + ParticlesMobBlockSpawn = 2004, + ParticleCropGrowth = 2005, + ParticleSoundGuardianGhost = 2006, + ParticleDeathSmoke = 2007, + ParticleDenyBlock = 2008, + ParticleGenericSpawn = 2009, + ParticlesDragonEgg = 2010, + ParticlesCropEaten = 2011, + ParticlesCrit = 2012, + ParticlesTeleport = 2013, + ParticlesCrackBlock = 2014, + ParticlesBubble = 2015, + ParticlesEvaporate = 2016, + ParticlesDestroyArmorStand = 2017, + ParticlesBreakingEgg = 2018, + ParticleDestroyEgg = 2019, + ParticlesEvaporateWater = 2020, + ParticlesDestroyBlockNoSound = 2021, + ParticlesKnockbackRoar = 2022, + ParticlesTeleportTrail = 2023, + ParticlesPointCloud = 2024, + ParticlesExplosion = 2025, + ParticlesBlockExplosion = 2026, + ParticlesVibrationSignal = 2027, + ParticlesDripstoneDrip = 2028, + ParticlesFizzEffect = 2029, + WaxOn = 2030, + WaxOff = 2031, + Scrape = 2032, + ParticlesElectricSpark = 2033, + ParticleTurtleEgg = 2034, + ParticlesSculkShriek = 2035, + SculkCatalystBloom = 2036, + SculkCharge = 2037, + SculkChargePop = 2038, + SonicExplosion = 2039, + DustPlume = 2040, + StartRaining = 3001, + StartThunderstorm = 3002, + StopRaining = 3003, + StopThunderstorm = 3004, + GlobalPause = 3005, + SimTimeStep = 3006, + SimTimeScale = 3007, + ActivateBlock = 3500, + CauldronExplode = 3501, + CauldronDyeArmor = 3502, + CauldronCleanArmor = 3503, + CauldronFillPotion = 3504, + CauldronTakePotion = 3505, + CauldronFillWater = 3506, + CauldronTakeWater = 3507, + CauldronAddDye = 3508, + CauldronCleanBanner = 3509, + CauldronFlush = 3510, + AgentSpawnEffect = 3511, + CauldronFillLava = 3512, + CauldronTakeLava = 3513, + CauldronFillPowderSnow = 3514, + CauldronTakePowderSnow = 3515, + StartBlockCracking = 3600, + StopBlockCracking = 3601, + UpdateBlockCracking = 3602, + ParticlesCrackBlockDown = 3603, + ParticlesCrackBlockUp = 3604, + ParticlesCrackBlockNorth = 3605, + ParticlesCrackBlockSouth = 3606, + ParticlesCrackBlockWest = 3607, + ParticlesCrackBlockEast = 3608, + ParticlesShootWhiteSmoke = 3609, + ParticlesBreezeWindExplosion = 3610, + ParticlesTrialSpawnerDetection = 3611, + ParticlesTrialSpawnerSpawning = 3612, + ParticlesTrialSpawnerEjecting = 3613, + ParticlesWindExplosion = 3614, + AllPlayersSleeping = 3615, + Deprecated = 3616, + SleepingPlayers = 9801, + JumpPrevented = 9810, + AnimationVaultActivate = 9811, + AnimationVaultDeactivate = 9812, + AnimationVaultEjectItem = 9813, + ParticleLegacyEvent = 0x4000, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/enums/level_sound_event_type.rs b/crates/proto/src/version/v662/enums/level_sound_event_type.rs new file mode 100644 index 00000000..83dc367c --- /dev/null +++ b/crates/proto/src/version/v662/enums/level_sound_event_type.rs @@ -0,0 +1,459 @@ +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +#[enum_repr(u32)] +#[enum_endianness(var)] +#[repr(u32)] +pub enum LevelSoundEventType { + ItemUseOn = 0, + Hit = 1, + Step = 2, + Fly = 3, + Jump = 4, + Break = 5, + Place = 6, + HeavyStep = 7, + Gallop = 8, + Fall = 9, + Ambient = 10, + AmbientBaby = 11, + AmbientInWater = 12, + Breathe = 13, + Death = 14, + DeathInWater = 15, + DeathToZombie = 16, + Hurt = 17, + HurtInWater = 18, + Mad = 19, + Boost = 20, + Bow = 21, + SquishBig = 22, + SquishSmall = 23, + FallBig = 24, + FallSmall = 25, + Splash = 26, + Fizz = 27, + Flap = 28, + Swim = 29, + Drink = 30, + Eat = 31, + Takeoff = 32, + Shake = 33, + Plop = 34, + Land = 35, + Saddle = 36, + Armor = 37, + ArmorPlace = 38, + AddChest = 39, + Throw = 40, + Attack = 41, + AttackNoDamage = 42, + AttackStrong = 43, + Warn = 44, + Shear = 45, + Milk = 46, + Thunder = 47, + Explode = 48, + Fire = 49, + Ignite = 50, + Fuse = 51, + Stare = 52, + Spawn = 53, + Shoot = 54, + BreakBlock = 55, + Launch = 56, + Blast = 57, + LargeBlast = 58, + Twinkle = 59, + Remedy = 60, + Unfect = 61, + LevelUp = 62, + BowHit = 63, + BulletHit = 64, + ExtinguishFire = 65, + ItemFizz = 66, + ChestOpen = 67, + ChestClosed = 68, + ShulkerBoxOpen = 69, + ShulkerBoxClosed = 70, + EnderChestOpen = 71, + EnderChestClosed = 72, + PowerOn = 73, + PowerOff = 74, + Attach = 75, + Detach = 76, + Deny = 77, + Tripod = 78, + Pop = 79, + DropSlot = 80, + Note = 81, + Thorns = 82, + PistonIn = 83, + PistonOut = 84, + Portal = 85, + Water = 86, + LavaPop = 87, + Lava = 88, + Burp = 89, + BucketFillWater = 90, + BucketFillLava = 91, + BucketEmptyWater = 92, + BucketEmptyLava = 93, + EquipChain = 94, + EquipDiamond = 95, + EquipGeneric = 96, + EquipGold = 97, + EquipIron = 98, + EquipLeather = 99, + EquipElytra = 100, + Record13 = 101, + RecordCat = 102, + RecordBlocks = 103, + RecordChirp = 104, + RecordFar = 105, + RecordMall = 106, + RecordMellohi = 107, + RecordStal = 108, + RecordStrad = 109, + RecordWard = 110, + Record11 = 111, + RecordWait = 112, + RecordNull = 113, + Flop = 114, + GuardianCurse = 115, + MobWarning = 116, + MobWarningBaby = 117, + Teleport = 118, + ShulkerOpen = 119, + ShulkerClose = 120, + Haggle = 121, + HaggleYes = 122, + HaggleNo = 123, + HaggleIdle = 124, + ChorusGrow = 125, + ChorusDeath = 126, + Glass = 127, + PotionBrewed = 128, + CastSpell = 129, + PrepareAttackSpell = 130, + PrepareSummon = 131, + PrepareWololo = 132, + Fang = 133, + Charge = 134, + TakePicture = 135, + PlaceLeashKnot = 136, + BreakLeashKnot = 137, + AmbientGrowl = 138, + AmbientWhine = 139, + AmbientPant = 140, + AmbientPurr = 141, + AmbientPurreow = 142, + DeathMinVolume = 143, + DeathMidVolume = 144, + ImitateBlaze = 145, + ImitateCaveSpider = 146, + ImitateCreeper = 147, + ImitateElderGuardian = 148, + ImitateEnderDragon = 149, + ImitateEnderman = 150, + ImitateEndermite = 151, + ImitateEvocationIllager = 152, + ImitateGhast = 153, + ImitateHusk = 154, + ImitateIllusionIllager = 155, + ImitateMagmaCube = 156, + ImitatePolarBear = 157, + ImitateShulker = 158, + ImitateSilverfish = 159, + ImitateSkeleton = 160, + ImitateSlime = 161, + ImitateSpider = 162, + ImitateStray = 163, + ImitateVex = 164, + ImitateVindicationIllager = 165, + ImitateWitch = 166, + ImitateWither = 167, + ImitateWitherSkeleton = 168, + ImitateWolf = 169, + ImitateZombie = 170, + ImitateZombiePigman = 171, + ImitateZombieVillager = 172, + EnderEyePlaced = 173, + EndPortalCreated = 174, + AnvilUse = 175, + BottleDragonBreath = 176, + PortalTravel = 177, + TridentHit = 178, + TridentReturn = 179, + TridentRiptide1 = 180, + TridentRiptide2 = 181, + TridentRiptide3 = 182, + TridentThrow = 183, + TridentThunder = 184, + TridentHitGround = 185, + Default = 186, + FletchingTableUse = 187, + ElemConstructOpen = 188, + IceBombHit = 189, + BalloonPop = 190, + LTReactionIceBomb = 191, + LTReactionBleach = 192, + LTReactionElephantToothpaste = 193, + LTReactionElephantToothpaste2 = 194, + LTReactionGlowStick = 195, + LTReactionGlowStick2 = 196, + LTReactionLuminol = 197, + LTReactionSalt = 198, + LTReactionFertilizer = 199, + LTReactionFireball = 200, + LTReactionMagnesiumSalt = 201, + LTReactionMiscFire = 202, + LTReactionFire = 203, + LTReactionMiscExplosion = 204, + LTReactionMiscMystical = 205, + LTReactionMiscMystical2 = 206, + LTReactionProduct = 207, + SparklerUse = 208, + GlowStickUse = 209, + SparklerActive = 210, + ConvertToDrowned = 211, + BucketFillFish = 212, + BucketEmptyFish = 213, + BubbleColumnUpwards = 214, + BubbleColumnDownwards = 215, + BubblePop = 216, + BubbleUpInside = 217, + BubbleDownInside = 218, + HurtBaby = 219, + DeathBaby = 220, + StepBaby = 221, + SpawnBaby = 222, + Born = 223, + TurtleEggBreak = 224, + TurtleEggCrack = 225, + TurtleEggHatched = 226, + LayEgg = 227, + TurtleEggAttacked = 228, + BeaconActivate = 229, + BeaconAmbient = 230, + BeaconDeactivate = 231, + BeaconPower = 232, + ConduitActivate = 233, + ConduitAmbient = 234, + ConduitAttack = 235, + ConduitDeactivate = 236, + ConduitShort = 237, + Swoop = 238, + BambooSaplingPlace = 239, + PreSneeze = 240, + Sneeze = 241, + AmbientTame = 242, + Scared = 243, + ScaffoldingClimb = 244, + CrossbowLoadingStart = 245, + CrossbowLoadingMiddle = 246, + CrossbowLoadingEnd = 247, + CrossbowShoot = 248, + CrossbowQuickChargeStart = 249, + CrossbowQuickChargeMiddle = 250, + CrossbowQuickChargeEnd = 251, + AmbientAggressive = 252, + AmbientWorried = 253, + CantBreed = 254, + ShieldBlock = 255, + LecternBookPlace = 256, + GrindstoneUse = 257, + Bell = 258, + CampfireCrackle = 259, + Roar = 260, + Stun = 261, + SweetBerryBushHurt = 262, + SweetBerryBushPick = 263, + CartographyTableUse = 264, + StonecutterUse = 265, + ComposterEmpty = 266, + ComposterFill = 267, + ComposterFillLayer = 268, + ComposterReady = 269, + BarrelOpen = 270, + BarrelClose = 271, + RaidHorn = 272, + LoomUse = 273, + AmbientInRaid = 274, + UICartographyTableUse = 275, + UIStonecutterUse = 276, + UILoomUse = 277, + SmokerUse = 278, + BlastFurnaceUse = 279, + SmithingTableUse = 280, + Screech = 281, + Sleep = 282, + FurnaceUse = 283, + MooshroomConvert = 284, + MilkSuspiciously = 285, + Celebrate = 286, + JumpPrevent = 287, + AmbientPollinate = 288, + BeehiveDrip = 289, + BeehiveEnter = 290, + BeehiveExit = 291, + BeehiveWork = 292, + BeehiveShear = 293, + HoneybottleDrink = 294, + AmbientCave = 295, + Retreat = 296, + ConvertToZombified = 297, + Admire = 298, + StepLava = 299, + Tempt = 300, + Panic = 301, + Angry = 302, + AmbientMoodWarpedForest = 303, + AmbientMoodSoulsandValley = 304, + AmbientMoodNetherWastes = 305, + AmbientMoodBasaltDeltas = 306, + AmbientMoodCrimsonForest = 307, + RespawnAnchorCharge = 308, + RespawnAnchorDeplete = 309, + RespawnAnchorSetSpawn = 310, + RespawnAnchorAmbient = 311, + SoulEscapeQuiet = 312, + SoulEscapeLoud = 313, + RecordPigstep = 314, + LinkCompassToLodestone = 315, + UseSmithingTable = 316, + EquipNetherite = 317, + AmbientLoopWarpedForest = 318, + AmbientLoopSoulsandValley = 319, + AmbientLoopNetherWastes = 320, + AmbientLoopBasaltDeltas = 321, + AmbientLoopCrimsonForest = 322, + AmbientAdditionWarpedForest = 323, + AmbientAdditionSoulsandValley = 324, + AmbientAdditionNetherWastes = 325, + AmbientAdditionBasaltDeltas = 326, + AmbientAdditionCrimsonForest = 327, + SculkSensorPowerOn = 328, + SculkSensorPowerOff = 329, + BucketFillPowderSnow = 330, + BucketEmptyPowderSnow = 331, + PointedDripstoneCauldronDripWater = 332, + PointedDripstoneCauldronDripLava = 333, + PointedDripstoneDripWater = 334, + PointedDripstoneDripLava = 335, + CaveVinesPickBerries = 336, + BigDripleafTiltDown = 337, + BigDripleafTiltUp = 338, + CopperWaxOn = 339, + CopperWaxOff = 340, + Scrape = 341, + PlayerHurtDrown = 342, + PlayerHurtOnFire = 343, + PlayerHurtFreeze = 344, + UseSpyglass = 345, + StopUsingSpyglass = 346, + AmethystBlockChime = 347, + AmbientScreamer = 348, + HurtScreamer = 349, + DeathScreamer = 350, + MilkScreamer = 351, + JumpToBlock = 352, + PreRam = 353, + PreRamScreamer = 354, + RamImpact = 355, + RamImpactScreamer = 356, + SquidInkSquirt = 357, + GlowSquidInkSquirt = 358, + ConvertToStray = 359, + CakeAddCandle = 360, + ExtinguishCandle = 361, + AmbientCandle = 362, + BlockClick = 363, + BlockClickFail = 364, + SculkCatalystBloom = 365, + SculkShriekerShriek = 366, + NearbyClose = 367, + NearbyCloser = 368, + NearbyClosest = 369, + Agitated = 370, + RecordOtherside = 371, + Tongue = 372, + CrackIronGolem = 373, + RepairIronGolem = 374, + Listening = 375, + Heartbeat = 376, + HornBreak = 377, + SculkSpread = 379, + SculkCharge = 380, + SculkSensorPlace = 381, + SculkShriekerPlace = 382, + GoatCall0 = 383, + GoatCall1 = 384, + GoatCall2 = 385, + GoatCall3 = 386, + GoatCall4 = 387, + GoatCall5 = 388, + GoatCall6 = 389, + GoatCall7 = 390, + ImitateWarden = 426, + ListeningAngry = 427, + ItemGiven = 428, + ItemTaken = 429, + Disappeared = 430, + Reappeared = 431, + DrinkMilk = 432, + FrogspawnHatched = 433, + LaySpawn = 434, + FrogspawnBreak = 435, + SonicBoom = 436, + SonicCharge = 437, + ItemThrown = 438, + Record5 = 439, + ConvertToFrog = 440, + RecordPlaying = 441, + EnchantingTableUse = 442, + StepSand = 443, + DashReady = 444, + BundleDropContents = 445, + BundleInsert = 446, + BundleRemoveOne = 447, + PressurePlateClickOff = 448, + PressurePlateClickOn = 449, + ButtonClickOff = 450, + ButtonClickOn = 451, + DoorOpen = 452, + DoorClose = 453, + TrapdoorOpen = 454, + TrapdoorClose = 455, + FenceGateOpen = 456, + FenceGateClose = 457, + Insert = 458, + Pickup = 459, + InsertEnchanted = 460, + PickupEnchanted = 461, + Brush = 462, + BrushCompleted = 463, + ShatterDecoratedPot = 464, + BreakDecoratedPot = 465, + SnifferEggCrack = 466, + SnifferEggHatched = 467, + WaxedSignInteractFail = 468, + RecordRelic = 469, + Bump = 470, + PumpkinCarve = 471, + ConvertHuskToZombie = 472, + PigDeath = 473, + HoglinConvertToZombified = 474, + AmbientUnderwaterEnter = 475, + AmbientUnderwaterExit = 476, + BottleFill = 477, + BottleEmpty = 478, + CrafterCraft = 479, + CrafterFail = 480, + DecoratedPotInsert = 481, + DecoratedPotInsertFail = 482, + CrafterDisableSlot = 483, + CopperBulbTurnOn = 490, + CopperBulbTurnOff = 491, + Undefined = 492, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/enums/minecraft_eventing.rs b/crates/proto/src/version/v662/enums/minecraft_eventing.rs new file mode 100644 index 00000000..ba787fff --- /dev/null +++ b/crates/proto/src/version/v662/enums/minecraft_eventing.rs @@ -0,0 +1,70 @@ +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +#[enum_repr(i32)] +#[enum_endianness(var)] +#[repr(i32)] +pub enum InteractionType { + Breeding = 1, + Taming = 2, + Curing = 3, + Crafted = 4, + Shearing = 5, + Milking = 6, + Trading = 7, + Feeding = 8, + Igniting = 9, + Coloring = 10, + Naming = 11, + Leashing = 12, + Unleashing = 13, + PetSleep = 14, + Trusting = 15, + Commanding = 16, +} + +#[derive(ProtoCodec, Clone, Debug)] +#[enum_repr(i32)] +#[enum_endianness(var)] +#[repr(i32)] +pub enum POIBlockInteractionType { + None = 0, + Extend = 1, + Clone = 2, + Lock = 3, + Create = 4, + CreateLocator = 5, + Rename = 6, + ItemPlaced = 7, + ItemRemoved = 8, + Cooking = 9, + Dousing = 10, + Lighting = 11, + Haystack = 12, + Filled = 13, + Emptied = 14, + AddDye = 15, + DyeItem = 16, + ClearItem = 17, + EnchantArrow = 18, + CompostItemPlaced = 19, + RecoveredBonemeal = 20, + BookPlaced = 21, + BookOpened = 22, + Disenchant = 23, + Repair = 24, + DisenchantAndRepair = 25, +} + +#[derive(ProtoCodec, Clone, Debug)] +#[enum_repr(i32)] +#[enum_endianness(le)] +#[repr(i32)] +pub enum TeleportationCause { + Unknown = 0, + Projectile = 1, + ChorusFruit = 2, + Command = 3, + Behavior = 4, + TeleportationCauseCount = 5, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/enums/minecraft_packet_ids.rs b/crates/proto/src/version/v662/enums/minecraft_packet_ids.rs new file mode 100644 index 00000000..f7fef675 --- /dev/null +++ b/crates/proto/src/version/v662/enums/minecraft_packet_ids.rs @@ -0,0 +1,217 @@ +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +#[enum_repr(i32)] +#[enum_endianness(var)] +#[repr(i32)] +pub enum MinecraftPacketIds { + KeepAlive = 0, + Login = 1, + PlayStatus = 2, + ServerToClientHandshake = 3, + ClientToServerHandshake = 4, + Disconnect = 5, + ResourcePacksInfo = 6, + ResourcePackStack = 7, + ResourcePackClientResponse = 8, + Text = 9, + SetTime = 10, + StartGame = 11, + AddPlayer = 12, + AddActor = 13, + RemoveActor = 14, + AddItemActor = 15, + ServerPlayerPostMovePosition = 16, + TakeItemActor = 17, + MoveAbsoluteActor = 18, + MovePlayer = 19, + PassengerJump = 20, + UpdateBlock = 21, + AddPainting = 22, + TickSync = 23, + LevelSoundEventV1 = 24, + LevelEvent = 25, + TileEvent = 26, + ActorEvent = 27, + MobEffect = 28, + UpdateAttributes = 29, + InventoryTransaction = 30, + PlayerEquipment = 31, + MobArmorEquipment = 32, + Interact = 33, + BlockPickRequest = 34, + ActorPickRequest = 35, + PlayerAction = 36, + #[deprecated] ActorFall = 37, + HurtArmor = 38, + SetActorData = 39, + SetActorMotion = 40, + SetActorLink = 41, + SetHealth = 42, + SetSpawnPosition = 43, + Animate = 44, + Respawn = 45, + ContainerOpen = 46, + ContainerClose = 47, + PlayerHotbar = 48, + InventoryContent = 49, + InventorySlot = 50, + ContainerSetData = 51, + CraftingData = 52, + #[deprecated] CraftingEvent = 53, + GuiDataPickItem = 54, + #[deprecated] AdventureSettings = 55, + BlockActorData = 56, + PlayerInput = 57, + FullChunkData = 58, + SetCommandsEnabled = 59, + SetDifficulty = 60, + ChangeDimension = 61, + SetPlayerGameType = 62, + PlayerList = 63, + SimpleEvent = 64, + LegacyTelemetryEvent = 65, + SpawnExperienceOrb = 66, + MapData = 67, + MapInfoRequest = 68, + RequestChunkRadius = 69, + ChunkRadiusUpdated = 70, + #[deprecated] ItemFrameDropItem = 71, + GameRulesChanged = 72, + Camera = 73, + BossEvent = 74, + ShowCredits = 75, + AvailableCommands = 76, + CommandRequest = 77, + CommandBlockUpdate = 78, + CommandOutput = 79, + UpdateTrade = 80, + UpdateEquip = 81, + ResourcePackDataInfo = 82, + ResourcePackChunkData = 83, + ResourcePackChunkRequest = 84, + Transfer = 85, + PlaySound = 86, + StopSound = 87, + SetTitle = 88, + AddBehaviorTree = 89, + StructureBlockUpdate = 90, + ShowStoreOffer = 91, + PurchaseReceipt = 92, + PlayerSkin = 93, + SubclientLogin = 94, + AutomationClientConnect = 95, + SetLastHurtBy = 96, + BookEdit = 97, + NPCRequest = 98, + PhotoTransfer = 99, + ShowModalForm = 100, + ModalFormResponse = 101, + ServerSettingsRequest = 102, + ServerSettingsResponse = 103, + ShowProfile = 104, + SetDefaultGameType = 105, + RemoveObjective = 106, + SetDisplayObjective = 107, + SetScore = 108, + LabTable = 109, + UpdateBlockSynced = 110, + MoveDeltaActor = 111, + SetScoreboardIdentity = 112, + SetLocalPlayerAsInit = 113, + UpdateSoftEnum = 114, + Ping = 115, + BlockPalette = 116, + ScriptCustomEvent = 117, + SpawnParticleEffect = 118, + AvailableActorIDList = 119, + LevelSoundEventV2 = 120, + NetworkChunkPublisherUpdate = 121, + BiomeDefinitionList = 122, + LevelSoundEvent = 123, + LevelEventGeneric = 124, + LecternUpdate = 125, + #[deprecated] VideoStreamConnect = 126, + #[deprecated] AddEntity = 127, + #[deprecated] RemoveEntity = 128, + ClientCacheStatus = 129, + OnScreenTextureAnimation = 130, + MapCreateLockedCopy = 131, + StructureTemplateDataExportRequest = 132, + StructureTemplateDataExportResponse = 133, + UnusedPlsUseMe = 134, + ClientCacheBlobStatusPacket = 135, + ClientCacheMissResponsePacket = 136, + EducationSettingsPacket = 137, + Emote = 138, + MultiplayerSettingsPacket = 139, + SettingsCommandPacket = 140, + AnvilDamage = 141, + CompletedUsingItem = 142, + NetworkSettings = 143, + PlayerAuthInputPacket = 144, + CreativeContent = 145, + PlayerEnchantOptions = 146, + ItemStackRequest = 147, + ItemStackResponse = 148, + PlayerArmorDamage = 149, + CodeBuilderPacket = 150, + UpdatePlayerGameType = 151, + EmoteList = 152, + PositionTrackingDBServerBroadcast = 153, + PositionTrackingDBClientRequest = 154, + DebugInfoPacket = 155, + PacketViolationWarning = 156, + MotionPredictionHints = 157, + TriggerAnimation = 158, + CameraShake = 159, + PlayerFogSetting = 160, + CorrectPlayerMovePredictionPacket = 161, + ItemComponentPacket = 162, + FilterTextPacket = 163, + ClientBoundDebugRendererPacket = 164, + SyncActorProperty = 165, + AddVolumeEntityPacket = 166, + RemoveVolumeEntityPacket = 167, + SimulationTypePacket = 168, + NpcDialoguePacket = 169, + EduUriResourcePacket = 170, + CreatePhotoPacket = 171, + UpdateSubChunkBlocks = 172, + #[deprecated] PhotoInfoRequest = 173, + SubChunkPacket = 174, + SubChunkRequestPacket = 175, + PlayerStartItemCooldown = 176, + ScriptMessagePacket = 177, + CodeBuilderSourcePacket = 178, + TickingAreasLoadStatus = 179, + DimensionDataPacket = 180, + AgentAction = 181, + ChangeMobProperty = 182, + LessonProgressPacket = 183, + RequestAbilityPacket = 184, + RequestPermissionsPacket = 185, + ToastRequest = 186, + UpdateAbilitiesPacket = 187, + UpdateAdventureSettingsPacket = 188, + DeathInfo = 189, + EditorNetworkPacket = 190, + FeatureRegistryPacket = 191, + ServerStats = 192, + RequestNetworkSettings = 193, + GameTestRequestPacket = 194, + GameTestResultsPacket = 195, + PlayerClientInputPermissions = 196, + #[deprecated] ClientCheatAbilityPacket = 197, + CameraPresets = 198, + UnlockedRecipes = 199, + CameraInstruction = 300, + CompressedBiomeDefinitionList = 301, + TrimData = 302, + OpenSign = 303, + AgentAnimation = 304, + RefreshEntitlementsPacket = 305, + PlayerToggleCrafterSlotRequestPacket = 306, + SetPlayerInventoryOptions = 307, + SetHudPacket = 308, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/enums/mirror.rs b/crates/proto/src/version/v662/enums/mirror.rs new file mode 100644 index 00000000..c9fc3d5f --- /dev/null +++ b/crates/proto/src/version/v662/enums/mirror.rs @@ -0,0 +1,11 @@ +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +#[enum_repr(i8)] +#[repr(i8)] +pub enum Mirror { + None = 0, + X = 1, + Z = 2, + XZ = 3, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/enums/mod.rs b/crates/proto/src/version/v662/enums/mod.rs new file mode 100644 index 00000000..b8c4833c --- /dev/null +++ b/crates/proto/src/version/v662/enums/mod.rs @@ -0,0 +1,107 @@ +macro_rules! export { + ($name:ident) => { + mod $name; + pub use $name::*; + }; +} + +export!(abilities_index); +export!(actor_block_sync_message_id); +export!(actor_damage_cause); +export!(actor_data_ids); +export!(actor_event); +export!(actor_flags); +export!(actor_link_type); +export!(actor_type); +export!(agent_action_type); +export!(animation_mode); +export!(attribute_modifier_operation); +export!(attribute_operands); +export!(book_edit_action); +export!(boss_event_update_type); +export!(build_platform); +export!(camera_shake_action); +export!(camera_shake_type); +export!(chat_restriction_level); +export!(client_play_mode); +export!(code_builder_storage); +export!(command_block_mode); +export!(command_origin_type); +export!(command_output_type); +export!(command_parameter_option); +export!(command_permission_level); +export!(complex_inventory_transaction_type); +export!(connection_fail_reason); +export!(container_enum_name); +export!(container_id); +export!(container_type); +export!(crafting_data_entry_type); +export!(crafting_type); +export!(data_item_type); +export!(difficulty); +export!(easing_type); +export!(editor_world_type); +export!(education_edition_offer); +export!(enchant_type); +export!(game_type); +export!(generator_type); +export!(hud_element); +export!(hud_visibility); +export!(identity_definition_type); +export!(input_mode); +export!(inventory_layout); +export!(inventory_left_tab_index); +export!(inventory_right_tab_index); +export!(inventory_source_flags); +export!(inventory_source_type); +export!(item_descriptor_internal_type); +export!(item_release_inventory_transaction_type); +export!(item_stack_net_result); +export!(item_stack_request_action_type); +export!(item_use_inventory_transaction_type); +export!(item_use_method); +export!(item_use_on_actor_inventory_transaction_type); +export!(lab_table_reaction_type); +export!(lesson_action); +export!(level_event); +export!(minecraft_eventing); +export!(minecraft_packet_ids); +export!(mirror); +export!(modal_form_cancel_reason); +export!(molang_version); +export!(multiplayer_settings_packet_type); +export!(new_interaction_model); +export!(objective_sort_order); +export!(pack_type); +export!(packet_compression_algorithm); +export!(packet_violation_severity); +export!(packet_violation_type); +export!(particle_type); +export!(photo_type); +export!(play_status); +export!(player_action_type); +export!(player_list_packet_type); +export!(player_permission_level); +export!(player_position_mode); +export!(player_respawn_state); +export!(level_sound_event_type); +export!(resource_pack_response); +export!(rotation); +export!(score_packet_type); +export!(scoreboard_identity_packet_type); +export!(server_auth_movement_mode); +export!(show_store_offer_redirect_type); +export!(simulation_type); +export!(game_publish_setting); +export!(soft_enum_update_type); +export!(spawn_biome_type); +export!(spawn_position_type); +export!(structure_block_type); +export!(structure_redstone_save_mode); +export!(structure_template_request_operation); +export!(structure_template_response_type); +export!(text_packet_type); +export!(text_processing_event_origin); +export!(ui_profile); +export!(persona); +export!(prediction_type); diff --git a/crates/proto/src/version/v662/enums/modal_form_cancel_reason.rs b/crates/proto/src/version/v662/enums/modal_form_cancel_reason.rs new file mode 100644 index 00000000..326a504d --- /dev/null +++ b/crates/proto/src/version/v662/enums/modal_form_cancel_reason.rs @@ -0,0 +1,9 @@ +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +#[enum_repr(i8)] +#[repr(i8)] +pub enum ModalFormCancelReason { + UserClosed = 0, + UserBusy = 1, +} diff --git a/crates/proto/src/version/v662/enums/molang_version.rs b/crates/proto/src/version/v662/enums/molang_version.rs new file mode 100644 index 00000000..5eaef93e --- /dev/null +++ b/crates/proto/src/version/v662/enums/molang_version.rs @@ -0,0 +1,28 @@ +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +#[enum_repr(i32)] +#[enum_endianness(le)] +#[repr(i32)] +pub enum MolangVersion { + Invalid = -1, + BeforeVersioning = 0, + Initial = 1, + FixedItemRemainingUseDurationQuery = 2, + ExpressionErrorMessages = 3, + UnexpectedOperatorErrors = 4, + ConditionalOperatorAssociativity = 5, + ComparisonAndLogicalOperatorPrecedence = 6, + DivideByNegativeValue = 7, + FixedCapeFlapAmountQuery = 8, + QueryBlockPropertyRenamedToState = 9, + DeprecateOldBlockQueryNames = 10, + DeprecatedSnifferAndCamelQueries = 11, + LeafSupportingInFirstSolidBlockBelow = 12, + NumValidVersions = 13, +} + +impl MolangVersion { + pub const LATEST: MolangVersion = MolangVersion::LeafSupportingInFirstSolidBlockBelow; // TODO: NumValidVersions - 1 (error) + pub const HARDCODED_MOLANG: MolangVersion = MolangVersion::LATEST; +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/enums/multiplayer_settings_packet_type.rs b/crates/proto/src/version/v662/enums/multiplayer_settings_packet_type.rs new file mode 100644 index 00000000..12dc26f9 --- /dev/null +++ b/crates/proto/src/version/v662/enums/multiplayer_settings_packet_type.rs @@ -0,0 +1,11 @@ +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +#[enum_repr(i32)] +#[enum_endianness(var)] +#[repr(i32)] +pub enum MultiplayerSettingsPacketType { + EnableMultiplayer = 0, + DisableMultiplayer = 1, + RefreshJoinCode = 2, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/enums/new_interaction_model.rs b/crates/proto/src/version/v662/enums/new_interaction_model.rs new file mode 100644 index 00000000..29a4f7e6 --- /dev/null +++ b/crates/proto/src/version/v662/enums/new_interaction_model.rs @@ -0,0 +1,12 @@ +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +#[enum_repr(u32)] +#[enum_endianness(var)] +#[repr(u32)] +pub enum NewInteractionModel { + Touch = 0, + Crosshair = 1, + Classic = 2, + Count = 3, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/enums/objective_sort_order.rs b/crates/proto/src/version/v662/enums/objective_sort_order.rs new file mode 100644 index 00000000..80085cc7 --- /dev/null +++ b/crates/proto/src/version/v662/enums/objective_sort_order.rs @@ -0,0 +1,10 @@ +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +#[enum_repr(i32)] +#[enum_endianness(var)] +#[repr(i32)] +pub enum ObjectiveSortOrder { + Ascending = 0, + Descending = 1, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/enums/pack_type.rs b/crates/proto/src/version/v662/enums/pack_type.rs new file mode 100644 index 00000000..e9bf6438 --- /dev/null +++ b/crates/proto/src/version/v662/enums/pack_type.rs @@ -0,0 +1,17 @@ +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +#[enum_repr(i8)] +#[repr(i8)] +pub enum PackType { + Invalid = 0, + Addon = 1, + Cached = 2, + CopyProtected = 3, + Behavior = 4, + PersonaPiece = 5, + Resources = 6, + Skins = 7, + WorldTemplate = 8, + Count = 9, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/enums/packet_compression_algorithm.rs b/crates/proto/src/version/v662/enums/packet_compression_algorithm.rs new file mode 100644 index 00000000..72e61abc --- /dev/null +++ b/crates/proto/src/version/v662/enums/packet_compression_algorithm.rs @@ -0,0 +1,11 @@ +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +#[enum_repr(u16)] +#[enum_endianness(le)] +#[repr(u16)] +pub enum PacketCompressionAlgorithm { + ZLib = 0, + Snappy = 1, + None = 0xffff, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/enums/packet_violation_severity.rs b/crates/proto/src/version/v662/enums/packet_violation_severity.rs new file mode 100644 index 00000000..71d4b4ea --- /dev/null +++ b/crates/proto/src/version/v662/enums/packet_violation_severity.rs @@ -0,0 +1,12 @@ +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +#[enum_repr(i32)] +#[enum_endianness(var)] +#[repr(i32)] +pub enum PacketViolationSeverity { + Unknown = -1, + Warning = 0, + FinalWarning = 1, + TerminatingConnection = 2, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/enums/packet_violation_type.rs b/crates/proto/src/version/v662/enums/packet_violation_type.rs new file mode 100644 index 00000000..bd13d99b --- /dev/null +++ b/crates/proto/src/version/v662/enums/packet_violation_type.rs @@ -0,0 +1,10 @@ +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +#[enum_repr(i32)] +#[enum_endianness(var)] +#[repr(i32)] +pub enum PacketViolationType { + Unknown = -1, + PacketMalformed = 0, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/enums/particle_type.rs b/crates/proto/src/version/v662/enums/particle_type.rs new file mode 100644 index 00000000..72cf8ac6 --- /dev/null +++ b/crates/proto/src/version/v662/enums/particle_type.rs @@ -0,0 +1,97 @@ +/// UNUSED +#[derive(Clone, Debug)] +pub enum ParticleType { + Undefined = 0, + Bubble = 1, + BubbleManual = 2, + Crit = 3, + BlockForceField = 4, + Smoke = 5, + Explode = 6, + Evaporation = 7, + Flame = 8, + CandleFlame = 9, + Lava = 10, + LargeSmoke = 11, + RedDust = 12, + RisingBorderDust = 13, + IconCrack = 14, + SnowballPoof = 15, + LargeExplode = 16, + HugeExplosion = 17, + BreezeWindExplosion = 18, + MobFlame = 19, + Heart = 20, + Terrain = 21, + TownAura = 22, + Portal = 23, + MobPortal = 24, + WaterSplash = 25, + WaterSplashManual = 26, + WaterWake = 27, + DripWater = 28, + DripLava = 29, + DripHoney = 30, + StalactiteDripWater = 31, + StalactiteDripLava = 32, + FallingDust = 33, + MobSpell = 34, + MobSpellAmbient = 35, + MobSpellInstantaneous = 36, + Ink = 37, + Slime = 38, + RainSplash = 39, + VillagerAngry = 40, + VillagerHappy = 41, + EnchantingTable = 42, + TrackingEmitter = 43, + Note = 44, + WitchSpell = 45, + CarrotBoost = 46, + MobAppearance = 47, + EndRod = 48, + DragonBreath = 49, + Spit = 50, + Totem = 51, + Food = 52, + FireworksStarter = 53, + Fireworks = 54, + FireworksOverlay = 55, + BalloonGas = 56, + ColoredFlame = 57, + Sparkler = 58, + Conduit = 59, + BubbleColumnUp = 60, + BubbleColumnDown = 61, + Sneeze = 62, + ShulkerBullet = 63, + Bleach = 64, + DragonDestroyBlock = 65, + MyceliumDust = 66, + FallingBorderDust = 67, + CampfireSmoke = 68, + CampfireSmokeTall = 69, + DragonBreathFire = 70, + DragonBreathTrail = 71, + BlueFlame = 72, + Soul = 73, + ObsidianTear = 74, + PortalReverse = 75, + Snowflake = 76, + VibrationSignal = 77, + SculkSensorRedstone = 78, + SporeBlossomShower = 79, + SporeBlossomAmbient = 80, + Wax = 81, + ElectricSpark = 82, + Shriek = 83, + SculkSoul = 84, + SonicExplosion = 85, + BrushDust = 86, + CherryLeaves = 87, + DustPlume = 88, + WhiteSmoke = 89, + VaultConnection = 90, + WindExplosion = 91, + Count = 92, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/enums/persona.rs b/crates/proto/src/version/v662/enums/persona.rs new file mode 100644 index 00000000..57bfcf46 --- /dev/null +++ b/crates/proto/src/version/v662/enums/persona.rs @@ -0,0 +1,21 @@ +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +#[enum_repr(u32)] +#[enum_endianness(le)] +#[repr(u32)] +pub enum AnimatedTextureType { + None = 0, + Face = 1, + Body32x32 = 2, + Body128x128 = 3, +} + +#[derive(ProtoCodec, Clone, Debug)] +#[enum_repr(u32)] +#[enum_endianness(le)] +#[repr(u32)] +pub enum AnimationExpression { + Linear = 0, + Blinking = 1, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/enums/photo_type.rs b/crates/proto/src/version/v662/enums/photo_type.rs new file mode 100644 index 00000000..a0cc0f76 --- /dev/null +++ b/crates/proto/src/version/v662/enums/photo_type.rs @@ -0,0 +1,10 @@ +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +#[enum_repr(i8)] +#[repr(i8)] +pub enum PhotoType { + Portfolio = 0, + PhotoItem = 1, + Book = 2, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/enums/play_status.rs b/crates/proto/src/version/v662/enums/play_status.rs new file mode 100644 index 00000000..dab1f822 --- /dev/null +++ b/crates/proto/src/version/v662/enums/play_status.rs @@ -0,0 +1,18 @@ +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +#[enum_repr(i32)] +#[enum_endianness(be)] +#[repr(i32)] +pub enum PlayStatus { + LoginSuccess = 0, + LoginFailedClientOld = 1, + LoginFailedServerOld = 2, + PlayerSpawn = 3, + LoginFailedInvalidTenant = 4, + LoginFailedEditionMismatchEduToVanilla = 5, + LoginFailedEditionMismatchVanillaToEdu = 6, + LoginFailedServerFullSubClient = 7, + LoginFailedEditorMismatchEditorToVanilla = 8, + LoginFailedEditorMismatchVanillaToEditor = 9, +} diff --git a/crates/proto/src/version/v662/enums/player_action_type.rs b/crates/proto/src/version/v662/enums/player_action_type.rs new file mode 100644 index 00000000..db3098df --- /dev/null +++ b/crates/proto/src/version/v662/enums/player_action_type.rs @@ -0,0 +1,72 @@ +use crate::version::v662::types::BlockPos; +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +#[enum_repr(i32)] +#[enum_endianness(var)] +#[repr(i32)] +pub enum PlayerActionType { + Unknown = -1, + StartDestroyBlock { + position: BlockPos, + #[endianness(var)] + facing: i32, + } = 0, + AbortDestroyBlock { + position: BlockPos, + #[endianness(var)] + facing: i32, + } = 1, + StopDestroyBlock { + position: BlockPos, + #[endianness(var)] + facing: i32, + } = 2, + GetUpdatedBlock = 3, + DropItem = 4, + StartSleeping = 5, + StopSleeping = 6, + Respawn = 7, + StartJump = 8, + StartSprinting = 9, + StopSprinting = 10, + StartSneaking = 11, + StopSneaking = 12, + CreativeDestroyBlock = 13, + ChangeDimensionAck = 14, + StartGliding = 15, + StopGliding = 16, + DenyDestroyBlock = 17, + CrackBlock { + position: BlockPos, + #[endianness(var)] + facing: i32, + } = 18, + ChangeSkin = 19, + DeprecatedUpdatedEnchantingSeed = 20, + StartSwimming = 21, + StopSwimming = 22, + StartSpinAttack = 23, + StopSpinAttack = 24, + InteractWithBlock = 25, + PredictDestroyBlock { + position: BlockPos, + #[endianness(var)] + facing: i32, + } = 26, + ContinueDestroyBlock { + position: BlockPos, + #[endianness(var)] + facing: i32, + } = 27, + StartItemUseOn = 28, + StopItemUseOn = 29, + HandledTeleport = 30, + MissedSwing = 31, + StartCrawling = 32, + StopCrawling = 33, + StartFlying = 34, + StopFlying = 35, + ClientAckServerData = 36, + Count = 37, +} diff --git a/crates/proto/src/version/v662/enums/player_list_packet_type.rs b/crates/proto/src/version/v662/enums/player_list_packet_type.rs new file mode 100644 index 00000000..3313d14b --- /dev/null +++ b/crates/proto/src/version/v662/enums/player_list_packet_type.rs @@ -0,0 +1,36 @@ +use crate::version::v662::enums::BuildPlatform; +use crate::version::v662::types::{ActorUniqueID, SerializedSkin}; +use bedrockrs_macros::ProtoCodec; +use uuid::Uuid; + +#[derive(ProtoCodec, Clone, Debug)] +pub struct AddPlayerListEntry { + pub uuid: Uuid, + pub target_actor_id: ActorUniqueID, + pub player_name: String, + pub xbl_xuid: String, + pub platform_chat_id: String, + pub build_platform: BuildPlatform, + pub serialized_skin: SerializedSkin, + pub is_teacher: bool, + pub is_host: bool, + pub is_sub_client: bool, + +} + +#[derive(ProtoCodec, Clone, Debug)] +#[enum_repr(i8)] +#[repr(i8)] +pub enum PlayerListPacketType { + Add { + #[vec_repr(u32)] + #[vec_endianness(var)] + add_player_list: Vec, + is_trusted_skin: bool, + } = 0, + Remove { + #[vec_repr(u32)] + #[vec_endianness(var)] + remove_player_list: Vec + } = 1, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/enums/player_permission_level.rs b/crates/proto/src/version/v662/enums/player_permission_level.rs new file mode 100644 index 00000000..617b9178 --- /dev/null +++ b/crates/proto/src/version/v662/enums/player_permission_level.rs @@ -0,0 +1,12 @@ +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +#[enum_repr(i32)] +#[enum_endianness(var)] +#[repr(i32)] +pub enum PlayerPermissionLevel { + Visitor = 0, + Member = 1, + Operator = 2, + Custom = 3, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/enums/player_position_mode.rs b/crates/proto/src/version/v662/enums/player_position_mode.rs new file mode 100644 index 00000000..b2532c00 --- /dev/null +++ b/crates/proto/src/version/v662/enums/player_position_mode.rs @@ -0,0 +1,16 @@ +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +#[enum_repr(i8)] +#[repr(i8)] +pub enum PlayerPositionMode { + Normal = 0, + Respawn = 1, + Teleport { + #[endianness(le)] + teleportation_cause: i32, + #[endianness(le)] + source_actor_type: i32, + } = 2, + OnlyHeadRot = 3, +} diff --git a/crates/proto/src/version/v662/enums/player_respawn_state.rs b/crates/proto/src/version/v662/enums/player_respawn_state.rs new file mode 100644 index 00000000..39f2bd15 --- /dev/null +++ b/crates/proto/src/version/v662/enums/player_respawn_state.rs @@ -0,0 +1,10 @@ +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +#[enum_repr(i8)] +#[repr(i8)] +pub enum PlayerRespawnState { + SearchingForSpawn = 0, + ReadyToSpawn = 1, + ClientReadyToSpawn = 2, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/enums/prediction_type.rs b/crates/proto/src/version/v662/enums/prediction_type.rs new file mode 100644 index 00000000..e671da17 --- /dev/null +++ b/crates/proto/src/version/v662/enums/prediction_type.rs @@ -0,0 +1,9 @@ +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +#[enum_repr(i8)] +#[repr(i8)] +pub enum PredictionType { + Player = 0, + Vehicle = 1, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/enums/resource_pack_response.rs b/crates/proto/src/version/v662/enums/resource_pack_response.rs new file mode 100644 index 00000000..59bab0a9 --- /dev/null +++ b/crates/proto/src/version/v662/enums/resource_pack_response.rs @@ -0,0 +1,11 @@ +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +#[enum_repr(i8)] +#[repr(i8)] +pub enum ResourcePackResponse { + Cancel = 1, + Downloading = 2, + DownloadingFinished = 3, + ResourcePackStackFinished = 4, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/enums/rotation.rs b/crates/proto/src/version/v662/enums/rotation.rs new file mode 100644 index 00000000..195fcbfa --- /dev/null +++ b/crates/proto/src/version/v662/enums/rotation.rs @@ -0,0 +1,12 @@ +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +#[enum_repr(i8)] +#[repr(i8)] +pub enum Rotation { + None = 0, + Rotate90 = 1, + Rotate180 = 2, + Rotate270 = 3, + Total = 4, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/enums/score_packet_type.rs b/crates/proto/src/version/v662/enums/score_packet_type.rs new file mode 100644 index 00000000..2c4ff71b --- /dev/null +++ b/crates/proto/src/version/v662/enums/score_packet_type.rs @@ -0,0 +1,36 @@ +use crate::version::v662::enums::IdentityDefinitionType; +use crate::version::v662::types::ScoreboardId; +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +pub struct ScorePacketInfoChangeEntry { + pub id: ScoreboardId, + pub objective_name: String, + #[endianness(le)] + pub score_value: i32, +} + +#[derive(ProtoCodec, Clone, Debug)] +pub struct ScorePacketInfoRemoveEntry { + pub id: ScoreboardId, + pub objective_name: String, + #[endianness(le)] + pub score_value: i32, + pub identity_definition_type: IdentityDefinitionType, +} + +#[derive(ProtoCodec, Clone, Debug)] +#[enum_repr(i8)] +#[repr(i8)] +pub enum ScorePacketType { + Change { + #[vec_repr(u32)] + #[vec_endianness(var)] + score_packet_info: Vec, + } = 0, + Remove { + #[vec_repr(u32)] + #[vec_endianness(var)] + score_packet_info: Vec, + } = 1, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/enums/scoreboard_identity_packet_type.rs b/crates/proto/src/version/v662/enums/scoreboard_identity_packet_type.rs new file mode 100644 index 00000000..15d05bff --- /dev/null +++ b/crates/proto/src/version/v662/enums/scoreboard_identity_packet_type.rs @@ -0,0 +1,25 @@ +use crate::version::v662::types::ScoreboardId; +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +pub struct IdentityInfoUpdateEntry { + pub scoreboard_id: ScoreboardId, + #[endianness(var)] + pub player_unique_id: i64, +} + +#[derive(ProtoCodec, Clone, Debug)] +#[enum_repr(i8)] +#[repr(i8)] +pub enum ScoreboardIdentityPacketType { + Update { + #[vec_repr(u32)] + #[vec_endianness(var)] + identity_info: Vec, + } = 0, + Remove { + #[vec_repr(u32)] + #[vec_endianness(var)] + identity_info: Vec, + } = 1, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/enums/server_auth_movement_mode.rs b/crates/proto/src/version/v662/enums/server_auth_movement_mode.rs new file mode 100644 index 00000000..c2974632 --- /dev/null +++ b/crates/proto/src/version/v662/enums/server_auth_movement_mode.rs @@ -0,0 +1,11 @@ +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +#[enum_repr(i32)] +#[enum_endianness(var)] +#[repr(i32)] +pub enum ServerAuthMovementMode { + ClientAuthoritative = 0, + ServerAuthoritative = 1, + ServerAuthoritativeWithRewind = 2, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/enums/show_store_offer_redirect_type.rs b/crates/proto/src/version/v662/enums/show_store_offer_redirect_type.rs new file mode 100644 index 00000000..b803cf18 --- /dev/null +++ b/crates/proto/src/version/v662/enums/show_store_offer_redirect_type.rs @@ -0,0 +1,11 @@ +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +#[enum_repr(i8)] +#[repr(i8)] +pub enum ShowStoreOfferRedirectType { + MarketplaceOffer = 0, + DressingRoomOffer = 1, + ThirdPartyServerPage = 2, + Count = 3, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/enums/simulation_type.rs b/crates/proto/src/version/v662/enums/simulation_type.rs new file mode 100644 index 00000000..5d8a10a4 --- /dev/null +++ b/crates/proto/src/version/v662/enums/simulation_type.rs @@ -0,0 +1,11 @@ +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +#[enum_repr(i8)] +#[repr(i8)] +pub enum SimulationType { + Game = 0, + Editor = 1, + Test = 2, + Invalid = 3, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/enums/soft_enum_update_type.rs b/crates/proto/src/version/v662/enums/soft_enum_update_type.rs new file mode 100644 index 00000000..3427f581 --- /dev/null +++ b/crates/proto/src/version/v662/enums/soft_enum_update_type.rs @@ -0,0 +1,11 @@ +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +#[enum_repr(u32)] +#[enum_endianness(le)] +#[repr(u32)] +pub enum SoftEnumUpdateType { + Add = 0, + Remove = 1, + Replace = 2, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/enums/spawn_biome_type.rs b/crates/proto/src/version/v662/enums/spawn_biome_type.rs new file mode 100644 index 00000000..8933787b --- /dev/null +++ b/crates/proto/src/version/v662/enums/spawn_biome_type.rs @@ -0,0 +1,10 @@ +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +#[enum_repr(i16)] +#[enum_endianness(le)] +#[repr(i16)] +pub enum SpawnBiomeType { + Default = 0, + UserDefined = 1, +} diff --git a/crates/proto/src/version/v662/enums/spawn_position_type.rs b/crates/proto/src/version/v662/enums/spawn_position_type.rs new file mode 100644 index 00000000..d04fd607 --- /dev/null +++ b/crates/proto/src/version/v662/enums/spawn_position_type.rs @@ -0,0 +1,10 @@ +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +#[enum_repr(i32)] +#[enum_endianness(var)] +#[repr(i32)] +pub enum SpawnPositionType { + PlayerRespawn = 0, + WorldSpawn = 1, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/enums/structure_block_type.rs b/crates/proto/src/version/v662/enums/structure_block_type.rs new file mode 100644 index 00000000..b5651e75 --- /dev/null +++ b/crates/proto/src/version/v662/enums/structure_block_type.rs @@ -0,0 +1,15 @@ +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +#[enum_repr(i32)] +#[enum_endianness(var)] +#[repr(i32)] +pub enum StructureBlockType { + Data = 0, + Save = 1, + Load = 2, + Corner = 3, + Invalid = 4, + Export = 5, + Count = 6, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/enums/structure_redstone_save_mode.rs b/crates/proto/src/version/v662/enums/structure_redstone_save_mode.rs new file mode 100644 index 00000000..21f6ddf5 --- /dev/null +++ b/crates/proto/src/version/v662/enums/structure_redstone_save_mode.rs @@ -0,0 +1,10 @@ +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +#[enum_repr(i32)] +#[enum_endianness(var)] +#[repr(i32)] +pub enum StructureRedstoneSaveMode { + SavesToMemory = 0, + SavesToDisk = 1, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/enums/structure_template_request_operation.rs b/crates/proto/src/version/v662/enums/structure_template_request_operation.rs new file mode 100644 index 00000000..1fa80b38 --- /dev/null +++ b/crates/proto/src/version/v662/enums/structure_template_request_operation.rs @@ -0,0 +1,12 @@ +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +#[enum_repr(i8)] +#[repr(i8)] +pub enum StructureTemplateRequestOperation { + None = 0, + ExportFromSaveMode = 1, + ExportFromLoadMode = 2, + QuerySavedStructure = 3, + Import = 4, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/enums/structure_template_response_type.rs b/crates/proto/src/version/v662/enums/structure_template_response_type.rs new file mode 100644 index 00000000..b3310a95 --- /dev/null +++ b/crates/proto/src/version/v662/enums/structure_template_response_type.rs @@ -0,0 +1,11 @@ +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +#[enum_repr(i8)] +#[repr(i8)] +pub enum StructureTemplateResponseType { + None = 0, + Export = 1, + Query = 2, + Import = 3, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/enums/text_packet_type.rs b/crates/proto/src/version/v662/enums/text_packet_type.rs new file mode 100644 index 00000000..64984643 --- /dev/null +++ b/crates/proto/src/version/v662/enums/text_packet_type.rs @@ -0,0 +1,43 @@ +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +#[enum_repr(i8)] +#[repr(i8)] +pub enum TextPacketType { + Raw(String) = 0, + Chat { + player_name: String, + message: String, + } = 1, + Translate { + message: String, + #[vec_repr(u32)] + #[vec_endianness(var)] + parameter_list: Vec, + } = 2, + Popup { + message: String, + #[vec_repr(u32)] + #[vec_endianness(var)] + parameter_list: Vec, + } = 3, + JukeboxPopup { + message: String, + #[vec_repr(u32)] + #[vec_endianness(var)] + parameter_list: Vec, + } = 4, + Tip(String) = 5, + SystemMessage(String) = 6, + Whisper { + player_name: String, + message: String, + } = 7, + Announcement { + player_name: String, + message: String, + } = 8, + TextObjectWhisper(String) = 9, + TextObject(String) = 10, + TextObjectAnnouncement(String) = 11, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/enums/text_processing_event_origin.rs b/crates/proto/src/version/v662/enums/text_processing_event_origin.rs new file mode 100644 index 00000000..aff3d0e2 --- /dev/null +++ b/crates/proto/src/version/v662/enums/text_processing_event_origin.rs @@ -0,0 +1,25 @@ +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +#[enum_repr(i32)] +#[enum_endianness(le)] +#[repr(i32)] +pub enum TextProcessingEventOrigin { + Unknown = -1, + ServerChatPublic = 0, + ServerChatWhisper = 1, + SignText = 2, + AnvilText = 3, + BookAndQuillText = 4, + CommandBlockText = 5, + BlockActorDataText = 6, + JoinEventText = 7, + LeaveEventText = 8, + SlashCommandChat = 9, + CartographyText = 10, + KickCommand = 11, + TitleCommand = 12, + SummonCommand = 13, + ServerForm = 14, + Count = 15, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/enums/ui_profile.rs b/crates/proto/src/version/v662/enums/ui_profile.rs new file mode 100644 index 00000000..5010a271 --- /dev/null +++ b/crates/proto/src/version/v662/enums/ui_profile.rs @@ -0,0 +1,7 @@ +/// UNUSED +pub enum UIProfile { + Classic = 0, + Pocket = 1, + None = 2, + Count = 3, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/gamepackets.rs b/crates/proto/src/version/v662/gamepackets.rs new file mode 100644 index 00000000..8959843f --- /dev/null +++ b/crates/proto/src/version/v662/gamepackets.rs @@ -0,0 +1,338 @@ +use crate::version::v662::packets::{ + ActorEventPacket, ActorPickRequestPacket, AddActorPacket, AddBehaviourTreePacket, + AddItemActorPacket, AddPaintingPacket, AddPlayerPacket, AddVolumeEntityPacket, + AgentActionEventPacket, AgentAnimationPacket, AnimateEntityPacket, AnimatePacket, + AnvilDamagePacket, AutomationClientConnectPacket, AvailableActorIdentifiersPacket, + AvailableCommandsPacket, BiomeDefinitionListPacket, BlockActorDataPacket, BlockEventPacket, + BlockPickRequestPacket, BookEditPacket, BossEventPacket, CameraInstructionPacket, CameraPacket, + CameraPresetsPacket, CameraShakePacket, ChangeDimensionPacket, ChangeMobPropertyPacket, + ChunkRadiusUpdatedPacket, ClientBoundDebugRendererPacket, ClientBoundMapItemDataPacket, + ClientCacheBlobStatusPacket, ClientCacheMissResponsePacket, ClientCacheStatusPacket, + ClientToServerHandshakePacket, CodeBuilderPacket, CodeBuilderSourcePacket, + CommandBlockUpdatePacket, CommandOutputPacket, CommandRequestPacket, CompletedUsingItemPacket, + CompressedBiomeDefinitionListPacket, ContainerClosePacket, ContainerOpenPacket, + ContainerSetDataPacket, CorrectPlayerMovePredictionPacket, CraftingDataPacket, + CreatePhotoPacket, CreativeContentPacket, DeathInfoPacket, DebugInfoPacket, + DimensionDataPacket, DisconnectPacket, EditorNetworkPacket, EduUriResourcePacket, + EducationSettingsPacket, EmoteListPacket, EmotePacket, FeatureRegistryPacket, FilterTextPacket, + GameRulesChangedPacket, GameTestRequestPacket, GameTestResultsPacket, GuiDataPickItemPacket, + HurtArmorPacket, InteractPacket, InventoryContentPacket, InventorySlotPacket, + InventoryTransactionPacket, ItemComponentPacket, ItemStackRequestPacket, + ItemStackResponsePacket, LabTablePacket, LecternUpdatePacket, LegacyTelemetryEventPacket, + LessonProgressPacket, LevelChunkPacket, LevelEventGenericPacket, LevelEventPacket, + LevelSoundEventPacket, LevelSoundEventPacketV1, LevelSoundEventPacketV2, LoginPacket, + MapCreateLockedCopyPacket, MapInfoRequestPacket, MobArmorEquipmentPacket, MobEffectPacket, + MobEquipmentPacket, ModalFormRequestPacket, ModalFormResponsePacket, + MotionPredictionHintsPacket, MoveActorAbsolutePacket, MoveActorDeltaPacket, MovePlayerPacket, + MultiplayerSettingsPacket, NetworkChunkPublisherUpdatePacket, NetworkSettingsPacket, + NetworkStackLatencyPacket, NpcDialoguePacket, NpcRequestPacket, OnScreenTextureAnimationPacket, + OpenSignPacket, PacketViolationWarningPacket, PassengerJumpPacket, PhotoTransferPacket, + PlaySoundPacket, PlayStatusPacket, PlayerActionPacket, PlayerArmorDamagePacket, + PlayerAuthInputPacket, PlayerEnchantOptionsPacket, PlayerFogPacket, PlayerHotbarPacket, + PlayerInputPacket, PlayerListPacket, PlayerSkinPacket, PlayerStartItemCooldownPacket, + PlayerToggleCrafterSlotRequestPacket, PositionTrackingDBClientRequestPacket, + PositionTrackingDBServerBroadcastPacket, PurchaseReceiptPacket, RefreshEntitlementsPacket, + RemoveActorPacket, RemoveObjectivePacket, RemoveVolumeEntityPacket, RequestAbilityPacket, + RequestChunkRadiusPacket, RequestNetworkSettingsPacket, RequestPermissionsPacket, + ResourcePackChunkDataPacket, ResourcePackChunkRequestPacket, ResourcePackClientResponsePacket, + ResourcePackDataInfoPacket, ResourcePackStackPacket, ResourcePacksInfoPacket, RespawnPacket, + ScriptMessagePacket, ServerPlayerPostMovePositionPacket, ServerSettingsRequestPacket, + ServerSettingsResponsePacket, ServerStatsPacket, ServerToClientHandshakePacket, + SetActorDataPacket, SetActorLinkPacket, SetActorMotionPacket, SetCommandsEnabledPacket, + SetDefaultGameTypePacket, SetDifficultyPacket, SetDisplayObjectivePacket, SetHealthPacket, + SetHudPacket, SetLastHurtByPacket, SetLocalPlayerAsInitializedPacket, SetPlayerGameTypePacket, + SetPlayerInventoryOptionsPacket, SetScorePacket, SetScoreboardIdentityPacket, + SetSpawnPositionPacket, SetTimePacket, SetTitlePacket, SettingsCommandPacket, + ShowCreditsPacket, ShowProfilePacket, ShowStoreOfferPacket, SimpleEventPacket, + SimulationTypePacket, SpawnExperienceOrbPacket, SpawnParticleEffectPacket, StartGamePacket, + StopSoundPacket, StructureBlockUpdatePacket, StructureDataRequestPacket, + StructureDataResponsePacket, SubChunkPacket, SubChunkRequestPacket, SubClientLoginPacket, + SyncActorPropertyPacket, TakeItemActorPacket, TextPacket, TickSyncPacket, + TickingAreaLoadStatusPacket, ToastRequestPacket, TransferPlayerPacket, TrimDataPacket, + UnlockedRecipesPacket, UpdateAbilitiesPacket, UpdateAdventureSettingsPacket, + UpdateAttributesPacket, UpdateBlockPacket, UpdateBlockSyncedPacket, + UpdateClientInputLocksPacket, UpdateEquipPacket, UpdatePlayerGameTypePacket, + UpdateSoftEnumPacket, UpdateSubChunkBlocksPacket, UpdateTradePacket, +}; +use bedrockrs_macros::gamepackets; +use bedrockrs_proto_core::error::ProtoCodecError; +use bedrockrs_proto_core::sub_client::SubClientID; +use std::io::{Cursor, Write}; +use varint_rs::{VarintReader, VarintWriter}; + +gamepackets! { + Login: LoginPacket, + PlaySatus: PlayStatusPacket, + ServerToClientHandshake: ServerToClientHandshakePacket, + ClientToServerHandshake: ClientToServerHandshakePacket, + Disconnect: DisconnectPacket, + ResourcePacksInfo: ResourcePacksInfoPacket, + ResourcePackStack: ResourcePackStackPacket, + ResourcePackClientResponse: ResourcePackClientResponsePacket, + Text: TextPacket, + SetTime: SetTimePacket, + StartGame: StartGamePacket, + AddPlayer: AddPlayerPacket, + AddActor: AddActorPacket, + RemoveActor: RemoveActorPacket, + AddItemActor: AddItemActorPacket, + ServerPlayerPostMovePosition: ServerPlayerPostMovePositionPacket, + TakeItemActor: TakeItemActorPacket, + MoveActorAbsolute: MoveActorAbsolutePacket, + MovePlayer: MovePlayerPacket, + PassengerJump: PassengerJumpPacket, + UpdateBlock: UpdateBlockPacket, + AddPainting: AddPaintingPacket, + TickSync: TickSyncPacket, + LevelSoundEventV1: LevelSoundEventPacketV1, + LevelEvent: LevelEventPacket, + BlockEvent: BlockEventPacket, + ActorEvent: ActorEventPacket, + MobEffect: MobEffectPacket, + UpdateAttributes: UpdateAttributesPacket, + InventoryTransaction: InventoryTransactionPacket, + MobEquipment: MobEquipmentPacket, + MobArmorEquipment: MobArmorEquipmentPacket, + Interact: InteractPacket, + BlockPickRequest: BlockPickRequestPacket, + ActorPickRequest: ActorPickRequestPacket, + PlayerAction: PlayerActionPacket, + HurtArmor: HurtArmorPacket, + SetActorData: SetActorDataPacket, + SetActorMotion: SetActorMotionPacket, + SetActorLink: SetActorLinkPacket, + SetHealth: SetHealthPacket, + SetSpawnPosition: SetSpawnPositionPacket, + Animate: AnimatePacket, + Respawn: RespawnPacket, + ContainerOpen: ContainerOpenPacket, + ContainerClose: ContainerClosePacket, + PlayerHotbar: PlayerHotbarPacket, + InventoryContent: InventoryContentPacket, + InventorySlot: InventorySlotPacket, + ContainerSetData: ContainerSetDataPacket, + CraftingData: CraftingDataPacket, + GuiDataPickItem: GuiDataPickItemPacket, + BlockActorData: BlockActorDataPacket, + PlayerInput: PlayerInputPacket, + LevelChunk: LevelChunkPacket, + SetCommandsEnabled: SetCommandsEnabledPacket, + SetDifficulty: SetDifficultyPacket, + ChangeDimension: ChangeDimensionPacket, + SetPlayerGameType: SetPlayerGameTypePacket, + PlayerList: PlayerListPacket, + SimpleEvent: SimpleEventPacket, + LegacyTelemetryEvent: LegacyTelemetryEventPacket, + SpawnExperienceOrb: SpawnExperienceOrbPacket, + ClientboundMapItemData: ClientBoundMapItemDataPacket, + MapInfoRequest: MapInfoRequestPacket, + RequestChunkRadius: RequestChunkRadiusPacket, + ChunkRadiusUpdated: ChunkRadiusUpdatedPacket, + GameRulesChanged: GameRulesChangedPacket, + Camera: CameraPacket, + BossEvent: BossEventPacket, + ShowCredits: ShowCreditsPacket, + AvailableCommands: AvailableCommandsPacket, + CommandRequest: CommandRequestPacket, + CommandBlockUpdate: CommandBlockUpdatePacket, + CommandOutput: CommandOutputPacket, + UpdateTrade: UpdateTradePacket, + UpdateEquip: UpdateEquipPacket, + ResourcePackDataInfo: ResourcePackDataInfoPacket, + ResourcePackChunkData: ResourcePackChunkDataPacket, + ResourcePackChunkRequest: ResourcePackChunkRequestPacket, + TransferPlayer: TransferPlayerPacket, + PlaySound: PlaySoundPacket, + StopSound: StopSoundPacket, + SetTitle: SetTitlePacket, + AddBehaviourTree: AddBehaviourTreePacket, + StructureBlockUpdate: StructureBlockUpdatePacket, + ShowStoreOffer: ShowStoreOfferPacket, + PurchaseReceipt: PurchaseReceiptPacket, + PlayerSkin: PlayerSkinPacket, + SubClientLogin: SubClientLoginPacket, + AutomationClientConnect: AutomationClientConnectPacket, + SetLastHurtBy: SetLastHurtByPacket, + BookEdit: BookEditPacket, + NpcRequest: NpcRequestPacket, + PhotoTransfer: PhotoTransferPacket, + ModalFormRequest: ModalFormRequestPacket, + ModalFormResponse: ModalFormResponsePacket, + ServerSettingsRequest: ServerSettingsRequestPacket, + ServerSettingsResponse: ServerSettingsResponsePacket, + ShowProfile: ShowProfilePacket, + SetDefaultGameType: SetDefaultGameTypePacket, + RemoveObjective: RemoveObjectivePacket, + SetDisplayObjective: SetDisplayObjectivePacket, + SetScore: SetScorePacket, + LabTable: LabTablePacket, + UpdateBlockSynced: UpdateBlockSyncedPacket, + MoveActorDelta: MoveActorDeltaPacket, + SetScoreboardIdentity: SetScoreboardIdentityPacket, + SetLocalPlayerAsInitialized: SetLocalPlayerAsInitializedPacket, + UpdateSoftEnum: UpdateSoftEnumPacket, + NetworkStackLatency: NetworkStackLatencyPacket, + SpawnParticleEffect: SpawnParticleEffectPacket, + AvailableActorIdentifiers: AvailableActorIdentifiersPacket, + LevelSoundEventV2: LevelSoundEventPacketV2, + NetworkChunkPublisherUpdate: NetworkChunkPublisherUpdatePacket, + BiomeDefinitionList: BiomeDefinitionListPacket, + LevelSoundEvent: LevelSoundEventPacket, + LevelEventGeneric: LevelEventGenericPacket, + LecternUpdate: LecternUpdatePacket, + ClientCacheStatus: ClientCacheStatusPacket, + OnScreenTextureAnimation: OnScreenTextureAnimationPacket, + MapCreateLockedCopy: MapCreateLockedCopyPacket, + StructureDataRequest: StructureDataRequestPacket, + StructureDataResponse: StructureDataResponsePacket, + ClientCacheBlobStatus: ClientCacheBlobStatusPacket, + ClientCacheMissResponse: ClientCacheMissResponsePacket, + EducationSettings: EducationSettingsPacket, + Emote: EmotePacket, + MultiplayerSettings: MultiplayerSettingsPacket, + SettingsCommand: SettingsCommandPacket, + AnvilDamage: AnvilDamagePacket, + CompletedUsingItem: CompletedUsingItemPacket, + NetworkSettings: NetworkSettingsPacket, + PlayerAuthInput: PlayerAuthInputPacket, + CreativeContent: CreativeContentPacket, + PlayerEnchantOptions: PlayerEnchantOptionsPacket, + ItemStackRequest: ItemStackRequestPacket, + ItemStackResponse: ItemStackResponsePacket, + PlayerArmorDamage: PlayerArmorDamagePacket, + CodeBuilder: CodeBuilderPacket, + UpdatePlayerGameType: UpdatePlayerGameTypePacket, + EmoteList: EmoteListPacket, + PositionTrackingDbServerBroadcast: PositionTrackingDBServerBroadcastPacket, + PositionTrackingDbClientRequest: PositionTrackingDBClientRequestPacket, + DebugInfo: DebugInfoPacket, + PacketViolationWarning: PacketViolationWarningPacket, + MotionPredictionHints: MotionPredictionHintsPacket, + AnimateEntity: AnimateEntityPacket, + CameraShake: CameraShakePacket, + PlayerFog: PlayerFogPacket, + CorrectPlayerMovePrediction: CorrectPlayerMovePredictionPacket, + ItemComponent: ItemComponentPacket, + FilterText: FilterTextPacket, + ClientboundDebugRenderer: ClientBoundDebugRendererPacket, + SyncActorProperty: SyncActorPropertyPacket, + AddVolumeEntity: AddVolumeEntityPacket, + RemoveVolumeEntity: RemoveVolumeEntityPacket, + SimulationType: SimulationTypePacket, + NpcDialogue: NpcDialoguePacket, + EduUriResource: EduUriResourcePacket, + CreatePhoto: CreatePhotoPacket, + UpdateSubChunkBlocks: UpdateSubChunkBlocksPacket, + SubChunk: SubChunkPacket, + SubChunkRequest: SubChunkRequestPacket, + PlayerStartItemCooldown: PlayerStartItemCooldownPacket, + ScriptMessage: ScriptMessagePacket, + CodeBuilderSource: CodeBuilderSourcePacket, + TickingAreaLoadStatus: TickingAreaLoadStatusPacket, + DimensionData: DimensionDataPacket, + AgentActionEvent: AgentActionEventPacket, + ChangeMobProperty: ChangeMobPropertyPacket, + LessonProgress: LessonProgressPacket, + RequestAbility: RequestAbilityPacket, + RequestPermissions: RequestPermissionsPacket, + ToastRequest: ToastRequestPacket, + UpdateAbilities: UpdateAbilitiesPacket, + UpdateAdventureSettings: UpdateAdventureSettingsPacket, + DeathInfo: DeathInfoPacket, + EditorNetwork: EditorNetworkPacket, + FeatureRegistry: FeatureRegistryPacket, + ServerStats: ServerStatsPacket, + RequestNetworkSettings: RequestNetworkSettingsPacket, + GameTestRequest: GameTestRequestPacket, + GameTestResults: GameTestResultsPacket, + UpdateClientInputLocks: UpdateClientInputLocksPacket, + CameraPresets: CameraPresetsPacket, + UnlockedRecipes: UnlockedRecipesPacket, + CameraInstruction: CameraInstructionPacket, + CompressedBiomeDefinitionList: CompressedBiomeDefinitionListPacket, + TrimData: TrimDataPacket, + OpenSign: OpenSignPacket, + AgentAnimation: AgentAnimationPacket, + RefreshEntitlements: RefreshEntitlementsPacket, + PlayerToggleCrafterSlotRequest: PlayerToggleCrafterSlotRequestPacket, + SetPlayerInventoryOptions: SetPlayerInventoryOptionsPacket, + SetHud: SetHudPacket +} + +pub fn read_gamepacket_header( + stream: &mut Cursor<&[u8]>, +) -> Result<(u32, u16, SubClientID, SubClientID), ProtoCodecError> { + // Read the gamepacket length + let length = stream.read_u32_varint()?; + + // Read the gamepacket header and parse it into an u16 + // Since the (var)int is only storing 14 bytes we can treat it as an u16 + // This is normally treated as u32 varint + let gamepacket_header: u16 = stream.read_u16_varint()?; + + // Get the first 10 bits as the packet id + // Can never be more than a 16-bit integer due to being 10-bits big + // Gamepacket IDs through 200-299 are used for spin-offs, they are free to use for custom packets + let gamepacket_id = gamepacket_header & 0b0000_0011_1111_1111; + + // Get the next 2 bits as the sub client sender id + // Can never be more than an 8-bit integer due to being 2 bits big + let subclient_sender_id = + SubClientID::try_from(((gamepacket_header & 0b0000_1100_0000_0000) >> 10) as u8)?; + // Get the next 2 bits as the sub client target id + // Never more than an 8-bit integer due to being 2 bits big + let subclient_target_id = + SubClientID::try_from(((gamepacket_header & 0b0011_0000_0000_0000) >> 12) as u8)?; + + Ok(( + length, + gamepacket_id, + subclient_sender_id, + subclient_target_id, + )) +} + +pub fn write_gamepacket_header( + stream: &mut Vec, + length: u32, + gamepacket_id: u16, + subclient_sender_id: SubClientID, + subclient_target_id: SubClientID, +) -> Result<(), ProtoCodecError> { + // Since the (var)int is only storing 14 bytes, we can treat it as an u16 + // This is normally treated as u32 varint + let mut gamepacket_header: u16 = 0; + + // Set the first 10 bits as the packet id + // Can never be more than a 16-bit integer due to being 10-bits big + // Gamepacket IDs through 200-299 are used for spin-offs, they are free to use for custom packets + gamepacket_header |= 0b0000_0011_1111_1111 & gamepacket_id; + + // Set the next 2 bits as the sub client sender id + // Never more than an 8-bit integer due to being 2 bits big + gamepacket_header |= (Into::::into(subclient_sender_id) >> 10) & 0b0000_1100_0000_0000; + // Set the next 2 bits as the sub client target id + // Never more than an 8-bit integer due to being 2 bits big + gamepacket_header |= (Into::::into(subclient_target_id) >> 12) & 0b0011_0000_0000_0000; + + // Since the size of the header is also included in the batched packet size, + // we need to write it to a temporary buffer + let mut gamepacket_header_buf = Vec::new(); + + // Write the gamepacket header into temporary buffer + gamepacket_header_buf.write_u16_varint(gamepacket_header)?; + + // Write the gamepacket length and the header length + stream.write_u32_varint(length + gamepacket_header_buf.len() as u32)?; + + // Write the final game packet header + stream.write_all(gamepacket_header_buf.as_slice())?; + + Ok(()) +} + +pub const fn get_gamepacket_header_size_prediction() -> usize { + // 2 = gamepacket header (varint u32, only 14 bites can be treated as an u16) + // 4 = gamepacket length size (varint u32) + 2 + 4 +} diff --git a/crates/proto/src/version/v662/helper.rs b/crates/proto/src/version/v662/helper.rs new file mode 100644 index 00000000..e3c7fdb4 --- /dev/null +++ b/crates/proto/src/version/v662/helper.rs @@ -0,0 +1,8 @@ +use crate::helper::ProtoHelper; +use crate::version::v662::gamepackets::GamePackets; + +pub struct ProtoHelperV662; + +impl ProtoHelper for ProtoHelperV662 { + type GamePacketType = GamePackets; +} diff --git a/crates/proto/src/version/v662/info.rs b/crates/proto/src/version/v662/info.rs new file mode 100644 index 00000000..e3ea5635 --- /dev/null +++ b/crates/proto/src/version/v662/info.rs @@ -0,0 +1 @@ +pub const PROTOCOL_VERSION: i32 = 662; diff --git a/crates/proto/src/version/v662/mod.rs b/crates/proto/src/version/v662/mod.rs new file mode 100644 index 00000000..c54619e2 --- /dev/null +++ b/crates/proto/src/version/v662/mod.rs @@ -0,0 +1,13 @@ +//! r/20_u7 + +pub mod enums; +mod gamepackets; +mod helper; +pub mod info; +pub mod packets; +pub mod types; + +pub mod nbt; + +pub use gamepackets::*; +pub use helper::*; diff --git a/crates/proto/src/version/v662/nbt/item_component_data.rs b/crates/proto/src/version/v662/nbt/item_component_data.rs new file mode 100644 index 00000000..735558b2 --- /dev/null +++ b/crates/proto/src/version/v662/nbt/item_component_data.rs @@ -0,0 +1,331 @@ +use serde::{Deserialize, Serialize}; + +#[derive(Serialize, Deserialize, Clone, Debug)] +pub struct Value17 { + pub tags: Struct2, +} + +#[derive(Serialize, Deserialize, Clone, Debug)] +pub struct MinecraftTags { + pub name: String, + pub value: Value17, + #[serde(rename = "type")] + pub r#type: i64, +} + +#[derive(Serialize, Deserialize, Clone, Debug)] +pub struct Value16 { + pub name: Struct1, +} + +#[derive(Serialize, Deserialize, Clone, Debug)] +pub struct UsingConvertsTo { + pub name: String, + pub value: Value16, + #[serde(rename = "type")] + pub r#type: i64, +} + +#[derive(Serialize, Deserialize, Clone, Debug)] +pub struct Value15 { + pub can_always_eat: Struct, + pub nutrition: Struct, + pub saturation_modifier: Struct4, + pub using_converts_to: UsingConvertsTo, +} + +#[derive(Serialize, Deserialize, Clone, Debug)] +pub struct MinecraftFood { + pub name: String, + pub value: Value15, + #[serde(rename = "type")] + pub r#type: i64, +} + +#[derive(Serialize, Deserialize, Clone, Debug)] +pub struct Value14 { + pub max: Struct, + pub min: Struct, +} + +#[derive(Serialize, Deserialize, Clone, Debug)] +pub struct DamageChance { + pub name: String, + pub value: Value14, + #[serde(rename = "type")] + pub r#type: i64, +} + +#[derive(Serialize, Deserialize, Clone, Debug)] +pub struct Value13 { + pub damage_chance: DamageChance, + pub max_durability: Struct, +} + +#[derive(Serialize, Deserialize, Clone, Debug)] +pub struct MinecraftDurability { + pub name: String, + pub value: Value13, + #[serde(rename = "type")] + pub r#type: i64, +} + +#[derive(Serialize, Deserialize, Clone, Debug)] +pub struct Value12 { + pub value: Struct1, +} + +#[derive(Serialize, Deserialize, Clone, Debug)] +pub struct Struct6 { + pub name: String, + pub value: Value12, + #[serde(rename = "type")] + pub r#type: i64, +} + +#[derive(Serialize, Deserialize, Clone, Debug)] +pub struct Value11 {} + +#[derive(Serialize, Deserialize, Clone, Debug)] +pub struct States { + pub name: String, + pub value: Value11, + #[serde(rename = "type")] + pub r#type: i64, +} + +#[derive(Serialize, Deserialize, Clone, Debug)] +pub struct Value10 { + pub name: Struct1, + pub states: States, + pub tags: Struct1, +} + +#[derive(Serialize, Deserialize, Clone, Debug)] +pub struct Block { + pub name: String, + pub value: Value10, + #[serde(rename = "type")] + pub r#type: i64, +} + +#[derive(Serialize, Deserialize, Clone, Debug)] +pub struct Value9 { + pub block: Block, + pub speed: Struct, +} + +#[derive(Serialize, Deserialize, Clone, Debug)] +pub struct Struct5 { + pub name: String, + pub value: Value9, + #[serde(rename = "type")] + pub r#type: i64, +} + +#[derive(Serialize, Deserialize, Clone, Debug)] +pub struct DestroySpeeds { + pub name: String, + pub value: Vec, + #[serde(rename = "type")] + pub r#type: i64, +} + +#[derive(Serialize, Deserialize, Clone, Debug)] +pub struct Value8 { + pub destroy_speeds: DestroySpeeds, + pub use_efficiency: Struct, +} + +#[derive(Serialize, Deserialize, Clone, Debug)] +pub struct MinecraftDigger { + pub name: String, + pub value: Value8, + #[serde(rename = "type")] + pub r#type: i64, +} + +#[derive(Serialize, Deserialize, Clone, Debug)] +pub struct Struct4 { + pub name: String, + pub value: f64, + #[serde(rename = "type")] + pub r#type: i64, +} + +#[derive(Serialize, Deserialize, Clone, Debug)] +pub struct Value7 { + pub category: Struct1, + pub duration: Struct4, +} + +#[derive(Serialize, Deserialize, Clone, Debug)] +pub struct MinecraftCooldown { + pub name: String, + pub value: Value7, + #[serde(rename = "type")] + pub r#type: i64, +} + +#[derive(Serialize, Deserialize, Clone, Debug)] +pub struct Value6 { + pub num_viewable_slots: Struct, +} + +#[derive(Serialize, Deserialize, Clone, Debug)] +pub struct MinecraftBundleInteraction { + pub name: String, + pub value: Value6, + #[serde(rename = "type")] + pub r#type: i64, +} + +#[derive(Serialize, Deserialize, Clone, Debug)] +pub struct Value5 { + pub value: Struct, +} + +#[derive(Serialize, Deserialize, Clone, Debug)] +pub struct Struct3 { + pub name: String, + pub value: Value5, + #[serde(rename = "type")] + pub r#type: i64, +} + +#[derive(Serialize, Deserialize, Clone, Debug)] +pub struct Struct2 { + pub name: String, + pub value: Vec, + #[serde(rename = "type")] + pub r#type: i64, +} + +#[derive(Serialize, Deserialize, Clone, Debug)] +pub struct Value4 { + pub default: Struct1, +} + +#[derive(Serialize, Deserialize, Clone, Debug)] +pub struct Textures { + pub name: String, + pub value: Value4, + #[serde(rename = "type")] + pub r#type: i64, +} + +#[derive(Serialize, Deserialize, Clone, Debug)] +pub struct Value3 { + pub textures: Textures, +} + +#[derive(Serialize, Deserialize, Clone, Debug)] +pub struct MinecraftIcon { + pub name: String, + pub value: Value3, + #[serde(rename = "type")] + pub r#type: i64, +} + +#[derive(Serialize, Deserialize, Clone, Debug)] +pub struct Struct1 { + pub name: String, + pub value: String, + #[serde(rename = "type")] + pub r#type: i64, +} + +#[derive(Serialize, Deserialize, Clone, Debug)] +pub struct Struct { + pub name: String, + pub value: i64, + #[serde(rename = "type")] + pub r#type: i64, +} + +#[derive(Serialize, Deserialize, Clone, Debug)] +pub struct Value2 { + pub allow_off_hand: Struct, + pub can_destroy_in_creative: Struct, + pub creative_category: Struct, + pub creative_group: Struct1, + pub damage: Struct, + pub enchantable_slot: Struct1, + pub enchantable_value: Struct, + pub foil: Struct, + pub frame_count: Struct, + pub hand_equipped: Struct, + pub hover_text_color: Struct1, + pub liquid_clipped: Struct, + pub max_stack_size: Struct, + #[serde(rename = "minecraft:icon")] + pub minecraft_icon: MinecraftIcon, + pub mining_speed: Struct, + pub should_despawn: Struct, + pub stacked_by_data: Struct, + pub use_animation: Struct, + pub use_duration: Struct, +} + +#[derive(Serialize, Deserialize, Clone, Debug)] +pub struct ItemProperties { + pub name: String, + pub value: Value2, + #[serde(rename = "type")] + pub r#type: i64, +} + +#[derive(Serialize, Deserialize, Clone, Debug)] +pub struct Value1 { + pub item_properties: ItemProperties, + pub item_tags: Struct2, + #[serde(rename = "minecraft:allow_off_hand")] + pub minecraft_allow_off_hand: Struct3, + #[serde(rename = "minecraft:bundle_interaction")] + pub minecraft_bundle_interaction: MinecraftBundleInteraction, + #[serde(rename = "minecraft:can_destroy_in_creative")] + pub minecraft_can_destroy_in_creative: Struct3, + #[serde(rename = "minecraft:cooldown")] + pub minecraft_cooldown: MinecraftCooldown, + #[serde(rename = "minecraft:damage")] + pub minecraft_damage: Struct3, + #[serde(rename = "minecraft:digger")] + pub minecraft_digger: MinecraftDigger, + #[serde(rename = "minecraft:display_name")] + pub minecraft_display_name: Struct6, + #[serde(rename = "minecraft:durability")] + pub minecraft_durability: MinecraftDurability, + #[serde(rename = "minecraft:food")] + pub minecraft_food: MinecraftFood, + #[serde(rename = "minecraft:hand_equipped")] + pub minecraft_hand_equipped: Struct3, + #[serde(rename = "minecraft:hover_text_color")] + pub minecraft_hover_text_color: Struct6, + #[serde(rename = "minecraft:rarity")] + pub minecraft_rarity: Struct6, + #[serde(rename = "minecraft:tags")] + pub minecraft_tags: MinecraftTags, +} + +#[derive(Serialize, Deserialize, Clone, Debug)] +pub struct Components { + pub name: String, + pub value: Value1, + #[serde(rename = "type")] + pub r#type: i64, +} + +#[derive(Serialize, Deserialize, Clone, Debug)] +pub struct Value { + pub components: Components, + pub id: Struct, + pub name: Struct1, +} + +#[derive(Serialize, Deserialize, Clone, Debug)] +pub struct ItemComponentDataNBT { + pub name: String, + #[serde(rename = "type")] + pub r#type: i64, + pub value: Value, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/nbt/mod.rs b/crates/proto/src/version/v662/nbt/mod.rs new file mode 100644 index 00000000..d903aca8 --- /dev/null +++ b/crates/proto/src/version/v662/nbt/mod.rs @@ -0,0 +1,8 @@ +macro_rules! export { + ($name:ident) => { + mod $name; + pub use $name::*; + }; +} + +export!(item_component_data); diff --git a/crates/proto/src/version/v662/packets/actor_event.rs b/crates/proto/src/version/v662/packets/actor_event.rs new file mode 100644 index 00000000..4fd275db --- /dev/null +++ b/crates/proto/src/version/v662/packets/actor_event.rs @@ -0,0 +1,12 @@ +use crate::version::v662::enums::ActorEvent; +use crate::version::v662::types::ActorRuntimeID; +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 27)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct ActorEventPacket { + pub target_runtime_id: ActorRuntimeID, + pub event_id: ActorEvent, + #[endianness(var)] + pub data: i32, +} diff --git a/crates/proto/src/version/v662/packets/actor_pick_request.rs b/crates/proto/src/version/v662/packets/actor_pick_request.rs new file mode 100644 index 00000000..c357ddaf --- /dev/null +++ b/crates/proto/src/version/v662/packets/actor_pick_request.rs @@ -0,0 +1,10 @@ +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 35)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct ActorPickRequestPacket { + #[endianness(le)] + pub actor_id: i64, + pub max_slots: i8, + pub with_data: bool, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/add_actor.rs b/crates/proto/src/version/v662/packets/add_actor.rs new file mode 100644 index 00000000..b122b1e5 --- /dev/null +++ b/crates/proto/src/version/v662/packets/add_actor.rs @@ -0,0 +1,42 @@ +use crate::version::v662::types::{ActorLink, ActorRuntimeID, ActorUniqueID, DataItem, PropertySyncData}; +use bedrockrs_macros::{gamepacket, ProtoCodec}; +use vek::{Vec2, Vec3}; + +#[derive(ProtoCodec, Clone, Debug)] +pub struct AttributeEntry { + pub attribute_name: String, + #[endianness(le)] + pub min_value: f32, + #[endianness(le)] + pub current_value: f32, + #[endianness(le)] + pub max_value: f32, +} + +#[gamepacket(id = 13)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct AddActorPacket { + pub target_actor_id: ActorUniqueID, + pub target_runtime_id: ActorRuntimeID, + pub actor_type: String, + #[endianness(le)] + pub position: Vec3, + #[endianness(le)] + pub velocity: Vec3, + #[endianness(le)] + pub rotation: Vec2, + #[endianness(le)] + pub y_head_rotation: f32, + #[endianness(le)] + pub y_body_rotation: f32, + #[vec_repr(u32)] + #[vec_endianness(var)] + pub attributes: Vec, + #[vec_repr(u32)] + #[vec_endianness(var)] + pub actor_data: Vec, // VERIFY: vec_repr & vec_endianness + pub synced_properties: PropertySyncData, + #[vec_repr(u32)] + #[vec_endianness(var)] + pub actor_links: Vec, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/add_behaviour_tree.rs b/crates/proto/src/version/v662/packets/add_behaviour_tree.rs new file mode 100644 index 00000000..16bc3c18 --- /dev/null +++ b/crates/proto/src/version/v662/packets/add_behaviour_tree.rs @@ -0,0 +1,7 @@ +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 89)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct AddBehaviourTreePacket { + pub json_behaviour_tree_structure: String, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/add_item_actor.rs b/crates/proto/src/version/v662/packets/add_item_actor.rs new file mode 100644 index 00000000..5a3f3844 --- /dev/null +++ b/crates/proto/src/version/v662/packets/add_item_actor.rs @@ -0,0 +1,19 @@ +use crate::version::v662::types::{ActorRuntimeID, ActorUniqueID, DataItem, NetworkItemStackDescriptor}; +use bedrockrs_macros::{gamepacket, ProtoCodec}; +use vek::Vec3; + +#[gamepacket(id = 15)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct AddItemActorPacket { + pub target_actor_id: ActorUniqueID, + pub target_runtime_id: ActorRuntimeID, + pub item: NetworkItemStackDescriptor, + #[endianness(le)] + pub position: Vec3, + #[endianness(le)] + pub velocity: Vec3, + #[vec_repr(u32)] + #[vec_endianness(var)] + pub entity_data: Vec, // VERIFY: vec_repr & vec_endianness + pub from_fishing: bool, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/add_painting.rs b/crates/proto/src/version/v662/packets/add_painting.rs new file mode 100644 index 00000000..dbfb27ec --- /dev/null +++ b/crates/proto/src/version/v662/packets/add_painting.rs @@ -0,0 +1,15 @@ +use crate::version::v662::types::{ActorRuntimeID, ActorUniqueID}; +use bedrockrs_macros::{gamepacket, ProtoCodec}; +use vek::Vec3; + +#[gamepacket(id = 22)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct AddPaintingPacket { + pub target_actor_id: ActorUniqueID, + pub target_runtime_id: ActorRuntimeID, + #[endianness(le)] + pub position: Vec3, + #[endianness(var)] + pub direction: i32, + pub motif: String, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/add_player.rs b/crates/proto/src/version/v662/packets/add_player.rs new file mode 100644 index 00000000..3473725e --- /dev/null +++ b/crates/proto/src/version/v662/packets/add_player.rs @@ -0,0 +1,34 @@ +use crate::version::v662::enums::{BuildPlatform, GameType}; +use crate::version::v662::types::{ActorLink, ActorRuntimeID, DataItem, NetworkItemStackDescriptor, PropertySyncData, SerializedAbilitiesData}; +use bedrockrs_macros::{gamepacket, ProtoCodec}; +use uuid::Uuid; +use vek::{Vec2, Vec3}; + +#[gamepacket(id = 12)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct AddPlayerPacket { + pub uuid: Uuid, + pub player_name: String, + pub target_runtime_id: ActorRuntimeID, + pub platform_chat_id: String, + #[endianness(le)] + pub position: Vec3, + #[endianness(le)] + pub velocity: Vec3, + #[endianness(le)] + pub rotation: Vec2, + #[endianness(le)] + pub y_head_rotation: f32, + pub carried_item: NetworkItemStackDescriptor, + pub player_game_type: GameType, + #[vec_repr(u32)] + #[vec_endianness(var)] + pub entity_data: Vec, // VERIFY: vec_repr & vec_endianness + pub synced_properties: PropertySyncData, + pub abilities_data: SerializedAbilitiesData, + #[vec_repr(u32)] + #[vec_endianness(var)] + pub actor_links: Vec, + pub device_id: String, + pub build_platform: BuildPlatform, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/add_volume_entity.rs b/crates/proto/src/version/v662/packets/add_volume_entity.rs new file mode 100644 index 00000000..9ebfaebd --- /dev/null +++ b/crates/proto/src/version/v662/packets/add_volume_entity.rs @@ -0,0 +1,17 @@ +use crate::version::v662::types::{EntityNetID, NetworkBlockPosition}; +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 166)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct AddVolumeEntityPacket { + pub entity_network_id: EntityNetID, + #[nbt] + pub components: nbtx::Value, // TODO: NBT Structure + pub json_identifier: String, + pub instance_name: String, + pub min_bounds: NetworkBlockPosition, + pub max_bounds: NetworkBlockPosition, + #[endianness(var)] + pub dimension_type: i32, + pub engine_version: String, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/agent_action_event.rs b/crates/proto/src/version/v662/packets/agent_action_event.rs new file mode 100644 index 00000000..f0093863 --- /dev/null +++ b/crates/proto/src/version/v662/packets/agent_action_event.rs @@ -0,0 +1,10 @@ +use crate::version::v662::enums::AgentActionType; +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 181)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct AgentActionEventPacket { + pub request_id: String, + pub action_type: AgentActionType, + pub response: String, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/agent_animation.rs b/crates/proto/src/version/v662/packets/agent_animation.rs new file mode 100644 index 00000000..4f0f295a --- /dev/null +++ b/crates/proto/src/version/v662/packets/agent_animation.rs @@ -0,0 +1,9 @@ +use crate::version::v662::types::ActorRuntimeID; +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 304)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct AgentAnimationPacket { + pub agent_animation: i8, + pub runtime_id: ActorRuntimeID, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/animate.rs b/crates/proto/src/version/v662/packets/animate.rs new file mode 100644 index 00000000..a6874d13 --- /dev/null +++ b/crates/proto/src/version/v662/packets/animate.rs @@ -0,0 +1,69 @@ +use crate::version::v662::types::ActorRuntimeID; +use bedrockrs_macros::{gamepacket, ProtoCodec}; +use bedrockrs_proto_core::error::ProtoCodecError; +use bedrockrs_proto_core::ProtoCodec; +use std::io::{Cursor, Read}; +use varint_rs::{VarintReader, VarintWriter}; + +#[derive(ProtoCodec, Clone, Debug)] +#[enum_repr(i32)] +#[enum_endianness(var)] +#[repr(i32)] +pub enum Action { + NoAction = 0, + Swing = 1, + WakeUp = 3, + CriticalHit = 4, + MagicCriticalHit = 5, + RowRight { + #[endianness(le)] + rowing_time: f32, + } = 128, + RowLeft { + #[endianness(le)] + rowing_time: f32, + } = 129, +} + +#[gamepacket(id = 44)] +#[derive(Clone, Debug)] +pub struct AnimatePacket { + pub action: Action, + pub target_runtime_id: ActorRuntimeID, +} + +impl ProtoCodec for AnimatePacket { + fn proto_serialize(&self, stream: &mut Vec) -> Result<(), ProtoCodecError> { + let mut action_stream: Vec = Vec::new(); + ::proto_serialize(&self.action, &mut action_stream)?; + let mut action_cursor = Cursor::new(action_stream.as_slice()); + + stream.write_i32_varint(action_cursor.read_i32_varint()?)?; + ::proto_serialize(&self.target_runtime_id, stream)?; + action_cursor.read_to_end(stream)?; + + Ok(()) + } + + fn proto_deserialize(stream: &mut Cursor<&[u8]>) -> Result { + let mut action_stream: Vec = Vec::new(); + + action_stream.write_i32_varint(stream.read_i32_varint()?)?; + let target_runtime_id = ::proto_deserialize(stream)?; + stream.read_to_end(&mut action_stream)?; + + let mut action_cursor = Cursor::new(action_stream.as_slice()); + let action = ::proto_deserialize(&mut action_cursor)?; + + Ok(Self { + action, + target_runtime_id, + }) + } + + fn get_size_prediction(&self) -> usize { + self.action.get_size_prediction() + self.target_runtime_id.get_size_prediction() + } +} + +// VERIFY: ProtoCodec impl diff --git a/crates/proto/src/version/v662/packets/animate_entity.rs b/crates/proto/src/version/v662/packets/animate_entity.rs new file mode 100644 index 00000000..c1f5280c --- /dev/null +++ b/crates/proto/src/version/v662/packets/animate_entity.rs @@ -0,0 +1,18 @@ +use crate::version::v662::enums::MolangVersion; +use crate::version::v662::types::ActorRuntimeID; +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 158)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct AnimateEntityPacket { + pub animation: String, + pub next_state: String, + pub stop_expression: String, + pub stop_expression_molang_version: MolangVersion, + pub controller: String, + #[endianness(le)] + pub blend_out_time: f32, + #[vec_repr(u32)] + #[vec_endianness(var)] + pub runtime_ids: Vec, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/anvil_damage.rs b/crates/proto/src/version/v662/packets/anvil_damage.rs new file mode 100644 index 00000000..15b58c3f --- /dev/null +++ b/crates/proto/src/version/v662/packets/anvil_damage.rs @@ -0,0 +1,9 @@ +use crate::version::v662::types::NetworkBlockPosition; +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 141)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct AnvilDamagePacket { + pub damage_amount: i8, + pub block_position: NetworkBlockPosition, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/automation_client_connect.rs b/crates/proto/src/version/v662/packets/automation_client_connect.rs new file mode 100644 index 00000000..8e3262c7 --- /dev/null +++ b/crates/proto/src/version/v662/packets/automation_client_connect.rs @@ -0,0 +1,8 @@ +use crate::version::v662::types::WebSocketPacketData; +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 95)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct AutomationClientConnectPacket { + pub web_socket_data: WebSocketPacketData, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/available_actor_identifiers.rs b/crates/proto/src/version/v662/packets/available_actor_identifiers.rs new file mode 100644 index 00000000..ebe1c634 --- /dev/null +++ b/crates/proto/src/version/v662/packets/available_actor_identifiers.rs @@ -0,0 +1,8 @@ +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 119)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct AvailableActorIdentifiersPacket { + #[nbt] + pub actor_info_list: nbtx::Value, // TODO: NBT Structure +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/available_commands.rs b/crates/proto/src/version/v662/packets/available_commands.rs new file mode 100644 index 00000000..6633e2fc --- /dev/null +++ b/crates/proto/src/version/v662/packets/available_commands.rs @@ -0,0 +1,210 @@ +use crate::version::v662::enums::CommandPermissionLevel; +use bedrockrs_macros::{gamepacket, ProtoCodec}; +use bedrockrs_proto_core::error::ProtoCodecError; +use bedrockrs_proto_core::{ProtoCodec, ProtoCodecLE, ProtoCodecVAR}; +use std::io::Cursor; +use std::mem::size_of; + +#[derive(Clone, Debug)] +pub struct EnumDataEntry { + name: String, + values: Vec, +} + +impl ProtoCodec for EnumDataEntry { + fn proto_serialize(&self, stream: &mut Vec) -> Result<(), ProtoCodecError> { + ::proto_serialize(&self.name, stream)?; + { + let len: u32 = self.values.len().try_into()?; + ::proto_serialize(&len, stream)?; + for i in &self.values { + ::proto_serialize(i, stream)?; + // VERIFY: If this varint works + } + } + + Ok(()) + } + + fn proto_deserialize(stream: &mut Cursor<&[u8]>) -> Result { + let name = ::proto_deserialize(stream)?; + let values = { + let len = ::proto_deserialize(stream)?; + let mut vec = Vec::with_capacity(len.try_into()?); + for _ in 0..len { + vec.push(::proto_deserialize(stream)?); + } + vec + }; + + Ok(Self { name, values }) + } + + fn get_size_prediction(&self) -> usize { + self.name.get_size_prediction() + self.values.len() * size_of::() + } +} + +#[derive(ProtoCodec, Clone, Debug)] +pub struct SubCommandValues { + #[endianness(le)] + pub sub_command_first_value: u16, + #[endianness(le)] + pub sub_command_second_value: u16, +} + +#[derive(ProtoCodec, Clone, Debug)] +pub struct ParameterDataEntry { + pub name: String, + #[endianness(le)] + pub parse_symbol: u32, + pub is_optional: bool, + pub options: i8, +} + +#[derive(ProtoCodec, Clone, Debug)] +pub struct OverloadsEntry { + pub is_chaining: bool, + #[vec_repr(u32)] + #[vec_endianness(var)] + pub parameter_data: Vec, +} + +#[derive(Clone, Debug)] +pub struct CommandsEntry { + pub name: String, + pub description: String, + pub flags: u16, + pub permission_level: CommandPermissionLevel, + pub alias_enum: i32, + pub chained_sub_command_indices: Vec, + pub overloads: Vec, +} + +impl ProtoCodec for CommandsEntry { + fn proto_serialize(&self, stream: &mut Vec) -> Result<(), ProtoCodecError> { + ::proto_serialize(&self.name, stream)?; + ::proto_serialize(&self.description, stream)?; + ::proto_serialize(&self.flags, stream)?; + ::proto_serialize(&self.permission_level, stream)?; + ::proto_serialize(&self.alias_enum, stream)?; + { + let len: u32 = self.chained_sub_command_indices.len().try_into()?; + ::proto_serialize(&len, stream)?; + for i in &self.chained_sub_command_indices { + ::proto_serialize(i, stream)?; + } + } + { + let len: u32 = self.overloads.len().try_into()?; + ::proto_serialize(&len, stream)?; + for i in &self.overloads { + ::proto_serialize(i, stream)?; + } + } + + Ok(()) + } + + fn proto_deserialize(stream: &mut Cursor<&[u8]>) -> Result { + let name = ::proto_deserialize(stream)?; + let description = ::proto_deserialize(stream)?; + let flags = ::proto_deserialize(stream)?; + let permission_level = ::proto_deserialize(stream)?; + let alias_enum = ::proto_deserialize(stream)?; + let chained_sub_command_indices = { + let len = ::proto_deserialize(stream)?; + let mut vec = Vec::with_capacity(len.try_into()?); + for _ in 0..len { + vec.push(::proto_deserialize(stream)?); + } + vec + }; + let overloads = { + let len = ::proto_deserialize(stream)?; + let mut vec = Vec::with_capacity(len.try_into()?); + for _ in 0..len { + vec.push(::proto_deserialize(stream)?); + } + vec + }; + + Ok(Self { + name, + description, + flags, + permission_level, + alias_enum, + chained_sub_command_indices, + overloads, + }) + } + + fn get_size_prediction(&self) -> usize { + self.name.get_size_prediction() + + self.description.get_size_prediction() + + size_of::() + + self.chained_sub_command_indices.len() * size_of::() + + size_of::() + + self + .overloads + .iter() + .map(|i| i.get_size_prediction()) + .sum::() + } +} + +#[derive(ProtoCodec, Clone, Debug)] +pub struct SoftEnumsEntry { + pub enum_name: String, + #[vec_repr(u32)] + #[vec_endianness(var)] + pub enum_options: Vec, +} + +#[derive(ProtoCodec, Clone, Debug)] +pub struct ConstraintsEntry { + #[endianness(le)] + pub enum_value_symbol: u32, + #[endianness(le)] + pub enum_symbol: u32, + #[vec_repr(u32)] + #[vec_endianness(var)] + pub constraint_indices: Vec, +} + +#[derive(ProtoCodec, Clone, Debug)] +pub struct ChainedSubCommandDataEntry { + pub sub_command_name: String, + #[vec_repr(u32)] + #[vec_endianness(var)] + pub sub_command_values: Vec, +} + +#[gamepacket(id = 76)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct AvailableCommandsPacket { + #[vec_repr(u32)] + #[vec_endianness(var)] + pub enum_values: Vec, + #[vec_repr(u32)] + #[vec_endianness(var)] + pub post_fixes: Vec, + #[vec_repr(u32)] + #[vec_endianness(var)] + pub enum_data: Vec, + #[vec_repr(u32)] + #[vec_endianness(var)] + pub chained_sub_command_data: Vec, + #[vec_repr(u32)] + #[vec_endianness(var)] + pub commands: Vec, + #[vec_repr(u32)] + #[vec_endianness(var)] + pub soft_enums: Vec, + #[vec_repr(u32)] + #[vec_endianness(var)] + pub constraints: Vec, +} + +// VERIFY: ProtoCodec impl diff --git a/crates/proto/src/version/v662/packets/biome_definition_list.rs b/crates/proto/src/version/v662/packets/biome_definition_list.rs new file mode 100644 index 00000000..ced7ebf3 --- /dev/null +++ b/crates/proto/src/version/v662/packets/biome_definition_list.rs @@ -0,0 +1,8 @@ +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 122)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct BiomeDefinitionListPacket { + #[nbt] + pub biome_definition_data: nbtx::Value, // TODO: NBT Structure +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/block_actor_data.rs b/crates/proto/src/version/v662/packets/block_actor_data.rs new file mode 100644 index 00000000..32a96a52 --- /dev/null +++ b/crates/proto/src/version/v662/packets/block_actor_data.rs @@ -0,0 +1,10 @@ +use crate::version::v662::types::NetworkBlockPosition; +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 56)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct BlockActorDataPacket { + pub block_position: NetworkBlockPosition, + #[nbt] + pub actor_data_tags: nbtx::Value, // TODO: NBT Structure +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/block_event.rs b/crates/proto/src/version/v662/packets/block_event.rs new file mode 100644 index 00000000..5d3f496e --- /dev/null +++ b/crates/proto/src/version/v662/packets/block_event.rs @@ -0,0 +1,12 @@ +use crate::version::v662::types::NetworkBlockPosition; +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 26)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct BlockEventPacket { + pub block_position: NetworkBlockPosition, + #[endianness(var)] + pub event_type: i32, + #[endianness(var)] + pub event_value: i32, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/block_pick_request.rs b/crates/proto/src/version/v662/packets/block_pick_request.rs new file mode 100644 index 00000000..5a9c9ac5 --- /dev/null +++ b/crates/proto/src/version/v662/packets/block_pick_request.rs @@ -0,0 +1,10 @@ +use crate::version::v662::types::BlockPos; +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 34)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct BlockPickRequestPacket { + pub position: BlockPos, + pub with_data: bool, + pub max_slots: i8, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/book_edit.rs b/crates/proto/src/version/v662/packets/book_edit.rs new file mode 100644 index 00000000..b2ab27f0 --- /dev/null +++ b/crates/proto/src/version/v662/packets/book_edit.rs @@ -0,0 +1,47 @@ +use crate::version::v662::enums::BookEditAction; +use bedrockrs_macros::gamepacket; +use bedrockrs_proto_core::error::ProtoCodecError; +use bedrockrs_proto_core::ProtoCodec; +use byteorder::{ReadBytesExt, WriteBytesExt}; +use std::io::{Cursor, Read}; +use std::mem::size_of; + +#[gamepacket(id = 97)] +#[derive(Clone, Debug)] +pub struct BookEditPacket { + pub action: BookEditAction, + pub book_slot: i8, +} + +impl ProtoCodec for BookEditPacket { + fn proto_serialize(&self, stream: &mut Vec) -> Result<(), ProtoCodecError> { + let mut action_stream: Vec = Vec::new(); + ::proto_serialize(&self.action, &mut action_stream)?; + let mut action_cursor = Cursor::new(action_stream.as_slice()); + + stream.write_i8(action_cursor.read_i8()?)?; + ::proto_serialize(&self.book_slot, stream)?; + action_cursor.read_to_end(stream)?; + + Ok(()) + } + + fn proto_deserialize(stream: &mut Cursor<&[u8]>) -> Result { + let mut action_stream: Vec = Vec::new(); + + action_stream.write_i8(stream.read_i8()?)?; + let book_slot = ::proto_deserialize(stream)?; + stream.read_to_end(&mut action_stream)?; + + let mut action_cursor = Cursor::new(action_stream.as_slice()); + let action = ::proto_deserialize(&mut action_cursor)?; + + Ok(Self { action, book_slot }) + } + + fn get_size_prediction(&self) -> usize { + self.action.get_size_prediction() + size_of::() + } +} + +// VERIFY: ProtoCodec impl diff --git a/crates/proto/src/version/v662/packets/boss_event.rs b/crates/proto/src/version/v662/packets/boss_event.rs new file mode 100644 index 00000000..e068a2c4 --- /dev/null +++ b/crates/proto/src/version/v662/packets/boss_event.rs @@ -0,0 +1,10 @@ +use crate::version::v662::enums::BossEventUpdateType; +use crate::version::v662::types::ActorUniqueID; +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 74)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct BossEventPacket { + pub target_actor_id: ActorUniqueID, + pub event_type: BossEventUpdateType, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/camera.rs b/crates/proto/src/version/v662/packets/camera.rs new file mode 100644 index 00000000..9c0baa4b --- /dev/null +++ b/crates/proto/src/version/v662/packets/camera.rs @@ -0,0 +1,9 @@ +use crate::version::v662::types::ActorUniqueID; +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 73)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct CameraPacket { + pub camera_id: ActorUniqueID, + pub target_player_id: ActorUniqueID, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/camera_instruction.rs b/crates/proto/src/version/v662/packets/camera_instruction.rs new file mode 100644 index 00000000..be1baa07 --- /dev/null +++ b/crates/proto/src/version/v662/packets/camera_instruction.rs @@ -0,0 +1,8 @@ +use crate::version::v662::types::CameraInstruction; +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 300)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct CameraInstructionPacket { + pub camera_instruction: CameraInstruction, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/camera_presets.rs b/crates/proto/src/version/v662/packets/camera_presets.rs new file mode 100644 index 00000000..763099bc --- /dev/null +++ b/crates/proto/src/version/v662/packets/camera_presets.rs @@ -0,0 +1,8 @@ +use crate::version::v662::types::CameraPresets; +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 198)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct CameraPresetsPacket { + pub camera_presets: CameraPresets, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/camera_shake.rs b/crates/proto/src/version/v662/packets/camera_shake.rs new file mode 100644 index 00000000..1909846b --- /dev/null +++ b/crates/proto/src/version/v662/packets/camera_shake.rs @@ -0,0 +1,13 @@ +use crate::version::v662::enums::{CameraShakeAction, CameraShakeType}; +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 159)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct CameraShakePacket { + #[endianness(le)] + pub intensity: f32, + #[endianness(le)] + pub seconds: f32, + pub shake_type: CameraShakeType, + pub shake_action: CameraShakeAction, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/change_dimension.rs b/crates/proto/src/version/v662/packets/change_dimension.rs new file mode 100644 index 00000000..ae65fb4e --- /dev/null +++ b/crates/proto/src/version/v662/packets/change_dimension.rs @@ -0,0 +1,12 @@ +use bedrockrs_macros::{gamepacket, ProtoCodec}; +use vek::Vec3; + +#[gamepacket(id = 61)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct ChangeDimensionPacket { + #[endianness(var)] + pub dimension_id: i32, + #[endianness(le)] + pub position: Vec3, + pub respawn: bool, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/change_mob_property.rs b/crates/proto/src/version/v662/packets/change_mob_property.rs new file mode 100644 index 00000000..a760c7d5 --- /dev/null +++ b/crates/proto/src/version/v662/packets/change_mob_property.rs @@ -0,0 +1,15 @@ +use crate::version::v662::types::ActorUniqueID; +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 182)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct ChangeMobPropertyPacket { + pub actor_id: ActorUniqueID, + pub property_name: String, + pub bool_component_value: bool, + pub string_component_value: String, + #[endianness(var)] + pub int_component_value: i32, + #[endianness(le)] + pub float_component_value: f32, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/chunk_radius_updated.rs b/crates/proto/src/version/v662/packets/chunk_radius_updated.rs new file mode 100644 index 00000000..dffe910f --- /dev/null +++ b/crates/proto/src/version/v662/packets/chunk_radius_updated.rs @@ -0,0 +1,8 @@ +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 70)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct ChunkRadiusUpdatedPacket { + #[endianness(var)] + pub chunk_radius: i32, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/client_bound_debug_renderer.rs b/crates/proto/src/version/v662/packets/client_bound_debug_renderer.rs new file mode 100644 index 00000000..52cc46e7 --- /dev/null +++ b/crates/proto/src/version/v662/packets/client_bound_debug_renderer.rs @@ -0,0 +1,32 @@ +use bedrockrs_macros::{gamepacket, ProtoCodec}; +use vek::Vec3; + +#[derive(ProtoCodec, Clone, Debug)] +#[enum_repr(u32)] +#[enum_endianness(var)] +#[repr(u32)] +pub enum Type { + Invalid = 0, + ClearDebugMarkers = 1, + AddDebugMarkerCube { + text: String, + #[endianness(le)] + position: Vec3, + #[endianness(le)] + r: f32, + #[endianness(le)] + g: f32, + #[endianness(le)] + b: f32, + #[endianness(le)] + a: f32, + #[endianness(le)] + millisecond_duration: u64, + } = 2, +} + +#[gamepacket(id = 163)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct ClientBoundDebugRendererPacket { + pub debug_marker_type: Type, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/client_bound_map_item_data.rs b/crates/proto/src/version/v662/packets/client_bound_map_item_data.rs new file mode 100644 index 00000000..fd84f846 --- /dev/null +++ b/crates/proto/src/version/v662/packets/client_bound_map_item_data.rs @@ -0,0 +1,105 @@ +use crate::version::v662::types::{ActorUniqueID, BlockPos, MapDecoration, MapItemTrackedActorUniqueID}; +use bedrockrs_macros::{gamepacket, ProtoCodec}; +use bedrockrs_proto_core::error::ProtoCodecError; +use bedrockrs_proto_core::ProtoCodec; +use std::io::{Cursor, Read}; +use varint_rs::{VarintReader, VarintWriter}; + +#[derive(ProtoCodec, Clone, Debug)] +pub struct PixelsEntry { + #[endianness(var)] + pub pixel: u32, +} + +#[derive(ProtoCodec, Clone, Debug)] +#[enum_repr(u32)] +#[enum_endianness(var)] +#[repr(u32)] +pub enum Type { + Invalid = 0x0, + TextureUpdate { + #[endianness(var)] + texture_width: i32, + #[endianness(var)] + texture_height: i32, + #[endianness(var)] + x_tex_coordinate: i32, + #[endianness(var)] + y_tex_coordinate: i32, + #[vec_repr(u32)] + #[vec_endianness(var)] + pixels: Vec, + } = 0x2, + DecorationUpdate { + #[vec_repr(u32)] + #[vec_endianness(var)] + actor_ids: Vec, + #[vec_repr(u32)] + #[vec_endianness(var)] + decoration_list: Vec, + } = 0x4, + Creation { + #[vec_repr(u32)] + #[vec_endianness(var)] + map_id_list: Vec, + } = 0x8, +} + +#[gamepacket(id = 67)] +#[derive(Clone, Debug)] +pub struct ClientBoundMapItemDataPacket { + pub map_id: ActorUniqueID, + pub type_flags: Type, + pub dimension: i8, + pub is_locked: bool, + pub map_origin: BlockPos, +} + +impl ProtoCodec for ClientBoundMapItemDataPacket { + fn proto_serialize(&self, stream: &mut Vec) -> Result<(), ProtoCodecError> { + let mut type_flags_stream: Vec = Vec::new(); + ::proto_serialize(&self.type_flags, &mut type_flags_stream)?; + let mut type_flags_cursor = Cursor::new(type_flags_stream.as_slice()); + + ::proto_serialize(&self.map_id, stream)?; + stream.write_u32_varint(type_flags_cursor.read_u32_varint()?)?; + ::proto_serialize(&self.dimension, stream)?; + ::proto_serialize(&self.is_locked, stream)?; + ::proto_serialize(&self.map_origin, stream)?; + type_flags_cursor.read_to_end(stream)?; + + Ok(()) + } + + fn proto_deserialize(stream: &mut Cursor<&[u8]>) -> Result { + let mut type_flags_stream: Vec = Vec::new(); + + let map_id = ::proto_deserialize(stream)?; + type_flags_stream.write_u32_varint(stream.read_u32_varint()?)?; + let dimension = ::proto_deserialize(stream)?; + let is_locked = ::proto_deserialize(stream)?; + let map_origin = ::proto_deserialize(stream)?; + stream.read_to_end(&mut type_flags_stream)?; + + let mut type_flags_cursor = Cursor::new(type_flags_stream.as_slice()); + let type_flags = ::proto_deserialize(&mut type_flags_cursor)?; + + Ok(Self { + map_id, + type_flags, + dimension, + is_locked, + map_origin, + }) + } + + fn get_size_prediction(&self) -> usize { + self.map_id.get_size_prediction() + + self.type_flags.get_size_prediction() + + self.dimension.get_size_prediction() + + self.is_locked.get_size_prediction() + + self.map_origin.get_size_prediction() + } +} + +// VERIFY: ProtoCodec impl diff --git a/crates/proto/src/version/v662/packets/client_cache_blob_status.rs b/crates/proto/src/version/v662/packets/client_cache_blob_status.rs new file mode 100644 index 00000000..ebe2ab36 --- /dev/null +++ b/crates/proto/src/version/v662/packets/client_cache_blob_status.rs @@ -0,0 +1,54 @@ +use bedrockrs_macros::gamepacket; +use bedrockrs_proto_core::error::ProtoCodecError; +use bedrockrs_proto_core::{ProtoCodec, ProtoCodecLE, ProtoCodecVAR}; +use std::io::Cursor; +use std::mem::size_of; + +#[gamepacket(id = 135)] +#[derive(Clone, Debug)] +pub struct ClientCacheBlobStatusPacket { + pub missing_blobs: Vec, + pub obtained_blobs: Vec, +} + +impl ProtoCodec for ClientCacheBlobStatusPacket { + fn proto_serialize(&self, stream: &mut Vec) -> Result<(), ProtoCodecError> { + ::proto_serialize(&(self.missing_blobs.len() as u32), stream)?; + ::proto_serialize(&(self.obtained_blobs.len() as u32), stream)?; + for i in &self.missing_blobs { + ::proto_serialize(i, stream)?; + } + for i in &self.obtained_blobs { + ::proto_serialize(i, stream)?; + } + + Ok(()) + } + + fn proto_deserialize(stream: &mut Cursor<&[u8]>) -> Result { + let missing_blobs_len = ::proto_deserialize(stream)?; + let obtained_blobs_len = ::proto_deserialize(stream)?; + let mut missing_blobs = Vec::with_capacity(missing_blobs_len.try_into()?); + let mut obtained_blobs = Vec::with_capacity(obtained_blobs_len.try_into()?); + for _ in 0..missing_blobs_len { + missing_blobs.push(::proto_deserialize(stream)?); + } + for _ in 0..obtained_blobs_len { + obtained_blobs.push(::proto_deserialize(stream)?); + } + + Ok(Self { + missing_blobs, + obtained_blobs, + }) + } + + fn get_size_prediction(&self) -> usize { + size_of::() + + size_of::() + + self.missing_blobs.len() * size_of::() + + self.obtained_blobs.len() * size_of::() + } +} + +// VERIFY: ProtoCodec impl diff --git a/crates/proto/src/version/v662/packets/client_cache_miss_response.rs b/crates/proto/src/version/v662/packets/client_cache_miss_response.rs new file mode 100644 index 00000000..2ef90b68 --- /dev/null +++ b/crates/proto/src/version/v662/packets/client_cache_miss_response.rs @@ -0,0 +1,16 @@ +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[derive(ProtoCodec, Clone, Debug)] +pub struct MissingBlobEntry { + #[endianness(le)] + pub blob_id: u64, + pub blob_data: String, +} + +#[gamepacket(id = 136)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct ClientCacheMissResponsePacket { + #[vec_repr(u32)] + #[vec_endianness(var)] + pub missing_blobs: Vec, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/client_cache_status.rs b/crates/proto/src/version/v662/packets/client_cache_status.rs new file mode 100644 index 00000000..20094317 --- /dev/null +++ b/crates/proto/src/version/v662/packets/client_cache_status.rs @@ -0,0 +1,7 @@ +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 129)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct ClientCacheStatusPacket { + pub is_cache_supported: bool, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/client_to_server_handshake.rs b/crates/proto/src/version/v662/packets/client_to_server_handshake.rs new file mode 100644 index 00000000..3ce7bab9 --- /dev/null +++ b/crates/proto/src/version/v662/packets/client_to_server_handshake.rs @@ -0,0 +1,5 @@ +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 4)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct ClientToServerHandshakePacket {} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/code_builder.rs b/crates/proto/src/version/v662/packets/code_builder.rs new file mode 100644 index 00000000..dff09a81 --- /dev/null +++ b/crates/proto/src/version/v662/packets/code_builder.rs @@ -0,0 +1,8 @@ +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 150)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct CodeBuilderPacket { + pub url: String, + pub should_open_code_builder: bool, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/code_builder_source.rs b/crates/proto/src/version/v662/packets/code_builder_source.rs new file mode 100644 index 00000000..f5957f39 --- /dev/null +++ b/crates/proto/src/version/v662/packets/code_builder_source.rs @@ -0,0 +1,10 @@ +use crate::version::v662::enums::{CodeBuilderStorageCategory, CodeBuilderStorageOperation}; +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 178)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct CodeBuilderSourcePacket { + pub operation: CodeBuilderStorageOperation, + pub category: CodeBuilderStorageCategory, + pub value: String, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/command_block_update.rs b/crates/proto/src/version/v662/packets/command_block_update.rs new file mode 100644 index 00000000..d5b1764a --- /dev/null +++ b/crates/proto/src/version/v662/packets/command_block_update.rs @@ -0,0 +1,143 @@ +use crate::version::v662::enums::CommandBlockMode; +use crate::version::v662::types::{ActorRuntimeID, NetworkBlockPosition}; +use bedrockrs_macros::gamepacket; +use bedrockrs_proto_core::error::ProtoCodecError; +use bedrockrs_proto_core::{ProtoCodec, ProtoCodecLE}; +use std::io::Cursor; +use std::mem::size_of; + +#[gamepacket(id = 78)] +#[derive(Clone, Debug)] +pub struct CommandBlockUpdatePacket { + pub is_block: bool, + pub target_runtime_id: Option, // Only if is_block is false + pub block_position: Option, // Only if is_block is true + pub command_block_mode: Option, // Only if is_block is true + pub redstone_mode: Option, // Only if is_block is true + pub is_conditional: Option, // Only if is_block is true + pub command: String, + pub last_output: String, + pub name: String, + pub track_output: bool, + pub tick_delay: u32, + pub should_execute_on_first_tick: bool, +} + +impl ProtoCodec for CommandBlockUpdatePacket { + fn proto_serialize(&self, stream: &mut Vec) -> Result<(), ProtoCodecError> { + ::proto_serialize(&self.is_block, stream)?; + match &self.is_block { + true => { + ::proto_serialize( + &self.target_runtime_id.as_ref().unwrap(), + stream, + )?; + } + false => { + ::proto_serialize( + &self.block_position.as_ref().unwrap(), + stream, + )?; + ::proto_serialize( + &self.command_block_mode.as_ref().unwrap(), + stream, + )?; + ::proto_serialize( + &self.redstone_mode.as_ref().unwrap(), + stream, + )?; + ::proto_serialize( + &self.is_conditional.as_ref().unwrap(), + stream, + )?; + } + } + ::proto_serialize(&self.command, stream)?; + ::proto_serialize(&self.last_output, stream)?; + ::proto_serialize(&self.name, stream)?; + ::proto_serialize(&self.track_output, stream)?; + ::proto_serialize(&self.tick_delay, stream)?; + ::proto_serialize(&self.should_execute_on_first_tick, stream)?; + + Ok(()) + } + + fn proto_deserialize(stream: &mut Cursor<&[u8]>) -> Result { + let is_block = ::proto_deserialize(stream)?; + let (target_runtime_id, block_position, command_block_mode, redstone_mode, is_conditional) = + match &is_block { + true => { + let target_runtime_id = + Some(::proto_deserialize(stream)?); + (target_runtime_id, None, None, None, None) + } + false => { + let block_position = Some( + ::proto_deserialize(stream)?, + ); + let command_block_mode = + Some(::proto_deserialize(stream)?); + let redstone_mode = Some(::proto_deserialize(stream)?); + let is_conditional = Some(::proto_deserialize(stream)?); + ( + None, + block_position, + command_block_mode, + redstone_mode, + is_conditional, + ) + } + }; + + let command = ::proto_deserialize(stream)?; + let last_output = ::proto_deserialize(stream)?; + let name = ::proto_deserialize(stream)?; + let track_output = ::proto_deserialize(stream)?; + let tick_delay = ::proto_deserialize(stream)?; + let should_execute_on_first_tick = ::proto_deserialize(stream)?; + + Ok(Self { + is_block, + target_runtime_id, + block_position, + command_block_mode, + redstone_mode, + is_conditional, + command, + last_output, + name, + track_output, + tick_delay, + should_execute_on_first_tick, + }) + } + + fn get_size_prediction(&self) -> usize { + size_of::() + + match &self.is_block { + true => self + .target_runtime_id + .as_ref() + .unwrap() + .get_size_prediction(), + false => { + self.block_position.as_ref().unwrap().get_size_prediction() + + self + .command_block_mode + .as_ref() + .unwrap() + .get_size_prediction() + + size_of::() + + size_of::() + } + } + + &self.command.get_size_prediction() + + &self.last_output.get_size_prediction() + + &self.name.get_size_prediction() + + size_of::() + + size_of::() + + size_of::() + } +} + +// VERIFY: ProtoCodec impl diff --git a/crates/proto/src/version/v662/packets/command_output.rs b/crates/proto/src/version/v662/packets/command_output.rs new file mode 100644 index 00000000..2c1c1f80 --- /dev/null +++ b/crates/proto/src/version/v662/packets/command_output.rs @@ -0,0 +1,92 @@ +use crate::version::v662::enums::CommandOutputType; +use crate::version::v662::types::CommandOriginData; +use bedrockrs_macros::{gamepacket, ProtoCodec}; +use bedrockrs_proto_core::error::ProtoCodecError; +use bedrockrs_proto_core::{ProtoCodec, ProtoCodecVAR}; +use byteorder::{ReadBytesExt, WriteBytesExt}; +use std::io::{Cursor, Read}; +use std::mem::size_of; + +#[derive(ProtoCodec, Clone, Debug)] +pub struct OutputMessagesEntry { + pub successful: bool, + pub message_id: String, + #[vec_repr(u32)] + #[vec_endianness(var)] + pub parameters: Vec, +} + +#[gamepacket(id = 79)] +#[derive(Clone, Debug)] +pub struct CommandOutputPacket { + pub origin_data: CommandOriginData, + pub output_type: CommandOutputType, + pub success_count: u32, + pub output_messages: Vec, +} + +impl ProtoCodec for CommandOutputPacket { + fn proto_serialize(&self, stream: &mut Vec) -> Result<(), ProtoCodecError> { + let mut output_type_stream: Vec = Vec::new(); + ::proto_serialize( + &self.output_type, + &mut output_type_stream, + )?; + let mut output_type_cursor = Cursor::new(output_type_stream.as_slice()); + + ::proto_serialize(&self.origin_data, stream)?; + stream.write_i8(output_type_cursor.read_i8()?)?; + ::proto_serialize(&self.success_count, stream)?; + ::proto_serialize(&(self.output_messages.len() as u32), stream)?; + for i in &self.output_messages { + ::proto_serialize(i, stream)?; + } + output_type_cursor.read_to_end(stream)?; + + Ok(()) + } + + fn proto_deserialize(stream: &mut Cursor<&[u8]>) -> Result { + let mut output_type_stream: Vec = Vec::new(); + + let origin_data = ::proto_deserialize(stream)?; + output_type_stream.write_i8(stream.read_i8()?)?; + let success_count = ::proto_deserialize(stream)?; + let output_messages = { + let len = ::proto_deserialize(stream)?; + let mut vec = Vec::with_capacity(len.try_into()?); + for _ in 0..len { + vec.push(::proto_deserialize( + stream, + )?); + } + vec + }; + stream.read_to_end(&mut output_type_stream)?; + + let mut output_type_cursor = Cursor::new(output_type_stream.as_slice()); + let output_type = + ::proto_deserialize(&mut output_type_cursor)?; + + Ok(Self { + origin_data, + output_type, + success_count, + output_messages, + }) + } + + fn get_size_prediction(&self) -> usize { + self.origin_data.get_size_prediction() + + self.output_type.get_size_prediction() + + self.success_count.get_size_prediction() + + size_of::() + + self + .output_messages + .iter() + .map(|i| i.get_size_prediction()) + .sum::() + } +} + +// VERIFY: ProtoCodec impl diff --git a/crates/proto/src/version/v662/packets/command_request.rs b/crates/proto/src/version/v662/packets/command_request.rs new file mode 100644 index 00000000..1746ce27 --- /dev/null +++ b/crates/proto/src/version/v662/packets/command_request.rs @@ -0,0 +1,12 @@ +use crate::version::v662::types::CommandOriginData; +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 77)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct CommandRequestPacket { + pub command: String, + pub command_origin: CommandOriginData, + pub is_internal_source: bool, + #[endianness(var)] + pub version: i32, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/completed_using_item.rs b/crates/proto/src/version/v662/packets/completed_using_item.rs new file mode 100644 index 00000000..9ed94095 --- /dev/null +++ b/crates/proto/src/version/v662/packets/completed_using_item.rs @@ -0,0 +1,10 @@ +use crate::version::v662::enums::ItemUseMethod; +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 142)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct CompletedUsingItemPacket { + #[endianness(le)] + pub item_id: u16, + pub item_use_method: ItemUseMethod, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/compressed_biome_definition_list.rs b/crates/proto/src/version/v662/packets/compressed_biome_definition_list.rs new file mode 100644 index 00000000..1866ae38 --- /dev/null +++ b/crates/proto/src/version/v662/packets/compressed_biome_definition_list.rs @@ -0,0 +1,7 @@ +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 301)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct CompressedBiomeDefinitionListPacket { + pub compressed_biome_data: String, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/container_close.rs b/crates/proto/src/version/v662/packets/container_close.rs new file mode 100644 index 00000000..14fb7953 --- /dev/null +++ b/crates/proto/src/version/v662/packets/container_close.rs @@ -0,0 +1,9 @@ +use crate::version::v662::enums::ContainerID; +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 47)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct ContainerClosePacket { + pub container_id: ContainerID, + pub server_initiated_close: bool, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/container_open.rs b/crates/proto/src/version/v662/packets/container_open.rs new file mode 100644 index 00000000..e1ef9769 --- /dev/null +++ b/crates/proto/src/version/v662/packets/container_open.rs @@ -0,0 +1,12 @@ +use crate::version::v662::enums::{ContainerID, ContainerType}; +use crate::version::v662::types::{ActorUniqueID, NetworkBlockPosition}; +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 46)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct ContainerOpenPacket { + pub container_id: ContainerID, + pub container_type: ContainerType, + pub position: NetworkBlockPosition, + pub target_actor_id: ActorUniqueID, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/container_set_data.rs b/crates/proto/src/version/v662/packets/container_set_data.rs new file mode 100644 index 00000000..11f9dbd9 --- /dev/null +++ b/crates/proto/src/version/v662/packets/container_set_data.rs @@ -0,0 +1,12 @@ +use crate::version::v662::enums::ContainerID; +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 51)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct ContainerSetDataPacket { + pub container_id: ContainerID, + #[endianness(var)] + pub id: i32, + #[endianness(var)] + pub value: i32, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/correct_player_move_prediction.rs b/crates/proto/src/version/v662/packets/correct_player_move_prediction.rs new file mode 100644 index 00000000..7e0c0de2 --- /dev/null +++ b/crates/proto/src/version/v662/packets/correct_player_move_prediction.rs @@ -0,0 +1,16 @@ +use crate::version::v662::enums::PredictionType; +use bedrockrs_macros::{gamepacket, ProtoCodec}; +use vek::Vec3; + +#[gamepacket(id = 161)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct CorrectPlayerMovePredictionPacket { + #[endianness(le)] + pub position: Vec3, + #[endianness(le)] + pub velocity: Vec3, + pub on_ground: bool, + #[endianness(var)] + pub tick: u64, + pub prediction_type: PredictionType, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/crafting_data.rs b/crates/proto/src/version/v662/packets/crafting_data.rs new file mode 100644 index 00000000..abe597bc --- /dev/null +++ b/crates/proto/src/version/v662/packets/crafting_data.rs @@ -0,0 +1,20 @@ +use crate::version::v662::types::{ContainerMixDataEntry, CraftingDataEntry, MaterialReducerDataEntry, PotionMixDataEntry}; +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 52)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct CraftingDataPacket { + #[vec_repr(u32)] + #[vec_endianness(var)] + pub crafting_entries: Vec, + #[vec_repr(u32)] + #[vec_endianness(var)] + pub potion_mixes: Vec, + #[vec_repr(u32)] + #[vec_endianness(var)] + pub container_mixes: Vec, + #[vec_repr(u32)] + #[vec_endianness(var)] + pub material_reducers: Vec, + pub clear_recipes: bool, +} diff --git a/crates/proto/src/version/v662/packets/create_photo.rs b/crates/proto/src/version/v662/packets/create_photo.rs new file mode 100644 index 00000000..6bc265be --- /dev/null +++ b/crates/proto/src/version/v662/packets/create_photo.rs @@ -0,0 +1,10 @@ +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 171)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct CreatePhotoPacket { + #[endianness(le)] + pub raw_id: u64, + pub photo_name: String, + pub photo_item_name: String, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/creative_content.rs b/crates/proto/src/version/v662/packets/creative_content.rs new file mode 100644 index 00000000..76317361 --- /dev/null +++ b/crates/proto/src/version/v662/packets/creative_content.rs @@ -0,0 +1,17 @@ +use crate::version::v662::types::NetworkItemInstanceDescriptor; +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[derive(ProtoCodec, Clone, Debug)] +pub struct WriteEntry { + #[endianness(var)] + pub creative_net_id: u32, + pub item_instance: NetworkItemInstanceDescriptor, +} + +#[gamepacket(id = 145)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct CreativeContentPacket { + #[vec_repr(u32)] + #[vec_endianness(var)] + pub write_entries: Vec, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/death_info.rs b/crates/proto/src/version/v662/packets/death_info.rs new file mode 100644 index 00000000..523f045e --- /dev/null +++ b/crates/proto/src/version/v662/packets/death_info.rs @@ -0,0 +1,10 @@ +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 189)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct DeathInfoPacket { + pub death_cause_attack_name: String, + #[vec_repr(u32)] + #[vec_endianness(var)] + pub death_cause_message_list: Vec, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/debug_info.rs b/crates/proto/src/version/v662/packets/debug_info.rs new file mode 100644 index 00000000..7919814b --- /dev/null +++ b/crates/proto/src/version/v662/packets/debug_info.rs @@ -0,0 +1,9 @@ +use crate::version::v662::types::ActorUniqueID; +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 155)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct DebugInfoPacket { + pub actor_id: ActorUniqueID, + pub data: String, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/dimension_data.rs b/crates/proto/src/version/v662/packets/dimension_data.rs new file mode 100644 index 00000000..f7a57738 --- /dev/null +++ b/crates/proto/src/version/v662/packets/dimension_data.rs @@ -0,0 +1,8 @@ +use crate::version::v662::types::DimensionDefinitionGroup; +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 180)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct DimensionDataPacket { + pub dimension_definition_group: DimensionDefinitionGroup, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/disconnect.rs b/crates/proto/src/version/v662/packets/disconnect.rs new file mode 100644 index 00000000..dfa70f83 --- /dev/null +++ b/crates/proto/src/version/v662/packets/disconnect.rs @@ -0,0 +1,47 @@ +use crate::version::v662::enums::ConnectionFailReason; +use bedrockrs_macros::gamepacket; +use bedrockrs_proto_core::error::ProtoCodecError; +use bedrockrs_proto_core::ProtoCodec; +use std::io::Cursor; + +#[gamepacket(id = 5)] +#[derive(Clone, Debug)] +pub struct DisconnectPacket { + pub reason: ConnectionFailReason, + pub message: Option, +} + +impl ProtoCodec for DisconnectPacket { + fn proto_serialize(&self, stream: &mut Vec) -> Result<(), ProtoCodecError> { + self.reason.proto_serialize(stream)?; + + // Normally an optional type is prefixed by a bool indicating if the following type has a value, + // but for the message in the DisconnectPacket it is the other way around, + // indicating if the following value should be skipped + bool::proto_serialize(&self.message.is_none(), stream)?; + + if let Some(ref message) = self.message { + message.proto_serialize(stream)?; + } + + Ok(()) + } + + fn proto_deserialize(stream: &mut Cursor<&[u8]>) -> Result { + let reason = ConnectionFailReason::proto_deserialize(stream)?; + + let skip_message = bool::proto_deserialize(stream)?; + + let message = if !skip_message { + Some(String::proto_deserialize(stream)?) + } else { + None + }; + + Ok(DisconnectPacket { reason, message }) + } + + fn get_size_prediction(&self) -> usize { + self.reason.get_size_prediction() + self.message.get_size_prediction() + } +} diff --git a/crates/proto/src/version/v662/packets/editor_network.rs b/crates/proto/src/version/v662/packets/editor_network.rs new file mode 100644 index 00000000..dffef50e --- /dev/null +++ b/crates/proto/src/version/v662/packets/editor_network.rs @@ -0,0 +1,8 @@ +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 190)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct EditorNetworkPacket { + #[nbt] + pub binary_payload: nbtx::Value, // TODO: NBT Structure +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/edu_uri_resource.rs b/crates/proto/src/version/v662/packets/edu_uri_resource.rs new file mode 100644 index 00000000..48c68a10 --- /dev/null +++ b/crates/proto/src/version/v662/packets/edu_uri_resource.rs @@ -0,0 +1,8 @@ +use crate::version::v662::types::EduSharedUriResource; +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 170)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct EduUriResourcePacket { + pub edu_shared_uri_resource: EduSharedUriResource, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/education_settings.rs b/crates/proto/src/version/v662/packets/education_settings.rs new file mode 100644 index 00000000..986fbd43 --- /dev/null +++ b/crates/proto/src/version/v662/packets/education_settings.rs @@ -0,0 +1,8 @@ +use crate::version::v662::types::EducationLevelSettings; +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 137)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct EducationSettingsPacket { + pub education_level_settings: EducationLevelSettings, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/emote.rs b/crates/proto/src/version/v662/packets/emote.rs new file mode 100644 index 00000000..52fb1f29 --- /dev/null +++ b/crates/proto/src/version/v662/packets/emote.rs @@ -0,0 +1,20 @@ +use crate::version::v662::types::ActorRuntimeID; +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[derive(ProtoCodec, Clone, Debug)] +#[enum_repr(i8)] +#[repr(i8)] +pub enum Flags { + ServerSide = 0x0, + MuteEmoteChat = 0x2, +} + +#[gamepacket(id = 138)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct EmotePacket { + pub actor_runtime_id: ActorRuntimeID, + pub emote_id: String, + pub xuid: String, + pub platform_id: String, + pub flags: Flags, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/emote_list.rs b/crates/proto/src/version/v662/packets/emote_list.rs new file mode 100644 index 00000000..8aec9528 --- /dev/null +++ b/crates/proto/src/version/v662/packets/emote_list.rs @@ -0,0 +1,12 @@ +use crate::version::v662::types::ActorRuntimeID; +use bedrockrs_macros::{gamepacket, ProtoCodec}; +use uuid::Uuid; + +#[gamepacket(id = 152)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct EmoteListPacket { + pub runtime_id: ActorRuntimeID, + #[vec_repr(u32)] + #[vec_endianness(var)] + pub emote_piece_ids: Vec, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/feature_registry.rs b/crates/proto/src/version/v662/packets/feature_registry.rs new file mode 100644 index 00000000..52913c3d --- /dev/null +++ b/crates/proto/src/version/v662/packets/feature_registry.rs @@ -0,0 +1,15 @@ +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[derive(ProtoCodec, Clone, Debug)] +pub struct FeaturesDataListEntry { + pub feature_name: String, + pub binary_json_output: String, +} + +#[gamepacket(id = 191)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct FeatureRegistryPacket { + #[vec_repr(u32)] + #[vec_endianness(var)] + pub features_data_list: Vec, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/filter_text.rs b/crates/proto/src/version/v662/packets/filter_text.rs new file mode 100644 index 00000000..74b22024 --- /dev/null +++ b/crates/proto/src/version/v662/packets/filter_text.rs @@ -0,0 +1,8 @@ +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 163)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct FilterTextPacket { + pub text: String, + pub from_server: bool, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/game_rules_changed.rs b/crates/proto/src/version/v662/packets/game_rules_changed.rs new file mode 100644 index 00000000..b382d383 --- /dev/null +++ b/crates/proto/src/version/v662/packets/game_rules_changed.rs @@ -0,0 +1,8 @@ +use crate::version::v662::types::GameRulesChangedPacketData; +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 72)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct GameRulesChangedPacket { + pub rules_data: GameRulesChangedPacketData, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/game_test_request.rs b/crates/proto/src/version/v662/packets/game_test_request.rs new file mode 100644 index 00000000..9a70f5b0 --- /dev/null +++ b/crates/proto/src/version/v662/packets/game_test_request.rs @@ -0,0 +1,18 @@ +use crate::version::v662::enums::Rotation; +use crate::version::v662::types::BlockPos; +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 194)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct GameTestRequestPacket { + #[endianness(var)] + pub max_tests_per_batch: i32, + #[endianness(var)] + pub repeat_count: i32, + pub rotation: Rotation, + pub stop_on_failure: bool, + pub test_pos: BlockPos, + #[endianness(var)] + pub tests_per_row: i32, + pub test_name: String, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/game_test_results.rs b/crates/proto/src/version/v662/packets/game_test_results.rs new file mode 100644 index 00000000..dea61794 --- /dev/null +++ b/crates/proto/src/version/v662/packets/game_test_results.rs @@ -0,0 +1,9 @@ +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 195)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct GameTestResultsPacket { + pub succeeded: bool, + pub error: String, + pub test_name: String, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/gui_data_pick_item.rs b/crates/proto/src/version/v662/packets/gui_data_pick_item.rs new file mode 100644 index 00000000..2545fc25 --- /dev/null +++ b/crates/proto/src/version/v662/packets/gui_data_pick_item.rs @@ -0,0 +1,10 @@ +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 54)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct GuiDataPickItemPacket { + pub item_name: String, + pub item_effect_name: String, + #[endianness(le)] + pub slot: i32, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/hurt_armor.rs b/crates/proto/src/version/v662/packets/hurt_armor.rs new file mode 100644 index 00000000..358ae325 --- /dev/null +++ b/crates/proto/src/version/v662/packets/hurt_armor.rs @@ -0,0 +1,12 @@ +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 38)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct HurtArmorPacket { + #[endianness(var)] + pub cause: i32, + #[endianness(var)] + pub damage: i32, + #[endianness(var)] + pub armor_slots: u64, +} diff --git a/crates/proto/src/version/v662/packets/interact.rs b/crates/proto/src/version/v662/packets/interact.rs new file mode 100644 index 00000000..43c9c31a --- /dev/null +++ b/crates/proto/src/version/v662/packets/interact.rs @@ -0,0 +1,74 @@ +use crate::version::v662::types::ActorRuntimeID; +use bedrockrs_macros::{gamepacket, ProtoCodec}; +use bedrockrs_proto_core::error::ProtoCodecError; +use bedrockrs_proto_core::ProtoCodec; +use byteorder::{ReadBytesExt, WriteBytesExt}; +use std::io::{Cursor, Read}; + +#[derive(ProtoCodec, Clone, Debug)] +#[enum_repr(i8)] +#[repr(i8)] +pub enum Action { + Invalid = 0, + StopRiding { + #[endianness(le)] + position_x: f32, + #[endianness(le)] + position_y: f32, + #[endianness(le)] + position_z: f32, + } = 3, + InteractUpdate { + #[endianness(le)] + position_x: f32, + #[endianness(le)] + position_y: f32, + #[endianness(le)] + position_z: f32, + } = 4, + NpcOpen = 5, + OpenInventory = 6, +} + +#[gamepacket(id = 33)] +#[derive(Clone, Debug)] +pub struct InteractPacket { + pub action: Action, + pub target_runtime_id: ActorRuntimeID, +} + +impl ProtoCodec for InteractPacket { + fn proto_serialize(&self, stream: &mut Vec) -> Result<(), ProtoCodecError> { + let mut action_stream: Vec = Vec::new(); + ::proto_serialize(&self.action, &mut action_stream)?; + let mut action_cursor = Cursor::new(action_stream.as_slice()); + + stream.write_i8(action_cursor.read_i8()?)?; + ::proto_serialize(&self.target_runtime_id, stream)?; + action_cursor.read_to_end(stream)?; + + Ok(()) + } + + fn proto_deserialize(stream: &mut Cursor<&[u8]>) -> Result { + let mut action_stream: Vec = Vec::new(); + + action_stream.write_i8(stream.read_i8()?)?; + let target_runtime_id = ::proto_deserialize(stream)?; + stream.read_to_end(&mut action_stream)?; + + let mut action_cursor = Cursor::new(action_stream.as_slice()); + let action = ::proto_deserialize(&mut action_cursor)?; + + Ok(Self { + action, + target_runtime_id, + }) + } + + fn get_size_prediction(&self) -> usize { + self.action.get_size_prediction() + self.target_runtime_id.get_size_prediction() + } +} + +// VERIFY: ProtoCodec impl diff --git a/crates/proto/src/version/v662/packets/inventory_content.rs b/crates/proto/src/version/v662/packets/inventory_content.rs new file mode 100644 index 00000000..2ca67ed5 --- /dev/null +++ b/crates/proto/src/version/v662/packets/inventory_content.rs @@ -0,0 +1,12 @@ +use crate::version::v662::types::NetworkItemStackDescriptor; +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 49)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct InventoryContentPacket { + #[endianness(var)] + pub inventory_id: u32, + #[vec_repr(u32)] + #[vec_endianness(var)] + pub slots: Vec, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/inventory_slot.rs b/crates/proto/src/version/v662/packets/inventory_slot.rs new file mode 100644 index 00000000..6d3ad8fd --- /dev/null +++ b/crates/proto/src/version/v662/packets/inventory_slot.rs @@ -0,0 +1,12 @@ +use crate::version::v662::enums::ContainerID; +use crate::version::v662::types::NetworkItemStackDescriptor; +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 50)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct InventorySlotPacket { + pub container_id: ContainerID, + #[endianness(var)] + pub slot: u32, + pub item: NetworkItemStackDescriptor, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/inventory_transaction.rs b/crates/proto/src/version/v662/packets/inventory_transaction.rs new file mode 100644 index 00000000..7f48b491 --- /dev/null +++ b/crates/proto/src/version/v662/packets/inventory_transaction.rs @@ -0,0 +1,23 @@ +use crate::version::v662::enums::ComplexInventoryTransactionType; +use crate::version::v662::types::InventoryTransaction; +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[derive(ProtoCodec, Clone, Debug)] +pub struct LegacySetItemSlotsEntry { + pub container_enum: i8, // TODO: find container enum? + #[vec_repr(u32)] + #[vec_endianness(var)] + pub slot_vector: Vec, // TODO: find slot enum? (i8 is Slot) +} + +#[gamepacket(id = 30)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct InventoryTransactionPacket { + #[endianness(var)] + pub raw_id: i32, + #[vec_repr(u32)] + #[vec_endianness(var)] + pub legacy_set_item_slots: Vec, + pub transaction_type: ComplexInventoryTransactionType, + pub transaction: InventoryTransaction, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/item_component.rs b/crates/proto/src/version/v662/packets/item_component.rs new file mode 100644 index 00000000..a5501f7c --- /dev/null +++ b/crates/proto/src/version/v662/packets/item_component.rs @@ -0,0 +1,18 @@ +use serde::{Deserialize, Serialize}; +use bedrockrs_macros::{gamepacket, ProtoCodec}; +use crate::v662::nbt::ItemComponentDataNBT; + +#[derive(ProtoCodec, Clone, Debug)] +pub struct ItemsEntry { + pub component_item_name: String, + #[nbt] + pub component_data: ItemComponentDataNBT, // TODO: NBT Structure +} + +#[gamepacket(id = 162)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct ItemComponentPacket { + #[vec_repr(u32)] + #[vec_endianness(var)] + pub items: Vec, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/item_stack_request.rs b/crates/proto/src/version/v662/packets/item_stack_request.rs new file mode 100644 index 00000000..909b3381 --- /dev/null +++ b/crates/proto/src/version/v662/packets/item_stack_request.rs @@ -0,0 +1,32 @@ +use crate::version::v662::enums::{ItemStackRequestActionType, TextProcessingEventOrigin}; +use crate::version::v662::types::ItemStackRequestSlotInfo; +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[derive(ProtoCodec, Clone, Debug)] +pub struct ActionsEntry { + pub action_type: ItemStackRequestActionType, + pub amount: i8, + pub source: ItemStackRequestSlotInfo, + pub destination: ItemStackRequestSlotInfo, +} + +#[derive(ProtoCodec, Clone, Debug)] +pub struct RequestsEntry { + #[endianness(var)] + pub client_request_id: u32, + #[vec_repr(u32)] + #[vec_endianness(var)] + pub actions: Vec, + #[vec_repr(u32)] + #[vec_endianness(var)] + pub strings_to_filter: Vec, + pub strings_to_filter_origin: TextProcessingEventOrigin, +} + +#[gamepacket(id = 147)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct ItemStackRequestPacket { + #[vec_repr(u32)] + #[vec_endianness(var)] + pub requests: Vec, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/item_stack_response.rs b/crates/proto/src/version/v662/packets/item_stack_response.rs new file mode 100644 index 00000000..dd283eac --- /dev/null +++ b/crates/proto/src/version/v662/packets/item_stack_response.rs @@ -0,0 +1,10 @@ +use crate::version::v662::types::ItemStackResponseInfo; +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 148)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct ItemStackResponsePacket { + #[vec_repr(u32)] + #[vec_endianness(var)] + pub responses: Vec, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/lab_table.rs b/crates/proto/src/version/v662/packets/lab_table.rs new file mode 100644 index 00000000..19a920a0 --- /dev/null +++ b/crates/proto/src/version/v662/packets/lab_table.rs @@ -0,0 +1,20 @@ +use crate::version::v662::enums::LabTableReactionType; +use crate::version::v662::types::BlockPos; +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[derive(ProtoCodec, Clone, Debug)] +#[enum_repr(i8)] +#[repr(i8)] +pub enum Type { + StartCombine = 0, + StartReaction = 1, + Reset = 2, +} + +#[gamepacket(id = 109)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct LabTablePacket { + pub lab_table_packet_type: Type, + pub position: BlockPos, + pub reaction: LabTableReactionType, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/lectern_update.rs b/crates/proto/src/version/v662/packets/lectern_update.rs new file mode 100644 index 00000000..673819d2 --- /dev/null +++ b/crates/proto/src/version/v662/packets/lectern_update.rs @@ -0,0 +1,10 @@ +use crate::version::v662::types::NetworkBlockPosition; +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 125)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct LecternUpdatePacket { + pub new_page_to_show: i8, + pub total_pages: i8, + pub position_of_lectern_to_update: NetworkBlockPosition, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/legacy_telemetry_event.rs b/crates/proto/src/version/v662/packets/legacy_telemetry_event.rs new file mode 100644 index 00000000..ad6682a4 --- /dev/null +++ b/crates/proto/src/version/v662/packets/legacy_telemetry_event.rs @@ -0,0 +1,208 @@ +use crate::version::v662::enums::{ActorDamageCause, ActorType, InteractionType, POIBlockInteractionType}; +use crate::version::v662::types::ActorUniqueID; +use bedrockrs_macros::{gamepacket, ProtoCodec}; +use bedrockrs_proto_core::error::ProtoCodecError; +use bedrockrs_proto_core::ProtoCodec; +use std::io::{Cursor, Read}; +use varint_rs::{VarintReader, VarintWriter}; + +#[derive(ProtoCodec, Clone, Debug)] +#[enum_repr(i32)] +#[enum_endianness(var)] +#[repr(i32)] +pub enum AgentResult { + ActionFail = 0, + ActionSuccess = 1, + QueryResultFalse = 2, + QueryResultTrue = 3, +} + +#[derive(ProtoCodec, Clone, Debug)] +#[enum_repr(i32)] +#[enum_endianness(var)] +#[repr(i32)] +pub enum Type { + Achievement { + #[endianness(var)] + achievement_id: i32, + } = 0, + Interaction { + interaction_type: InteractionType, + interaction_actor_type: ActorType, + #[endianness(var)] + interaction_actor_variant: i32, + interaction_actor_color: i8, + } = 1, + PortalCreated { + #[endianness(var)] + dimension_id: i32, + } = 2, + PortalUsed { + #[endianness(var)] + source_dimension_id: i32, + #[endianness(var)] + target_dimension_id: i32, + } = 3, + MobKilled { + #[endianness(var)] + instigator_actor_id: i64, + #[endianness(var)] + target_actor_id: i64, + instigator_child_actor_type: ActorType, + damage_source: ActorDamageCause, + #[endianness(var)] + trade_tier: i32, + trader_name: String, + } = 4, + CauldronUsed { + #[endianness(var)] + contents_color: u32, + #[endianness(var)] + contents_type: i32, + #[endianness(var)] + fill_level: i32, + } = 5, + PlayerDied { + #[endianness(var)] + instigator_actor_id: i32, + #[endianness(var)] + instigator_mob_variant: i32, + damage_source: ActorDamageCause, + died_in_raid: bool, + } = 6, + BossKilled { + #[endianness(var)] + boss_actor_id: i64, + #[endianness(var)] + party_size: i32, + boss_type: ActorType, + } = 7, + AgentCommandObsolete { + result: AgentResult, + #[endianness(var)] + result_number: i32, + command_name: String, + result_key: String, + result_string: String, + } = 8, + AgentCreated = 9, + PatternRemovedObsolete = 10, + SlashCommand { + #[endianness(var)] + success_count: i32, + #[endianness(var)] + error_count: i32, + command_name: String, + error_list: String, + } = 11, + #[deprecated] + FishBucketed = 12, + MobBorn { + #[endianness(var)] + baby_entity_type: i32, + #[endianness(var)] + baby_entity_variant: i32, + baby_color: i8, + } = 13, + PetDiedObsolete = 14, + POICauldronUsed { + block_interaction_type: POIBlockInteractionType, + #[endianness(var)] + item_id: i32, + } = 15, + ComposterUsed { + block_interaction_type: POIBlockInteractionType, + #[endianness(var)] + item_id: i32, + } = 16, + BellUsed { + #[endianness(var)] + item_id: i32, + } = 17, + ActorDefinition { + event_name: String, + } = 18, + RaidUpdate { + #[endianness(var)] + current_raid_wave: i32, + #[endianness(var)] + total_raid_waves: i32, + raid_won: bool, + } = 19, + PlayerMovementAnomalyObsolete = 20, + PlayerMovementCorrectedObsolete = 21, + HoneyHarvested = 22, + TargetBlockHit { + #[endianness(var)] + redstone_level: i32, + } = 23, + PiglinBarter { + #[endianness(var)] + item_id: i32, + bartering_with_player: bool, + } = 24, + PlayerWaxedOrUnwaxedCopper { + #[endianness(var)] + block_id: i32, + } = 25, + CodeBuilderRuntimeAction { + runtime_action: String, + } = 26, + CodeBuilderScoreboard { + objective_name: String, + #[endianness(var)] + score: i32, + } = 27, + StriderRiddenInLavaInOverworld = 28, + SneakCloseToSculkSensor = 29, + CarefulRestoration = 30, +} + +#[gamepacket(id = 65)] +#[derive(Clone, Debug)] +pub struct LegacyTelemetryEventPacket { + pub target_actor_id: ActorUniqueID, + pub event_type: Type, + pub use_player_id: i8, +} + +impl ProtoCodec for LegacyTelemetryEventPacket { + fn proto_serialize(&self, stream: &mut Vec) -> Result<(), ProtoCodecError> { + let mut event_type_stream: Vec = Vec::new(); + ::proto_serialize(&self.event_type, &mut event_type_stream)?; + let mut event_type_cursor = Cursor::new(event_type_stream.as_slice()); + + ::proto_serialize(&self.target_actor_id, stream)?; + stream.write_i32_varint(event_type_cursor.read_i32_varint()?)?; + ::proto_serialize(&self.use_player_id, stream)?; + event_type_cursor.read_to_end(stream)?; + + Ok(()) + } + + fn proto_deserialize(stream: &mut Cursor<&[u8]>) -> Result { + let mut event_type_stream: Vec = Vec::new(); + + let target_actor_id = ::proto_deserialize(stream)?; + event_type_stream.write_i32_varint(stream.read_i32_varint()?)?; + let use_player_id = ::proto_deserialize(stream)?; + stream.read_to_end(&mut event_type_stream)?; + + let mut event_type_cursor = Cursor::new(event_type_stream.as_slice()); + let event_type = ::proto_deserialize(&mut event_type_cursor)?; + + Ok(Self { + target_actor_id, + event_type, + use_player_id, + }) + } + + fn get_size_prediction(&self) -> usize { + self.event_type.get_size_prediction() + + self.target_actor_id.get_size_prediction() + + self.use_player_id.get_size_prediction() + } +} + +// VERIFY: ProtoCodec impl diff --git a/crates/proto/src/version/v662/packets/lesson_progress.rs b/crates/proto/src/version/v662/packets/lesson_progress.rs new file mode 100644 index 00000000..d6fe51b7 --- /dev/null +++ b/crates/proto/src/version/v662/packets/lesson_progress.rs @@ -0,0 +1,11 @@ +use crate::version::v662::enums::LessonAction; +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 183)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct LessonProgressPacket { + pub lesson_action: LessonAction, + #[endianness(var)] + pub score: i32, + pub activity_id: String, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/level_chunk.rs b/crates/proto/src/version/v662/packets/level_chunk.rs new file mode 100644 index 00000000..1248baee --- /dev/null +++ b/crates/proto/src/version/v662/packets/level_chunk.rs @@ -0,0 +1,24 @@ +use crate::version::v662::types::ChunkPos; +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[derive(ProtoCodec, Clone, Debug)] +pub struct CacheBlobEntry { + #[endianness(var)] + blob: u64, +} + +#[gamepacket(id = 58)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct LevelChunkPacket { + pub chunk_position: ChunkPos, + #[endianness(var)] + pub dimension_id: i32, + // TODO: sub-chunk count stuff + pub cache_enabled: bool, + #[vec_repr(u32)] + #[vec_endianness(var)] + pub cache_blobs: Vec, + pub serialized_chunk_data: String, +} + +// TODO: this whole thing is terrible \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/level_event.rs b/crates/proto/src/version/v662/packets/level_event.rs new file mode 100644 index 00000000..09bc92f9 --- /dev/null +++ b/crates/proto/src/version/v662/packets/level_event.rs @@ -0,0 +1,13 @@ +use crate::version::v662::enums::LevelEvent; +use bedrockrs_macros::{gamepacket, ProtoCodec}; +use vek::Vec3; + +#[gamepacket(id = 25)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct LevelEventPacket { + pub event_id: LevelEvent, + #[endianness(le)] + pub position: Vec3, + #[endianness(var)] + pub data: i32, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/level_event_generic.rs b/crates/proto/src/version/v662/packets/level_event_generic.rs new file mode 100644 index 00000000..c992255a --- /dev/null +++ b/crates/proto/src/version/v662/packets/level_event_generic.rs @@ -0,0 +1,10 @@ +use crate::version::v662::enums::LevelEvent; +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 124)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct LevelEventGenericPacket { + pub event_id: LevelEvent, + #[nbt] + pub event_data: nbtx::Value, // TODO: NBT Structure +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/level_sound_event.rs b/crates/proto/src/version/v662/packets/level_sound_event.rs new file mode 100644 index 00000000..f19df454 --- /dev/null +++ b/crates/proto/src/version/v662/packets/level_sound_event.rs @@ -0,0 +1,16 @@ +use crate::version::v662::enums::LevelSoundEventType; +use bedrockrs_macros::{gamepacket, ProtoCodec}; +use vek::Vec3; + +#[gamepacket(id = 123)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct LevelSoundEventPacket { + pub event_id: LevelSoundEventType, + #[endianness(le)] + pub position: Vec3, + #[endianness(var)] + pub data: i32, + pub actor_identifier: String, + pub is_baby_mob: bool, + pub is_global: bool, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/level_sound_event_v1.rs b/crates/proto/src/version/v662/packets/level_sound_event_v1.rs new file mode 100644 index 00000000..587adde2 --- /dev/null +++ b/crates/proto/src/version/v662/packets/level_sound_event_v1.rs @@ -0,0 +1,74 @@ +use crate::version::v662::enums::{ActorType, LevelSoundEventType}; +use bedrockrs_macros::gamepacket; +use bedrockrs_proto_core::error::ProtoCodecError; +use bedrockrs_proto_core::{ProtoCodec, ProtoCodecLE, ProtoCodecVAR}; +use byteorder::{ReadBytesExt, WriteBytesExt}; +use std::io::Cursor; +use std::mem::size_of; +use varint_rs::{VarintReader, VarintWriter}; +use vek::Vec3; + +#[gamepacket(id = 24)] +#[derive(Clone, Debug)] +pub struct LevelSoundEventPacketV1 { + pub event_id: LevelSoundEventType, + pub position: Vec3, + pub data: i32, + pub actor_type: ActorType, + pub baby_mob: bool, + pub global: bool, +} + +impl ProtoCodec for LevelSoundEventPacketV1 { + fn proto_serialize(&self, stream: &mut Vec) -> Result<(), ProtoCodecError> { + let mut event_id_stream: Vec = Vec::new(); + LevelSoundEventType::proto_serialize( + &self.event_id, + &mut event_id_stream, + )?; + let mut event_id_cursor = Cursor::new(event_id_stream.as_slice()); + + stream.write_i8(event_id_cursor.read_u32_varint()? as i8)?; + as ProtoCodecLE>::proto_serialize(&self.position, stream)?; + ::proto_serialize(&self.data, stream)?; + ::proto_serialize(&self.actor_type, stream)?; + ::proto_serialize(&self.baby_mob, stream)?; + ::proto_serialize(&self.global, stream)?; + + Ok(()) + } + + fn proto_deserialize(stream: &mut Cursor<&[u8]>) -> Result { + let mut event_id_stream: Vec = Vec::new(); + event_id_stream.write_u32_varint(stream.read_i8()? as u32)?; + let mut event_id_cursor = Cursor::new(event_id_stream.as_slice()); + + let event_id = + LevelSoundEventType::proto_deserialize(&mut event_id_cursor)?; + let position = as ProtoCodecLE>::proto_deserialize(stream)?; + let data = ::proto_deserialize(stream)?; + let actor_type = ::proto_deserialize(stream)?; + let baby_mob = ::proto_deserialize(stream)?; + let global = ::proto_deserialize(stream)?; + + Ok(Self { + event_id, + position, + data, + actor_type, + baby_mob, + global, + }) + } + + fn get_size_prediction(&self) -> usize { + size_of::() + + ProtoCodecLE::get_size_prediction(&self.position) + + ProtoCodecVAR::get_size_prediction(&self.data) + + self.actor_type.get_size_prediction() + + self.baby_mob.get_size_prediction() + + self.global.get_size_prediction() + } +} + +// VERIFY: ProtoCodec impl diff --git a/crates/proto/src/version/v662/packets/level_sound_event_v2.rs b/crates/proto/src/version/v662/packets/level_sound_event_v2.rs new file mode 100644 index 00000000..af27d129 --- /dev/null +++ b/crates/proto/src/version/v662/packets/level_sound_event_v2.rs @@ -0,0 +1,74 @@ +use crate::version::v662::enums::LevelSoundEventType; +use bedrockrs_macros::gamepacket; +use bedrockrs_proto_core::error::ProtoCodecError; +use bedrockrs_proto_core::{ProtoCodec, ProtoCodecLE, ProtoCodecVAR}; +use byteorder::{ReadBytesExt, WriteBytesExt}; +use std::io::Cursor; +use std::mem::size_of; +use varint_rs::{VarintReader, VarintWriter}; +use vek::Vec3; + +#[gamepacket(id = 120)] +#[derive(Clone, Debug)] +pub struct LevelSoundEventPacketV2 { + pub event_id: LevelSoundEventType, + pub position: Vec3, + pub data: i32, + pub actor_identifier: String, + pub baby_mob: bool, + pub global: bool, +} + +impl ProtoCodec for LevelSoundEventPacketV2 { + fn proto_serialize(&self, stream: &mut Vec) -> Result<(), ProtoCodecError> { + let mut event_id_stream: Vec = Vec::new(); + LevelSoundEventType::proto_serialize( + &self.event_id, + &mut event_id_stream, + )?; + let mut event_id_cursor = Cursor::new(event_id_stream.as_slice()); + + stream.write_i8(event_id_cursor.read_u32_varint()? as i8)?; + as ProtoCodecLE>::proto_serialize(&self.position, stream)?; + ::proto_serialize(&self.data, stream)?; + ::proto_serialize(&self.actor_identifier, stream)?; + ::proto_serialize(&self.baby_mob, stream)?; + ::proto_serialize(&self.global, stream)?; + + Ok(()) + } + + fn proto_deserialize(stream: &mut Cursor<&[u8]>) -> Result { + let mut event_id_stream: Vec = Vec::new(); + event_id_stream.write_u32_varint(stream.read_i8()? as u32)?; + let mut event_id_cursor = Cursor::new(event_id_stream.as_slice()); + + let event_id = + LevelSoundEventType::proto_deserialize(&mut event_id_cursor)?; + let position = as ProtoCodecLE>::proto_deserialize(stream)?; + let data = ::proto_deserialize(stream)?; + let actor_identifier = ::proto_deserialize(stream)?; + let baby_mob = ::proto_deserialize(stream)?; + let global = ::proto_deserialize(stream)?; + + Ok(Self { + event_id, + position, + data, + actor_identifier, + baby_mob, + global, + }) + } + + fn get_size_prediction(&self) -> usize { + size_of::() + + ProtoCodecLE::get_size_prediction(&self.position) + + ProtoCodecVAR::get_size_prediction(&self.data) + + self.actor_identifier.get_size_prediction() + + self.baby_mob.get_size_prediction() + + self.global.get_size_prediction() + } +} + +// VERIFY: ProtoCodec impl diff --git a/crates/proto/src/version/v662/packets/login.rs b/crates/proto/src/version/v662/packets/login.rs new file mode 100644 index 00000000..9197849c --- /dev/null +++ b/crates/proto/src/version/v662/packets/login.rs @@ -0,0 +1,9 @@ +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 1)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct LoginPacket { + #[endianness(be)] + pub client_network_version: i32, + pub connection_request: String, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/map_create_locked_copy.rs b/crates/proto/src/version/v662/packets/map_create_locked_copy.rs new file mode 100644 index 00000000..d390323e --- /dev/null +++ b/crates/proto/src/version/v662/packets/map_create_locked_copy.rs @@ -0,0 +1,9 @@ +use crate::version::v662::types::ActorUniqueID; +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 131)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct MapCreateLockedCopyPacket { + pub original_map_id: ActorUniqueID, + pub new_map_id: ActorUniqueID, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/map_info_request.rs b/crates/proto/src/version/v662/packets/map_info_request.rs new file mode 100644 index 00000000..25288205 --- /dev/null +++ b/crates/proto/src/version/v662/packets/map_info_request.rs @@ -0,0 +1,19 @@ +use crate::version::v662::types::ActorUniqueID; +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[derive(ProtoCodec, Clone, Debug)] +pub struct ClientPixelsListEntry { + #[endianness(le)] + pub pixel: u32, + #[endianness(le)] + pub index: u16, +} + +#[gamepacket(id = 68)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct MapInfoRequestPacket { + pub map_unique_id: ActorUniqueID, + #[vec_repr(u32)] + #[vec_endianness(le)] + pub client_pixels_list: Vec, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/mob_armor_equipment.rs b/crates/proto/src/version/v662/packets/mob_armor_equipment.rs new file mode 100644 index 00000000..1a2f020a --- /dev/null +++ b/crates/proto/src/version/v662/packets/mob_armor_equipment.rs @@ -0,0 +1,12 @@ +use crate::version::v662::types::{ActorRuntimeID, NetworkItemStackDescriptor}; +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 32)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct MobArmorEquipmentPacket { + pub target_runtime_id: ActorRuntimeID, + pub head: NetworkItemStackDescriptor, + pub torso: NetworkItemStackDescriptor, + pub legs: NetworkItemStackDescriptor, + pub feet: NetworkItemStackDescriptor, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/mob_effect.rs b/crates/proto/src/version/v662/packets/mob_effect.rs new file mode 100644 index 00000000..179e0ae0 --- /dev/null +++ b/crates/proto/src/version/v662/packets/mob_effect.rs @@ -0,0 +1,28 @@ +use crate::version::v662::types::ActorRuntimeID; +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[derive(ProtoCodec, Clone, Debug)] +#[enum_repr(i8)] +#[repr(i8)] +pub enum Event { + Invalid = 0, + Add = 1, + Update = 2, + Remove = 3, +} + +#[gamepacket(id = 28)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct MobEffectPacket { + pub target_runtime_id: ActorRuntimeID, + pub event_id: Event, + #[endianness(var)] + pub effect_id: i32, + #[endianness(var)] + pub effect_amplifier: i32, + pub show_particles: bool, + #[endianness(var)] + pub effect_duration_ticks: i32, + #[endianness(le)] + pub tick: u64, +} diff --git a/crates/proto/src/version/v662/packets/mob_equipment.rs b/crates/proto/src/version/v662/packets/mob_equipment.rs new file mode 100644 index 00000000..e220a454 --- /dev/null +++ b/crates/proto/src/version/v662/packets/mob_equipment.rs @@ -0,0 +1,13 @@ +use crate::version::v662::enums::ContainerID; +use crate::version::v662::types::{ActorRuntimeID, NetworkItemStackDescriptor}; +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 31)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct MobEquipmentPacket { + pub target_runtime_id: ActorRuntimeID, + pub item: NetworkItemStackDescriptor, + pub slot: i8, + pub selected_slot: i8, + pub container_id: ContainerID, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/mod.rs b/crates/proto/src/version/v662/packets/mod.rs new file mode 100644 index 00000000..8239f848 --- /dev/null +++ b/crates/proto/src/version/v662/packets/mod.rs @@ -0,0 +1,203 @@ +macro_rules! export { + ($name:ident) => { + mod $name; + pub use $name::*; + }; +} + +export!(login); +export!(play_status); +export!(server_to_client_handshake); +export!(client_to_server_handshake); +export!(disconnect); +export!(resource_packs_info); +export!(resource_pack_stack); +export!(resource_pack_client_response); +export!(text); +export!(set_time); +export!(start_game); +export!(add_player); +export!(add_actor); +export!(remove_actor); +export!(add_item_actor); +export!(server_player_post_move_position); +export!(take_item_actor); +export!(move_actor_absolute); +export!(move_player); +export!(passenger_jump); +export!(update_block); +export!(add_painting); +export!(tick_sync); +export!(level_sound_event_v1); +export!(level_event); +export!(block_event); +export!(actor_event); +export!(mob_effect); +export!(update_attributes); +export!(inventory_transaction); +export!(mob_equipment); +export!(mob_armor_equipment); +export!(interact); +export!(block_pick_request); +export!(actor_pick_request); +export!(player_action); +export!(hurt_armor); +export!(set_actor_data); +export!(set_actor_motion); +export!(set_actor_link); +export!(set_health); +export!(set_spawn_position); +export!(animate); +export!(respawn); +export!(container_open); +export!(container_close); +export!(player_hotbar); +export!(inventory_content); +export!(inventory_slot); +export!(container_set_data); +export!(crafting_data); +export!(gui_data_pick_item); +export!(block_actor_data); +export!(player_input); +export!(level_chunk); +export!(set_commands_enabled); +export!(set_difficulty); +export!(change_dimension); +export!(set_player_game_type); +export!(player_list); +export!(simple_event); +export!(legacy_telemetry_event); +export!(spawn_experience_orb); +export!(client_bound_map_item_data); +export!(map_info_request); +export!(request_chunk_radius); +export!(chunk_radius_updated); +export!(game_rules_changed); +export!(camera); +export!(boss_event); +export!(show_credits); +export!(available_commands); +export!(command_request); +export!(command_block_update); +export!(command_output); +export!(update_trade); +export!(update_equip); +export!(resource_pack_data_info); +export!(resource_pack_chunk_data); +export!(resource_pack_chunk_request); +export!(transfer_player); +export!(play_sound); +export!(stop_sound); +export!(set_title); +export!(add_behaviour_tree); +export!(structure_block_update); +export!(show_store_offer); +export!(purchase_receipt); +export!(player_skin); +export!(sub_client_login); +export!(automation_client_connect); +export!(set_last_hurt_by); +export!(book_edit); +export!(npc_request); +export!(photo_transfer); +export!(modal_form_request); +export!(modal_form_response); +export!(server_settings_request); +export!(server_settings_response); +export!(show_profile); +export!(set_default_game_type); +export!(remove_objective); +export!(set_display_objective); +export!(set_score); +export!(lab_table); +export!(update_block_synced); +export!(move_actor_delta); +export!(set_scoreboard_identity); +export!(set_local_player_as_initialized); +export!(update_soft_enum); +export!(network_stack_latency); +export!(spawn_particle_effect); +export!(available_actor_identifiers); +export!(level_sound_event_v2); +export!(network_chunk_publisher_update); +export!(biome_definition_list); +export!(level_sound_event); +export!(level_event_generic); +export!(lectern_update); +export!(client_cache_status); +export!(on_screen_texture_animation); +export!(map_create_locked_copy); +export!(structure_data_request); +export!(structure_data_response); +export!(client_cache_blob_status); +export!(client_cache_miss_response); +export!(education_settings); +export!(emote); +export!(multiplayer_settings); +export!(settings_command); +export!(anvil_damage); +export!(completed_using_item); +export!(network_settings); +export!(player_auth_input); +export!(creative_content); +export!(player_enchant_options); +export!(item_stack_request); +export!(item_stack_response); +export!(player_armor_damage); +export!(code_builder); +export!(update_player_game_type); +export!(emote_list); +export!(position_tracking_db_server_broadcast); +export!(position_tracking_db_client_request); +export!(debug_info); +export!(packet_violation_warning); +export!(motion_prediction_hints); +export!(animate_entity); +export!(camera_shake); +export!(player_fog); +export!(correct_player_move_prediction); +export!(item_component); +export!(filter_text); +export!(client_bound_debug_renderer); +export!(sync_actor_property); +export!(add_volume_entity); +export!(remove_volume_entity); +export!(simulation_type); +export!(npc_dialogue); +export!(edu_uri_resource); +export!(create_photo); +export!(update_sub_chunk_blocks); +export!(sub_chunk); +export!(sub_chunk_request); +export!(player_start_item_cooldown); +export!(script_message); +export!(code_builder_source); +export!(ticking_area_load_status); +export!(dimension_data); +export!(agent_action_event); +export!(change_mob_property); +export!(lesson_progress); +export!(request_ability); +export!(request_permissions); +export!(toast_request); +export!(update_abilities); +export!(update_adventure_settings); +export!(death_info); +export!(editor_network); +export!(feature_registry); +export!(server_stats); +export!(request_network_settings); +export!(game_test_request); +export!(game_test_results); +export!(update_client_input_locks); +export!(camera_presets); +export!(unlocked_recipes); +export!(camera_instruction); +export!(compressed_biome_definition_list); +export!(trim_data); +export!(open_sign); +export!(agent_animation); +export!(refresh_entitlements); +export!(player_toggle_crafter_slot_request); +export!(set_player_inventory_options); +export!(set_hud); diff --git a/crates/proto/src/version/v662/packets/modal_form_request.rs b/crates/proto/src/version/v662/packets/modal_form_request.rs new file mode 100644 index 00000000..2df489e7 --- /dev/null +++ b/crates/proto/src/version/v662/packets/modal_form_request.rs @@ -0,0 +1,9 @@ +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 100)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct ModalFormRequestPacket { + #[endianness(var)] + pub form_id: u32, + pub form_ui_json: String, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/modal_form_response.rs b/crates/proto/src/version/v662/packets/modal_form_response.rs new file mode 100644 index 00000000..0e888a60 --- /dev/null +++ b/crates/proto/src/version/v662/packets/modal_form_response.rs @@ -0,0 +1,11 @@ +use crate::version::v662::enums::ModalFormCancelReason; +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 101)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct ModalFormResponsePacket { + #[endianness(var)] + pub form_id: u32, + pub json_response: Option, + pub form_cancel_reason: Option, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/motion_prediction_hints.rs b/crates/proto/src/version/v662/packets/motion_prediction_hints.rs new file mode 100644 index 00000000..8c633dfc --- /dev/null +++ b/crates/proto/src/version/v662/packets/motion_prediction_hints.rs @@ -0,0 +1,12 @@ +use crate::version::v662::types::ActorRuntimeID; +use bedrockrs_macros::{gamepacket, ProtoCodec}; +use vek::Vec3; + +#[gamepacket(id = 157)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct MotionPredictionHintsPacket { + pub runtime_id: ActorRuntimeID, + #[endianness(le)] + pub motion: Vec3, + pub on_ground: bool, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/move_actor_absolute.rs b/crates/proto/src/version/v662/packets/move_actor_absolute.rs new file mode 100644 index 00000000..347d063c --- /dev/null +++ b/crates/proto/src/version/v662/packets/move_actor_absolute.rs @@ -0,0 +1,8 @@ +use crate::version::v662::types::MoveActorAbsoluteData; +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 18)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct MoveActorAbsolutePacket { + pub move_data: MoveActorAbsoluteData, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/move_actor_delta.rs b/crates/proto/src/version/v662/packets/move_actor_delta.rs new file mode 100644 index 00000000..e3b16302 --- /dev/null +++ b/crates/proto/src/version/v662/packets/move_actor_delta.rs @@ -0,0 +1,8 @@ +use crate::version::v662::types::MoveActorDeltaData; +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 111)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct MoveActorDeltaPacket { + pub move_data: MoveActorDeltaData, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/move_player.rs b/crates/proto/src/version/v662/packets/move_player.rs new file mode 100644 index 00000000..1b2408aa --- /dev/null +++ b/crates/proto/src/version/v662/packets/move_player.rs @@ -0,0 +1,88 @@ +use crate::version::v662::enums::PlayerPositionMode; +use bedrockrs_macros::gamepacket; +use bedrockrs_proto_core::error::ProtoCodecError; +use bedrockrs_proto_core::{ProtoCodec, ProtoCodecLE, ProtoCodecVAR}; +use bedrockrs_shared::actor_runtime_id::ActorRuntimeID; +use byteorder::{ReadBytesExt, WriteBytesExt}; +use std::io::{Cursor, Read}; +use vek::{Vec2, Vec3}; + +#[gamepacket(id = 19)] +#[derive(Clone, Debug)] +pub struct MovePlayerPacket { + pub player_runtime_id: ActorRuntimeID, + pub position: Vec3, + pub rotation: Vec2, + pub y_head_rotation: f32, + pub position_mode: PlayerPositionMode, + pub on_ground: bool, + pub riding_runtime_id: ActorRuntimeID, + pub tick: u64, +} + +impl ProtoCodec for MovePlayerPacket { + fn proto_serialize(&self, stream: &mut Vec) -> Result<(), ProtoCodecError> { + let mut position_mode_stream: Vec = Vec::new(); + PlayerPositionMode::proto_serialize( + &self.position_mode, + &mut position_mode_stream, + )?; + let mut position_mode_cursor = Cursor::new(position_mode_stream.as_slice()); + + ::proto_serialize(&self.player_runtime_id, stream)?; + as ProtoCodecLE>::proto_serialize(&self.position, stream)?; + as ProtoCodecLE>::proto_serialize(&self.rotation, stream)?; + ::proto_serialize(&self.y_head_rotation, stream)?; + stream.write_i8(position_mode_cursor.read_i8()?)?; + ::proto_serialize(&self.on_ground, stream)?; + ::proto_serialize(&self.riding_runtime_id, stream)?; + position_mode_cursor.read_to_end(stream)?; + ::proto_serialize(&self.tick, stream)?; + + Ok(()) + } + + fn proto_deserialize(stream: &mut Cursor<&[u8]>) -> Result { + let mut sub_stream = Vec::::new(); + + let player_runtime_id = ::proto_deserialize(stream)?; + let position = as ProtoCodecLE>::proto_deserialize(stream)?; + let rotation = as ProtoCodecLE>::proto_deserialize(stream)?; + let y_head_rotation = ::proto_deserialize(stream)?; + sub_stream.write_i8(stream.read_i8()?)?; + let on_ground = ::proto_deserialize(stream)?; + let riding_runtime_id = ::proto_deserialize(stream)?; + stream.read_to_end(&mut sub_stream)?; + + let mut sub_cursor = Cursor::new(sub_stream.as_slice()); + let position_mode = + PlayerPositionMode::proto_deserialize( + &mut sub_cursor, + )?; + let tick = ::proto_deserialize(&mut sub_cursor)?; + + Ok(Self { + player_runtime_id, + position, + rotation, + y_head_rotation, + position_mode, + on_ground, + riding_runtime_id, + tick, + }) + } + + fn get_size_prediction(&self) -> usize { + self.player_runtime_id.get_size_prediction() + + ProtoCodecLE::get_size_prediction(&self.position) + + ProtoCodecLE::get_size_prediction(&self.rotation) + + ProtoCodecLE::get_size_prediction(&self.y_head_rotation) + + self.position_mode.get_size_prediction() + + self.on_ground.get_size_prediction() + + self.riding_runtime_id.get_size_prediction() + + ProtoCodecVAR::get_size_prediction(&self.tick) + } +} + +// VERIFY: ProtoCodec impl diff --git a/crates/proto/src/version/v662/packets/multiplayer_settings.rs b/crates/proto/src/version/v662/packets/multiplayer_settings.rs new file mode 100644 index 00000000..72b40285 --- /dev/null +++ b/crates/proto/src/version/v662/packets/multiplayer_settings.rs @@ -0,0 +1,8 @@ +use crate::version::v662::enums::MultiplayerSettingsPacketType; +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 139)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct MultiplayerSettingsPacket { + pub multiplayer_settings_packet_type: MultiplayerSettingsPacketType, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/network_chunk_publisher_update.rs b/crates/proto/src/version/v662/packets/network_chunk_publisher_update.rs new file mode 100644 index 00000000..d3bc6345 --- /dev/null +++ b/crates/proto/src/version/v662/packets/network_chunk_publisher_update.rs @@ -0,0 +1,15 @@ +use crate::version::v662::types::{BlockPos, ChunkPos}; +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 121)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct NetworkChunkPublisherUpdatePacket { + pub new_view_position: BlockPos, + #[endianness(var)] + pub new_view_radius: u32, + #[endianness(le)] + pub server_built_chunks_size: u32, + #[vec_repr(u32)] + #[vec_endianness(var)] + pub server_built_chunks_list: Vec, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/network_settings.rs b/crates/proto/src/version/v662/packets/network_settings.rs new file mode 100644 index 00000000..4110db67 --- /dev/null +++ b/crates/proto/src/version/v662/packets/network_settings.rs @@ -0,0 +1,14 @@ +use crate::version::v662::enums::PacketCompressionAlgorithm; +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 143)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct NetworkSettingsPacket { + #[endianness(le)] + pub compression_threshold: u16, + pub compression_algorithm: PacketCompressionAlgorithm, + pub client_throttle_enabled: bool, + pub client_throttle_threshold: i8, + #[endianness(le)] + pub client_throttle_scalar: f32, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/network_stack_latency.rs b/crates/proto/src/version/v662/packets/network_stack_latency.rs new file mode 100644 index 00000000..57573e67 --- /dev/null +++ b/crates/proto/src/version/v662/packets/network_stack_latency.rs @@ -0,0 +1,9 @@ +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 115)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct NetworkStackLatencyPacket { + #[endianness(le)] + pub creation_time: u64, + pub is_from_server: bool, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/npc_dialogue.rs b/crates/proto/src/version/v662/packets/npc_dialogue.rs new file mode 100644 index 00000000..0b1e9bfc --- /dev/null +++ b/crates/proto/src/version/v662/packets/npc_dialogue.rs @@ -0,0 +1,22 @@ +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[derive(ProtoCodec, Clone, Debug)] +#[enum_repr(i32)] +#[enum_endianness(var)] +#[repr(i32)] +pub enum NpcDialogueActionType { + Open = 0, + Close = 1, +} + +#[gamepacket(id = 169)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct NpcDialoguePacket { + #[endianness(le)] + pub npc_raw_id: u64, + pub npc_dialogue_action_type: NpcDialogueActionType, + pub dialogue: String, + pub scene_name: String, + pub npc_name: String, + pub action_json: String, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/npc_request.rs b/crates/proto/src/version/v662/packets/npc_request.rs new file mode 100644 index 00000000..0920c9e9 --- /dev/null +++ b/crates/proto/src/version/v662/packets/npc_request.rs @@ -0,0 +1,25 @@ +use crate::version::v662::types::ActorRuntimeID; +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[derive(ProtoCodec, Clone, Debug)] +#[enum_repr(i8)] +#[repr(i8)] +pub enum RequestType { + SetActions = 0, + ExecuteAction = 1, + ExecuteClosingCommands = 2, + SetName = 3, + SetSkin = 4, + SetInteractText = 5, + ExecuteOpeningCommands = 6, +} + +#[gamepacket(id = 98)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct NpcRequestPacket { + pub npc_runtime_id: ActorRuntimeID, + pub request_type: RequestType, + pub actions: String, + pub action_index: i8, + pub scene_name: String, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/on_screen_texture_animation.rs b/crates/proto/src/version/v662/packets/on_screen_texture_animation.rs new file mode 100644 index 00000000..1200a758 --- /dev/null +++ b/crates/proto/src/version/v662/packets/on_screen_texture_animation.rs @@ -0,0 +1,8 @@ +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 130)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct OnScreenTextureAnimationPacket { + #[endianness(le)] + pub effect_id: u32, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/open_sign.rs b/crates/proto/src/version/v662/packets/open_sign.rs new file mode 100644 index 00000000..a96166eb --- /dev/null +++ b/crates/proto/src/version/v662/packets/open_sign.rs @@ -0,0 +1,9 @@ +use crate::version::v662::types::NetworkBlockPosition; +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 303)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct OpenSignPacket { + pub pos: NetworkBlockPosition, + pub is_front: bool, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/packet_violation_warning.rs b/crates/proto/src/version/v662/packets/packet_violation_warning.rs new file mode 100644 index 00000000..f953b281 --- /dev/null +++ b/crates/proto/src/version/v662/packets/packet_violation_warning.rs @@ -0,0 +1,11 @@ +use crate::version::v662::enums::{MinecraftPacketIds, PacketViolationSeverity, PacketViolationType}; +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 156)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct PacketViolationWarningPacket { + pub violation_type: PacketViolationType, + pub violation_severity: PacketViolationSeverity, + pub violating_packet_id: MinecraftPacketIds, + pub violation_context: String, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/passenger_jump.rs b/crates/proto/src/version/v662/packets/passenger_jump.rs new file mode 100644 index 00000000..9f8e57df --- /dev/null +++ b/crates/proto/src/version/v662/packets/passenger_jump.rs @@ -0,0 +1,8 @@ +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 20)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct PassengerJumpPacket { + #[endianness(var)] + pub jump_scale: i32, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/photo_transfer.rs b/crates/proto/src/version/v662/packets/photo_transfer.rs new file mode 100644 index 00000000..1e1777d0 --- /dev/null +++ b/crates/proto/src/version/v662/packets/photo_transfer.rs @@ -0,0 +1,15 @@ +use crate::version::v662::enums::PhotoType; +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 99)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct PhotoTransferPacket { + pub photo_name: String, + pub photo_data: String, + pub book_id: String, + pub photo_type: PhotoType, + pub source_type: PhotoType, + #[endianness(le)] + pub owner_id: i64, + pub new_photo_name: String, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/play_sound.rs b/crates/proto/src/version/v662/packets/play_sound.rs new file mode 100644 index 00000000..0ae2d0f4 --- /dev/null +++ b/crates/proto/src/version/v662/packets/play_sound.rs @@ -0,0 +1,13 @@ +use crate::version::v662::types::NetworkBlockPosition; +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 86)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct PlaySoundPacket { + pub name: String, + pub position: NetworkBlockPosition, + #[endianness(le)] + pub volume: f32, + #[endianness(le)] + pub pitch: f32, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/play_status.rs b/crates/proto/src/version/v662/packets/play_status.rs new file mode 100644 index 00000000..42c8c90d --- /dev/null +++ b/crates/proto/src/version/v662/packets/play_status.rs @@ -0,0 +1,8 @@ +use crate::version::v662::enums::PlayStatus; +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 2)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct PlayStatusPacket { + pub status: PlayStatus, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/player_action.rs b/crates/proto/src/version/v662/packets/player_action.rs new file mode 100644 index 00000000..cd548896 --- /dev/null +++ b/crates/proto/src/version/v662/packets/player_action.rs @@ -0,0 +1,16 @@ +use crate::version::v662::enums::PlayerActionType; +use crate::version::v662::types::{ActorRuntimeID, NetworkBlockPosition}; +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 36)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct PlayerActionPacket { + pub player_runtime_id: ActorRuntimeID, + pub action: PlayerActionType, + pub block_position: NetworkBlockPosition, + pub result_pos: NetworkBlockPosition, + #[endianness(var)] + pub face: i32, +} + +// TODO: PlayerActionType is has enum variants, but this packet doesn't serialize them. Might require moving the variants into their specific type \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/player_armor_damage.rs b/crates/proto/src/version/v662/packets/player_armor_damage.rs new file mode 100644 index 00000000..228a756b --- /dev/null +++ b/crates/proto/src/version/v662/packets/player_armor_damage.rs @@ -0,0 +1,65 @@ +use bedrockrs_macros::gamepacket; +use bedrockrs_proto_core::error::ProtoCodecError; +use bedrockrs_proto_core::{ProtoCodec, ProtoCodecVAR}; +use std::io::Cursor; + +pub enum PlayerArmorDamageFlag { + Helmet = 1 << 0, + Chestplate = 1 << 1, + Leggings = 1 << 2, + Boots = 1 << 3, +} + +#[gamepacket(id = 149)] +#[derive(Clone, Debug)] +pub struct PlayerArmorDamagePacket { + pub slot_bitset: i8, + pub damage: [i32; 4], +} + +impl ProtoCodec for PlayerArmorDamagePacket { + fn proto_serialize(&self, stream: &mut Vec) -> Result<(), ProtoCodecError> { + self.slot_bitset.proto_serialize(stream)?; + for i in 0..4 { + let flag = 1 << i; + if (self.slot_bitset & flag) != 0 { + ProtoCodecVAR::proto_serialize(&self.damage[i], stream)?; + } + } + + Ok(()) + } + + fn proto_deserialize(stream: &mut Cursor<&[u8]>) -> Result { + let slot_bitset = i8::proto_deserialize(stream)?; + let damage = { + let mut damage = [0; 4]; + for i in 0..4 { + let flag = 1 << i; + if (slot_bitset & flag) != 0 { + damage[i] = ::proto_deserialize(stream)?; + } + } + damage + }; + + Ok(Self { + slot_bitset, + damage, + }) + } + + fn get_size_prediction(&self) -> usize { + self.slot_bitset.get_size_prediction() + + (0..4) + .filter_map(|i| { + let flag = 1 << i; + if (self.slot_bitset & flag) != 0 { + Some(ProtoCodecVAR::get_size_prediction(&self.damage[i])) + } else { + None + } + }) + .sum::() + } +} diff --git a/crates/proto/src/version/v662/packets/player_auth_input.rs b/crates/proto/src/version/v662/packets/player_auth_input.rs new file mode 100644 index 00000000..ca76e3b8 --- /dev/null +++ b/crates/proto/src/version/v662/packets/player_auth_input.rs @@ -0,0 +1,273 @@ +use crate::version::v662::enums::{ + ClientPlayMode, InputMode, ItemStackRequestActionType, NewInteractionModel, + TextProcessingEventOrigin, +}; +use crate::version::v662::types::{ + ActorUniqueID, ItemStackRequestSlotInfo, PackedItemUseLegacyInventoryTransaction, + PlayerBlockActions, +}; +use bedrockrs_macros::{gamepacket, ProtoCodec}; +use bedrockrs_proto_core::error::ProtoCodecError; +use bedrockrs_proto_core::{ProtoCodec, ProtoCodecLE, ProtoCodecVAR}; +use std::io::Cursor; +use vek::{Vec2, Vec3}; + +#[repr(u64)] +pub enum PlayerAuthInputFlags { + Ascend = 1 << 0, + Descend = 1 << 1, + #[deprecated] + NorthJump = 1 << 2, + JumpDown = 1 << 3, + SprintDown = 1 << 4, + ChangeHeight = 1 << 5, + Jumping = 1 << 6, + AutoJumpingInWater = 1 << 7, + Sneaking = 1 << 8, + SneakDown = 1 << 9, + Up = 1 << 10, + Down = 1 << 11, + Left = 1 << 12, + Right = 1 << 13, + UpLeft = 1 << 14, + UpRight = 1 << 15, + WantUp = 1 << 16, + WantDown = 1 << 17, + WantDownSlow = 1 << 18, + WantUpSlow = 1 << 19, + Sprinting = 1 << 20, + AscendBlock = 1 << 21, + DescendBlock = 1 << 22, + SneakToggleDown = 1 << 23, + PersistSneak = 1 << 24, + StartSprinting = 1 << 25, + StopSprinting = 1 << 26, + StartSneaking = 1 << 27, + StopSneaking = 1 << 28, + StartSwimming = 1 << 29, + StopSwimming = 1 << 30, + StartJumping = 1 << 31, + StartGliding = 1 << 32, + StopGliding = 1 << 33, + PerformItemInteraction = 1 << 34, + PerformBlockActions = 1 << 35, + PerformItemStackRequest = 1 << 36, + HandleTeleport = 1 << 37, + Emoting = 1 << 38, + MissedSwing = 1 << 39, + StartCrawling = 1 << 40, + StopCrawling = 1 << 41, + StartFlying = 1 << 42, + StopFlying = 1 << 43, + ReceivedServerData = 1 << 44, + IsInClientPredictedVehicle = 1 << 45, + PaddleLeft = 1 << 46, + PaddleRight = 1 << 47, +} + +#[derive(ProtoCodec, Clone, Debug)] +pub struct ActionsEntry { + pub action_type: ItemStackRequestActionType, + pub amount: i8, + pub source: ItemStackRequestSlotInfo, + pub destination: ItemStackRequestSlotInfo, +} + +#[derive(ProtoCodec, Clone, Debug)] +pub struct PerformItemStackRequestData { + #[endianness(var)] + pub client_request_id: u32, + #[vec_repr(u32)] + #[vec_endianness(var)] + pub actions: Vec, + #[vec_repr(u32)] + #[vec_endianness(var)] + pub strings_to_filter: Vec, + pub strings_to_filter_origin: TextProcessingEventOrigin, +} + +#[derive(ProtoCodec, Clone, Debug)] +pub struct ClientPredictedVehicleData { + #[endianness(le)] + pub vehicle_rotation: Vec2, + pub client_predicted_vehicle: ActorUniqueID, +} + +#[gamepacket(id = 144)] +#[derive(Clone, Debug)] +pub struct PlayerAuthInputPacket { + pub player_rotation: Vec2, + pub player_position: Vec3, + pub move_vector: Vec3, + pub player_head_rotation: f32, + pub input_data: u64, + pub input_mode: InputMode, + pub play_mode: ClientPlayMode, + pub new_interaction_model: NewInteractionModel, + pub vr_gaze_direction: Option>, // If play_mode == ClientPlayMode::Reality + pub client_tick: u64, + pub velocity: Vec3, + pub item_use_transaction: Option, // If input_data has PlayerAuthInputPacket::InputData::PerformItemInteraction set. + pub item_stack_request: Option, // If input data has PlayerAuthInputPacket::InputData::PerformItemStackRequest set. + pub player_block_actions: Option, // If input data has PlayerAuthInputPacket::InputData::PerformBlockActions set. + pub client_predicted_vehicle: Option, // If input data has PlayerAuthInputPacket::InputData::IsInClientPredictedVehicle set. + pub analog_move_vector: Vec2, +} + +impl ProtoCodec for PlayerAuthInputPacket { + fn proto_serialize(&self, stream: &mut Vec) -> Result<(), ProtoCodecError> { + as ProtoCodecLE>::proto_serialize(&self.player_rotation, stream)?; + as ProtoCodecLE>::proto_serialize(&self.player_position, stream)?; + as ProtoCodecLE>::proto_serialize(&self.move_vector, stream)?; + ::proto_serialize(&self.player_head_rotation, stream)?; + ::proto_serialize(&self.input_data, stream)?; + ::proto_serialize(&self.input_mode, stream)?; + ::proto_serialize(&self.play_mode, stream)?; + ::proto_serialize(&self.new_interaction_model, stream)?; + match &self.play_mode { + ClientPlayMode::Reality => { + as ProtoCodecLE>::proto_serialize( + &self.vr_gaze_direction.as_ref().unwrap(), + stream, + )?; + } + _ => {} + } + ::proto_serialize(&self.client_tick, stream)?; + as ProtoCodecLE>::proto_serialize(&self.velocity, stream)?; + if &self.input_data & PlayerAuthInputFlags::PerformItemInteraction as u64 != 0 { + ::proto_serialize( + &self.item_use_transaction.as_ref().unwrap(), + stream, + )?; + } + if &self.input_data & PlayerAuthInputFlags::PerformItemStackRequest as u64 != 0 { + ::proto_serialize( + &self.item_stack_request.as_ref().unwrap(), + stream, + )?; + } + if &self.input_data & PlayerAuthInputFlags::PerformBlockActions as u64 != 0 { + ::proto_serialize( + &self.player_block_actions.as_ref().unwrap(), + stream, + )?; + } + if &self.input_data & PlayerAuthInputFlags::IsInClientPredictedVehicle as u64 != 0 { + ::proto_serialize( + &self.client_predicted_vehicle.as_ref().unwrap(), + stream, + )?; + } + as ProtoCodecLE>::proto_serialize(&self.analog_move_vector, stream)?; + + Ok(()) + } + + fn proto_deserialize(stream: &mut Cursor<&[u8]>) -> Result { + let player_rotation = as ProtoCodecLE>::proto_deserialize(stream)?; + let player_position = as ProtoCodecLE>::proto_deserialize(stream)?; + let move_vector = as ProtoCodecLE>::proto_deserialize(stream)?; + let player_head_rotation = ::proto_deserialize(stream)?; + let input_data = ::proto_deserialize(stream)?; + let input_mode = ::proto_deserialize(stream)?; + let play_mode = ::proto_deserialize(stream)?; + let new_interaction_model = ::proto_deserialize(stream)?; + let vr_gaze_direction = match &play_mode { + ClientPlayMode::Reality => { + Some( as ProtoCodecLE>::proto_deserialize(stream)?) + } + _ => None, + }; + let client_tick = ::proto_deserialize(stream)?; + let velocity = as ProtoCodecLE>::proto_deserialize(stream)?; + let item_use_transaction = match &input_data + & PlayerAuthInputFlags::PerformItemInteraction as u64 + != 0 + { + true => Some( + ::proto_deserialize(stream)?, + ), + false => None, + }; + let item_stack_request = match &input_data + & PlayerAuthInputFlags::PerformItemStackRequest as u64 + != 0 + { + true => Some(::proto_deserialize(stream)?), + false => None, + }; + let player_block_actions = + match &input_data & PlayerAuthInputFlags::PerformBlockActions as u64 != 0 { + true => Some(::proto_deserialize( + stream, + )?), + false => None, + }; + let client_predicted_vehicle = match &input_data + & PlayerAuthInputFlags::IsInClientPredictedVehicle as u64 + != 0 + { + true => Some(::proto_deserialize(stream)?), + false => None, + }; + let analog_move_vector = as ProtoCodecLE>::proto_deserialize(stream)?; + + Ok(Self { + player_rotation, + player_position, + move_vector, + player_head_rotation, + input_data, + input_mode, + play_mode, + new_interaction_model, + vr_gaze_direction, + client_tick, + velocity, + item_use_transaction, + item_stack_request, + player_block_actions, + client_predicted_vehicle, + analog_move_vector, + }) + } + + fn get_size_prediction(&self) -> usize { + ProtoCodecLE::get_size_prediction(&self.player_rotation) + + ProtoCodecLE::get_size_prediction(&self.player_position) + + ProtoCodecLE::get_size_prediction(&self.move_vector) + + ProtoCodecLE::get_size_prediction(&self.player_head_rotation) + + ProtoCodecVAR::get_size_prediction(&self.input_data) + + self.input_mode.get_size_prediction() + + self.play_mode.get_size_prediction() + + self.new_interaction_model.get_size_prediction() + + match self.play_mode { + ClientPlayMode::Reality => ProtoCodecLE::get_size_prediction(&self.vr_gaze_direction), + _ => 0, + } + + ProtoCodecVAR::get_size_prediction(&self.client_tick) + + ProtoCodecLE::get_size_prediction(&self.velocity) + + match &self.input_data & PlayerAuthInputFlags::PerformItemInteraction as u64 != 0 { + true => self.item_use_transaction.get_size_prediction(), + false => 0, + } + + match &self.input_data & PlayerAuthInputFlags::PerformItemStackRequest as u64 != 0 { + true => self.item_stack_request.get_size_prediction(), + false => 0, + } + + match &self.input_data & PlayerAuthInputFlags::PerformBlockActions as u64 != 0 { + true => self.player_block_actions.get_size_prediction(), + false => 0, + } + + match &self.input_data & PlayerAuthInputFlags::IsInClientPredictedVehicle as u64 + != 0 + { + true => self.client_predicted_vehicle.get_size_prediction(), + false => 0, + } + + ProtoCodecLE::get_size_prediction(&self.analog_move_vector) + } +} + +// VERIFY: ProtoCodec impl diff --git a/crates/proto/src/version/v662/packets/player_enchant_options.rs b/crates/proto/src/version/v662/packets/player_enchant_options.rs new file mode 100644 index 00000000..927b0fed --- /dev/null +++ b/crates/proto/src/version/v662/packets/player_enchant_options.rs @@ -0,0 +1,20 @@ +use crate::version::v662::types::ItemEnchants; +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[derive(ProtoCodec, Clone, Debug)] +pub struct OptionsEntry { + #[endianness(var)] + pub cost: u32, + pub enchants: ItemEnchants, + pub enchant_name: String, + #[endianness(var)] + pub enchant_net_id: u32, +} + +#[gamepacket(id = 146)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct PlayerEnchantOptionsPacket { + #[vec_repr(u32)] + #[vec_endianness(var)] + pub options: Vec, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/player_fog.rs b/crates/proto/src/version/v662/packets/player_fog.rs new file mode 100644 index 00000000..5829a957 --- /dev/null +++ b/crates/proto/src/version/v662/packets/player_fog.rs @@ -0,0 +1,9 @@ +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 160)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct PlayerFogPacket { + #[vec_repr(u32)] + #[vec_endianness(var)] + pub fog_stack: Vec, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/player_hotbar.rs b/crates/proto/src/version/v662/packets/player_hotbar.rs new file mode 100644 index 00000000..f07452e3 --- /dev/null +++ b/crates/proto/src/version/v662/packets/player_hotbar.rs @@ -0,0 +1,11 @@ +use crate::version::v662::enums::ContainerID; +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 48)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct PlayerHotbarPacket { + #[endianness(var)] + pub selected_slot: u32, + pub container_id: ContainerID, + pub should_select_slot: bool, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/player_input.rs b/crates/proto/src/version/v662/packets/player_input.rs new file mode 100644 index 00000000..8b2973dc --- /dev/null +++ b/crates/proto/src/version/v662/packets/player_input.rs @@ -0,0 +1,11 @@ +use bedrockrs_macros::{gamepacket, ProtoCodec}; +use vek::Vec2; + +#[gamepacket(id = 57)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct PlayerInputPacket { + #[endianness(le)] + pub move_vector: Vec2, + pub jumping: bool, + pub sneaking: bool, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/player_list.rs b/crates/proto/src/version/v662/packets/player_list.rs new file mode 100644 index 00000000..b0403152 --- /dev/null +++ b/crates/proto/src/version/v662/packets/player_list.rs @@ -0,0 +1,8 @@ +use crate::version::v662::enums::PlayerListPacketType; +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 63)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct PlayerListPacket { + pub action: PlayerListPacketType, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/player_skin.rs b/crates/proto/src/version/v662/packets/player_skin.rs new file mode 100644 index 00000000..6c81d6ce --- /dev/null +++ b/crates/proto/src/version/v662/packets/player_skin.rs @@ -0,0 +1,13 @@ +use crate::version::v662::types::SerializedSkin; +use bedrockrs_macros::{gamepacket, ProtoCodec}; +use uuid::Uuid; + +#[gamepacket(id = 93)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct PlayerSkinPacket { + pub uuid: Uuid, + pub serialized_skin: SerializedSkin, + pub new_skin_name: String, + pub old_skin_name: String, + pub trusted_marketplace_skin: bool, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/player_start_item_cooldown.rs b/crates/proto/src/version/v662/packets/player_start_item_cooldown.rs new file mode 100644 index 00000000..8dcb749d --- /dev/null +++ b/crates/proto/src/version/v662/packets/player_start_item_cooldown.rs @@ -0,0 +1,9 @@ +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 176)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct PlayerStartItemCooldownPacket { + pub item_category: String, + #[endianness(var)] + pub duration_ticks: i32, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/player_toggle_crafter_slot_request.rs b/crates/proto/src/version/v662/packets/player_toggle_crafter_slot_request.rs new file mode 100644 index 00000000..ecd6c46a --- /dev/null +++ b/crates/proto/src/version/v662/packets/player_toggle_crafter_slot_request.rs @@ -0,0 +1,14 @@ +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 306)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct PlayerToggleCrafterSlotRequestPacket { + #[endianness(le)] + pub pos_x: i32, + #[endianness(le)] + pub pos_y: i32, + #[endianness(le)] + pub pos_z: i32, + pub slot_index: i8, + pub is_disabled: bool, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/position_tracking_db_client_request.rs b/crates/proto/src/version/v662/packets/position_tracking_db_client_request.rs new file mode 100644 index 00000000..afc9acb9 --- /dev/null +++ b/crates/proto/src/version/v662/packets/position_tracking_db_client_request.rs @@ -0,0 +1,16 @@ +use crate::version::v662::types::PositionTrackingId; +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[derive(ProtoCodec, Clone, Debug)] +#[enum_repr(i8)] +#[repr(i8)] +pub enum Action { + Query = 0 +} + +#[gamepacket(id = 154)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct PositionTrackingDBClientRequestPacket { + pub action: Action, + pub id: PositionTrackingId, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/position_tracking_db_server_broadcast.rs b/crates/proto/src/version/v662/packets/position_tracking_db_server_broadcast.rs new file mode 100644 index 00000000..f43c71e4 --- /dev/null +++ b/crates/proto/src/version/v662/packets/position_tracking_db_server_broadcast.rs @@ -0,0 +1,20 @@ +use crate::version::v662::types::PositionTrackingId; +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[derive(ProtoCodec, Clone, Debug)] +#[enum_repr(i8)] +#[repr(i8)] +pub enum Action { + Update = 0, + Destroy = 1, + NotFound = 2, +} + +#[gamepacket(id = 153)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct PositionTrackingDBServerBroadcastPacket { + pub action: Action, + pub id: PositionTrackingId, + #[nbt] + pub position_tracking_data: nbtx::Value, // TODO: NBT Structure +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/purchase_receipt.rs b/crates/proto/src/version/v662/packets/purchase_receipt.rs new file mode 100644 index 00000000..87de1b05 --- /dev/null +++ b/crates/proto/src/version/v662/packets/purchase_receipt.rs @@ -0,0 +1,9 @@ +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 92)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct PurchaseReceiptPacket { + #[vec_repr(u32)] + #[vec_endianness(var)] + pub purchase_receipts: Vec, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/refresh_entitlements.rs b/crates/proto/src/version/v662/packets/refresh_entitlements.rs new file mode 100644 index 00000000..4176090e --- /dev/null +++ b/crates/proto/src/version/v662/packets/refresh_entitlements.rs @@ -0,0 +1,5 @@ +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 305)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct RefreshEntitlementsPacket {} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/remove_actor.rs b/crates/proto/src/version/v662/packets/remove_actor.rs new file mode 100644 index 00000000..f4e2fb6d --- /dev/null +++ b/crates/proto/src/version/v662/packets/remove_actor.rs @@ -0,0 +1,8 @@ +use crate::version::v662::types::ActorUniqueID; +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 14)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct RemoveActorPacket { + pub target_actor_id: ActorUniqueID, +} diff --git a/crates/proto/src/version/v662/packets/remove_objective.rs b/crates/proto/src/version/v662/packets/remove_objective.rs new file mode 100644 index 00000000..fe821832 --- /dev/null +++ b/crates/proto/src/version/v662/packets/remove_objective.rs @@ -0,0 +1,7 @@ +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 106)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct RemoveObjectivePacket { + pub objective_name: String, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/remove_volume_entity.rs b/crates/proto/src/version/v662/packets/remove_volume_entity.rs new file mode 100644 index 00000000..157ba6b7 --- /dev/null +++ b/crates/proto/src/version/v662/packets/remove_volume_entity.rs @@ -0,0 +1,10 @@ +use crate::version::v662::types::EntityNetID; +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 167)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct RemoveVolumeEntityPacket { + pub entity_network_id: EntityNetID, + #[endianness(var)] + pub dimension_type: i32, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/request_ability.rs b/crates/proto/src/version/v662/packets/request_ability.rs new file mode 100644 index 00000000..07d335b1 --- /dev/null +++ b/crates/proto/src/version/v662/packets/request_ability.rs @@ -0,0 +1,28 @@ +use crate::version::v662::enums::AbilitiesIndex; +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[derive(ProtoCodec, Clone, Debug)] +#[enum_repr(i8)] +#[repr(i8)] +pub enum Type { + Unset = 0, + Bool { + variable_value: bool, + #[endianness(le)] + default_value: f32, + } = 1, + Float { + #[endianness(le)] + variable_value: f32, + default_value: bool, + } = 2, +} + +// VERIFY: default_values. They seem to be incorrectly documented. + +#[gamepacket(id = 184)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct RequestAbilityPacket { + pub ability: AbilitiesIndex, + pub value_type: Type, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/request_chunk_radius.rs b/crates/proto/src/version/v662/packets/request_chunk_radius.rs new file mode 100644 index 00000000..86e89761 --- /dev/null +++ b/crates/proto/src/version/v662/packets/request_chunk_radius.rs @@ -0,0 +1,9 @@ +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 69)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct RequestChunkRadiusPacket { + #[endianness(var)] + pub chunk_radius: i32, + pub max_chunk_radius: i8, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/request_network_settings.rs b/crates/proto/src/version/v662/packets/request_network_settings.rs new file mode 100644 index 00000000..cb35f874 --- /dev/null +++ b/crates/proto/src/version/v662/packets/request_network_settings.rs @@ -0,0 +1,8 @@ +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 193)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct RequestNetworkSettingsPacket { + #[endianness(be)] + pub client_network_version: i32, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/request_permissions.rs b/crates/proto/src/version/v662/packets/request_permissions.rs new file mode 100644 index 00000000..dd5d81e4 --- /dev/null +++ b/crates/proto/src/version/v662/packets/request_permissions.rs @@ -0,0 +1,12 @@ +use crate::version::v662::enums::PlayerPermissionLevel; +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 185)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct RequestPermissionsPacket { + #[endianness(le)] + pub target_player_raw_id: i64, + pub player_permission_level: PlayerPermissionLevel, + #[endianness(le)] + pub custom_permission_flags: u16, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/resource_pack_chunk_data.rs b/crates/proto/src/version/v662/packets/resource_pack_chunk_data.rs new file mode 100644 index 00000000..baef8d51 --- /dev/null +++ b/crates/proto/src/version/v662/packets/resource_pack_chunk_data.rs @@ -0,0 +1,12 @@ +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 83)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct ResourcePackChunkDataPacket { + pub resource_name: String, + #[endianness(le)] + pub chunk_id: u32, + #[endianness(le)] + pub byte_offset: u64, + pub chunk_data: String, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/resource_pack_chunk_request.rs b/crates/proto/src/version/v662/packets/resource_pack_chunk_request.rs new file mode 100644 index 00000000..11fa13d1 --- /dev/null +++ b/crates/proto/src/version/v662/packets/resource_pack_chunk_request.rs @@ -0,0 +1,9 @@ +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 84)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct ResourcePackChunkRequestPacket { + pub resource_name: String, + #[endianness(le)] + pub chunk: u32, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/resource_pack_client_response.rs b/crates/proto/src/version/v662/packets/resource_pack_client_response.rs new file mode 100644 index 00000000..420bd712 --- /dev/null +++ b/crates/proto/src/version/v662/packets/resource_pack_client_response.rs @@ -0,0 +1,11 @@ +use crate::version::v662::enums::ResourcePackResponse; +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 8)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct ResourcePackClientResponsePacket { + pub response: ResourcePackResponse, + #[vec_repr(u16)] + #[vec_endianness(le)] + pub downloading_packs: Vec, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/resource_pack_data_info.rs b/crates/proto/src/version/v662/packets/resource_pack_data_info.rs new file mode 100644 index 00000000..c7ce3670 --- /dev/null +++ b/crates/proto/src/version/v662/packets/resource_pack_data_info.rs @@ -0,0 +1,17 @@ +use crate::version::v662::enums::PackType; +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 82)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct ResourcePackDataInfoPacket { + pub resource_name: String, + #[endianness(le)] + pub chunk_size: u32, + #[endianness(le)] + pub chunk_amount: u32, + #[endianness(le)] + pub file_size: u64, + pub file_hash: String, + pub is_premium: bool, + pub pack_type: PackType, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/resource_pack_stack.rs b/crates/proto/src/version/v662/packets/resource_pack_stack.rs new file mode 100644 index 00000000..d72cc053 --- /dev/null +++ b/crates/proto/src/version/v662/packets/resource_pack_stack.rs @@ -0,0 +1,23 @@ +use crate::version::v662::types::{BaseGameVersion, Experiments}; +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[derive(ProtoCodec, Clone, Debug)] +pub struct PackEntry { + pub id: String, + pub version: String, + pub sub_pack_name: String, +} + +#[gamepacket(id = 7)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct ResourcePackStackPacket { + pub texture_pack_required: bool, + #[vec_repr(u32)] + #[vec_endianness(var)] + pub addon_list: Vec, + #[vec_repr(u32)] + #[vec_endianness(var)] + pub texture_pack_list: Vec, + pub base_game_version: BaseGameVersion, + pub experiments: Experiments, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/resource_packs_info.rs b/crates/proto/src/version/v662/packets/resource_packs_info.rs new file mode 100644 index 00000000..d35dd0cb --- /dev/null +++ b/crates/proto/src/version/v662/packets/resource_packs_info.rs @@ -0,0 +1,50 @@ +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[derive(ProtoCodec, Clone, Debug)] +pub struct BehaviourPackEntry { + pub id: String, + pub version: String, + #[endianness(le)] + pub size: u64, + pub content_key: String, + pub sub_pack_name: String, + pub content_identity: String, + pub has_scripts: bool, +} + +#[derive(ProtoCodec, Clone, Debug)] +pub struct ResourcePackEntry { + pub id: String, + pub version: String, + #[endianness(le)] + pub size: u64, + pub content_key: String, + pub sub_pack_name: String, + pub content_identity: String, + pub has_scripts: bool, + pub is_ray_tracing_capable: bool, +} + +#[derive(ProtoCodec, Clone, Debug)] +pub struct CDNUrl { + pub first: String, + pub second: String, +} + +#[gamepacket(id = 6)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct ResourcePacksInfoPacket { + pub resource_pack_required: bool, + pub has_addon_packs: bool, + pub has_scripts: bool, + pub force_server_packs_enabled: bool, + #[vec_repr(u16)] + #[vec_endianness(le)] + pub behaviour_packs: Vec, + #[vec_repr(u16)] + #[vec_endianness(le)] + pub resource_packs: Vec, + #[vec_repr(u32)] + #[vec_endianness(var)] + pub cdn_urls: Vec, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/respawn.rs b/crates/proto/src/version/v662/packets/respawn.rs new file mode 100644 index 00000000..e74f20d6 --- /dev/null +++ b/crates/proto/src/version/v662/packets/respawn.rs @@ -0,0 +1,13 @@ +use crate::version::v662::enums::PlayerRespawnState; +use crate::version::v662::types::ActorRuntimeID; +use bedrockrs_macros::{gamepacket, ProtoCodec}; +use vek::Vec3; + +#[gamepacket(id = 45)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct RespawnPacket { + #[endianness(le)] + pub position: Vec3, + pub state: PlayerRespawnState, + pub player_runtime_id: ActorRuntimeID, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/script_message.rs b/crates/proto/src/version/v662/packets/script_message.rs new file mode 100644 index 00000000..387c73f8 --- /dev/null +++ b/crates/proto/src/version/v662/packets/script_message.rs @@ -0,0 +1,8 @@ +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 177)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct ScriptMessagePacket { + pub message_id: String, + pub message_value: String, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/server_player_post_move_position.rs b/crates/proto/src/version/v662/packets/server_player_post_move_position.rs new file mode 100644 index 00000000..763509a8 --- /dev/null +++ b/crates/proto/src/version/v662/packets/server_player_post_move_position.rs @@ -0,0 +1,9 @@ +use bedrockrs_macros::{gamepacket, ProtoCodec}; +use vek::Vec3; + +#[gamepacket(id = 16)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct ServerPlayerPostMovePositionPacket { + #[endianness(le)] + pub pos: Vec3, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/server_settings_request.rs b/crates/proto/src/version/v662/packets/server_settings_request.rs new file mode 100644 index 00000000..1598f2a5 --- /dev/null +++ b/crates/proto/src/version/v662/packets/server_settings_request.rs @@ -0,0 +1,5 @@ +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 102)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct ServerSettingsRequestPacket {} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/server_settings_response.rs b/crates/proto/src/version/v662/packets/server_settings_response.rs new file mode 100644 index 00000000..2f3ce4b9 --- /dev/null +++ b/crates/proto/src/version/v662/packets/server_settings_response.rs @@ -0,0 +1,11 @@ +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 103)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct ServerSettingsResponsePacket { + #[endianness(var)] + pub form_id: u32, + pub form_ui_json: String, +} + +// TODO: this doesn't seem right. Probably an error in the proto docs. Check gopher or cloudburst \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/server_stats.rs b/crates/proto/src/version/v662/packets/server_stats.rs new file mode 100644 index 00000000..4279457a --- /dev/null +++ b/crates/proto/src/version/v662/packets/server_stats.rs @@ -0,0 +1,10 @@ +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 192)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct ServerStatsPacket { + #[endianness(le)] + pub server_time: f32, + #[endianness(le)] + pub network_time: f32, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/server_to_client_handshake.rs b/crates/proto/src/version/v662/packets/server_to_client_handshake.rs new file mode 100644 index 00000000..0650a1ea --- /dev/null +++ b/crates/proto/src/version/v662/packets/server_to_client_handshake.rs @@ -0,0 +1,9 @@ +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 3)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct ServerToClientHandshakePacket { + pub handshake_web_token: String, +} + +// TODO: more complex stuff \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/set_actor_data.rs b/crates/proto/src/version/v662/packets/set_actor_data.rs new file mode 100644 index 00000000..01d13773 --- /dev/null +++ b/crates/proto/src/version/v662/packets/set_actor_data.rs @@ -0,0 +1,14 @@ +use crate::version::v662::types::{ActorRuntimeID, DataItem, PropertySyncData}; +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 39)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct SetActorDataPacket { + pub target_runtime_id: ActorRuntimeID, + #[vec_repr(u32)] + #[vec_endianness(var)] + pub actor_data: Vec, // VERIFY: vec_repr & vec_endianness + pub synced_properties: PropertySyncData, + #[endianness(var)] + pub tick: u64, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/set_actor_link.rs b/crates/proto/src/version/v662/packets/set_actor_link.rs new file mode 100644 index 00000000..46de73c4 --- /dev/null +++ b/crates/proto/src/version/v662/packets/set_actor_link.rs @@ -0,0 +1,8 @@ +use crate::version::v662::types::ActorLink; +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 41)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct SetActorLinkPacket { + pub link: ActorLink, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/set_actor_motion.rs b/crates/proto/src/version/v662/packets/set_actor_motion.rs new file mode 100644 index 00000000..8886d7d4 --- /dev/null +++ b/crates/proto/src/version/v662/packets/set_actor_motion.rs @@ -0,0 +1,13 @@ +use crate::version::v662::types::ActorRuntimeID; +use bedrockrs_macros::{gamepacket, ProtoCodec}; +use vek::Vec3; + +#[gamepacket(id = 40)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct SetActorMotionPacket { + pub target_runtime_id: ActorRuntimeID, + #[endianness(le)] + pub motion: Vec3, + #[endianness(var)] + pub server_tick: u64, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/set_commands_enabled.rs b/crates/proto/src/version/v662/packets/set_commands_enabled.rs new file mode 100644 index 00000000..8bc85bdf --- /dev/null +++ b/crates/proto/src/version/v662/packets/set_commands_enabled.rs @@ -0,0 +1,7 @@ +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 59)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct SetCommandsEnabledPacket { + pub commands_enabled: bool, +} diff --git a/crates/proto/src/version/v662/packets/set_default_game_type.rs b/crates/proto/src/version/v662/packets/set_default_game_type.rs new file mode 100644 index 00000000..66836608 --- /dev/null +++ b/crates/proto/src/version/v662/packets/set_default_game_type.rs @@ -0,0 +1,8 @@ +use crate::version::v662::enums::GameType; +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 105)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct SetDefaultGameTypePacket { + pub default_game_type: GameType, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/set_difficulty.rs b/crates/proto/src/version/v662/packets/set_difficulty.rs new file mode 100644 index 00000000..97eb83ca --- /dev/null +++ b/crates/proto/src/version/v662/packets/set_difficulty.rs @@ -0,0 +1,8 @@ +use crate::version::v662::enums::Difficulty; +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 60)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct SetDifficultyPacket { + pub difficulty: Difficulty, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/set_display_objective.rs b/crates/proto/src/version/v662/packets/set_display_objective.rs new file mode 100644 index 00000000..0d60da5d --- /dev/null +++ b/crates/proto/src/version/v662/packets/set_display_objective.rs @@ -0,0 +1,12 @@ +use crate::version::v662::enums::ObjectiveSortOrder; +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 107)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct SetDisplayObjectivePacket { + pub display_slot_name: String, + pub objective_name: String, + pub objective_display_name: String, + pub criteria_name: String, + pub sort_order: ObjectiveSortOrder, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/set_health.rs b/crates/proto/src/version/v662/packets/set_health.rs new file mode 100644 index 00000000..f5115f48 --- /dev/null +++ b/crates/proto/src/version/v662/packets/set_health.rs @@ -0,0 +1,8 @@ +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 42)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct SetHealthPacket { + #[endianness(var)] + pub health: i32, +} diff --git a/crates/proto/src/version/v662/packets/set_hud.rs b/crates/proto/src/version/v662/packets/set_hud.rs new file mode 100644 index 00000000..3b141611 --- /dev/null +++ b/crates/proto/src/version/v662/packets/set_hud.rs @@ -0,0 +1,11 @@ +use crate::version::v662::enums::{HudElement, HudVisibility}; +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 308)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct SetHudPacket { + #[vec_repr(u32)] + #[vec_endianness(var)] + pub hud_elements_list: Vec, + pub hud_visibility: HudVisibility, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/set_last_hurt_by.rs b/crates/proto/src/version/v662/packets/set_last_hurt_by.rs new file mode 100644 index 00000000..8d13edae --- /dev/null +++ b/crates/proto/src/version/v662/packets/set_last_hurt_by.rs @@ -0,0 +1,8 @@ +use crate::version::v662::enums::ActorType; +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 96)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct SetLastHurtByPacket { + pub last_hurt_by: ActorType, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/set_local_player_as_initialized.rs b/crates/proto/src/version/v662/packets/set_local_player_as_initialized.rs new file mode 100644 index 00000000..2f914c5b --- /dev/null +++ b/crates/proto/src/version/v662/packets/set_local_player_as_initialized.rs @@ -0,0 +1,8 @@ +use crate::version::v662::types::ActorRuntimeID; +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 113)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct SetLocalPlayerAsInitializedPacket { + pub player_id: ActorRuntimeID, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/set_player_game_type.rs b/crates/proto/src/version/v662/packets/set_player_game_type.rs new file mode 100644 index 00000000..89fd0628 --- /dev/null +++ b/crates/proto/src/version/v662/packets/set_player_game_type.rs @@ -0,0 +1,8 @@ +use crate::version::v662::enums::GameType; +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 62)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct SetPlayerGameTypePacket { + pub player_game_type: GameType, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/set_player_inventory_options.rs b/crates/proto/src/version/v662/packets/set_player_inventory_options.rs new file mode 100644 index 00000000..4942e8b7 --- /dev/null +++ b/crates/proto/src/version/v662/packets/set_player_inventory_options.rs @@ -0,0 +1,12 @@ +use crate::version::v662::enums::{InventoryLayout, InventoryLeftTabIndex, InventoryRightTabIndex}; +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 307)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct SetPlayerInventoryOptionsPacket { + pub left_inventory_tab: InventoryLeftTabIndex, + pub right_inventory_tab: InventoryRightTabIndex, + pub filtering: bool, + pub layout_inv: InventoryLayout, + pub layout_craft: InventoryLayout, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/set_score.rs b/crates/proto/src/version/v662/packets/set_score.rs new file mode 100644 index 00000000..59fcf9ad --- /dev/null +++ b/crates/proto/src/version/v662/packets/set_score.rs @@ -0,0 +1,10 @@ +use crate::version::v662::enums::ScorePacketType; +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 108)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct SetScorePacket { + pub score_packet_type: ScorePacketType, +} + +// TODO: this kinda sucks, might wanna refactor later \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/set_scoreboard_identity.rs b/crates/proto/src/version/v662/packets/set_scoreboard_identity.rs new file mode 100644 index 00000000..69fe7578 --- /dev/null +++ b/crates/proto/src/version/v662/packets/set_scoreboard_identity.rs @@ -0,0 +1,10 @@ +use crate::version::v662::enums::ScoreboardIdentityPacketType; +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 112)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct SetScoreboardIdentityPacket { + pub scoreboard_identity_packet_type: ScoreboardIdentityPacketType, +} + +// TODO: same thing here, scoreboard seem to be a bit janky. Might refactor \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/set_spawn_position.rs b/crates/proto/src/version/v662/packets/set_spawn_position.rs new file mode 100644 index 00000000..91dac9cc --- /dev/null +++ b/crates/proto/src/version/v662/packets/set_spawn_position.rs @@ -0,0 +1,13 @@ +use crate::version::v662::enums::SpawnPositionType; +use crate::version::v662::types::NetworkBlockPosition; +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 43)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct SetSpawnPositionPacket { + pub spawn_position_type: SpawnPositionType, + pub block_position: NetworkBlockPosition, + #[endianness(var)] + pub dimension_type: i32, + pub spawn_block_pos: NetworkBlockPosition, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/set_time.rs b/crates/proto/src/version/v662/packets/set_time.rs new file mode 100644 index 00000000..a08d5f8e --- /dev/null +++ b/crates/proto/src/version/v662/packets/set_time.rs @@ -0,0 +1,8 @@ +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 10)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct SetTimePacket { + #[endianness(var)] + pub time: i32, +} diff --git a/crates/proto/src/version/v662/packets/set_title.rs b/crates/proto/src/version/v662/packets/set_title.rs new file mode 100644 index 00000000..d75cc039 --- /dev/null +++ b/crates/proto/src/version/v662/packets/set_title.rs @@ -0,0 +1,32 @@ +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[derive(ProtoCodec, Clone, Debug)] +#[enum_repr(i32)] +#[enum_endianness(var)] +#[repr(i32)] +pub enum TitleType { + Clear = 0, + Reset = 1, + Title = 2, + Subtitle = 3, + Actionbar = 4, + Times = 5, + TitleTextObject = 6, + SubtitleTextObject = 7, + ActionbarTextObject = 8, +} + +#[gamepacket(id = 88)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct SetTitlePacket { + pub title_type: TitleType, + pub title_text: String, + #[endianness(var)] + pub fade_in_time: i32, + #[endianness(var)] + pub stay_time: i32, + #[endianness(var)] + pub fade_out_time: i32, + pub xuid: String, + pub platform_online_id: String, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/settings_command.rs b/crates/proto/src/version/v662/packets/settings_command.rs new file mode 100644 index 00000000..42ddacf5 --- /dev/null +++ b/crates/proto/src/version/v662/packets/settings_command.rs @@ -0,0 +1,8 @@ +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 140)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct SettingsCommandPacket { + pub command: String, + pub suppress_output: bool, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/show_credits.rs b/crates/proto/src/version/v662/packets/show_credits.rs new file mode 100644 index 00000000..d72e9874 --- /dev/null +++ b/crates/proto/src/version/v662/packets/show_credits.rs @@ -0,0 +1,18 @@ +use crate::version::v662::types::ActorRuntimeID; +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[derive(ProtoCodec, Clone, Debug)] +#[enum_repr(i32)] +#[enum_endianness(var)] +#[repr(i32)] +pub enum CreditsState { + Start = 0, + Finished = 1, +} + +#[gamepacket(id = 75)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct ShowCreditsPacket { + pub player_runtime_id: ActorRuntimeID, + pub credits_state: CreditsState, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/show_profile.rs b/crates/proto/src/version/v662/packets/show_profile.rs new file mode 100644 index 00000000..9b03e532 --- /dev/null +++ b/crates/proto/src/version/v662/packets/show_profile.rs @@ -0,0 +1,7 @@ +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 104)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct ShowProfilePacket { + pub player_xuid: String, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/show_store_offer.rs b/crates/proto/src/version/v662/packets/show_store_offer.rs new file mode 100644 index 00000000..6a2f6e25 --- /dev/null +++ b/crates/proto/src/version/v662/packets/show_store_offer.rs @@ -0,0 +1,9 @@ +use crate::version::v662::enums::ShowStoreOfferRedirectType; +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 91)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct ShowStoreOfferPacket { + pub product_id: String, + pub redirect_type: ShowStoreOfferRedirectType, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/simple_event.rs b/crates/proto/src/version/v662/packets/simple_event.rs new file mode 100644 index 00000000..74f76313 --- /dev/null +++ b/crates/proto/src/version/v662/packets/simple_event.rs @@ -0,0 +1,18 @@ +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[derive(ProtoCodec, Clone, Debug)] +#[enum_repr(u16)] +#[enum_endianness(le)] +#[repr(u16)] +pub enum Subtype { + UninitializedSubtype = 0, + EnableCommands = 1, + DisableCommands = 2, + UnlockWorldTemplateSettings = 3, +} + +#[gamepacket(id = 64)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct SimpleEventPacket { + pub simple_event_type: Subtype, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/simulation_type.rs b/crates/proto/src/version/v662/packets/simulation_type.rs new file mode 100644 index 00000000..f6ae0a58 --- /dev/null +++ b/crates/proto/src/version/v662/packets/simulation_type.rs @@ -0,0 +1,8 @@ +use crate::version::v662::enums::SimulationType; +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 168)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct SimulationTypePacket { + pub sim_type: SimulationType, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/spawn_experience_orb.rs b/crates/proto/src/version/v662/packets/spawn_experience_orb.rs new file mode 100644 index 00000000..30da1f38 --- /dev/null +++ b/crates/proto/src/version/v662/packets/spawn_experience_orb.rs @@ -0,0 +1,11 @@ +use bedrockrs_macros::{gamepacket, ProtoCodec}; +use vek::Vec3; + +#[gamepacket(id = 66)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct SpawnExperienceOrbPacket { + #[endianness(le)] + pub position: Vec3, + #[endianness(var)] + pub xp_value: i32, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/spawn_particle_effect.rs b/crates/proto/src/version/v662/packets/spawn_particle_effect.rs new file mode 100644 index 00000000..885b18fb --- /dev/null +++ b/crates/proto/src/version/v662/packets/spawn_particle_effect.rs @@ -0,0 +1,14 @@ +use crate::version::v662::types::{ActorUniqueID, MolangVariableMap}; +use bedrockrs_macros::{gamepacket, ProtoCodec}; +use vek::Vec3; + +#[gamepacket(id = 118)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct SpawnParticleEffectPacket { + pub dimension_id: i8, + pub actor_id: ActorUniqueID, + #[endianness(le)] + pub position: Vec3, + pub effect_name: String, + pub molang_variables: Option, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/start_game.rs b/crates/proto/src/version/v662/packets/start_game.rs new file mode 100644 index 00000000..8cb68d92 --- /dev/null +++ b/crates/proto/src/version/v662/packets/start_game.rs @@ -0,0 +1,51 @@ +use crate::version::v662::enums::GameType; +use crate::version::v662::types::{ActorRuntimeID, ActorUniqueID, ItemData, LevelSettings, NetworkPermissions, SyncedPlayerMovementSettings}; +use bedrockrs_macros::{gamepacket, ProtoCodec}; +use uuid::Uuid; +use vek::{Vec2, Vec3}; + +#[derive(ProtoCodec, Clone, Debug)] +pub struct BlockProperty { + pub block_name: String, + #[nbt] + pub block_definition: nbtx::Value, // TODO: NBT Structure +} + +#[gamepacket(id = 11)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct StartGamePacket { + pub target_actor_id: ActorUniqueID, + pub target_runtime_id: ActorRuntimeID, + pub actor_game_type: GameType, + #[endianness(le)] + pub position: Vec3, + #[endianness(le)] + pub rotation: Vec2, + pub settings: LevelSettings, + pub level_id: String, + pub level_name: String, + pub template_content_identity: String, + pub is_trial: bool, + pub movement_settings: SyncedPlayerMovementSettings, + #[endianness(le)] + pub current_level_time: u64, + #[endianness(var)] + pub enchantment_seed: i32, + #[vec_repr(u32)] + #[vec_endianness(var)] + pub block_properties: Vec, + #[vec_repr(u32)] + #[vec_endianness(var)] + pub item_list: Vec, + pub multiplayer_correlation_id: String, + pub enable_item_stack_net_manager: bool, + pub server_version: String, + #[nbt] + pub player_property_data: nbtx::Value, // TODO: NBT Structure, + #[endianness(le)] + pub server_block_type_registry_checksum: u64, + pub world_template_id: Uuid, + pub server_enabled_client_side_generation: bool, + pub block_network_ids_are_hashes: bool, + pub network_permissions: NetworkPermissions, +} diff --git a/crates/proto/src/version/v662/packets/stop_sound.rs b/crates/proto/src/version/v662/packets/stop_sound.rs new file mode 100644 index 00000000..0479f354 --- /dev/null +++ b/crates/proto/src/version/v662/packets/stop_sound.rs @@ -0,0 +1,8 @@ +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 87)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct StopSoundPacket { + pub sound_name: String, + pub stop_all_sounds: bool, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/structure_block_update.rs b/crates/proto/src/version/v662/packets/structure_block_update.rs new file mode 100644 index 00000000..0c2b1fd6 --- /dev/null +++ b/crates/proto/src/version/v662/packets/structure_block_update.rs @@ -0,0 +1,11 @@ +use crate::version::v662::types::{NetworkBlockPosition, StructureEditorData}; +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 90)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct StructureBlockUpdatePacket { + pub block_position: NetworkBlockPosition, + pub structure_data: StructureEditorData, + pub trigger: bool, + pub is_waterlogged: bool, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/structure_data_request.rs b/crates/proto/src/version/v662/packets/structure_data_request.rs new file mode 100644 index 00000000..03b51928 --- /dev/null +++ b/crates/proto/src/version/v662/packets/structure_data_request.rs @@ -0,0 +1,12 @@ +use crate::version::v662::enums::StructureTemplateRequestOperation; +use crate::version::v662::types::{NetworkBlockPosition, StructureSettings}; +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 132)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct StructureDataRequestPacket { + pub structure_name: String, + pub structure_position: NetworkBlockPosition, + pub structure_settings: StructureSettings, + pub requested_operation: StructureTemplateRequestOperation, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/structure_data_response.rs b/crates/proto/src/version/v662/packets/structure_data_response.rs new file mode 100644 index 00000000..59dba00d --- /dev/null +++ b/crates/proto/src/version/v662/packets/structure_data_response.rs @@ -0,0 +1,13 @@ +use crate::version::v662::enums::StructureTemplateResponseType; +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 133)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct StructureDataResponsePacket { + pub structure_name: String, + #[nbt] + pub structure_nbt: Option, // TODO: NBT Structure + pub response_type: StructureTemplateResponseType, +} + +// VERIFY: If this actually works \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/sub_chunk.rs b/crates/proto/src/version/v662/packets/sub_chunk.rs new file mode 100644 index 00000000..3b83726e --- /dev/null +++ b/crates/proto/src/version/v662/packets/sub_chunk.rs @@ -0,0 +1,180 @@ +use crate::version::v662::types::{SubChunkPos, SubChunkPosOffset}; +use bedrockrs_macros::{gamepacket, ProtoCodec}; +use bedrockrs_proto_core::error::ProtoCodecError; +use bedrockrs_proto_core::{ProtoCodec, ProtoCodecLE, ProtoCodecVAR}; +use std::cmp::PartialEq; +use std::io::Cursor; +use std::mem::size_of; + +#[derive(ProtoCodec, Clone, Debug, PartialEq)] +#[enum_repr(i8)] +#[repr(i8)] +pub enum HeightMapDataType { + NoData = 0, + HasData = 1, + AllTooHigh = 2, + AllTooLow = 3, +} + +#[derive(ProtoCodec, Clone, Debug, PartialEq)] +#[enum_repr(i8)] +#[repr(i8)] +pub enum SubChunkRequestResult { + Undefined = 0, + Success = 1, + LevelChunkDoesntExist = 2, + WrongDimension = 3, + PlayerDoesntExist = 4, + IndexOutOfBounds = 5, + SuccessAllAir = 6, +} + +#[derive(Clone, Debug)] +pub struct SubChunkDataEntry { + pub sub_chunk_pos_offset: SubChunkPosOffset, + pub sub_chunk_request_result: SubChunkRequestResult, + pub serialized_sub_chunk: Option, // If sub_chunk_request_result == SuccessAllAir, or cache_enabled == false + pub height_map_data_type: HeightMapDataType, + pub sub_chunk_height_map: Option<[[i8; 16]; 16]>, // If height_map_data_type == HasData (vec sizes are i8) + pub blob_id: Option, // If cache_enabled == true +} + +#[gamepacket(id = 174)] +#[derive(Clone, Debug)] +pub struct SubChunkPacket { + pub cache_enabled: bool, + pub dimension_type: i32, + pub center_pos: SubChunkPos, + pub sub_chunk_data: Vec, +} + +impl ProtoCodec for SubChunkPacket { + fn proto_serialize(&self, stream: &mut Vec) -> Result<(), ProtoCodecError> { + self.cache_enabled.proto_serialize(stream)?; + ::proto_serialize(&self.dimension_type, stream)?; + self.center_pos.proto_serialize(stream)?; + ::proto_serialize(&self.sub_chunk_data.len().try_into()?, stream)?; + for i in &self.sub_chunk_data { + i.sub_chunk_pos_offset.proto_serialize(stream)?; + i.sub_chunk_request_result.proto_serialize(stream)?; + if i.sub_chunk_request_result == SubChunkRequestResult::SuccessAllAir + || !self.cache_enabled + { + i.serialized_sub_chunk + .as_ref() + .unwrap() + .proto_serialize(stream)?; + } + i.height_map_data_type.proto_serialize(stream)?; + if i.height_map_data_type == HeightMapDataType::HasData { + let height_map = i.sub_chunk_height_map.as_ref().unwrap(); + for x in height_map { + for y in x { + y.proto_serialize(stream)?; + } + } + } + if self.cache_enabled { + ::proto_serialize(&i.blob_id.as_ref().unwrap(), stream)?; + } + } + + Ok(()) + } + + fn proto_deserialize(stream: &mut Cursor<&[u8]>) -> Result { + let cache_enabled = bool::proto_deserialize(stream)?; + let dimension_type = ProtoCodecVAR::proto_deserialize(stream)?; + let center_pos = SubChunkPos::proto_deserialize(stream)?; + let sub_chunk_data = { + let len = ::proto_deserialize(stream)?; + let mut vec = Vec::with_capacity(len.try_into()?); + for _ in 0..len { + let sub_chunk_pos_offset = SubChunkPosOffset::proto_deserialize(stream)?; + let sub_chunk_request_result = SubChunkRequestResult::proto_deserialize(stream)?; + let serialized_sub_chunk = match sub_chunk_request_result + == SubChunkRequestResult::SuccessAllAir + || cache_enabled + { + true => Some(String::proto_deserialize(stream)?), + false => None, + }; + let height_map_data_type = HeightMapDataType::proto_deserialize(stream)?; + let sub_chunk_height_map = + match height_map_data_type == HeightMapDataType::HasData { + true => { + let mut height_map: [[i8; 16]; 16] = [[0; 16]; 16]; + for x in 0..16 { + for y in 0..16 { + height_map[x][y] = i8::proto_deserialize(stream)?; + } + } + + Some(height_map) + } + false => None, + }; + let blob_id = match cache_enabled { + true => Some(ProtoCodecLE::proto_deserialize(stream)?), + false => None, + }; + + vec.push(SubChunkDataEntry { + sub_chunk_pos_offset, + sub_chunk_request_result, + serialized_sub_chunk, + height_map_data_type, + sub_chunk_height_map, + blob_id, + }) + } + vec + }; + + Ok(Self { + cache_enabled, + dimension_type, + center_pos, + sub_chunk_data, + }) + } + + fn get_size_prediction(&self) -> usize { + self.cache_enabled.get_size_prediction() + + ::get_size_prediction(&self.dimension_type) + + self.center_pos.get_size_prediction() + + size_of::() + + self + .sub_chunk_data + .iter() + .map(|i| { + i.sub_chunk_pos_offset.get_size_prediction() + + i.sub_chunk_request_result.get_size_prediction() + + match i.sub_chunk_request_result == SubChunkRequestResult::SuccessAllAir + || self.cache_enabled + { + true => i + .serialized_sub_chunk + .as_ref() + .unwrap() + .get_size_prediction(), + false => 0, + } + + i.height_map_data_type.get_size_prediction() + + match i.height_map_data_type == HeightMapDataType::HasData { + true => { + let height_map = i.sub_chunk_height_map.as_ref().unwrap(); + height_map.len() * height_map[0].len() * size_of::() + } + false => 0, + } + + match self.cache_enabled { + true => size_of::(), + false => 0, + } + }) + .sum::() + } +} + +// VERIFY: ProtoCodec impl diff --git a/crates/proto/src/version/v662/packets/sub_chunk_request.rs b/crates/proto/src/version/v662/packets/sub_chunk_request.rs new file mode 100644 index 00000000..1ee0ea0b --- /dev/null +++ b/crates/proto/src/version/v662/packets/sub_chunk_request.rs @@ -0,0 +1,14 @@ +use crate::version::v662::types::SubChunkPos; +use crate::version::v662::types::SubChunkPosOffset; +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 175)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct SubChunkRequestPacket { + #[endianness(var)] + pub dimension_type: i32, + pub center_pos: SubChunkPos, + #[vec_repr(u32)] + #[vec_endianness(le)] + pub sub_chunk_pos_offsets: Vec, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/sub_client_login.rs b/crates/proto/src/version/v662/packets/sub_client_login.rs new file mode 100644 index 00000000..8215804c --- /dev/null +++ b/crates/proto/src/version/v662/packets/sub_client_login.rs @@ -0,0 +1,7 @@ +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 94)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct SubClientLoginPacket { + pub connection_request: String, // TODO: SubClientConnectionRequest diagram, not sure. +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/sync_actor_property.rs b/crates/proto/src/version/v662/packets/sync_actor_property.rs new file mode 100644 index 00000000..9b3fccb9 --- /dev/null +++ b/crates/proto/src/version/v662/packets/sync_actor_property.rs @@ -0,0 +1,8 @@ +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 165)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct SyncActorPropertyPacket { + #[nbt] + pub property_data: nbtx::Value, // TODO: NBT Structure +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/take_item_actor.rs b/crates/proto/src/version/v662/packets/take_item_actor.rs new file mode 100644 index 00000000..c20e436f --- /dev/null +++ b/crates/proto/src/version/v662/packets/take_item_actor.rs @@ -0,0 +1,9 @@ +use bedrockrs_macros::{gamepacket, ProtoCodec}; +use bedrockrs_shared::actor_runtime_id::ActorRuntimeID; + +#[gamepacket(id = 17)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct TakeItemActorPacket { + pub item_runtime_id: ActorRuntimeID, + pub actor_runtime_id: ActorRuntimeID, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/text.rs b/crates/proto/src/version/v662/packets/text.rs new file mode 100644 index 00000000..74c6e1e4 --- /dev/null +++ b/crates/proto/src/version/v662/packets/text.rs @@ -0,0 +1,59 @@ +use crate::version::v662::enums::TextPacketType; +use bedrockrs_macros::gamepacket; +use bedrockrs_proto_core::error::ProtoCodecError; +use bedrockrs_proto_core::ProtoCodec; +use byteorder::{ReadBytesExt, WriteBytesExt}; +use std::io::{Cursor, Read}; + +#[gamepacket(id = 9)] +#[derive(Clone, Debug)] +pub struct TextPacket { + pub message_type: TextPacketType, + pub localize: bool, + pub sender_xuid: String, + pub platform_id: String, +} + +impl ProtoCodec for TextPacket { + fn proto_serialize(&self, stream: &mut Vec) -> Result<(), ProtoCodecError> { + let mut message_type_stream: Vec = Vec::new(); + TextPacketType::proto_serialize(&self.message_type, &mut message_type_stream)?; + let mut message_type_cursor = Cursor::new(message_type_stream.as_slice()); + + stream.write_i8(message_type_cursor.read_i8()?)?; + bool::proto_serialize(&self.localize, stream)?; + message_type_cursor.read_to_end(stream)?; + String::proto_serialize(&self.sender_xuid, stream)?; + String::proto_serialize(&self.platform_id, stream)?; + + Ok(()) + } + + fn proto_deserialize(stream: &mut Cursor<&[u8]>) -> Result { + let mut sub_stream: Vec = Vec::new(); + + sub_stream.write_i8(stream.read_i8()?)?; + let localize = bool::proto_deserialize(stream)?; + stream.read_to_end(&mut sub_stream)?; + let mut sub_cursor = Cursor::new(sub_stream.as_slice()); + let message_type = TextPacketType::proto_deserialize(&mut sub_cursor)?; + let sender_xuid = String::proto_deserialize(&mut sub_cursor)?; + let platform_id = String::proto_deserialize(&mut sub_cursor)?; + + Ok(Self { + message_type, + localize, + sender_xuid, + platform_id, + }) + } + + fn get_size_prediction(&self) -> usize { + self.message_type.get_size_prediction() + + self.localize.get_size_prediction() + + self.sender_xuid.get_size_prediction() + + self.platform_id.get_size_prediction() + } +} + +// VERIFY: ProtoCodec impl diff --git a/crates/proto/src/version/v662/packets/tick_sync.rs b/crates/proto/src/version/v662/packets/tick_sync.rs new file mode 100644 index 00000000..0dbc0384 --- /dev/null +++ b/crates/proto/src/version/v662/packets/tick_sync.rs @@ -0,0 +1,10 @@ +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 23)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct TickSyncPacket { + #[endianness(le)] + pub client_request_timestamp: i64, + #[endianness(le)] + pub server_response_timestamp: i64, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/ticking_area_load_status.rs b/crates/proto/src/version/v662/packets/ticking_area_load_status.rs new file mode 100644 index 00000000..1da29b35 --- /dev/null +++ b/crates/proto/src/version/v662/packets/ticking_area_load_status.rs @@ -0,0 +1,7 @@ +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 179)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct TickingAreaLoadStatusPacket { + pub waiting_for_preload: bool, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/toast_request.rs b/crates/proto/src/version/v662/packets/toast_request.rs new file mode 100644 index 00000000..55a5df2d --- /dev/null +++ b/crates/proto/src/version/v662/packets/toast_request.rs @@ -0,0 +1,8 @@ +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 186)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct ToastRequestPacket { + pub title: String, + pub content: String, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/transfer_player.rs b/crates/proto/src/version/v662/packets/transfer_player.rs new file mode 100644 index 00000000..928dfe32 --- /dev/null +++ b/crates/proto/src/version/v662/packets/transfer_player.rs @@ -0,0 +1,9 @@ +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 85)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct TransferPlayerPacket { + pub server_address: String, + #[endianness(le)] + pub server_port: u16, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/trim_data.rs b/crates/proto/src/version/v662/packets/trim_data.rs new file mode 100644 index 00000000..cba5d2af --- /dev/null +++ b/crates/proto/src/version/v662/packets/trim_data.rs @@ -0,0 +1,25 @@ +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[derive(ProtoCodec, Clone, Debug)] +pub struct TrimPattern { + pub item_name: String, + pub pattern_id: String, +} + +#[derive(ProtoCodec, Clone, Debug)] +pub struct TrimMaterial { + pub material_id: String, + pub color: String, + pub item_name: String, +} + +#[gamepacket(id = 302)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct TrimDataPacket { + #[vec_repr(u32)] + #[vec_endianness(var)] + pub trim_pattern_list: Vec, + #[vec_repr(u32)] + #[vec_endianness(var)] + pub trim_material_list: Vec, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/unlocked_recipes.rs b/crates/proto/src/version/v662/packets/unlocked_recipes.rs new file mode 100644 index 00000000..f81c53d3 --- /dev/null +++ b/crates/proto/src/version/v662/packets/unlocked_recipes.rs @@ -0,0 +1,11 @@ +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 199)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct UnlockedRecipesPacket { + #[endianness(le)] + pub packet_type: u32, + #[vec_repr(u32)] + #[vec_endianness(var)] + pub unlocked_recipes_list: Vec, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/update_abilities.rs b/crates/proto/src/version/v662/packets/update_abilities.rs new file mode 100644 index 00000000..8aa64d1a --- /dev/null +++ b/crates/proto/src/version/v662/packets/update_abilities.rs @@ -0,0 +1,8 @@ +use crate::version::v662::types::SerializedAbilitiesData; +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 187)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct UpdateAbilitiesPacket { + pub data: SerializedAbilitiesData, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/update_adventure_settings.rs b/crates/proto/src/version/v662/packets/update_adventure_settings.rs new file mode 100644 index 00000000..c97f8788 --- /dev/null +++ b/crates/proto/src/version/v662/packets/update_adventure_settings.rs @@ -0,0 +1,8 @@ +use crate::version::v662::types::AdventureSettings; +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 188)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct UpdateAdventureSettingsPacket { + pub adventure_settings: AdventureSettings, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/update_attributes.rs b/crates/proto/src/version/v662/packets/update_attributes.rs new file mode 100644 index 00000000..7434248c --- /dev/null +++ b/crates/proto/src/version/v662/packets/update_attributes.rs @@ -0,0 +1,41 @@ +use crate::version::v662::enums::{AttributeModifierOperation, AttributeOperands}; +use crate::version::v662::types::ActorRuntimeID; +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[derive(ProtoCodec, Clone, Debug)] +pub struct AttributeModifier { + pub id: String, + pub name: String, + #[endianness(le)] + pub amount: f32, + pub operation: AttributeModifierOperation, + pub operand: AttributeOperands, + pub is_serializable: bool, +} + +#[derive(ProtoCodec, Clone, Debug)] +pub struct AttributeData { + #[endianness(le)] + pub min_value: f32, + #[endianness(le)] + pub max_value: f32, + #[endianness(le)] + pub current_value: f32, + #[endianness(le)] + pub default_value: f32, + pub attribute_name: String, + #[vec_repr(u32)] + #[vec_endianness(var)] + pub attribute_modifiers: Vec, +} + +#[gamepacket(id = 29)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct UpdateAttributesPacket { + pub target_runtime_id: ActorRuntimeID, + #[vec_repr(u32)] + #[vec_endianness(var)] + pub attribute_list: Vec, + #[endianness(var)] + pub ticks_since_sim_started: u64, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/update_block.rs b/crates/proto/src/version/v662/packets/update_block.rs new file mode 100644 index 00000000..9fd1472a --- /dev/null +++ b/crates/proto/src/version/v662/packets/update_block.rs @@ -0,0 +1,14 @@ +use crate::version::v662::types::NetworkBlockPosition; +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 21)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct UpdateBlockPacket { + pub block_position: NetworkBlockPosition, + #[endianness(var)] + pub block_runtime_id: u32, + #[endianness(var)] + pub flags: u32, + #[endianness(var)] + pub layer: u32, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/update_block_synced.rs b/crates/proto/src/version/v662/packets/update_block_synced.rs new file mode 100644 index 00000000..719f424b --- /dev/null +++ b/crates/proto/src/version/v662/packets/update_block_synced.rs @@ -0,0 +1,18 @@ +use crate::version::v662::enums::ActorBlockSyncMessageID; +use crate::version::v662::types::NetworkBlockPosition; +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 110)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct UpdateBlockSyncedPacket { + pub block_position: NetworkBlockPosition, + #[endianness(var)] + pub block_runtime_id: u32, + #[endianness(var)] + pub flags: u32, + #[endianness(var)] + pub later: u32, + #[endianness(var)] + pub unique_actor_id: u64, + pub actor_sync_message: ActorBlockSyncMessageID, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/update_client_input_locks.rs b/crates/proto/src/version/v662/packets/update_client_input_locks.rs new file mode 100644 index 00000000..87651741 --- /dev/null +++ b/crates/proto/src/version/v662/packets/update_client_input_locks.rs @@ -0,0 +1,11 @@ +use bedrockrs_macros::{gamepacket, ProtoCodec}; +use vek::Vec3; + +#[gamepacket(id = 196)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct UpdateClientInputLocksPacket { + #[endianness(var)] + pub input_lock_component_data: i32, + #[endianness(le)] + pub server_pos: Vec3, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/update_equip.rs b/crates/proto/src/version/v662/packets/update_equip.rs new file mode 100644 index 00000000..dd563113 --- /dev/null +++ b/crates/proto/src/version/v662/packets/update_equip.rs @@ -0,0 +1,15 @@ +use crate::version::v662::enums::{ContainerID, ContainerType}; +use crate::version::v662::types::ActorUniqueID; +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 81)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct UpdateEquipPacket { + pub container_id: ContainerID, + pub container_type: ContainerType, + #[endianness(var)] + pub size: i32, + pub target_actor_id: ActorUniqueID, + #[nbt] + pub data_tags: nbtx::Value, // TODO: NBT Structure +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/update_player_game_type.rs b/crates/proto/src/version/v662/packets/update_player_game_type.rs new file mode 100644 index 00000000..5ec62eed --- /dev/null +++ b/crates/proto/src/version/v662/packets/update_player_game_type.rs @@ -0,0 +1,10 @@ +use crate::version::v662::enums::GameType; +use crate::version::v662::types::ActorUniqueID; +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 151)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct UpdatePlayerGameTypePacket { + pub player_game_type: GameType, + pub target_player: ActorUniqueID, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/update_soft_enum.rs b/crates/proto/src/version/v662/packets/update_soft_enum.rs new file mode 100644 index 00000000..d77bca1e --- /dev/null +++ b/crates/proto/src/version/v662/packets/update_soft_enum.rs @@ -0,0 +1,12 @@ +use crate::version::v662::enums::SoftEnumUpdateType; +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 114)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct UpdateSoftEnumPacket { + pub enum_name: String, + #[vec_repr(u32)] + #[vec_endianness(var)] + pub values: Vec, + pub update_type: SoftEnumUpdateType, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/update_sub_chunk_blocks.rs b/crates/proto/src/version/v662/packets/update_sub_chunk_blocks.rs new file mode 100644 index 00000000..5fa09ad4 --- /dev/null +++ b/crates/proto/src/version/v662/packets/update_sub_chunk_blocks.rs @@ -0,0 +1,77 @@ +use crate::version::v662::enums::ActorBlockSyncMessageID; +use crate::version::v662::types::NetworkBlockPosition; +use bedrockrs_macros::{gamepacket, ProtoCodec}; +use bedrockrs_proto_core::error::ProtoCodecError; +use bedrockrs_proto_core::{ProtoCodec, ProtoCodecVAR}; +use std::io::Cursor; +use std::mem::size_of; +use varint_rs::{VarintReader, VarintWriter}; + +#[derive(Clone, Debug)] +pub struct BlocksChangedEntry { + pub pos: NetworkBlockPosition, + pub runtime_id: u32, + pub update_flags: u32, + pub sync_message_entity_unique_id: u64, + pub sync_message: ActorBlockSyncMessageID, // This is sent as unsigned varint, needs to be varint64 +} + +impl ProtoCodec for BlocksChangedEntry { + fn proto_serialize(&self, stream: &mut Vec) -> Result<(), ProtoCodecError> { + self.pos.proto_serialize(stream)?; + ::proto_serialize(&self.runtime_id, stream)?; + ::proto_serialize(&self.update_flags, stream)?; + ::proto_serialize(&self.sync_message_entity_unique_id, stream)?; + + let mut sync_message_stream: Vec = Vec::new(); + self.sync_message.proto_serialize(&mut sync_message_stream)?; + let mut sync_message_cursor = Cursor::new(sync_message_stream.as_slice()); + + stream.write_u32_varint(sync_message_cursor.read_i64_varint()? as u32)?; + + Ok(()) + } + + fn proto_deserialize(stream: &mut Cursor<&[u8]>) -> Result { + let pos = NetworkBlockPosition::proto_deserialize(stream)?; + let runtime_id = ::proto_deserialize(stream)?; + let update_flags = ::proto_deserialize(stream)?; + let sync_message_entity_unique_id = ::proto_deserialize(stream)?; + + let mut sync_message_stream: Vec = Vec::new(); + sync_message_stream.write_i64_varint(stream.read_u32_varint()? as i64)?; + let mut sync_message_cursor = Cursor::new(sync_message_stream.as_slice()); + + let sync_message = ActorBlockSyncMessageID::proto_deserialize(&mut sync_message_cursor)?; + + Ok(Self { + pos, + runtime_id, + update_flags, + sync_message_entity_unique_id, + sync_message, + }) + } + + fn get_size_prediction(&self) -> usize { + self.pos.get_size_prediction() + + self.runtime_id.get_size_prediction() + + self.update_flags.get_size_prediction() + + self.sync_message_entity_unique_id.get_size_prediction() + + size_of::() + } +} + +#[gamepacket(id = 172)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct UpdateSubChunkBlocksPacket { + pub sub_chunk_block_position: NetworkBlockPosition, + #[vec_repr(u32)] + #[vec_endianness(var)] + pub standard_blocks_changed: Vec, + #[vec_repr(u32)] + #[vec_endianness(var)] + pub extra_blocks_changed: Vec, +} + +// VERIFY: ProtoCodec impl \ No newline at end of file diff --git a/crates/proto/src/version/v662/packets/update_trade.rs b/crates/proto/src/version/v662/packets/update_trade.rs new file mode 100644 index 00000000..6d9adb3a --- /dev/null +++ b/crates/proto/src/version/v662/packets/update_trade.rs @@ -0,0 +1,21 @@ +use crate::version::v662::enums::{ContainerID, ContainerType}; +use crate::version::v662::types::ActorUniqueID; +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 80)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct UpdateTradePacket { + pub container_id: ContainerID, + pub container_type: ContainerType, + #[endianness(var)] + pub size: i32, + #[endianness(var)] + pub trade_tier: i32, + pub target_actor_id: ActorUniqueID, + pub last_trading_player_id: ActorUniqueID, + pub display_name: String, + pub use_new_trade_ui: bool, + pub using_economy_trade: bool, + #[nbt] + pub data_tags: nbtx::Value, // TODO: NBT Structure +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/types/actor_link.rs b/crates/proto/src/version/v662/types/actor_link.rs new file mode 100644 index 00000000..21360974 --- /dev/null +++ b/crates/proto/src/version/v662/types/actor_link.rs @@ -0,0 +1,13 @@ +use crate::version::v662::enums::ActorLinkType; +use crate::version::v662::types::ActorUniqueID; +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +pub struct ActorLink { + pub actor_unique_id_a: ActorUniqueID, + pub actor_unique_id_b: ActorUniqueID, + pub link_type: ActorLinkType, + pub immediate: bool, + /// Whether the link was changed by the passenger + pub passenger_initiated: bool, +} diff --git a/crates/proto/src/version/v662/types/actor_runtime_id.rs b/crates/proto/src/version/v662/types/actor_runtime_id.rs new file mode 100644 index 00000000..ec4470cd --- /dev/null +++ b/crates/proto/src/version/v662/types/actor_runtime_id.rs @@ -0,0 +1,24 @@ +use bedrockrs_proto_core::error::ProtoCodecError; +use bedrockrs_proto_core::ProtoCodec; +use std::io::Cursor; +use std::mem::size_of; +use varint_rs::{VarintReader, VarintWriter}; + +#[derive(Clone, Debug)] +pub struct ActorRuntimeID(pub u64); + +impl ProtoCodec for ActorRuntimeID { + fn proto_serialize(&self, stream: &mut Vec) -> Result<(), ProtoCodecError> { + stream.write_u64_varint(self.0)?; + + Ok(()) + } + + fn proto_deserialize(stream: &mut Cursor<&[u8]>) -> Result { + Ok(Self(stream.read_u64_varint()?)) + } + + fn get_size_prediction(&self) -> usize { + size_of::() + } +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/types/actor_unique_id.rs b/crates/proto/src/version/v662/types/actor_unique_id.rs new file mode 100644 index 00000000..ec6c658b --- /dev/null +++ b/crates/proto/src/version/v662/types/actor_unique_id.rs @@ -0,0 +1,24 @@ +use bedrockrs_proto_core::error::ProtoCodecError; +use bedrockrs_proto_core::ProtoCodec; +use std::io::Cursor; +use std::mem::size_of; +use varint_rs::{VarintReader, VarintWriter}; + +#[derive(Clone, Debug)] +pub struct ActorUniqueID(pub u64); + +impl ProtoCodec for ActorUniqueID { + fn proto_serialize(&self, stream: &mut Vec) -> Result<(), ProtoCodecError> { + stream.write_u64_varint(self.0)?; + + Ok(()) + } + + fn proto_deserialize(stream: &mut Cursor<&[u8]>) -> Result { + Ok(Self(stream.read_u64_varint()?)) + } + + fn get_size_prediction(&self) -> usize { + size_of::() + } +} diff --git a/crates/proto/src/version/v662/types/adventure_settings.rs b/crates/proto/src/version/v662/types/adventure_settings.rs new file mode 100644 index 00000000..099bfe8c --- /dev/null +++ b/crates/proto/src/version/v662/types/adventure_settings.rs @@ -0,0 +1,10 @@ +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +pub struct AdventureSettings { + pub no_pvm: bool, + pub no_mvp: bool, + pub immutable_world: bool, + pub show_name_tags: bool, + pub auto_jump: bool, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/types/base_description.rs b/crates/proto/src/version/v662/types/base_description.rs new file mode 100644 index 00000000..866a79d7 --- /dev/null +++ b/crates/proto/src/version/v662/types/base_description.rs @@ -0,0 +1,35 @@ +use crate::version::v662::enums::MolangVersion; +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +pub struct InternalItemDescriptor { + pub full_name: String, + #[endianness(le)] + pub aux_value: u16, +} + +#[derive(ProtoCodec, Clone, Debug)] +pub struct MolangDescriptor { + pub full_name: String, + pub molang_version: MolangVersion, +} + +#[derive(ProtoCodec, Clone, Debug)] +pub struct ItemTagDescriptor { + pub item_tag: String, +} + +#[derive(ProtoCodec, Clone, Debug)] +pub struct DeferredDescriptor { + pub full_name: String, + #[endianness(le)] + pub aux_value: u16, +} + +#[derive(ProtoCodec, Clone, Debug)] +pub struct BaseDescription { + pub internal_item_descriptor: InternalItemDescriptor, + pub molang_descriptor: MolangDescriptor, + pub item_tag_descriptor: ItemTagDescriptor, + pub deferred_descriptor: DeferredDescriptor, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/types/base_game_version.rs b/crates/proto/src/version/v662/types/base_game_version.rs new file mode 100644 index 00000000..23ae9dc9 --- /dev/null +++ b/crates/proto/src/version/v662/types/base_game_version.rs @@ -0,0 +1,21 @@ +use bedrockrs_proto_core::error::ProtoCodecError; +use bedrockrs_proto_core::ProtoCodec; +use std::io::Cursor; + +#[derive(Clone, Debug)] +pub struct BaseGameVersion(pub String); + +impl ProtoCodec for BaseGameVersion { + fn proto_serialize(&self, stream: &mut Vec) -> Result<(), ProtoCodecError> { + self.0.proto_serialize(stream)?; + Ok(()) + } + + fn proto_deserialize(stream: &mut Cursor<&[u8]>) -> Result { + Ok(Self(String::proto_deserialize(stream)?)) + } + + fn get_size_prediction(&self) -> usize { + self.0.get_size_prediction() + } +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/types/block_pos.rs b/crates/proto/src/version/v662/types/block_pos.rs new file mode 100644 index 00000000..900acb57 --- /dev/null +++ b/crates/proto/src/version/v662/types/block_pos.rs @@ -0,0 +1,11 @@ +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +pub struct BlockPos { + #[endianness(var)] + pub x: i32, + #[endianness(var)] + pub y: i32, + #[endianness(var)] + pub z: i32, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/types/camera_instruction.rs b/crates/proto/src/version/v662/types/camera_instruction.rs new file mode 100644 index 00000000..16a15087 --- /dev/null +++ b/crates/proto/src/version/v662/types/camera_instruction.rs @@ -0,0 +1,59 @@ +use crate::version::v662::enums::EasingType; +use bedrockrs_macros::ProtoCodec; +use vek::{Vec2, Vec3}; + +#[derive(ProtoCodec, Clone, Debug)] +pub struct EaseData { + pub ease_type: EasingType, + #[endianness(le)] + pub ease_time: f32, +} + +#[derive(ProtoCodec, Clone, Debug)] +pub struct SetInstruction { + #[endianness(le)] + pub runtime_id: i32, + pub ease_data: Option, + #[endianness(le)] + pub position: Option>, + #[endianness(le)] + pub rotation: Option>, + #[endianness(le)] + pub facing: Option>, + pub default_preset: Option, +} + +#[derive(ProtoCodec, Clone, Debug)] +pub struct TimeData { + #[endianness(le)] + pub fade_in_time: f32, + #[endianness(le)] + pub wait_time: f32, + #[endianness(le)] + pub fade_out_time: f32, +} + +#[derive(ProtoCodec, Clone, Debug)] +pub struct Color { + #[endianness(le)] + pub r: f32, + #[endianness(le)] + pub g: f32, + #[endianness(le)] + pub b: f32, +} + +#[derive(ProtoCodec, Clone, Debug)] +pub struct FadeInstruction { + pub time_data: Option, + pub color: Option, +} + +#[derive(ProtoCodec, Clone, Debug)] +pub struct CameraInstruction { + pub set: Option, + pub clear: Option, + pub fade: Option, +} + +// VERIFY: SetInstruction & FadeInstruction \ No newline at end of file diff --git a/crates/proto/src/version/v662/types/camera_preset.rs b/crates/proto/src/version/v662/types/camera_preset.rs new file mode 100644 index 00000000..2902ed36 --- /dev/null +++ b/crates/proto/src/version/v662/types/camera_preset.rs @@ -0,0 +1,27 @@ +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +#[enum_repr(i8)] +#[repr(i8)] +pub enum AudioListener { + Camera = 0, + Player = 1, +} + +#[derive(ProtoCodec, Clone, Debug)] +pub struct CameraPreset { + pub name: String, + pub inherit_from: String, + #[endianness(le)] + pub pos_x: Option, + #[endianness(le)] + pub pos_y: Option, + #[endianness(le)] + pub pos_z: Option, + #[endianness(le)] + pub rot_x: Option, + #[endianness(le)] + pub rot_y: Option, + pub listener: Option, + pub player_effects: Option, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/types/camera_presets.rs b/crates/proto/src/version/v662/types/camera_presets.rs new file mode 100644 index 00000000..1934ff21 --- /dev/null +++ b/crates/proto/src/version/v662/types/camera_presets.rs @@ -0,0 +1,9 @@ +use crate::version::v662::types::CameraPreset; +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +pub struct CameraPresets { + #[vec_repr(u32)] + #[vec_endianness(var)] + pub presets: Vec, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/types/chunk_pos.rs b/crates/proto/src/version/v662/types/chunk_pos.rs new file mode 100644 index 00000000..f25f02ba --- /dev/null +++ b/crates/proto/src/version/v662/types/chunk_pos.rs @@ -0,0 +1,9 @@ +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +pub struct ChunkPos { + #[endianness(var)] + pub x: i32, + #[endianness(var)] + pub z: i32, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/types/command_origin_data.rs b/crates/proto/src/version/v662/types/command_origin_data.rs new file mode 100644 index 00000000..0bd458a1 --- /dev/null +++ b/crates/proto/src/version/v662/types/command_origin_data.rs @@ -0,0 +1,51 @@ +use crate::version::v662::enums::CommandOriginType; +use bedrockrs_proto_core::error::ProtoCodecError; +use bedrockrs_proto_core::ProtoCodec; +use std::io::{Cursor, Read}; +use uuid::Uuid; +use varint_rs::{VarintReader, VarintWriter}; + +#[derive(Clone, Debug)] +pub struct CommandOriginData { + pub command_type: CommandOriginType, + pub command_uuid: Uuid, + pub request_id: String, +} + +impl ProtoCodec for CommandOriginData { + fn proto_serialize(&self, stream: &mut Vec) -> Result<(), ProtoCodecError> { + let mut type_stream: Vec = Vec::new(); + self.command_type.proto_serialize(&mut type_stream)?; + let mut type_cursor = Cursor::new(type_stream.as_slice()); + + stream.write_u32_varint(type_cursor.read_u32_varint()?)?; + self.command_uuid.proto_serialize(stream)?; + self.request_id.proto_serialize(stream)?; + type_cursor.read_to_end(stream)?; + + Ok(()) + } + + fn proto_deserialize(stream: &mut Cursor<&[u8]>) -> Result { + let mut type_stream: Vec = Vec::new(); + type_stream.write_u32_varint(stream.read_u32_varint()?)?; + + let command_uuid = Uuid::proto_deserialize(stream)?; + let request_id = String::proto_deserialize(stream)?; + stream.read_to_end(&mut type_stream)?; + let mut type_cursor = Cursor::new(type_stream.as_slice()); + let command_type = CommandOriginType::proto_deserialize(&mut type_cursor)?; + + Ok(Self { + command_type, + command_uuid, + request_id, + }) + } + + fn get_size_prediction(&self) -> usize { + self.command_type.get_size_prediction() + + self.command_uuid.get_size_prediction() + + self.request_id.get_size_prediction() + } +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/types/container_mix_data_entry.rs b/crates/proto/src/version/v662/types/container_mix_data_entry.rs new file mode 100644 index 00000000..9406dc5f --- /dev/null +++ b/crates/proto/src/version/v662/types/container_mix_data_entry.rs @@ -0,0 +1,11 @@ +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +pub struct ContainerMixDataEntry { + #[endianness(var)] + pub input_item_id: i32, + #[endianness(var)] + pub reagent_item_id: i32, + #[endianness(var)] + pub output_item_id: i32, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/types/crafting_data_entry.rs b/crates/proto/src/version/v662/types/crafting_data_entry.rs new file mode 100644 index 00000000..7d84d71d --- /dev/null +++ b/crates/proto/src/version/v662/types/crafting_data_entry.rs @@ -0,0 +1,7 @@ +use crate::version::v662::enums::CraftingDataEntryType; +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +pub struct CraftingDataEntry { + pub crafting_type: CraftingDataEntryType, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/types/data_item.rs b/crates/proto/src/version/v662/types/data_item.rs new file mode 100644 index 00000000..875b8d57 --- /dev/null +++ b/crates/proto/src/version/v662/types/data_item.rs @@ -0,0 +1,9 @@ +use crate::version::v662::enums::DataItemType; +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +pub struct DataItem { + #[endianness(var)] + pub data_item_id: u32, + pub data_item_type: DataItemType, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/types/dimension_definition_group.rs b/crates/proto/src/version/v662/types/dimension_definition_group.rs new file mode 100644 index 00000000..1e21d502 --- /dev/null +++ b/crates/proto/src/version/v662/types/dimension_definition_group.rs @@ -0,0 +1,24 @@ +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +pub struct DimensionDefinitionGroupType { + pub name: String, + pub dimension_definition: DimensionDefinition, +} + +#[derive(ProtoCodec, Clone, Debug)] +pub struct DimensionDefinition { + #[endianness(var)] + pub height_max: i32, + #[endianness(var)] + pub height_min: i32, + #[endianness(var)] + pub generator_type: i32, +} + +#[derive(ProtoCodec, Clone, Debug)] +pub struct DimensionDefinitionGroup { + #[vec_repr(u32)] + #[vec_endianness(var)] + pub definitions: Vec, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/types/edu_shared_uri_resource.rs b/crates/proto/src/version/v662/types/edu_shared_uri_resource.rs new file mode 100644 index 00000000..a132ff2b --- /dev/null +++ b/crates/proto/src/version/v662/types/edu_shared_uri_resource.rs @@ -0,0 +1,7 @@ +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +pub struct EduSharedUriResource { + pub button_name: String, + pub link_uri: String, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/types/education_level_settings.rs b/crates/proto/src/version/v662/types/education_level_settings.rs new file mode 100644 index 00000000..aa53d32c --- /dev/null +++ b/crates/proto/src/version/v662/types/education_level_settings.rs @@ -0,0 +1,15 @@ +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +pub struct EducationLevelSettings { + pub code_builder_default_uri: String, + pub code_builder_title: String, + pub code_builder_resizable: bool, + pub disable_legacy_title_bar: bool, + pub post_process_filter: String, + pub screenshot_border_resource_path: String, + pub agent_capabilities: Option<()>, // TODO: AgentCapabilities + pub code_builder_override_uri: Option, + pub has_quiz: bool, + pub external_link_settings: Option<()>, // TODO: ExternalLinkSettings +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/types/entity_net_id.rs b/crates/proto/src/version/v662/types/entity_net_id.rs new file mode 100644 index 00000000..a09d4931 --- /dev/null +++ b/crates/proto/src/version/v662/types/entity_net_id.rs @@ -0,0 +1,7 @@ +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +pub struct EntityNetID { + #[endianness(var)] + pub raw_entity_id: u32, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/types/experiments.rs b/crates/proto/src/version/v662/types/experiments.rs new file mode 100644 index 00000000..fa1b9a89 --- /dev/null +++ b/crates/proto/src/version/v662/types/experiments.rs @@ -0,0 +1,15 @@ +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +pub struct Experiment { + pub name: String, + pub enabled: bool, +} + +#[derive(ProtoCodec, Clone, Debug)] +pub struct Experiments { + #[vec_repr(u32)] + #[vec_endianness(le)] + pub experiments: Vec, + pub ever_toggled: bool, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/types/game_rules_changed_packet_data.rs b/crates/proto/src/version/v662/types/game_rules_changed_packet_data.rs new file mode 100644 index 00000000..5fc77ccd --- /dev/null +++ b/crates/proto/src/version/v662/types/game_rules_changed_packet_data.rs @@ -0,0 +1,27 @@ +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +#[enum_repr(u32)] +#[enum_endianness(var)] +#[repr(u32)] +pub enum Type { + Invalid = 0, + Bool(bool) = 1, + Int = 2, + Float = 3, +} + +#[derive(ProtoCodec, Clone, Debug)] +pub struct GameRuleChanged { + pub rule_name: String, + pub can_be_modified_by_player: bool, + pub rule_type: Type, +} + +#[derive(ProtoCodec, Clone, Debug)] +pub struct GameRulesChangedPacketData { + #[vec_repr(u32)] + #[vec_endianness(var)] + pub rules_list: Vec, +} + diff --git a/crates/proto/src/version/v662/types/inventory_action.rs b/crates/proto/src/version/v662/types/inventory_action.rs new file mode 100644 index 00000000..bbbe09c7 --- /dev/null +++ b/crates/proto/src/version/v662/types/inventory_action.rs @@ -0,0 +1,11 @@ +use crate::version::v662::types::{InventorySource, NetworkItemStackDescriptor}; +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +pub struct InventoryAction { + pub source: InventorySource, + #[endianness(var)] + pub slot: u32, + pub from_item_descriptor: NetworkItemStackDescriptor, + pub to_item_descriptor: NetworkItemStackDescriptor, +} diff --git a/crates/proto/src/version/v662/types/inventory_source.rs b/crates/proto/src/version/v662/types/inventory_source.rs new file mode 100644 index 00000000..f8ea5905 --- /dev/null +++ b/crates/proto/src/version/v662/types/inventory_source.rs @@ -0,0 +1,7 @@ +use crate::version::v662::enums::InventorySourceType; +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +pub struct InventorySource { + pub source_type: InventorySourceType, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/types/inventory_transaction.rs b/crates/proto/src/version/v662/types/inventory_transaction.rs new file mode 100644 index 00000000..b7416ba0 --- /dev/null +++ b/crates/proto/src/version/v662/types/inventory_transaction.rs @@ -0,0 +1,9 @@ +use crate::version::v662::types::InventoryAction; +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +pub struct InventoryTransaction { + #[vec_repr(u32)] + #[vec_endianness(var)] + pub action: Vec, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/types/item_data.rs b/crates/proto/src/version/v662/types/item_data.rs new file mode 100644 index 00000000..edb37d39 --- /dev/null +++ b/crates/proto/src/version/v662/types/item_data.rs @@ -0,0 +1,9 @@ +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +pub struct ItemData { + pub name: String, + #[endianness(le)] + pub id: i16, + pub is_component_based: bool, +} diff --git a/crates/proto/src/version/v662/types/item_enchants.rs b/crates/proto/src/version/v662/types/item_enchants.rs new file mode 100644 index 00000000..f6c28f39 --- /dev/null +++ b/crates/proto/src/version/v662/types/item_enchants.rs @@ -0,0 +1,17 @@ +use crate::version::v662::enums::EnchantType; +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +pub struct ItemEnchant { + pub enchant_type: EnchantType, + pub enchant_level: i8, +} + +#[derive(ProtoCodec, Clone, Debug)] +pub struct ItemEnchants { + #[endianness(le)] + pub slot: i32, + #[vec_repr(u32)] + #[vec_endianness(var)] + pub enchants_for_given_activation: Vec, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/types/item_instance_user_data.rs b/crates/proto/src/version/v662/types/item_instance_user_data.rs new file mode 100644 index 00000000..fa7a7175 --- /dev/null +++ b/crates/proto/src/version/v662/types/item_instance_user_data.rs @@ -0,0 +1,16 @@ +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +pub struct ItemInstanceUserData { + #[endianness(le)] + pub serialization_marker: i16, + pub serialization_version: i8, + #[nbt] + pub tags: nbtx::Value, // TODO: NBT Structure + #[vec_repr(u32)] + #[vec_endianness(var)] + pub can_place_on: Vec, + #[vec_repr(u32)] + #[vec_endianness(var)] + pub can_break: Vec, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/types/item_stack_request_slot_info.rs b/crates/proto/src/version/v662/types/item_stack_request_slot_info.rs new file mode 100644 index 00000000..26584017 --- /dev/null +++ b/crates/proto/src/version/v662/types/item_stack_request_slot_info.rs @@ -0,0 +1,10 @@ +use crate::version::v662::enums::ContainerName; +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +pub struct ItemStackRequestSlotInfo { + pub container_net_id: ContainerName, + pub slot: i8, + #[endianness(var)] + pub raw_id: i32, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/types/item_stack_response_container_info.rs b/crates/proto/src/version/v662/types/item_stack_response_container_info.rs new file mode 100644 index 00000000..db75432a --- /dev/null +++ b/crates/proto/src/version/v662/types/item_stack_response_container_info.rs @@ -0,0 +1,10 @@ +use crate::version::v662::types::ItemStackResponseSlotInfo; +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +pub struct ItemStackResponseContainerInfo { + pub container_net_id: i8, + #[vec_repr(u32)] + #[vec_endianness(var)] + pub slots: Vec, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/types/item_stack_response_info.rs b/crates/proto/src/version/v662/types/item_stack_response_info.rs new file mode 100644 index 00000000..6afa5c90 --- /dev/null +++ b/crates/proto/src/version/v662/types/item_stack_response_info.rs @@ -0,0 +1,47 @@ +use crate::version::v662::enums::ItemStackNetResult; +use bedrockrs_proto_core::error::ProtoCodecError; +use bedrockrs_proto_core::{ProtoCodec, ProtoCodecVAR}; +use byteorder::{ReadBytesExt, WriteBytesExt}; +use std::io::{Cursor, Read}; + +#[derive(Clone, Debug)] +pub struct ItemStackResponseInfo { + pub result: ItemStackNetResult, + pub client_request_id: i32, +} + +impl ProtoCodec for ItemStackResponseInfo { + fn proto_serialize(&self, stream: &mut Vec) -> Result<(), ProtoCodecError> { + let mut result_stream: Vec = Vec::new(); + + self.result.proto_serialize(&mut result_stream)?; + let mut result_cursor = Cursor::new(result_stream.as_slice()); + + stream.write_i8(result_cursor.read_i8()?)?; + ::proto_serialize(&self.client_request_id, stream)?; + result_cursor.read_to_end(stream)?; + + Ok(()) + } + + fn proto_deserialize(stream: &mut Cursor<&[u8]>) -> Result { + let mut result_stream: Vec = Vec::new(); + + result_stream.write_i8(stream.read_i8()?)?; + let client_request_id = ::proto_deserialize(stream)?; + stream.read_to_end(&mut result_stream)?; + + let mut result_cursor = Cursor::new(result_stream.as_slice()); + let result = ItemStackNetResult::proto_deserialize(&mut result_cursor)?; + + Ok(Self { + result, + client_request_id, + }) + } + + fn get_size_prediction(&self) -> usize { + self.result.get_size_prediction() + + ::get_size_prediction(&self.client_request_id) + } +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/types/item_stack_response_slot_info.rs b/crates/proto/src/version/v662/types/item_stack_response_slot_info.rs new file mode 100644 index 00000000..e3ee4b56 --- /dev/null +++ b/crates/proto/src/version/v662/types/item_stack_response_slot_info.rs @@ -0,0 +1,13 @@ +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +pub struct ItemStackResponseSlotInfo { + pub requested_slot: i8, + pub slot: i8, + pub amount: i8, + #[endianness(var)] + pub item_stack_net_id: i32, + pub custom_name: String, + #[endianness(var)] + pub durability_correction: i32, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/types/level_settings.rs b/crates/proto/src/version/v662/types/level_settings.rs new file mode 100644 index 00000000..8ec25ea7 --- /dev/null +++ b/crates/proto/src/version/v662/types/level_settings.rs @@ -0,0 +1,61 @@ +use crate::version::v662::enums::{ChatRestrictionLevel, Difficulty, EditorWorldType, EducationEditionOffer, GamePublishSetting, GameType, GeneratorType, PlayerPermissionLevel}; +use crate::version::v662::types::{BaseGameVersion, EduSharedUriResource, Experiments, GameRulesChangedPacketData, NetworkBlockPosition, SpawnSettings}; +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +pub struct LevelSettings { + #[endianness(le)] + pub seed: u64, + pub spawn_settings: SpawnSettings, + pub generator_type: GeneratorType, + pub game_type: GameType, + pub game_difficulty: Difficulty, + pub default_spawn_block_position: NetworkBlockPosition, + pub achievements_disabled: bool, + pub editor_world_type: EditorWorldType, + pub is_created_in_editor: bool, + pub is_exported_from_editor: bool, + #[endianness(var)] + pub day_cycle_stop_time: i32, + pub education_edition_offer: EducationEditionOffer, + pub education_features_enabled: bool, + pub education_product_id: String, + #[endianness(le)] + pub rain_level: f32, + #[endianness(le)] + pub lightning_level: f32, + pub has_confirmed_platform_locked_content: bool, + pub multiplayer_enabled: bool, + pub lan_broadcasting_enabled: bool, + pub xbox_live_broadcast_setting: GamePublishSetting, + pub platform_broadcast_setting: GamePublishSetting, + pub commands_enabled: bool, + pub texture_packs_required: bool, + pub rule_data: GameRulesChangedPacketData, + pub experiments: Experiments, + pub bonus_chest_enabled: bool, + pub starting_map_enabled: bool, + pub player_permissions: PlayerPermissionLevel, + #[endianness(le)] + pub server_chunk_tick_range: i32, + pub locked_behaviour_pack: bool, + pub locked_resource_pack: bool, + pub from_locked_template: bool, + pub use_msa_gamer_tags: bool, + pub from_template: bool, + pub has_locked_template_settings: bool, + pub only_spawn_v1_villagers: bool, + pub persona_disabled: bool, + pub custom_skins_disabled: bool, + pub emote_chat_muted: bool, + pub base_game_version: BaseGameVersion, + #[endianness(le)] + pub limited_world_width: i32, + #[endianness(le)] + pub limited_world_depth: i32, + pub nether_type: bool, + pub edu_shared_uri_resource: EduSharedUriResource, + pub override_force_experimental_gameplay: bool, + pub chat_restriction_level: ChatRestrictionLevel, + pub disable_player_interactions: bool, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/types/map_decoration.rs b/crates/proto/src/version/v662/types/map_decoration.rs new file mode 100644 index 00000000..ef9c733a --- /dev/null +++ b/crates/proto/src/version/v662/types/map_decoration.rs @@ -0,0 +1,50 @@ +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +#[enum_repr(i8)] +pub enum MapDecorationType { + MarkerWhite = 0, + MarkerGreen = 1, + MarkerRed = 2, + MarkerBlue = 3, + XWhite = 4, + TriangleRed = 5, + SquareWhite = 6, + MarkerSign = 7, + MarkerPink = 8, + MarkerOrange = 9, + MarkerYellow = 10, + MarkerTeal = 11, + TriangleGreen = 12, + SmallSquareWhite = 13, + Mansion = 14, + Monument = 15, + NoDraw = 16, + VillageDesert = 17, + VillagePlains = 18, + VillageSavanna = 19, + VillageSnowy = 20, + VillageTaiga = 21, + JungleTemple = 22, + WitchHut = 23, + Count = 24, +} + +impl MapDecorationType { + pub const PLAYER: MapDecorationType = MapDecorationType::MarkerWhite; + pub const PLAYER_OFF_MAP: MapDecorationType = MapDecorationType::SquareWhite; + pub const PLAYER_OFF_LIMITS: MapDecorationType = MapDecorationType::SmallSquareWhite; + pub const PLAYER_HIDDEN: MapDecorationType = MapDecorationType::NoDraw; + pub const ITEM_FRAME: MapDecorationType = MapDecorationType::MarkerGreen; +} + +#[derive(ProtoCodec, Clone, Debug)] +pub struct MapDecoration { + pub map_decoration_type: MapDecorationType, + pub rotation: i8, + pub x: i8, + pub y: i8, + pub label: String, + #[endianness(var)] + pub color_argb: u32, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/types/map_item_tracked_actor_unique_id.rs b/crates/proto/src/version/v662/types/map_item_tracked_actor_unique_id.rs new file mode 100644 index 00000000..97835c89 --- /dev/null +++ b/crates/proto/src/version/v662/types/map_item_tracked_actor_unique_id.rs @@ -0,0 +1,17 @@ +use crate::version::v662::types::{ActorUniqueID, NetworkBlockPosition}; +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +#[enum_repr(i32)] +#[enum_endianness(le)] +#[repr(i32)] +pub enum MapItemTrackedActorType { + Entity(ActorUniqueID) = 0, + BlockEntity(NetworkBlockPosition) = 1, + Other = 2, +} + +#[derive(ProtoCodec, Clone, Debug)] +pub struct MapItemTrackedActorUniqueID { + pub unique_id_type: MapItemTrackedActorType, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/types/material_reducer_data_entry.rs b/crates/proto/src/version/v662/types/material_reducer_data_entry.rs new file mode 100644 index 00000000..3dc17b44 --- /dev/null +++ b/crates/proto/src/version/v662/types/material_reducer_data_entry.rs @@ -0,0 +1,18 @@ +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +pub struct MaterialReducerDataEntryIdAndCount { + #[endianness(var)] + pub id: i32, + #[endianness(var)] + pub count: i32, +} + +#[derive(ProtoCodec, Clone, Debug)] +pub struct MaterialReducerDataEntry { + #[endianness(var)] + pub input: i32, + #[vec_repr(u32)] + #[vec_endianness(var)] + pub ids_and_counts: Vec, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/types/mod.rs b/crates/proto/src/version/v662/types/mod.rs new file mode 100644 index 00000000..ff6d7dc3 --- /dev/null +++ b/crates/proto/src/version/v662/types/mod.rs @@ -0,0 +1,73 @@ +macro_rules! export { + ($name:ident) => { + mod $name; + pub use $name::*; + }; +} + +export!(actor_link); +export!(actor_runtime_id); +export!(actor_unique_id); +export!(adventure_settings); +export!(base_description); +export!(base_game_version); +export!(block_pos); +export!(camera_instruction); +export!(camera_preset); +export!(camera_presets); +export!(chunk_pos); +export!(command_origin_data); +export!(container_mix_data_entry); +export!(crafting_data_entry); +export!(data_item); +export!(dimension_definition_group); +export!(edu_shared_uri_resource); +export!(education_level_settings); +export!(entity_net_id); +export!(experiments); +export!(game_rules_changed_packet_data); +export!(inventory_action); +export!(inventory_source); +export!(inventory_transaction); +export!(item_data); +export!(item_enchants); +export!(item_instance_user_data); +export!(item_stack_request_slot_info); +export!(item_stack_response_container_info); +export!(item_stack_response_info); +export!(item_stack_response_slot_info); +export!(level_settings); +export!(map_decoration); +export!(map_item_tracked_actor_unique_id); +export!(material_reducer_data_entry); +export!(molang_variable_map); +export!(move_actor_absolute_data); +export!(move_actor_delta_data); +export!(network_block_position); +export!(network_item_instance_descriptor); +export!(network_item_stack_descriptor); +export!(network_permissions); +export!(packed_item_use_legacy_inventory_transaction); +export!(player_block_action_data); +export!(player_block_actions); +export!(position_tracking_id); +export!(potion_mix_data_entry); +export!(property_sync_data); +export!(recipe_ingredient); +export!(scoreboard_id); +export!(serialized_abilities_data); +export!(serialized_skin); +export!(shaped_chemistry_recipe); +export!(shaped_recipe); +export!(shapeless_chemistry_recipe); +export!(shapeless_recipe); +export!(shulker_box_recipe); +export!(smithing_transform_recipe); +export!(smithing_trim_recipe); +export!(spawn_settings); +export!(structure_editor_data); +export!(structure_settings); +export!(sub_chunk_pos); +export!(synced_player_movement_settings); +export!(web_socket_packet_data); +export!(sub_chunk_pos_offset); diff --git a/crates/proto/src/version/v662/types/molang_variable_map.rs b/crates/proto/src/version/v662/types/molang_variable_map.rs new file mode 100644 index 00000000..a10585dd --- /dev/null +++ b/crates/proto/src/version/v662/types/molang_variable_map.rs @@ -0,0 +1,6 @@ +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +pub struct MolangVariableMap { + pub serialized_variable_map: String, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/types/move_actor_absolute_data.rs b/crates/proto/src/version/v662/types/move_actor_absolute_data.rs new file mode 100644 index 00000000..d11292fb --- /dev/null +++ b/crates/proto/src/version/v662/types/move_actor_absolute_data.rs @@ -0,0 +1,14 @@ +use crate::version::v662::types::ActorRuntimeID; +use bedrockrs_macros::ProtoCodec; +use vek::Vec3; + +#[derive(ProtoCodec, Clone, Debug)] +pub struct MoveActorAbsoluteData { + pub actor_runtime_id: ActorRuntimeID, + pub header: i8, + #[endianness(le)] + pub position: Vec3, + pub rotation_x: i8, + pub rotation_y: i8, + pub rotation_y_head: i8, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/types/move_actor_delta_data.rs b/crates/proto/src/version/v662/types/move_actor_delta_data.rs new file mode 100644 index 00000000..8a049ed1 --- /dev/null +++ b/crates/proto/src/version/v662/types/move_actor_delta_data.rs @@ -0,0 +1,18 @@ +use crate::version::v662::types::ActorRuntimeID; +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +pub struct MoveActorDeltaData { + pub actor_runtime_id: ActorRuntimeID, + #[endianness(le)] + pub header: u16, + #[endianness(le)] + pub position_x: f32, + #[endianness(le)] + pub position_y: f32, + #[endianness(le)] + pub position_z: f32, + pub rotation_x: i8, + pub rotation_y: i8, + pub rotation_y_head: i8, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/types/network_block_position.rs b/crates/proto/src/version/v662/types/network_block_position.rs new file mode 100644 index 00000000..3c8ac125 --- /dev/null +++ b/crates/proto/src/version/v662/types/network_block_position.rs @@ -0,0 +1,11 @@ +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +pub struct NetworkBlockPosition { + #[endianness(var)] + pub x: i32, + #[endianness(var)] + pub y: u32, + #[endianness(var)] + pub z: i32, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/types/network_item_instance_descriptor.rs b/crates/proto/src/version/v662/types/network_item_instance_descriptor.rs new file mode 100644 index 00000000..bc6e9300 --- /dev/null +++ b/crates/proto/src/version/v662/types/network_item_instance_descriptor.rs @@ -0,0 +1,74 @@ +use bedrockrs_proto_core::error::ProtoCodecError; +use bedrockrs_proto_core::{ProtoCodec, ProtoCodecLE, ProtoCodecVAR}; +use std::io::Cursor; + +#[derive(Clone, Debug)] +pub struct NetworkItemInstanceDescriptor { + id: i32, + stack_size: Option, + aux_value: Option, + block_runtime_id: Option, + user_data_buffer: Option, +} + +impl ProtoCodec for NetworkItemInstanceDescriptor { + fn proto_serialize(&self, stream: &mut Vec) -> Result<(), ProtoCodecError> { + ProtoCodecVAR::proto_serialize(&self.id, stream)?; + + match &self.id { + 0 => {} + _ => { + ProtoCodecLE::proto_serialize(self.stack_size.as_ref().unwrap(), stream)?; + ProtoCodecVAR::proto_serialize(self.aux_value.as_ref().unwrap(), stream)?; + ProtoCodecVAR::proto_serialize(self.block_runtime_id.as_ref().unwrap(), stream)?; + ProtoCodec::proto_serialize(self.user_data_buffer.as_ref().unwrap(), stream)?; + } + } + + Ok(()) + } + + fn proto_deserialize(stream: &mut Cursor<&[u8]>) -> Result { + let id = ProtoCodecVAR::proto_deserialize(stream)?; + + let (stack_size, aux_value, block_runtime_id, user_data_buffer) = match &id { + 0 => (None, None, None, None), + _ => { + let stack_size = ProtoCodecLE::proto_deserialize(stream)?; + let aux_value = ProtoCodecVAR::proto_deserialize(stream)?; + let block_runtime_id = ProtoCodecVAR::proto_deserialize(stream)?; + let user_data_buffer = ProtoCodec::proto_deserialize(stream)?; + + ( + Some(stack_size), + Some(aux_value), + Some(block_runtime_id), + Some(user_data_buffer), + ) + } + }; + + Ok(Self { + id, + stack_size, + aux_value, + block_runtime_id, + user_data_buffer, + }) + } + + fn get_size_prediction(&self) -> usize { + ProtoCodecVAR::get_size_prediction(&self.id) + + match self.id { + 0 => 0, + _ => { + ProtoCodecLE::get_size_prediction(self.stack_size.as_ref().unwrap()) + + ProtoCodecVAR::get_size_prediction(self.aux_value.as_ref().unwrap()) + + ProtoCodecVAR::get_size_prediction(self.block_runtime_id.as_ref().unwrap()) + + ProtoCodec::get_size_prediction(self.user_data_buffer.as_ref().unwrap()) + } + } + } +} + +// VERIFY: ProtoCodec impl diff --git a/crates/proto/src/version/v662/types/network_item_stack_descriptor.rs b/crates/proto/src/version/v662/types/network_item_stack_descriptor.rs new file mode 100644 index 00000000..dcf05e41 --- /dev/null +++ b/crates/proto/src/version/v662/types/network_item_stack_descriptor.rs @@ -0,0 +1,74 @@ +use bedrockrs_proto_core::error::ProtoCodecError; +use bedrockrs_proto_core::{ProtoCodec, ProtoCodecLE, ProtoCodecVAR}; +use std::io::Cursor; + +#[derive(Clone, Debug)] +pub struct NetworkItemStackDescriptor { + id: i32, + stack_size: Option, + aux_value: Option, + net_id_variant: Option>, + block_runtime_id: Option, + user_data_buffer: Option, +} + +impl ProtoCodec for NetworkItemStackDescriptor { + fn proto_serialize(&self, stream: &mut Vec) -> Result<(), ProtoCodecError> { + ProtoCodecVAR::proto_serialize(&self.id, stream)?; + + match &self.id { + 0 => {} + _ => { + ProtoCodecLE::proto_serialize(self.stack_size.as_ref().unwrap(), stream)?; + ProtoCodecVAR::proto_serialize(self.aux_value.as_ref().unwrap(), stream)?; + as ProtoCodecVAR>::proto_serialize(self.net_id_variant.as_ref().unwrap(), stream)?; + ProtoCodecVAR::proto_serialize(self.block_runtime_id.as_ref().unwrap(), stream)?; + String::proto_serialize(self.user_data_buffer.as_ref().unwrap(), stream)?; + } + } + + Ok(()) + } + + fn proto_deserialize(stream: &mut Cursor<&[u8]>) -> Result { + let id = ::proto_deserialize(stream)?; + + let (stack_size, aux_value, net_id_variant, block_runtime_id, user_data_buffer) = match id { + 0 => (None, None, None, None, None), + _ => { + let stack_size = ::proto_deserialize(stream)?; + let aux_value = ::proto_deserialize(stream)?; + let net_id_variant = as ProtoCodecVAR>::proto_deserialize(stream)?; + let block_runtime_id = ::proto_deserialize(stream)?; + let user_data_buffer = String::proto_deserialize(stream)?; + + (Some(stack_size), Some(aux_value), Some(net_id_variant), Some(block_runtime_id), Some(user_data_buffer)) + } + }; + + Ok(Self { + id, + stack_size, + aux_value, + net_id_variant, + block_runtime_id, + user_data_buffer, + }) + } + + fn get_size_prediction(&self) -> usize { + ProtoCodecVAR::get_size_prediction(&self.id) + + match &self.id { + 0 => 0, + _ => { + ProtoCodecLE::get_size_prediction(self.stack_size.as_ref().unwrap()) + + ProtoCodecVAR::get_size_prediction(self.aux_value.as_ref().unwrap()) + + as ProtoCodecVAR>::get_size_prediction(self.net_id_variant.as_ref().unwrap()) + + ProtoCodecVAR::get_size_prediction(self.block_runtime_id.as_ref().unwrap()) + + String::get_size_prediction(self.user_data_buffer.as_ref().unwrap()) + } + } + } +} + +// TODO: impl ProtoCodec \ No newline at end of file diff --git a/crates/proto/src/version/v662/types/network_permissions.rs b/crates/proto/src/version/v662/types/network_permissions.rs new file mode 100644 index 00000000..a0a63c8e --- /dev/null +++ b/crates/proto/src/version/v662/types/network_permissions.rs @@ -0,0 +1,6 @@ +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +pub struct NetworkPermissions { + pub server_auth_sound_enabled: bool, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/types/packed_item_use_legacy_inventory_transaction.rs b/crates/proto/src/version/v662/types/packed_item_use_legacy_inventory_transaction.rs new file mode 100644 index 00000000..1e82fc6c --- /dev/null +++ b/crates/proto/src/version/v662/types/packed_item_use_legacy_inventory_transaction.rs @@ -0,0 +1,120 @@ +use crate::version::v662::enums::ItemUseInventoryTransactionType; +use crate::version::v662::types::{ + InventoryTransaction, NetworkBlockPosition, NetworkItemStackDescriptor, +}; +use bedrockrs_macros::ProtoCodec; +use bedrockrs_proto_core::error::ProtoCodecError; +use bedrockrs_proto_core::{ProtoCodec, ProtoCodecLE, ProtoCodecVAR}; +use std::io::Cursor; +use vek::Vec3; + +#[derive(ProtoCodec, Clone, Debug)] +pub struct ContainerSlotEntry { + pub container_enum_name: String, + #[vec_repr(u32)] + #[vec_endianness(var)] + pub slots: Vec, +} + +#[derive(Clone, Debug)] +pub struct PackedItemUseLegacyInventoryTransaction { + id: i32, + container_slots: Option>, + action: InventoryTransaction, + action_type: ItemUseInventoryTransactionType, + position: NetworkBlockPosition, + face: i32, + slot: i32, + item: NetworkItemStackDescriptor, + from_position: Vec3, + click_position: Vec3, + target_block_id: u32, +} + +impl ProtoCodec for PackedItemUseLegacyInventoryTransaction { + fn proto_serialize(&self, stream: &mut Vec) -> Result<(), ProtoCodecError> { + ProtoCodecVAR::proto_serialize(&self.id, stream)?; + + match &self.id { + 0 => {} + _ => { + let vec = self.container_slots.as_ref().unwrap(); + let len: u32 = vec.len().try_into()?; + ProtoCodecVAR::proto_serialize(&len, stream)?; + for i in vec { + i.proto_serialize(stream)? + } + } + } + + self.action.proto_serialize(stream)?; + self.action_type.proto_serialize(stream)?; + self.position.proto_serialize(stream)?; + ProtoCodecVAR::proto_serialize(&self.face, stream)?; + ProtoCodecVAR::proto_serialize(&self.slot, stream)?; + self.item.proto_serialize(stream)?; + ProtoCodecLE::proto_serialize(&self.from_position, stream)?; + ProtoCodecLE::proto_serialize(&self.click_position, stream)?; + ProtoCodecVAR::proto_serialize(&self.target_block_id, stream)?; + + Ok(()) + } + + fn proto_deserialize(stream: &mut Cursor<&[u8]>) -> Result { + let id = ::proto_deserialize(stream)?; + let container_slots = match id { + 0 => None, + _ => { + let len = ::proto_deserialize(stream)?; + let mut vec = Vec::with_capacity(len.try_into()?); + for _ in 0..len { + vec.push(ContainerSlotEntry::proto_deserialize(stream)?); + } + Some(vec) + } + }; + let action = InventoryTransaction::proto_deserialize(stream)?; + let action_type = ItemUseInventoryTransactionType::proto_deserialize(stream)?; + let position = NetworkBlockPosition::proto_deserialize(stream)?; + let face = ::proto_deserialize(stream)?; + let slot = ::proto_deserialize(stream)?; + let item = NetworkItemStackDescriptor::proto_deserialize(stream)?; + let from_position = as ProtoCodecLE>::proto_deserialize(stream)?; + let click_position = as ProtoCodecLE>::proto_deserialize(stream)?; + let target_block_id = ::proto_deserialize(stream)?; + + Ok(Self { + id, + container_slots, + action, + action_type, + position, + face, + slot, + item, + from_position, + click_position, + target_block_id, + }) + } + + fn get_size_prediction(&self) -> usize { + ProtoCodecVAR::get_size_prediction(&self.id) + + match &self.id { + 0 => 0, + _ => { + let vec = self.container_slots.as_ref().unwrap(); + vec.len() + vec.iter().map(|i| i.get_size_prediction()).sum::() + } + } + + self.action.get_size_prediction() + + self.action_type.get_size_prediction() + + self.position.get_size_prediction() + + ProtoCodecVAR::get_size_prediction(&self.face) + + ProtoCodecVAR::get_size_prediction(&self.slot) + + self.item.get_size_prediction() + + ProtoCodecLE::get_size_prediction(&self.from_position) + + ProtoCodecLE::get_size_prediction(&self.click_position) + + ProtoCodecVAR::get_size_prediction(&self.target_block_id) + } +} diff --git a/crates/proto/src/version/v662/types/player_block_action_data.rs b/crates/proto/src/version/v662/types/player_block_action_data.rs new file mode 100644 index 00000000..7c4149d3 --- /dev/null +++ b/crates/proto/src/version/v662/types/player_block_action_data.rs @@ -0,0 +1,7 @@ +use crate::version::v662::enums::PlayerActionType; +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +pub struct PlayerBlockActionData { + pub player_action_type: PlayerActionType, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/types/player_block_actions.rs b/crates/proto/src/version/v662/types/player_block_actions.rs new file mode 100644 index 00000000..a276fa4b --- /dev/null +++ b/crates/proto/src/version/v662/types/player_block_actions.rs @@ -0,0 +1,9 @@ +use crate::version::v662::types::PlayerBlockActionData; +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +pub struct PlayerBlockActions { + #[vec_repr(i32)] + #[vec_endianness(var)] + pub player_block_actions: Vec, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/types/position_tracking_id.rs b/crates/proto/src/version/v662/types/position_tracking_id.rs new file mode 100644 index 00000000..44bc4581 --- /dev/null +++ b/crates/proto/src/version/v662/types/position_tracking_id.rs @@ -0,0 +1,7 @@ +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +pub struct PositionTrackingId { + #[endianness(var)] + pub value: i32, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/types/potion_mix_data_entry.rs b/crates/proto/src/version/v662/types/potion_mix_data_entry.rs new file mode 100644 index 00000000..397d8a88 --- /dev/null +++ b/crates/proto/src/version/v662/types/potion_mix_data_entry.rs @@ -0,0 +1,17 @@ +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +pub struct PotionMixDataEntry { + #[endianness(var)] + pub input_potion_id: i32, + #[endianness(var)] + pub input_item_aux: i32, + #[endianness(var)] + pub reagent_item_id: i32, + #[endianness(var)] + pub reagent_item_aux: i32, + #[endianness(var)] + pub output_potion_id: i32, + #[endianness(var)] + pub output_item_aux: i32, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/types/property_sync_data.rs b/crates/proto/src/version/v662/types/property_sync_data.rs new file mode 100644 index 00000000..bb7dff06 --- /dev/null +++ b/crates/proto/src/version/v662/types/property_sync_data.rs @@ -0,0 +1,27 @@ +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +pub struct IntEntry { + #[endianness(var)] + pub property_index: u32, + #[endianness(le)] + pub data: f32, +} + +#[derive(ProtoCodec, Clone, Debug)] +pub struct FloatEntry { + #[endianness(var)] + pub property_index: u32, + #[endianness(var)] + pub data: i32, +} + +#[derive(ProtoCodec, Clone, Debug)] +pub struct PropertySyncData { + #[vec_repr(u32)] + #[vec_endianness(var)] + pub int_entries_list: Vec, + #[vec_repr(u32)] + #[vec_endianness(var)] + pub float_entries_list: Vec, +} diff --git a/crates/proto/src/version/v662/types/recipe_ingredient.rs b/crates/proto/src/version/v662/types/recipe_ingredient.rs new file mode 100644 index 00000000..f74e0c58 --- /dev/null +++ b/crates/proto/src/version/v662/types/recipe_ingredient.rs @@ -0,0 +1,9 @@ +use crate::version::v662::enums::ItemDescriptorInternalType; +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +pub struct RecipeIngredient { + pub internal_type: ItemDescriptorInternalType, + #[endianness(var)] + pub stack_size: i32, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/types/scoreboard_id.rs b/crates/proto/src/version/v662/types/scoreboard_id.rs new file mode 100644 index 00000000..493da471 --- /dev/null +++ b/crates/proto/src/version/v662/types/scoreboard_id.rs @@ -0,0 +1,7 @@ +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +pub struct ScoreboardId { + #[endianness(var)] + pub id: i64, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/types/serialized_abilities_data.rs b/crates/proto/src/version/v662/types/serialized_abilities_data.rs new file mode 100644 index 00000000..f9dafd93 --- /dev/null +++ b/crates/proto/src/version/v662/types/serialized_abilities_data.rs @@ -0,0 +1,39 @@ +use crate::version::v662::enums::{CommandPermissionLevel, PlayerPermissionLevel}; +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +#[enum_repr(u16)] +#[enum_endianness(le)] +#[repr(u16)] +pub enum SerializedAbilitiesLayer { + CustomCache = 0, + Base = 1, + Spectator = 2, + Commands = 3, + Editor = 4, +} + +#[derive(ProtoCodec, Clone, Debug)] +pub struct SerializedLayer { + pub serialized_layer: SerializedAbilitiesLayer, + #[endianness(le)] + pub abilities_set: u32, + #[endianness(le)] + pub ability_values: u32, + #[endianness(le)] + pub fly_speed: f32, + #[endianness(le)] + pub walk_speed: f32, +} + +#[derive(ProtoCodec, Clone, Debug)] +pub struct SerializedAbilitiesData { + #[endianness(le)] + pub target_player_raw_id: i64, + pub player_permissions: PlayerPermissionLevel, + pub command_permissions: CommandPermissionLevel, + #[vec_repr(u32)] + #[vec_endianness(var)] + pub layers: Vec, +} + diff --git a/crates/proto/src/version/v662/types/serialized_skin.rs b/crates/proto/src/version/v662/types/serialized_skin.rs new file mode 100644 index 00000000..bc94678d --- /dev/null +++ b/crates/proto/src/version/v662/types/serialized_skin.rs @@ -0,0 +1,68 @@ +use crate::version::v662::enums::{AnimatedTextureType, AnimationExpression}; +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +pub struct SerializedSkinAnimationFrame { + #[endianness(le)] + pub image_width: u32, + #[endianness(le)] + pub image_height: u32, + pub image_bytes: String, + pub animation_type: AnimatedTextureType, + #[endianness(le)] + pub frame_count: f32, + pub animation_expression: AnimationExpression, +} + +#[derive(ProtoCodec, Clone, Debug)] +pub struct PersonaPiecesEntry { + pub piece_id: String, + pub piece_type: String, + pub pack_id: String, + pub is_default_piece: bool, + pub product_id: String, +} + +#[derive(ProtoCodec, Clone, Debug)] +pub struct PieceTintColorsEntry { + pub piece_type: String, + pub piece_tint_color: String, +} + +#[derive(ProtoCodec, Clone, Debug)] +pub struct SerializedSkin { + pub skin_id: String, + pub play_fab_id: String, + pub skin_resource_patch: String, + #[endianness(le)] + pub skin_image_width: u32, + #[endianness(le)] + pub skin_image_height: u32, + pub skin_image_bytes: String, + #[vec_repr(u32)] + #[vec_endianness(le)] + pub animations: Vec, + #[endianness(le)] + pub cape_image_width: u32, + #[endianness(le)] + pub cape_image_height: u32, + pub cape_image_bytes: String, + pub geometry_data: String, + pub geometry_data_engine_version: String, + pub animation_data: String, + pub cape_id: String, + pub full_id: String, + pub arm_size: String, + pub skin_color: String, + #[vec_repr(u32)] + #[vec_endianness(le)] + pub persona_pieces: Vec, + #[vec_repr(u32)] + #[vec_endianness(le)] + pub piece_tint_colors: Vec, + pub is_premium_skin: bool, + pub is_persona_skin: bool, + pub is_persona_cape_on_classic_skin: bool, + pub is_primary_user: bool, + pub overrides_player_appearance: bool, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/types/shaped_chemistry_recipe.rs b/crates/proto/src/version/v662/types/shaped_chemistry_recipe.rs new file mode 100644 index 00000000..a31921e3 --- /dev/null +++ b/crates/proto/src/version/v662/types/shaped_chemistry_recipe.rs @@ -0,0 +1,20 @@ +use crate::version::v662::types::{NetworkItemInstanceDescriptor, RecipeIngredient}; +use bedrockrs_macros::ProtoCodec; +use uuid::Uuid; + +#[derive(ProtoCodec, Clone, Debug)] +pub struct ShapedChemistryRecipe { + pub recipe_id: String, + #[endianness(var)] + pub width: i32, + #[endianness(var)] + pub height: i32, + pub ingredient: RecipeIngredient, + #[vec_repr(u32)] + #[vec_endianness(var)] + pub result_items: Vec, + pub id: Uuid, + pub tag: String, + #[endianness(var)] + pub priority: i32, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/types/shaped_recipe.rs b/crates/proto/src/version/v662/types/shaped_recipe.rs new file mode 100644 index 00000000..ae76ba27 --- /dev/null +++ b/crates/proto/src/version/v662/types/shaped_recipe.rs @@ -0,0 +1,105 @@ +use crate::version::v662::types::{NetworkItemInstanceDescriptor, RecipeIngredient}; +use bedrockrs_proto_core::error::ProtoCodecError; +use bedrockrs_proto_core::{ProtoCodec, ProtoCodecVAR}; +use std::io::Cursor; +use std::mem::size_of; +use uuid::Uuid; + +#[derive(Clone, Debug)] +pub struct ShapedRecipe { + pub recipe_unique_id: String, + pub ingredient_grid: Vec>, + pub production_list: Vec, + pub recipe_id: Uuid, + pub recipe_tag: String, + pub priority: i32, +} + +impl ProtoCodec for ShapedRecipe { + fn proto_serialize(&self, stream: &mut Vec) -> Result<(), ProtoCodecError> { + self.recipe_unique_id.proto_serialize(stream)?; + + let x_len: u32 = self.ingredient_grid.len().try_into()?; + let y_len: u32 = self.ingredient_grid[0].len().try_into()?; + ::proto_serialize(&x_len, stream)?; + ::proto_serialize(&y_len, stream)?; + for y in &self.ingredient_grid { + for recipe in y { + recipe.proto_serialize(stream)?; + } + } + + ::proto_serialize(&self.production_list.len().try_into()?, stream)?; + for p in &self.production_list { + p.proto_serialize(stream)?; + } + + self.recipe_id.proto_serialize(stream)?; + self.recipe_tag.proto_serialize(stream)?; + ::proto_serialize(&self.priority, stream)?; + + Ok(()) + } + + fn proto_deserialize(stream: &mut Cursor<&[u8]>) -> Result { + let recipe_unique_id = String::proto_deserialize(stream)?; + + let ingredient_grid = { + let x_len = ::proto_deserialize(stream)?; + let y_len = ::proto_deserialize(stream)?; + let mut x_vec = Vec::with_capacity(x_len.try_into()?); + for _ in 0..x_len { + let mut y_vec = Vec::with_capacity(y_len.try_into()?); + for _ in 0..y_len { + y_vec.push(RecipeIngredient::proto_deserialize(stream)?); + } + x_vec.push(y_vec); + } + x_vec + }; + + let production_list = { + let len = ::proto_deserialize(stream)?; + let mut vec = Vec::with_capacity(len.try_into()?); + for _ in 0..len { + vec.push(NetworkItemInstanceDescriptor::proto_deserialize(stream)?); + } + vec + }; + + let recipe_id = Uuid::proto_deserialize(stream)?; + let recipe_tag = String::proto_deserialize(stream)?; + let priority = ::proto_deserialize(stream)?; + + Ok(Self { + recipe_unique_id, + ingredient_grid, + production_list, + recipe_id, + recipe_tag, + priority, + }) + } + + fn get_size_prediction(&self) -> usize { + self.recipe_unique_id.get_size_prediction() + + size_of::() + + size_of::() + + self + .ingredient_grid + .iter() + .map(|y| y + .iter() + .map(|i| + i.get_size_prediction()) + .sum::()) + .sum::() + + size_of::() + + self.production_list.iter().map(|y| y.get_size_prediction()).sum::() + + self.recipe_id.get_size_prediction() + + self.recipe_tag.get_size_prediction() + + self.priority.get_size_prediction() + } +} + +// VERIFY: ProtoCodec impl \ No newline at end of file diff --git a/crates/proto/src/version/v662/types/shapeless_chemistry_recipe.rs b/crates/proto/src/version/v662/types/shapeless_chemistry_recipe.rs new file mode 100644 index 00000000..52546e86 --- /dev/null +++ b/crates/proto/src/version/v662/types/shapeless_chemistry_recipe.rs @@ -0,0 +1,18 @@ +use crate::version::v662::types::{NetworkItemInstanceDescriptor, RecipeIngredient}; +use bedrockrs_macros::ProtoCodec; +use uuid::Uuid; + +#[derive(ProtoCodec, Clone, Debug)] +pub struct ShapelessChemistryRecipe { + pub recipe_id: String, + #[vec_repr(u32)] + #[vec_endianness(var)] + pub ingredients: Vec, + #[vec_repr(u32)] + #[vec_endianness(var)] + pub results: Vec, + pub id: Uuid, + pub tag: String, + #[endianness(var)] + pub priority: i32, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/types/shapeless_recipe.rs b/crates/proto/src/version/v662/types/shapeless_recipe.rs new file mode 100644 index 00000000..4738d879 --- /dev/null +++ b/crates/proto/src/version/v662/types/shapeless_recipe.rs @@ -0,0 +1,18 @@ +use crate::version::v662::types::{NetworkItemInstanceDescriptor, RecipeIngredient}; +use bedrockrs_macros::ProtoCodec; +use uuid::Uuid; + +#[derive(ProtoCodec, Clone, Debug)] +pub struct ShapelessRecipe { + pub recipe_unique_id: String, + #[vec_repr(u32)] + #[vec_endianness(var)] + pub ingredient_list: Vec, + #[vec_repr(u32)] + #[vec_endianness(var)] + pub production_list: Vec, + pub recipe_id: Uuid, + pub recipe_tag: String, + #[endianness(var)] + pub priority: i32, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/types/shulker_box_recipe.rs b/crates/proto/src/version/v662/types/shulker_box_recipe.rs new file mode 100644 index 00000000..50630619 --- /dev/null +++ b/crates/proto/src/version/v662/types/shulker_box_recipe.rs @@ -0,0 +1,18 @@ +use crate::version::v662::types::{NetworkItemInstanceDescriptor, RecipeIngredient}; +use bedrockrs_macros::ProtoCodec; +use uuid::Uuid; + +#[derive(ProtoCodec, Clone, Debug)] +pub struct ShulkerBoxRecipe { + pub recipe_unique_id: String, + #[vec_repr(u32)] + #[vec_endianness(var)] + pub ingredient_list: Vec, + #[vec_repr(u32)] + #[vec_endianness(var)] + pub production_list: Vec, + pub recipe_id: Uuid, + pub recipe_tag: String, + #[endianness(var)] + pub priority: i32, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/types/smithing_transform_recipe.rs b/crates/proto/src/version/v662/types/smithing_transform_recipe.rs new file mode 100644 index 00000000..15ea03a9 --- /dev/null +++ b/crates/proto/src/version/v662/types/smithing_transform_recipe.rs @@ -0,0 +1,12 @@ +use crate::version::v662::types::{NetworkItemInstanceDescriptor, RecipeIngredient}; +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +pub struct SmithingTransformRecipe { + pub recipe_id: String, + pub template_ingredient: RecipeIngredient, + pub base_ingredient: RecipeIngredient, + pub addition_ingredient: RecipeIngredient, + pub result: NetworkItemInstanceDescriptor, + pub tag: String, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/types/smithing_trim_recipe.rs b/crates/proto/src/version/v662/types/smithing_trim_recipe.rs new file mode 100644 index 00000000..da37a102 --- /dev/null +++ b/crates/proto/src/version/v662/types/smithing_trim_recipe.rs @@ -0,0 +1,11 @@ +use crate::version::v662::types::RecipeIngredient; +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +pub struct SmithingTrimRecipe { + pub recipe_id: String, + pub template_ingredient: RecipeIngredient, + pub base_ingredient: RecipeIngredient, + pub addition_ingredient: RecipeIngredient, + pub tag: String, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/types/spawn_settings.rs b/crates/proto/src/version/v662/types/spawn_settings.rs new file mode 100644 index 00000000..959f286f --- /dev/null +++ b/crates/proto/src/version/v662/types/spawn_settings.rs @@ -0,0 +1,10 @@ +use crate::version::v662::enums::SpawnBiomeType; +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +pub struct SpawnSettings { + pub spawn_type: SpawnBiomeType, + pub user_defined_biome_name: String, + #[endianness(var)] + pub dimension: i32, +} diff --git a/crates/proto/src/version/v662/types/structure_editor_data.rs b/crates/proto/src/version/v662/types/structure_editor_data.rs new file mode 100644 index 00000000..16b5ddf3 --- /dev/null +++ b/crates/proto/src/version/v662/types/structure_editor_data.rs @@ -0,0 +1,14 @@ +use crate::version::v662::enums::{StructureBlockType, StructureRedstoneSaveMode}; +use crate::version::v662::types::StructureSettings; +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +pub struct StructureEditorData { + pub structure_name: String, + pub data_field: String, + pub include_players: bool, + pub show_bounding_box: bool, + pub structure_block_type: StructureBlockType, + pub structure_settings: StructureSettings, + pub redstone_save_mode: StructureRedstoneSaveMode, +} diff --git a/crates/proto/src/version/v662/types/structure_settings.rs b/crates/proto/src/version/v662/types/structure_settings.rs new file mode 100644 index 00000000..1a82dacf --- /dev/null +++ b/crates/proto/src/version/v662/types/structure_settings.rs @@ -0,0 +1,26 @@ +use crate::version::v662::enums::{AnimationMode, Mirror, Rotation}; +use crate::version::v662::types::{ActorUniqueID, NetworkBlockPosition}; +use bedrockrs_macros::ProtoCodec; +use vek::Vec3; + +#[derive(ProtoCodec, Clone, Debug)] +pub struct StructureSettings { + pub structure_palette_name: String, + pub ignore_entities: bool, + pub ignore_locks: bool, + pub allow_non_ticking_player_and_ticking_area_chunks: bool, + pub structure_size: NetworkBlockPosition, + pub structure_offset: NetworkBlockPosition, + pub last_edit_player: ActorUniqueID, + pub rotation: Rotation, + pub mirror: Mirror, + pub animation_mode: AnimationMode, + #[endianness(le)] + pub animation_seconds: f32, + #[endianness(le)] + pub integrity_value: f32, + #[endianness(le)] + pub integrity_seed: u32, + #[endianness(le)] + pub rotation_pivot: Vec3, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/types/sub_chunk_pos.rs b/crates/proto/src/version/v662/types/sub_chunk_pos.rs new file mode 100644 index 00000000..e2ddac4e --- /dev/null +++ b/crates/proto/src/version/v662/types/sub_chunk_pos.rs @@ -0,0 +1,11 @@ +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +pub struct SubChunkPos { + #[endianness(var)] + pub x: i32, + #[endianness(var)] + pub y: i32, + #[endianness(var)] + pub z: i32, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/types/sub_chunk_pos_offset.rs b/crates/proto/src/version/v662/types/sub_chunk_pos_offset.rs new file mode 100644 index 00000000..85a83af9 --- /dev/null +++ b/crates/proto/src/version/v662/types/sub_chunk_pos_offset.rs @@ -0,0 +1,8 @@ +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +pub struct SubChunkPosOffset { + pub offset_x: i8, + pub offset_y: i8, + pub offset_z: i8, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/types/synced_player_movement_settings.rs b/crates/proto/src/version/v662/types/synced_player_movement_settings.rs new file mode 100644 index 00000000..99c2b1a7 --- /dev/null +++ b/crates/proto/src/version/v662/types/synced_player_movement_settings.rs @@ -0,0 +1,10 @@ +use crate::version::v662::enums::ServerAuthMovementMode; +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +pub struct SyncedPlayerMovementSettings { + pub authority_mode: ServerAuthMovementMode, + #[endianness(var)] + pub rewind_history_size: i32, + pub server_authoritative_block_breaking: bool, +} \ No newline at end of file diff --git a/crates/proto/src/version/v662/types/web_socket_packet_data.rs b/crates/proto/src/version/v662/types/web_socket_packet_data.rs new file mode 100644 index 00000000..ddf26533 --- /dev/null +++ b/crates/proto/src/version/v662/types/web_socket_packet_data.rs @@ -0,0 +1,6 @@ +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +pub struct WebSocketPacketData { + pub web_socket_server_uri: String, +} \ No newline at end of file diff --git a/crates/proto/src/version/v671/enums/mod.rs b/crates/proto/src/version/v671/enums/mod.rs new file mode 100644 index 00000000..6ed5e578 --- /dev/null +++ b/crates/proto/src/version/v671/enums/mod.rs @@ -0,0 +1,6 @@ +macro_rules! export { + ($name:ident) => { + mod $name; + pub use $name::*; + }; +} diff --git a/crates/proto/src/version/v671/gamepackets.rs b/crates/proto/src/version/v671/gamepackets.rs new file mode 100644 index 00000000..b4b710ba --- /dev/null +++ b/crates/proto/src/version/v671/gamepackets.rs @@ -0,0 +1,260 @@ +use crate::version::v662::packets::{ + ActorEventPacket, ActorPickRequestPacket, AddActorPacket, AddBehaviourTreePacket, + AddItemActorPacket, AddPaintingPacket, AddPlayerPacket, AddVolumeEntityPacket, + AgentActionEventPacket, AgentAnimationPacket, AnimateEntityPacket, AnimatePacket, + AnvilDamagePacket, AutomationClientConnectPacket, AvailableActorIdentifiersPacket, + AvailableCommandsPacket, BiomeDefinitionListPacket, BlockActorDataPacket, BlockEventPacket, + BlockPickRequestPacket, BookEditPacket, BossEventPacket, CameraInstructionPacket, CameraPacket, + CameraPresetsPacket, CameraShakePacket, ChangeDimensionPacket, ChangeMobPropertyPacket, + ChunkRadiusUpdatedPacket, ClientBoundDebugRendererPacket, ClientBoundMapItemDataPacket, + ClientCacheBlobStatusPacket, ClientCacheMissResponsePacket, ClientCacheStatusPacket, + ClientToServerHandshakePacket, CodeBuilderPacket, CodeBuilderSourcePacket, + CommandBlockUpdatePacket, CommandOutputPacket, CommandRequestPacket, CompletedUsingItemPacket, + CompressedBiomeDefinitionListPacket, ContainerClosePacket, ContainerOpenPacket, + ContainerSetDataPacket, CorrectPlayerMovePredictionPacket, CraftingDataPacket, + CreatePhotoPacket, CreativeContentPacket, DeathInfoPacket, DebugInfoPacket, + DimensionDataPacket, DisconnectPacket, EditorNetworkPacket, EduUriResourcePacket, + EducationSettingsPacket, EmoteListPacket, EmotePacket, FeatureRegistryPacket, + GameRulesChangedPacket, GameTestRequestPacket, GameTestResultsPacket, GuiDataPickItemPacket, + HurtArmorPacket, InteractPacket, InventoryContentPacket, InventorySlotPacket, + InventoryTransactionPacket, ItemComponentPacket, ItemStackRequestPacket, + ItemStackResponsePacket, LabTablePacket, LecternUpdatePacket, LegacyTelemetryEventPacket, + LessonProgressPacket, LevelChunkPacket, LevelEventGenericPacket, LevelEventPacket, + LevelSoundEventPacket, LevelSoundEventPacketV1, LevelSoundEventPacketV2, LoginPacket, + MapCreateLockedCopyPacket, MapInfoRequestPacket, MobArmorEquipmentPacket, MobEffectPacket, + MobEquipmentPacket, ModalFormRequestPacket, ModalFormResponsePacket, + MotionPredictionHintsPacket, MoveActorAbsolutePacket, MoveActorDeltaPacket, MovePlayerPacket, + MultiplayerSettingsPacket, NetworkChunkPublisherUpdatePacket, NetworkSettingsPacket, + NetworkStackLatencyPacket, NpcDialoguePacket, NpcRequestPacket, OnScreenTextureAnimationPacket, + OpenSignPacket, PacketViolationWarningPacket, PassengerJumpPacket, PhotoTransferPacket, + PlaySoundPacket, PlayStatusPacket, PlayerActionPacket, PlayerArmorDamagePacket, + PlayerAuthInputPacket, PlayerEnchantOptionsPacket, PlayerFogPacket, PlayerHotbarPacket, + PlayerInputPacket, PlayerListPacket, PlayerSkinPacket, PlayerStartItemCooldownPacket, + PlayerToggleCrafterSlotRequestPacket, PositionTrackingDBClientRequestPacket, + PositionTrackingDBServerBroadcastPacket, PurchaseReceiptPacket, RefreshEntitlementsPacket, + RemoveActorPacket, RemoveObjectivePacket, RemoveVolumeEntityPacket, RequestAbilityPacket, + RequestChunkRadiusPacket, RequestNetworkSettingsPacket, RequestPermissionsPacket, + ResourcePackChunkDataPacket, ResourcePackChunkRequestPacket, ResourcePackClientResponsePacket, + ResourcePackDataInfoPacket, ResourcePacksInfoPacket, RespawnPacket, ScriptMessagePacket, + ServerPlayerPostMovePositionPacket, ServerSettingsRequestPacket, ServerSettingsResponsePacket, + ServerStatsPacket, ServerToClientHandshakePacket, SetActorDataPacket, SetActorLinkPacket, + SetActorMotionPacket, SetCommandsEnabledPacket, SetDefaultGameTypePacket, SetDifficultyPacket, + SetDisplayObjectivePacket, SetHealthPacket, SetHudPacket, SetLastHurtByPacket, + SetLocalPlayerAsInitializedPacket, SetPlayerGameTypePacket, SetPlayerInventoryOptionsPacket, + SetScorePacket, SetScoreboardIdentityPacket, SetSpawnPositionPacket, SetTimePacket, + SetTitlePacket, SettingsCommandPacket, ShowCreditsPacket, ShowProfilePacket, + ShowStoreOfferPacket, SimpleEventPacket, SimulationTypePacket, SpawnExperienceOrbPacket, + SpawnParticleEffectPacket, StartGamePacket, StopSoundPacket, StructureBlockUpdatePacket, + StructureDataRequestPacket, StructureDataResponsePacket, SubChunkPacket, SubChunkRequestPacket, + SubClientLoginPacket, SyncActorPropertyPacket, TakeItemActorPacket, TextPacket, TickSyncPacket, + TickingAreaLoadStatusPacket, ToastRequestPacket, TransferPlayerPacket, TrimDataPacket, + UnlockedRecipesPacket, UpdateAbilitiesPacket, UpdateAdventureSettingsPacket, + UpdateAttributesPacket, UpdateBlockPacket, UpdateBlockSyncedPacket, + UpdateClientInputLocksPacket, UpdateEquipPacket, UpdateSoftEnumPacket, + UpdateSubChunkBlocksPacket, UpdateTradePacket, +}; +use crate::version::v662::{ + get_gamepacket_header_size_prediction, read_gamepacket_header, write_gamepacket_header, +}; +use crate::version::v671::packets::{ResourcePackStackPacket, UpdatePlayerGameTypePacket}; +use bedrockrs_macros::gamepackets; +use bedrockrs_proto_core::sub_client::SubClientID; +use std::io::{Cursor, Write}; + +gamepackets! { + Login: LoginPacket, + PlaySatus: PlayStatusPacket, + ServerToClientHandshake: ServerToClientHandshakePacket, + ClientToServerHandshake: ClientToServerHandshakePacket, + Disconnect: DisconnectPacket, + ResourcePacksInfo: ResourcePacksInfoPacket, + ResourcePackStack: ResourcePackStackPacket, + ResourcePackClientResponse: ResourcePackClientResponsePacket, + Text: TextPacket, + SetTime: SetTimePacket, + StartGame: StartGamePacket, + AddPlayer: AddPlayerPacket, + AddActor: AddActorPacket, + RemoveActor: RemoveActorPacket, + AddItemActor: AddItemActorPacket, + ServerPlayerPostMovePosition: ServerPlayerPostMovePositionPacket, + TakeItemActor: TakeItemActorPacket, + MoveActorAbsolute: MoveActorAbsolutePacket, + MovePlayer: MovePlayerPacket, + PassengerJump: PassengerJumpPacket, + UpdateBlock: UpdateBlockPacket, + AddPainting: AddPaintingPacket, + TickSync: TickSyncPacket, + LevelSoundEventV1: LevelSoundEventPacketV1, + LevelEvent: LevelEventPacket, + BlockEvent: BlockEventPacket, + ActorEvent: ActorEventPacket, + MobEffect: MobEffectPacket, + UpdateAttributes: UpdateAttributesPacket, + InventoryTransaction: InventoryTransactionPacket, + MobEquipment: MobEquipmentPacket, + MobArmorEquipment: MobArmorEquipmentPacket, + Interact: InteractPacket, + BlockPickRequest: BlockPickRequestPacket, + ActorPickRequest: ActorPickRequestPacket, + PlayerAction: PlayerActionPacket, + HurtArmor: HurtArmorPacket, + SetActorData: SetActorDataPacket, + SetActorMotion: SetActorMotionPacket, + SetActorLink: SetActorLinkPacket, + SetHealth: SetHealthPacket, + SetSpawnPosition: SetSpawnPositionPacket, + Animate: AnimatePacket, + Respawn: RespawnPacket, + ContainerOpen: ContainerOpenPacket, + ContainerClose: ContainerClosePacket, + PlayerHotbar: PlayerHotbarPacket, + InventoryContent: InventoryContentPacket, + InventorySlot: InventorySlotPacket, + ContainerSetData: ContainerSetDataPacket, + CraftingData: CraftingDataPacket, + GuiDataPickItem: GuiDataPickItemPacket, + BlockActorData: BlockActorDataPacket, + PlayerInput: PlayerInputPacket, + LevelChunk: LevelChunkPacket, + SetCommandsEnabled: SetCommandsEnabledPacket, + SetDifficulty: SetDifficultyPacket, + ChangeDimension: ChangeDimensionPacket, + SetPlayerGameType: SetPlayerGameTypePacket, + PlayerList: PlayerListPacket, + SimpleEvent: SimpleEventPacket, + LegacyTelemetryEvent: LegacyTelemetryEventPacket, + SpawnExperienceOrb: SpawnExperienceOrbPacket, + ClientboundMapItemData: ClientBoundMapItemDataPacket, + MapInfoRequest: MapInfoRequestPacket, + RequestChunkRadius: RequestChunkRadiusPacket, + ChunkRadiusUpdated: ChunkRadiusUpdatedPacket, + GameRulesChanged: GameRulesChangedPacket, + Camera: CameraPacket, + BossEvent: BossEventPacket, + ShowCredits: ShowCreditsPacket, + AvailableCommands: AvailableCommandsPacket, + CommandRequest: CommandRequestPacket, + CommandBlockUpdate: CommandBlockUpdatePacket, + CommandOutput: CommandOutputPacket, + UpdateTrade: UpdateTradePacket, + UpdateEquip: UpdateEquipPacket, + ResourcePackDataInfo: ResourcePackDataInfoPacket, + ResourcePackChunkData: ResourcePackChunkDataPacket, + ResourcePackChunkRequest: ResourcePackChunkRequestPacket, + TransferPlayer: TransferPlayerPacket, + PlaySound: PlaySoundPacket, + StopSound: StopSoundPacket, + SetTitle: SetTitlePacket, + AddBehaviourTree: AddBehaviourTreePacket, + StructureBlockUpdate: StructureBlockUpdatePacket, + ShowStoreOffer: ShowStoreOfferPacket, + PurchaseReceipt: PurchaseReceiptPacket, + PlayerSkin: PlayerSkinPacket, + SubClientLogin: SubClientLoginPacket, + AutomationClientConnect: AutomationClientConnectPacket, + SetLastHurtBy: SetLastHurtByPacket, + BookEdit: BookEditPacket, + NpcRequest: NpcRequestPacket, + PhotoTransfer: PhotoTransferPacket, + ModalFormRequest: ModalFormRequestPacket, + ModalFormResponse: ModalFormResponsePacket, + ServerSettingsRequest: ServerSettingsRequestPacket, + ServerSettingsResponse: ServerSettingsResponsePacket, + ShowProfile: ShowProfilePacket, + SetDefaultGameType: SetDefaultGameTypePacket, + RemoveObjective: RemoveObjectivePacket, + SetDisplayObjective: SetDisplayObjectivePacket, + SetScore: SetScorePacket, + LabTable: LabTablePacket, + UpdateBlockSynced: UpdateBlockSyncedPacket, + MoveActorDelta: MoveActorDeltaPacket, + SetScoreboardIdentity: SetScoreboardIdentityPacket, + SetLocalPlayerAsInitialized: SetLocalPlayerAsInitializedPacket, + UpdateSoftEnum: UpdateSoftEnumPacket, + NetworkStackLatency: NetworkStackLatencyPacket, + SpawnParticleEffect: SpawnParticleEffectPacket, + AvailableActorIdentifiers: AvailableActorIdentifiersPacket, + LevelSoundEventV2: LevelSoundEventPacketV2, + NetworkChunkPublisherUpdate: NetworkChunkPublisherUpdatePacket, + BiomeDefinitionList: BiomeDefinitionListPacket, + LevelSoundEvent: LevelSoundEventPacket, + LevelEventGeneric: LevelEventGenericPacket, + LecternUpdate: LecternUpdatePacket, + ClientCacheStatus: ClientCacheStatusPacket, + OnScreenTextureAnimation: OnScreenTextureAnimationPacket, + MapCreateLockedCopy: MapCreateLockedCopyPacket, + StructureDataRequest: StructureDataRequestPacket, + StructureDataResponse: StructureDataResponsePacket, + ClientCacheBlobStatus: ClientCacheBlobStatusPacket, + ClientCacheMissResponse: ClientCacheMissResponsePacket, + EducationSettings: EducationSettingsPacket, + Emote: EmotePacket, + MultiplayerSettings: MultiplayerSettingsPacket, + SettingsCommand: SettingsCommandPacket, + AnvilDamage: AnvilDamagePacket, + CompletedUsingItem: CompletedUsingItemPacket, + NetworkSettings: NetworkSettingsPacket, + PlayerAuthInput: PlayerAuthInputPacket, + CreativeContent: CreativeContentPacket, + PlayerEnchantOptions: PlayerEnchantOptionsPacket, + ItemStackRequest: ItemStackRequestPacket, + ItemStackResponse: ItemStackResponsePacket, + PlayerArmorDamage: PlayerArmorDamagePacket, + CodeBuilder: CodeBuilderPacket, + UpdatePlayerGameType: UpdatePlayerGameTypePacket, + EmoteList: EmoteListPacket, + PositionTrackingDbServerBroadcast: PositionTrackingDBServerBroadcastPacket, + PositionTrackingDbClientRequest: PositionTrackingDBClientRequestPacket, + DebugInfo: DebugInfoPacket, + PacketViolationWarning: PacketViolationWarningPacket, + MotionPredictionHints: MotionPredictionHintsPacket, + AnimateEntity: AnimateEntityPacket, + CameraShake: CameraShakePacket, + PlayerFog: PlayerFogPacket, + CorrectPlayerMovePrediction: CorrectPlayerMovePredictionPacket, + ItemComponent: ItemComponentPacket, + ClientboundDebugRenderer: ClientBoundDebugRendererPacket, + SyncActorProperty: SyncActorPropertyPacket, + AddVolumeEntity: AddVolumeEntityPacket, + RemoveVolumeEntity: RemoveVolumeEntityPacket, + SimulationType: SimulationTypePacket, + NpcDialogue: NpcDialoguePacket, + EduUriResource: EduUriResourcePacket, + CreatePhoto: CreatePhotoPacket, + UpdateSubChunkBlocks: UpdateSubChunkBlocksPacket, + SubChunk: SubChunkPacket, + SubChunkRequest: SubChunkRequestPacket, + PlayerStartItemCooldown: PlayerStartItemCooldownPacket, + ScriptMessage: ScriptMessagePacket, + CodeBuilderSource: CodeBuilderSourcePacket, + TickingAreaLoadStatus: TickingAreaLoadStatusPacket, + DimensionData: DimensionDataPacket, + AgentActionEvent: AgentActionEventPacket, + ChangeMobProperty: ChangeMobPropertyPacket, + LessonProgress: LessonProgressPacket, + RequestAbility: RequestAbilityPacket, + RequestPermissions: RequestPermissionsPacket, + ToastRequest: ToastRequestPacket, + UpdateAbilities: UpdateAbilitiesPacket, + UpdateAdventureSettings: UpdateAdventureSettingsPacket, + DeathInfo: DeathInfoPacket, + EditorNetwork: EditorNetworkPacket, + FeatureRegistry: FeatureRegistryPacket, + ServerStats: ServerStatsPacket, + RequestNetworkSettings: RequestNetworkSettingsPacket, + GameTestRequest: GameTestRequestPacket, + GameTestResults: GameTestResultsPacket, + UpdateClientInputLocks: UpdateClientInputLocksPacket, + CameraPresets: CameraPresetsPacket, + UnlockedRecipes: UnlockedRecipesPacket, + CameraInstruction: CameraInstructionPacket, + CompressedBiomeDefinitionList: CompressedBiomeDefinitionListPacket, + TrimData: TrimDataPacket, + OpenSign: OpenSignPacket, + AgentAnimation: AgentAnimationPacket, + RefreshEntitlements: RefreshEntitlementsPacket, + PlayerToggleCrafterSlotRequest: PlayerToggleCrafterSlotRequestPacket, + SetPlayerInventoryOptions: SetPlayerInventoryOptionsPacket, + SetHud: SetHudPacket +} diff --git a/crates/proto/src/version/v671/helper.rs b/crates/proto/src/version/v671/helper.rs new file mode 100644 index 00000000..b0ef8f0f --- /dev/null +++ b/crates/proto/src/version/v671/helper.rs @@ -0,0 +1,8 @@ +use crate::helper::ProtoHelper; +use crate::version::v671::gamepackets::GamePackets; + +pub struct ProtoHelperV671; + +impl ProtoHelper for ProtoHelperV671 { + type GamePacketType = GamePackets; +} diff --git a/crates/proto/src/version/v671/info.rs b/crates/proto/src/version/v671/info.rs new file mode 100644 index 00000000..4436a748 --- /dev/null +++ b/crates/proto/src/version/v671/info.rs @@ -0,0 +1 @@ +pub const PROTOCOL_VERSION: i32 = 671; diff --git a/crates/proto/src/version/v671/mod.rs b/crates/proto/src/version/v671/mod.rs new file mode 100644 index 00000000..01da27c3 --- /dev/null +++ b/crates/proto/src/version/v671/mod.rs @@ -0,0 +1,8 @@ +//! r/20_u8 + +pub mod enums; +pub mod gamepackets; +pub mod helper; +pub mod info; +pub mod packets; +pub mod types; diff --git a/crates/proto/src/version/v671/packets/mod.rs b/crates/proto/src/version/v671/packets/mod.rs new file mode 100644 index 00000000..41c6ed2b --- /dev/null +++ b/crates/proto/src/version/v671/packets/mod.rs @@ -0,0 +1,9 @@ +macro_rules! export { + ($name:ident) => { + mod $name; + pub use $name::*; + }; +} + +export!(update_player_game_type); +export!(resource_pack_stack); diff --git a/crates/proto/src/version/v671/packets/resource_pack_stack.rs b/crates/proto/src/version/v671/packets/resource_pack_stack.rs new file mode 100644 index 00000000..54eb3e95 --- /dev/null +++ b/crates/proto/src/version/v671/packets/resource_pack_stack.rs @@ -0,0 +1,24 @@ +use crate::version::v662::types::{BaseGameVersion, Experiments}; +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[derive(ProtoCodec, Clone, Debug)] +pub struct PackEntry { + pub id: String, + pub version: String, + pub sub_pack_name: String, +} + +#[gamepacket(id = 7)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct ResourcePackStackPacket { + pub texture_pack_required: bool, + #[vec_repr(u32)] + #[vec_endianness(var)] + pub addon_list: Vec, + #[vec_repr(u32)] + #[vec_endianness(var)] + pub texture_pack_list: Vec, + pub base_game_version: BaseGameVersion, + pub experiments: Experiments, + pub include_editor_packs: bool, +} \ No newline at end of file diff --git a/crates/proto/src/version/v671/packets/update_player_game_type.rs b/crates/proto/src/version/v671/packets/update_player_game_type.rs new file mode 100644 index 00000000..90cfa62a --- /dev/null +++ b/crates/proto/src/version/v671/packets/update_player_game_type.rs @@ -0,0 +1,12 @@ +use crate::version::v662::enums::GameType; +use crate::version::v662::types::ActorUniqueID; +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 151)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct UpdatePlayerGameTypePacket { + pub player_game_type: GameType, + pub target_player: ActorUniqueID, + #[endianness(var)] + pub player_replay_state_component_tick: u32, +} \ No newline at end of file diff --git a/crates/proto/src/version/v671/types/level_settings.rs b/crates/proto/src/version/v671/types/level_settings.rs new file mode 100644 index 00000000..f332e0bf --- /dev/null +++ b/crates/proto/src/version/v671/types/level_settings.rs @@ -0,0 +1,62 @@ +use crate::version::v662::enums::{ChatRestrictionLevel, Difficulty, EditorWorldType, EducationEditionOffer, GamePublishSetting, GameType, GeneratorType, PlayerPermissionLevel}; +use crate::version::v662::types::{BaseGameVersion, EduSharedUriResource, Experiments, GameRulesChangedPacketData, NetworkBlockPosition, SpawnSettings}; +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +pub struct LevelSettings { + #[endianness(le)] + pub seed: u64, + pub spawn_settings: SpawnSettings, + pub generator_type: GeneratorType, + pub game_type: GameType, + pub is_hardcore_enabled: bool, + pub game_difficulty: Difficulty, + pub default_spawn_block_position: NetworkBlockPosition, + pub achievements_disabled: bool, + pub editor_world_type: EditorWorldType, + pub is_created_in_editor: bool, + pub is_exported_from_editor: bool, + #[endianness(var)] + pub day_cycle_stop_time: i32, + pub education_edition_offer: EducationEditionOffer, + pub education_features_enabled: bool, + pub education_product_id: String, + #[endianness(le)] + pub rain_level: f32, + #[endianness(le)] + pub lightning_level: f32, + pub has_confirmed_platform_locked_content: bool, + pub multiplayer_enabled: bool, + pub lan_broadcasting_enabled: bool, + pub xbox_live_broadcast_setting: GamePublishSetting, + pub platform_broadcast_setting: GamePublishSetting, + pub commands_enabled: bool, + pub texture_packs_required: bool, + pub rule_data: GameRulesChangedPacketData, + pub experiments: Experiments, + pub bonus_chest_enabled: bool, + pub starting_map_enabled: bool, + pub player_permissions: PlayerPermissionLevel, + #[endianness(le)] + pub server_chunk_tick_range: i32, + pub locked_behaviour_pack: bool, + pub locked_resource_pack: bool, + pub from_locked_template: bool, + pub use_msa_gamer_tags: bool, + pub from_template: bool, + pub has_locked_template_settings: bool, + pub only_spawn_v1_villagers: bool, + pub persona_disabled: bool, + pub custom_skins_disabled: bool, + pub emote_chat_muted: bool, + pub base_game_version: BaseGameVersion, + #[endianness(le)] + pub limited_world_width: i32, + #[endianness(le)] + pub limited_world_depth: i32, + pub nether_type: bool, + pub edu_shared_uri_resource: EduSharedUriResource, + pub override_force_experimental_gameplay: bool, + pub chat_restriction_level: ChatRestrictionLevel, + pub disable_player_interactions: bool, +} \ No newline at end of file diff --git a/crates/proto/src/version/v671/types/mod.rs b/crates/proto/src/version/v671/types/mod.rs new file mode 100644 index 00000000..74591973 --- /dev/null +++ b/crates/proto/src/version/v671/types/mod.rs @@ -0,0 +1,10 @@ +macro_rules! export { + ($name:ident) => { + mod $name; + pub use $name::*; + }; +} + +export!(shaped_chemistry_recipe); +export!(shaped_recipe); +export!(level_settings); diff --git a/crates/proto/src/version/v671/types/shaped_chemistry_recipe.rs b/crates/proto/src/version/v671/types/shaped_chemistry_recipe.rs new file mode 100644 index 00000000..2e6a8d43 --- /dev/null +++ b/crates/proto/src/version/v671/types/shaped_chemistry_recipe.rs @@ -0,0 +1,21 @@ +use crate::version::v662::types::{NetworkItemInstanceDescriptor, RecipeIngredient}; +use bedrockrs_macros::ProtoCodec; +use uuid::Uuid; + +#[derive(ProtoCodec, Clone, Debug)] +pub struct ShapedChemistryRecipe { + pub recipe_id: String, + #[endianness(var)] + pub width: i32, + #[endianness(var)] + pub height: i32, + pub ingredient: RecipeIngredient, + #[vec_repr(u32)] + #[vec_endianness(var)] + pub result_items: Vec, + pub id: Uuid, + pub tag: String, + #[endianness(var)] + pub priority: i32, + pub assume_symmetry: bool, +} \ No newline at end of file diff --git a/crates/proto/src/version/v671/types/shaped_recipe.rs b/crates/proto/src/version/v671/types/shaped_recipe.rs new file mode 100644 index 00000000..74779f41 --- /dev/null +++ b/crates/proto/src/version/v671/types/shaped_recipe.rs @@ -0,0 +1,109 @@ +use crate::version::v662::types::{NetworkItemInstanceDescriptor, RecipeIngredient}; +use bedrockrs_proto_core::error::ProtoCodecError; +use bedrockrs_proto_core::{ProtoCodec, ProtoCodecVAR}; +use std::io::Cursor; +use std::mem::size_of; +use uuid::Uuid; + +#[derive(Clone, Debug)] +pub struct ShapedRecipe { + pub recipe_unique_id: String, + pub ingredient_grid: Vec>, + pub production_list: Vec, + pub recipe_id: Uuid, + pub recipe_tag: String, + pub priority: i32, + pub assume_symmetry: bool, +} + +impl ProtoCodec for ShapedRecipe { + fn proto_serialize(&self, stream: &mut Vec) -> Result<(), ProtoCodecError> { + self.recipe_unique_id.proto_serialize(stream)?; + + let x_len: u32 = self.ingredient_grid.len().try_into()?; + let y_len: u32 = self.ingredient_grid[0].len().try_into()?; + ::proto_serialize(&x_len, stream)?; + ::proto_serialize(&y_len, stream)?; + for y in &self.ingredient_grid { + for recipe in y { + recipe.proto_serialize(stream)?; + } + } + + ::proto_serialize(&self.production_list.len().try_into()?, stream)?; + for p in &self.production_list { + p.proto_serialize(stream)?; + } + + self.recipe_id.proto_serialize(stream)?; + self.recipe_tag.proto_serialize(stream)?; + ::proto_serialize(&self.priority, stream)?; + self.assume_symmetry.proto_serialize(stream)?; + + Ok(()) + } + + fn proto_deserialize(stream: &mut Cursor<&[u8]>) -> Result { + let recipe_unique_id = String::proto_deserialize(stream)?; + + let ingredient_grid = { + let x_len = ::proto_deserialize(stream)?; + let y_len = ::proto_deserialize(stream)?; + let mut x_vec = Vec::with_capacity(x_len.try_into()?); + for _ in 0..x_len { + let mut y_vec = Vec::with_capacity(y_len.try_into()?); + for _ in 0..y_len { + y_vec.push(RecipeIngredient::proto_deserialize(stream)?); + } + x_vec.push(y_vec); + } + x_vec + }; + + let production_list = { + let len = ::proto_deserialize(stream)?; + let mut vec = Vec::with_capacity(len.try_into()?); + for _ in 0..len { + vec.push(NetworkItemInstanceDescriptor::proto_deserialize(stream)?); + } + vec + }; + + let recipe_id = Uuid::proto_deserialize(stream)?; + let recipe_tag = String::proto_deserialize(stream)?; + let priority = ::proto_deserialize(stream)?; + let assume_symmetry = bool::proto_deserialize(stream)?; + + Ok(Self { + recipe_unique_id, + ingredient_grid, + production_list, + recipe_id, + recipe_tag, + priority, + assume_symmetry, + }) + } + + fn get_size_prediction(&self) -> usize { + self.recipe_unique_id.get_size_prediction() + + size_of::() + + size_of::() + + self + .ingredient_grid + .iter() + .map(|y| y + .iter() + .map(|i| + i.get_size_prediction()) + .sum::()) + .sum::() + + size_of::() + + self.production_list.iter().map(|y| y.get_size_prediction()).sum::() + + self.recipe_id.get_size_prediction() + + self.recipe_tag.get_size_prediction() + + self.priority.get_size_prediction() + } +} + +// VERIFY: ProtoCodec impl \ No newline at end of file diff --git a/crates/proto/src/version/v685/mod.rs b/crates/proto/src/version/v685/mod.rs new file mode 100644 index 00000000..94d85c13 --- /dev/null +++ b/crates/proto/src/version/v685/mod.rs @@ -0,0 +1 @@ +//! r/21_u0 diff --git a/crates/proto/src/version/v686/mod.rs b/crates/proto/src/version/v686/mod.rs new file mode 100644 index 00000000..06e921b9 --- /dev/null +++ b/crates/proto/src/version/v686/mod.rs @@ -0,0 +1 @@ +//! r/21_u0 (hotfix) diff --git a/crates/proto/src/version/v712/mod.rs b/crates/proto/src/version/v712/mod.rs new file mode 100644 index 00000000..02eb47e4 --- /dev/null +++ b/crates/proto/src/version/v712/mod.rs @@ -0,0 +1 @@ +//! r/21_u2 diff --git a/crates/proto/src/gamepackets.rs b/crates/proto/src/version/v729/gamepackets.rs similarity index 61% rename from crates/proto/src/gamepackets.rs rename to crates/proto/src/version/v729/gamepackets.rs index 7004d550..413407a6 100644 --- a/crates/proto/src/gamepackets.rs +++ b/crates/proto/src/version/v729/gamepackets.rs @@ -1,71 +1,50 @@ -#![allow(non_upper_case_globals)] - -use crate::packets::add_actor::AddActorPacket; -use crate::packets::add_painting::AddPaintingPacket; -use crate::packets::add_player::AddPlayerPacket; -use crate::packets::animate_player::AnimatePlayerPacket; -use crate::packets::boss_event::BossEventPacket; -use crate::packets::camera::CameraPacket; -use crate::packets::change_dimension::ChangeDimensionPacket; -use crate::packets::chunk_publisher_update::ChunkPublisherUpdatePacket; -use crate::packets::chunk_radius_request::ChunkRadiusRequestPacket; -use crate::packets::chunk_radius_updated::ChunkRadiusUpdatedPacket; -use crate::packets::client_cache_status::ClientCacheStatusPacket; -use crate::packets::command_request::CommandRequestPacket; -use crate::packets::container_close::ContainerClosePacket; -use crate::packets::container_open::ContainerOpenPacket; -use crate::packets::correct_player_move_prediction::CorrectPlayerMovePredictionPacket; -use crate::packets::debug_info::DebugInfoPacket; -use crate::packets::emote_list::EmoteListPacket; -use crate::packets::handshake_server_to_client::HandshakeServerToClientPacket; -use crate::packets::interact::InteractPacket; -use crate::packets::inventory_content::InventoryContentPacket; -use crate::packets::level_chunk::LevelChunkPacket; -use crate::packets::login::LoginPacket; -use crate::packets::mob_equipment::MobEquipmentPacket; -use crate::packets::modal_form_request::ModalFormRequestPacket; -use crate::packets::modal_form_response::ModalFormResponsePacket; -use crate::packets::network_settings::NetworkSettingsPacket; -use crate::packets::network_settings_request::NetworkSettingsRequestPacket; -use crate::packets::packet_violation_warning::PacketViolationWarningPacket; -use crate::packets::play_status::PlayStatusPacket; -use crate::packets::player_action::PlayerActionPacket; -use crate::packets::player_auth_input::PlayerAuthInputPacket; -use crate::packets::player_disconnect::DisconnectPlayerPacket; -use crate::packets::player_hotbar::PlayerHotbarPacket; -use crate::packets::player_move::MovePlayerPacket; -use crate::packets::player_transfer::TransferPlayerPacket; -use crate::packets::remove_actor::RemoveEntityPacket; -use crate::packets::resource_packs_info::ResourcePacksInfoPacket; -use crate::packets::resource_packs_response::ResourcePacksResponsePacket; -use crate::packets::resource_packs_stack::ResourcePacksStackPacket; -use crate::packets::respawn::RespawnPacket; -use crate::packets::server_player_post_move_position::ServerPlayerPostMovePositionPacket; -use crate::packets::server_settings_request::ServerSettingsRequestPacket; -use crate::packets::server_settings_response::ServerSettingsResponsePacket; -use crate::packets::set_commands_enabled::SetCommandsEnabledPacket; -use crate::packets::set_difficulty::SetDifficultyPacket; -use crate::packets::set_local_player_as_initialized::SetLocalPlayerAsInitializedPacket; -use crate::packets::set_player_gamemode::SetPlayerGamemode; -use crate::packets::set_time::SetTimePacket; -use crate::packets::set_title::SetTitlePacket; -use crate::packets::show_credits::ShowCreditsPacket; -use crate::packets::show_profile::ShowProfilePacket; -use crate::packets::start_game::StartGamePacket; -use crate::packets::text_message::TextMessagePacket; -use crate::packets::toast_request::ToastRequestPacket; -use crate::sub_client::SubClientID; -use bedrockrs_core::int::VAR; -use bedrockrs_proto_core::{error::ProtoCodecError, GamePacket, ProtoCodec}; -use bedrockrs_proto_macros::gamepackets; +use crate::version::v729::packets::handshake_client_to_server::HandshakeClientToServerPacket; +use crate::version::v729::packets::{ + add_actor::AddActorPacket, add_painting::AddPaintingPacket, add_player::AddPlayerPacket, + animate_player::AnimatePlayerPacket, + available_entity_identifiers::AvailableEntityIdentifiersPacket, + award_achievement::AwardAchievementPacket, boss_event::BossEventPacket, camera::CameraPacket, + camera_shake::CameraShakePacket, change_dimension::ChangeDimensionPacket, + chunk_publisher_update::ChunkPublisherUpdatePacket, + chunk_radius_request::ChunkRadiusRequestPacket, chunk_radius_updated::ChunkRadiusUpdatedPacket, + client_cache_status::ClientCacheStatusPacket, command_request::CommandRequestPacket, + container_close::ContainerClosePacket, container_open::ContainerOpenPacket, + correct_player_move_prediction::CorrectPlayerMovePredictionPacket, debug_info::DebugInfoPacket, + emote::EmotePacket, emote_list::EmoteListPacket, + handshake_server_to_client::HandshakeServerToClientPacket, interact::InteractPacket, + inventory_content::InventoryContentPacket, level_chunk::LevelChunkPacket, + loading_screen::LoadingScreenPacket, login::LoginPacket, mob_equipment::MobEquipmentPacket, + modal_form_request::ModalFormRequestPacket, modal_form_response::ModalFormResponsePacket, + network_settings::NetworkSettingsPacket, + network_settings_request::NetworkSettingsRequestPacket, open_sign::OpenSignPacket, + packet_violation_warning::PacketViolationWarningPacket, play_status::PlayStatusPacket, + player_action::PlayerActionPacket, player_auth_input::PlayerAuthInputPacket, + player_disconnect::DisconnectPlayerPacket, player_hotbar::PlayerHotbarPacket, + player_move::MovePlayerPacket, player_transfer::TransferPlayerPacket, + remove_actor::RemoveEntityPacket, resource_packs_info::ResourcePacksInfoPacket, + resource_packs_response::ResourcePacksResponsePacket, + resource_packs_stack::ResourcePacksStackPacket, respawn::RespawnPacket, + server_player_post_move_position::ServerPlayerPostMovePositionPacket, + server_settings_request::ServerSettingsRequestPacket, + server_settings_response::ServerSettingsResponsePacket, + set_commands_enabled::SetCommandsEnabledPacket, + set_local_player_as_initialized::SetLocalPlayerAsInitializedPacket, set_time::SetTimePacket, + set_title::SetTitlePacket, show_credits::ShowCreditsPacket, show_profile::ShowProfilePacket, + start_game::StartGamePacket, text_message::TextMessagePacket, + toast_request::ToastRequestPacket, update_difficulty::UpdateDifficultyPacket, + update_player_gamemode::UpdatePlayerGamemodePacket, +}; +use bedrockrs_macros::gamepackets; +use bedrockrs_proto_core::error::ProtoCodecError; +use bedrockrs_proto_core::sub_client::SubClientID; use std::io::{Cursor, Write}; -use crate::packets::loading_screen::LoadingScreenPacket; +use varint_rs::{VarintReader, VarintWriter}; gamepackets! { Login: LoginPacket, PlayStatus: PlayStatusPacket, - ServerToClientHandshake: HandshakeServerToClientPacket, - ClientToServerHandshake: _, + HandshakeServerToClient: HandshakeServerToClientPacket, + HandshakeClientToServer: HandshakeClientToServerPacket, DisconnectPlayer: DisconnectPlayerPacket, ResourcePacksInfo: ResourcePacksInfoPacket, ResourcePackStack: ResourcePacksStackPacket, @@ -118,9 +97,9 @@ gamepackets! { PlayerInput: _, LevelChunk: LevelChunkPacket, SetCommandsEnabled: SetCommandsEnabledPacket, - SetDifficulty: SetDifficultyPacket, + UpdateDifficulty: UpdateDifficultyPacket, ChangeDimension: ChangeDimensionPacket, - SetPlayerGamemode: SetPlayerGamemode, + UpdatePlayerGamemode: UpdatePlayerGamemodePacket, PlayerList: _, SimpleEvent: _, TelemetryEvent: _, @@ -174,7 +153,7 @@ gamepackets! { UpdateSoftEnum: _, Ping: _, SpawnParticleEffect: _, - AvailableEntityIdentifiers: _, + AvailableEntityIdentifiers: AvailableEntityIdentifiersPacket, LevelSoundEventV2: _, ChunkPublisherUpdate: ChunkPublisherUpdatePacket, BiomeDefinitionList: _, @@ -189,7 +168,7 @@ gamepackets! { ClientCacheBlobStatus: _, ClientCacheMissResponse: _, EducationSettings: _, - Emote: _, + Emote: EmotePacket, MultiplayerSettings: _, SettingsCommand: _, AnvilDamage: _, @@ -202,7 +181,8 @@ gamepackets! { ItemStackResponse: _, PlayerArmorDamage: _, CodeBuilder: _, - UpdatePlayerGamemode: _, + // TODO: Find a better name for this, else this collides with `UpdatePlayerGamemode` + UpdateOtherPlayerGamemode: _, EmoteList: EmoteListPacket, PositionTrackingDBServerBroadcast: _, PositionTrackingDBClientRequest: _, @@ -210,11 +190,11 @@ gamepackets! { PacketViolationWarning: PacketViolationWarningPacket, MotionPredictionHints: _, AnimateEntity: _, - CameraShake: _, + CameraShake: CameraShakePacket, PlayerFog: _, CorrectPlayerMovePrediction: CorrectPlayerMovePredictionPacket, ItemComponent: _, - ClientboundDebugRenderer: _, + DebugRenderer: _, SyncEntityProperty: _, AddVolumeEntity: _, RemoveVolumeEntity: _, @@ -249,46 +229,48 @@ gamepackets! { CameraPresets: _, UnlockedRecipes: _, CameraInstruction: _, - CompressedBiomeDefinitionList: _, + BiomeDefinitionListCompressed: _, TrimData: _, - OpenSign: _, + OpenSign: OpenSignPacket, AgentAnimation: _, RefreshEntitlements: _, PlayerToggleCrafterSlotRequest: _, SetPlayerInventoryOptions: _, SetHud: _, - AwardAchievement: _, + AwardAchievement: AwardAchievementPacket, CloseForm: _, LoadingScreen: LoadingScreenPacket, JigsawStructureData: _, CurrentStructureFeature: _, DiagnosticsPacket: _, + CameraAimAssist: _, + DynamicContainerRegistryCleanup: _, } fn read_gamepacket_header( stream: &mut Cursor<&[u8]>, ) -> Result<(u32, u16, SubClientID, SubClientID), ProtoCodecError> { // Read the gamepacket length - let length = VAR::::proto_deserialize(stream)?.into_inner(); + let length = stream.read_u32_varint()?; // Read the gamepacket header and parse it into an u16 // Since the (var)int is only storing 14 bytes we can treat it as an u16 // This is normally treated as u32 varint - let game_packet_header: u16 = VAR::::proto_deserialize(stream)?.into_inner(); + let gamepacket_header: u16 = stream.read_u16_varint()?; // Get the first 10 bits as the packet id // Can never be more than a 16-bit integer due to being 10-bits big // Gamepacket IDs through 200-299 are used for spin-offs, they are free to use for custom packets - let gamepacket_id = game_packet_header & 0b0000_0011_1111_1111; + let gamepacket_id = gamepacket_header & 0b0000_0011_1111_1111; // Get the next 2 bits as the sub client sender id // Can never be more than an 8-bit integer due to being 2 bits big let subclient_sender_id = - SubClientID::proto_from(((game_packet_header & 0b0000_1100_0000_0000) >> 10) as u8)?; + SubClientID::try_from(((gamepacket_header & 0b0000_1100_0000_0000) >> 10) as u8)?; // Get the next 2 bits as the sub client target id // Never more than an 8-bit integer due to being 2 bits big let subclient_target_id = - SubClientID::proto_from(((game_packet_header & 0b0011_0000_0000_0000) >> 12) as u8)?; + SubClientID::try_from(((gamepacket_header & 0b0011_0000_0000_0000) >> 12) as u8)?; Ok(( length, @@ -307,34 +289,38 @@ fn write_gamepacket_header( ) -> Result<(), ProtoCodecError> { // Since the (var)int is only storing 14 bytes, we can treat it as an u16 // This is normally treated as u32 varint - let mut game_packet_header: u16 = 0; + let mut gamepacket_header: u16 = 0; // Set the first 10 bits as the packet id // Can never be more than a 16-bit integer due to being 10-bits big // Gamepacket IDs through 200-299 are used for spin-offs, they are free to use for custom packets - game_packet_header |= 0b0000_0011_1111_1111 & gamepacket_id; + gamepacket_header |= 0b0000_0011_1111_1111 & gamepacket_id; // Set the next 2 bits as the sub client sender id // Never more than an 8-bit integer due to being 2 bits big - game_packet_header |= (subclient_sender_id.proto_to() as u16 >> 10) & 0b0000_1100_0000_0000; + gamepacket_header |= (Into::::into(subclient_sender_id) >> 10) & 0b0000_1100_0000_0000; // Set the next 2 bits as the sub client target id // Never more than an 8-bit integer due to being 2 bits big - game_packet_header |= (subclient_target_id.proto_to() as u16 >> 12) & 0b0011_0000_0000_0000; + gamepacket_header |= (Into::::into(subclient_target_id) >> 12) & 0b0011_0000_0000_0000; // Since the size of the header is also included in the batched packet size, // we need to write it to a temporary buffer - let mut game_packet_header_buf = Vec::new(); + let mut gamepacket_header_buf = Vec::new(); // Write the gamepacket header into temporary buffer - VAR::::new(game_packet_header).proto_serialize(&mut game_packet_header_buf)?; + gamepacket_header_buf.write_u16_varint(gamepacket_header)?; // Write the gamepacket length and the header length - VAR::::new(length + game_packet_header_buf.len() as u32).proto_serialize(stream)?; + stream.write_u32_varint(length + gamepacket_header_buf.len() as u32)?; // Write the final game packet header - stream - .write_all(game_packet_header_buf.as_slice()) - .map_err(ProtoCodecError::from)?; + stream.write_all(gamepacket_header_buf.as_slice())?; Ok(()) } + +const fn get_gamepacket_header_size_prediction() -> usize { + // 2 = gamepacket header (varint u32, only 14 bites can be treated as an u16) + // 4 = gamepacket length size (varint u32) + 2 + 4 +} diff --git a/crates/proto/src/version/v729/helper.rs b/crates/proto/src/version/v729/helper.rs new file mode 100644 index 00000000..900b21c3 --- /dev/null +++ b/crates/proto/src/version/v729/helper.rs @@ -0,0 +1,8 @@ +use crate::helper::ProtoHelper; +use crate::version::v729::gamepackets::GamePackets; + +pub struct ProtoHelperV729; + +impl ProtoHelper for ProtoHelperV729 { + type GamePacketType = GamePackets; +} diff --git a/crates/proto/src/version/v729/info.rs b/crates/proto/src/version/v729/info.rs new file mode 100644 index 00000000..4212241b --- /dev/null +++ b/crates/proto/src/version/v729/info.rs @@ -0,0 +1 @@ +pub const PROTOCOL_VERSION: i32 = 729; diff --git a/crates/proto/src/version/v729/mod.rs b/crates/proto/src/version/v729/mod.rs new file mode 100644 index 00000000..9b8675a2 --- /dev/null +++ b/crates/proto/src/version/v729/mod.rs @@ -0,0 +1,7 @@ +//! r/21_u3 + +pub mod gamepackets; +pub mod helper; +pub mod info; +pub mod packets; +pub mod types; diff --git a/crates/proto/src/packets/add_actor.rs b/crates/proto/src/version/v729/packets/add_actor.rs similarity index 52% rename from crates/proto/src/packets/add_actor.rs rename to crates/proto/src/version/v729/packets/add_actor.rs index 85ca9f73..19bad035 100644 --- a/crates/proto/src/packets/add_actor.rs +++ b/crates/proto/src/version/v729/packets/add_actor.rs @@ -1,14 +1,10 @@ -use bedrockrs_core::{ - int::{LE, VAR}, - Vec2, Vec3, -}; -use bedrockrs_proto_macros::{gamepacket, ProtoCodec}; -use bedrockrs_shared::{actor_runtime_id::ActorRuntimeID, actor_unique_id::ActorUniqueID}; - -use crate::types::{ +use crate::version::v729::types::{ actor_link::ActorLink, attribute::Attribute, data_item::DataItem, property_sync_data::PropertySyncData, }; +use bedrockrs_macros::{gamepacket, ProtoCodec}; +use bedrockrs_shared::{actor_runtime_id::ActorRuntimeID, actor_unique_id::ActorUniqueID}; +use vek::{Vec2, Vec3}; #[gamepacket(id = 12)] #[derive(ProtoCodec, Debug, Clone)] @@ -16,16 +12,24 @@ pub struct AddActorPacket { pub target_actor_id: ActorUniqueID, pub target_runtime_id: ActorRuntimeID, pub actor_type: String, - pub position: Vec3>, - pub velocity: Vec3>, - pub rotation: Vec2>, - pub y_head_rotation: LE, - pub y_body_rotation: LE, - #[len_repr(VAR::)] + #[endianness(le)] + pub position: Vec3, + #[endianness(le)] + pub velocity: Vec3, + #[endianness(le)] + pub rotation: Vec2, + #[endianness(le)] + pub y_head_rotation: f32, + #[endianness(le)] + pub y_body_rotation: f32, + #[vec_repr(u32)] + #[vec_endianness(var)] pub attributes: Vec, - #[len_repr(VAR::)] + #[vec_repr(u32)] + #[vec_endianness(var)] pub actor_data: Vec, pub synced_properties: PropertySyncData, - #[len_repr(VAR::)] + #[vec_repr(u32)] + #[vec_endianness(var)] pub actor_links: Vec, } diff --git a/crates/proto/src/packets/add_painting.rs b/crates/proto/src/version/v729/packets/add_painting.rs similarity index 62% rename from crates/proto/src/packets/add_painting.rs rename to crates/proto/src/version/v729/packets/add_painting.rs index 896e1bf8..4e683ec5 100644 --- a/crates/proto/src/packets/add_painting.rs +++ b/crates/proto/src/version/v729/packets/add_painting.rs @@ -1,16 +1,15 @@ -use bedrockrs_core::{ - int::{LE, VAR}, - Vec3, -}; -use bedrockrs_proto_macros::{gamepacket, ProtoCodec}; +use bedrockrs_macros::{gamepacket, ProtoCodec}; use bedrockrs_shared::{actor_runtime_id::ActorRuntimeID, actor_unique_id::ActorUniqueID}; +use vek::Vec3; #[gamepacket(id = 22)] #[derive(ProtoCodec, Debug, Clone)] pub struct AddPaintingPacket { pub target_actor_id: ActorUniqueID, pub target_runtime_id: ActorRuntimeID, - pub position: Vec3>, - pub direction: VAR, + #[endianness(le)] + pub position: Vec3, + #[endianness(var)] + pub direction: i32, pub motif: String, } diff --git a/crates/proto/src/version/v729/packets/add_player.rs b/crates/proto/src/version/v729/packets/add_player.rs new file mode 100644 index 00000000..5e6af8b7 --- /dev/null +++ b/crates/proto/src/version/v729/packets/add_player.rs @@ -0,0 +1,32 @@ +use crate::version::v729::types::ability_data::AbilityData; +use crate::version::v729::types::actor_link::ActorLink; +use crate::version::v729::types::item_stack_descriptor::ItemStackDescriptor; +use crate::version::v729::types::property_sync_data::PropertySyncData; +use bedrockrs_macros::{gamepacket, ProtoCodec}; +use bedrockrs_shared::actor_runtime_id::ActorRuntimeID; +use bedrockrs_shared::world::gamemode::Gamemode; +use uuid::Uuid; +use vek::Vec3; + +#[gamepacket(id = 12)] +#[derive(ProtoCodec, Debug, Clone)] +pub struct AddPlayerPacket { + pub uuid: Uuid, + pub name: String, + pub runtime_id: ActorRuntimeID, + pub platform_chat_id: String, + #[endianness(le)] + pub position: Vec3, + #[endianness(le)] + pub velocity: Vec3, + #[endianness(le)] + pub rotation: Vec3, + pub carried_item: ItemStackDescriptor, + pub gamemode: Gamemode, + // TODO: Impl SyncedActorDataEntityWrapper + pub synced_properties: PropertySyncData, + pub abilities: AbilityData, + #[vec_repr(u32)] + #[vec_endianness(var)] + pub links: Vec, +} diff --git a/crates/proto/src/packets/animate_player.rs b/crates/proto/src/version/v729/packets/animate_player.rs similarity index 73% rename from crates/proto/src/packets/animate_player.rs rename to crates/proto/src/version/v729/packets/animate_player.rs index 3b0aa06f..6f8db66e 100644 --- a/crates/proto/src/packets/animate_player.rs +++ b/crates/proto/src/version/v729/packets/animate_player.rs @@ -1,16 +1,17 @@ -use crate::types::animate_action::AnimateAction; -use bedrockrs_core::int::{LE, VAR}; +use crate::version::v729::types::animate_action::AnimateAction; +use bedrockrs_macros::gamepacket; use bedrockrs_proto_core::error::ProtoCodecError; use bedrockrs_proto_core::ProtoCodec; -use bedrockrs_proto_macros::gamepacket; use bedrockrs_shared::actor_runtime_id::ActorRuntimeID; +use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; use std::io::Cursor; +use varint_rs::{VarintReader, VarintWriter}; #[gamepacket(id = 44)] #[derive(Debug, Clone)] pub struct AnimatePlayerPacket { - action: AnimateAction, - target_runtime_id: ActorRuntimeID, + pub action: AnimateAction, + pub target_runtime_id: ActorRuntimeID, } impl ProtoCodec for AnimatePlayerPacket { @@ -25,25 +26,25 @@ impl ProtoCodec for AnimatePlayerPacket { AnimateAction::RowLeft => 129, }; - VAR::::new(action).proto_serialize(stream)?; + stream.write_i32_varint(action)?; self.target_runtime_id.proto_serialize(stream)?; if let AnimateAction::Swing { rowing_time } = self.action { - LE::new(rowing_time).proto_serialize(stream)?; + stream.write_f32::(rowing_time)?; } Ok(()) } fn proto_deserialize(stream: &mut Cursor<&[u8]>) -> Result { - let action = VAR::::proto_deserialize(stream)?.into_inner(); + let action = stream.read_i32_varint()?; let target_runtime_id = ActorRuntimeID::proto_deserialize(stream)?; let action = match action { 0 => AnimateAction::NoAction, 1 => AnimateAction::Swing { - rowing_time: LE::::proto_deserialize(stream)?.into_inner(), + rowing_time: stream.read_f32::()?, }, 3 => AnimateAction::WakeUp, 4 => AnimateAction::CriticalHit, @@ -53,7 +54,7 @@ impl ProtoCodec for AnimatePlayerPacket { other => { return Err(ProtoCodecError::InvalidEnumID( format!("{other:?}"), - String::from("AnimateAction"), + "AnimateAction", )) } }; @@ -63,4 +64,8 @@ impl ProtoCodec for AnimatePlayerPacket { target_runtime_id, }) } + + fn get_size_prediction(&self) -> usize { + todo!() + } } diff --git a/crates/proto/src/version/v729/packets/available_entity_identifiers.rs b/crates/proto/src/version/v729/packets/available_entity_identifiers.rs new file mode 100644 index 00000000..4e77e166 --- /dev/null +++ b/crates/proto/src/version/v729/packets/available_entity_identifiers.rs @@ -0,0 +1,9 @@ +use crate::version::v729::types::entity_info::EntityInfoList; +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 119)] +#[derive(ProtoCodec, Debug, Clone)] +pub struct AvailableEntityIdentifiersPacket { + #[nbt] + entity_info_list: EntityInfoList, +} diff --git a/crates/proto/src/version/v729/packets/award_achievement.rs b/crates/proto/src/version/v729/packets/award_achievement.rs new file mode 100644 index 00000000..4637e3eb --- /dev/null +++ b/crates/proto/src/version/v729/packets/award_achievement.rs @@ -0,0 +1,10 @@ +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 309)] +#[derive(ProtoCodec, Debug, Clone)] +pub struct AwardAchievementPacket { + /// Refers to the id of the achievement. + // TODO: Turn into enum if possible + #[endianness(le)] + id: i32, +} diff --git a/crates/proto/src/version/v729/packets/boss_event.rs b/crates/proto/src/version/v729/packets/boss_event.rs new file mode 100644 index 00000000..e42f1294 --- /dev/null +++ b/crates/proto/src/version/v729/packets/boss_event.rs @@ -0,0 +1,10 @@ +use crate::version::v729::types::event_type::BossEventType; +use bedrockrs_macros::{gamepacket, ProtoCodec}; +use bedrockrs_shared::actor_unique_id::ActorUniqueID; + +#[gamepacket(id = 74)] +#[derive(ProtoCodec, Debug, Clone)] +pub struct BossEventPacket { + pub actor_id: ActorUniqueID, + pub event_type: BossEventType, +} diff --git a/crates/proto/src/packets/camera.rs b/crates/proto/src/version/v729/packets/camera.rs similarity index 80% rename from crates/proto/src/packets/camera.rs rename to crates/proto/src/version/v729/packets/camera.rs index 3ee1e268..dccae75c 100644 --- a/crates/proto/src/packets/camera.rs +++ b/crates/proto/src/version/v729/packets/camera.rs @@ -1,4 +1,4 @@ -use bedrockrs_proto_macros::{gamepacket, ProtoCodec}; +use bedrockrs_macros::{gamepacket, ProtoCodec}; use bedrockrs_shared::actor_unique_id::ActorUniqueID; #[gamepacket(id = 73)] diff --git a/crates/proto/src/version/v729/packets/camera_shake.rs b/crates/proto/src/version/v729/packets/camera_shake.rs new file mode 100644 index 00000000..f079b284 --- /dev/null +++ b/crates/proto/src/version/v729/packets/camera_shake.rs @@ -0,0 +1,14 @@ +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 159)] +#[derive(ProtoCodec, Debug, Clone)] +pub struct CameraShakePacket { + #[endianness(le)] + pub intensity: f32, + #[endianness(le)] + pub seconds: f32, + // TODO: Turn into enum + pub shake_type: i8, + // TODO: Turn into enum + pub shake_action: i8, +} diff --git a/crates/proto/src/version/v729/packets/change_dimension.rs b/crates/proto/src/version/v729/packets/change_dimension.rs new file mode 100644 index 00000000..83b96396 --- /dev/null +++ b/crates/proto/src/version/v729/packets/change_dimension.rs @@ -0,0 +1,14 @@ +use bedrockrs_macros::{gamepacket, ProtoCodec}; +use bedrockrs_shared::world::dimension::Dimension; +use vek::Vec3; + +#[gamepacket(id = 61)] +#[derive(ProtoCodec, Debug, Clone)] +pub struct ChangeDimensionPacket { + pub dimension: Dimension, + #[endianness(le)] + pub pos: Vec3, + pub respawn: bool, + #[endianness(le)] + pub loading_screen: Option, +} diff --git a/crates/proto/src/version/v729/packets/chunk_publisher_update.rs b/crates/proto/src/version/v729/packets/chunk_publisher_update.rs new file mode 100644 index 00000000..814ff9e4 --- /dev/null +++ b/crates/proto/src/version/v729/packets/chunk_publisher_update.rs @@ -0,0 +1,15 @@ +use crate::version::v729::types::block_pos::BlockPos; +use crate::version::v729::types::chunk_pos::ChunkPos; +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 121)] +#[derive(ProtoCodec, Debug, Clone)] +pub struct ChunkPublisherUpdatePacket { + pub position: BlockPos, + #[endianness(var)] + pub radius: u32, + #[vec_repr(u32)] + // TODO: Figure out if it is a var or le + #[vec_endianness(var)] + pub saved_chunks: Vec, +} diff --git a/crates/proto/src/packets/chunk_radius_request.rs b/crates/proto/src/version/v729/packets/chunk_radius_request.rs similarity index 52% rename from crates/proto/src/packets/chunk_radius_request.rs rename to crates/proto/src/version/v729/packets/chunk_radius_request.rs index cfc0bd4d..875203a4 100644 --- a/crates/proto/src/packets/chunk_radius_request.rs +++ b/crates/proto/src/version/v729/packets/chunk_radius_request.rs @@ -1,9 +1,9 @@ -use bedrockrs_core::int::VAR; -use bedrockrs_proto_macros::{gamepacket, ProtoCodec}; +use bedrockrs_macros::{gamepacket, ProtoCodec}; #[gamepacket(id = 69)] #[derive(ProtoCodec, Debug, Clone)] pub struct ChunkRadiusRequestPacket { - pub chunk_radius: VAR, + #[endianness(var)] + pub chunk_radius: i32, pub chunk_radius_max: u8, } diff --git a/crates/proto/src/version/v729/packets/chunk_radius_updated.rs b/crates/proto/src/version/v729/packets/chunk_radius_updated.rs new file mode 100644 index 00000000..a837f89d --- /dev/null +++ b/crates/proto/src/version/v729/packets/chunk_radius_updated.rs @@ -0,0 +1,8 @@ +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 70)] +#[derive(ProtoCodec, Debug, Clone)] +pub struct ChunkRadiusUpdatedPacket { + #[endianness(var)] + pub chunk_radius: i32, +} diff --git a/crates/proto/src/packets/client_cache_status.rs b/crates/proto/src/version/v729/packets/client_cache_status.rs similarity index 71% rename from crates/proto/src/packets/client_cache_status.rs rename to crates/proto/src/version/v729/packets/client_cache_status.rs index 668d694b..6b77e6ee 100644 --- a/crates/proto/src/packets/client_cache_status.rs +++ b/crates/proto/src/version/v729/packets/client_cache_status.rs @@ -1,4 +1,4 @@ -use bedrockrs_proto_macros::{gamepacket, ProtoCodec}; +use bedrockrs_macros::{gamepacket, ProtoCodec}; #[gamepacket(id = 129)] #[derive(ProtoCodec, Debug, Copy, Clone)] diff --git a/crates/proto/src/version/v729/packets/command_request.rs b/crates/proto/src/version/v729/packets/command_request.rs new file mode 100644 index 00000000..60f93b2d --- /dev/null +++ b/crates/proto/src/version/v729/packets/command_request.rs @@ -0,0 +1,12 @@ +use crate::version::v729::types::command_origin_data::CommandOriginData; +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 77)] +#[derive(ProtoCodec, Debug, Clone)] +pub struct CommandRequestPacket { + pub command: String, + pub command_origin: CommandOriginData, + pub is_internal_source: bool, + #[endianness(var)] + pub version: i32, +} diff --git a/crates/proto/src/version/v729/packets/container_close.rs b/crates/proto/src/version/v729/packets/container_close.rs new file mode 100644 index 00000000..1cf2cfb9 --- /dev/null +++ b/crates/proto/src/version/v729/packets/container_close.rs @@ -0,0 +1,11 @@ +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +use crate::version::v729::types::container_type::ContainerType; + +#[gamepacket(id = 47)] +#[derive(ProtoCodec, Debug, Clone)] +pub struct ContainerClosePacket { + pub container_id: u8, + pub container_type: ContainerType, + pub server_initiated_close: bool, +} diff --git a/crates/proto/src/packets/container_open.rs b/crates/proto/src/version/v729/packets/container_open.rs similarity index 63% rename from crates/proto/src/packets/container_open.rs rename to crates/proto/src/version/v729/packets/container_open.rs index b55a0d3a..7a6a4a7e 100644 --- a/crates/proto/src/packets/container_open.rs +++ b/crates/proto/src/version/v729/packets/container_open.rs @@ -1,7 +1,9 @@ -use bedrockrs_proto_macros::{gamepacket, ProtoCodec}; +use bedrockrs_macros::{gamepacket, ProtoCodec}; use bedrockrs_shared::actor_unique_id::ActorUniqueID; -use crate::types::{block_pos::BlockPos, container_id::ContainerID, container_type::ContainerType}; +use crate::version::v729::types::{ + block_pos::BlockPos, container_id::ContainerID, container_type::ContainerType, +}; #[gamepacket(id = 46)] #[derive(ProtoCodec, Debug, Clone)] diff --git a/crates/proto/src/version/v729/packets/correct_player_move_prediction.rs b/crates/proto/src/version/v729/packets/correct_player_move_prediction.rs new file mode 100644 index 00000000..0b6ed791 --- /dev/null +++ b/crates/proto/src/version/v729/packets/correct_player_move_prediction.rs @@ -0,0 +1,16 @@ +use bedrockrs_macros::{gamepacket, ProtoCodec}; +use vek::Vec3; + +#[gamepacket(id = 161)] +#[derive(ProtoCodec, Debug, Clone)] +pub struct CorrectPlayerMovePredictionPacket { + // TODO: Possibly turn this into an enum + pub prediction_type: u8, + #[endianness(le)] + pub pos: Vec3, + #[endianness(le)] + pub pos_delta: Vec3, + pub on_ground: bool, + #[endianness(le)] + pub tick: u64, +} diff --git a/crates/proto/src/packets/debug_info.rs b/crates/proto/src/version/v729/packets/debug_info.rs similarity index 78% rename from crates/proto/src/packets/debug_info.rs rename to crates/proto/src/version/v729/packets/debug_info.rs index bc7b6c6f..b52ed94b 100644 --- a/crates/proto/src/packets/debug_info.rs +++ b/crates/proto/src/version/v729/packets/debug_info.rs @@ -1,4 +1,4 @@ -use bedrockrs_proto_macros::{gamepacket, ProtoCodec}; +use bedrockrs_macros::{gamepacket, ProtoCodec}; use bedrockrs_shared::actor_unique_id::ActorUniqueID; #[gamepacket(id = 155)] diff --git a/crates/proto/src/version/v729/packets/emote.rs b/crates/proto/src/version/v729/packets/emote.rs new file mode 100644 index 00000000..0b86f303 --- /dev/null +++ b/crates/proto/src/version/v729/packets/emote.rs @@ -0,0 +1,17 @@ +use bedrockrs_macros::{gamepacket, ProtoCodec}; +use bedrockrs_shared::actor_runtime_id::ActorRuntimeID; +use xuid::Xuid; + +#[gamepacket(id = 138)] +#[derive(ProtoCodec, Debug, Clone)] +pub struct EmotePacket { + runtime_id: ActorRuntimeID, + emote_id: String, + /// Emote length measured in ticks. + #[endianness(var)] + emote_length: u32, + xuid: Xuid, + platform_id: String, + // TODO: Turn this into an enum + flags: i8, +} diff --git a/crates/proto/src/version/v729/packets/emote_list.rs b/crates/proto/src/version/v729/packets/emote_list.rs new file mode 100644 index 00000000..cec453c3 --- /dev/null +++ b/crates/proto/src/version/v729/packets/emote_list.rs @@ -0,0 +1,12 @@ +use bedrockrs_macros::{gamepacket, ProtoCodec}; +use bedrockrs_shared::actor_runtime_id::ActorRuntimeID; +use uuid::Uuid; + +#[gamepacket(id = 152)] +#[derive(ProtoCodec, Debug, Clone)] +pub struct EmoteListPacket { + pub runtime_id: ActorRuntimeID, + #[vec_repr(u32)] + #[vec_endianness(var)] + pub emote_piece_ids: Vec, +} diff --git a/crates/proto/src/version/v729/packets/handshake_client_to_server.rs b/crates/proto/src/version/v729/packets/handshake_client_to_server.rs new file mode 100644 index 00000000..2177ec36 --- /dev/null +++ b/crates/proto/src/version/v729/packets/handshake_client_to_server.rs @@ -0,0 +1,5 @@ +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 4)] +#[derive(Debug, Clone, ProtoCodec)] +pub struct HandshakeClientToServerPacket {} diff --git a/crates/proto/src/packets/handshake_server_to_client.rs b/crates/proto/src/version/v729/packets/handshake_server_to_client.rs similarity index 83% rename from crates/proto/src/packets/handshake_server_to_client.rs rename to crates/proto/src/version/v729/packets/handshake_server_to_client.rs index dd63c1c1..7eb3a90a 100644 --- a/crates/proto/src/packets/handshake_server_to_client.rs +++ b/crates/proto/src/version/v729/packets/handshake_server_to_client.rs @@ -1,11 +1,13 @@ use std::collections::BTreeMap; use std::io::Cursor; +use bedrockrs_macros::gamepacket; use bedrockrs_proto_core::error::ProtoCodecError; use bedrockrs_proto_core::ProtoCodec; -use bedrockrs_proto_macros::gamepacket; use serde_json::Value; +// Yeah we aren't supporting secure things rn... + #[gamepacket(id = 3)] #[derive(Debug, Clone)] pub struct HandshakeServerToClientPacket { @@ -13,11 +15,15 @@ pub struct HandshakeServerToClientPacket { } impl ProtoCodec for HandshakeServerToClientPacket { - fn proto_serialize(&self, buf: &mut Vec) -> Result<(), ProtoCodecError> { + fn proto_serialize(&self, _stream: &mut Vec) -> Result<(), ProtoCodecError> { + todo!() + } + + fn proto_deserialize(_stream: &mut Cursor<&[u8]>) -> Result { todo!() } - fn proto_deserialize(cursor: &mut Cursor<&[u8]>) -> Result { + fn get_size_prediction(&self) -> usize { todo!() } } diff --git a/crates/proto/src/packets/interact.rs b/crates/proto/src/version/v729/packets/interact.rs similarity index 72% rename from crates/proto/src/packets/interact.rs rename to crates/proto/src/version/v729/packets/interact.rs index b1dd3380..7fef7e52 100644 --- a/crates/proto/src/packets/interact.rs +++ b/crates/proto/src/version/v729/packets/interact.rs @@ -1,11 +1,10 @@ -use crate::types::interact_action::InteractAction; -use bedrockrs_core::int::LE; -use bedrockrs_core::Vec3; +use crate::version::v729::types::interact_action::InteractAction; +use bedrockrs_macros::gamepacket; use bedrockrs_proto_core::error::ProtoCodecError; -use bedrockrs_proto_core::ProtoCodec; -use bedrockrs_proto_macros::gamepacket; +use bedrockrs_proto_core::{ProtoCodec, ProtoCodecLE}; use bedrockrs_shared::actor_runtime_id::ActorRuntimeID; use std::io::Cursor; +use vek::Vec3; #[gamepacket(id = 33)] #[derive(Debug, Clone)] @@ -26,8 +25,8 @@ impl ProtoCodec for InteractPacket { u8::proto_serialize(&action, stream)?; - if let InteractAction::InteractUpdate(pos) = self.action { - pos.to_le().proto_serialize(stream)?; + if let InteractAction::InteractUpdate(pos) | InteractAction::StopRiding(pos) = self.action { + ProtoCodecLE::proto_serialize(&pos, stream)?; } Ok(()) @@ -41,14 +40,12 @@ impl ProtoCodec for InteractPacket { let action = match action { 0 => InteractAction::Invalid, 3 => { - let pos = Vec3::>::proto_deserialize(stream)?; - let pos = Vec3::::from_le(pos); + let pos = as ProtoCodecLE>::proto_deserialize(stream)?; InteractAction::StopRiding(pos) } 4 => { - let pos = Vec3::>::proto_deserialize(stream)?; - let pos = Vec3::::from_le(pos); + let pos = as ProtoCodecLE>::proto_deserialize(stream)?; InteractAction::InteractUpdate(pos) } @@ -57,7 +54,7 @@ impl ProtoCodec for InteractPacket { other => { return Err(ProtoCodecError::InvalidEnumID( format!("{other:?}"), - String::from("InteractAction"), + "InteractAction", )) } }; @@ -67,4 +64,8 @@ impl ProtoCodec for InteractPacket { target_runtime_id, }) } + + fn get_size_prediction(&self) -> usize { + todo!() + } } diff --git a/crates/proto/src/version/v729/packets/inventory_content.rs b/crates/proto/src/version/v729/packets/inventory_content.rs new file mode 100644 index 00000000..3e06383a --- /dev/null +++ b/crates/proto/src/version/v729/packets/inventory_content.rs @@ -0,0 +1,14 @@ +use crate::version::v729::types::item_stack_descriptor::ItemStackDescriptor; +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 49)] +#[derive(ProtoCodec, Debug, Clone)] +pub struct InventoryContentPacket { + #[endianness(var)] + pub inventory_id: u32, + #[vec_repr(u32)] + #[vec_endianness(var)] + pub slots: Vec, + // TODO: Add FullContainerName + // TODO: Add DynamicContainerSize +} diff --git a/crates/proto/src/version/v729/packets/level_chunk.rs b/crates/proto/src/version/v729/packets/level_chunk.rs new file mode 100644 index 00000000..8a21f78b --- /dev/null +++ b/crates/proto/src/version/v729/packets/level_chunk.rs @@ -0,0 +1,57 @@ +use crate::version::v729::types::chunk_pos::ChunkPos; +use bedrockrs_macros::gamepacket; +use bedrockrs_proto_core::error::ProtoCodecError; +use bedrockrs_proto_core::ProtoCodec; +use bedrockrs_shared::world::dimension::Dimension; +use varint_rs::VarintWriter; + +#[gamepacket(id = 58)] +#[derive(Debug, Clone)] +pub struct LevelChunkPacket { + pub chunk_position: ChunkPos, + pub dimension_id: Dimension, + pub sub_chunk_count: u32, + pub cache_enabled: bool, + pub serialized_chunk_data: Vec, + pub client_needs_to_request_subchunks: bool, + pub client_request_subchunk_limit: i32, +} + +impl ProtoCodec for LevelChunkPacket { + fn proto_serialize(&self, stream: &mut Vec) -> Result<(), ProtoCodecError> { + self.chunk_position.proto_serialize(stream)?; + self.dimension_id.proto_serialize(stream)?; + + if !self.client_needs_to_request_subchunks { + stream.write_u32_varint(self.sub_chunk_count)?; + } else if self.client_request_subchunk_limit >= 0 { + stream.write_u32_varint(u32::MAX - 1)?; + stream.write_i32_varint(self.client_request_subchunk_limit)?; + } else { + stream.write_u32_varint(u32::MAX)?; + } + + self.cache_enabled.proto_serialize(stream)?; + if self.cache_enabled { + todo!("implement sending with cached blobs.") + } + + let len = self.serialized_chunk_data.len().try_into()?; + + stream.write_u32_varint(len)?; + stream.extend_from_slice(&self.serialized_chunk_data); + + println!("finish"); + + Ok(()) + } + + fn proto_deserialize(_stream: &mut std::io::Cursor<&[u8]>) -> Result { + todo!() + } + + fn get_size_prediction(&self) -> usize { + // TODO + 1 + } +} diff --git a/crates/proto/src/version/v729/packets/loading_screen.rs b/crates/proto/src/version/v729/packets/loading_screen.rs new file mode 100644 index 00000000..a0a05b29 --- /dev/null +++ b/crates/proto/src/version/v729/packets/loading_screen.rs @@ -0,0 +1,10 @@ +use crate::version::v729::types::loading_screen_action::LoadingScreenAction; +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 312)] +#[derive(ProtoCodec, Debug, Clone)] +pub struct LoadingScreenPacket { + pub screen_action: LoadingScreenAction, + #[endianness(le)] + pub screen_id: Option, +} diff --git a/crates/proto/src/version/v729/packets/login.rs b/crates/proto/src/version/v729/packets/login.rs new file mode 100644 index 00000000..e7479c5c --- /dev/null +++ b/crates/proto/src/version/v729/packets/login.rs @@ -0,0 +1,11 @@ +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +use crate::version::v729::types::connection_request::ConnectionRequest; + +#[gamepacket(id = 1)] +#[derive(ProtoCodec, Debug, Clone)] +pub struct LoginPacket { + #[endianness(be)] + pub client_network_version: i32, + pub connection_request: ConnectionRequest, +} diff --git a/crates/proto/src/version/v729/packets/mob_equipment.rs b/crates/proto/src/version/v729/packets/mob_equipment.rs new file mode 100644 index 00000000..1c2874c6 --- /dev/null +++ b/crates/proto/src/version/v729/packets/mob_equipment.rs @@ -0,0 +1,14 @@ +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +use crate::version::v729::types::item_stack_descriptor::ItemStackDescriptor; + +#[gamepacket(id = 31)] +#[derive(ProtoCodec, Debug, Clone)] +pub struct MobEquipmentPacket { + #[endianness(var)] + pub runtime_id: i32, + pub item_stack_descriptor: ItemStackDescriptor, + pub slot: u8, + pub selected_slot: u8, + pub container: u8, +} diff --git a/crates/proto/src/packets/mod.rs b/crates/proto/src/version/v729/packets/mod.rs similarity index 86% rename from crates/proto/src/packets/mod.rs rename to crates/proto/src/version/v729/packets/mod.rs index b104a4da..67524229 100644 --- a/crates/proto/src/packets/mod.rs +++ b/crates/proto/src/version/v729/packets/mod.rs @@ -2,8 +2,11 @@ pub mod add_actor; pub mod add_painting; pub mod add_player; pub mod animate_player; +pub mod available_entity_identifiers; +pub mod award_achievement; pub mod boss_event; pub mod camera; +pub mod camera_shake; pub mod change_dimension; pub mod chunk_publisher_update; pub mod chunk_radius_request; @@ -14,17 +17,21 @@ pub mod container_close; pub mod container_open; pub mod correct_player_move_prediction; pub mod debug_info; +pub mod emote; pub mod emote_list; +pub mod handshake_client_to_server; pub mod handshake_server_to_client; pub mod interact; pub mod inventory_content; pub mod level_chunk; +pub mod loading_screen; pub mod login; pub mod mob_equipment; pub mod modal_form_request; pub mod modal_form_response; pub mod network_settings; pub mod network_settings_request; +pub mod open_sign; pub mod packet_violation_warning; pub mod play_status; pub mod player_action; @@ -42,9 +49,7 @@ pub mod server_player_post_move_position; pub mod server_settings_request; pub mod server_settings_response; pub mod set_commands_enabled; -pub mod set_difficulty; pub mod set_local_player_as_initialized; -pub mod set_player_gamemode; pub mod set_time; pub mod set_title; pub mod show_credits; @@ -52,4 +57,5 @@ pub mod show_profile; pub mod start_game; pub mod text_message; pub mod toast_request; -pub mod loading_screen; +pub mod update_difficulty; +pub mod update_player_gamemode; diff --git a/crates/proto/src/packets/modal_form_request.rs b/crates/proto/src/version/v729/packets/modal_form_request.rs similarity index 53% rename from crates/proto/src/packets/modal_form_request.rs rename to crates/proto/src/version/v729/packets/modal_form_request.rs index 4bcc5315..5f33029c 100644 --- a/crates/proto/src/packets/modal_form_request.rs +++ b/crates/proto/src/version/v729/packets/modal_form_request.rs @@ -1,9 +1,9 @@ -use bedrockrs_core::int::VAR; -use bedrockrs_proto_macros::{gamepacket, ProtoCodec}; +use bedrockrs_macros::{gamepacket, ProtoCodec}; #[gamepacket(id = 100)] #[derive(ProtoCodec, Debug, Clone)] pub struct ModalFormRequestPacket { - pub form_id: VAR, + #[endianness(var)] + pub form_id: u32, pub form_json: String, } diff --git a/crates/proto/src/packets/modal_form_response.rs b/crates/proto/src/version/v729/packets/modal_form_response.rs similarity index 52% rename from crates/proto/src/packets/modal_form_response.rs rename to crates/proto/src/version/v729/packets/modal_form_response.rs index 2231ea62..b4685727 100644 --- a/crates/proto/src/packets/modal_form_response.rs +++ b/crates/proto/src/version/v729/packets/modal_form_response.rs @@ -1,11 +1,11 @@ -use crate::types::modal_form_cancel_reason::ModalFormCancelReason; -use bedrockrs_core::int::VAR; -use bedrockrs_proto_macros::{gamepacket, ProtoCodec}; +use crate::version::v729::types::modal_form_cancel_reason::ModalFormCancelReason; +use bedrockrs_macros::{gamepacket, ProtoCodec}; #[gamepacket(id = 101)] #[derive(ProtoCodec, Debug, Clone)] pub struct ModalFormResponsePacket { - pub form_id: VAR, + #[endianness(var)] + pub form_id: u32, pub form_response: Option, pub cancel_reason: Option, } diff --git a/crates/proto/src/packets/network_settings.rs b/crates/proto/src/version/v729/packets/network_settings.rs similarity index 53% rename from crates/proto/src/packets/network_settings.rs rename to crates/proto/src/version/v729/packets/network_settings.rs index 3517c3fb..83428e77 100644 --- a/crates/proto/src/packets/network_settings.rs +++ b/crates/proto/src/version/v729/packets/network_settings.rs @@ -1,5 +1,4 @@ -use bedrockrs_core::int::LE; -use bedrockrs_proto_macros::{gamepacket, ProtoCodec}; +use bedrockrs_macros::{gamepacket, ProtoCodec}; #[gamepacket(id = 143)] #[derive(ProtoCodec, Debug, Clone)] @@ -8,15 +7,21 @@ pub struct NetworkSettingsPacket { /// - 0 is "disable compression" /// - 1 is "compress everything 1 byte or larger" (so everything) /// - others are just the normal threshold - pub compression_threshold: LE, + #[endianness(le)] + pub compression_threshold: u16, /// Determines the compression Algorithm used /// - 0x0000 is Zlib /// - 0x0001 is Snappy /// - 0xFFFF is No compression /// - /// All 3 compression Algorithms are supported - pub compression_algorithm: LE, - pub client_throttle_enabled: bool, + /// All three compression Algorithms are supported + #[endianness(le)] + pub compression_algorithm: u16, + // TODO: Document what this field does + pub client_throttle: bool, + // TODO: Document what this field does pub client_throttle_threshold: u8, - pub client_throttle_scalar: LE, + // TODO: Document what this field does + #[endianness(le)] + pub client_throttle_scalar: f32, } diff --git a/crates/proto/src/version/v729/packets/network_settings_request.rs b/crates/proto/src/version/v729/packets/network_settings_request.rs new file mode 100644 index 00000000..2705f3e4 --- /dev/null +++ b/crates/proto/src/version/v729/packets/network_settings_request.rs @@ -0,0 +1,8 @@ +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 193)] +#[derive(ProtoCodec, Debug, Copy, Clone)] +pub struct NetworkSettingsRequestPacket { + #[endianness(be)] + pub client_network_version: i32, +} diff --git a/crates/proto/src/version/v729/packets/open_sign.rs b/crates/proto/src/version/v729/packets/open_sign.rs new file mode 100644 index 00000000..c3ec96ef --- /dev/null +++ b/crates/proto/src/version/v729/packets/open_sign.rs @@ -0,0 +1,9 @@ +use crate::version::v729::types::block_pos::BlockPos; +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 303)] +#[derive(ProtoCodec, Debug, Clone)] +pub struct OpenSignPacket { + pos: BlockPos, + front: bool, +} diff --git a/crates/proto/src/version/v729/packets/packet_violation_warning.rs b/crates/proto/src/version/v729/packets/packet_violation_warning.rs new file mode 100644 index 00000000..55bdd3e7 --- /dev/null +++ b/crates/proto/src/version/v729/packets/packet_violation_warning.rs @@ -0,0 +1,13 @@ +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 156)] +#[derive(ProtoCodec, Debug, Clone)] +pub struct PacketViolationWarningPacket { + #[endianness(var)] + pub kind: i32, + #[endianness(var)] + pub severity: i32, + #[endianness(var)] + pub violating_packet_id: i32, + pub context: String, +} diff --git a/crates/proto/src/packets/play_status.rs b/crates/proto/src/version/v729/packets/play_status.rs similarity index 53% rename from crates/proto/src/packets/play_status.rs rename to crates/proto/src/version/v729/packets/play_status.rs index 601d0a4a..6151db94 100644 --- a/crates/proto/src/packets/play_status.rs +++ b/crates/proto/src/version/v729/packets/play_status.rs @@ -1,6 +1,5 @@ -use bedrockrs_proto_macros::{gamepacket, ProtoCodec}; - -use crate::types::play_status::PlayStatusType; +use crate::version::v729::types::play_status::PlayStatusType; +use bedrockrs_macros::{gamepacket, ProtoCodec}; #[gamepacket(id = 2)] #[derive(ProtoCodec, Debug, Copy, Clone)] diff --git a/crates/proto/src/packets/player_action.rs b/crates/proto/src/version/v729/packets/player_action.rs similarity index 60% rename from crates/proto/src/packets/player_action.rs rename to crates/proto/src/version/v729/packets/player_action.rs index 37268413..c7acd42b 100644 --- a/crates/proto/src/packets/player_action.rs +++ b/crates/proto/src/version/v729/packets/player_action.rs @@ -1,6 +1,5 @@ -use crate::types::{block_pos::BlockPos, player_action_type::PlayerActionType}; -use bedrockrs_core::int::VAR; -use bedrockrs_proto_macros::{gamepacket, ProtoCodec}; +use crate::version::v729::types::{block_pos::BlockPos, player_action_type::PlayerActionType}; +use bedrockrs_macros::{gamepacket, ProtoCodec}; use bedrockrs_shared::actor_runtime_id::ActorRuntimeID; #[gamepacket(id = 36)] @@ -10,5 +9,6 @@ pub struct PlayerActionPacket { pub action: PlayerActionType, pub block_pos: BlockPos, pub result_pos: BlockPos, - pub face: VAR, + #[endianness(var)] + pub face: i32, } diff --git a/crates/proto/src/packets/player_auth_input.rs b/crates/proto/src/version/v729/packets/player_auth_input.rs similarity index 69% rename from crates/proto/src/packets/player_auth_input.rs rename to crates/proto/src/version/v729/packets/player_auth_input.rs index 11e3b87c..de313d24 100644 --- a/crates/proto/src/packets/player_auth_input.rs +++ b/crates/proto/src/version/v729/packets/player_auth_input.rs @@ -1,34 +1,34 @@ -use crate::types::input_data::InputData; -use crate::types::input_mode::InputMode; -use crate::types::interaction_model::InteractionModel; -use crate::types::play_mode::PlayMode; -use bedrockrs_core::int::{LE, VAR}; -use bedrockrs_core::{Vec2, Vec3}; +use crate::version::v729::types::block_actions::BlockActions; +use crate::version::v729::types::input_data::InputData; +use crate::version::v729::types::input_mode::InputMode; +use crate::version::v729::types::interaction_model::InteractionModel; +use crate::version::v729::types::play_mode::PlayMode; +use bedrockrs_macros::gamepacket; use bedrockrs_proto_core::error::ProtoCodecError; -use bedrockrs_proto_core::ProtoCodec; -use bedrockrs_proto_macros::gamepacket; +use bedrockrs_proto_core::{ProtoCodec, ProtoCodecLE, ProtoCodecVAR}; use bedrockrs_shared::actor_unique_id::ActorUniqueID; use std::io::Cursor; +use vek::{Vec2, Vec3}; #[gamepacket(id = 144)] #[derive(Debug, Clone)] pub struct PlayerAuthInputPacket { - pub rotation: Vec2>, - pub position: Vec3>, - pub move_vec: Vec2>, - pub head_rotation: LE, + pub rotation: Vec2, + pub position: Vec3, + pub move_vec: Vec2, + pub head_rotation: f32, pub input_data: InputData, pub input_mode: InputMode, pub play_mode: PlayMode, pub interaction_model: InteractionModel, - /// Which simulation frame client is on. Used to match corrections - pub client_tick: VAR, + /// Which simulation frame client is on, used to match corrections + pub client_tick: u64, /// Velocity - pub pos_delta: Vec3>, - pub analog_move_vec: Vec2>, + pub pos_delta: Vec3, + pub analog_move_vec: Vec2, } -macro_rules! set_bit { +macro_rules! _set_bit { ($v:expr, $bit:expr) => { $v |= 1 << $bit }; @@ -41,19 +41,19 @@ macro_rules! get_bit { } impl ProtoCodec for PlayerAuthInputPacket { - fn proto_serialize(&self, stream: &mut Vec) -> Result<(), ProtoCodecError> { + fn proto_serialize(&self, _stream: &mut Vec) -> Result<(), ProtoCodecError> { todo!() } fn proto_deserialize(stream: &mut Cursor<&[u8]>) -> Result { - let rotation = Vec2::>::proto_deserialize(stream)?; - let position = Vec3::>::proto_deserialize(stream)?; - let move_vec = Vec2::>::proto_deserialize(stream)?; - let head_rotation = LE::::proto_deserialize(stream)?; + let rotation = as ProtoCodecLE>::proto_deserialize(stream)?; + let position = as ProtoCodecLE>::proto_deserialize(stream)?; + let move_vec = as ProtoCodecLE>::proto_deserialize(stream)?; + let head_rotation = ::proto_deserialize(stream)?; - let input_data = VAR::::proto_deserialize(stream)?.into_inner(); + let input_data = ::proto_deserialize(stream)?; let input_mode = InputMode::proto_deserialize(stream)?; - let play_mode_int = VAR::::proto_deserialize(stream)?.into_inner(); + let play_mode_int = ::proto_deserialize(stream)?; let interaction_model = InteractionModel::proto_deserialize(stream)?; let play_mode = match play_mode_int { @@ -62,7 +62,7 @@ impl ProtoCodec for PlayerAuthInputPacket { 2 => PlayMode::Screen, 3 => PlayMode::Viewer, 4 => { - let vr_gaze_direction = ProtoCodec::proto_deserialize(stream)?; + let vr_gaze_direction = ProtoCodecLE::proto_deserialize(stream)?; PlayMode::Reality(vr_gaze_direction) } 5 => PlayMode::Placement, @@ -72,18 +72,18 @@ impl ProtoCodec for PlayerAuthInputPacket { other => { return Err(ProtoCodecError::InvalidEnumID( other.to_string(), - String::from("PlayMode"), + "PlayMode", )) } }; - let client_tick = VAR::::proto_deserialize(stream)?; - let pos_delta = Vec3::>::proto_deserialize(stream)?; + let client_tick = ::proto_deserialize(stream)?; + let pos_delta = as ProtoCodecLE>::proto_deserialize(stream)?; let input_data = InputData { ascend: get_bit!(input_data, 0), descend: get_bit!(input_data, 1), - north_jump_DEPRECATED: get_bit!(input_data, 2), + north_jump_deprecated: get_bit!(input_data, 2), jump_down: get_bit!(input_data, 3), sprint_down: get_bit!(input_data, 4), change_height: get_bit!(input_data, 5), @@ -116,7 +116,11 @@ impl ProtoCodec for PlayerAuthInputPacket { start_gliding: get_bit!(input_data, 32), stop_gliding: get_bit!(input_data, 33), perform_item_interaction: get_bit!(input_data, 34), - perform_block_actions: get_bit!(input_data, 35), + perform_block_actions: if get_bit!(input_data, 35) { + Some(BlockActions::proto_deserialize(stream)?) + } else { + None + }, perform_item_stack_request: get_bit!(input_data, 36), handled_teleport: get_bit!(input_data, 37), emoting: get_bit!(input_data, 38), @@ -128,9 +132,8 @@ impl ProtoCodec for PlayerAuthInputPacket { client_ack_server_data: get_bit!(input_data, 44), is_in_client_predicted_vehicle: { if get_bit!(input_data, 45) { - let vehicle_rotation = Vec2::>::proto_deserialize(stream)?; + let vehicle_rotation = as ProtoCodecLE>::proto_deserialize(stream)?; let client_predicted_vehicle = ActorUniqueID::proto_deserialize(stream)?; - Some((vehicle_rotation, client_predicted_vehicle)) } else { None @@ -142,7 +145,7 @@ impl ProtoCodec for PlayerAuthInputPacket { input_num: get_bit!(input_data, 49), }; - let analog_move_vec = Vec2::>::proto_deserialize(stream)?; + let analog_move_vec = as ProtoCodecLE>::proto_deserialize(stream)?; Ok(Self { rotation, @@ -158,4 +161,8 @@ impl ProtoCodec for PlayerAuthInputPacket { analog_move_vec, }) } + + fn get_size_prediction(&self) -> usize { + todo!() + } } diff --git a/crates/proto/src/version/v729/packets/player_disconnect.rs b/crates/proto/src/version/v729/packets/player_disconnect.rs new file mode 100644 index 00000000..25a0cdad --- /dev/null +++ b/crates/proto/src/version/v729/packets/player_disconnect.rs @@ -0,0 +1,180 @@ +use std::io::Cursor; + +use bedrockrs_macros::{gamepacket, ProtoCodec}; +use bedrockrs_proto_core::error::ProtoCodecError; +use bedrockrs_proto_core::ProtoCodec; + +#[gamepacket(id = 5)] +#[derive(Debug, Clone)] +pub struct DisconnectPlayerPacket { + /// Seems to have no effect on the message being shown. + /// It is just for telemetry. + pub reason: DisconnectReason, + pub message: Option, +} + +// ProtoCodec +impl ProtoCodec for DisconnectPlayerPacket { + fn proto_serialize(&self, buf: &mut Vec) -> Result<(), ProtoCodecError> + where + Self: Sized, + { + self.reason.proto_serialize(buf)?; + + if let Some(text) = &self.message { + bool::proto_serialize(&false, buf)?; + text.proto_serialize(buf)?; + } else { + // Skip message + bool::proto_serialize(&true, buf)?; + } + + Ok(()) + } + + fn proto_deserialize(cursor: &mut Cursor<&[u8]>) -> Result + where + Self: Sized, + { + let reason = DisconnectReason::proto_deserialize(cursor)?; + + // Read if the message should be skipped + let skip_message = bool::proto_deserialize(cursor)?; + + let message = if !skip_message { + Some(String::proto_deserialize(cursor)?) + } else { + None + }; + + Ok(Self { reason, message }) + } + + fn get_size_prediction(&self) -> usize { + self.reason.get_size_prediction() + self.message.get_size_prediction() + } +} + +#[derive(ProtoCodec, Debug, Clone)] +#[enum_repr(i32)] +#[enum_endianness(var)] +pub enum DisconnectReason { + Unknown = 0, + CantConnectNoInternet = 1, + NoPermissions = 2, + UnrecoverableError = 3, + ThirdPartyBlocked = 4, + ThirdPartyNoInternet = 5, + ThirdPartyBadIP = 6, + ThirdPartyNoServerOrServerLocked = 7, + VersionMismatch = 8, + SkinIssue = 9, + InviteSessionNotFound = 10, + EduLevelSettingsMissing = 11, + LocalServerNotFound = 12, + LegacyDisconnect = 13, + UserLeaveGameAttempted = 14, + PlatformLockedSkinsError = 15, + RealmsWorldUnassigned = 16, + RealmsServerCantConnect = 17, + RealmsServerHidden = 18, + RealmsServerDisabledBeta = 19, + RealmsServerDisabled = 20, + CrossPlatformDisabled = 21, + CantConnect = 22, + SessionNotFound = 23, + ClientSettingsIncompatibleWithServer = 24, + ServerFull = 25, + InvalidPlatformSkin = 26, + EditionVersionMismatch = 27, + EditionMismatch = 28, + LevelNewerThanExeVersion = 29, + NoFailOccurred = 30, + BannedSkin = 31, + Timeout = 32, + ServerNotFound = 33, + OutdatedServer = 34, + OutdatedClient = 35, + NoPremiumPlatform = 36, + MultiplayerDisabled = 37, + NoWiFi = 38, + WorldCorruption = 39, + NoReason = 40, + Disconnected = 41, + InvalidPlayer = 42, + LoggedInOtherLocation = 43, + ServerIdConflict = 44, + NotAllowed = 45, + NotAuthenticated = 46, + InvalidTenant = 47, + UnknownPacket = 48, + UnexpectedPacket = 49, + InvalidCommandRequestPacket = 50, + HostSuspended = 51, + LoginPacketNoRequest = 52, + LoginPacketNoCert = 53, + MissingClient = 54, + Kicked = 55, + KickedForExploit = 56, + KickedForIdle = 57, + ResourcePackProblem = 58, + IncompatiblePack = 59, + OutOfStorage = 60, + InvalidLevel = 61, + #[deprecated] + DisconnectPacket = 62, + BlockMismatch = 63, + InvalidHeights = 64, + InvalidWidths = 65, + ConnectionLost = 66, + ZombieConnection = 67, + Shutdown = 68, + #[deprecated] + ReasonNotSet = 69, + LoadingStateTimeout = 70, + ResourcePackLoadingFailed = 71, + SearchingForSessionLoadingScreenFailed = 72, + NetherNetProtocolVersion = 73, + SubsystemStatusError = 74, + EmptyAuthFromDiscovery = 75, + EmptyUrlFromDiscovery = 76, + ExpiredAuthFromDiscovery = 77, + UnknownSignalServiceSignInFailure = 78, + XBLJoinLobbyFailure = 79, + UnspecifiedClientInstanceDisconnection = 80, + NetherNetSessionNotFound = 81, + NetherNetCreatePeerConnection = 82, + NetherNetICE = 83, + NetherNetConnectRequest = 84, + NetherNetConnectResponse = 85, + NetherNetNegotiationTimeout = 86, + NetherNetInactivityTimeout = 87, + StaleConnectionBeingReplaced = 88, + RealmsSessionNotFoundDeprecated = 89, + BadPacket = 90, + NetherNetFailedToCreateOffer = 91, + NetherNetFailedToCreateAnswer = 92, + NetherNetFailedToSetLocalDescription = 93, + NetherNetFailedToSetRemoteDescription = 94, + NetherNetNegotiationTimeoutWaitingForResponse = 95, + NetherNetNegotiationTimeoutWaitingForAccept = 96, + NetherNetIncomingConnectionIgnored = 97, + NetherNetSignalingParsingFailure = 98, + NetherNetSignalingUnknownError = 99, + NetherNetSignalingUnicastDeliveryFailed = 100, + NetherNetSignalingBroadcastDeliveryFailed = 101, + NetherNetSignalingGenericDeliveryFailed = 102, + EditorMismatchEditorWorld = 103, + EditorMismatchVanillaWorld = 104, + WorldTransferNotPrimaryClient = 105, + RequestServerShutdown = 106, + ClientGameSetupCancelled = 107, + ClientGameSetupFailed = 108, + NoVenue = 109, + NetherNetSignalingSignInFailed = 110, + SessionAccessDenied = 111, + ServiceSignInIssue = 112, + NetherNetNoSignalingChannel = 113, + NetherNetNotLoggedIn = 114, + NetherNetClientSignalingError = 115, +} diff --git a/crates/proto/src/version/v729/packets/player_hotbar.rs b/crates/proto/src/version/v729/packets/player_hotbar.rs new file mode 100644 index 00000000..55bbc9d8 --- /dev/null +++ b/crates/proto/src/version/v729/packets/player_hotbar.rs @@ -0,0 +1,11 @@ +use crate::version::v729::types::container_id::ContainerID; +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 48)] +#[derive(ProtoCodec, Debug, Clone)] +pub struct PlayerHotbarPacket { + #[endianness(var)] + pub selected_slot: u32, + pub container_id: ContainerID, + pub should_select_slot: bool, +} diff --git a/crates/proto/src/packets/player_move.rs b/crates/proto/src/version/v729/packets/player_move.rs similarity index 51% rename from crates/proto/src/packets/player_move.rs rename to crates/proto/src/version/v729/packets/player_move.rs index f047c4b3..79413630 100644 --- a/crates/proto/src/packets/player_move.rs +++ b/crates/proto/src/version/v729/packets/player_move.rs @@ -1,51 +1,50 @@ -use bedrockrs_core::int::{LE, VAR}; -use bedrockrs_core::Vec2; -use bedrockrs_core::Vec3; +use bedrockrs_macros::gamepacket; use bedrockrs_proto_core::error::ProtoCodecError; -use bedrockrs_proto_core::ProtoCodec; -use bedrockrs_proto_macros::gamepacket; +use bedrockrs_proto_core::{ProtoCodec, ProtoCodecLE, ProtoCodecVAR}; use bedrockrs_shared::actor_runtime_id::ActorRuntimeID; use std::io::Cursor; +use vek::Vec2; +use vek::Vec3; #[gamepacket(id = 19)] #[derive(Debug, Clone)] pub struct MovePlayerPacket { pub player_runtime_id: ActorRuntimeID, - pub position: Vec3>, - pub rotation: Vec2>, - pub head_rotation: LE, + pub position: Vec3, + pub rotation: Vec2, + pub head_rotation: f32, pub position_mode: u8, pub on_ground: bool, pub riding_runtime_id: ActorRuntimeID, - pub teleportation_cause: Option>, - pub source_actor_type: Option>, - pub tick: VAR, + pub teleportation_cause: Option, + pub source_actor_type: Option, + pub tick: i64, } impl ProtoCodec for MovePlayerPacket { - fn proto_serialize(&self, stream: &mut Vec) -> Result<(), ProtoCodecError> { + fn proto_serialize(&self, _stream: &mut Vec) -> Result<(), ProtoCodecError> { unimplemented!(); } fn proto_deserialize(stream: &mut Cursor<&[u8]>) -> Result { let player_runtime_id = ActorRuntimeID::proto_deserialize(stream)?; - let position = Vec3::>::proto_deserialize(stream)?; - let rotation = Vec2::>::proto_deserialize(stream)?; - let head_rotation = LE::::proto_deserialize(stream)?; + let position = as ProtoCodecLE>::proto_deserialize(stream)?; + let rotation = as ProtoCodecLE>::proto_deserialize(stream)?; + let head_rotation = ::proto_deserialize(stream)?; let position_mode = u8::proto_deserialize(stream)?; let on_ground = bool::proto_deserialize(stream)?; let riding_runtime_id = ActorRuntimeID::proto_deserialize(stream)?; - let mut teleportation_cause: Option> = None; - let mut source_actor_type: Option> = None; + let mut teleportation_cause: Option = None; + let mut source_actor_type: Option = None; // teleportation mode.. if position_mode == 2 { - teleportation_cause = Some(LE::::proto_deserialize(stream)?); - source_actor_type = Some(LE::::proto_deserialize(stream)?); + teleportation_cause = Some(::proto_deserialize(stream)?); + source_actor_type = Some(::proto_deserialize(stream)?); } - let tick = VAR::::proto_deserialize(stream)?; + let tick = ::proto_deserialize(stream)?; Ok(Self { player_runtime_id, @@ -60,4 +59,8 @@ impl ProtoCodec for MovePlayerPacket { tick, }) } + + fn get_size_prediction(&self) -> usize { + todo!() + } } diff --git a/crates/proto/src/version/v729/packets/player_transfer.rs b/crates/proto/src/version/v729/packets/player_transfer.rs new file mode 100644 index 00000000..fab5aa84 --- /dev/null +++ b/crates/proto/src/version/v729/packets/player_transfer.rs @@ -0,0 +1,9 @@ +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 85)] +#[derive(ProtoCodec, Debug, Clone)] +pub struct TransferPlayerPacket { + addr: String, + #[endianness(le)] + port: u16, +} diff --git a/crates/proto/src/packets/remove_actor.rs b/crates/proto/src/version/v729/packets/remove_actor.rs similarity index 77% rename from crates/proto/src/packets/remove_actor.rs rename to crates/proto/src/version/v729/packets/remove_actor.rs index 680c7fe6..bc98c07d 100644 --- a/crates/proto/src/packets/remove_actor.rs +++ b/crates/proto/src/version/v729/packets/remove_actor.rs @@ -1,4 +1,4 @@ -use bedrockrs_proto_macros::{gamepacket, ProtoCodec}; +use bedrockrs_macros::{gamepacket, ProtoCodec}; use bedrockrs_shared::actor_unique_id::ActorUniqueID; #[gamepacket(id = 14)] diff --git a/crates/proto/src/version/v729/packets/resource_packs_info.rs b/crates/proto/src/version/v729/packets/resource_packs_info.rs new file mode 100644 index 00000000..8f31a272 --- /dev/null +++ b/crates/proto/src/version/v729/packets/resource_packs_info.rs @@ -0,0 +1,17 @@ +use crate::version::v729::types::pack_info_resource::ResourcePackInfoType; +use crate::version::v729::types::pack_url::PackURL; +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 6)] +#[derive(ProtoCodec, Debug, Clone)] +pub struct ResourcePacksInfoPacket { + pub resource_pack_required: bool, + pub has_addon_packs: bool, + pub has_scripts: bool, + #[vec_repr(u16)] + #[vec_endianness(le)] + pub resource_packs: Vec, + #[vec_repr(u32)] + #[vec_endianness(var)] + pub cdn_urls: Vec, +} diff --git a/crates/proto/src/packets/resource_packs_response.rs b/crates/proto/src/version/v729/packets/resource_packs_response.rs similarity index 55% rename from crates/proto/src/packets/resource_packs_response.rs rename to crates/proto/src/version/v729/packets/resource_packs_response.rs index c7478950..8a4ad40d 100644 --- a/crates/proto/src/packets/resource_packs_response.rs +++ b/crates/proto/src/version/v729/packets/resource_packs_response.rs @@ -1,8 +1,6 @@ -use bedrockrs_core::int::LE; -use bedrockrs_proto_core::ProtoCodec; -use bedrockrs_proto_macros::{gamepacket, ProtoCodec}; +use bedrockrs_macros::{gamepacket, ProtoCodec}; -use crate::types::resource_packs_response_status::ResourcePacksResponseStatus; +use crate::version::v729::types::resource_packs_response_status::ResourcePacksResponseStatus; #[gamepacket(id = 8)] #[derive(ProtoCodec, Debug, Clone)] @@ -10,6 +8,7 @@ pub struct ResourcePacksResponsePacket { pub response: ResourcePacksResponseStatus, /// The addons that are downloaded/getting downloaded /// with their pack name as strings - #[len_repr(LE::)] + #[vec_repr(u16)] + #[vec_endianness(le)] pub downloading_packs: Vec, } diff --git a/crates/proto/src/version/v729/packets/resource_packs_stack.rs b/crates/proto/src/version/v729/packets/resource_packs_stack.rs new file mode 100644 index 00000000..23ab8f12 --- /dev/null +++ b/crates/proto/src/version/v729/packets/resource_packs_stack.rs @@ -0,0 +1,20 @@ +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +use crate::version::v729::types::base_game_version::BaseGameVersion; +use crate::version::v729::types::experiments::Experiments; +use crate::version::v729::types::resource_packs_stack_pack::ResourcePacksStackPack; + +#[gamepacket(id = 7)] +#[derive(Debug, Clone, ProtoCodec)] +pub struct ResourcePacksStackPacket { + pub texture_pack_required: bool, + #[vec_repr(i32)] + #[vec_endianness(var)] + pub addons: Vec, + #[vec_repr(i32)] + #[vec_endianness(var)] + pub texture_packs: Vec, + pub base_game_version: BaseGameVersion, + pub experiments: Experiments, + pub include_editor_packs: bool, +} diff --git a/crates/proto/src/version/v729/packets/respawn.rs b/crates/proto/src/version/v729/packets/respawn.rs new file mode 100644 index 00000000..3e12329a --- /dev/null +++ b/crates/proto/src/version/v729/packets/respawn.rs @@ -0,0 +1,13 @@ +use crate::version::v729::types::respawn_state::RespawnState; +use bedrockrs_macros::{gamepacket, ProtoCodec}; +use bedrockrs_shared::actor_runtime_id::ActorRuntimeID; +use vek::Vec3; + +#[gamepacket(id = 45)] +#[derive(ProtoCodec, Debug, Clone)] +pub struct RespawnPacket { + #[endianness(le)] + pub position: Vec3, + pub state: RespawnState, + pub runtime_id: ActorRuntimeID, +} diff --git a/crates/proto/src/version/v729/packets/server_player_post_move_position.rs b/crates/proto/src/version/v729/packets/server_player_post_move_position.rs new file mode 100644 index 00000000..167b78f6 --- /dev/null +++ b/crates/proto/src/version/v729/packets/server_player_post_move_position.rs @@ -0,0 +1,9 @@ +use bedrockrs_macros::{gamepacket, ProtoCodec}; +use vek::Vec3; + +#[gamepacket(id = 18)] +#[derive(ProtoCodec, Debug, Clone)] +pub struct ServerPlayerPostMovePositionPacket { + #[endianness(le)] + pub pos: Vec3, +} diff --git a/crates/proto/src/packets/server_settings_request.rs b/crates/proto/src/version/v729/packets/server_settings_request.rs similarity index 65% rename from crates/proto/src/packets/server_settings_request.rs rename to crates/proto/src/version/v729/packets/server_settings_request.rs index 889c90bd..76cb10ae 100644 --- a/crates/proto/src/packets/server_settings_request.rs +++ b/crates/proto/src/version/v729/packets/server_settings_request.rs @@ -1,4 +1,4 @@ -use bedrockrs_proto_macros::{gamepacket, ProtoCodec}; +use bedrockrs_macros::{gamepacket, ProtoCodec}; #[gamepacket(id = 102)] #[derive(ProtoCodec, Debug, Clone)] diff --git a/crates/proto/src/packets/server_settings_response.rs b/crates/proto/src/version/v729/packets/server_settings_response.rs similarity index 54% rename from crates/proto/src/packets/server_settings_response.rs rename to crates/proto/src/version/v729/packets/server_settings_response.rs index 74efa42a..ccbf7548 100644 --- a/crates/proto/src/packets/server_settings_response.rs +++ b/crates/proto/src/version/v729/packets/server_settings_response.rs @@ -1,9 +1,9 @@ -use bedrockrs_core::int::VAR; -use bedrockrs_proto_macros::{gamepacket, ProtoCodec}; +use bedrockrs_macros::{gamepacket, ProtoCodec}; #[gamepacket(id = 103)] #[derive(ProtoCodec, Debug, Clone)] pub struct ServerSettingsResponsePacket { - pub form_id: VAR, + #[endianness(var)] + pub form_id: u32, pub form_json: String, } diff --git a/crates/proto/src/packets/set_commands_enabled.rs b/crates/proto/src/version/v729/packets/set_commands_enabled.rs similarity index 57% rename from crates/proto/src/packets/set_commands_enabled.rs rename to crates/proto/src/version/v729/packets/set_commands_enabled.rs index 97ecfcc3..a9ece114 100644 --- a/crates/proto/src/packets/set_commands_enabled.rs +++ b/crates/proto/src/version/v729/packets/set_commands_enabled.rs @@ -1,7 +1,7 @@ -use bedrockrs_proto_macros::{gamepacket, ProtoCodec}; +use bedrockrs_macros::{gamepacket, ProtoCodec}; #[gamepacket(id = 59)] #[derive(ProtoCodec, Debug, Clone)] pub struct SetCommandsEnabledPacket { - enabled: bool, + pub enabled: bool, } diff --git a/crates/proto/src/packets/set_local_player_as_initialized.rs b/crates/proto/src/version/v729/packets/set_local_player_as_initialized.rs similarity index 65% rename from crates/proto/src/packets/set_local_player_as_initialized.rs rename to crates/proto/src/version/v729/packets/set_local_player_as_initialized.rs index f811bdf6..79d28b48 100644 --- a/crates/proto/src/packets/set_local_player_as_initialized.rs +++ b/crates/proto/src/version/v729/packets/set_local_player_as_initialized.rs @@ -1,8 +1,8 @@ -use bedrockrs_proto_macros::{gamepacket, ProtoCodec}; +use bedrockrs_macros::{gamepacket, ProtoCodec}; use bedrockrs_shared::actor_runtime_id::ActorRuntimeID; #[gamepacket(id = 113)] #[derive(ProtoCodec, Debug, Clone)] pub struct SetLocalPlayerAsInitializedPacket { - actor_id: ActorRuntimeID, + pub target_actor_id: ActorRuntimeID, } diff --git a/crates/proto/src/version/v729/packets/set_time.rs b/crates/proto/src/version/v729/packets/set_time.rs new file mode 100644 index 00000000..9f9dc14a --- /dev/null +++ b/crates/proto/src/version/v729/packets/set_time.rs @@ -0,0 +1,8 @@ +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 10)] +#[derive(ProtoCodec, Debug, Clone)] +pub struct SetTimePacket { + #[endianness(var)] + pub time: i32, +} diff --git a/crates/proto/src/version/v729/packets/set_title.rs b/crates/proto/src/version/v729/packets/set_title.rs new file mode 100644 index 00000000..8db0c430 --- /dev/null +++ b/crates/proto/src/version/v729/packets/set_title.rs @@ -0,0 +1,19 @@ +use bedrockrs_macros::{gamepacket, ProtoCodec}; +use xuid::Xuid; + +use crate::version::v729::types::title_type::TitleType; + +#[gamepacket(id = 88)] +#[derive(ProtoCodec, Debug, Clone)] +pub struct SetTitlePacket { + pub title_type: TitleType, + pub title_text: String, + #[endianness(var)] + pub fade_in_time: i32, + #[endianness(var)] + pub stay_time: i32, + #[endianness(var)] + pub fade_out_time: i32, + pub xuid: Xuid, + pub platform_online_id: String, +} diff --git a/crates/proto/src/version/v729/packets/show_credits.rs b/crates/proto/src/version/v729/packets/show_credits.rs new file mode 100644 index 00000000..ba189490 --- /dev/null +++ b/crates/proto/src/version/v729/packets/show_credits.rs @@ -0,0 +1,10 @@ +use crate::version::v729::types::credits_state::CreditsState; +use bedrockrs_macros::{gamepacket, ProtoCodec}; +use bedrockrs_shared::actor_runtime_id::ActorRuntimeID; + +#[gamepacket(id = 75)] +#[derive(ProtoCodec, Debug, Clone)] +pub struct ShowCreditsPacket { + pub target_actor_id: ActorRuntimeID, + pub credits_state: CreditsState, +} diff --git a/crates/proto/src/packets/show_profile.rs b/crates/proto/src/version/v729/packets/show_profile.rs similarity index 70% rename from crates/proto/src/packets/show_profile.rs rename to crates/proto/src/version/v729/packets/show_profile.rs index 994e3d55..4761ac57 100644 --- a/crates/proto/src/packets/show_profile.rs +++ b/crates/proto/src/version/v729/packets/show_profile.rs @@ -1,5 +1,5 @@ +use bedrockrs_macros::{gamepacket, ProtoCodec}; use xuid::Xuid; -use bedrockrs_proto_macros::{gamepacket, ProtoCodec}; #[gamepacket(id = 104)] #[derive(ProtoCodec, Debug, Clone)] diff --git a/crates/proto/src/version/v729/packets/start_game.rs b/crates/proto/src/version/v729/packets/start_game.rs new file mode 100644 index 00000000..3d9ac03c --- /dev/null +++ b/crates/proto/src/version/v729/packets/start_game.rs @@ -0,0 +1,78 @@ +use bedrockrs_macros::{gamepacket, ProtoCodec}; +use serde::{Deserialize, Serialize}; +use uuid::Uuid; +use vek::{Vec2, Vec3}; + +use crate::version::v729::types::level_settings::LevelSettings; +use crate::version::v729::types::network_permissions::NetworkPermissions; +use crate::version::v729::types::player_movement_settings::PlayerMovementSettings; +use bedrockrs_shared::actor_runtime_id::ActorRuntimeID; +use bedrockrs_shared::actor_unique_id::ActorUniqueID; +use bedrockrs_shared::world::gamemode::Gamemode; + +#[gamepacket(id = 11)] +#[derive(ProtoCodec, Debug, Clone)] +pub struct StartGamePacket { + pub target_actor_id: ActorUniqueID, + pub target_runtime_id: ActorRuntimeID, + pub gamemode: Gamemode, + #[endianness(le)] + pub position: Vec3, + #[endianness(le)] + pub rotation: Vec2, + pub settings: LevelSettings, + pub level_id: String, + pub level_name: String, + pub template_content_identity: String, + pub trial: bool, + pub movement_settings: PlayerMovementSettings, + #[endianness(le)] + pub current_level_time: u64, + #[endianness(var)] + pub enchantment_seed: i32, + /// List of all custom blocks registered on the server. + #[vec_repr(u32)] + #[vec_endianness(var)] + pub blocks: Vec, + /// List of all items with their legacy IDs that are available in the game. + /// Failing to send any of the items that are in the game will crash mobile clients. + #[vec_repr(u32)] + #[vec_endianness(var)] + pub items: Vec, + pub multiplayer_correlation_id: String, + pub item_stack_net_manager: bool, + pub server_version: String, + // TODO: This can now be a concrete type rather than an NBT value. + // How should we do this with the ProtoCodec macro? + #[nbt] + pub player_property_data: nbtx::Value, + #[endianness(le)] + pub block_state_checksum: u64, + pub world_template_id: Uuid, + pub clientside_world_generation: bool, + pub block_id_hashes: bool, + pub network_permission: NetworkPermissions, +} + +#[derive(Debug, Clone, ProtoCodec)] +pub struct BlockEntry { + pub name: String, + #[nbt] + pub definition: BlockDefinition, +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(deny_unknown_fields)] +pub struct BlockDefinition { + // TODO: Add fields +} + +#[derive(Debug, Clone, ProtoCodec)] +pub struct ItemEntry { + pub name: String, + /// Block IDs < 256 (can be negative) + /// Item IDs > 257 + #[endianness(le)] + pub id: i16, + pub component_based: bool, +} diff --git a/crates/proto/src/version/v729/packets/text_message.rs b/crates/proto/src/version/v729/packets/text_message.rs new file mode 100644 index 00000000..12c1baeb --- /dev/null +++ b/crates/proto/src/version/v729/packets/text_message.rs @@ -0,0 +1,12 @@ +use crate::version::v729::types::text_message_data::TextMessageData; +use bedrockrs_macros::{gamepacket, ProtoCodec}; +use xuid::Xuid; + +#[gamepacket(id = 9)] +#[derive(ProtoCodec, Debug, Clone)] +pub struct TextMessagePacket { + pub message_type: TextMessageData, + pub sender_xuid: Xuid, + pub platform_id: String, + pub filtered_message: String, +} diff --git a/crates/proto/src/packets/toast_request.rs b/crates/proto/src/version/v729/packets/toast_request.rs similarity index 72% rename from crates/proto/src/packets/toast_request.rs rename to crates/proto/src/version/v729/packets/toast_request.rs index b6714850..725d003a 100644 --- a/crates/proto/src/packets/toast_request.rs +++ b/crates/proto/src/version/v729/packets/toast_request.rs @@ -1,4 +1,4 @@ -use bedrockrs_proto_macros::{gamepacket, ProtoCodec}; +use bedrockrs_macros::{gamepacket, ProtoCodec}; #[gamepacket(id = 186)] #[derive(ProtoCodec, Debug, Clone)] diff --git a/crates/proto/src/version/v729/packets/update_difficulty.rs b/crates/proto/src/version/v729/packets/update_difficulty.rs new file mode 100644 index 00000000..44d3cb39 --- /dev/null +++ b/crates/proto/src/version/v729/packets/update_difficulty.rs @@ -0,0 +1,8 @@ +use bedrockrs_macros::{gamepacket, ProtoCodec}; +use bedrockrs_shared::world::difficulty::Difficulty; + +#[gamepacket(id = 60)] +#[derive(ProtoCodec, Debug, Clone)] +pub struct UpdateDifficultyPacket { + pub difficulty: Difficulty, +} diff --git a/crates/proto/src/version/v729/packets/update_player_gamemode.rs b/crates/proto/src/version/v729/packets/update_player_gamemode.rs new file mode 100644 index 00000000..658eaff6 --- /dev/null +++ b/crates/proto/src/version/v729/packets/update_player_gamemode.rs @@ -0,0 +1,8 @@ +use bedrockrs_macros::{gamepacket, ProtoCodec}; +use bedrockrs_shared::world::gamemode::Gamemode; + +#[gamepacket(id = 62)] +#[derive(ProtoCodec, Debug, Clone)] +pub struct UpdatePlayerGamemodePacket { + pub gamemode: Gamemode, +} diff --git a/crates/proto/src/types/ability_data.rs b/crates/proto/src/version/v729/types/ability_data.rs similarity index 67% rename from crates/proto/src/types/ability_data.rs rename to crates/proto/src/version/v729/types/ability_data.rs index 17a6ae6f..f1423cc9 100644 --- a/crates/proto/src/types/ability_data.rs +++ b/crates/proto/src/version/v729/types/ability_data.rs @@ -1,10 +1,10 @@ -use bedrockrs_proto_macros::ProtoCodec; +use bedrockrs_macros::ProtoCodec; use bedrockrs_shared::actor_unique_id::ActorUniqueID; use bedrockrs_shared::world::permissions_level::PermissionLevel; #[derive(ProtoCodec, Debug, Clone)] pub struct AbilityData { /// This field is not necessary, 0 seems to work. - target_player_raw_id: ActorUniqueID, - permission: PermissionLevel, + pub target_player_id: ActorUniqueID, + pub permission: PermissionLevel, } diff --git a/crates/proto/src/version/v729/types/actor_link.rs b/crates/proto/src/version/v729/types/actor_link.rs new file mode 100644 index 00000000..782b1592 --- /dev/null +++ b/crates/proto/src/version/v729/types/actor_link.rs @@ -0,0 +1,13 @@ +use bedrockrs_macros::ProtoCodec; +use bedrockrs_shared::actor_unique_id::ActorUniqueID; + +use super::actor_link_type::ActorLinkType; + +#[derive(ProtoCodec, Debug, Clone)] +pub struct ActorLink { + pub actor_unique_id_a: ActorUniqueID, + pub actor_unique_id_b: ActorUniqueID, + pub link_type: ActorLinkType, + pub immediate: bool, + pub passenger_seat_id: bool, +} diff --git a/crates/proto/src/types/actor_link_type.rs b/crates/proto/src/version/v729/types/actor_link_type.rs similarity index 54% rename from crates/proto/src/types/actor_link_type.rs rename to crates/proto/src/version/v729/types/actor_link_type.rs index 90c516dd..fad74a89 100644 --- a/crates/proto/src/types/actor_link_type.rs +++ b/crates/proto/src/version/v729/types/actor_link_type.rs @@ -1,8 +1,8 @@ -use bedrockrs_core::int::VAR; -use bedrockrs_proto_macros::ProtoCodec; +use bedrockrs_macros::ProtoCodec; #[derive(ProtoCodec, Debug, Clone)] -#[enum_repr(VAR::)] +#[enum_repr(i32)] +#[enum_endianness(var)] pub enum ActorLinkType { None = 0, Riding = 1, diff --git a/crates/proto/src/types/actor_type.rs b/crates/proto/src/version/v729/types/actor_type.rs similarity index 99% rename from crates/proto/src/types/actor_type.rs rename to crates/proto/src/version/v729/types/actor_type.rs index 959222d8..2fd96a3d 100644 --- a/crates/proto/src/types/actor_type.rs +++ b/crates/proto/src/version/v729/types/actor_type.rs @@ -472,14 +472,18 @@ impl ActorType { impl ProtoCodec for ActorType { fn proto_serialize( &self, - stream: &mut Vec, + _stream: &mut Vec, ) -> Result<(), bedrockrs_proto_core::error::ProtoCodecError> { unimplemented!() } fn proto_deserialize( - stream: &mut std::io::Cursor<&[u8]>, + _stream: &mut std::io::Cursor<&[u8]>, ) -> Result { unimplemented!() } + + fn get_size_prediction(&self) -> usize { + unimplemented!() + } } diff --git a/crates/proto/src/types/animate_action.rs b/crates/proto/src/version/v729/types/animate_action.rs similarity index 100% rename from crates/proto/src/types/animate_action.rs rename to crates/proto/src/version/v729/types/animate_action.rs diff --git a/crates/proto/src/version/v729/types/attribute.rs b/crates/proto/src/version/v729/types/attribute.rs new file mode 100644 index 00000000..5aeedd90 --- /dev/null +++ b/crates/proto/src/version/v729/types/attribute.rs @@ -0,0 +1,12 @@ +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Debug, Clone)] +pub struct Attribute { + pub name: String, + #[endianness(le)] + pub min: f32, + #[endianness(le)] + pub current: f32, + #[endianness(le)] + pub max: f32, +} diff --git a/crates/proto/src/version/v729/types/base_game_version.rs b/crates/proto/src/version/v729/types/base_game_version.rs new file mode 100644 index 00000000..9171caeb --- /dev/null +++ b/crates/proto/src/version/v729/types/base_game_version.rs @@ -0,0 +1,23 @@ +use bedrockrs_proto_core::error::ProtoCodecError; +use bedrockrs_proto_core::ProtoCodec; +use std::io::Cursor; + +#[derive(Debug, Clone)] +#[repr(transparent)] +pub struct BaseGameVersion(pub String); + +impl ProtoCodec for BaseGameVersion { + fn proto_serialize(&self, stream: &mut Vec) -> Result<(), ProtoCodecError> { + self.0.proto_serialize(stream)?; + Ok(()) + } + + fn proto_deserialize(stream: &mut Cursor<&[u8]>) -> Result { + let base_game_version = String::proto_deserialize(stream)?; + Ok(BaseGameVersion(base_game_version)) + } + + fn get_size_prediction(&self) -> usize { + self.0.get_size_prediction() + } +} diff --git a/crates/proto/src/version/v729/types/block_actions.rs b/crates/proto/src/version/v729/types/block_actions.rs new file mode 100644 index 00000000..367a2c6e --- /dev/null +++ b/crates/proto/src/version/v729/types/block_actions.rs @@ -0,0 +1,60 @@ +use crate::version::v729::types::block_pos::BlockPos; +use bedrockrs_macros::ProtoCodec; + +#[derive(Debug, Clone, ProtoCodec)] +pub struct BlockActions { + #[vec_repr(i32)] + #[vec_endianness(var)] + actions: Vec, +} + +#[derive(Debug, Clone, ProtoCodec)] +#[enum_repr(i32)] +#[enum_endianness(var)] +pub enum BlockActionType { + StartBreak = 0, + AbortBreak = 1, + StopBreak = 2, + GetUpdatedBlock = 3, + DropItem = 4, + StartSleeping = 5, + StopSleeping = 6, + Respawn = 7, + Jump = 8, + StartSprint = 9, + StopSprint = 10, + StartSneak = 11, + StopSneak = 12, + CreativePlayerDestroyBlock = 13, + DimensionChangeDone = 14, + StartGlide = 15, + StopGlide = 16, + BuildDenied = 17, + CrackBreak = 18, + ChangeSkin = 19, + SetEnchantmentSeed = 20, + StartSwimming = 21, + StopSwimming = 22, + StartSpinAttack = 23, + StopSpinAttack = 24, + StartBuildingBlock = 25, + PredictDestroyBlock = 26, + ContinueDestroyBlock = 27, + StartItemUseOn = 28, + StopItemUseOn = 29, + HandledTeleport = 30, + MissedSwing = 31, + StartCrawling = 32, + StopCrawling = 33, + StartFlying = 34, + StopFlying = 35, + ClientAckServerData = 36, +} + +#[derive(Debug, Clone, ProtoCodec)] +pub struct BlockActionData { + action: BlockActionType, + block_pos: BlockPos, + #[endianness(var)] + face: i32, +} diff --git a/crates/proto/src/version/v729/types/block_pos.rs b/crates/proto/src/version/v729/types/block_pos.rs new file mode 100644 index 00000000..0b779394 --- /dev/null +++ b/crates/proto/src/version/v729/types/block_pos.rs @@ -0,0 +1,37 @@ +use bedrockrs_proto_core::error::ProtoCodecError; +use bedrockrs_proto_core::ProtoCodec; +use std::io::Cursor; +use std::mem::size_of; +use std::mem::transmute; +use varint_rs::{VarintReader, VarintWriter}; + +#[derive(Debug, Clone)] +pub struct BlockPos { + pub x: i32, + pub y: i32, + pub z: i32, +} + +impl ProtoCodec for BlockPos { + fn proto_serialize(&self, buf: &mut Vec) -> Result<(), ProtoCodecError> { + buf.write_i32_varint(self.x)?; + // the y i32 height is serialized as an u32 + unsafe { buf.write_u32_varint(transmute::(self.y))? }; + buf.write_i32_varint(self.z)?; + + Ok(()) + } + + fn proto_deserialize(buf: &mut Cursor<&[u8]>) -> Result { + Ok(Self { + x: buf.read_i32_varint()?, + // the y i32 height is deserialized as an u32 + y: unsafe { transmute::(buf.read_u32_varint()?) }, + z: buf.read_i32_varint()?, + }) + } + + fn get_size_prediction(&self) -> usize { + size_of::() + size_of::() + size_of::() + } +} diff --git a/crates/proto/src/version/v729/types/chat_restriction_level.rs b/crates/proto/src/version/v729/types/chat_restriction_level.rs new file mode 100644 index 00000000..d6e9abe5 --- /dev/null +++ b/crates/proto/src/version/v729/types/chat_restriction_level.rs @@ -0,0 +1,9 @@ +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Debug, Clone)] +#[enum_repr(i8)] +pub enum ChatRestrictionLevel { + None = 0, + Dropped = 1, + Disabled = 2, +} diff --git a/crates/proto/src/version/v729/types/chunk_pos.rs b/crates/proto/src/version/v729/types/chunk_pos.rs new file mode 100644 index 00000000..c57968a1 --- /dev/null +++ b/crates/proto/src/version/v729/types/chunk_pos.rs @@ -0,0 +1,9 @@ +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Debug, Clone)] +pub struct ChunkPos { + #[endianness(var)] + pub x: i32, + #[endianness(var)] + pub z: i32, +} diff --git a/crates/proto/src/types/command_origin_data.rs b/crates/proto/src/version/v729/types/command_origin_data.rs similarity index 86% rename from crates/proto/src/types/command_origin_data.rs rename to crates/proto/src/version/v729/types/command_origin_data.rs index adc07e7e..aeda680b 100644 --- a/crates/proto/src/types/command_origin_data.rs +++ b/crates/proto/src/version/v729/types/command_origin_data.rs @@ -1,8 +1,9 @@ -use bedrockrs_core::int::VAR; -use bedrockrs_proto_macros::ProtoCodec; +use bedrockrs_macros::ProtoCodec; use uuid::Uuid; + #[derive(ProtoCodec, Debug, Clone)] -#[enum_repr(VAR::)] +#[enum_repr(u32)] +#[enum_endianness(var)] pub enum CommandOriginType { Player = 0, CommandBlock = 1, diff --git a/crates/proto/src/types/connection_request.rs b/crates/proto/src/version/v729/types/connection_request.rs similarity index 56% rename from crates/proto/src/types/connection_request.rs rename to crates/proto/src/version/v729/types/connection_request.rs index 827359f8..8fd7c4ab 100644 --- a/crates/proto/src/types/connection_request.rs +++ b/crates/proto/src/version/v729/types/connection_request.rs @@ -1,20 +1,20 @@ use std::collections::BTreeMap; use std::io::{Cursor, Read}; -use std::sync::Arc; use base64::prelude::BASE64_STANDARD; use base64::Engine; -use bedrockrs_core::int::{LE, VAR}; use bedrockrs_proto_core::error::ProtoCodecError; use bedrockrs_proto_core::ProtoCodec; +use byteorder::{LittleEndian, ReadBytesExt}; use jsonwebtoken::{DecodingKey, Validation}; use serde_json::Value; +use varint_rs::VarintReader; #[derive(Debug, Clone)] pub struct ConnectionRequest { /// Array of Base64 encoded JSON Web Token certificates to authenticate the player. /// - /// The last certificate in the chain will have a property 'extraData' that contains player identity information including the XBL XUID (if the player was signed into XBL at the time of the connection). + /// The last certificate in the chain will have a property 'extraData' that contains player identity information including the XBL XUID (if the player was signed in to XBL at the time of the connection). pub certificate_chain: Vec>, /// Base64 encoded JSON Web Token that contains other relevant client properties. /// @@ -48,7 +48,7 @@ pub struct ConnectionRequest { /// - PieceId /// - IsDefault /// - PieceType - /// - ProuctId + /// - ProductId /// - PieceTintColors = Array of: /// - PieceType /// - Colors = Array of color hexstrings @@ -80,8 +80,20 @@ pub struct ConnectionRequest { pub raw_token: BTreeMap, } +fn read_i32_string(stream: &mut Cursor<&[u8]>) -> Result { + let len = stream + .read_i32::()? + .try_into() + .map_err(ProtoCodecError::FromIntError)?; + + let mut string_buf = vec![0; len]; + stream.read_exact(&mut string_buf)?; + + Ok(String::from_utf8(string_buf)?) +} + impl ProtoCodec for ConnectionRequest { - fn proto_serialize(&self, stream: &mut Vec) -> Result<(), ProtoCodecError> + fn proto_serialize(&self, _stream: &mut Vec) -> Result<(), ProtoCodecError> where Self: Sized, { @@ -96,62 +108,40 @@ impl ProtoCodec for ConnectionRequest { { let mut certificate_chain: Vec> = vec![]; - // read the ConnectionRequests length + // Read the ConnectionRequests length, Mojang stores it as a String // (certificate_chain len + raw_token len + 8) // 8 = i32 len + i32 len (length of certificate_chain's len and raw_token's len) // can be ignored, other lengths are provided - VAR::::proto_deserialize(stream)?; - - // read length of certificate_chain vec - let certificate_chain_len = LE::::proto_deserialize(stream)?.into_inner(); + stream.read_u32_varint()?; - let certificate_chain_len = certificate_chain_len - .try_into() - .map_err(ProtoCodecError::FromIntError)?; - - let mut certificate_chain_buf = vec![0; certificate_chain_len]; - - // read string data (certificate_chain) - stream - .read_exact(&mut certificate_chain_buf) - .map_err(|e| ProtoCodecError::IOError(Arc::new(e)))?; - - // transform into string - let certificate_chain_string = - String::from_utf8(certificate_chain_buf).map_err(ProtoCodecError::UTF8Error)?; + let certificate_chain_string = read_i32_string(stream)?; // parse certificate chain string into json - let certificate_chain_json = serde_json::from_str(&certificate_chain_string) - .map_err(|e| ProtoCodecError::JsonError(Arc::new(e)))?; + let mut certificate_chain_json = serde_json::from_str(&certificate_chain_string)?; let certificate_chain_json_jwts = match certificate_chain_json { - Value::Object(mut v) => { - match v.get_mut("chain") { - None => { - // the certificate chain should always be an object with just an array of - // JWTs called "chain" - return Err(ProtoCodecError::FormatMismatch(String::from( - "Missing element \"chain\" in JWT certificate_chain", - ))); - } - Some(v) => { - match v.take() { - Value::Array(v) => v, - other => { - // the certificate chain should always be an object with just an - // array of JWTs called "chain" - return Err(ProtoCodecError::FormatMismatch(format!("Expected \"chain\" in JWT certificate_chain to be an Array, but got {other:?}"))); - } - } + Value::Object(ref mut v) => { + let chain = v.get_mut("chain").ok_or(ProtoCodecError::FormatMismatch( + "Missing element chain in JWT certificate_chain", + ))?; + + match chain { + Value::Array(v) => v, + _ => { + // the certificate chain should always be an object with just an + // array of JWTs called "chain" + return Err(ProtoCodecError::FormatMismatch( + "Expected chain in JWT certificate_chain to be of type Array", + )); } } } - other => { + _ => { // the certificate chain should always be an object with just an array of // JWTs called "chain" - return Err(ProtoCodecError::FormatMismatch(format!( - "Expected Object in base of JWT certificate_chain, got {other:?}" - ))); + return Err(ProtoCodecError::FormatMismatch( + "Expected Object in base of JWT certificate_chain", + )); } }; @@ -160,32 +150,31 @@ impl ProtoCodec for ConnectionRequest { for jwt_json in certificate_chain_json_jwts { let jwt_string = match jwt_json { Value::String(str) => str, - other => { + _ => { // the certificate chain's should always be a jwt string - return Err(ProtoCodecError::FormatMismatch(format!("Expected chain array in certificate_chain to just contain Strings, but got {other:?}"))); + return Err(ProtoCodecError::FormatMismatch( + "Expected chain array in certificate_chain to just contain Strings", + )); } }; // Extract header let jwt_header = - jsonwebtoken::decode_header(&jwt_string).map_err(ProtoCodecError::JwtError)?; + jsonwebtoken::decode_header(jwt_string).map_err(ProtoCodecError::JwtError)?; let mut jwt_validation = Validation::new(jwt_header.alg); - // TODO: This definitely is not right. Even Zuri-MC doesn't understand this.. I may understand it.. I do understand it, update I don't. + // TODO: This definitely is not right. Even Zuri-MC doesn't understand this.. I may understand it.. I do understand it, update I don't. But I now know someone that does, I hope // TODO: Someone else should find out how this works jwt_validation.insecure_disable_signature_validation(); jwt_validation.set_required_spec_claims::<&str>(&[]); // Is first jwt, use self-signed header from x5u if key_data.is_empty() { - let x5u = match jwt_header.x5u { - None => { - return Err(ProtoCodecError::FormatMismatch(String::from( - "Expected x5u in JWT header", - ))); - } - Some(ref v) => v.as_bytes(), - }; + let x5u = jwt_header.x5u.ok_or(ProtoCodecError::FormatMismatch( + "Expected x5u in JWT header", + ))?; + + let x5u = x5u.as_bytes(); key_data = BASE64_STANDARD .decode(x5u) @@ -200,39 +189,28 @@ impl ProtoCodec for ConnectionRequest { ) .map_err(ProtoCodecError::JwtError)?; - key_data = match jwt.claims.get("identityPublicKey") { - None => return Err(ProtoCodecError::FormatMismatch(String::from("Expected identityPublicKey field in JWT for validation"))), - Some(v) => match v { - Value::String(str) => match BASE64_STANDARD.decode(str.as_bytes()) { - Ok(v) => v, - Err(e) => return Err(ProtoCodecError::Base64DecodeError(e)), - }, - other => return Err(ProtoCodecError::FormatMismatch(format!("Expected identityPublicKey field in JWT to be of type String, got {other:?}"))), - }, + let identity_field = + jwt.claims + .get("identityPublicKey") + .ok_or(ProtoCodecError::FormatMismatch( + "Missing identityPublicKey field in JWT for validation", + ))?; + + key_data = match identity_field { + Value::String(str) => BASE64_STANDARD + .decode(str.as_bytes()) + .map_err(ProtoCodecError::Base64DecodeError)?, + _ => { + return Err(ProtoCodecError::FormatMismatch( + "Expected identityPublicKey field in JWT to be of type String", + )) + } }; certificate_chain.push(jwt.claims); } - // read length of certificate_chain vec - let raw_token_len = LE::::read(stream) - .map_err(|e| ProtoCodecError::IOError(Arc::new(e)))? - .into_inner(); - - let raw_token_len = raw_token_len - .try_into() - .map_err(ProtoCodecError::FromIntError)?; - - let mut raw_token_buf = vec![0; raw_token_len]; - - // read string data (certificate_chain) - stream - .read_exact(&mut raw_token_buf) - .map_err(|e| ProtoCodecError::IOError(Arc::new(e)))?; - - // transform into string - let raw_token_string = - String::from_utf8(raw_token_buf).map_err(ProtoCodecError::UTF8Error)?; + let raw_token_string = read_i32_string(stream)?; // Extract header let raw_token_jwt_header = @@ -245,16 +223,22 @@ impl ProtoCodec for ConnectionRequest { jwt_validation.set_required_spec_claims::<&str>(&[]); // Decode the jwt string into a jwt object - let raw_token_jwt = jsonwebtoken::decode::>( + let raw_token = jsonwebtoken::decode::>( &raw_token_string, - &DecodingKey::from_ec_der(&vec![]), + &DecodingKey::from_ec_der(&[]), &jwt_validation, ) - .map_err(ProtoCodecError::JwtError)?; + .map_err(ProtoCodecError::JwtError)? + .claims; Ok(Self { certificate_chain, - raw_token: raw_token_jwt.claims, + raw_token, }) } + + fn get_size_prediction(&self) -> usize { + // TODO + 1 + } } diff --git a/crates/proto/src/types/container_id.rs b/crates/proto/src/version/v729/types/container_id.rs similarity index 87% rename from crates/proto/src/types/container_id.rs rename to crates/proto/src/version/v729/types/container_id.rs index 0478f42f..2aafef20 100644 --- a/crates/proto/src/types/container_id.rs +++ b/crates/proto/src/version/v729/types/container_id.rs @@ -1,9 +1,8 @@ -use bedrockrs_core::int::{BE, VAR}; -use bedrockrs_proto_macros::ProtoCodec; +use bedrockrs_macros::ProtoCodec; /// Defines an enum for container IDs, used to identify different types of containers. #[derive(ProtoCodec, Debug, Copy, Clone, Eq, PartialEq)] -#[enum_repr(BE::)] +#[enum_repr(i8)] pub enum ContainerID { /// Used to indicate that no container is selected. None = -1, diff --git a/crates/proto/src/version/v729/types/container_type.rs b/crates/proto/src/version/v729/types/container_type.rs new file mode 100644 index 00000000..81858268 --- /dev/null +++ b/crates/proto/src/version/v729/types/container_type.rs @@ -0,0 +1,45 @@ +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Debug, Copy, Clone, Eq, PartialEq)] +#[enum_repr(i8)] +pub enum ContainerType { + None = -9, + Inventory = -1, + Container = 0, + Workbench = 1, + Furnace = 2, + EnchantmentE = 3, + BrewingStand = 4, + Anvil = 5, + Dispenser = 6, + Dropper = 7, + Hopper = 8, + Cauldron = 9, + MinecartChest = 10, + MinecartHopper = 11, + Horse = 12, + Beacon = 13, + StructureEditor = 14, + Trade = 15, + CommandBlock = 16, + Jukebox = 17, + Armor = 18, + Hand = 19, + CompoundCreator = 20, + ElementConstructor = 21, + MaterialReducer = 22, + LabTable = 23, + Loom = 24, + Lectern = 25, + Grindstone = 26, + BlastFurnace = 27, + Smoker = 28, + Stonecutter = 29, + Cartography = 30, + Hud = 31, + JigsawEditor = 32, + SmithingTable = 33, + ChestBoat = 34, + DecoratedPot = 35, + Crafter = 36, +} diff --git a/crates/proto/src/types/credits_state.rs b/crates/proto/src/version/v729/types/credits_state.rs similarity index 50% rename from crates/proto/src/types/credits_state.rs rename to crates/proto/src/version/v729/types/credits_state.rs index 48002c94..0e29ab52 100644 --- a/crates/proto/src/types/credits_state.rs +++ b/crates/proto/src/version/v729/types/credits_state.rs @@ -1,8 +1,8 @@ -use bedrockrs_core::int::VAR; -use bedrockrs_proto_macros::ProtoCodec; +use bedrockrs_macros::ProtoCodec; #[derive(ProtoCodec, Debug, Clone)] -#[enum_repr(VAR::)] +#[enum_repr(u32)] +#[enum_endianness(var)] pub enum CreditsState { Start = 0, Finished = 1, diff --git a/crates/proto/src/version/v729/types/data_item.rs b/crates/proto/src/version/v729/types/data_item.rs new file mode 100644 index 00000000..0a233560 --- /dev/null +++ b/crates/proto/src/version/v729/types/data_item.rs @@ -0,0 +1,26 @@ +use crate::version::v729::types::block_pos::BlockPos; +use bedrockrs_macros::ProtoCodec; +use vek::Vec3; + +#[derive(ProtoCodec, Debug, Clone)] +pub struct DataItem { + #[endianness(var)] + pub id: u32, + pub value: DataItemValue, +} + +#[derive(ProtoCodec, Debug, Clone)] +#[enum_repr(u32)] +#[enum_endianness(var)] +#[repr(u32)] +pub enum DataItemValue { + ValByte(u8) = 0, + ValShort(#[endianness(le)] i16) = 1, + ValInt(#[endianness(var)] i32) = 2, + ValFloat(#[endianness(le)] f32) = 3, + ValString(String) = 4, + ValCompoundTag(#[nbt] nbtx::Value) = 5, + ValBlockPos(BlockPos) = 6, + ValInt64(#[endianness(var)] i64) = 7, + ValVec3(#[endianness(le)] Vec3) = 8, +} diff --git a/crates/proto/src/types/edu_shared_uri_resource.rs b/crates/proto/src/version/v729/types/edu_shared_uri_resource.rs similarity index 76% rename from crates/proto/src/types/edu_shared_uri_resource.rs rename to crates/proto/src/version/v729/types/edu_shared_uri_resource.rs index 6c45b9a7..2032d7e6 100644 --- a/crates/proto/src/types/edu_shared_uri_resource.rs +++ b/crates/proto/src/version/v729/types/edu_shared_uri_resource.rs @@ -1,4 +1,4 @@ -use bedrockrs_proto_macros::ProtoCodec; +use bedrockrs_macros::ProtoCodec; #[derive(ProtoCodec, Debug, Clone)] pub struct EduSharedResourceUri { diff --git a/crates/proto/src/version/v729/types/entity_info.rs b/crates/proto/src/version/v729/types/entity_info.rs new file mode 100644 index 00000000..f7bc33e5 --- /dev/null +++ b/crates/proto/src/version/v729/types/entity_info.rs @@ -0,0 +1,20 @@ +use serde::{Deserialize, Serialize}; + +// TODO: Figure out what fields are optional and which are not +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct EntityInfo { + /// Refers to the RuntimeID. + rid: i32, + id: String, + /// Refers to the BaseID. + // TODO: Find out what a BaseID id is + bid: String, + #[serde(rename = "hasspawnegg")] + has_spawn_egg: bool, + summonable: bool, +} + +#[derive(Serialize, Deserialize, Debug, Clone)] +pub struct EntityInfoList { + list: Vec, +} diff --git a/crates/proto/src/version/v729/types/event_type.rs b/crates/proto/src/version/v729/types/event_type.rs new file mode 100644 index 00000000..ab83950d --- /dev/null +++ b/crates/proto/src/version/v729/types/event_type.rs @@ -0,0 +1,51 @@ +use bedrockrs_macros::ProtoCodec; +use bedrockrs_shared::actor_unique_id::ActorUniqueID; + +#[derive(ProtoCodec, Debug, Clone)] +#[enum_endianness(var)] +#[enum_repr(u32)] +#[repr(u32)] +pub enum BossEventType { + Add { + name: String, + #[endianness(le)] + health_percentage: f32, + #[endianness(le)] + darken_screen: u16, + #[endianness(var)] + color: u32, + #[endianness(var)] + overlay: u32, + } = 0, + PlayerAdded { + actor_id: ActorUniqueID, + } = 1, + Remove = 2, + PlayerRemoved { + actor_id: ActorUniqueID, + } = 3, + UpdatePercent { + #[endianness(le)] + health_percentage: f32, + } = 4, + UpdateName { + name: String, + } = 5, + UpdateProperties { + #[endianness(le)] + darken_screen: u16, + #[endianness(var)] + color: u32, + #[endianness(var)] + overlay: u32, + } = 6, + UpdateStyle { + #[endianness(var)] + color: u32, + #[endianness(var)] + overlay: u32, + } = 7, + Query { + actor_id: ActorUniqueID, + } = 8, +} diff --git a/crates/proto/src/types/experiments.rs b/crates/proto/src/version/v729/types/experiments.rs similarity index 63% rename from crates/proto/src/types/experiments.rs rename to crates/proto/src/version/v729/types/experiments.rs index 7d3f6503..14fd5062 100644 --- a/crates/proto/src/types/experiments.rs +++ b/crates/proto/src/version/v729/types/experiments.rs @@ -1,10 +1,9 @@ -use bedrockrs_core::int::LE; -use bedrockrs_proto_core::ProtoCodec; -use bedrockrs_proto_macros::ProtoCodec; +use bedrockrs_macros::ProtoCodec; #[derive(ProtoCodec, Debug, Clone)] pub struct Experiments { - #[len_repr(LE::)] + #[vec_repr(u32)] + #[vec_endianness(le)] pub experiments: Vec, pub ever_toggled: bool, } diff --git a/crates/proto/src/version/v729/types/gamerule.rs b/crates/proto/src/version/v729/types/gamerule.rs new file mode 100644 index 00000000..8866a1ba --- /dev/null +++ b/crates/proto/src/version/v729/types/gamerule.rs @@ -0,0 +1,18 @@ +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Debug, Clone)] +pub struct GameRule { + pub name: String, + pub editable: bool, + pub value: GameRuleValue, +} + +#[derive(ProtoCodec, Debug, Clone)] +#[enum_repr(u32)] +#[enum_endianness(var)] +#[repr(u32)] +pub enum GameRuleValue { + Bool(bool) = 1, + VarU32(#[endianness(var)] u32) = 2, + F32(#[endianness(le)] f32) = 3, +} diff --git a/crates/proto/src/types/input_data.rs b/crates/proto/src/version/v729/types/input_data.rs similarity index 81% rename from crates/proto/src/types/input_data.rs rename to crates/proto/src/version/v729/types/input_data.rs index dc75198d..5b56bfa5 100644 --- a/crates/proto/src/types/input_data.rs +++ b/crates/proto/src/version/v729/types/input_data.rs @@ -1,14 +1,12 @@ -use crate::types::inventory_transaction::UseItemTransactionData; -use bedrockrs_core::int::{LE, VAR}; -use bedrockrs_core::Vec2; -use bedrockrs_proto_macros::ProtoCodec; +use crate::version::v729::types::block_actions::BlockActions; use bedrockrs_shared::actor_unique_id::ActorUniqueID; +use vek::Vec2; #[derive(Debug, Clone)] pub struct InputData { pub ascend: bool, pub descend: bool, - pub north_jump_DEPRECATED: bool, + pub north_jump_deprecated: bool, pub jump_down: bool, pub sprint_down: bool, pub change_height: bool, @@ -41,7 +39,7 @@ pub struct InputData { pub start_gliding: bool, pub stop_gliding: bool, pub perform_item_interaction: bool, - pub perform_block_actions: bool, + pub perform_block_actions: Option, pub perform_item_stack_request: bool, pub handled_teleport: bool, pub emoting: bool, @@ -51,7 +49,7 @@ pub struct InputData { pub start_flying: bool, pub stop_flying: bool, pub client_ack_server_data: bool, - pub is_in_client_predicted_vehicle: Option<(Vec2>, ActorUniqueID)>, + pub is_in_client_predicted_vehicle: Option<(Vec2, ActorUniqueID)>, pub paddling_left: bool, pub paddling_right: bool, pub block_breaking_delay_enabled: bool, diff --git a/crates/proto/src/types/input_mode.rs b/crates/proto/src/version/v729/types/input_mode.rs similarity index 54% rename from crates/proto/src/types/input_mode.rs rename to crates/proto/src/version/v729/types/input_mode.rs index c6c5d3ae..391d6027 100644 --- a/crates/proto/src/types/input_mode.rs +++ b/crates/proto/src/version/v729/types/input_mode.rs @@ -1,8 +1,9 @@ -use bedrockrs_core::int::VAR; -use bedrockrs_proto_macros::ProtoCodec; +use bedrockrs_macros::ProtoCodec; #[derive(ProtoCodec, Debug, Clone)] -#[enum_repr(VAR::)] +// TODO: Make sure that it is an u32 and not an i32 +#[enum_repr(u32)] +#[enum_endianness(var)] pub enum InputMode { Undefined = 0, Mouse = 1, diff --git a/crates/proto/src/types/interact_action.rs b/crates/proto/src/version/v729/types/interact_action.rs similarity index 85% rename from crates/proto/src/types/interact_action.rs rename to crates/proto/src/version/v729/types/interact_action.rs index 2f999f41..d7f02f74 100644 --- a/crates/proto/src/types/interact_action.rs +++ b/crates/proto/src/version/v729/types/interact_action.rs @@ -1,4 +1,4 @@ -use bedrockrs_core::Vec3; +use vek::Vec3; #[derive(Debug, Clone)] pub enum InteractAction { diff --git a/crates/proto/src/version/v729/types/interaction_model.rs b/crates/proto/src/version/v729/types/interaction_model.rs new file mode 100644 index 00000000..5fbb7e18 --- /dev/null +++ b/crates/proto/src/version/v729/types/interaction_model.rs @@ -0,0 +1,11 @@ +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Debug, Clone)] +// TODO: Make sure that it is an u32 and not an i32 +#[enum_repr(u32)] +#[enum_endianness(var)] +pub enum InteractionModel { + Touch = 0, + Crosshair = 1, + Classic = 2, +} diff --git a/crates/proto/src/types/inventory_transaction.rs b/crates/proto/src/version/v729/types/inventory_transaction.rs similarity index 65% rename from crates/proto/src/types/inventory_transaction.rs rename to crates/proto/src/version/v729/types/inventory_transaction.rs index 0246c195..c5a54025 100644 --- a/crates/proto/src/types/inventory_transaction.rs +++ b/crates/proto/src/version/v729/types/inventory_transaction.rs @@ -1,12 +1,13 @@ -use bedrockrs_core::int::LE; +use bedrockrs_macros::ProtoCodec; -#[derive(Debug, Clone)] +#[derive(ProtoCodec, Debug, Clone)] pub struct UseItemTransactionData { - /// legacy_request_id is an ID that is only non-zero at times when sent by the client. The server should + /// Legacy_request_id is an ID that is only non-zero at times when sent by the client. The server should /// always send 0 for this. When this field is not 0, the LegacySetItemSlots slice below will have values /// in it. - /// legacy_request_id ties in with the ItemStackResponse packet. If this field is non-0, the server should + /// Legacy_request_id ties in with the ItemStackResponse packet. If this field is non-0, the server should /// respond with an ItemStackResponse packet. Some inventory actions such as dropping an item out of the /// hotbar are still one using this packet, and the ItemStackResponse packet needs to tie in with it. - legacy_request_id: LE, + #[endianness(le)] + pub legacy_request_id: i32, } diff --git a/crates/proto/src/version/v729/types/item_stack_descriptor.rs b/crates/proto/src/version/v729/types/item_stack_descriptor.rs new file mode 100644 index 00000000..fbdac788 --- /dev/null +++ b/crates/proto/src/version/v729/types/item_stack_descriptor.rs @@ -0,0 +1,24 @@ +use super::item_stack_id_variant::ItemStackIdVariant; +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Debug, Clone)] +#[repr(u8)] +#[enum_repr(u8)] +pub enum ItemStackDescriptor { + Invalid { + #[endianness(var)] + id: i32, + } = 0, + Valid { + #[endianness(var)] + id: i32, + #[endianness(le)] + stack_size: u16, + #[endianness(le)] + aux_value: u16, + include_net_id_data: Option, + #[endianness(var)] + block_runtime_id: i32, + user_data_buffer: String, + } = 1, +} diff --git a/crates/proto/src/version/v729/types/item_stack_id_variant.rs b/crates/proto/src/version/v729/types/item_stack_id_variant.rs new file mode 100644 index 00000000..7bcc768c --- /dev/null +++ b/crates/proto/src/version/v729/types/item_stack_id_variant.rs @@ -0,0 +1,24 @@ +use bedrockrs_proto_core::error::ProtoCodecError; +use bedrockrs_proto_core::{ProtoCodec, ProtoCodecVAR}; +use std::io::Cursor; +use varint_rs::{VarintReader, VarintWriter}; + +#[derive(Debug, Clone)] +#[repr(transparent)] +pub struct ItemStackIdVariant(i32); + +impl ProtoCodec for ItemStackIdVariant { + fn proto_serialize(&self, stream: &mut Vec) -> Result<(), ProtoCodecError> { + stream.write_i32_varint(self.0)?; + Ok(()) + } + + fn proto_deserialize(stream: &mut Cursor<&[u8]>) -> Result { + let id = stream.read_i32_varint()?; + Ok(Self(id)) + } + + fn get_size_prediction(&self) -> usize { + self.0.get_size_prediction() + } +} diff --git a/crates/proto/src/types/level_settings.rs b/crates/proto/src/version/v729/types/level_settings.rs similarity index 56% rename from crates/proto/src/types/level_settings.rs rename to crates/proto/src/version/v729/types/level_settings.rs index 481e9134..5f52b5ab 100644 --- a/crates/proto/src/types/level_settings.rs +++ b/crates/proto/src/version/v729/types/level_settings.rs @@ -1,22 +1,22 @@ -use bedrockrs_core::int::{LE, VAR}; -use bedrockrs_proto_macros::ProtoCodec; +use bedrockrs_macros::ProtoCodec; use bedrockrs_shared::world::difficulty::Difficulty; use bedrockrs_shared::world::gamemode::Gamemode; use bedrockrs_shared::world::generator_type::GeneratorType; -use crate::types::base_game_version::BaseGameVersion; -use crate::types::block_pos::BlockPos; -use crate::types::chat_restriction_level::ChatRestrictionLevel; -use crate::types::edu_shared_uri_resource::EduSharedResourceUri; -use crate::types::experiments::Experiments; -use crate::types::gamerule::GameRule; -use crate::types::spawn_settings::SpawnSettings; +use crate::version::v729::types::base_game_version::BaseGameVersion; +use crate::version::v729::types::block_pos::BlockPos; +use crate::version::v729::types::chat_restriction_level::ChatRestrictionLevel; +use crate::version::v729::types::edu_shared_uri_resource::EduSharedResourceUri; +use crate::version::v729::types::experiments::Experiments; +use crate::version::v729::types::gamerule::GameRule; +use crate::version::v729::types::spawn_settings::SpawnSettings; use bedrockrs_shared::world::editor_world_type::EditorWorldType; #[derive(ProtoCodec, Debug, Clone)] pub struct LevelSettings { - pub seed: LE, + #[endianness(le)] + pub seed: u64, pub spawn_settings: SpawnSettings, pub generator_type: GeneratorType, pub gamemode: Gamemode, @@ -27,28 +27,39 @@ pub struct LevelSettings { pub editor_world_type: EditorWorldType, pub created_in_editor: bool, pub exported_from_editor: bool, - pub day_cycle_stop_time: VAR, - pub education_edition_offer: VAR, + #[endianness(var)] + pub day_cycle_stop_time: i32, + // TODO: Turn into enum + #[endianness(var)] + pub education_edition_offer: i32, pub education_features: bool, pub education_product_id: String, - pub rain_level: LE, - pub lightning_level: LE, + #[endianness(le)] + pub rain_level: f32, + #[endianness(le)] + pub lightning_level: f32, pub platform_locked_content: bool, pub multiplayer_intended: bool, pub lan_broadcasting_intended: bool, // TODO turn into enum - pub broadcasting_settings_xbox_live: VAR, - pub broadcasting_settings_platform: VAR, - pub commands_enabled: bool, + #[endianness(var)] + pub broadcasting_settings_xbox_live: i32, + // TODO: Turn into enum + #[endianness(var)] + pub broadcasting_settings_platform: i32, + pub commands: bool, pub texture_pack_required: bool, - #[len_repr(VAR::)] + #[vec_repr(u32)] + #[vec_endianness(var)] pub gamerules: Vec, pub experiments: Experiments, pub bonus_chest: bool, pub start_with_map: bool, // TODO turn into enum - pub player_permission: VAR, - pub server_chunk_tick_radius: LE, + #[endianness(var)] + pub player_permission: i32, + #[endianness(le)] + pub server_chunk_tick_radius: i32, pub locked_behavior_packs: bool, pub locked_resource_packs: bool, pub from_locked_template: bool, @@ -60,11 +71,13 @@ pub struct LevelSettings { pub custom_skins_disabled: bool, pub emote_chat_muted: bool, pub base_game_version: BaseGameVersion, - pub limited_world_width: LE, - pub limited_world_depth: LE, + #[endianness(le)] + pub limited_world_width: i32, + #[endianness(le)] + pub limited_world_depth: i32, pub new_nether: bool, pub edu_shared_uri_resource: EduSharedResourceUri, - pub force_experimental_gameplay: bool, + pub force_experimental_gameplay: Option, pub chat_restriction_level: ChatRestrictionLevel, pub disable_player_interactions: bool, pub server_id: String, diff --git a/crates/proto/src/types/loading_screen_action.rs b/crates/proto/src/version/v729/types/loading_screen_action.rs similarity index 54% rename from crates/proto/src/types/loading_screen_action.rs rename to crates/proto/src/version/v729/types/loading_screen_action.rs index 67c0d77f..030cb88e 100644 --- a/crates/proto/src/types/loading_screen_action.rs +++ b/crates/proto/src/version/v729/types/loading_screen_action.rs @@ -1,10 +1,10 @@ -use bedrockrs_proto_macros::ProtoCodec; -use bedrockrs_core::int::VAR; +use bedrockrs_macros::ProtoCodec; #[derive(ProtoCodec, Debug, Clone)] -#[enum_repr(VAR::)] +#[enum_repr(i32)] +#[enum_endianness(var)] pub enum LoadingScreenAction { Unknown = 0, Start = 1, End = 2, -} \ No newline at end of file +} diff --git a/crates/proto/src/types/mod.rs b/crates/proto/src/version/v729/types/mod.rs similarity index 87% rename from crates/proto/src/types/mod.rs rename to crates/proto/src/version/v729/types/mod.rs index b5cc384c..b6f71b5c 100644 --- a/crates/proto/src/types/mod.rs +++ b/crates/proto/src/version/v729/types/mod.rs @@ -5,7 +5,7 @@ pub mod actor_type; pub mod animate_action; pub mod attribute; pub mod base_game_version; -pub mod block_action; +pub mod block_actions; pub mod block_pos; pub mod chat_restriction_level; pub mod chunk_pos; @@ -15,8 +15,8 @@ pub mod container_id; pub mod container_type; pub mod credits_state; pub mod data_item; -pub mod disconnect_reason; pub mod edu_shared_uri_resource; +pub mod entity_info; pub mod event_type; pub mod experiments; pub mod gamerule; @@ -25,12 +25,12 @@ pub mod input_mode; pub mod interact_action; pub mod interaction_model; pub mod inventory_transaction; -pub mod item_stack_net_id_variant; +pub mod item_stack_descriptor; +pub mod item_stack_id_variant; pub mod level_settings; +pub mod loading_screen_action; pub mod modal_form_cancel_reason; -pub mod network_item_stack_descriptor; pub mod network_permissions; -pub mod pack_info_behavior; pub mod pack_info_resource; pub mod pack_url; pub mod play_mode; @@ -46,4 +46,3 @@ pub mod spawn_biome_type; pub mod spawn_settings; pub mod text_message_data; pub mod title_type; -pub mod loading_screen_action; diff --git a/crates/proto/src/types/modal_form_cancel_reason.rs b/crates/proto/src/version/v729/types/modal_form_cancel_reason.rs similarity index 52% rename from crates/proto/src/types/modal_form_cancel_reason.rs rename to crates/proto/src/version/v729/types/modal_form_cancel_reason.rs index 75809237..09047936 100644 --- a/crates/proto/src/types/modal_form_cancel_reason.rs +++ b/crates/proto/src/version/v729/types/modal_form_cancel_reason.rs @@ -1,8 +1,7 @@ -use bedrockrs_core::int::LE; -use bedrockrs_proto_macros::ProtoCodec; +use bedrockrs_macros::ProtoCodec; #[derive(ProtoCodec, Debug, Clone)] -#[enum_repr(LE::)] +#[enum_repr(i8)] pub enum ModalFormCancelReason { Closed = 0, Busy = 1, diff --git a/crates/proto/src/version/v729/types/network_permissions.rs b/crates/proto/src/version/v729/types/network_permissions.rs new file mode 100644 index 00000000..286d5aa9 --- /dev/null +++ b/crates/proto/src/version/v729/types/network_permissions.rs @@ -0,0 +1,6 @@ +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Debug, Clone)] +pub struct NetworkPermissions { + pub server_auth_sound: bool, +} diff --git a/crates/proto/src/version/v729/types/pack_info_resource.rs b/crates/proto/src/version/v729/types/pack_info_resource.rs new file mode 100644 index 00000000..d6f8f2f0 --- /dev/null +++ b/crates/proto/src/version/v729/types/pack_info_resource.rs @@ -0,0 +1,14 @@ +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Debug, Clone)] +pub struct ResourcePackInfoType { + pub id: String, + pub version: String, + #[endianness(le)] + pub size: u64, + pub content_key: String, + pub sub_pack_name: String, + pub content_identify: String, + pub has_scripts: bool, + pub ray_tracing_capable: bool, +} diff --git a/crates/proto/src/types/pack_url.rs b/crates/proto/src/version/v729/types/pack_url.rs similarity index 72% rename from crates/proto/src/types/pack_url.rs rename to crates/proto/src/version/v729/types/pack_url.rs index daa87e63..8ba0658c 100644 --- a/crates/proto/src/types/pack_url.rs +++ b/crates/proto/src/version/v729/types/pack_url.rs @@ -5,9 +5,9 @@ use bedrockrs_proto_core::ProtoCodec; #[derive(Debug, Clone)] pub struct PackURL { - uuid: String, - version: String, - url: String, + pub uuid: String, + pub version: String, + pub url: String, } impl ProtoCodec for PackURL { @@ -26,9 +26,9 @@ impl ProtoCodec for PackURL { fn proto_deserialize(stream: &mut Cursor<&[u8]>) -> Result { let (uuid, version) = match String::proto_deserialize(stream)?.split_once("_") { None => { - return Err(ProtoCodecError::FormatMismatch(String::from( - "Expected uuid and version of pack url to be seperated by _", - ))); + return Err(ProtoCodecError::FormatMismatch( + "Expected uuid and version of pack url to be seperated by an underscore", + )); } Some((u, v)) => (u.to_string(), v.to_string()), }; @@ -37,4 +37,10 @@ impl ProtoCodec for PackURL { Ok(Self { uuid, version, url }) } + + fn get_size_prediction(&self) -> usize { + self.uuid.get_size_prediction() + + self.version.get_size_prediction() + + self.url.get_size_prediction() + } } diff --git a/crates/proto/src/types/play_mode.rs b/crates/proto/src/version/v729/types/play_mode.rs similarity index 56% rename from crates/proto/src/types/play_mode.rs rename to crates/proto/src/version/v729/types/play_mode.rs index b9e008d1..0594e88f 100644 --- a/crates/proto/src/types/play_mode.rs +++ b/crates/proto/src/version/v729/types/play_mode.rs @@ -1,6 +1,4 @@ -use bedrockrs_core::int::{LE, VAR}; -use bedrockrs_core::Vec3; -use bedrockrs_proto_macros::ProtoCodec; +use vek::Vec3; #[derive(Debug, Clone)] pub enum PlayMode { @@ -8,7 +6,7 @@ pub enum PlayMode { Teaser, Screen, Viewer, - Reality(Vec3>), + Reality(Vec3), Placement, LivingRoom, ExitLevel, diff --git a/crates/proto/src/types/play_status.rs b/crates/proto/src/version/v729/types/play_status.rs similarity index 82% rename from crates/proto/src/types/play_status.rs rename to crates/proto/src/version/v729/types/play_status.rs index 12cb58d8..1cffe42e 100644 --- a/crates/proto/src/types/play_status.rs +++ b/crates/proto/src/version/v729/types/play_status.rs @@ -1,8 +1,8 @@ -use bedrockrs_core::int::BE; -use bedrockrs_proto_macros::ProtoCodec; +use bedrockrs_macros::ProtoCodec; #[derive(ProtoCodec, Debug, Copy, Clone, Eq, PartialEq)] -#[enum_repr(BE::)] +#[enum_repr(i32)] +#[enum_endianness(be)] pub enum PlayStatusType { /// Sent after Login has been successfully decoded and the player has logged in LoginSuccess = 0, @@ -20,6 +20,8 @@ pub enum PlayStatusType { FailedEditionMismatchVanillaToEdu = 6, /// Displays "Wow this server is popular! Check back later to see if space opens up. Server Full" FailedServerFull = 7, + /// Displays "The server is not in Editor Mode. Failed to connect." FailedEditorMismatchEditorToVanilla = 8, + /// Displays "The server is in Editor Mode. Failed to connect." FailedEditorMismatchVanillaToEditor = 9, } diff --git a/crates/proto/src/types/player_action_type.rs b/crates/proto/src/version/v729/types/player_action_type.rs similarity index 91% rename from crates/proto/src/types/player_action_type.rs rename to crates/proto/src/version/v729/types/player_action_type.rs index beeae950..0434e716 100644 --- a/crates/proto/src/types/player_action_type.rs +++ b/crates/proto/src/version/v729/types/player_action_type.rs @@ -1,8 +1,8 @@ -use bedrockrs_core::int::VAR; -use bedrockrs_proto_macros::ProtoCodec; +use bedrockrs_macros::ProtoCodec; #[derive(ProtoCodec, Debug, Copy, Clone, Eq, PartialEq)] -#[enum_repr(VAR::)] +#[enum_repr(i32)] +#[enum_endianness(var)] pub enum PlayerActionType { Unknown = -1, StartDestroyBlock = 0, diff --git a/crates/proto/src/types/player_movement_mode.rs b/crates/proto/src/version/v729/types/player_movement_mode.rs similarity index 57% rename from crates/proto/src/types/player_movement_mode.rs rename to crates/proto/src/version/v729/types/player_movement_mode.rs index 3430a037..b7cf371f 100644 --- a/crates/proto/src/types/player_movement_mode.rs +++ b/crates/proto/src/version/v729/types/player_movement_mode.rs @@ -1,8 +1,8 @@ -use bedrockrs_core::int::VAR; -use bedrockrs_proto_macros::ProtoCodec; +use bedrockrs_macros::ProtoCodec; #[derive(ProtoCodec, Debug, Clone)] -#[enum_repr(VAR::)] +#[enum_repr(i32)] +#[enum_endianness(var)] pub enum PlayerMovementMode { Client = 0, Server = 1, diff --git a/crates/proto/src/version/v729/types/player_movement_settings.rs b/crates/proto/src/version/v729/types/player_movement_settings.rs new file mode 100644 index 00000000..a75d50cf --- /dev/null +++ b/crates/proto/src/version/v729/types/player_movement_settings.rs @@ -0,0 +1,11 @@ +use bedrockrs_macros::ProtoCodec; + +use crate::version::v729::types::player_movement_mode::PlayerMovementMode; + +#[derive(ProtoCodec, Debug, Clone)] +pub struct PlayerMovementSettings { + pub authority_mode: PlayerMovementMode, + #[endianness(var)] + pub rewind_history_size: i32, + pub server_auth_block_breaking: bool, +} diff --git a/crates/proto/src/types/property_sync_data.rs b/crates/proto/src/version/v729/types/property_sync_data.rs similarity index 59% rename from crates/proto/src/types/property_sync_data.rs rename to crates/proto/src/version/v729/types/property_sync_data.rs index 2780795d..eca7d1a0 100644 --- a/crates/proto/src/types/property_sync_data.rs +++ b/crates/proto/src/version/v729/types/property_sync_data.rs @@ -1,4 +1,4 @@ -use bedrockrs_core::int::{LE, VAR}; +use bedrockrs_macros::ProtoCodec; #[derive(ProtoCodec, Debug, Clone)] pub struct PropertySyncData { @@ -6,27 +6,32 @@ pub struct PropertySyncData { pub float: FloatEntriesList, } -use bedrockrs_proto_macros::ProtoCodec; #[derive(ProtoCodec, Debug, Clone)] pub struct IntEntriesList { - #[len_repr(VAR::)] + #[vec_repr(u32)] + #[vec_endianness(var)] pub entries: Vec, } #[derive(ProtoCodec, Debug, Clone)] -pub struct FloatEntriesList { - #[len_repr(VAR::)] - pub entries: Vec, +pub struct IntEntry { + #[endianness(var)] + pub property_index: u32, + #[endianness(var)] + pub data: i32, } #[derive(ProtoCodec, Debug, Clone)] -pub struct IntEntry { - pub property_index: VAR, - pub data: VAR, +pub struct FloatEntriesList { + #[vec_repr(u32)] + #[vec_endianness(var)] + pub entries: Vec, } #[derive(ProtoCodec, Debug, Clone)] pub struct FloatEntry { - pub property_index: VAR, - pub data: LE, + #[endianness(var)] + pub property_index: u32, + #[endianness(le)] + pub data: f32, } diff --git a/crates/proto/src/types/resource_packs_response_status.rs b/crates/proto/src/version/v729/types/resource_packs_response_status.rs similarity index 67% rename from crates/proto/src/types/resource_packs_response_status.rs rename to crates/proto/src/version/v729/types/resource_packs_response_status.rs index c792008d..ad547d11 100644 --- a/crates/proto/src/types/resource_packs_response_status.rs +++ b/crates/proto/src/version/v729/types/resource_packs_response_status.rs @@ -1,8 +1,7 @@ -use bedrockrs_core::int::LE; -use bedrockrs_proto_macros::ProtoCodec; +use bedrockrs_macros::ProtoCodec; #[derive(ProtoCodec, Debug, Copy, Clone, Eq, PartialEq)] -#[enum_repr(LE::)] +#[enum_repr(i8)] pub enum ResourcePacksResponseStatus { None = 0, Refused = 1, diff --git a/crates/proto/src/types/resource_packs_stack_pack.rs b/crates/proto/src/version/v729/types/resource_packs_stack_pack.rs similarity index 79% rename from crates/proto/src/types/resource_packs_stack_pack.rs rename to crates/proto/src/version/v729/types/resource_packs_stack_pack.rs index f86feaae..9f47f962 100644 --- a/crates/proto/src/types/resource_packs_stack_pack.rs +++ b/crates/proto/src/version/v729/types/resource_packs_stack_pack.rs @@ -1,4 +1,4 @@ -use bedrockrs_proto_macros::ProtoCodec; +use bedrockrs_macros::ProtoCodec; #[derive(ProtoCodec, Debug, Clone)] pub struct ResourcePacksStackPack { diff --git a/crates/proto/src/types/respawn_state.rs b/crates/proto/src/version/v729/types/respawn_state.rs similarity index 60% rename from crates/proto/src/types/respawn_state.rs rename to crates/proto/src/version/v729/types/respawn_state.rs index b5d32817..eb0007ac 100644 --- a/crates/proto/src/types/respawn_state.rs +++ b/crates/proto/src/version/v729/types/respawn_state.rs @@ -1,8 +1,7 @@ -use bedrockrs_core::int::LE; -use bedrockrs_proto_macros::ProtoCodec; +use bedrockrs_macros::ProtoCodec; #[derive(ProtoCodec, Debug, Clone)] -#[enum_repr(LE::)] +#[enum_repr(i8)] pub enum RespawnState { SearchingForSpawn = 0, ReadyToSpawn = 1, diff --git a/crates/proto/src/version/v729/types/spawn_biome_type.rs b/crates/proto/src/version/v729/types/spawn_biome_type.rs new file mode 100644 index 00000000..5c45c58f --- /dev/null +++ b/crates/proto/src/version/v729/types/spawn_biome_type.rs @@ -0,0 +1,9 @@ +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Debug, Clone)] +#[enum_repr(i16)] +#[enum_endianness(le)] +pub enum SpawnBiomeType { + Default = 0, + UserDefined = 1, +} diff --git a/crates/proto/src/types/spawn_settings.rs b/crates/proto/src/version/v729/types/spawn_settings.rs similarity index 69% rename from crates/proto/src/types/spawn_settings.rs rename to crates/proto/src/version/v729/types/spawn_settings.rs index f97973a5..dee9b666 100644 --- a/crates/proto/src/types/spawn_settings.rs +++ b/crates/proto/src/version/v729/types/spawn_settings.rs @@ -1,8 +1,8 @@ -use bedrockrs_proto_macros::ProtoCodec; +use bedrockrs_macros::ProtoCodec; use bedrockrs_shared::world::dimension::Dimension; -use crate::types::spawn_biome_type::SpawnBiomeType; +use crate::version::v729::types::spawn_biome_type::SpawnBiomeType; #[derive(ProtoCodec, Debug, Clone)] pub struct SpawnSettings { diff --git a/crates/proto/src/version/v729/types/text_message_data.rs b/crates/proto/src/version/v729/types/text_message_data.rs new file mode 100644 index 00000000..4e08705a --- /dev/null +++ b/crates/proto/src/version/v729/types/text_message_data.rs @@ -0,0 +1,67 @@ +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Debug, Clone)] +#[enum_repr(i8)] +#[repr(i8)] +pub enum TextMessageData { + Raw { + localize: bool, + message: String, + } = 0, + Chat { + localize: bool, + player_name: String, + message: String, + } = 1, + Translate { + localize: bool, + message: String, + #[vec_repr(u32)] + #[vec_endianness(var)] + parameters: Vec, + } = 2, + Popup { + localize: bool, + message: String, + #[vec_repr(u32)] + #[vec_endianness(var)] + parameters: Vec, + } = 3, + JukeboxPopup { + localize: bool, + message: String, + #[vec_repr(u32)] + #[vec_endianness(var)] + parameters: Vec, + } = 4, + Tip { + localize: bool, + message: String, + } = 5, + SystemMessage { + localize: bool, + message: String, + } = 6, + Whisper { + localize: bool, + player_name: String, + message: String, + } = 7, + Announcement { + localize: bool, + player_name: String, + message: String, + } = 8, + TextObjectWhisper { + localize: bool, + message: String, + } = 9, + TextObject { + localize: bool, + message: String, + } = 10, + TextObjectAnnouncement { + localize: bool, + message: String, + } = 11, +} diff --git a/crates/proto/src/types/title_type.rs b/crates/proto/src/version/v729/types/title_type.rs similarity index 73% rename from crates/proto/src/types/title_type.rs rename to crates/proto/src/version/v729/types/title_type.rs index 502dcf76..b69c6625 100644 --- a/crates/proto/src/types/title_type.rs +++ b/crates/proto/src/version/v729/types/title_type.rs @@ -1,8 +1,8 @@ -use bedrockrs_core::int::VAR; -use bedrockrs_proto_macros::ProtoCodec; +use bedrockrs_macros::ProtoCodec; #[derive(ProtoCodec, Debug, Copy, Clone, Eq, PartialEq)] -#[enum_repr(VAR::)] +#[enum_repr(i32)] +#[enum_endianness(var)] pub enum TitleType { Clear = 0, Reset = 1, diff --git a/crates/proto/src/version/v748/mod.rs b/crates/proto/src/version/v748/mod.rs new file mode 100644 index 00000000..b8d0428d --- /dev/null +++ b/crates/proto/src/version/v748/mod.rs @@ -0,0 +1 @@ +//! r/21_u4 diff --git a/crates/proto/src/version/v766/enums/boss_event_update_type.rs b/crates/proto/src/version/v766/enums/boss_event_update_type.rs new file mode 100644 index 00000000..2641cf1e --- /dev/null +++ b/crates/proto/src/version/v766/enums/boss_event_update_type.rs @@ -0,0 +1,51 @@ +use crate::version::v662::types::ActorUniqueID; +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +#[enum_repr(u32)] +#[enum_endianness(var)] +#[repr(u32)] +pub enum BossEventUpdateType { + Add { + name: String, + #[endianness(le)] + health_percent: f32, + #[endianness(le)] + darken_screen: u16, + #[endianness(var)] + color: u32, + #[endianness(var)] + overlay: u32, + } = 0, + PlayerAdded { + player_id: ActorUniqueID, + } = 1, + Remove = 2, + PlayerRemoved { + player_id: ActorUniqueID, + } = 3, + UpdatePercent { + #[endianness(le)] + health_percent: f32, + } = 4, + UpdateName { + name: String, + } = 5, + UpdateProperties { + #[endianness(le)] + darken_screen: u16, + #[endianness(var)] + color: u32, + #[endianness(var)] + overlay: u32, + } = 6, + UpdateStyle { + #[endianness(var)] + color: u32, + #[endianness(var)] + overlay: u32, + } = 7, + Query { + player_id: ActorUniqueID, + } = 8, +} \ No newline at end of file diff --git a/crates/proto/src/version/v766/enums/code_builder_execution_state.rs b/crates/proto/src/version/v766/enums/code_builder_execution_state.rs new file mode 100644 index 00000000..dcc348fb --- /dev/null +++ b/crates/proto/src/version/v766/enums/code_builder_execution_state.rs @@ -0,0 +1,13 @@ +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +#[enum_repr(i8)] +#[repr(i8)] +pub enum CodeBuilderExecutionState { + None = 0, + NotStarted = 1, + InProgress = 2, + Paused = 3, + Error = 4, + Succeeded = 5, +} \ No newline at end of file diff --git a/crates/proto/src/version/v766/enums/crafting_data_entry_type.rs b/crates/proto/src/version/v766/enums/crafting_data_entry_type.rs new file mode 100644 index 00000000..321fd954 --- /dev/null +++ b/crates/proto/src/version/v766/enums/crafting_data_entry_type.rs @@ -0,0 +1,65 @@ +use crate::version::v662::types::{NetworkItemInstanceDescriptor, SmithingTransformRecipe, SmithingTrimRecipe}; +use crate::version::v766::types::{ShapedChemistryRecipe, ShapedRecipe, ShapelessRecipe, UserDataShapelessRecipe}; +use bedrockrs_macros::ProtoCodec; +use uuid::Uuid; + +#[derive(ProtoCodec, Clone, Debug)] +#[enum_repr(i32)] +#[enum_endianness(var)] +#[repr(i32)] +pub enum CraftingDataEntryType { + ShapelessRecipe { + shapeless_recipe: ShapelessRecipe, + #[endianness(var)] + net_id: i32, + } = 0, + ShapedRecipe { + shaped_recipe: ShapedRecipe, + #[endianness(var)] + net_id: i32, + } = 1, + FurnaceRecipe { + #[endianness(var)] + item_data: i32, + result_item: NetworkItemInstanceDescriptor, + recipe_tag: String, + } = 2, + FurnaceAuxRecipe { + #[endianness(var)] + item_data: i32, + #[endianness(var)] + auxiliary_item_data: i32, + result_item: NetworkItemInstanceDescriptor, + recipe_tag: String, + } = 3, + MultiRecipe { + multi_recipe: Uuid, + #[endianness(var)] + net_id: i32, + } = 4, + UserDataShapelessRecipe { + user_data_shapeless_recipe: UserDataShapelessRecipe, + #[endianness(var)] + net_id: i32, + } = 5, + ShapelessChemistryRecipe { + shapeless_chemistry_recipe: ShapelessRecipe, + #[endianness(var)] + net_id: i32, + } = 6, + ShapedChemistryRecipe { + shaped_chemistry_recipe: ShapedChemistryRecipe, + #[endianness(var)] + net_id: i32, + } = 7, + SmithingTransformRecipe { + smithing_transform_recipe: SmithingTransformRecipe, + #[endianness(var)] + net_id: i32 + } = 8, + SmithingTrimRecipe { + smithing_trim_recipe: SmithingTrimRecipe, + #[endianness(var)] + net_id: i32 + } = 9, +} diff --git a/crates/proto/src/version/v766/enums/data_item_type.rs b/crates/proto/src/version/v766/enums/data_item_type.rs new file mode 100644 index 00000000..db3740b4 --- /dev/null +++ b/crates/proto/src/version/v766/enums/data_item_type.rs @@ -0,0 +1,19 @@ +use crate::version::v662::types::BlockPos; +use bedrockrs_macros::ProtoCodec; +use vek::Vec3; + +#[derive(ProtoCodec, Clone, Debug)] +#[enum_repr(u32)] +#[enum_endianness(var)] +#[repr(u32)] +pub enum DataItemType { + Byte(i8) = 0, + Short(#[endianness(le)] i16) = 1, + Int(#[endianness(var)] i32) = 2, + Float(#[endianness(le)] f32) = 3, + String(String) = 4, + NBT(#[nbt] nbtx::Value) = 5, + Pos(BlockPos) = 6, + Int64(#[endianness(var)] i64) = 7, + Vec3(#[endianness(le)] Vec3) = 8, +} \ No newline at end of file diff --git a/crates/proto/src/version/v766/enums/item_stack_net_result.rs b/crates/proto/src/version/v766/enums/item_stack_net_result.rs new file mode 100644 index 00000000..1a81ae0f --- /dev/null +++ b/crates/proto/src/version/v766/enums/item_stack_net_result.rs @@ -0,0 +1,80 @@ +use crate::version::v766::types::ItemStackResponseContainerInfo; +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +#[enum_repr(i8)] +#[repr(i8)] +pub enum ItemStackNetResult { + Success( + #[vec_repr(u32)] + #[vec_endianness(var)] + Vec, + ) = 0, + Error = 1, + InvalidRequestActionType = 2, + ActionRequestNotAllowed = 3, + ScreenHandlerEndRequestFailed = 4, + ItemRequestActionHandlerCommitFailed = 5, + InvalidRequestCraftActionType = 6, + InvalidCraftRequest = 7, + InvalidCraftRequestScreen = 8, + InvalidCraftResult = 9, + InvalidCraftResultIndex = 10, + InvalidCraftResultItem = 11, + InvalidItemNetId = 12, + MissingCreatedOutputContainer = 13, + FailedToSetCreatedItemOutputSlot = 14, + RequestAlreadyInProgress = 15, + FailedToInitSparseContainer = 16, + ResultTransferFailed = 17, + ExpectedItemSlotNotFullyConsumed = 18, + ExpectedAnywhereItemNotFullyConsumed = 19, + ItemAlreadyConsumedFromSlot = 20, + ConsumedTooMuchFromSlot = 21, + MismatchSlotExpectedConsumedItem = 22, + MismatchSlotExpectedConsumedItemNetIdVariant = 23, + FailedToMatchExpectedSlotConsumedItem = 24, + FailedToMatchExpectedAllowedAnywhereConsumedItem = 25, + ConsumedItemOutOfAllowedSlotRange = 26, + ConsumedItemNotAllowed = 27, + PlayerNotInCreativeMode = 28, + InvalidExperimentalRecipeRequest = 29, + FailedToCraftCreative = 30, + FailedToGetLevelRecipe = 31, + FailedToFindRecipeByNetId = 32, + MismatchedCraftingSize = 33, + MissingInputSparseContainer = 34, + MismatchedRecipeForInputGridItems = 35, + EmptyCraftResults = 36, + FailedToEnchant = 37, + MissingInputItem = 38, + InsufficientPlayerLevelToEnchant = 39, + MissingMaterialItem = 40, + MissingActor = 41, + UnknownPrimaryEffect = 42, + PrimaryEffectOutOfRange = 43, + PrimaryEffectUnavailable = 44, + SecondaryEffectOutOfRange = 45, + SecondaryEffectUnavailable = 46, + DstContainerEqualToCreatedOutputContainer = 47, + DstContainerAndSlotEqualToSrcContainerAndSlot = 48, + FailedToValidateSrcSlot = 49, + FailedToValidateDstSlot = 50, + InvalidAdjustedAmount = 51, + InvalidItemSetType = 52, + InvalidTransferAmount = 53, + CannotSwapItem = 54, + CannotPlaceItem = 55, + UnhandledItemSetType = 56, + InvalidRemovedAmount = 57, + InvalidRegion = 58, + CannotDropItem = 59, + CannotDestroyItem = 60, + InvalidSourceContainer = 61, + ItemNotConsumed = 62, + InvalidNumCrafts = 63, + InvalidCraftResultStackSize = 64, + CannotRemoveItem = 65, + CannotConsumeItem = 66, + ScreenStackError = 67, +} diff --git a/crates/proto/src/version/v766/enums/mod.rs b/crates/proto/src/version/v766/enums/mod.rs new file mode 100644 index 00000000..e02de864 --- /dev/null +++ b/crates/proto/src/version/v766/enums/mod.rs @@ -0,0 +1,16 @@ +macro_rules! export { + ($name:ident) => { + mod $name; + pub use $name::*; + }; +} + +export!(boss_event_update_type); +export!(code_builder_execution_state); +export!(recipe_unlocking_context); +export!(crafting_data_entry_type); +export!(data_item_type); +export!(player_action_type); +export!(player_list_packet_type); +export!(soft_enum_update_type); +export!(item_stack_net_result); diff --git a/crates/proto/src/version/v766/enums/player_action_type.rs b/crates/proto/src/version/v766/enums/player_action_type.rs new file mode 100644 index 00000000..5057a603 --- /dev/null +++ b/crates/proto/src/version/v766/enums/player_action_type.rs @@ -0,0 +1,68 @@ +use crate::version::v662::types::BlockPos; +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +#[enum_repr(i32)] +#[enum_endianness(var)] +#[repr(i32)] +pub enum PlayerActionType { + Unknown = -1, + StartDestroyBlock { + position: BlockPos, + #[endianness(var)] + facing: i32, + } = 0, + AbortDestroyBlock { + position: BlockPos, + #[endianness(var)] + facing: i32, + } = 1, + StopDestroyBlock = 2, + GetUpdatedBlock = 3, + DropItem = 4, + StartSleeping = 5, + StopSleeping = 6, + Respawn = 7, + StartJump = 8, + StartSprinting = 9, + StopSprinting = 10, + StartSneaking = 11, + StopSneaking = 12, + CreativeDestroyBlock = 13, + ChangeDimensionAck = 14, + StartGliding = 15, + StopGliding = 16, + DenyDestroyBlock = 17, + CrackBlock { + position: BlockPos, + #[endianness(var)] + facing: i32, + } = 18, + ChangeSkin = 19, + DeprecatedUpdatedEnchantingSeed = 20, + StartSwimming = 21, + StopSwimming = 22, + StartSpinAttack = 23, + StopSpinAttack = 24, + InteractWithBlock = 25, + PredictDestroyBlock { + position: BlockPos, + #[endianness(var)] + facing: i32, + } = 26, + ContinueDestroyBlock { + position: BlockPos, + #[endianness(var)] + facing: i32, + } = 27, + StartItemUseOn = 28, + StopItemUseOn = 29, + HandledTeleport = 30, + MissedSwing = 31, + StartCrawling = 32, + StopCrawling = 33, + StartFlying = 34, + StopFlying = 35, + ClientAckServerData = 36, + Count = 37, +} diff --git a/crates/proto/src/version/v766/enums/player_list_packet_type.rs b/crates/proto/src/version/v766/enums/player_list_packet_type.rs new file mode 100644 index 00000000..49489cda --- /dev/null +++ b/crates/proto/src/version/v766/enums/player_list_packet_type.rs @@ -0,0 +1,131 @@ +use crate::version::v662::enums::BuildPlatform; +use crate::version::v662::types::{ActorUniqueID, SerializedSkin}; +use bedrockrs_macros::ProtoCodec; +use bedrockrs_proto_core::error::ProtoCodecError; +use bedrockrs_proto_core::{ProtoCodec, ProtoCodecVAR}; +use std::io::Cursor; +use std::mem::size_of; +use uuid::Uuid; + +#[derive(ProtoCodec, Clone, Debug)] +pub struct AddPlayerListEntry { + pub uuid: Uuid, + pub target_actor_id: ActorUniqueID, + pub player_name: String, + pub xbl_xuid: String, + pub platform_chat_id: String, + pub build_platform: BuildPlatform, + pub serialized_skin: SerializedSkin, + pub is_teacher: bool, + pub is_host: bool, + pub is_sub_client: bool, + pub is_trusted_skin: bool, +} + +#[derive(Clone, Debug)] +#[repr(i8)] +pub enum PlayerListPacketType { + Add { + add_player_list: Vec, + } = 0, + Remove { + remove_player_list: Vec + } = 1, +} + +impl ProtoCodec for PlayerListPacketType { + fn proto_serialize(&self, stream: &mut Vec) -> Result<(), ProtoCodecError> { + match self { + PlayerListPacketType::Add { add_player_list } => { + i8::proto_serialize(&0, stream)?; + let len: u32 = add_player_list.len().try_into()?; + ::proto_serialize(&len, stream)?; + + for i in add_player_list { + i.uuid.proto_serialize(stream)?; + i.target_actor_id.proto_serialize(stream)?; + i.player_name.proto_serialize(stream)?; + i.xbl_xuid.proto_serialize(stream)?; + i.platform_chat_id.proto_serialize(stream)?; + i.build_platform.proto_serialize(stream)?; + i.serialized_skin.proto_serialize(stream)?; + i.is_teacher.proto_serialize(stream)?; + i.is_host.proto_serialize(stream)?; + i.is_sub_client.proto_serialize(stream)?; + } + + for i in add_player_list { + i.is_trusted_skin.proto_serialize(stream)?; + } + + Ok(()) + } + PlayerListPacketType::Remove { remove_player_list } => { + i8::proto_serialize(&1, stream)?; + let len = remove_player_list.len().try_into()?; + ::proto_serialize(&len, stream)?; + + for i in remove_player_list { + i.proto_serialize(stream)? + } + + Ok(()) + } + } + } + + fn proto_deserialize(stream: &mut Cursor<&[u8]>) -> Result { + let discriminant = i8::proto_deserialize(stream)?; + let len = ::proto_deserialize(stream)?; + let value = match discriminant { + 0 => { + let mut add_player_list = Vec::with_capacity(len.try_into()?); + for _ in 0..len { + add_player_list.push(AddPlayerListEntry { + uuid: Uuid::proto_deserialize(stream)?, + target_actor_id: ActorUniqueID::proto_deserialize(stream)?, + player_name: String::proto_deserialize(stream)?, + xbl_xuid: String::proto_deserialize(stream)?, + platform_chat_id: String::proto_deserialize(stream)?, + build_platform: BuildPlatform::proto_deserialize(stream)?, + serialized_skin: SerializedSkin::proto_deserialize(stream)?, + is_teacher: bool::proto_deserialize(stream)?, + is_host: bool::proto_deserialize(stream)?, + is_sub_client: bool::proto_deserialize(stream)?, + is_trusted_skin: false, + }) + } + + for i in &mut add_player_list { + i.is_trusted_skin = bool::proto_deserialize(stream)? + } + + PlayerListPacketType::Add { add_player_list } + } + 1 => { + let mut remove_player_list = Vec::with_capacity(len.try_into()?); + for _ in 0..len { + remove_player_list.push(Uuid::proto_deserialize(stream)?); + } + + PlayerListPacketType::Remove { remove_player_list } + } + _ => { panic!("Unknown discriminant {}", discriminant) } + }; + + Ok(value) + } + + fn get_size_prediction(&self) -> usize { + match self { + PlayerListPacketType::Add { add_player_list } => { + size_of::() + + add_player_list.iter().map(|i| i.get_size_prediction()).sum::() + } + PlayerListPacketType::Remove { remove_player_list } => { + size_of::() + + remove_player_list.iter().map(|i| i.get_size_prediction()).sum::() + } + } + } +} \ No newline at end of file diff --git a/crates/proto/src/version/v766/enums/recipe_unlocking_context.rs b/crates/proto/src/version/v766/enums/recipe_unlocking_context.rs new file mode 100644 index 00000000..35e4ec2a --- /dev/null +++ b/crates/proto/src/version/v766/enums/recipe_unlocking_context.rs @@ -0,0 +1,16 @@ +use crate::version::v662::types::RecipeIngredient; +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +#[enum_repr(i8)] +#[repr(i8)] +pub enum RecipeUnlockingContext { + None { + #[vec_repr(u32)] + #[vec_endianness(var)] + unlocking_ingredients: Vec + } = 0, + AlwaysUnlocked = 1, + PlayerInWater = 2, + PlayerHasManyItems = 3, +} \ No newline at end of file diff --git a/crates/proto/src/version/v766/enums/soft_enum_update_type.rs b/crates/proto/src/version/v766/enums/soft_enum_update_type.rs new file mode 100644 index 00000000..d7bacd58 --- /dev/null +++ b/crates/proto/src/version/v766/enums/soft_enum_update_type.rs @@ -0,0 +1,10 @@ +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +#[enum_repr(i8)] +#[repr(i8)] +pub enum SoftEnumUpdateType { + Add = 0, + Remove = 1, + Replace = 2, +} \ No newline at end of file diff --git a/crates/proto/src/version/v766/gamepackets.rs b/crates/proto/src/version/v766/gamepackets.rs new file mode 100644 index 00000000..a3f3d2f5 --- /dev/null +++ b/crates/proto/src/version/v766/gamepackets.rs @@ -0,0 +1,275 @@ +use crate::v766::packets::{ + AddActorPacket, AddItemActorPacket, AddPlayerPacket, AwardAchievementPacket, BossEventPacket, + CameraAimAssistPacket, CameraAimAssistPresetsPacket, CameraInstructionPacket, + CameraPresetsPacket, ChangeDimensionPacket, ClientBoundCloseFormPacket, + ClientBoundDebugRendererPacket, ClientBoundMapItemDataPacket, CodeBuilderSourcePacket, + ContainerClosePacket, ContainerRegistryCleanupPacket, CorrectPlayerMovePredictionPacket, + CraftingDataPacket, DisconnectPacket, EditorNetworkPacket, EmotePacket, InventoryContentPacket, + InventorySlotPacket, ItemStackRequestPacket, ItemStackResponsePacket, + JigsawStructureDataPacket, LegacyTelemetryEventPacket, MobArmorEquipmentPacket, + PlayerActionPacket, PlayerArmorDamagePacket, PlayerAuthInputPacket, PlayerListPacket, + ResourcePackStackPacket, ResourcePacksInfoPacket, ServerBoundDiagnosticsPacket, + ServerBoundLoadingScreenPacket, SetActorDataPacket, SetActorLinkPacket, + SetMovementAuthorityPacket, SetTitlePacket, StartGamePacket, StopSoundPacket, TextPacket, + TransferPlayerPacket, UpdateAttributesPacket, UpdatePlayerGameTypePacket, UpdateSoftEnumPacket, +}; +use crate::version::v662::packets::{ + ActorEventPacket, ActorPickRequestPacket, AddBehaviourTreePacket, AddPaintingPacket, + AddVolumeEntityPacket, AgentActionEventPacket, AgentAnimationPacket, AnimateEntityPacket, + AnimatePacket, AnvilDamagePacket, AutomationClientConnectPacket, + AvailableActorIdentifiersPacket, AvailableCommandsPacket, BiomeDefinitionListPacket, + BlockActorDataPacket, BlockEventPacket, BlockPickRequestPacket, BookEditPacket, CameraPacket, + CameraShakePacket, ChangeMobPropertyPacket, ChunkRadiusUpdatedPacket, + ClientCacheBlobStatusPacket, ClientCacheMissResponsePacket, ClientCacheStatusPacket, + ClientToServerHandshakePacket, CodeBuilderPacket, CommandBlockUpdatePacket, + CommandOutputPacket, CommandRequestPacket, CompletedUsingItemPacket, + CompressedBiomeDefinitionListPacket, ContainerOpenPacket, ContainerSetDataPacket, + CreatePhotoPacket, CreativeContentPacket, DeathInfoPacket, DebugInfoPacket, + DimensionDataPacket, EduUriResourcePacket, EducationSettingsPacket, EmoteListPacket, + FeatureRegistryPacket, GameRulesChangedPacket, GameTestRequestPacket, GameTestResultsPacket, + GuiDataPickItemPacket, HurtArmorPacket, InteractPacket, InventoryTransactionPacket, + ItemComponentPacket, LabTablePacket, LecternUpdatePacket, LessonProgressPacket, + LevelChunkPacket, LevelEventGenericPacket, LevelEventPacket, LevelSoundEventPacket, + LevelSoundEventPacketV1, LevelSoundEventPacketV2, LoginPacket, MapCreateLockedCopyPacket, + MapInfoRequestPacket, MobEffectPacket, MobEquipmentPacket, ModalFormRequestPacket, + ModalFormResponsePacket, MotionPredictionHintsPacket, MoveActorAbsolutePacket, + MoveActorDeltaPacket, MovePlayerPacket, MultiplayerSettingsPacket, + NetworkChunkPublisherUpdatePacket, NetworkSettingsPacket, NetworkStackLatencyPacket, + NpcDialoguePacket, NpcRequestPacket, OnScreenTextureAnimationPacket, OpenSignPacket, + PacketViolationWarningPacket, PassengerJumpPacket, PhotoTransferPacket, PlaySoundPacket, + PlayStatusPacket, PlayerEnchantOptionsPacket, PlayerFogPacket, PlayerHotbarPacket, + PlayerInputPacket, PlayerSkinPacket, PlayerStartItemCooldownPacket, + PlayerToggleCrafterSlotRequestPacket, PositionTrackingDBClientRequestPacket, + PositionTrackingDBServerBroadcastPacket, PurchaseReceiptPacket, RefreshEntitlementsPacket, + RemoveActorPacket, RemoveObjectivePacket, RemoveVolumeEntityPacket, RequestAbilityPacket, + RequestChunkRadiusPacket, RequestNetworkSettingsPacket, RequestPermissionsPacket, + ResourcePackChunkDataPacket, ResourcePackChunkRequestPacket, ResourcePackClientResponsePacket, + ResourcePackDataInfoPacket, RespawnPacket, ScriptMessagePacket, + ServerPlayerPostMovePositionPacket, ServerSettingsRequestPacket, ServerSettingsResponsePacket, + ServerStatsPacket, ServerToClientHandshakePacket, SetActorMotionPacket, + SetCommandsEnabledPacket, SetDefaultGameTypePacket, SetDifficultyPacket, + SetDisplayObjectivePacket, SetHealthPacket, SetHudPacket, SetLastHurtByPacket, + SetLocalPlayerAsInitializedPacket, SetPlayerGameTypePacket, SetPlayerInventoryOptionsPacket, + SetScorePacket, SetScoreboardIdentityPacket, SetSpawnPositionPacket, SetTimePacket, + SettingsCommandPacket, ShowCreditsPacket, ShowProfilePacket, ShowStoreOfferPacket, + SimpleEventPacket, SimulationTypePacket, SpawnExperienceOrbPacket, SpawnParticleEffectPacket, + StructureBlockUpdatePacket, StructureDataRequestPacket, StructureDataResponsePacket, + SubChunkPacket, SubChunkRequestPacket, SubClientLoginPacket, SyncActorPropertyPacket, + TakeItemActorPacket, TickSyncPacket, TickingAreaLoadStatusPacket, ToastRequestPacket, + TrimDataPacket, UnlockedRecipesPacket, UpdateAbilitiesPacket, UpdateAdventureSettingsPacket, + UpdateBlockPacket, UpdateBlockSyncedPacket, UpdateClientInputLocksPacket, UpdateEquipPacket, + UpdateSubChunkBlocksPacket, UpdateTradePacket, +}; +use crate::version::v662::{ + get_gamepacket_header_size_prediction, read_gamepacket_header, write_gamepacket_header, +}; +use bedrockrs_macros::gamepackets; +use bedrockrs_proto_core::sub_client::SubClientID; +use std::io::{Cursor, Write}; + +gamepackets! { + CameraAimAssist: CameraAimAssistPacket, + CameraAimAssistPresets: CameraAimAssistPresetsPacket, + AwardAchievent: AwardAchievementPacket, + ClientBoundCloseForm: ClientBoundCloseFormPacket, + ContainerRegistryCleanup: ContainerRegistryCleanupPacket, + JigsawStructureData: JigsawStructureDataPacket, + ServerboundDiagnostics: ServerBoundDiagnosticsPacket, + ServerBoundLoadingScreen: ServerBoundLoadingScreenPacket, + SetMovementAuthority: SetMovementAuthorityPacket, + Login: LoginPacket, + PlaySatus: PlayStatusPacket, + ServerToClientHandshake: ServerToClientHandshakePacket, + ClientToServerHandshake: ClientToServerHandshakePacket, + Disconnect: DisconnectPacket, + ResourcePacksInfo: ResourcePacksInfoPacket, + ResourcePackStack: ResourcePackStackPacket, + ResourcePackClientResponse: ResourcePackClientResponsePacket, + Text: TextPacket, + SetTime: SetTimePacket, + StartGame: StartGamePacket, + AddPlayer: AddPlayerPacket, + AddActor: AddActorPacket, + RemoveActor: RemoveActorPacket, + AddItemActor: AddItemActorPacket, + ServerPlayerPostMovePosition: ServerPlayerPostMovePositionPacket, + TakeItemActor: TakeItemActorPacket, + MoveActorAbsolute: MoveActorAbsolutePacket, + MovePlayer: MovePlayerPacket, + PassengerJump: PassengerJumpPacket, + UpdateBlock: UpdateBlockPacket, + AddPainting: AddPaintingPacket, + TickSync: TickSyncPacket, + LevelSoundEventV1: LevelSoundEventPacketV1, + LevelEvent: LevelEventPacket, + BlockEvent: BlockEventPacket, + ActorEvent: ActorEventPacket, + MobEffect: MobEffectPacket, + UpdateAttributes: UpdateAttributesPacket, + InventoryTransaction: InventoryTransactionPacket, + MobEquipment: MobEquipmentPacket, + MobArmorEquipment: MobArmorEquipmentPacket, + Interact: InteractPacket, + BlockPickRequest: BlockPickRequestPacket, + ActorPickRequest: ActorPickRequestPacket, + PlayerAction: PlayerActionPacket, + HurtArmor: HurtArmorPacket, + SetActorData: SetActorDataPacket, + SetActorMotion: SetActorMotionPacket, + SetActorLink: SetActorLinkPacket, + SetHealth: SetHealthPacket, + SetSpawnPosition: SetSpawnPositionPacket, + Animate: AnimatePacket, + Respawn: RespawnPacket, + ContainerOpen: ContainerOpenPacket, + ContainerClose: ContainerClosePacket, + PlayerHotbar: PlayerHotbarPacket, + InventoryContent: InventoryContentPacket, + InventorySlot: InventorySlotPacket, + ContainerSetData: ContainerSetDataPacket, + CraftingData: CraftingDataPacket, + GuiDataPickItem: GuiDataPickItemPacket, + BlockActorData: BlockActorDataPacket, + PlayerInput: PlayerInputPacket, + LevelChunk: LevelChunkPacket, + SetCommandsEnabled: SetCommandsEnabledPacket, + SetDifficulty: SetDifficultyPacket, + ChangeDimension: ChangeDimensionPacket, + SetPlayerGameType: SetPlayerGameTypePacket, + PlayerList: PlayerListPacket, + SimpleEvent: SimpleEventPacket, + LegacyTelemetryEvent: LegacyTelemetryEventPacket, + SpawnExperienceOrb: SpawnExperienceOrbPacket, + ClientBoundMapItemData: ClientBoundMapItemDataPacket, + MapInfoRequest: MapInfoRequestPacket, + RequestChunkRadius: RequestChunkRadiusPacket, + ChunkRadiusUpdated: ChunkRadiusUpdatedPacket, + GameRulesChanged: GameRulesChangedPacket, + Camera: CameraPacket, + BossEvent: BossEventPacket, + ShowCredits: ShowCreditsPacket, + AvailableCommands: AvailableCommandsPacket, + CommandRequest: CommandRequestPacket, + CommandBlockUpdate: CommandBlockUpdatePacket, + CommandOutput: CommandOutputPacket, + UpdateTrade: UpdateTradePacket, + UpdateEquip: UpdateEquipPacket, + ResourcePackDataInfo: ResourcePackDataInfoPacket, + ResourcePackChunkData: ResourcePackChunkDataPacket, + ResourcePackChunkRequest: ResourcePackChunkRequestPacket, + TransferPlayer: TransferPlayerPacket, + PlaySound: PlaySoundPacket, + StopSound: StopSoundPacket, + SetTitle: SetTitlePacket, + AddBehaviourTree: AddBehaviourTreePacket, + StructureBlockUpdate: StructureBlockUpdatePacket, + ShowStoreOffer: ShowStoreOfferPacket, + PurchaseReceipt: PurchaseReceiptPacket, + PlayerSkin: PlayerSkinPacket, + SubClientLogin: SubClientLoginPacket, + AutomationClientConnect: AutomationClientConnectPacket, + SetLastHurtBy: SetLastHurtByPacket, + BookEdit: BookEditPacket, + NpcRequest: NpcRequestPacket, + PhotoTransfer: PhotoTransferPacket, + ModalFormRequest: ModalFormRequestPacket, + ModalFormResponse: ModalFormResponsePacket, + ServerSettingsRequest: ServerSettingsRequestPacket, + ServerSettingsResponse: ServerSettingsResponsePacket, + ShowProfile: ShowProfilePacket, + SetDefaultGameType: SetDefaultGameTypePacket, + RemoveObjective: RemoveObjectivePacket, + SetDisplayObjective: SetDisplayObjectivePacket, + SetScore: SetScorePacket, + LabTable: LabTablePacket, + UpdateBlockSynced: UpdateBlockSyncedPacket, + MoveActorDelta: MoveActorDeltaPacket, + SetScoreboardIdentity: SetScoreboardIdentityPacket, + SetLocalPlayerAsInitialized: SetLocalPlayerAsInitializedPacket, + UpdateSoftEnum: UpdateSoftEnumPacket, + NetworkStackLatency: NetworkStackLatencyPacket, + SpawnParticleEffect: SpawnParticleEffectPacket, + AvailableActorIdentifiers: AvailableActorIdentifiersPacket, + LevelSoundEventV2: LevelSoundEventPacketV2, + NetworkChunkPublisherUpdate: NetworkChunkPublisherUpdatePacket, + BiomeDefinitionList: BiomeDefinitionListPacket, + LevelSoundEvent: LevelSoundEventPacket, + LevelEventGeneric: LevelEventGenericPacket, + LecternUpdate: LecternUpdatePacket, + ClientCacheStatus: ClientCacheStatusPacket, + OnScreenTextureAnimation: OnScreenTextureAnimationPacket, + MapCreateLockedCopy: MapCreateLockedCopyPacket, + StructureDataRequest: StructureDataRequestPacket, + StructureDataResponse: StructureDataResponsePacket, + ClientCacheBlobStatus: ClientCacheBlobStatusPacket, + ClientCacheMissResponse: ClientCacheMissResponsePacket, + EducationSettings: EducationSettingsPacket, + Emote: EmotePacket, + MultiplayerSettings: MultiplayerSettingsPacket, + SettingsCommand: SettingsCommandPacket, + AnvilDamage: AnvilDamagePacket, + CompletedUsingItem: CompletedUsingItemPacket, + NetworkSettings: NetworkSettingsPacket, + PlayerAuthInput: PlayerAuthInputPacket, + CreativeContent: CreativeContentPacket, + PlayerEnchantOptions: PlayerEnchantOptionsPacket, + ItemStackRequest: ItemStackRequestPacket, + ItemStackResponse: ItemStackResponsePacket, + PlayerArmorDamage: PlayerArmorDamagePacket, + CodeBuilder: CodeBuilderPacket, + UpdatePlayerGameType: UpdatePlayerGameTypePacket, + EmoteList: EmoteListPacket, + PositionTrackingDbServerBroadcast: PositionTrackingDBServerBroadcastPacket, + PositionTrackingDbClientRequest: PositionTrackingDBClientRequestPacket, + DebugInfo: DebugInfoPacket, + PacketViolationWarning: PacketViolationWarningPacket, + MotionPredictionHints: MotionPredictionHintsPacket, + AnimateEntity: AnimateEntityPacket, + CameraShake: CameraShakePacket, + PlayerFog: PlayerFogPacket, + CorrectPlayerMovePrediction: CorrectPlayerMovePredictionPacket, + ItemComponent: ItemComponentPacket, + ClientBoundDebugRenderer: ClientBoundDebugRendererPacket, + SyncActorProperty: SyncActorPropertyPacket, + AddVolumeEntity: AddVolumeEntityPacket, + RemoveVolumeEntity: RemoveVolumeEntityPacket, + SimulationType: SimulationTypePacket, + NpcDialogue: NpcDialoguePacket, + EduUriResource: EduUriResourcePacket, + CreatePhoto: CreatePhotoPacket, + UpdateSubChunkBlocks: UpdateSubChunkBlocksPacket, + SubChunk: SubChunkPacket, + SubChunkRequest: SubChunkRequestPacket, + PlayerStartItemCooldown: PlayerStartItemCooldownPacket, + ScriptMessage: ScriptMessagePacket, + CodeBuilderSource: CodeBuilderSourcePacket, + TickingAreaLoadStatus: TickingAreaLoadStatusPacket, + DimensionData: DimensionDataPacket, + AgentActionEvent: AgentActionEventPacket, + ChangeMobProperty: ChangeMobPropertyPacket, + LessonProgress: LessonProgressPacket, + RequestAbility: RequestAbilityPacket, + RequestPermissions: RequestPermissionsPacket, + ToastRequest: ToastRequestPacket, + UpdateAbilities: UpdateAbilitiesPacket, + UpdateAdventureSettings: UpdateAdventureSettingsPacket, + DeathInfo: DeathInfoPacket, + EditorNetwork: EditorNetworkPacket, + FeatureRegistry: FeatureRegistryPacket, + ServerStats: ServerStatsPacket, + RequestNetworkSettings: RequestNetworkSettingsPacket, + GameTestRequest: GameTestRequestPacket, + GameTestResults: GameTestResultsPacket, + UpdateClientInputLocks: UpdateClientInputLocksPacket, + CameraPresets: CameraPresetsPacket, + UnlockedRecipes: UnlockedRecipesPacket, + CameraInstruction: CameraInstructionPacket, + CompressedBiomeDefinitionList: CompressedBiomeDefinitionListPacket, + TrimData: TrimDataPacket, + OpenSign: OpenSignPacket, + AgentAnimation: AgentAnimationPacket, + RefreshEntitlements: RefreshEntitlementsPacket, + PlayerToggleCrafterSlotRequest: PlayerToggleCrafterSlotRequestPacket, + SetPlayerInventoryOptions: SetPlayerInventoryOptionsPacket, + SetHud: SetHudPacket +} diff --git a/crates/proto/src/version/v766/helper.rs b/crates/proto/src/version/v766/helper.rs new file mode 100644 index 00000000..df8c8efa --- /dev/null +++ b/crates/proto/src/version/v766/helper.rs @@ -0,0 +1,8 @@ +use crate::helper::ProtoHelper; +use crate::version::v766::gamepackets::GamePackets; + +pub struct ProtoHelperV766; + +impl ProtoHelper for ProtoHelperV766 { + type GamePacketType = GamePackets; +} diff --git a/crates/proto/src/version/v766/info.rs b/crates/proto/src/version/v766/info.rs new file mode 100644 index 00000000..ed360a78 --- /dev/null +++ b/crates/proto/src/version/v766/info.rs @@ -0,0 +1 @@ +pub const PROTOCOL_VERSION: i32 = 766; diff --git a/crates/proto/src/version/v766/mod.rs b/crates/proto/src/version/v766/mod.rs new file mode 100644 index 00000000..b61c0038 --- /dev/null +++ b/crates/proto/src/version/v766/mod.rs @@ -0,0 +1,8 @@ +//! r/21_u5 + +pub mod enums; +pub mod gamepackets; +pub mod helper; +pub mod info; +pub mod packets; +pub mod types; diff --git a/crates/proto/src/version/v766/packets/add_actor.rs b/crates/proto/src/version/v766/packets/add_actor.rs new file mode 100644 index 00000000..2d1632e7 --- /dev/null +++ b/crates/proto/src/version/v766/packets/add_actor.rs @@ -0,0 +1,43 @@ +use crate::version::v662::types::{ActorRuntimeID, ActorUniqueID, PropertySyncData}; +use vek::{Vec2, Vec3}; +use bedrockrs_macros::{gamepacket, ProtoCodec}; +use crate::version::v766::types::{ActorLink, DataItem}; + +#[derive(ProtoCodec, Clone, Debug)] +pub struct AttributeEntry { + pub attribute_name: String, + #[endianness(le)] + pub min_value: f32, + #[endianness(le)] + pub current_value: f32, + #[endianness(le)] + pub max_value: f32, +} + +#[gamepacket(id = 13)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct AddActorPacket { + pub target_actor_id: ActorUniqueID, + pub target_runtime_id: ActorRuntimeID, + pub actor_type: String, + #[endianness(le)] + pub position: Vec3, + #[endianness(le)] + pub velocity: Vec3, + #[endianness(le)] + pub rotation: Vec2, + #[endianness(le)] + pub y_head_rotation: f32, + #[endianness(le)] + pub y_body_rotation: f32, + #[vec_repr(u32)] + #[vec_endianness(var)] + pub attributes: Vec, + #[vec_repr(u32)] + #[vec_endianness(var)] + pub actor_data: Vec, // VERIFY: vec_repr & vec_endianness + pub synced_properties: PropertySyncData, + #[vec_repr(u32)] + #[vec_endianness(var)] + pub actor_links: Vec +} \ No newline at end of file diff --git a/crates/proto/src/version/v766/packets/add_item_actor.rs b/crates/proto/src/version/v766/packets/add_item_actor.rs new file mode 100644 index 00000000..c13f1a9f --- /dev/null +++ b/crates/proto/src/version/v766/packets/add_item_actor.rs @@ -0,0 +1,20 @@ +use crate::version::v662::types::{ActorRuntimeID, ActorUniqueID, NetworkItemStackDescriptor}; +use vek::Vec3; +use bedrockrs_macros::{gamepacket, ProtoCodec}; +use crate::version::v766::types::DataItem; + +#[gamepacket(id = 15)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct AddItemActorPacket { + pub target_actor_id: ActorUniqueID, + pub target_runtime_id: ActorRuntimeID, + pub item: NetworkItemStackDescriptor, + #[endianness(le)] + pub position: Vec3, + #[endianness(le)] + pub velocity: Vec3, + #[vec_repr(u32)] + #[vec_endianness(var)] + pub entity_data: Vec, // VERIFY: vec_repr & vec_endianness + pub from_fishing: bool, +} \ No newline at end of file diff --git a/crates/proto/src/version/v766/packets/add_player.rs b/crates/proto/src/version/v766/packets/add_player.rs new file mode 100644 index 00000000..5e5bb338 --- /dev/null +++ b/crates/proto/src/version/v766/packets/add_player.rs @@ -0,0 +1,35 @@ +use crate::version::v662::enums::{BuildPlatform, GameType}; +use crate::version::v662::types::{ActorRuntimeID, NetworkItemStackDescriptor, PropertySyncData, SerializedAbilitiesData}; +use vek::{Vec2, Vec3}; +use bedrockrs_macros::{gamepacket, ProtoCodec}; +use uuid::Uuid; +use crate::version::v766::types::{ActorLink, DataItem}; + +#[gamepacket(id = 12)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct AddPlayerPacket { + pub uuid: Uuid, + pub player_name: String, + pub target_runtime_id: ActorRuntimeID, + pub platform_chat_id: String, + #[endianness(le)] + pub position: Vec3, + #[endianness(le)] + pub velocity: Vec3, + #[endianness(le)] + pub rotation: Vec2, + #[endianness(le)] + pub y_head_rotation: f32, + pub carried_item: NetworkItemStackDescriptor, + pub player_game_type: GameType, + #[vec_repr(u32)] + #[vec_endianness(var)] + pub entity_data: Vec, // VERIFY: vec_repr & vec_endianness + pub synced_properties: PropertySyncData, + pub abilities_data: SerializedAbilitiesData, + #[vec_repr(u32)] + #[vec_endianness(var)] + pub actor_links: Vec, + pub device_id: String, + pub build_platform: BuildPlatform, +} \ No newline at end of file diff --git a/crates/proto/src/version/v766/packets/award_achievement.rs b/crates/proto/src/version/v766/packets/award_achievement.rs new file mode 100644 index 00000000..12d9288e --- /dev/null +++ b/crates/proto/src/version/v766/packets/award_achievement.rs @@ -0,0 +1,8 @@ +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 309)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct AwardAchievementPacket { + #[endianness(le)] + pub achievement_id: i32, +} \ No newline at end of file diff --git a/crates/proto/src/version/v766/packets/boss_event.rs b/crates/proto/src/version/v766/packets/boss_event.rs new file mode 100644 index 00000000..d07eb8d6 --- /dev/null +++ b/crates/proto/src/version/v766/packets/boss_event.rs @@ -0,0 +1,10 @@ +use crate::version::v662::types::ActorUniqueID; +use crate::version::v766::enums::BossEventUpdateType; +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 74)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct BossEventPacket { + pub target_actor_id: ActorUniqueID, + pub event_type: BossEventUpdateType, +} \ No newline at end of file diff --git a/crates/proto/src/version/v766/packets/camera_aim_assist.rs b/crates/proto/src/version/v766/packets/camera_aim_assist.rs new file mode 100644 index 00000000..b88095e9 --- /dev/null +++ b/crates/proto/src/version/v766/packets/camera_aim_assist.rs @@ -0,0 +1,30 @@ +use bedrockrs_macros::{gamepacket, ProtoCodec}; +use vek::Vec2; + +#[derive(ProtoCodec, Clone, Debug)] +#[enum_repr(i8)] +#[repr(i8)] +pub enum Action { + Set = 0, + Clear = 1, +} + +#[derive(ProtoCodec, Clone, Debug)] +#[enum_repr(i8)] +#[repr(i8)] +pub enum TargetMode { + Angle = 0, + Distance = 1, +} + +#[gamepacket(id = 316)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct CameraAimAssistPacket { + pub preset_id: String, + #[endianness(le)] + pub view_angle: Vec2, + #[endianness(le)] + pub distance: f32, + pub target_mode: TargetMode, + pub action: Action, +} \ No newline at end of file diff --git a/crates/proto/src/version/v766/packets/camera_aim_assist_presets.rs b/crates/proto/src/version/v766/packets/camera_aim_assist_presets.rs new file mode 100644 index 00000000..aa99ba7e --- /dev/null +++ b/crates/proto/src/version/v766/packets/camera_aim_assist_presets.rs @@ -0,0 +1,70 @@ +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[derive(ProtoCodec, Clone, Debug)] +pub struct CategoriesDefinition { + pub identifier: String, + #[vec_repr(u32)] + #[vec_endianness(var)] + pub categories: Vec, +} + +#[derive(ProtoCodec, Clone, Debug)] +pub struct CategoryDefinition { + pub name: String, + pub priorities: CategoryPriorities, +} + +#[derive(ProtoCodec, Clone, Debug)] +pub struct PriorityEntry { + pub id: String, + #[endianness(le)] + pub priority: i32, +} + +#[derive(ProtoCodec, Clone, Debug)] +pub struct CategoryPriorities { + #[vec_repr(u32)] + #[vec_endianness(var)] + pub entities: Vec, + #[vec_repr(u32)] + #[vec_endianness(var)] + pub blocks: Vec, + #[endianness(le)] + pub default_entity: Option, + #[endianness(le)] + pub default_block: Option, +} + +#[derive(ProtoCodec, Clone, Debug)] +pub struct ItemSettingsEntry { + pub item_id: String, + pub category: String, +} + +#[derive(ProtoCodec, Clone, Debug)] +pub struct PresetDefinition { + pub identifier: String, + pub categories: String, + #[vec_repr(u32)] + #[vec_endianness(var)] + pub exclusion_list: Vec, + #[vec_repr(u32)] + #[vec_endianness(var)] + pub liquid_targeting_list: Vec, + #[vec_repr(u32)] + #[vec_endianness(var)] + pub item_settings: Vec, + pub default_item_settings: String, + pub hand_settings: String, +} + +#[gamepacket(id = 320)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct CameraAimAssistPresetsPacket { + #[vec_repr(u32)] + #[vec_endianness(var)] + pub categories: Vec, + #[vec_repr(u32)] + #[vec_endianness(var)] + pub presets: Vec, +} \ No newline at end of file diff --git a/crates/proto/src/version/v766/packets/camera_instruction.rs b/crates/proto/src/version/v766/packets/camera_instruction.rs new file mode 100644 index 00000000..a54edc52 --- /dev/null +++ b/crates/proto/src/version/v766/packets/camera_instruction.rs @@ -0,0 +1,8 @@ +use crate::version::v766::types::CameraInstruction; +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 300)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct CameraInstructionPacket { + pub camera_instruction: CameraInstruction, +} \ No newline at end of file diff --git a/crates/proto/src/version/v766/packets/camera_presets.rs b/crates/proto/src/version/v766/packets/camera_presets.rs new file mode 100644 index 00000000..8b8743b6 --- /dev/null +++ b/crates/proto/src/version/v766/packets/camera_presets.rs @@ -0,0 +1,8 @@ +use crate::version::v766::types::CameraPresets; +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 198)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct CameraPresetsPacket { + pub camera_presets: CameraPresets, +} \ No newline at end of file diff --git a/crates/proto/src/version/v766/packets/change_dimension.rs b/crates/proto/src/version/v766/packets/change_dimension.rs new file mode 100644 index 00000000..b0d348f7 --- /dev/null +++ b/crates/proto/src/version/v766/packets/change_dimension.rs @@ -0,0 +1,14 @@ +use bedrockrs_macros::{gamepacket, ProtoCodec}; +use vek::Vec3; + +#[gamepacket(id = 61)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct ChangeDimensionPacket { + #[endianness(var)] + pub dimension_id: i32, + #[endianness(le)] + pub position: Vec3, + pub respawn: bool, + #[endianness(le)] + pub loading_screen_id: Option, +} \ No newline at end of file diff --git a/crates/proto/src/version/v766/packets/client_bound_close_form.rs b/crates/proto/src/version/v766/packets/client_bound_close_form.rs new file mode 100644 index 00000000..c9972870 --- /dev/null +++ b/crates/proto/src/version/v766/packets/client_bound_close_form.rs @@ -0,0 +1,5 @@ +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 310)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct ClientBoundCloseFormPacket {} \ No newline at end of file diff --git a/crates/proto/src/version/v766/packets/client_bound_debug_renderer.rs b/crates/proto/src/version/v766/packets/client_bound_debug_renderer.rs new file mode 100644 index 00000000..75fa10b6 --- /dev/null +++ b/crates/proto/src/version/v766/packets/client_bound_debug_renderer.rs @@ -0,0 +1,32 @@ +use bedrockrs_macros::{gamepacket, ProtoCodec}; +use vek::Vec3; + +#[derive(ProtoCodec, Clone, Debug)] +#[enum_repr(u32)] +#[enum_endianness(le)] +#[repr(u32)] +pub enum Type { + Invalid = 0, + ClearDebugMarkers = 1, + AddDebugMarkerCube { + text: String, + #[endianness(le)] + position: Vec3, + #[endianness(le)] + r: f32, + #[endianness(le)] + g: f32, + #[endianness(le)] + b: f32, + #[endianness(le)] + a: f32, + #[endianness(le)] + millisecond_duration: u64, + } = 2, +} + +#[gamepacket(id = 163)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct ClientBoundDebugRendererPacket { + pub debug_marker_type: Type, +} \ No newline at end of file diff --git a/crates/proto/src/version/v766/packets/client_bound_map_item_data.rs b/crates/proto/src/version/v766/packets/client_bound_map_item_data.rs new file mode 100644 index 00000000..3496f28c --- /dev/null +++ b/crates/proto/src/version/v766/packets/client_bound_map_item_data.rs @@ -0,0 +1,267 @@ +use crate::version::v662::types::{ + ActorUniqueID, BlockPos, MapDecoration, MapItemTrackedActorUniqueID, +}; +use bedrockrs_macros::gamepacket; +use bedrockrs_proto_core::error::ProtoCodecError; +use bedrockrs_proto_core::{ProtoCodec, ProtoCodecVAR}; +use std::io::Cursor; +use std::mem::size_of; + +#[repr(u32)] +pub enum Type { + Invalid = 0x0, + TextureUpdate = 0x2, + DecorationUpdate = 0x4, + Creation = 0x8, +} + +#[gamepacket(id = 67)] +#[derive(Clone, Debug)] +pub struct ClientBoundMapItemDataPacket { + pub map_id: ActorUniqueID, + pub type_flags: u32, + pub dimension: i8, + pub is_locked: bool, + pub map_origin: BlockPos, + pub map_id_list: Option>, + pub scale: Option, + pub actor_ids: Option>, + pub decoration_list: Option>, + pub texture_width: Option, + pub texture_height: Option, + pub x_tex_coordinate: Option, + pub y_tex_coordinate: Option, + pub pixels: Option>, +} + +impl ProtoCodec for ClientBoundMapItemDataPacket { + fn proto_serialize(&self, stream: &mut Vec) -> Result<(), ProtoCodecError> { + self.map_id.proto_serialize(stream)?; + ::proto_serialize(&self.type_flags, stream)?; + self.dimension.proto_serialize(stream)?; + self.is_locked.proto_serialize(stream)?; + self.map_origin.proto_serialize(stream)?; + + if self.type_flags & Type::Creation as u32 != 0 { + let vec = self.map_id_list.as_ref().unwrap(); + let len: u32 = vec.len().try_into()?; + ::proto_serialize(&len, stream)?; + for i in vec { + i.proto_serialize(stream)? + } + } + + if self.type_flags + & (Type::DecorationUpdate as u32 | Type::TextureUpdate as u32 | Type::Creation as u32) + != 0 + { + self.scale.as_ref().unwrap().proto_serialize(stream)?; + } + + if self.type_flags & Type::DecorationUpdate as u32 != 0 { + { + let vec = self.actor_ids.as_ref().unwrap(); + let len: u32 = vec.len().try_into()?; + ::proto_serialize(&len, stream)?; + for i in vec { + i.proto_serialize(stream)? + } + } + { + let vec = self.decoration_list.as_ref().unwrap(); + let len: u32 = vec.len().try_into()?; + ::proto_serialize(&len, stream)?; + for i in vec { + i.proto_serialize(stream)? + } + } + } + + if self.type_flags & Type::TextureUpdate as u32 != 0 { + ::proto_serialize(self.texture_width.as_ref().unwrap(), stream)?; + ::proto_serialize(self.texture_height.as_ref().unwrap(), stream)?; + ::proto_serialize( + self.x_tex_coordinate.as_ref().unwrap(), + stream, + )?; + ::proto_serialize( + self.y_tex_coordinate.as_ref().unwrap(), + stream, + )?; + { + let vec = self.pixels.as_ref().unwrap(); + let len: u32 = vec.len().try_into()?; + ::proto_serialize(&len, stream)?; + for i in vec { + ::proto_serialize(i, stream)?; + } + } + } + + Ok(()) + } + + fn proto_deserialize(stream: &mut Cursor<&[u8]>) -> Result { + let map_id = ActorUniqueID::proto_deserialize(stream)?; + let type_flags = ::proto_deserialize(stream)?; + let dimension = i8::proto_deserialize(stream)?; + let is_locked = bool::proto_deserialize(stream)?; + let map_origin = BlockPos::proto_deserialize(stream)?; + + let map_id_list = match type_flags & Type::Creation as u32 != 0 { + true => { + let len = ::proto_deserialize(stream)?; + let mut vec = Vec::with_capacity(len.try_into()?); + for _ in 0..len { + vec.push(ActorUniqueID::proto_deserialize(stream)?); + } + + Some(vec) + } + false => None, + }; + + let scale = match type_flags + & (Type::DecorationUpdate as u32 | Type::TextureUpdate as u32 | Type::Creation as u32) + != 0 + { + true => Some(i8::proto_deserialize(stream)?), + false => None, + }; + + let (actor_ids, decoration_list) = match type_flags & Type::DecorationUpdate as u32 != 0 { + true => { + let actor_ids = { + let len = ::proto_deserialize(stream)?; + let mut vec = Vec::with_capacity(len.try_into()?); + for _ in 0..len { + vec.push(MapItemTrackedActorUniqueID::proto_deserialize(stream)?); + } + vec + }; + let decoration_list = { + let len = ::proto_deserialize(stream)?; + let mut vec = Vec::with_capacity(len.try_into()?); + for _ in 0..len { + vec.push(MapDecoration::proto_deserialize(stream)?); + } + vec + }; + (Some(actor_ids), Some(decoration_list)) + } + false => (None, None), + }; + + let (texture_width, texture_height, x_tex_coordinate, y_tex_coordinate, pixels) = + match type_flags & Type::TextureUpdate as u32 != 0 { + true => { + let texture_width = ::proto_deserialize(stream)?; + let texture_height = ::proto_deserialize(stream)?; + let x_tex_coordinate = ::proto_deserialize(stream)?; + let y_tex_coordinate = ::proto_deserialize(stream)?; + let pixels = { + let len = ::proto_deserialize(stream)?; + let mut vec = Vec::with_capacity(len.try_into()?); + for _ in 0..len { + vec.push(::proto_deserialize(stream)?); + } + vec + }; + + ( + Some(texture_width), + Some(texture_height), + Some(x_tex_coordinate), + Some(y_tex_coordinate), + Some(pixels), + ) + } + false => (None, None, None, None, None), + }; + + Ok(Self { + map_id, + type_flags, + dimension, + is_locked, + map_origin, + map_id_list, + scale, + actor_ids, + decoration_list, + texture_width, + texture_height, + x_tex_coordinate, + y_tex_coordinate, + pixels, + }) + } + + fn get_size_prediction(&self) -> usize { + self.map_id.get_size_prediction() + + ::get_size_prediction(&self.type_flags) + + self.dimension.get_size_prediction() + + self.is_locked.get_size_prediction() + + self.map_origin.get_size_prediction() + + match &self.type_flags & Type::Creation as u32 != 0 { + true => { + size_of::() + + self + .map_id_list + .as_ref() + .unwrap() + .iter() + .map(|i| i.get_size_prediction()) + .sum::() + } + false => 0, + } + + match &self.type_flags + & (Type::DecorationUpdate as u32 + | Type::TextureUpdate as u32 + | Type::Creation as u32) + != 0 + { + true => self.scale.as_ref().unwrap().get_size_prediction(), + false => 0, + } + + match &self.type_flags & Type::DecorationUpdate as u32 != 0 { + true => { + size_of::() + + self + .actor_ids + .as_ref() + .unwrap() + .iter() + .map(|i| i.get_size_prediction()) + .sum::() + + size_of::() + + self + .decoration_list + .as_ref() + .unwrap() + .iter() + .map(|i| i.get_size_prediction()) + .sum::() + } + false => 0, + } + + match &self.type_flags & Type::TextureUpdate as u32 != 0 { + true => { + ::get_size_prediction(&self.texture_width.unwrap()) + + ::get_size_prediction(&self.texture_height.unwrap()) + + ::get_size_prediction( + &self.x_tex_coordinate.unwrap(), + ) + + ::get_size_prediction( + &self.y_tex_coordinate.unwrap(), + ) + + size_of::() + + &self.pixels.as_ref().unwrap().len() * size_of::() + } + false => 0, + } + } +} + +// VERIFY: ProtoCodec impl diff --git a/crates/proto/src/version/v766/packets/code_builder_source.rs b/crates/proto/src/version/v766/packets/code_builder_source.rs new file mode 100644 index 00000000..b01885a4 --- /dev/null +++ b/crates/proto/src/version/v766/packets/code_builder_source.rs @@ -0,0 +1,11 @@ +use crate::version::v662::enums::{CodeBuilderStorageCategory, CodeBuilderStorageOperation}; +use crate::version::v766::enums::CodeBuilderExecutionState; +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 178)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct CodeBuilderSourcePacket { + pub operation: CodeBuilderStorageOperation, + pub category: CodeBuilderStorageCategory, + pub code_status: CodeBuilderExecutionState, +} \ No newline at end of file diff --git a/crates/proto/src/version/v766/packets/container_close.rs b/crates/proto/src/version/v766/packets/container_close.rs new file mode 100644 index 00000000..61b6f7c5 --- /dev/null +++ b/crates/proto/src/version/v766/packets/container_close.rs @@ -0,0 +1,10 @@ +use crate::version::v662::enums::{ContainerID, ContainerType}; +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 47)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct ContainerClosePacket { + pub container_id: ContainerID, + pub container_type: ContainerType, + pub server_initiated_close: bool, +} \ No newline at end of file diff --git a/crates/proto/src/version/v766/packets/container_registry_cleanup.rs b/crates/proto/src/version/v766/packets/container_registry_cleanup.rs new file mode 100644 index 00000000..fc9ae3c3 --- /dev/null +++ b/crates/proto/src/version/v766/packets/container_registry_cleanup.rs @@ -0,0 +1,10 @@ +use crate::version::v766::types::FullContainerName; +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 317)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct ContainerRegistryCleanupPacket { + #[vec_repr(u32)] + #[vec_endianness(var)] + pub removed_containers: Vec, +} \ No newline at end of file diff --git a/crates/proto/src/version/v766/packets/correct_player_move_prediction.rs b/crates/proto/src/version/v766/packets/correct_player_move_prediction.rs new file mode 100644 index 00000000..e34fa2bc --- /dev/null +++ b/crates/proto/src/version/v766/packets/correct_player_move_prediction.rs @@ -0,0 +1,16 @@ +use crate::version::v662::enums::PredictionType; +use bedrockrs_macros::{gamepacket, ProtoCodec}; +use vek::Vec3; + +#[gamepacket(id = 161)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct CorrectPlayerMovePredictionPacket { + pub prediction_type: PredictionType, + #[endianness(le)] + pub position: Vec3, + #[endianness(le)] + pub velocity: Vec3, + pub on_ground: bool, + #[endianness(var)] + pub tick: u64, +} \ No newline at end of file diff --git a/crates/proto/src/version/v766/packets/crafting_data.rs b/crates/proto/src/version/v766/packets/crafting_data.rs new file mode 100644 index 00000000..20db69b1 --- /dev/null +++ b/crates/proto/src/version/v766/packets/crafting_data.rs @@ -0,0 +1,21 @@ +use crate::version::v662::types::{ContainerMixDataEntry, MaterialReducerDataEntry, PotionMixDataEntry}; +use bedrockrs_macros::{gamepacket, ProtoCodec}; +use crate::v766::types::CraftingDataEntry; + +#[gamepacket(id = 52)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct CraftingDataPacket { + #[vec_repr(u32)] + #[vec_endianness(var)] + pub crafting_entries: Vec, + #[vec_repr(u32)] + #[vec_endianness(var)] + pub potion_mixes: Vec, + #[vec_repr(u32)] + #[vec_endianness(var)] + pub container_mixes: Vec, + #[vec_repr(u32)] + #[vec_endianness(var)] + pub material_reducers: Vec, + pub clear_recipes: bool, +} diff --git a/crates/proto/src/version/v766/packets/current_structure_feature.rs b/crates/proto/src/version/v766/packets/current_structure_feature.rs new file mode 100644 index 00000000..799dc3b5 --- /dev/null +++ b/crates/proto/src/version/v766/packets/current_structure_feature.rs @@ -0,0 +1,6 @@ +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +pub struct CurrentStructureFeaturePacket { + pub current_structure_feature: String, +} \ No newline at end of file diff --git a/crates/proto/src/version/v766/packets/disconnect.rs b/crates/proto/src/version/v766/packets/disconnect.rs new file mode 100644 index 00000000..02cc3d71 --- /dev/null +++ b/crates/proto/src/version/v766/packets/disconnect.rs @@ -0,0 +1,46 @@ +use crate::version::v662::enums::ConnectionFailReason; +use bedrockrs_macros::{gamepacket, ProtoCodec}; +use bedrockrs_proto_core::error::ProtoCodecError; +use bedrockrs_proto_core::ProtoCodec; +use std::io::Cursor; + +#[derive(ProtoCodec, Clone, Debug)] +pub struct DisconnectPacketMessage { + pub message: String, + pub filtered_message: String, +} + +#[gamepacket(id = 5)] +#[derive(Clone, Debug)] +pub struct DisconnectPacket { + pub reason: ConnectionFailReason, + pub messages: Option, +} + +impl ProtoCodec for DisconnectPacket { + fn proto_serialize(&self, stream: &mut Vec) -> Result<(), ProtoCodecError> { + self.reason.proto_serialize(stream)?; + bool::proto_serialize(&self.messages.is_none(), stream)?; + + if let Some(ref message) = self.messages { + message.proto_serialize(stream)?; + } + + Ok(()) + } + + fn proto_deserialize(stream: &mut Cursor<&[u8]>) -> Result { + let reason = ConnectionFailReason::proto_deserialize(stream)?; + let skip_message = bool::proto_deserialize(stream)?; + let messages = match !skip_message { + true => Some(DisconnectPacketMessage::proto_deserialize(stream)?), + false => None, + }; + + Ok(DisconnectPacket { reason, messages }) + } + + fn get_size_prediction(&self) -> usize { + self.reason.get_size_prediction() + self.messages.get_size_prediction() + } +} diff --git a/crates/proto/src/version/v766/packets/editor_network.rs b/crates/proto/src/version/v766/packets/editor_network.rs new file mode 100644 index 00000000..581a8fc4 --- /dev/null +++ b/crates/proto/src/version/v766/packets/editor_network.rs @@ -0,0 +1,9 @@ +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 190)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct EditorNetworkPacket { + pub route_to_manager: bool, + #[nbt] + pub binary_payload: nbtx::Value, // TODO: NBT Structure +} \ No newline at end of file diff --git a/crates/proto/src/version/v766/packets/emote.rs b/crates/proto/src/version/v766/packets/emote.rs new file mode 100644 index 00000000..9e7debfa --- /dev/null +++ b/crates/proto/src/version/v766/packets/emote.rs @@ -0,0 +1,22 @@ +use crate::version::v662::types::ActorRuntimeID; +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[derive(ProtoCodec, Clone, Debug)] +#[enum_repr(i8)] +#[repr(i8)] +pub enum Flags { + ServerSide = 0x0, + MuteEmoteChat = 0x2, +} + +#[gamepacket(id = 138)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct EmotePacket { + pub actor_runtime_id: ActorRuntimeID, + pub emote_id: String, + #[endianness(var)] + pub emote_length: u32, + pub xuid: String, + pub platform_id: String, + pub flags: Flags, +} \ No newline at end of file diff --git a/crates/proto/src/version/v766/packets/inventory_content.rs b/crates/proto/src/version/v766/packets/inventory_content.rs new file mode 100644 index 00000000..bde77d8c --- /dev/null +++ b/crates/proto/src/version/v766/packets/inventory_content.rs @@ -0,0 +1,15 @@ +use crate::v766::types::FullContainerName; +use crate::version::v662::types::NetworkItemStackDescriptor; +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 49)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct InventoryContentPacket { + #[endianness(var)] + pub inventory_id: u32, + #[vec_repr(u32)] + #[vec_endianness(var)] + pub slots: Vec, + pub full_container_name: FullContainerName, + pub storage_item: NetworkItemStackDescriptor, +} \ No newline at end of file diff --git a/crates/proto/src/version/v766/packets/inventory_slot.rs b/crates/proto/src/version/v766/packets/inventory_slot.rs new file mode 100644 index 00000000..1705af3d --- /dev/null +++ b/crates/proto/src/version/v766/packets/inventory_slot.rs @@ -0,0 +1,15 @@ +use crate::v766::types::FullContainerName; +use crate::version::v662::enums::ContainerID; +use crate::version::v662::types::NetworkItemStackDescriptor; +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 50)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct InventorySlotPacket { + pub container_id: ContainerID, + #[endianness(var)] + pub slot: u32, + pub full_container_name: FullContainerName, + pub storage_item: NetworkItemStackDescriptor, + pub item: NetworkItemStackDescriptor, +} \ No newline at end of file diff --git a/crates/proto/src/version/v766/packets/item_stack_request.rs b/crates/proto/src/version/v766/packets/item_stack_request.rs new file mode 100644 index 00000000..6d8ed5dc --- /dev/null +++ b/crates/proto/src/version/v766/packets/item_stack_request.rs @@ -0,0 +1,32 @@ +use crate::version::v662::enums::{ItemStackRequestActionType, TextProcessingEventOrigin}; +use crate::version::v766::types::ItemStackRequestSlotInfo; +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[derive(ProtoCodec, Clone, Debug)] +pub struct ActionsEntry { + pub action_type: ItemStackRequestActionType, + pub amount: i8, + pub source: ItemStackRequestSlotInfo, + pub destination: ItemStackRequestSlotInfo, +} + +#[derive(ProtoCodec, Clone, Debug)] +pub struct RequestsEntry { + #[endianness(var)] + pub client_request_id: u32, + #[vec_repr(u32)] + #[vec_endianness(var)] + pub actions: Vec, + #[vec_repr(u32)] + #[vec_endianness(var)] + pub strings_to_filter: Vec, + pub strings_to_filter_origin: TextProcessingEventOrigin, +} + +#[gamepacket(id = 147)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct ItemStackRequestPacket { + #[vec_repr(u32)] + #[vec_endianness(var)] + pub requests: Vec, +} \ No newline at end of file diff --git a/crates/proto/src/version/v766/packets/item_stack_response.rs b/crates/proto/src/version/v766/packets/item_stack_response.rs new file mode 100644 index 00000000..fa92e8f9 --- /dev/null +++ b/crates/proto/src/version/v766/packets/item_stack_response.rs @@ -0,0 +1,10 @@ +use crate::version::v766::types::ItemStackResponseInfo; +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 148)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct ItemStackResponsePacket { + #[vec_repr(u32)] + #[vec_endianness(var)] + pub responses: Vec +} \ No newline at end of file diff --git a/crates/proto/src/version/v766/packets/jigsaw_structure_data.rs b/crates/proto/src/version/v766/packets/jigsaw_structure_data.rs new file mode 100644 index 00000000..0782c70c --- /dev/null +++ b/crates/proto/src/version/v766/packets/jigsaw_structure_data.rs @@ -0,0 +1,8 @@ +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 313)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct JigsawStructureDataPacket { + #[nbt] + pub tag: nbtx::Value, // TODO: NBT Structure +} \ No newline at end of file diff --git a/crates/proto/src/version/v766/packets/legacy_telemetry_event.rs b/crates/proto/src/version/v766/packets/legacy_telemetry_event.rs new file mode 100644 index 00000000..f738b1ac --- /dev/null +++ b/crates/proto/src/version/v766/packets/legacy_telemetry_event.rs @@ -0,0 +1,220 @@ +use crate::v662::enums::ItemUseMethod; +use crate::version::v662::enums::{ActorDamageCause, ActorType, InteractionType, POIBlockInteractionType}; +use crate::version::v662::types::ActorUniqueID; +use bedrockrs_macros::{gamepacket, ProtoCodec}; +use bedrockrs_proto_core::error::ProtoCodecError; +use bedrockrs_proto_core::ProtoCodec; +use std::io::{Cursor, Read}; +use varint_rs::{VarintReader, VarintWriter}; + +#[derive(ProtoCodec, Clone, Debug)] +#[enum_repr(i32)] +#[enum_endianness(var)] +#[repr(i32)] +pub enum AgentResult { + ActionFail = 0, + ActionSuccess = 1, + QueryResultFalse = 2, + QueryResultTrue = 3, +} + +#[derive(ProtoCodec, Clone, Debug)] +#[enum_repr(i32)] +#[enum_endianness(var)] +#[repr(i32)] +pub enum Type { + Achievement { + #[endianness(var)] + achievement_id: i32, + } = 0, + Interaction { + #[endianness(var)] + interacted_entity_id: i64, + interaction_type: InteractionType, + interaction_actor_type: ActorType, + #[endianness(var)] + interaction_actor_variant: i32, + interaction_actor_color: i8, + } = 1, + PortalCreated { + #[endianness(var)] + dimension_id: i32, + } = 2, + PortalUsed { + #[endianness(var)] + source_dimension_id: i32, + #[endianness(var)] + target_dimension_id: i32, + } = 3, + MobKilled { + #[endianness(var)] + instigator_actor_id: i64, + #[endianness(var)] + target_actor_id: i64, + instigator_child_actor_type: ActorType, + damage_source: ActorDamageCause, + #[endianness(var)] + trade_tier: i32, + trader_name: String, + } = 4, + CauldronUsed { + #[endianness(var)] + contents_color: u32, + #[endianness(var)] + contents_type: i32, + #[endianness(var)] + fill_level: i32, + } = 5, + PlayerDied { + #[endianness(var)] + instigator_actor_id: i32, + #[endianness(var)] + instigator_mob_variant: i32, + damage_source: ActorDamageCause, + died_in_raid: bool, + } = 6, + BossKilled { + #[endianness(var)] + boss_actor_id: i64, + #[endianness(var)] + party_size: i32, + boss_type: ActorType, + } = 7, + AgentCommandObsolete { + result: AgentResult, + #[endianness(var)] + result_number: i32, + command_name: String, + result_key: String, + result_string: String, + } = 8, + AgentCreated = 9, + PatternRemovedObsolete = 10, + SlashCommand { + #[endianness(var)] + success_count: i32, + #[endianness(var)] + error_count: i32, + command_name: String, + error_list: String, + } = 11, + #[deprecated] + FishBucketed = 12, + MobBorn { + #[endianness(var)] + baby_entity_type: i32, + #[endianness(var)] + baby_entity_variant: i32, + baby_color: i8, + } = 13, + PetDiedObsolete = 14, + POICauldronUsed { + block_interaction_type: POIBlockInteractionType, + #[endianness(var)] + item_id: i32, + } = 15, + ComposterUsed { + block_interaction_type: POIBlockInteractionType, + #[endianness(var)] + item_id: i32, + } = 16, + BellUsed { + #[endianness(var)] + item_id: i32, + } = 17, + ActorDefinition { + event_name: String, + } = 18, + RaidUpdate { + #[endianness(var)] + current_raid_wave: i32, + #[endianness(var)] + total_raid_waves: i32, + raid_won: bool, + } = 19, + PlayerMovementAnomalyObsolete = 20, + PlayerMovementCorrectedObsolete = 21, + HoneyHarvested = 22, + TargetBlockHit { + #[endianness(var)] + redstone_level: i32, + } = 23, + PiglinBarter { + #[endianness(var)] + item_id: i32, + bartering_with_player: bool, + } = 24, + PlayerWaxedOrUnwaxedCopper { + #[endianness(var)] + block_id: i32, + } = 25, + CodeBuilderRuntimeAction { + runtime_action: String, + } = 26, + CodeBuilderScoreboard { + objective_name: String, + #[endianness(var)] + score: i32, + } = 27, + StriderRiddenInLavaInOverworld = 28, + SneakCloseToSculkSensor = 29, + CarefulRestoration = 30, + ItemUsedEvent { + #[endianness(var)] + item_id: i32, + #[endianness(var)] + item_aux: i32, + use_method: ItemUseMethod, + #[endianness(var)] + count: i32, + } = 31, +} + +#[gamepacket(id = 65)] +#[derive(Clone, Debug)] +pub struct LegacyTelemetryEventPacket { + pub target_actor_id: ActorUniqueID, + pub event_type: Type, + pub use_player_id: i8, +} + +impl ProtoCodec for LegacyTelemetryEventPacket { + fn proto_serialize(&self, stream: &mut Vec) -> Result<(), ProtoCodecError> { + let mut event_type_stream: Vec = Vec::new(); + ::proto_serialize(&self.event_type, &mut event_type_stream)?; + let mut event_type_cursor = Cursor::new(event_type_stream.as_slice()); + + ::proto_serialize(&self.target_actor_id, stream)?; + stream.write_i32_varint(event_type_cursor.read_i32_varint()?)?; + ::proto_serialize(&self.use_player_id, stream)?; + event_type_cursor.read_to_end(stream)?; + + Ok(()) + } + + fn proto_deserialize(stream: &mut Cursor<&[u8]>) -> Result { + let mut event_type_stream: Vec = Vec::new(); + + let target_actor_id = ::proto_deserialize(stream)?; + event_type_stream.write_i32_varint(stream.read_i32_varint()?)?; + let use_player_id = ::proto_deserialize(stream)?; + stream.read_to_end(&mut event_type_stream)?; + + let mut event_type_cursor = Cursor::new(event_type_stream.as_slice()); + let event_type = ::proto_deserialize(&mut event_type_cursor)?; + + Ok(Self { + target_actor_id, + event_type, + use_player_id, + }) + } + + fn get_size_prediction(&self) -> usize { + self.event_type.get_size_prediction() + + self.target_actor_id.get_size_prediction() + + self.use_player_id.get_size_prediction() + } +} + +// VERIFY: ProtoCodec impl diff --git a/crates/proto/src/version/v766/packets/mob_armor_equipment.rs b/crates/proto/src/version/v766/packets/mob_armor_equipment.rs new file mode 100644 index 00000000..dc12e75b --- /dev/null +++ b/crates/proto/src/version/v766/packets/mob_armor_equipment.rs @@ -0,0 +1,13 @@ +use crate::version::v662::types::{ActorRuntimeID, NetworkItemStackDescriptor}; +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 32)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct MobArmorEquipmentPacket { + pub target_runtime_id: ActorRuntimeID, + pub head: NetworkItemStackDescriptor, + pub torso: NetworkItemStackDescriptor, + pub legs: NetworkItemStackDescriptor, + pub feet: NetworkItemStackDescriptor, + pub body: NetworkItemStackDescriptor, +} \ No newline at end of file diff --git a/crates/proto/src/version/v766/packets/mod.rs b/crates/proto/src/version/v766/packets/mod.rs new file mode 100644 index 00000000..fb812243 --- /dev/null +++ b/crates/proto/src/version/v766/packets/mod.rs @@ -0,0 +1,56 @@ +macro_rules! export { + ($name:ident) => { + mod $name; + pub use $name::*; + }; +} + +export!(add_actor); +export!(add_player); +export!(award_achievement); +export!(boss_event); +export!(camera_aim_assist); +export!(camera_aim_assist_presets); +export!(camera_instruction); +export!(camera_presets); +export!(change_dimension); +export!(client_bound_close_form); +export!(client_bound_debug_renderer); +export!(client_bound_map_item_data); +export!(code_builder_source); +export!(container_close); +export!(container_registry_cleanup); +export!(correct_player_move_prediction); +export!(current_structure_feature); +export!(disconnect); +export!(editor_network); +export!(emote); +export!(inventory_content); +export!(inventory_slot); +export!(jigsaw_structure_data); +export!(legacy_telemetry_event); +export!(mob_armor_equipment); +export!(movement_effect); +export!(player_armor_damage); +export!(player_auth_input); +export!(player_list); +export!(resource_pack_stack); +export!(resource_packs_info); +export!(server_bound_diagnostics); +export!(server_bound_loading_screen); +export!(set_movement_authority); +export!(set_title); +export!(stop_sound); +export!(text); +export!(transfer_player); +export!(update_attributes); +export!(update_player_game_type); +export!(update_soft_enum); +export!(crafting_data); +export!(add_item_actor); +export!(set_actor_data); +export!(player_action); +export!(set_actor_link); +export!(item_stack_request); +export!(item_stack_response); +export!(start_game); diff --git a/crates/proto/src/version/v766/packets/movement_effect.rs b/crates/proto/src/version/v766/packets/movement_effect.rs new file mode 100644 index 00000000..8137f0d9 --- /dev/null +++ b/crates/proto/src/version/v766/packets/movement_effect.rs @@ -0,0 +1,14 @@ +use crate::v662::types::ActorRuntimeID; +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 318)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct MovementEffectPacket { + pub target_runtime_id: ActorRuntimeID, + #[endianness(var)] + pub effect_id: i32, + #[endianness(var)] + pub effect_duration: i32, + #[endianness(var)] + pub tick: i64, +} \ No newline at end of file diff --git a/crates/proto/src/version/v766/packets/player_action.rs b/crates/proto/src/version/v766/packets/player_action.rs new file mode 100644 index 00000000..7c3ba852 --- /dev/null +++ b/crates/proto/src/version/v766/packets/player_action.rs @@ -0,0 +1,16 @@ +use crate::version::v766::enums::PlayerActionType; +use crate::version::v662::types::{ActorRuntimeID, NetworkBlockPosition}; +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 36)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct PlayerActionPacket { + pub player_runtime_id: ActorRuntimeID, + pub action: PlayerActionType, + pub block_position: NetworkBlockPosition, + pub result_pos: NetworkBlockPosition, + #[endianness(var)] + pub face: i32, +} + +// TODO: PlayerActionType is has enum variants, but this packet doesn't serialize them. Might require moving the variants into their specific type \ No newline at end of file diff --git a/crates/proto/src/version/v766/packets/player_armor_damage.rs b/crates/proto/src/version/v766/packets/player_armor_damage.rs new file mode 100644 index 00000000..98edae37 --- /dev/null +++ b/crates/proto/src/version/v766/packets/player_armor_damage.rs @@ -0,0 +1,66 @@ +use bedrockrs_macros::gamepacket; +use bedrockrs_proto_core::error::ProtoCodecError; +use bedrockrs_proto_core::{ProtoCodec, ProtoCodecVAR}; +use std::io::Cursor; + +pub enum PlayerArmorDamageFlag { + Helmet = 1 << 0, + Chestplate = 1 << 1, + Leggings = 1 << 2, + Boots = 1 << 3, + Body = 1 << 4, +} + +#[gamepacket(id = 149)] +#[derive(Clone, Debug)] +pub struct PlayerArmorDamagePacket { + pub slot_bitset: i8, + pub damage: [i32; 5], +} + +impl ProtoCodec for PlayerArmorDamagePacket { + fn proto_serialize(&self, stream: &mut Vec) -> Result<(), ProtoCodecError> { + self.slot_bitset.proto_serialize(stream)?; + for i in 0..5 { + let flag = 1 << i; + if (self.slot_bitset & flag) != 0 { + ProtoCodecVAR::proto_serialize(&self.damage[i], stream)?; + } + } + + Ok(()) + } + + fn proto_deserialize(stream: &mut Cursor<&[u8]>) -> Result { + let slot_bitset = i8::proto_deserialize(stream)?; + let damage = { + let mut damage = [0; 5]; + for i in 0..5 { + let flag = 1 << i; + if (slot_bitset & flag) != 0 { + damage[i] = ::proto_deserialize(stream)?; + } + } + damage + }; + + Ok(Self { + slot_bitset, + damage, + }) + } + + fn get_size_prediction(&self) -> usize { + self.slot_bitset.get_size_prediction() + + (0..5) + .filter_map(|i| { + let flag = 1 << i; + if (self.slot_bitset & flag) != 0 { + Some(ProtoCodecVAR::get_size_prediction(&self.damage[i])) + } else { + None + } + }) + .sum::() + } +} diff --git a/crates/proto/src/version/v766/packets/player_auth_input.rs b/crates/proto/src/version/v766/packets/player_auth_input.rs new file mode 100644 index 00000000..dece3886 --- /dev/null +++ b/crates/proto/src/version/v766/packets/player_auth_input.rs @@ -0,0 +1,284 @@ +use crate::version::v662::enums::{ + ClientPlayMode, InputMode, ItemStackRequestActionType, NewInteractionModel, + TextProcessingEventOrigin, +}; +use crate::version::v662::types::{ + ActorUniqueID, +}; +use bedrockrs_macros::{gamepacket, ProtoCodec}; +use bedrockrs_proto_core::error::ProtoCodecError; +use bedrockrs_proto_core::{ProtoCodec, ProtoCodecLE, ProtoCodecVAR}; +use std::io::Cursor; +use vek::{Vec2, Vec3}; +use crate::version::v766::types::{ItemStackRequestSlotInfo, PackedItemUseLegacyInventoryTransaction, PlayerBlockActions}; + +pub struct PlayerAuthInputFlags; + +impl PlayerAuthInputFlags { + pub const ASCEND: u128 = 1 << 0; + pub const DESCEND: u128 = 1 << 1; + #[deprecated] + pub const NORTH_JUMP: u128 = 1 << 2; + pub const JUMP_DOWN: u128 = 1 << 3; + pub const SPRINT_DOWN: u128 = 1 << 4; + pub const CHANGE_HEIGHT: u128 = 1 << 5; + pub const JUMPING: u128 = 1 << 6; + pub const AUTO_JUMPING_IN_WATER: u128 = 1 << 7; + pub const SNEAKING: u128 = 1 << 8; + pub const SNEAK_DOWN: u128 = 1 << 9; + pub const UP: u128 = 1 << 10; + pub const DOWN: u128 = 1 << 11; + pub const LEFT: u128 = 1 << 12; + pub const RIGHT: u128 = 1 << 13; + pub const UP_LEFT: u128 = 1 << 14; + pub const UP_RIGHT: u128 = 1 << 15; + pub const WANT_UP: u128 = 1 << 16; + pub const WANT_DOWN: u128 = 1 << 17; + pub const WANT_DOWN_SLOW: u128 = 1 << 18; + pub const WANT_UP_SLOW: u128 = 1 << 19; + pub const SPRINTING: u128 = 1 << 20; + pub const ASCEND_BLOCK: u128 = 1 << 21; + pub const DESCEND_BLOCK: u128 = 1 << 22; + pub const SNEAK_TOGGLE_DOWN: u128 = 1 << 23; + pub const PERSIST_SNEAK: u128 = 1 << 24; + pub const START_SPRINTING: u128 = 1 << 25; + pub const STOP_SPRINTING: u128 = 1 << 26; + pub const START_SNEAKING: u128 = 1 << 27; + pub const STOP_SNEAKING: u128 = 1 << 28; + pub const START_SWIMMING: u128 = 1 << 29; + pub const STOP_SWIMMING: u128 = 1 << 30; + pub const START_JUMPING: u128 = 1 << 31; + pub const START_GLIDING: u128 = 1 << 32; + pub const STOP_GLIDING: u128 = 1 << 33; + pub const PERFORM_ITEM_INTERACTION: u128 = 1 << 34; + pub const PERFORM_BLOCK_ACTIONS: u128 = 1 << 35; + pub const PERFORM_ITEM_STACK_REQUEST: u128 = 1 << 36; + pub const HANDLE_TELEPORT: u128 = 1 << 37; + pub const EMOTING: u128 = 1 << 38; + pub const MISSED_SWING: u128 = 1 << 39; + pub const START_CRAWLING: u128 = 1 << 40; + pub const STOP_CRAWLING: u128 = 1 << 41; + pub const START_FLYING: u128 = 1 << 42; + pub const STOP_FLYING: u128 = 1 << 43; + pub const RECEIVED_SERVER_DATA: u128 = 1 << 44; + pub const IS_IN_CLIENT_PREDICTED_VEHICLE: u128 = 1 << 45; + pub const PADDLE_LEFT: u128 = 1 << 46; + pub const PADDLE_RIGHT: u128 = 1 << 47; + pub const BLOCK_BREAKING_DELAY_ENABLED: u128 = 1 << 48; + pub const HORIZONTAL_COLLISION: u128 = 1 << 49; + pub const VERTICAL_COLLISION: u128 = 1 << 50; + pub const DOWN_LEFT: u128 = 1 << 51; + pub const DOWN_RIGHT: u128 = 1 << 52; + pub const START_USING_ITEM: u128 = 1 << 53; + pub const IS_CAMERA_RELATIVE_MOVEMENT_ENABLED: u128 = 1 << 54; + pub const IS_ROT_CONTROLLED_BY_MOVE_DIRECTION: u128 = 1 << 55; + pub const START_SPIN_ATTACK: u128 = 1 << 56; + pub const STOP_SPIN_ATTACK: u128 = 1 << 57; + pub const IS_HOTBAR_ONLY_TOUCH: u128 = 1 << 58; + pub const JUMP_RELEASED_RAW: u128 = 1 << 59; + pub const JUMP_PRESSED_RAW: u128 = 1 << 60; + pub const JUMP_CURRENT_RAW: u128 = 1 << 61; + pub const SNEAK_RELEASED_RAW: u128 = 1 << 62; + pub const SNEAK_PRESSED_RAW: u128 = 1 << 63; + pub const SNEAK_CURRENT_RAW: u128 = 1 << 64; +} + +#[derive(ProtoCodec, Clone, Debug)] +pub struct ActionsEntry { + pub action_type: ItemStackRequestActionType, + pub amount: i8, + pub source: ItemStackRequestSlotInfo, + pub destination: ItemStackRequestSlotInfo, +} + +#[derive(ProtoCodec, Clone, Debug)] +pub struct PerformItemStackRequestData { + #[endianness(var)] + pub client_request_id: u32, + #[vec_repr(u32)] + #[vec_endianness(var)] + pub actions: Vec, + #[vec_repr(u32)] + #[vec_endianness(var)] + pub strings_to_filter: Vec, + pub strings_to_filter_origin: TextProcessingEventOrigin, +} + +#[derive(ProtoCodec, Clone, Debug)] +pub struct ClientPredictedVehicleData { + #[endianness(le)] + pub vehicle_rotation: Vec2, + pub client_predicted_vehicle: ActorUniqueID, +} + +#[gamepacket(id = 144)] +#[derive(Clone, Debug)] +pub struct PlayerAuthInputPacket { + pub player_rotation: Vec2, + pub player_position: Vec3, + pub move_vector: Vec3, + pub player_head_rotation: f32, + pub input_data: u128, + pub input_mode: InputMode, + pub play_mode: ClientPlayMode, + pub new_interaction_model: NewInteractionModel, + pub interact_rotation: Vec3, + pub client_tick: u64, + pub velocity: Vec3, + pub item_use_transaction: Option, // If input_data has PlayerAuthInputPacket::InputData::PerformItemInteraction set. + pub item_stack_request: Option, // If input data has PlayerAuthInputPacket::InputData::PerformItemStackRequest set. + pub player_block_actions: Option, // If input data has PlayerAuthInputPacket::InputData::PerformBlockActions set. + pub client_predicted_vehicle: Option, // If input data has PlayerAuthInputPacket::InputData::IsInClientPredictedVehicle set. + pub analog_move_vector: Vec2, + pub camera_orientation: Vec3, + pub raw_move_vector: Vec2, +} + +impl ProtoCodec for PlayerAuthInputPacket { + fn proto_serialize(&self, stream: &mut Vec) -> Result<(), ProtoCodecError> { + as ProtoCodecLE>::proto_serialize(&self.player_rotation, stream)?; + as ProtoCodecLE>::proto_serialize(&self.player_position, stream)?; + as ProtoCodecLE>::proto_serialize(&self.move_vector, stream)?; + ::proto_serialize(&self.player_head_rotation, stream)?; + ::proto_serialize(&self.input_data, stream)?; + ::proto_serialize(&self.input_mode, stream)?; + ::proto_serialize(&self.play_mode, stream)?; + ::proto_serialize(&self.new_interaction_model, stream)?; + as ProtoCodecLE>::proto_serialize(&self.interact_rotation, stream)?; + ::proto_serialize(&self.client_tick, stream)?; + as ProtoCodecLE>::proto_serialize(&self.velocity, stream)?; + if &self.input_data & PlayerAuthInputFlags::PERFORM_ITEM_INTERACTION != 0 { + ::proto_serialize( + &self.item_use_transaction.as_ref().unwrap(), + stream, + )?; + } + if &self.input_data & PlayerAuthInputFlags::PERFORM_ITEM_STACK_REQUEST != 0 { + ::proto_serialize( + &self.item_stack_request.as_ref().unwrap(), + stream, + )?; + } + if &self.input_data & PlayerAuthInputFlags::PERFORM_BLOCK_ACTIONS != 0 { + ::proto_serialize( + &self.player_block_actions.as_ref().unwrap(), + stream, + )?; + } + if &self.input_data & PlayerAuthInputFlags::IS_IN_CLIENT_PREDICTED_VEHICLE != 0 { + ::proto_serialize( + &self.client_predicted_vehicle.as_ref().unwrap(), + stream, + )?; + } + as ProtoCodecLE>::proto_serialize(&self.analog_move_vector, stream)?; + as ProtoCodecLE>::proto_serialize(&self.camera_orientation, stream)?; + as ProtoCodecLE>::proto_serialize(&self.raw_move_vector, stream)?; + + Ok(()) + } + + fn proto_deserialize(stream: &mut Cursor<&[u8]>) -> Result { + let player_rotation = as ProtoCodecLE>::proto_deserialize(stream)?; + let player_position = as ProtoCodecLE>::proto_deserialize(stream)?; + let move_vector = as ProtoCodecLE>::proto_deserialize(stream)?; + let player_head_rotation = ::proto_deserialize(stream)?; + let input_data = ::proto_deserialize(stream)?; + let input_mode = ::proto_deserialize(stream)?; + let play_mode = ::proto_deserialize(stream)?; + let new_interaction_model = ::proto_deserialize(stream)?; + let interact_rotation = as ProtoCodecLE>::proto_deserialize(stream)?; + let client_tick = ::proto_deserialize(stream)?; + let velocity = as ProtoCodecLE>::proto_deserialize(stream)?; + let item_use_transaction = match &input_data + & PlayerAuthInputFlags::PERFORM_ITEM_INTERACTION + != 0 + { + true => Some( + ::proto_deserialize(stream)?, + ), + false => None, + }; + let item_stack_request = match &input_data + & PlayerAuthInputFlags::PERFORM_ITEM_STACK_REQUEST + != 0 + { + true => Some(::proto_deserialize(stream)?), + false => None, + }; + let player_block_actions = + match &input_data & PlayerAuthInputFlags::PERFORM_BLOCK_ACTIONS != 0 { + true => Some(::proto_deserialize( + stream, + )?), + false => None, + }; + let client_predicted_vehicle = match &input_data + & PlayerAuthInputFlags::IS_IN_CLIENT_PREDICTED_VEHICLE + != 0 + { + true => Some(::proto_deserialize(stream)?), + false => None, + }; + let analog_move_vector = as ProtoCodecLE>::proto_deserialize(stream)?; + let camera_orientation = as ProtoCodecLE>::proto_deserialize(stream)?; + let raw_move_vector = as ProtoCodecLE>::proto_deserialize(stream)?; + + Ok(Self { + player_rotation, + player_position, + move_vector, + player_head_rotation, + input_data, + input_mode, + play_mode, + new_interaction_model, + interact_rotation, + client_tick, + velocity, + item_use_transaction, + item_stack_request, + player_block_actions, + client_predicted_vehicle, + analog_move_vector, + camera_orientation, + raw_move_vector, + }) + } + + fn get_size_prediction(&self) -> usize { + ProtoCodecLE::get_size_prediction(&self.player_rotation) + + ProtoCodecLE::get_size_prediction(&self.player_position) + + ProtoCodecLE::get_size_prediction(&self.move_vector) + + ProtoCodecLE::get_size_prediction(&self.player_head_rotation) + + ProtoCodecVAR::get_size_prediction(&self.input_data) + + self.input_mode.get_size_prediction() + + self.play_mode.get_size_prediction() + + self.new_interaction_model.get_size_prediction() + + ProtoCodecLE::get_size_prediction(&self.interact_rotation) + + ProtoCodecVAR::get_size_prediction(&self.client_tick) + + ProtoCodecLE::get_size_prediction(&self.velocity) + + match &self.input_data & PlayerAuthInputFlags::PERFORM_ITEM_INTERACTION != 0 { + true => self.item_use_transaction.get_size_prediction(), + false => 0, + } + + match &self.input_data & PlayerAuthInputFlags::PERFORM_ITEM_STACK_REQUEST != 0 { + true => self.item_stack_request.get_size_prediction(), + false => 0, + } + + match &self.input_data & PlayerAuthInputFlags::PERFORM_BLOCK_ACTIONS != 0 { + true => self.player_block_actions.get_size_prediction(), + false => 0, + } + + match &self.input_data & PlayerAuthInputFlags::IS_IN_CLIENT_PREDICTED_VEHICLE != 0 + { + true => self.client_predicted_vehicle.get_size_prediction(), + false => 0, + } + + ProtoCodecLE::get_size_prediction(&self.analog_move_vector) + + ProtoCodecLE::get_size_prediction(&self.camera_orientation) + + ProtoCodecLE::get_size_prediction(&self.raw_move_vector) + } +} + +// VERIFY: ProtoCodec impl diff --git a/crates/proto/src/version/v766/packets/player_list.rs b/crates/proto/src/version/v766/packets/player_list.rs new file mode 100644 index 00000000..cd3dd3bd --- /dev/null +++ b/crates/proto/src/version/v766/packets/player_list.rs @@ -0,0 +1,8 @@ +use crate::version::v766::enums::PlayerListPacketType; +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 63)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct PlayerListPacket { + pub action: PlayerListPacketType, +} \ No newline at end of file diff --git a/crates/proto/src/version/v766/packets/resource_pack_stack.rs b/crates/proto/src/version/v766/packets/resource_pack_stack.rs new file mode 100644 index 00000000..54eb3e95 --- /dev/null +++ b/crates/proto/src/version/v766/packets/resource_pack_stack.rs @@ -0,0 +1,24 @@ +use crate::version::v662::types::{BaseGameVersion, Experiments}; +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[derive(ProtoCodec, Clone, Debug)] +pub struct PackEntry { + pub id: String, + pub version: String, + pub sub_pack_name: String, +} + +#[gamepacket(id = 7)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct ResourcePackStackPacket { + pub texture_pack_required: bool, + #[vec_repr(u32)] + #[vec_endianness(var)] + pub addon_list: Vec, + #[vec_repr(u32)] + #[vec_endianness(var)] + pub texture_pack_list: Vec, + pub base_game_version: BaseGameVersion, + pub experiments: Experiments, + pub include_editor_packs: bool, +} \ No newline at end of file diff --git a/crates/proto/src/version/v766/packets/resource_packs_info.rs b/crates/proto/src/version/v766/packets/resource_packs_info.rs new file mode 100644 index 00000000..f0d7ba49 --- /dev/null +++ b/crates/proto/src/version/v766/packets/resource_packs_info.rs @@ -0,0 +1,29 @@ +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[derive(ProtoCodec, Clone, Debug)] +pub struct ResourcePackEntry { + pub id: String, + pub version: String, + #[endianness(le)] + pub size: u64, + pub content_key: String, + pub sub_pack_name: String, + pub content_identity: String, + pub has_scripts: bool, + pub is_addon_pack: bool, + pub is_ray_tracing_capable: bool, + pub cdn_url: String, +} + +#[gamepacket(id = 6)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct ResourcePacksInfoPacket { + pub resource_pack_required: bool, + pub has_addon_packs: bool, + pub has_scripts: bool, + pub world_template_uuid: uuid::Uuid, + pub world_template_version: String, + #[vec_repr(u16)] + #[vec_endianness(le)] + pub resource_packs: Vec, +} \ No newline at end of file diff --git a/crates/proto/src/version/v766/packets/server_bound_diagnostics.rs b/crates/proto/src/version/v766/packets/server_bound_diagnostics.rs new file mode 100644 index 00000000..40898a34 --- /dev/null +++ b/crates/proto/src/version/v766/packets/server_bound_diagnostics.rs @@ -0,0 +1,24 @@ +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 315)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct ServerBoundDiagnosticsPacket { + #[endianness(le)] + pub average_fps: f32, + #[endianness(le)] + pub average_server_time: f32, + #[endianness(le)] + pub average_client_time: f32, + #[endianness(le)] + pub average_begin_frame_time: f32, + #[endianness(le)] + pub average_input_time: f32, + #[endianness(le)] + pub average_render_time: f32, + #[endianness(le)] + pub average_end_frame_time: f32, + #[endianness(le)] + pub average_remaining_time_percent: f32, + #[endianness(le)] + pub average_unaccounted_time_percent: f32, +} \ No newline at end of file diff --git a/crates/proto/src/version/v766/packets/server_bound_loading_screen.rs b/crates/proto/src/version/v766/packets/server_bound_loading_screen.rs new file mode 100644 index 00000000..50ad771e --- /dev/null +++ b/crates/proto/src/version/v766/packets/server_bound_loading_screen.rs @@ -0,0 +1,19 @@ +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[derive(ProtoCodec, Clone, Debug)] +#[enum_repr(i32)] +#[enum_endianness(var)] +#[repr(i32)] +pub enum LoadingScreenType { + Unknown = 0, + StartLoadingScreen = 1, + EndLoadingScreen = 2, +} + +#[gamepacket(id = 312)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct ServerBoundLoadingScreenPacket { + pub loading_screen_type: LoadingScreenType, + #[endianness(var)] + pub loading_screen_id: Option, +} \ No newline at end of file diff --git a/crates/proto/src/version/v766/packets/set_actor_data.rs b/crates/proto/src/version/v766/packets/set_actor_data.rs new file mode 100644 index 00000000..e0cc4f52 --- /dev/null +++ b/crates/proto/src/version/v766/packets/set_actor_data.rs @@ -0,0 +1,15 @@ +use crate::version::v662::types::{ActorRuntimeID, PropertySyncData}; +use bedrockrs_macros::{gamepacket, ProtoCodec}; +use crate::version::v766::types::DataItem; + +#[gamepacket(id = 39)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct SetActorDataPacket { + pub target_runtime_id: ActorRuntimeID, + #[vec_repr(u32)] + #[vec_endianness(var)] + pub actor_data: Vec, // VERIFY: vec_repr & vec_endianness + pub synced_properties: PropertySyncData, + #[endianness(var)] + pub tick: u64, +} \ No newline at end of file diff --git a/crates/proto/src/version/v766/packets/set_actor_link.rs b/crates/proto/src/version/v766/packets/set_actor_link.rs new file mode 100644 index 00000000..0323d6da --- /dev/null +++ b/crates/proto/src/version/v766/packets/set_actor_link.rs @@ -0,0 +1,8 @@ +use crate::version::v766::types::ActorLink; +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 41)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct SetActorLinkPacket { + pub link: ActorLink, +} \ No newline at end of file diff --git a/crates/proto/src/version/v766/packets/set_movement_authority.rs b/crates/proto/src/version/v766/packets/set_movement_authority.rs new file mode 100644 index 00000000..726cdfab --- /dev/null +++ b/crates/proto/src/version/v766/packets/set_movement_authority.rs @@ -0,0 +1,17 @@ +use bedrockrs_macros::{gamepacket, ProtoCodec}; + + +#[derive(ProtoCodec, Clone, Debug)] +#[enum_repr(i8)] +#[repr(i8)] +pub enum AuthMovementMode { + LegacyClientAuthoritativeV1 = 0, + ClientAuthoritativeV2 = 1, + ServerAuthoritativeV3 = 2, +} + +#[gamepacket(id = 319)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct SetMovementAuthorityPacket { + pub new_auth_movement_mode: AuthMovementMode, +} \ No newline at end of file diff --git a/crates/proto/src/version/v766/packets/set_title.rs b/crates/proto/src/version/v766/packets/set_title.rs new file mode 100644 index 00000000..34875b47 --- /dev/null +++ b/crates/proto/src/version/v766/packets/set_title.rs @@ -0,0 +1,33 @@ +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[derive(ProtoCodec, Clone, Debug)] +#[enum_repr(i32)] +#[enum_endianness(var)] +#[repr(i32)] +pub enum TitleType { + Clear = 0, + Reset = 1, + Title = 2, + Subtitle = 3, + Actionbar = 4, + Times = 5, + TitleTextObject = 6, + SubtitleTextObject = 7, + ActionbarTextObject = 8, +} + +#[gamepacket(id = 88)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct SetTitlePacket { + pub title_type: TitleType, + pub title_text: String, + #[endianness(var)] + pub fade_in_time: i32, + #[endianness(var)] + pub stay_time: i32, + #[endianness(var)] + pub fade_out_time: i32, + pub xuid: String, + pub platform_online_id: String, + pub filtered_title_message: String, +} \ No newline at end of file diff --git a/crates/proto/src/version/v766/packets/start_game.rs b/crates/proto/src/version/v766/packets/start_game.rs new file mode 100644 index 00000000..c4e5be31 --- /dev/null +++ b/crates/proto/src/version/v766/packets/start_game.rs @@ -0,0 +1,52 @@ +use crate::version::v662::enums::GameType; +use crate::version::v662::types::{ActorRuntimeID, ActorUniqueID, ItemData, NetworkPermissions, SyncedPlayerMovementSettings}; +use crate::version::v766::types::LevelSettings; +use vek::{Vec2, Vec3}; +use bedrockrs_macros::{gamepacket, ProtoCodec}; +use uuid::Uuid; + +#[derive(ProtoCodec, Clone, Debug)] +pub struct BlockProperty { + pub block_name: String, + #[nbt] + pub block_definition: nbtx::Value, // TODO: NBT Structure +} + +#[gamepacket(id = 11)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct StartGamePacket { + pub target_actor_id: ActorUniqueID, + pub target_runtime_id: ActorRuntimeID, + pub actor_game_type: GameType, + #[endianness(le)] + pub position: Vec3, + #[endianness(le)] + pub rotation: Vec2, + pub settings: LevelSettings, + pub level_id: String, + pub level_name: String, + pub template_content_identity: String, + pub is_trial: bool, + pub movement_settings: SyncedPlayerMovementSettings, + #[endianness(le)] + pub current_level_time: u64, + #[endianness(var)] + pub enchantment_seed: i32, + #[vec_repr(u32)] + #[vec_endianness(var)] + pub block_properties: Vec, + #[vec_repr(u32)] + #[vec_endianness(var)] + pub item_list: Vec, + pub multiplayer_correlation_id: String, + pub enable_item_stack_net_manager: bool, + pub server_version: String, + #[nbt] + pub player_property_data: nbtx::Value, // TODO: NBT Structure, + #[endianness(le)] + pub server_block_type_registry_checksum: u64, + pub world_template_id: Uuid, + pub server_enabled_client_side_generation: bool, + pub block_network_ids_are_hashes: bool, + pub network_permissions: NetworkPermissions, +} diff --git a/crates/proto/src/version/v766/packets/stop_sound.rs b/crates/proto/src/version/v766/packets/stop_sound.rs new file mode 100644 index 00000000..3884aabe --- /dev/null +++ b/crates/proto/src/version/v766/packets/stop_sound.rs @@ -0,0 +1,9 @@ +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 87)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct StopSoundPacket { + pub sound_name: String, + pub stop_all_sounds: bool, + pub stop_music: bool, +} \ No newline at end of file diff --git a/crates/proto/src/version/v766/packets/text.rs b/crates/proto/src/version/v766/packets/text.rs new file mode 100644 index 00000000..dc382f2e --- /dev/null +++ b/crates/proto/src/version/v766/packets/text.rs @@ -0,0 +1,64 @@ +use crate::version::v662::enums::TextPacketType; +use bedrockrs_macros::gamepacket; +use bedrockrs_proto_core::error::ProtoCodecError; +use bedrockrs_proto_core::ProtoCodec; +use byteorder::{ReadBytesExt, WriteBytesExt}; +use std::io::{Cursor, Read}; + +#[gamepacket(id = 9)] +#[derive(Clone, Debug)] +pub struct TextPacket { + pub message_type: TextPacketType, + pub localize: bool, + pub sender_xuid: String, + pub platform_id: String, + pub filtered_message: String, +} + +impl ProtoCodec for TextPacket { + fn proto_serialize(&self, stream: &mut Vec) -> Result<(), ProtoCodecError> { + let mut message_type_stream: Vec = Vec::new(); + TextPacketType::proto_serialize(&self.message_type, &mut message_type_stream)?; + let mut message_type_cursor = Cursor::new(message_type_stream.as_slice()); + + stream.write_i8(message_type_cursor.read_i8()?)?; + bool::proto_serialize(&self.localize, stream)?; + message_type_cursor.read_to_end(stream)?; + String::proto_serialize(&self.sender_xuid, stream)?; + String::proto_serialize(&self.platform_id, stream)?; + String::proto_serialize(&self.filtered_message, stream)?; + + Ok(()) + } + + fn proto_deserialize(stream: &mut Cursor<&[u8]>) -> Result { + let mut sub_stream: Vec = Vec::new(); + + sub_stream.write_i8(stream.read_i8()?)?; + let localize = bool::proto_deserialize(stream)?; + stream.read_to_end(&mut sub_stream)?; + let mut sub_cursor = Cursor::new(sub_stream.as_slice()); + let message_type = TextPacketType::proto_deserialize(&mut sub_cursor)?; + let sender_xuid = String::proto_deserialize(&mut sub_cursor)?; + let platform_id = String::proto_deserialize(&mut sub_cursor)?; + let filtered_message = String::proto_deserialize(&mut sub_cursor)?; + + Ok(Self { + message_type, + localize, + sender_xuid, + platform_id, + filtered_message, + }) + } + + fn get_size_prediction(&self) -> usize { + self.message_type.get_size_prediction() + + self.localize.get_size_prediction() + + self.sender_xuid.get_size_prediction() + + self.platform_id.get_size_prediction() + + self.filtered_message.get_size_prediction() + } +} + +// VERIFY: ProtoCodec impl diff --git a/crates/proto/src/version/v766/packets/transfer_player.rs b/crates/proto/src/version/v766/packets/transfer_player.rs new file mode 100644 index 00000000..5d85a077 --- /dev/null +++ b/crates/proto/src/version/v766/packets/transfer_player.rs @@ -0,0 +1,10 @@ +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 85)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct TransferPlayerPacket { + pub server_address: String, + #[endianness(le)] + pub server_port: u16, + pub reload_world: bool, +} \ No newline at end of file diff --git a/crates/proto/src/version/v766/packets/update_attributes.rs b/crates/proto/src/version/v766/packets/update_attributes.rs new file mode 100644 index 00000000..541904df --- /dev/null +++ b/crates/proto/src/version/v766/packets/update_attributes.rs @@ -0,0 +1,45 @@ +use crate::version::v662::enums::{AttributeModifierOperation, AttributeOperands}; +use crate::version::v662::types::ActorRuntimeID; +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[derive(ProtoCodec, Clone, Debug)] +pub struct AttributeModifier { + pub id: String, + pub name: String, + #[endianness(le)] + pub amount: f32, + pub operation: AttributeModifierOperation, + pub operand: AttributeOperands, + pub is_serializable: bool, +} + +#[derive(ProtoCodec, Clone, Debug)] +pub struct AttributeData { + #[endianness(le)] + pub min_value: f32, + #[endianness(le)] + pub max_value: f32, + #[endianness(le)] + pub current_value: f32, + #[endianness(le)] + pub default_min_value: f32, + #[endianness(le)] + pub default_max_value: f32, + #[endianness(le)] + pub default_value: f32, + pub name: String, + #[vec_repr(u32)] + #[vec_endianness(var)] + pub modifiers: Vec, +} + +#[gamepacket(id = 29)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct UpdateAttributesPacket { + pub target_runtime_id: ActorRuntimeID, + #[vec_repr(u32)] + #[vec_endianness(var)] + pub attribute_list: Vec, + #[endianness(var)] + pub tick: u64, +} \ No newline at end of file diff --git a/crates/proto/src/version/v766/packets/update_player_game_type.rs b/crates/proto/src/version/v766/packets/update_player_game_type.rs new file mode 100644 index 00000000..01e29a64 --- /dev/null +++ b/crates/proto/src/version/v766/packets/update_player_game_type.rs @@ -0,0 +1,12 @@ +use crate::version::v662::enums::GameType; +use crate::version::v662::types::ActorUniqueID; +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 151)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct UpdatePlayerGameTypePacket { + pub player_game_type: GameType, + pub target_player: ActorUniqueID, + #[endianness(var)] + pub tick: u64, +} \ No newline at end of file diff --git a/crates/proto/src/version/v766/packets/update_soft_enum.rs b/crates/proto/src/version/v766/packets/update_soft_enum.rs new file mode 100644 index 00000000..b279cb2c --- /dev/null +++ b/crates/proto/src/version/v766/packets/update_soft_enum.rs @@ -0,0 +1,12 @@ +use crate::version::v766::enums::SoftEnumUpdateType; +use bedrockrs_macros::{gamepacket, ProtoCodec}; + +#[gamepacket(id = 114)] +#[derive(ProtoCodec, Clone, Debug)] +pub struct UpdateSoftEnumPacket { + pub enum_name: String, + #[vec_repr(u32)] + #[vec_endianness(var)] + pub values: Vec, + pub update_type: SoftEnumUpdateType, +} \ No newline at end of file diff --git a/crates/proto/src/version/v766/types/actor_link.rs b/crates/proto/src/version/v766/types/actor_link.rs new file mode 100644 index 00000000..1e892eff --- /dev/null +++ b/crates/proto/src/version/v766/types/actor_link.rs @@ -0,0 +1,15 @@ +use crate::version::v662::enums::ActorLinkType; +use crate::version::v662::types::ActorUniqueID; +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +pub struct ActorLink { + pub actor_unique_id_a: ActorUniqueID, + pub actor_unique_id_b: ActorUniqueID, + pub link_type: ActorLinkType, + pub immediate: bool, + /// Whether the link was changed by the passenger + pub passenger_initiated: bool, + #[endianness(le)] + pub vehicle_angular_velocity: f32, +} diff --git a/crates/proto/src/version/v766/types/base_description.rs b/crates/proto/src/version/v766/types/base_description.rs new file mode 100644 index 00000000..2fea203d --- /dev/null +++ b/crates/proto/src/version/v766/types/base_description.rs @@ -0,0 +1,33 @@ +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +pub struct DeferredDescriptor { + pub full_name: String, + #[endianness(le)] + pub aux_value: u16, +} + +#[derive(ProtoCodec, Clone, Debug)] +pub struct InternalItemDescriptor { + pub full_name: String, + #[endianness(le)] + pub aux_value: u16, +} + +#[derive(ProtoCodec, Clone, Debug)] +pub struct MolangDescriptor { + pub full_name: String, +} + +#[derive(ProtoCodec, Clone, Debug)] +pub struct ItemTagDescriptor { + pub item_tag: String, +} + +#[derive(ProtoCodec, Clone, Debug)] +pub struct BaseDescription { + pub deferred_descriptor: DeferredDescriptor, + pub internal_item_descriptor: InternalItemDescriptor, + pub item_tag_descriptor: ItemTagDescriptor, + pub molang_descriptor: MolangDescriptor, +} \ No newline at end of file diff --git a/crates/proto/src/version/v766/types/camera_instruction.rs b/crates/proto/src/version/v766/types/camera_instruction.rs new file mode 100644 index 00000000..8997ba3e --- /dev/null +++ b/crates/proto/src/version/v766/types/camera_instruction.rs @@ -0,0 +1,69 @@ +use crate::version::v662::enums::EasingType; +use bedrockrs_macros::ProtoCodec; +use vek::{Vec2, Vec3}; + +#[derive(ProtoCodec, Clone, Debug)] +pub struct EaseData { + pub ease_type: EasingType, + #[endianness(le)] + pub ease_time: f32, +} + +#[derive(ProtoCodec, Clone, Debug)] +pub struct SetInstruction { + #[endianness(le)] + pub runtime_id: i32, + pub ease_data: Option, + #[endianness(le)] + pub position: Option>, + #[endianness(le)] + pub rotation: Option>, + #[endianness(le)] + pub facing: Option>, + pub default_preset: Option, +} + +#[derive(ProtoCodec, Clone, Debug)] +pub struct TimeData { + #[endianness(le)] + pub fade_in_time: f32, + #[endianness(le)] + pub wait_time: f32, + #[endianness(le)] + pub fade_out_time: f32, +} + +#[derive(ProtoCodec, Clone, Debug)] +pub struct Color { + #[endianness(le)] + pub r: f32, + #[endianness(le)] + pub g: f32, + #[endianness(le)] + pub b: f32, +} + +#[derive(ProtoCodec, Clone, Debug)] +pub struct FadeInstruction { + pub time_data: Option, + pub color: Option, +} + +#[derive(ProtoCodec, Clone, Debug)] +pub struct TargetInstruction { + #[endianness(le)] + pub target_center_offset: Vec3, + #[endianness(le)] + pub unique_entity_id: i64, +} + +#[derive(ProtoCodec, Clone, Debug)] +pub struct CameraInstruction { + pub set: Option, + pub clear: Option, + pub fade: Option, + pub target: Option, + pub remove_target: Option, +} + +// VERIFY: SetInstruction & FadeInstruction \ No newline at end of file diff --git a/crates/proto/src/version/v766/types/camera_preset.rs b/crates/proto/src/version/v766/types/camera_preset.rs new file mode 100644 index 00000000..5a3921fd --- /dev/null +++ b/crates/proto/src/version/v766/types/camera_preset.rs @@ -0,0 +1,57 @@ +use bedrockrs_macros::ProtoCodec; +use vek::{Vec2, Vec3}; + +#[derive(ProtoCodec, Clone, Debug)] +#[enum_repr(i8)] +#[repr(i8)] +pub enum AudioListener { + Camera = 0, + Player = 1, +} + +#[derive(ProtoCodec, Clone, Debug)] +pub struct CameraPresetAimAssist { + pub id: String, + #[endianness(le)] + pub target_mode: i32, + #[endianness(le)] + pub angle: Vec2, + #[endianness(le)] + pub distance: f32, +} + +#[derive(ProtoCodec, Clone, Debug)] +pub struct CameraPreset { + pub name: String, + pub inherit_from: String, + #[endianness(le)] + pub pos_x: Option, + #[endianness(le)] + pub pos_y: Option, + #[endianness(le)] + pub pos_z: Option, + #[endianness(le)] + pub rot_x: Option, + #[endianness(le)] + pub rot_y: Option, + #[endianness(le)] + pub rotation_speed: Option, + pub snap_to_target: Option, + #[endianness(le)] + pub horizontal_rotation_limit: Option>, + #[endianness(le)] + pub vertical_rotation_limit: Option>, + pub continue_targeting: Option, + #[endianness(le)] + pub block_listening_radius: Option, + #[endianness(le)] + pub view_offset: Option>, + #[endianness(le)] + pub entity_offset: Option>, + #[endianness(le)] + pub radius: Option, + pub listener: Option, + pub player_effects: Option, + pub align_target_and_camera_forward: Option, + pub aim_assist: Option, +} \ No newline at end of file diff --git a/crates/proto/src/version/v766/types/camera_presets.rs b/crates/proto/src/version/v766/types/camera_presets.rs new file mode 100644 index 00000000..5eebd527 --- /dev/null +++ b/crates/proto/src/version/v766/types/camera_presets.rs @@ -0,0 +1,9 @@ +use crate::version::v766::types::CameraPreset; +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +pub struct CameraPresets { + #[vec_repr(u32)] + #[vec_endianness(var)] + pub presets: Vec, +} \ No newline at end of file diff --git a/crates/proto/src/version/v766/types/crafting_data_entry.rs b/crates/proto/src/version/v766/types/crafting_data_entry.rs new file mode 100644 index 00000000..b0470b33 --- /dev/null +++ b/crates/proto/src/version/v766/types/crafting_data_entry.rs @@ -0,0 +1,7 @@ +use crate::version::v766::enums::CraftingDataEntryType; +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +pub struct CraftingDataEntry { + pub crafting_type: CraftingDataEntryType, +} \ No newline at end of file diff --git a/crates/proto/src/version/v766/types/data_item.rs b/crates/proto/src/version/v766/types/data_item.rs new file mode 100644 index 00000000..5f3d5232 --- /dev/null +++ b/crates/proto/src/version/v766/types/data_item.rs @@ -0,0 +1,9 @@ +use crate::version::v766::enums::DataItemType; +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +pub struct DataItem { + #[endianness(var)] + pub data_item_id: u32, + pub data_item_type: DataItemType, +} \ No newline at end of file diff --git a/crates/proto/src/version/v766/types/full_container_name.rs b/crates/proto/src/version/v766/types/full_container_name.rs new file mode 100644 index 00000000..fef7d064 --- /dev/null +++ b/crates/proto/src/version/v766/types/full_container_name.rs @@ -0,0 +1,9 @@ +use crate::version::v662::enums::ContainerName; +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +pub struct FullContainerName { + pub container_name: ContainerName, + #[endianness(le)] + pub dynamic_id: Option, +} \ No newline at end of file diff --git a/crates/proto/src/version/v766/types/item_stack_request_slot_info.rs b/crates/proto/src/version/v766/types/item_stack_request_slot_info.rs new file mode 100644 index 00000000..d95123e4 --- /dev/null +++ b/crates/proto/src/version/v766/types/item_stack_request_slot_info.rs @@ -0,0 +1,10 @@ +use crate::v766::types::FullContainerName; +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +pub struct ItemStackRequestSlotInfo { + pub full_container_name: FullContainerName, + pub slot: i8, + #[endianness(var)] + pub raw_id: i32, +} \ No newline at end of file diff --git a/crates/proto/src/version/v766/types/item_stack_response_container_info.rs b/crates/proto/src/version/v766/types/item_stack_response_container_info.rs new file mode 100644 index 00000000..b69c24df --- /dev/null +++ b/crates/proto/src/version/v766/types/item_stack_response_container_info.rs @@ -0,0 +1,11 @@ +use crate::version::v766::types::ItemStackResponseSlotInfo; +use bedrockrs_macros::ProtoCodec; +use crate::v766::types::FullContainerName; + +#[derive(ProtoCodec, Clone, Debug)] +pub struct ItemStackResponseContainerInfo { + pub full_container_name: FullContainerName, + #[vec_repr(u32)] + #[vec_endianness(var)] + pub slots: Vec +} \ No newline at end of file diff --git a/crates/proto/src/version/v766/types/item_stack_response_info.rs b/crates/proto/src/version/v766/types/item_stack_response_info.rs new file mode 100644 index 00000000..192e6185 --- /dev/null +++ b/crates/proto/src/version/v766/types/item_stack_response_info.rs @@ -0,0 +1,47 @@ +use std::io::{Cursor, Read}; +use byteorder::{ReadBytesExt, WriteBytesExt}; +use crate::version::v766::enums::ItemStackNetResult; +use bedrockrs_proto_core::error::ProtoCodecError; +use bedrockrs_proto_core::{ProtoCodec, ProtoCodecVAR}; + +#[derive(Clone, Debug)] +pub struct ItemStackResponseInfo { + pub result: ItemStackNetResult, + pub client_request_id: i32, +} + +impl ProtoCodec for ItemStackResponseInfo { + fn proto_serialize(&self, stream: &mut Vec) -> Result<(), ProtoCodecError> { + let mut result_stream: Vec = Vec::new(); + + self.result.proto_serialize(&mut result_stream)?; + let mut result_cursor = Cursor::new(result_stream.as_slice()); + + stream.write_i8(result_cursor.read_i8()?)?; + ::proto_serialize(&self.client_request_id, stream)?; + result_cursor.read_to_end(stream)?; + + Ok(()) + } + + fn proto_deserialize(stream: &mut Cursor<&[u8]>) -> Result { + let mut result_stream: Vec = Vec::new(); + + result_stream.write_i8(stream.read_i8()?)?; + let client_request_id = ::proto_deserialize(stream)?; + stream.read_to_end(&mut result_stream)?; + + let mut result_cursor = Cursor::new(result_stream.as_slice()); + let result = ItemStackNetResult::proto_deserialize(&mut result_cursor)?; + + Ok(Self { + result, + client_request_id + }) + } + + fn get_size_prediction(&self) -> usize { + self.result.get_size_prediction() + + ::get_size_prediction(&self.client_request_id) + } +} \ No newline at end of file diff --git a/crates/proto/src/version/v766/types/item_stack_response_slot_info.rs b/crates/proto/src/version/v766/types/item_stack_response_slot_info.rs new file mode 100644 index 00000000..4ed85461 --- /dev/null +++ b/crates/proto/src/version/v766/types/item_stack_response_slot_info.rs @@ -0,0 +1,14 @@ +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +pub struct ItemStackResponseSlotInfo { + pub requested_slot: i8, + pub slot: i8, + pub amount: i8, + #[endianness(var)] + pub item_stack_net_id: i32, + pub custom_name: String, + pub filtered_custom_name: String, + #[endianness(var)] + pub durability_correction: i32, +} \ No newline at end of file diff --git a/crates/proto/src/version/v766/types/level_settings.rs b/crates/proto/src/version/v766/types/level_settings.rs new file mode 100644 index 00000000..6faaae78 --- /dev/null +++ b/crates/proto/src/version/v766/types/level_settings.rs @@ -0,0 +1,65 @@ +use crate::version::v662::enums::{ChatRestrictionLevel, Difficulty, EditorWorldType, EducationEditionOffer, GamePublishSetting, GameType, GeneratorType, PlayerPermissionLevel}; +use crate::version::v662::types::{BaseGameVersion, EduSharedUriResource, Experiments, GameRulesChangedPacketData, NetworkBlockPosition, SpawnSettings}; +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +pub struct LevelSettings { + #[endianness(le)] + pub seed: u64, + pub spawn_settings: SpawnSettings, + pub generator_type: GeneratorType, + pub game_type: GameType, + pub is_hardcore_mode_enabled: bool, + pub game_difficulty: Difficulty, + pub default_spawn_block_position: NetworkBlockPosition, + pub achievements_disabled: bool, + pub editor_world_type: EditorWorldType, + pub is_created_in_editor: bool, + pub is_exported_from_editor: bool, + #[endianness(var)] + pub day_cycle_stop_time: i32, + pub education_edition_offer: EducationEditionOffer, + pub education_features_enabled: bool, + pub education_product_id: String, + #[endianness(le)] + pub rain_level: f32, + #[endianness(le)] + pub lightning_level: f32, + pub has_confirmed_platform_locked_content: bool, + pub multiplayer_enabled: bool, + pub lan_broadcasting_enabled: bool, + pub xbox_live_broadcast_setting: GamePublishSetting, + pub platform_broadcast_setting: GamePublishSetting, + pub commands_enabled: bool, + pub texture_packs_required: bool, + pub rule_data: GameRulesChangedPacketData, + pub experiments: Experiments, + pub bonus_chest_enabled: bool, + pub starting_map_enabled: bool, + pub player_permissions: PlayerPermissionLevel, + #[endianness(le)] + pub server_chunk_tick_range: i32, + pub locked_behaviour_pack: bool, + pub locked_resource_pack: bool, + pub from_locked_template: bool, + pub use_msa_gamer_tags: bool, + pub from_template: bool, + pub has_locked_template_settings: bool, + pub only_spawn_v1_villagers: bool, + pub persona_disabled: bool, + pub custom_skins_disabled: bool, + pub emote_chat_muted: bool, + pub base_game_version: BaseGameVersion, + #[endianness(le)] + pub limited_world_width: i32, + #[endianness(le)] + pub limited_world_depth: i32, + pub nether_type: bool, + pub edu_shared_uri_resource: EduSharedUriResource, + pub override_force_experimental_gameplay: bool, + pub chat_restriction_level: ChatRestrictionLevel, + pub disable_player_interactions: bool, + pub server_identifier: String, + pub server_world_identifier: String, + pub server_scenario_identifier: String, +} \ No newline at end of file diff --git a/crates/proto/src/version/v766/types/mod.rs b/crates/proto/src/version/v766/types/mod.rs new file mode 100644 index 00000000..a0178ff0 --- /dev/null +++ b/crates/proto/src/version/v766/types/mod.rs @@ -0,0 +1,29 @@ +macro_rules! export { + ($name:ident) => { + mod $name; + pub use $name::*; + }; +} + +export!(actor_link); +export!(base_description); +export!(camera_instruction); +export!(camera_preset); +export!(camera_presets); +export!(full_container_name); +export!(user_data_shapeless_recipe); +export!(recipe_unlocking_requirement); +export!(crafting_data_entry); +export!(data_item); +export!(item_stack_request_slot_info); +export!(item_stack_response_container_info); +export!(item_stack_response_slot_info); +export!(level_settings); +export!(packed_item_use_legacy_inventory_transaction); +export!(player_block_action_data); +export!(player_input_tick); +export!(shaped_chemistry_recipe); +export!(shaped_recipe); +export!(shapeless_recipe); +export!(item_stack_response_info); +export!(player_block_actions); diff --git a/crates/proto/src/version/v766/types/packed_item_use_legacy_inventory_transaction.rs b/crates/proto/src/version/v766/types/packed_item_use_legacy_inventory_transaction.rs new file mode 100644 index 00000000..2d884297 --- /dev/null +++ b/crates/proto/src/version/v766/types/packed_item_use_legacy_inventory_transaction.rs @@ -0,0 +1,148 @@ +use crate::version::v662::enums::ItemUseInventoryTransactionType; +use crate::version::v662::types::{ + InventoryTransaction, NetworkBlockPosition, NetworkItemStackDescriptor, +}; +use bedrockrs_macros::ProtoCodec; +use bedrockrs_proto_core::error::ProtoCodecError; +use bedrockrs_proto_core::{ProtoCodec, ProtoCodecLE, ProtoCodecVAR}; +use std::io::Cursor; +use vek::Vec3; + +#[derive(ProtoCodec, Clone, Debug)] +pub struct ContainerSlotEntry { + pub container_enum_name: String, + #[vec_repr(u32)] + #[vec_endianness(var)] + pub slots: Vec, +} + +#[derive(ProtoCodec, Clone, Debug)] +#[enum_repr(u32)] +#[enum_endianness(var)] +#[repr(u32)] +pub enum TriggerType { + Unknown = 0, + PlayerInput = 1, + SimulationTick = 2, +} + +#[derive(ProtoCodec, Clone, Debug)] +#[enum_repr(i8)] +#[repr(i8)] +pub enum PredictedResult { + Failure = 0, + Success = 1, +} + +#[derive(Clone, Debug)] +pub struct PackedItemUseLegacyInventoryTransaction { + id: i32, + container_slots: Option>, + action: InventoryTransaction, + action_type: ItemUseInventoryTransactionType, + trigger_type: TriggerType, + position: NetworkBlockPosition, + face: i32, + slot: i32, + item: NetworkItemStackDescriptor, + from_position: Vec3, + click_position: Vec3, + target_block_id: u32, + predicted_result: PredictedResult, +} + +impl ProtoCodec for PackedItemUseLegacyInventoryTransaction { + fn proto_serialize(&self, stream: &mut Vec) -> Result<(), ProtoCodecError> { + ProtoCodecVAR::proto_serialize(&self.id, stream)?; + + match &self.id { + 0 => {} + _ => { + let vec = self.container_slots.as_ref().unwrap(); + let len: u32 = vec.len().try_into()?; + ProtoCodecVAR::proto_serialize(&len, stream)?; + for i in vec { + i.proto_serialize(stream)? + } + } + } + + self.action.proto_serialize(stream)?; + self.action_type.proto_serialize(stream)?; + self.trigger_type.proto_serialize(stream)?; + self.position.proto_serialize(stream)?; + ProtoCodecVAR::proto_serialize(&self.face, stream)?; + ProtoCodecVAR::proto_serialize(&self.slot, stream)?; + self.item.proto_serialize(stream)?; + ProtoCodecLE::proto_serialize(&self.from_position, stream)?; + ProtoCodecLE::proto_serialize(&self.click_position, stream)?; + ProtoCodecVAR::proto_serialize(&self.target_block_id, stream)?; + self.predicted_result.proto_serialize(stream)?; + + Ok(()) + } + + fn proto_deserialize(stream: &mut Cursor<&[u8]>) -> Result { + let id = ::proto_deserialize(stream)?; + let container_slots = match id { + 0 => None, + _ => { + let len = ::proto_deserialize(stream)?; + let mut vec = Vec::with_capacity(len.try_into()?); + for _ in 0..len { + vec.push(ContainerSlotEntry::proto_deserialize(stream)?); + } + Some(vec) + } + }; + let action = InventoryTransaction::proto_deserialize(stream)?; + let action_type = ItemUseInventoryTransactionType::proto_deserialize(stream)?; + let trigger_type = TriggerType::proto_deserialize(stream)?; + let position = NetworkBlockPosition::proto_deserialize(stream)?; + let face = ::proto_deserialize(stream)?; + let slot = ::proto_deserialize(stream)?; + let item = NetworkItemStackDescriptor::proto_deserialize(stream)?; + let from_position = as ProtoCodecLE>::proto_deserialize(stream)?; + let click_position = as ProtoCodecLE>::proto_deserialize(stream)?; + let target_block_id = ::proto_deserialize(stream)?; + let predicted_result = PredictedResult::proto_deserialize(stream)?; + + Ok(Self { + id, + container_slots, + action, + action_type, + trigger_type, + position, + face, + slot, + item, + from_position, + click_position, + target_block_id, + predicted_result, + }) + } + + fn get_size_prediction(&self) -> usize { + ProtoCodecVAR::get_size_prediction(&self.id) + + match &self.id { + 0 => 0, + _ => { + let vec = self.container_slots.as_ref().unwrap(); + vec.len() + vec.iter().map(|i| i.get_size_prediction()).sum::() + } + } + + self.action.get_size_prediction() + + self.action_type.get_size_prediction() + + self.trigger_type.get_size_prediction() + + self.position.get_size_prediction() + + ProtoCodecVAR::get_size_prediction(&self.face) + + ProtoCodecVAR::get_size_prediction(&self.slot) + + self.item.get_size_prediction() + + ProtoCodecLE::get_size_prediction(&self.from_position) + + ProtoCodecLE::get_size_prediction(&self.click_position) + + ProtoCodecVAR::get_size_prediction(&self.target_block_id) + + self.predicted_result.get_size_prediction() + } +} diff --git a/crates/proto/src/version/v766/types/player_block_action_data.rs b/crates/proto/src/version/v766/types/player_block_action_data.rs new file mode 100644 index 00000000..a09ecc0b --- /dev/null +++ b/crates/proto/src/version/v766/types/player_block_action_data.rs @@ -0,0 +1,7 @@ +use crate::version::v766::enums::PlayerActionType; +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +pub struct PlayerBlockActionData { + pub player_action_type: PlayerActionType, +} \ No newline at end of file diff --git a/crates/proto/src/version/v766/types/player_block_actions.rs b/crates/proto/src/version/v766/types/player_block_actions.rs new file mode 100644 index 00000000..89fbc863 --- /dev/null +++ b/crates/proto/src/version/v766/types/player_block_actions.rs @@ -0,0 +1,9 @@ +use crate::version::v766::types::PlayerBlockActionData; +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +pub struct PlayerBlockActions { + #[vec_repr(i32)] + #[vec_endianness(var)] + pub player_block_actions: Vec +} \ No newline at end of file diff --git a/crates/proto/src/version/v766/types/player_input_tick.rs b/crates/proto/src/version/v766/types/player_input_tick.rs new file mode 100644 index 00000000..9f69c3b4 --- /dev/null +++ b/crates/proto/src/version/v766/types/player_input_tick.rs @@ -0,0 +1,7 @@ +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +pub struct PlayerInputTick { + #[endianness(var)] + pub tick: u64, +} \ No newline at end of file diff --git a/crates/proto/src/version/v766/types/recipe_unlocking_requirement.rs b/crates/proto/src/version/v766/types/recipe_unlocking_requirement.rs new file mode 100644 index 00000000..a1a05e0a --- /dev/null +++ b/crates/proto/src/version/v766/types/recipe_unlocking_requirement.rs @@ -0,0 +1,7 @@ +use crate::version::v766::enums::RecipeUnlockingContext; +use bedrockrs_macros::ProtoCodec; + +#[derive(ProtoCodec, Clone, Debug)] +pub struct RecipeUnlockingRequirement { + pub unlocking_context: RecipeUnlockingContext, +} \ No newline at end of file diff --git a/crates/proto/src/version/v766/types/shaped_chemistry_recipe.rs b/crates/proto/src/version/v766/types/shaped_chemistry_recipe.rs new file mode 100644 index 00000000..2e6a8d43 --- /dev/null +++ b/crates/proto/src/version/v766/types/shaped_chemistry_recipe.rs @@ -0,0 +1,21 @@ +use crate::version::v662::types::{NetworkItemInstanceDescriptor, RecipeIngredient}; +use bedrockrs_macros::ProtoCodec; +use uuid::Uuid; + +#[derive(ProtoCodec, Clone, Debug)] +pub struct ShapedChemistryRecipe { + pub recipe_id: String, + #[endianness(var)] + pub width: i32, + #[endianness(var)] + pub height: i32, + pub ingredient: RecipeIngredient, + #[vec_repr(u32)] + #[vec_endianness(var)] + pub result_items: Vec, + pub id: Uuid, + pub tag: String, + #[endianness(var)] + pub priority: i32, + pub assume_symmetry: bool, +} \ No newline at end of file diff --git a/crates/proto/src/version/v766/types/shaped_recipe.rs b/crates/proto/src/version/v766/types/shaped_recipe.rs new file mode 100644 index 00000000..08b0ae46 --- /dev/null +++ b/crates/proto/src/version/v766/types/shaped_recipe.rs @@ -0,0 +1,116 @@ +use crate::v766::types::RecipeUnlockingRequirement; +use crate::version::v662::types::{NetworkItemInstanceDescriptor, RecipeIngredient}; +use bedrockrs_proto_core::error::ProtoCodecError; +use bedrockrs_proto_core::{ProtoCodec, ProtoCodecVAR}; +use std::io::Cursor; +use std::mem::size_of; +use uuid::Uuid; + +#[derive(Clone, Debug)] +pub struct ShapedRecipe { + pub recipe_unique_id: String, + pub ingredient_grid: Vec>, + pub production_list: Vec, + pub recipe_id: Uuid, + pub recipe_tag: String, + pub priority: i32, + pub assume_symmetry: bool, + pub unlocking_requirement: RecipeUnlockingRequirement, +} + +impl ProtoCodec for ShapedRecipe { + fn proto_serialize(&self, stream: &mut Vec) -> Result<(), ProtoCodecError> { + self.recipe_unique_id.proto_serialize(stream)?; + + let x_len: u32 = self.ingredient_grid.len().try_into()?; + let y_len: u32 = self.ingredient_grid[0].len().try_into()?; + ::proto_serialize(&x_len, stream)?; + ::proto_serialize(&y_len, stream)?; + for y in &self.ingredient_grid { + for recipe in y { + recipe.proto_serialize(stream)?; + } + } + + ::proto_serialize(&self.production_list.len().try_into()?, stream)?; + for p in &self.production_list { + p.proto_serialize(stream)?; + } + + self.recipe_id.proto_serialize(stream)?; + self.recipe_tag.proto_serialize(stream)?; + ::proto_serialize(&self.priority, stream)?; + self.assume_symmetry.proto_serialize(stream)?; + self.unlocking_requirement.proto_serialize(stream)?; + + Ok(()) + } + + fn proto_deserialize(stream: &mut Cursor<&[u8]>) -> Result { + let recipe_unique_id = String::proto_deserialize(stream)?; + + let ingredient_grid = { + let x_len = ::proto_deserialize(stream)?; + let y_len = ::proto_deserialize(stream)?; + let mut x_vec = Vec::with_capacity(x_len.try_into()?); + for _ in 0..x_len { + let mut y_vec = Vec::with_capacity(y_len.try_into()?); + for _ in 0..y_len { + y_vec.push(RecipeIngredient::proto_deserialize(stream)?); + } + x_vec.push(y_vec); + } + x_vec + }; + + let production_list = { + let len = ::proto_deserialize(stream)?; + let mut vec = Vec::with_capacity(len.try_into()?); + for _ in 0..len { + vec.push(NetworkItemInstanceDescriptor::proto_deserialize(stream)?); + } + vec + }; + + let recipe_id = Uuid::proto_deserialize(stream)?; + let recipe_tag = String::proto_deserialize(stream)?; + let priority = ::proto_deserialize(stream)?; + let assume_symmetry = bool::proto_deserialize(stream)?; + let unlocking_requirement = RecipeUnlockingRequirement::proto_deserialize(stream)?; + + Ok(Self { + recipe_unique_id, + ingredient_grid, + production_list, + recipe_id, + recipe_tag, + priority, + assume_symmetry, + unlocking_requirement, + }) + } + + fn get_size_prediction(&self) -> usize { + self.recipe_unique_id.get_size_prediction() + + size_of::() + + size_of::() + + self + .ingredient_grid + .iter() + .map(|y| y + .iter() + .map(|i| + i.get_size_prediction()) + .sum::()) + .sum::() + + size_of::() + + self.production_list.iter().map(|y| y.get_size_prediction()).sum::() + + self.recipe_id.get_size_prediction() + + self.recipe_tag.get_size_prediction() + + self.priority.get_size_prediction() + + self.assume_symmetry.get_size_prediction() + + self.unlocking_requirement.get_size_prediction() + } +} + +// VERIFY: ProtoCodec impl \ No newline at end of file diff --git a/crates/proto/src/version/v766/types/shapeless_recipe.rs b/crates/proto/src/version/v766/types/shapeless_recipe.rs new file mode 100644 index 00000000..3bad8c30 --- /dev/null +++ b/crates/proto/src/version/v766/types/shapeless_recipe.rs @@ -0,0 +1,20 @@ +use crate::v766::types::RecipeUnlockingRequirement; +use crate::version::v662::types::{NetworkItemInstanceDescriptor, RecipeIngredient}; +use bedrockrs_macros::ProtoCodec; +use uuid::Uuid; + +#[derive(ProtoCodec, Clone, Debug)] +pub struct ShapelessRecipe { + pub recipe_unique_id: String, + #[vec_repr(u32)] + #[vec_endianness(var)] + pub ingredient_list: Vec, + #[vec_repr(u32)] + #[vec_endianness(var)] + pub production_list: Vec, + pub recipe_id: Uuid, + pub recipe_tag: String, + #[endianness(var)] + pub priority: i32, + pub unlocking_requirement: RecipeUnlockingRequirement, +} \ No newline at end of file diff --git a/crates/proto/src/version/v766/types/user_data_shapeless_recipe.rs b/crates/proto/src/version/v766/types/user_data_shapeless_recipe.rs new file mode 100644 index 00000000..fcd22478 --- /dev/null +++ b/crates/proto/src/version/v766/types/user_data_shapeless_recipe.rs @@ -0,0 +1,20 @@ +use crate::version::v662::types::{NetworkItemInstanceDescriptor, RecipeIngredient}; +use crate::version::v766::types::RecipeUnlockingRequirement; +use bedrockrs_macros::ProtoCodec; +use uuid::Uuid; + +#[derive(ProtoCodec, Clone, Debug)] +pub struct UserDataShapelessRecipe { + pub recipe_unique_id: String, + #[vec_repr(u32)] + #[vec_endianness(var)] + pub ingredient_list: Vec, + #[vec_repr(u32)] + #[vec_endianness(var)] + pub production_list: Vec, + pub recipe_id: Uuid, + pub recipe_tag: String, + #[endianness(var)] + pub priority: i32, + pub unlocking_requirement: RecipeUnlockingRequirement, +} \ No newline at end of file diff --git a/crates/proto_core/Cargo.toml b/crates/proto_core/Cargo.toml index 9bd16cb0..6d91dc93 100644 --- a/crates/proto_core/Cargo.toml +++ b/crates/proto_core/Cargo.toml @@ -4,15 +4,21 @@ version = "0.1.0" edition = "2021" [dependencies] -bedrockrs_core = { path = "../core" } -bedrockrs_proto_macros = { path = "../proto_macros" } +bedrockrs_macros = { path = "../macros" } nbtx = { git = "https://github.com/bedrock-crustaceans/nbtx" } -xuid = "1.0.0" +xuid = "1.0" + +paste = "1.0" +seq-macro = "0.3" + +byteorder = "1.5" +varint-rs = "2.2" + +vek = "0.17" +thiserror = "2.0" -thiserror = "1.0" serde_json = "1.0" jsonwebtoken = "9.3" base64 = "0.22" -byteorder = "1.5" -uuid = { version = "1.10", features = ["v4"] } +uuid = { version = "1.11", features = ["v4"] } diff --git a/crates/proto_core/src/endian.rs b/crates/proto_core/src/endian.rs new file mode 100644 index 00000000..fabace12 --- /dev/null +++ b/crates/proto_core/src/endian.rs @@ -0,0 +1,26 @@ +use crate::error::ProtoCodecError; +use std::io::Cursor; + +pub trait ProtoCodecLE: Sized { + fn proto_serialize(&self, stream: &mut Vec) -> Result<(), ProtoCodecError>; + + fn proto_deserialize(stream: &mut Cursor<&[u8]>) -> Result; + + fn get_size_prediction(&self) -> usize; +} + +pub trait ProtoCodecBE: Sized { + fn proto_serialize(&self, stream: &mut Vec) -> Result<(), ProtoCodecError>; + + fn proto_deserialize(stream: &mut Cursor<&[u8]>) -> Result; + + fn get_size_prediction(&self) -> usize; +} + +pub trait ProtoCodecVAR: Sized { + fn proto_serialize(&self, stream: &mut Vec) -> Result<(), ProtoCodecError>; + + fn proto_deserialize(stream: &mut Cursor<&[u8]>) -> Result; + + fn get_size_prediction(&self) -> usize; +} diff --git a/crates/proto_core/src/error.rs b/crates/proto_core/src/error.rs index 70fcb7b3..c693bf2d 100644 --- a/crates/proto_core/src/error.rs +++ b/crates/proto_core/src/error.rs @@ -1,18 +1,22 @@ +use std::convert::Infallible; +use std::error::Error; use std::io::Error as IOError; use std::num::{ParseIntError, TryFromIntError}; use std::string::FromUtf8Error; -use std::sync::Arc; use base64::DecodeError as Base64DecodeError; use jsonwebtoken::errors::Error as JwtError; use nbtx::NbtError; use serde_json::error::Error as JsonError; use thiserror::Error; +use uuid::Error as UuidError; -#[derive(Error, Debug, Clone)] +#[derive(Error, Debug)] pub enum ProtoCodecError { #[error("IOError occurred: {0}")] - IOError(#[from] Arc), + IOError(#[from] IOError), + #[error("Unread bytes remaining: {0} bytes left")] + LeftOvers(usize), #[error("NbtError: {0}")] NbtError(#[from] NbtError), #[error("Error while reading UTF8 encoded String: {0}")] @@ -20,23 +24,48 @@ pub enum ProtoCodecError { #[error("Error while converting integers: {0}")] FromIntError(#[from] TryFromIntError), #[error("Json Error: {0}")] - JsonError(#[from] Arc), + JsonError(#[from] JsonError), #[error("Jwt Error: {0}")] JwtError(#[from] JwtError), + #[error("Uuid Error: {0}")] + UuidError(#[from] UuidError), #[error("Base64 decoding Error: {0}")] Base64DecodeError(#[from] Base64DecodeError), #[error("XUID could not be parsed : {0}")] - XuidParseError(ParseIntError), + XuidParseError(#[from] ParseIntError), + /// TODO: This likely hurts performance, but it is *kinda* good for debugging #[error("parse value `{0}` to enum variant for {1} enum")] - InvalidEnumID(String, String), + InvalidEnumID(String, &'static str), #[error("Got an unknown/invalid game packet id: {0}")] InvalidGamePacketID(u16), #[error("Expected format got mismatched: {0}")] - FormatMismatch(String), + FormatMismatch(&'static str), + #[error("Compression Error: {0}")] + CompressError(#[from] CompressionError), + #[error("Encryption Error: {0}")] + EncryptionError(#[from] EncryptionError), } -impl From for ProtoCodecError { - fn from(value: IOError) -> Self { - ProtoCodecError::IOError(Arc::new(value)) +impl From for ProtoCodecError { + fn from(_: Infallible) -> Self { + unreachable!() } } + +#[derive(Error, Debug)] +pub enum CompressionError { + #[error("Zlib Error: {0}")] + ZlibError(#[from] Box), + #[error("Snappy Error: {0}")] + SnappyError(#[from] IOError), + #[error("Unknown Compression Method: {0}")] + UnknownCompressionMethod(u8), + #[error("IO Error: {0}")] + IOError(IOError), +} + +#[derive(Error, Debug)] +pub enum EncryptionError { + #[error("IO Error: {0}")] + IOError(IOError), +} diff --git a/crates/proto_core/src/lib.rs b/crates/proto_core/src/lib.rs index bf3f0cf0..d45201af 100644 --- a/crates/proto_core/src/lib.rs +++ b/crates/proto_core/src/lib.rs @@ -4,13 +4,20 @@ use std::io::Cursor; use crate::error::ProtoCodecError; +mod endian; +use crate::sub_client::SubClientID; +pub use endian::*; + pub mod error; +pub mod sub_client; pub mod types; pub trait ProtoCodec: Sized { - fn proto_serialize(&self, buf: &mut Vec) -> Result<(), ProtoCodecError>; + fn proto_serialize(&self, stream: &mut Vec) -> Result<(), ProtoCodecError>; + + fn proto_deserialize(stream: &mut Cursor<&[u8]>) -> Result; - fn proto_deserialize(buf: &mut Cursor<&[u8]>) -> Result; + fn get_size_prediction(&self) -> usize; } pub trait GamePacket: Sized + ProtoCodec { @@ -19,12 +26,24 @@ pub trait GamePacket: Sized + ProtoCodec { const ENCRYPT: bool; #[inline] - fn serialize(&self, buf: &mut Vec) -> Result<(), ProtoCodecError> { - self.proto_serialize(buf) + fn get_size_prediction(&self) -> usize { + ::get_size_prediction(self) } +} - #[inline] - fn deserialize(buf: &mut Cursor<&[u8]>) -> Result { - Self::proto_deserialize(buf) - } +pub trait GamePacketsAll: Sized { + fn compress(&self) -> bool; + fn encrypt(&self) -> bool; + + fn pk_serialize( + &self, + stream: &mut Vec, + subclient_sender_id: SubClientID, + subclient_target_id: SubClientID, + ) -> Result<(), ProtoCodecError>; + fn pk_deserialize( + stream: &mut Cursor<&[u8]>, + ) -> Result<(Self, SubClientID, SubClientID), ProtoCodecError>; + + fn get_size_prediction(&self) -> usize; } diff --git a/crates/proto_core/src/mod.rs b/crates/proto_core/src/mod.rs deleted file mode 100644 index 4d38d274..00000000 --- a/crates/proto_core/src/mod.rs +++ /dev/null @@ -1,3 +0,0 @@ -pub mod de; -pub mod ser; -pub mod int; diff --git a/crates/proto_core/src/sub_client.rs b/crates/proto_core/src/sub_client.rs new file mode 100644 index 00000000..84f7816a --- /dev/null +++ b/crates/proto_core/src/sub_client.rs @@ -0,0 +1,52 @@ +use crate::error::ProtoCodecError; + +#[derive(Debug, Clone)] +pub enum SubClientID { + PrimaryClient, + Client2, + Client3, + Client4, +} + +macro_rules! impl_sub_client { + ($int:ty) => { + impl TryFrom<$int> for SubClientID { + type Error = ProtoCodecError; + + fn try_from(value: $int) -> Result { + match value { + 0 => Ok(SubClientID::PrimaryClient), + 1 => Ok(SubClientID::Client2), + 2 => Ok(SubClientID::Client3), + 3 => Ok(SubClientID::Client4), + other => Err(ProtoCodecError::InvalidEnumID( + format!("{other:?}"), + "SubClientID", + )), + } + } + } + + impl From for $int { + fn from(value: SubClientID) -> Self { + match value { + SubClientID::PrimaryClient => 0, + SubClientID::Client2 => 1, + SubClientID::Client3 => 2, + SubClientID::Client4 => 3, + } + } + } + }; +} + +impl_sub_client!(u8); +impl_sub_client!(i8); +impl_sub_client!(u16); +impl_sub_client!(i16); +impl_sub_client!(u32); +impl_sub_client!(i32); +impl_sub_client!(u64); +impl_sub_client!(i64); +impl_sub_client!(u128); +impl_sub_client!(i128); diff --git a/crates/proto_core/src/types/bool.rs b/crates/proto_core/src/types/bool.rs index 1cad894c..095fa991 100644 --- a/crates/proto_core/src/types/bool.rs +++ b/crates/proto_core/src/types/bool.rs @@ -1,41 +1,31 @@ +use byteorder::{ReadBytesExt, WriteBytesExt}; use std::io::Cursor; -use std::sync::Arc; - -use bedrockrs_core::int::LE; +use std::mem::size_of; use crate::error::ProtoCodecError; use crate::ProtoCodec; impl ProtoCodec for bool { - fn proto_serialize(&self, buf: &mut Vec) -> Result<(), ProtoCodecError> + fn proto_serialize(&self, stream: &mut Vec) -> Result<(), ProtoCodecError> where Self: Sized, { match self { - true => LE::::new(1) - .write(buf) - .map_err(|e| ProtoCodecError::IOError(Arc::new(e))), - false => LE::::new(0) - .write(buf) - .map_err(|e| ProtoCodecError::IOError(Arc::new(e))), - } + true => stream.write_u8(1)?, + false => stream.write_u8(0)?, + }; + + Ok(()) } fn proto_deserialize(stream: &mut Cursor<&[u8]>) -> Result where Self: Sized, { - // a Bool is represented as a byte - Ok( - match LE::::read(stream) - .map_err(|e| ProtoCodecError::IOError(Arc::new(e)))? - .into_inner() - { - // 0 is counted as false - 0 => false, - // Anything above 0 is true - _ => true, - }, - ) + Ok(!matches!(stream.read_u8()?, 0)) + } + + fn get_size_prediction(&self) -> usize { + size_of::() } } diff --git a/crates/proto_core/src/types/int.rs b/crates/proto_core/src/types/int.rs index 85f89bbf..407166ec 100644 --- a/crates/proto_core/src/types/int.rs +++ b/crates/proto_core/src/types/int.rs @@ -1,82 +1,128 @@ -use std::io::Cursor; -use std::sync::Arc; - -use bedrockrs_core::int::{BE, LE, VAR}; -use byteorder::{ReadBytesExt, WriteBytesExt}; - +use crate::endian::{ProtoCodecBE, ProtoCodecLE, ProtoCodecVAR}; use crate::error::ProtoCodecError; use crate::ProtoCodec; +use byteorder::{BigEndian, LittleEndian, ReadBytesExt, WriteBytesExt}; +use paste::paste; +use std::io::Cursor; +use std::mem::size_of; +use varint_rs::VarintReader; +use varint_rs::VarintWriter; impl ProtoCodec for u8 { fn proto_serialize(&self, stream: &mut Vec) -> Result<(), ProtoCodecError> { - stream - .write_u8(*self) - .map_err(|e| ProtoCodecError::IOError(Arc::new(e))) + Ok(stream.write_u8(*self)?) } fn proto_deserialize(stream: &mut Cursor<&[u8]>) -> Result { - stream - .read_u8() - .map_err(|e| ProtoCodecError::IOError(Arc::new(e))) + Ok(stream.read_u8()?) + } + + fn get_size_prediction(&self) -> usize { + size_of::() } } impl ProtoCodec for i8 { fn proto_serialize(&self, stream: &mut Vec) -> Result<(), ProtoCodecError> { - stream - .write_i8(*self) - .map_err(|e| ProtoCodecError::IOError(Arc::new(e))) + Ok(stream.write_i8(*self)?) } fn proto_deserialize(stream: &mut Cursor<&[u8]>) -> Result { - stream - .read_i8() - .map_err(|e| ProtoCodecError::IOError(Arc::new(e))) + Ok(stream.read_i8()?) } + + fn get_size_prediction(&self) -> usize { + size_of::() + } +} + +macro_rules! impl_proto_codec_le { + ($int:ident) => { + paste! { + impl ProtoCodecLE for $int { + fn proto_serialize(&self, stream: &mut Vec) -> Result<(), ProtoCodecError> { + Ok(WriteBytesExt::[]::(stream, *self)?) + } + + fn proto_deserialize(stream: &mut Cursor<&[u8]>) -> Result { + Ok(ReadBytesExt::[]::(stream)?) + } + + fn get_size_prediction(&self) -> usize { + size_of::<$int>() + } + } + } + }; } -macro_rules! impl_proto_codec { - ($wrapper:ident, $int:ty) => { - impl ProtoCodec for $wrapper<$int> { - fn proto_serialize(&self, stream: &mut Vec) -> Result<(), ProtoCodecError> { - $wrapper::<$int>::write(self, stream) - .map_err(|e| ProtoCodecError::IOError(Arc::new(e))) +macro_rules! impl_proto_codec_be { + ($int:ident) => { + paste! { + impl ProtoCodecBE for $int { + fn proto_serialize(&self, stream: &mut Vec) -> Result<(), ProtoCodecError> { + Ok(WriteBytesExt::[]::(stream, *self)?) + } + + fn proto_deserialize(stream: &mut Cursor<&[u8]>) -> Result { + Ok(ReadBytesExt::[]::(stream)?) + } + + fn get_size_prediction(&self) -> usize { + size_of::<$int>() + } } + } + }; +} + +macro_rules! impl_proto_codec_var { + ($int:ident) => { + paste! { + impl ProtoCodecVAR for $int { + fn proto_serialize(&self, stream: &mut Vec) -> Result<(), ProtoCodecError> { + Ok(VarintWriter::[](stream, *self)?) + } - fn proto_deserialize(stream: &mut Cursor<&[u8]>) -> Result { - $wrapper::<$int>::read(stream).map_err(|e| ProtoCodecError::IOError(Arc::new(e))) + fn proto_deserialize(stream: &mut Cursor<&[u8]>) -> Result { + Ok(VarintReader::[](stream)?) + } + + fn get_size_prediction(&self) -> usize { + size_of::<$int>() + } } } }; } -impl_proto_codec!(LE, u16); -impl_proto_codec!(LE, i16); -impl_proto_codec!(LE, u32); -impl_proto_codec!(LE, i32); -impl_proto_codec!(LE, u64); -impl_proto_codec!(LE, i64); -impl_proto_codec!(LE, u128); -impl_proto_codec!(LE, i128); -impl_proto_codec!(LE, f32); -impl_proto_codec!(LE, f64); - -impl_proto_codec!(BE, u16); -impl_proto_codec!(BE, i16); -impl_proto_codec!(BE, u32); -impl_proto_codec!(BE, i32); -impl_proto_codec!(BE, u64); -impl_proto_codec!(BE, i64); -impl_proto_codec!(BE, u128); -impl_proto_codec!(BE, i128); -impl_proto_codec!(BE, f32); -impl_proto_codec!(BE, f64); - -impl_proto_codec!(VAR, u16); -impl_proto_codec!(VAR, i16); -impl_proto_codec!(VAR, u32); -impl_proto_codec!(VAR, i32); -impl_proto_codec!(VAR, u64); -impl_proto_codec!(VAR, i64); -impl_proto_codec!(VAR, u128); -impl_proto_codec!(VAR, i128); +impl_proto_codec_le!(u16); +impl_proto_codec_le!(i16); +impl_proto_codec_le!(u32); +impl_proto_codec_le!(i32); +impl_proto_codec_le!(u64); +impl_proto_codec_le!(i64); +impl_proto_codec_le!(u128); +impl_proto_codec_le!(i128); +impl_proto_codec_le!(f32); +impl_proto_codec_le!(f64); + +impl_proto_codec_be!(u16); +impl_proto_codec_be!(i16); +impl_proto_codec_be!(u32); +impl_proto_codec_be!(i32); +impl_proto_codec_be!(u64); +impl_proto_codec_be!(i64); +impl_proto_codec_be!(u128); +impl_proto_codec_be!(i128); +impl_proto_codec_be!(f32); +impl_proto_codec_be!(f64); + +impl_proto_codec_var!(u16); +impl_proto_codec_var!(i16); +impl_proto_codec_var!(u32); +impl_proto_codec_var!(i32); +impl_proto_codec_var!(u64); +impl_proto_codec_var!(i64); +impl_proto_codec_var!(u128); +impl_proto_codec_var!(i128); diff --git a/crates/proto_core/src/types/mod.rs b/crates/proto_core/src/types/mod.rs index a52e280a..7187327e 100644 --- a/crates/proto_core/src/types/mod.rs +++ b/crates/proto_core/src/types/mod.rs @@ -1,8 +1,9 @@ pub mod bool; pub mod int; -pub mod nbt_tag; pub mod option; +pub mod slice; pub mod string; +pub mod tuple; pub mod uuid; pub mod vec; pub mod xuid; diff --git a/crates/proto_core/src/types/nbt_tag.rs b/crates/proto_core/src/types/nbt_tag.rs deleted file mode 100644 index c9d864a6..00000000 --- a/crates/proto_core/src/types/nbt_tag.rs +++ /dev/null @@ -1,16 +0,0 @@ -use std::io::Cursor; - -use crate::error::ProtoCodecError; -use crate::ProtoCodec; - -impl ProtoCodec for nbtx::Value { - fn proto_serialize(&self, stream: &mut Vec) -> Result<(), ProtoCodecError> { - nbtx::to_net_bytes_in(stream, self)?; - Ok(()) - } - - fn proto_deserialize(cursor: &mut Cursor<&[u8]>) -> Result { - let nbt = nbtx::from_net_bytes::(cursor)?; - Ok(nbt) - } -} diff --git a/crates/proto_core/src/types/option.rs b/crates/proto_core/src/types/option.rs index fe8c3c2e..22eaf03a 100644 --- a/crates/proto_core/src/types/option.rs +++ b/crates/proto_core/src/types/option.rs @@ -1,31 +1,48 @@ -use std::io::Cursor; - +use crate::endian::{ProtoCodecBE, ProtoCodecLE, ProtoCodecVAR}; use crate::error::ProtoCodecError; use crate::ProtoCodec; +use std::io::Cursor; +use std::mem::size_of; + +macro_rules! impl_proto_option { + ($name:ident) => { + impl $name for Option { + fn proto_serialize(&self, buf: &mut Vec) -> Result<(), ProtoCodecError> + where + Self: Sized, + { + match self { + Some(v) => { + bool::proto_serialize(&true, buf)?; + T::proto_serialize(&v, buf)?; + } + None => bool::proto_serialize(&false, buf)?, + } -impl ProtoCodec for Option { - fn proto_serialize(&self, buf: &mut Vec) -> Result<(), ProtoCodecError> - where - Self: Sized, - { - match self { - None => false.proto_serialize(buf)?, - Some(v) => { - true.proto_serialize(buf)?; - v.proto_serialize(buf)?; + Ok(()) } - }; - Ok(()) - } + fn proto_deserialize(stream: &mut Cursor<&[u8]>) -> Result + where + Self: Sized, + { + Ok(match bool::proto_deserialize(stream)? { + false => None, + true => Some(T::proto_deserialize(stream)?), + }) + } - fn proto_deserialize(stream: &mut Cursor<&[u8]>) -> Result - where - Self: Sized, - { - Ok(match bool::proto_deserialize(stream)? { - false => None, - true => Some(T::proto_deserialize(stream)?), - }) - } + fn get_size_prediction(&self) -> usize { + match self { + Some(v) => T::get_size_prediction(v) + size_of::(), + None => size_of::(), + } + } + } + }; } + +impl_proto_option!(ProtoCodec); +impl_proto_option!(ProtoCodecLE); +impl_proto_option!(ProtoCodecBE); +impl_proto_option!(ProtoCodecVAR); diff --git a/crates/proto_core/src/types/slice.rs b/crates/proto_core/src/types/slice.rs new file mode 100644 index 00000000..3661f21a --- /dev/null +++ b/crates/proto_core/src/types/slice.rs @@ -0,0 +1,104 @@ +use crate::endian::{ProtoCodecBE, ProtoCodecLE, ProtoCodecVAR}; +use crate::error::ProtoCodecError; +use crate::ProtoCodec; +use seq_macro::seq; +use std::io::Cursor; + +macro_rules! impl_proto_slice { + ($name:ident, 0) => { + impl $name for [T; 0] { + fn proto_serialize(&self, _stream: &mut Vec) -> Result<(), ProtoCodecError> { + Ok(()) + } + + fn proto_deserialize(_stream: &mut Cursor<&[u8]>) -> Result { + Ok([]) + } + + fn get_size_prediction(&self) -> usize { + 0 + } + } + }; + ($name:ident, $size:literal) => { + impl $name for [T; $size] { + fn proto_serialize(&self, stream: &mut Vec) -> Result<(), ProtoCodecError> { + seq!(N in 0..$size { + self[N].proto_serialize(stream)?; + }); + + Ok(()) + } + + fn proto_deserialize(stream: &mut Cursor<&[u8]>) -> Result { + seq!(N in 0..$size { + let buf = [ + #( T::proto_deserialize(stream)?, )* + ]; + }); + + Ok(buf) + } + + fn get_size_prediction(&self) -> usize { + self[0].get_size_prediction() * $size + } + } + }; +} + +impl_proto_slice!(ProtoCodec, 0); +impl_proto_slice!(ProtoCodec, 1); +impl_proto_slice!(ProtoCodec, 2); +impl_proto_slice!(ProtoCodec, 3); +impl_proto_slice!(ProtoCodec, 4); +impl_proto_slice!(ProtoCodec, 5); +impl_proto_slice!(ProtoCodec, 6); +impl_proto_slice!(ProtoCodec, 7); +impl_proto_slice!(ProtoCodec, 8); +impl_proto_slice!(ProtoCodec, 9); +impl_proto_slice!(ProtoCodec, 10); +impl_proto_slice!(ProtoCodec, 11); +impl_proto_slice!(ProtoCodec, 12); + +impl_proto_slice!(ProtoCodecLE, 0); +impl_proto_slice!(ProtoCodecLE, 1); +impl_proto_slice!(ProtoCodecLE, 2); +impl_proto_slice!(ProtoCodecLE, 3); +impl_proto_slice!(ProtoCodecLE, 4); +impl_proto_slice!(ProtoCodecLE, 5); +impl_proto_slice!(ProtoCodecLE, 6); +impl_proto_slice!(ProtoCodecLE, 7); +impl_proto_slice!(ProtoCodecLE, 8); +impl_proto_slice!(ProtoCodecLE, 9); +impl_proto_slice!(ProtoCodecLE, 10); +impl_proto_slice!(ProtoCodecLE, 11); +impl_proto_slice!(ProtoCodecLE, 12); + +impl_proto_slice!(ProtoCodecBE, 0); +impl_proto_slice!(ProtoCodecBE, 1); +impl_proto_slice!(ProtoCodecBE, 2); +impl_proto_slice!(ProtoCodecBE, 3); +impl_proto_slice!(ProtoCodecBE, 4); +impl_proto_slice!(ProtoCodecBE, 5); +impl_proto_slice!(ProtoCodecBE, 6); +impl_proto_slice!(ProtoCodecBE, 7); +impl_proto_slice!(ProtoCodecBE, 8); +impl_proto_slice!(ProtoCodecBE, 9); +impl_proto_slice!(ProtoCodecBE, 10); +impl_proto_slice!(ProtoCodecBE, 11); +impl_proto_slice!(ProtoCodecBE, 12); + +impl_proto_slice!(ProtoCodecVAR, 0); +impl_proto_slice!(ProtoCodecVAR, 1); +impl_proto_slice!(ProtoCodecVAR, 2); +impl_proto_slice!(ProtoCodecVAR, 3); +impl_proto_slice!(ProtoCodecVAR, 4); +impl_proto_slice!(ProtoCodecVAR, 5); +impl_proto_slice!(ProtoCodecVAR, 6); +impl_proto_slice!(ProtoCodecVAR, 7); +impl_proto_slice!(ProtoCodecVAR, 8); +impl_proto_slice!(ProtoCodecVAR, 9); +impl_proto_slice!(ProtoCodecVAR, 10); +impl_proto_slice!(ProtoCodecVAR, 11); +impl_proto_slice!(ProtoCodecVAR, 12); diff --git a/crates/proto_core/src/types/string.rs b/crates/proto_core/src/types/string.rs index de6090a2..a69a3f57 100644 --- a/crates/proto_core/src/types/string.rs +++ b/crates/proto_core/src/types/string.rs @@ -1,8 +1,6 @@ use std::convert::TryInto; use std::io::{Cursor, Read, Write}; -use std::sync::Arc; - -use bedrockrs_core::int::VAR; +use varint_rs::{VarintReader, VarintWriter}; use crate::error::ProtoCodecError; use crate::ProtoCodec; @@ -12,15 +10,10 @@ impl ProtoCodec for String { where Self: Sized, { - let len = self - .len() - .try_into() - .map_err(|e| ProtoCodecError::FromIntError(e))?; - - VAR::::new(len).proto_serialize(buf)?; + let len = self.len().try_into()?; - buf.write_all(self.as_bytes()) - .map_err(|e| ProtoCodecError::IOError(Arc::new(e)))?; + buf.write_u32_varint(len)?; + buf.write_all(self.as_bytes())?; Ok(()) } @@ -29,16 +22,16 @@ impl ProtoCodec for String { where Self: Sized, { - let len = VAR::::proto_deserialize(stream)?.into_inner(); - let len = len - .try_into() - .map_err(|e| ProtoCodecError::FromIntError(e))?; + let len = stream.read_u32_varint()?.try_into()?; let mut string_buf = vec![0u8; len]; + stream.read_exact(&mut string_buf)?; + + Ok(String::from_utf8(string_buf)?) + } - stream - .read_exact(&mut *string_buf) - .map_err(|e| ProtoCodecError::IOError(Arc::new(e)))?; - String::from_utf8(string_buf).map_err(|e| ProtoCodecError::UTF8Error(e)) + fn get_size_prediction(&self) -> usize { + // 4 = u32 String size + self.len() + 4 } } diff --git a/crates/proto_core/src/types/tuple.rs b/crates/proto_core/src/types/tuple.rs new file mode 100644 index 00000000..c5c9565e --- /dev/null +++ b/crates/proto_core/src/types/tuple.rs @@ -0,0 +1,104 @@ +use crate::endian::{ProtoCodecBE, ProtoCodecLE, ProtoCodecVAR}; +use crate::error::ProtoCodecError; +use crate::ProtoCodec; +use seq_macro::seq; +use std::io::Cursor; + +macro_rules! impl_proto_tuple { + ($name:ident, 0) => { + impl $name for () { + fn proto_serialize(&self, _stream: &mut Vec) -> Result<(), ProtoCodecError> { + Ok(()) + } + + fn proto_deserialize(_stream: &mut Cursor<&[u8]>) -> Result { + Ok(()) + } + + fn get_size_prediction(&self) -> usize { + 0 + } + } + }; + ($name:ident, $size:literal) => { + impl $name for seq!(N in 0..$size { ( #(T, )* ) }) { + fn proto_serialize(&self, stream: &mut Vec) -> Result<(), ProtoCodecError> { + seq!(N in 0..$size { + self.N.proto_serialize(stream)?; + }); + + Ok(()) + } + + fn proto_deserialize(stream: &mut Cursor<&[u8]>) -> Result { + seq!(N in 0..$size { + let tuple = ( + #( T::proto_deserialize(stream)?, )* + ); + }); + + Ok(tuple) + } + + fn get_size_prediction(&self) -> usize { + self.0.get_size_prediction() * $size + } + } + }; +} + +impl_proto_tuple!(ProtoCodec, 0); +impl_proto_tuple!(ProtoCodec, 1); +impl_proto_tuple!(ProtoCodec, 2); +impl_proto_tuple!(ProtoCodec, 3); +impl_proto_tuple!(ProtoCodec, 4); +impl_proto_tuple!(ProtoCodec, 5); +impl_proto_tuple!(ProtoCodec, 6); +impl_proto_tuple!(ProtoCodec, 7); +impl_proto_tuple!(ProtoCodec, 8); +impl_proto_tuple!(ProtoCodec, 9); +impl_proto_tuple!(ProtoCodec, 10); +impl_proto_tuple!(ProtoCodec, 11); +impl_proto_tuple!(ProtoCodec, 12); + +impl_proto_tuple!(ProtoCodecLE, 0); +impl_proto_tuple!(ProtoCodecLE, 1); +impl_proto_tuple!(ProtoCodecLE, 2); +impl_proto_tuple!(ProtoCodecLE, 3); +impl_proto_tuple!(ProtoCodecLE, 4); +impl_proto_tuple!(ProtoCodecLE, 5); +impl_proto_tuple!(ProtoCodecLE, 6); +impl_proto_tuple!(ProtoCodecLE, 7); +impl_proto_tuple!(ProtoCodecLE, 8); +impl_proto_tuple!(ProtoCodecLE, 9); +impl_proto_tuple!(ProtoCodecLE, 10); +impl_proto_tuple!(ProtoCodecLE, 11); +impl_proto_tuple!(ProtoCodecLE, 12); + +impl_proto_tuple!(ProtoCodecBE, 0); +impl_proto_tuple!(ProtoCodecBE, 1); +impl_proto_tuple!(ProtoCodecBE, 2); +impl_proto_tuple!(ProtoCodecBE, 3); +impl_proto_tuple!(ProtoCodecBE, 4); +impl_proto_tuple!(ProtoCodecBE, 5); +impl_proto_tuple!(ProtoCodecBE, 6); +impl_proto_tuple!(ProtoCodecBE, 7); +impl_proto_tuple!(ProtoCodecBE, 8); +impl_proto_tuple!(ProtoCodecBE, 9); +impl_proto_tuple!(ProtoCodecBE, 10); +impl_proto_tuple!(ProtoCodecBE, 11); +impl_proto_tuple!(ProtoCodecBE, 12); + +impl_proto_tuple!(ProtoCodecVAR, 0); +impl_proto_tuple!(ProtoCodecVAR, 1); +impl_proto_tuple!(ProtoCodecVAR, 2); +impl_proto_tuple!(ProtoCodecVAR, 3); +impl_proto_tuple!(ProtoCodecVAR, 4); +impl_proto_tuple!(ProtoCodecVAR, 5); +impl_proto_tuple!(ProtoCodecVAR, 6); +impl_proto_tuple!(ProtoCodecVAR, 7); +impl_proto_tuple!(ProtoCodecVAR, 8); +impl_proto_tuple!(ProtoCodecVAR, 9); +impl_proto_tuple!(ProtoCodecVAR, 10); +impl_proto_tuple!(ProtoCodecVAR, 11); +impl_proto_tuple!(ProtoCodecVAR, 12); diff --git a/crates/proto_core/src/types/uuid.rs b/crates/proto_core/src/types/uuid.rs index 4043692f..80b4b501 100644 --- a/crates/proto_core/src/types/uuid.rs +++ b/crates/proto_core/src/types/uuid.rs @@ -1,25 +1,28 @@ -use std::io::Cursor; - -use bedrockrs_core::int::LE; -use uuid::Uuid; - use crate::error::ProtoCodecError; use crate::ProtoCodec; +use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; +use std::io::Cursor; +use std::mem::size_of; +use uuid::Uuid; impl ProtoCodec for Uuid { fn proto_serialize(&self, stream: &mut Vec) -> Result<(), ProtoCodecError> { - let pair = self.as_u64_pair(); + let (upper, lower) = self.as_u64_pair(); - LE::::new(pair.0).proto_serialize(stream)?; - LE::::new(pair.1).proto_serialize(stream)?; + stream.write_u64::(upper)?; + stream.write_u64::(lower)?; Ok(()) } fn proto_deserialize(stream: &mut Cursor<&[u8]>) -> Result { - let first = LE::::proto_deserialize(stream)?.into_inner(); - let second = LE::::proto_deserialize(stream)?.into_inner(); + Ok(Uuid::from_u64_pair( + stream.read_u64::()?, + stream.read_u64::()?, + )) + } - Ok(Uuid::from_u64_pair(first, second)) + fn get_size_prediction(&self) -> usize { + size_of::() + size_of::() } } diff --git a/crates/proto_core/src/types/vec.rs b/crates/proto_core/src/types/vec.rs index b8b3d576..bafae35c 100644 --- a/crates/proto_core/src/types/vec.rs +++ b/crates/proto_core/src/types/vec.rs @@ -1,52 +1,78 @@ use std::io::Cursor; -use bedrockrs_core::{Vec2, Vec3}; - +use crate::endian::{ProtoCodecBE, ProtoCodecLE, ProtoCodecVAR}; use crate::error::ProtoCodecError; use crate::ProtoCodec; +use vek::{Vec2, Vec3}; + +macro_rules! impl_proto_vec2 { + ($name:ident) => { + impl $name for Vec2 { + fn proto_serialize(&self, stream: &mut Vec) -> Result<(), ProtoCodecError> + where + Self: Sized, + { + T::proto_serialize(&self.x, stream)?; + T::proto_serialize(&self.y, stream)?; + + Ok(()) + } -impl ProtoCodec for Vec2 { - fn proto_serialize(&self, stream: &mut Vec) -> Result<(), ProtoCodecError> - where - Self: Sized, - { - T::proto_serialize(&self.x, stream)?; - T::proto_serialize(&self.y, stream)?; - - Ok(()) - } - - fn proto_deserialize(stream: &mut Cursor<&[u8]>) -> Result - where - Self: Sized, - { - Ok(Self { - x: T::proto_deserialize(stream)?, - y: T::proto_deserialize(stream)?, - }) - } + fn proto_deserialize(stream: &mut Cursor<&[u8]>) -> Result + where + Self: Sized, + { + Ok(Self { + x: T::proto_deserialize(stream)?, + y: T::proto_deserialize(stream)?, + }) + } + + fn get_size_prediction(&self) -> usize { + self.x.get_size_prediction() * 2 + } + } + }; } -impl ProtoCodec for Vec3 { - fn proto_serialize(&self, stream: &mut Vec) -> Result<(), ProtoCodecError> - where - Self: Sized, - { - T::proto_serialize(&self.x, stream)?; - T::proto_serialize(&self.y, stream)?; - T::proto_serialize(&self.z, stream)?; - - Ok(()) - } - - fn proto_deserialize(stream: &mut Cursor<&[u8]>) -> Result - where - Self: Sized, - { - Ok(Self { - x: T::proto_deserialize(stream)?, - y: T::proto_deserialize(stream)?, - z: T::proto_deserialize(stream)?, - }) - } +macro_rules! impl_proto_vec3 { + ($name:ident) => { + impl $name for Vec3 { + fn proto_serialize(&self, stream: &mut Vec) -> Result<(), ProtoCodecError> + where + Self: Sized, + { + T::proto_serialize(&self.x, stream)?; + T::proto_serialize(&self.y, stream)?; + T::proto_serialize(&self.z, stream)?; + + Ok(()) + } + + fn proto_deserialize(stream: &mut Cursor<&[u8]>) -> Result + where + Self: Sized, + { + Ok(Self { + x: T::proto_deserialize(stream)?, + y: T::proto_deserialize(stream)?, + z: T::proto_deserialize(stream)?, + }) + } + + fn get_size_prediction(&self) -> usize { + self.x.get_size_prediction() * 3 + } + } + }; } + +impl_proto_vec2!(ProtoCodec); +impl_proto_vec2!(ProtoCodecLE); +impl_proto_vec2!(ProtoCodecBE); +impl_proto_vec2!(ProtoCodecVAR); + +impl_proto_vec3!(ProtoCodec); +impl_proto_vec3!(ProtoCodecLE); +impl_proto_vec3!(ProtoCodecBE); +impl_proto_vec3!(ProtoCodecVAR); diff --git a/crates/proto_core/src/types/xuid.rs b/crates/proto_core/src/types/xuid.rs index 4265c8b2..c5dad258 100644 --- a/crates/proto_core/src/types/xuid.rs +++ b/crates/proto_core/src/types/xuid.rs @@ -1,7 +1,8 @@ -use std::io::Cursor; -use xuid::Xuid; use crate::error::ProtoCodecError; use crate::ProtoCodec; +use std::io::Cursor; +use std::mem::size_of; +use xuid::Xuid; impl ProtoCodec for Xuid { fn proto_serialize(&self, buf: &mut Vec) -> Result<(), ProtoCodecError> { @@ -10,6 +11,11 @@ impl ProtoCodec for Xuid { } fn proto_deserialize(buf: &mut Cursor<&[u8]>) -> Result { - Xuid::try_from(String::proto_deserialize(buf)?).map_err(ProtoCodecError::XuidParseError) + Ok(Xuid::try_from(String::proto_deserialize(buf)?)?) + } + + fn get_size_prediction(&self) -> usize { + // 20 = u64::MAX as String + size_of::() + 20 } -} \ No newline at end of file +} diff --git a/crates/proto_macros/src/de.rs b/crates/proto_macros/src/de.rs deleted file mode 100644 index cf89dcc9..00000000 --- a/crates/proto_macros/src/de.rs +++ /dev/null @@ -1,175 +0,0 @@ -use proc_macro2::{Ident, TokenStream}; -use quote::quote; -use syn::{Attribute, DataEnum, DataStruct, Expr, Fields, Index}; - -pub fn proto_build_de_struct(struct_data: &DataStruct) -> TokenStream { - let fields = &struct_data.fields; - - let expand = match fields { - Fields::Named(ref fields) => { - let calls = fields.named.iter().map(|f| { - let field_name = f.ident.clone(); - - let mut quote = None; - - for attr in &f.attrs { - if attr.path().is_ident("len_repr") { - let int_type: Expr = attr - .parse_args() - .unwrap_or_else(|_| panic!("Given attribute meta for field {field_name:?} could not be parsed")); - - quote = Some(quote! { - #field_name: { - let len = match #int_type::read(stream) { - Ok(v) => { v.into_inner() }, - Err(e) => { return Err(::bedrockrs_proto_core::error::ProtoCodecError::IOError(std::sync::Arc::new(e))) } - }; - - let mut vec = Vec::with_capacity(match len.try_into() { - Ok(v) => { v }, - Err(e) => { return Err(::bedrockrs_proto_core::error::ProtoCodecError::FromIntError(e.into())) } - }); - - for _ in 0..len { - vec.push(match ::bedrockrs_proto_core::ProtoCodec::proto_deserialize(stream) { - Ok(v) => { v }, - Err(e) => { return Err(e) } - }); - }; - - vec - }, - }); - } - } - - match quote { - None => { - quote! { - #field_name: match ::bedrockrs_proto_core::ProtoCodec::proto_deserialize(stream) { - Ok(v) => { v }, - Err(e) => { return Err(e) } - }, - } - } - Some(v) => { - v - } - } - }); - - quote! { - #(#calls)* - } - } - Fields::Unnamed(ref fields) => { - let calls = fields.unnamed.iter().enumerate().map(|(i, f)| { - let index = Index::from(i); - - let mut quote = None; - - for attr in &f.attrs { - if attr.path().is_ident("len_repr") { - let int_type: Expr = attr - .parse_args() - .unwrap_or_else(|_| panic!("Given attribute meta for field self.{:?} could not be parsed", index.index)); - - quote = Some(quote! { - #index: { - let len = match #int_type::read(stream) { - Ok(v) => { v.into_inner() }, - Err(e) => { return Err(::bedrockrs_proto_core::error::ProtoCodecError::IOError(std::sync::Arc::new(e))) } - }; - - let mut vec = Vec::with_capacity( match len.try_into() { - Ok(v) => { v }, - Err(e) => { return Err(::bedrockrs_proto_core::error::ProtoCodecError::FromIntError(e.into())) } - }); - - for _ in 0..len { - vec.push(match ::bedrockrs_proto_core::ProtoCodec::proto_deserialize(stream) { - Ok(v) => { v }, - Err(e) => { return Err(e) } - }); - }; - - vec - }, - }); - } - } - - match quote { - None => { - quote! { - #index: match ::bedrockrs_proto_core::ProtoCodec::proto_deserialize(stream) { - Ok(v) => { v }, - Err(e) => { return Err(e) } - }, - } - } - Some(v) => { - v - } - } - }); - - quote! { - #(#calls)* - } - } - Fields::Unit => { - // Unit structs are empty and not supported - panic!( - "ProtoCodec macro only supports named/unnamed structs and enums, got unit struct." - ) - } - }; - - expand -} - -pub fn proto_build_de_enum( - enum_data: &DataEnum, - attributes: &Vec, - enum_name: &Ident, -) -> TokenStream { - let mut int_type: Option = None; - - for attr in attributes { - if attr.path().is_ident("enum_repr") { - int_type = - Some(attr.parse_args().unwrap_or_else(|_| { - panic!("Given attribute meta for enum could not be parsed") - })); - } - } - - let int_type = int_type - .unwrap_or_else(|| panic!("Missing attribute \"enum_repr\" for ProtoCodec macro on Enum")); - - let calls = enum_data.variants.iter().map(|v| { - let val = v - .discriminant - .clone() - .unwrap_or_else(|| panic!("Discriminant needed")) - .1; - let name = v.ident.clone(); - - quote! { - #val => #enum_name::#name, - } - }); - - quote! { - let int = match #int_type::read(stream) { - Ok(v) => { v.into_inner() }, - Err(e) => { return Err(::bedrockrs_proto_core::error::ProtoCodecError::IOError(std::sync::Arc::new(e))) } - }; - - match int { - #(#calls)* - other => { return Err(::bedrockrs_proto_core::error::ProtoCodecError::InvalidEnumID(format!("{other:?}"), stringify!(#enum_name).to_string())); } - } - } -} diff --git a/crates/proto_macros/src/ser.rs b/crates/proto_macros/src/ser.rs deleted file mode 100644 index 47eee59b..00000000 --- a/crates/proto_macros/src/ser.rs +++ /dev/null @@ -1,160 +0,0 @@ -use proc_macro2::{Ident, TokenStream}; -use quote::quote; -use syn::{Attribute, DataEnum, DataStruct, Expr, Fields, Index}; - -pub fn proto_build_ser_struct(struct_data: &DataStruct) -> TokenStream { - let fields = &struct_data.fields; - - let expand = match fields { - Fields::Named(ref fields) => { - let calls = fields.named.iter().map(|f| { - let field_name = f.ident.clone(); - - let mut quote = None; - - for attr in &f.attrs { - if attr.path().is_ident("len_repr") { - let int_type: Expr = attr - .parse_args() - .unwrap_or_else(|_| panic!("Given attribute meta for field {field_name:?} could not be parsed")); - - quote = Some(quote! { - { - let len = #int_type::new(match Vec::len(&self.#field_name).try_into() { - Ok(v) => { v }, - Err(e) => { return Err(::bedrockrs_proto_core::error::ProtoCodecError::FromIntError(e.into())) } - }); - - match len.write(stream) { - Ok(_) => { }, - Err(e) => { return Err(::bedrockrs_proto_core::error::ProtoCodecError::IOError(std::sync::Arc::new(e))) } - }; - - for i in &self.#field_name { - match ::bedrockrs_proto_core::ProtoCodec::proto_serialize(i, stream) { - Ok(_) => { }, - Err(e) => { return Err(e) } - }; - } - }; - }); - } - } - - match quote { - None => { - quote! { - match ::bedrockrs_proto_core::ProtoCodec::proto_serialize(&self.#field_name, stream) { - Ok(_) => { }, - Err(e) => { return Err(e) } - }; - } - } - Some(v) => { - v - } - } - }); - - quote! { - #(#calls)* - } - } - Fields::Unnamed(ref fields) => { - let calls = fields.unnamed.iter().enumerate().map(|(i, f)| { - let index = Index::from(i); - - let mut quote = None; - - for attr in &f.attrs { - if attr.path().is_ident("len_repr") { - let int_type: Expr = attr - .parse_args() - .unwrap_or_else(|_| panic!("Given attribute meta for field self.{:?} could not be parsed", index.index)); - - quote = Some(quote! { - { - let len = #int_type::new(match Vec::len(&self.#index).try_into() { - Ok(v) => { v }, - Err(e) => { return Err(::bedrockrs_proto_core::error::ProtoCodecError::FromIntError(e.into())) } - }); - - match len.write(stream) { - Ok(_) => { }, - Err(e) => { return Err(::bedrockrs_proto_core::error::ProtoCodecError::IOError(std::sync::Arc::new(e))) } - }; - - for i in &self.#index { - ::bedrockrs_proto_core::ProtoCodec::proto_serialize(i, stream)?; - } - }; - }); - } - } - - match quote { - None => { - quote! { - ::bedrockrs_proto_core::ProtoCodec::proto_serialize(&self.#index, stream)?; - } - } - Some(v) => { - v - } - } - }); - - quote! { - #(#calls)* - } - } - Fields::Unit => { - // Unit structs are empty and not supported - panic!( - "ProtoCodec macro only supports named/unnamed structs and enums, got unit struct." - ) - } - }; - - expand -} - -pub fn proto_build_ser_enum( - enum_data: &DataEnum, - attributes: &Vec, - enum_name: &Ident, -) -> TokenStream { - let mut int_type: Option = None; - - for attr in attributes { - if attr.path().is_ident("enum_repr") { - int_type = - Some(attr.parse_args().unwrap_or_else(|_| { - panic!("Given attribute meta for enum could not be parsed") - })); - } - } - - let int_type = int_type - .unwrap_or_else(|| panic!("Missing attribute \"enum_repr\" for ProtoCodec macro on Enum")); - - let calls = enum_data.variants.iter().map(|v| { - let val = v.discriminant.clone().expect("Discriminant needed").1; - let name = v.ident.clone(); - - quote! { - #enum_name::#name => #val, - } - }); - - quote! { - let int = #int_type::new(match self { - #(#calls)* - }); - - match int.write(stream) { - Ok(_) => { }, - Err(e) => { return Err(::bedrockrs_proto_core::error::ProtoCodecError::IOError(std::sync::Arc::new(e))) } - }; - } -} diff --git a/crates/server/Cargo.toml b/crates/server/Cargo.toml new file mode 100644 index 00000000..0da66c69 --- /dev/null +++ b/crates/server/Cargo.toml @@ -0,0 +1,23 @@ +[package] +name = "bedrockrs_server" +version = "0.1.0" +edition = "2021" + +[dependencies] +thiserror = "2.0" + +bedrockrs_core = { path = "../core" } +bedrockrs_shared = { path = "../shared" } +bedrockrs_proto = { path = "../proto" } + +tokio = { version = "1.40", features = ["full", "tracing"] } +shipyard = { version = "0.7", features = ["parallel", "proc", "rayon", "tracing"] } +rayon = "1.10" +vek = "0.17" + +xuid = "1.0" + +[features] +scoreboard = [] +forms = [] +visibility = [] diff --git a/crates/server/src/ecs/components/connected.rs b/crates/server/src/ecs/components/connected.rs new file mode 100644 index 00000000..ef9d7bb5 --- /dev/null +++ b/crates/server/src/ecs/components/connected.rs @@ -0,0 +1,11 @@ +use bedrockrs_proto::connection::shard::arc::ConnectionShared; +use bedrockrs_proto::ProtoHelper; +use shipyard::Component; + +#[derive(Component)] +pub struct Connected +where + ::GamePacketType: Sync, +{ + pub connection: ConnectionShared, +} diff --git a/crates/server/src/ecs/components/damage.rs b/crates/server/src/ecs/components/damage.rs new file mode 100644 index 00000000..42ab4d12 --- /dev/null +++ b/crates/server/src/ecs/components/damage.rs @@ -0,0 +1,6 @@ +use shipyard::Component; + +#[derive(Component)] +pub struct Damage { + pub damage: f32, +} diff --git a/crates/server/src/ecs/components/health.rs b/crates/server/src/ecs/components/health.rs new file mode 100644 index 00000000..d73da8ba --- /dev/null +++ b/crates/server/src/ecs/components/health.rs @@ -0,0 +1,8 @@ +use shipyard::Component; + +#[derive(Component)] +pub struct Health { + pub current: f32, + pub min: f32, + pub max: f32, +} diff --git a/crates/server/src/ecs/components/mod.rs b/crates/server/src/ecs/components/mod.rs new file mode 100644 index 00000000..80e13563 --- /dev/null +++ b/crates/server/src/ecs/components/mod.rs @@ -0,0 +1,5 @@ +pub mod connected; +mod damage; +mod health; +pub mod position; +pub mod velocity; diff --git a/crates/server/src/ecs/components/position.rs b/crates/server/src/ecs/components/position.rs new file mode 100644 index 00000000..b761062b --- /dev/null +++ b/crates/server/src/ecs/components/position.rs @@ -0,0 +1,5 @@ +use shipyard::Component; +use vek::Vec3; + +#[derive(Component)] +pub struct Pos(pub Vec3); diff --git a/crates/server/src/ecs/components/velocity.rs b/crates/server/src/ecs/components/velocity.rs new file mode 100644 index 00000000..61303a2d --- /dev/null +++ b/crates/server/src/ecs/components/velocity.rs @@ -0,0 +1,5 @@ +use shipyard::Component; +use vek::Vec3; + +#[derive(Component)] +pub struct Vel(pub Vec3); diff --git a/crates/server/src/ecs/mod.rs b/crates/server/src/ecs/mod.rs new file mode 100644 index 00000000..621600aa --- /dev/null +++ b/crates/server/src/ecs/mod.rs @@ -0,0 +1,2 @@ +pub mod components; +pub mod systems; diff --git a/crates/server/src/ecs/systems/death.rs b/crates/server/src/ecs/systems/death.rs new file mode 100644 index 00000000..af9020b6 --- /dev/null +++ b/crates/server/src/ecs/systems/death.rs @@ -0,0 +1 @@ +pub fn death() {} diff --git a/crates/server/src/ecs/systems/mod.rs b/crates/server/src/ecs/systems/mod.rs new file mode 100644 index 00000000..2ea13551 --- /dev/null +++ b/crates/server/src/ecs/systems/mod.rs @@ -0,0 +1 @@ +pub mod death; diff --git a/crates/server/src/error.rs b/crates/server/src/error.rs new file mode 100644 index 00000000..33f8c608 --- /dev/null +++ b/crates/server/src/error.rs @@ -0,0 +1,16 @@ +use bedrockrs_proto::error::ConnectionError; +use thiserror::Error; + +pub enum StartError {} + +#[derive(Error, Debug)] +pub enum LoginError { + #[error("Connection Error: {0}")] + ConnectionError(#[from] ConnectionError), + #[error("Login aborted, reason: {reason}")] + Abort { reason: String }, + #[error("Wrong protocol version (client: {client}, server: {server:?})")] + WrongProtocolVersion { client: i32, server: Vec }, + #[error("Format Error: {0}")] + FormatError(String), +} diff --git a/crates/server/src/lib.rs b/crates/server/src/lib.rs new file mode 100644 index 00000000..484c8be0 --- /dev/null +++ b/crates/server/src/lib.rs @@ -0,0 +1,4 @@ +pub mod ecs; +pub mod error; +pub mod login; +pub mod server; diff --git a/crates/server/src/login/handler.rs b/crates/server/src/login/handler.rs new file mode 100644 index 00000000..3c9651bf --- /dev/null +++ b/crates/server/src/login/handler.rs @@ -0,0 +1 @@ +pub trait LoginHandler {} diff --git a/crates/server/src/login/mod.rs b/crates/server/src/login/mod.rs new file mode 100644 index 00000000..21bc8199 --- /dev/null +++ b/crates/server/src/login/mod.rs @@ -0,0 +1,18 @@ +mod handler; + +use crate::error::LoginError; +use crate::login::handler::LoginHandler; +use bedrockrs_proto::connection::shard::arc::shard; +use bedrockrs_proto::connection::Connection; +use bedrockrs_proto::v729::helper::ProtoHelperV729; +use shipyard::World; + +pub async fn login( + connection: Connection, + world: &mut World, + login_handler: impl LoginHandler, +) -> Result<(), LoginError> { + let mut shard = shard::(connection); + + todo!() +} diff --git a/crates/server/src/server/builder.rs b/crates/server/src/server/builder.rs new file mode 100644 index 00000000..1aa2780e --- /dev/null +++ b/crates/server/src/server/builder.rs @@ -0,0 +1,76 @@ +use crate::server::Server; +use bedrockrs_proto::listener::Listener; +use std::net::{IpAddr, Ipv4Addr, SocketAddr}; + +pub struct ServerBuilder { + name: String, + sub_name: String, + listeners_info: Vec, + max_player: u32, +} + +impl ServerBuilder { + pub fn new() -> ServerBuilder { + Self::default() + } + + pub fn name(mut self, name: &str) -> ServerBuilder { + self.name = name.to_owned(); + self + } + + pub fn sub_name(mut self, sub_name: &str) -> ServerBuilder { + self.sub_name = sub_name.to_owned(); + self + } + + pub fn listener(mut self, addr: SocketAddr) -> ServerBuilder { + self.listeners_info.push(addr); + self + } + + pub async fn build(mut self) -> Server { + if self.listeners_info.is_empty() { + self.listeners_info.push(SocketAddr::new( + IpAddr::V4(Ipv4Addr::new(127, 0, 0, 0)), + 19132, + )); + } + + let mut listeners = Vec::with_capacity(self.listeners_info.len()); + + for addr in self.listeners_info { + listeners.push( + Listener::new_raknet( + self.name.clone(), + self.sub_name.clone(), + String::from("1.21.0"), + self.max_player, + 0, + addr, + false, + ) + .await + .unwrap(), + ) + } + + Server { + listeners, + name: self.name, + sub_name: self.sub_name, + world: Default::default(), + } + } +} + +impl Default for ServerBuilder { + fn default() -> Self { + Self { + name: "bedrock-server".to_string(), + sub_name: "bedrock-rs".to_string(), + listeners_info: vec![], + max_player: 100, + } + } +} diff --git a/crates/server/src/server/mod.rs b/crates/server/src/server/mod.rs new file mode 100644 index 00000000..d70fd985 --- /dev/null +++ b/crates/server/src/server/mod.rs @@ -0,0 +1,33 @@ +use crate::error::LoginError; +use bedrockrs_proto::listener::Listener; +use shipyard::World; +use std::error::Error; + +pub mod builder; + +pub struct Server { + listeners: Vec, + name: String, + sub_name: String, + pub world: World, +} + +impl Server { + pub async fn start(&mut self) { + for listener in &mut self.listeners { + listener.start().await.unwrap(); + } + + self.world.run_default_workload().unwrap() + } + + pub async fn stop(&mut self) { + for listener in &mut self.listeners { + listener.stop().await.expect("TODO: panic message"); + } + } + + pub async fn accept(&mut self) -> Result<(), LoginError> { + todo!() + } +} diff --git a/crates/shared/Cargo.toml b/crates/shared/Cargo.toml index 22589b36..63ee2a38 100644 --- a/crates/shared/Cargo.toml +++ b/crates/shared/Cargo.toml @@ -4,8 +4,10 @@ version = "0.1.0" edition = "2021" [dependencies] -bedrockrs_core = { path = "../core" } bedrockrs_proto_core = { path = "../proto_core" } -bedrockrs_proto_macros = { path = "../proto_macros" } +bedrockrs_macros = { path = "../macros" } -log = "0.4" \ No newline at end of file +log = "0.4" + +byteorder = "1.5.0" +varint-rs = "2.2" diff --git a/crates/shared/src/actor_runtime_id.rs b/crates/shared/src/actor_runtime_id.rs index d860b5a8..000d06c0 100644 --- a/crates/shared/src/actor_runtime_id.rs +++ b/crates/shared/src/actor_runtime_id.rs @@ -1,19 +1,23 @@ -use std::io::Cursor; - -use bedrockrs_core::int::VAR; use bedrockrs_proto_core::error::ProtoCodecError; use bedrockrs_proto_core::ProtoCodec; +use std::io::Cursor; +use std::mem::size_of; +use varint_rs::{VarintReader, VarintWriter}; -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] pub struct ActorRuntimeID(pub u64); // ProtoCodec impl ProtoCodec for ActorRuntimeID { fn proto_serialize(&self, stream: &mut Vec) -> Result<(), ProtoCodecError> { - VAR::new(self.0).proto_serialize(stream) + Ok(stream.write_u64_varint(self.0)?) } fn proto_deserialize(stream: &mut Cursor<&[u8]>) -> Result { - Ok(Self(VAR::proto_deserialize(stream)?.into_inner())) + Ok(Self(stream.read_u64_varint()?)) + } + + fn get_size_prediction(&self) -> usize { + size_of::() } } diff --git a/crates/shared/src/actor_unique_id.rs b/crates/shared/src/actor_unique_id.rs index 21b80ee8..eb255e4d 100644 --- a/crates/shared/src/actor_unique_id.rs +++ b/crates/shared/src/actor_unique_id.rs @@ -1,19 +1,23 @@ -use std::io::Cursor; - -use bedrockrs_core::int::VAR; use bedrockrs_proto_core::error::ProtoCodecError; use bedrockrs_proto_core::ProtoCodec; +use std::io::Cursor; +use std::mem::size_of; +use varint_rs::{VarintReader, VarintWriter}; -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] pub struct ActorUniqueID(pub i64); // ProtoCodec impl ProtoCodec for ActorUniqueID { fn proto_serialize(&self, stream: &mut Vec) -> Result<(), ProtoCodecError> { - VAR::new(self.0).proto_serialize(stream) + Ok(stream.write_i64_varint(self.0)?) } fn proto_deserialize(stream: &mut Cursor<&[u8]>) -> Result { - Ok(Self(VAR::proto_deserialize(stream)?.into_inner())) + Ok(Self(stream.read_i64_varint()?)) + } + + fn get_size_prediction(&self) -> usize { + size_of::() } } diff --git a/crates/shared/src/world/difficulty.rs b/crates/shared/src/world/difficulty.rs index a38181db..efb732ea 100644 --- a/crates/shared/src/world/difficulty.rs +++ b/crates/shared/src/world/difficulty.rs @@ -1,8 +1,8 @@ -use bedrockrs_core::int::VAR; -use bedrockrs_proto_macros::ProtoCodec; +use bedrockrs_macros::ProtoCodec; #[derive(ProtoCodec, Debug, Clone)] -#[enum_repr(VAR::)] +#[enum_repr(i32)] +#[enum_endianness(var)] pub enum Difficulty { Peaceful = 0, Easy = 1, diff --git a/crates/shared/src/world/dimension.rs b/crates/shared/src/world/dimension.rs index dcab69c4..8f1cc87f 100644 --- a/crates/shared/src/world/dimension.rs +++ b/crates/shared/src/world/dimension.rs @@ -1,11 +1,33 @@ -use bedrockrs_core::int::VAR; -use bedrockrs_proto_macros::ProtoCodec; +use bedrockrs_macros::ProtoCodec; -#[derive(ProtoCodec, Debug, Clone)] -#[enum_repr(VAR::)] +#[derive(ProtoCodec, Debug, Clone, Eq, PartialEq, Copy, Hash)] +#[enum_repr(i32)] +#[enum_endianness(var)] pub enum Dimension { Overworld = 0, Nether = 1, End = 2, Undefined = 3, } + +impl From for Dimension { + fn from(value: i32) -> Self { + match value { + 0 => Self::Overworld, + 1 => Self::Nether, + 2 => Self::End, + _ => Self::Undefined, + } + } +} + +impl From for i32 { + fn from(value: Dimension) -> i32 { + match value { + Dimension::Overworld => 0, + Dimension::Nether => 1, + Dimension::End => 2, + Dimension::Undefined => 3, + } + } +} diff --git a/crates/shared/src/world/editor_world_type.rs b/crates/shared/src/world/editor_world_type.rs index 33720da5..4ae3e115 100644 --- a/crates/shared/src/world/editor_world_type.rs +++ b/crates/shared/src/world/editor_world_type.rs @@ -1,8 +1,8 @@ -use bedrockrs_core::int::VAR; -use bedrockrs_proto_macros::ProtoCodec; +use bedrockrs_macros::ProtoCodec; #[derive(ProtoCodec, Debug, Clone)] -#[enum_repr(VAR::)] +#[enum_repr(i32)] +#[enum_endianness(var)] pub enum EditorWorldType { NotEditor = 0, Project = 1, diff --git a/crates/shared/src/world/gamemode.rs b/crates/shared/src/world/gamemode.rs index 4c48abe1..adb2a382 100644 --- a/crates/shared/src/world/gamemode.rs +++ b/crates/shared/src/world/gamemode.rs @@ -1,8 +1,8 @@ -use bedrockrs_core::int::VAR; -use bedrockrs_proto_macros::ProtoCodec; +use bedrockrs_macros::ProtoCodec; #[derive(ProtoCodec, Debug, Clone)] -#[enum_repr(VAR::)] +#[enum_repr(i32)] +#[enum_endianness(var)] pub enum Gamemode { Survival = 0, Creative = 1, diff --git a/crates/shared/src/world/generator_type.rs b/crates/shared/src/world/generator_type.rs index 6e4c6fbb..6973bb13 100644 --- a/crates/shared/src/world/generator_type.rs +++ b/crates/shared/src/world/generator_type.rs @@ -1,13 +1,13 @@ -use bedrockrs_core::int::VAR; -use bedrockrs_proto_macros::ProtoCodec; +use bedrockrs_macros::ProtoCodec; #[derive(ProtoCodec, Debug, Clone)] -#[enum_repr(VAR::)] +#[enum_repr(i32)] +#[enum_endianness(var)] pub enum GeneratorType { - Legacy = 0x00, - Overworld = 0x01, - Flat = 0x02, - Nether = 0x03, - End = 0x04, - Void = 0x05, + Legacy = 0, + Overworld = 1, + Flat = 2, + Nether = 3, + End = 4, + Void = 5, } diff --git a/crates/shared/src/world.rs b/crates/shared/src/world/mod.rs similarity index 100% rename from crates/shared/src/world.rs rename to crates/shared/src/world/mod.rs diff --git a/crates/shared/src/world/permissions_level.rs b/crates/shared/src/world/permissions_level.rs index c44e1958..0d6d0fcc 100644 --- a/crates/shared/src/world/permissions_level.rs +++ b/crates/shared/src/world/permissions_level.rs @@ -1,8 +1,9 @@ -use bedrockrs_core::int::VAR; -use bedrockrs_proto_macros::ProtoCodec; +use bedrockrs_macros::ProtoCodec; #[derive(ProtoCodec, Debug, Clone)] -#[enum_repr(VAR::)] +// TODO: Give more specialized name, find out if u32 or i32 +#[enum_repr(u32)] +#[enum_endianness(var)] pub enum PermissionLevel { /// Any/Normal permission Default = 0, diff --git a/crates/world/Cargo.toml b/crates/world/Cargo.toml deleted file mode 100644 index fbdb726b..00000000 --- a/crates/world/Cargo.toml +++ /dev/null @@ -1,16 +0,0 @@ -[package] -name = "bedrockrs_world" -version = "0.1.0" -edition = "2021" - -[dependencies] -bedrockrs_core = { path = "../core" } -bedrockrs_shared = { path = "../shared" } -bedrockrs_paletted_storage = { path = "../paletted_storage" } - -nbtx = { git = "https://github.com/bedrock-crustaceans/nbtx" } - -mojang-leveldb = "0.6" -thiserror = "1.0" -byteorder = "1.5" -uuid = { version = "1.10", features = ["v4"] } diff --git a/crates/world/src/error.rs b/crates/world/src/error.rs deleted file mode 100644 index 7efcc066..00000000 --- a/crates/world/src/error.rs +++ /dev/null @@ -1,13 +0,0 @@ -use thiserror::Error; - -#[derive(Error, Debug)] -pub enum WorldError { - #[error("DB Error: {0}")] - DBError(#[from] mojang_leveldb::error::DBError), - - #[error("Nbt Error: {0}")] - NbtError(#[from] nbtx::NbtError), - - #[error("Format Error: {0}")] - FormatError(String), -} diff --git a/crates/world/src/level_dat/abilities.rs b/crates/world/src/level_dat/abilities.rs deleted file mode 100644 index 62804d22..00000000 --- a/crates/world/src/level_dat/abilities.rs +++ /dev/null @@ -1,195 +0,0 @@ -use std::collections::HashMap; - -use bedrockrs_shared::world::permissions_level::PermissionLevel; - -use crate::error::WorldError; - -/// Represents the `abilities` compound tag in the `level.dat` and `level.dat_old` files, -/// it's for storing the default permissions for players in the world. -#[derive(Debug)] -pub struct LevelDatAbilities { - /// If the player can attack mobs. (NBT entry: `attackmobs`) - pub attack_mobs: bool, - /// If the player can attack other players. (NBT entry: `attackplayers`) - pub attack_players: bool, - /// If the player is able to interact with redstone components. (NBT entry: `doorsandswitches`) - pub redstone_interact: bool, - /// If the player can place blocks. (NBT entry: `build`) - pub build: bool, - /// If the player can destroy blocks. (NBT entry: `mine`) - pub mine: bool, - /// If the player can instantly destroy blocks. (NBT entry: `instabuild`) - pub mine_instantly: bool, - /// If the player is currently flying. (NBT entry: `flying`) - pub flying: bool, - /// The flying speed, always 0.05. (NBT entry: `flySpeed`) - pub fly_speed: f32, - /// The walking speed, always 0.1. (NBT entry: `walkSpeed`) - pub walk_speed: f32, - /// If the player is immune to all damage and harmful effects. (NBT entry: `invulnerable`) - pub invulnerable: bool, - /// If lightning struck the player. (NBT entry: `lightning`) - pub lightning: bool, - /// If the player can fly. (NBT entry: `mayfly`) - pub mayfly: bool, - /// If the player messages cannot be seen by other players. (NBT entry: `mute`) - pub mute: Option, - /// If the player can phase through blocks. (NBT entry: `noclip`) - pub no_clip: Option, - /// If the player is able to open containers. (NBT entry: `opencontainers`) - pub open_containers: bool, - /// If the player is a world builder. (NBT entry: `worldbuilder`) - pub world_builder: Option, - /// If the player is allowed to teleport. (NBT entry: `teleport`) - pub teleport: bool, - /// If the player has operator commands. (NBT entry: `op`) - pub op: bool, - - /// What permissions a player defaults to, when joining a world. (NBT entry: `permissionsLevel`) - pub permissions_level: Option, - /// What permissions a player has. (NBT entry: `playerPermissionsLevel`) - pub permissions_level_default: Option, -} - -impl LevelDatAbilities { - /// Parses a given [`nbt::Value`] into a [`LevelDatAbilities`] object. - pub fn parse(tag: nbtx::Value) -> Result { - fn get_byte_as_bool( - map: &mut HashMap, - key: &str, - ) -> Result { - match map.remove(key) { - Some(nbtx::Value::Byte(v)) => Ok(v != 0), - Some(other) => Err(WorldError::FormatError(format!( - "Expected `{}` in LevelDat abilities to be of type Byte, got {:?}", - key, other - ))), - None => Err(WorldError::FormatError(format!( - "Missing field `{}` in LevelDat abilities", - key - ))), - } - } - - fn get_byte_as_bool_option( - map: &mut HashMap, - key: &str, - ) -> Result, WorldError> { - match map.remove(key) { - Some(nbtx::Value::Byte(v)) => Ok(Some(v != 0)), - Some(other) => Err(WorldError::FormatError(format!( - "Expected `{}` in LevelDat abilities to be of type Byte, got {:?}", - key, other - ))), - None => Ok(None), - } - } - - fn get_int32(map: &mut HashMap, key: &str) -> Result { - match map.remove(key) { - Some(nbtx::Value::Int(v)) => Ok(v), - Some(other) => Err(WorldError::FormatError(format!( - "Expected `{}` in LevelDat abilities to be of type Int32, got {:?}", - key, other - ))), - None => Err(WorldError::FormatError(format!( - "Missing field `{}` in LevelDat abilities", - key - ))), - } - } - - fn get_int32_option( - map: &mut HashMap, - key: &str, - ) -> Result, WorldError> { - match map.remove(key) { - Some(nbtx::Value::Int(v)) => Ok(Some(v)), - Some(other) => Err(WorldError::FormatError(format!( - "Expected `{}` in LevelDat abilities to be of type Int32, got {:?}", - key, other - ))), - None => Ok(None), - } - } - - fn get_int64(map: &mut HashMap, key: &str) -> Result { - match map.remove(key) { - Some(nbtx::Value::Long(v)) => Ok(v), - Some(other) => Err(WorldError::FormatError(format!( - "Expected `{}` in LevelDat abilities to be of type Int64, got {:?}", - key, other - ))), - None => Err(WorldError::FormatError(format!( - "Missing field `{}` in LevelDat abilities", - key - ))), - } - } - - fn get_f32(map: &mut HashMap, key: &str) -> Result { - match map.remove(key) { - Some(nbtx::Value::Float(v)) => Ok(v), - Some(other) => Err(WorldError::FormatError(format!( - "Expected `{}` in LevelDat abilities to be of type Float32, got {:?}", - key, other - ))), - None => Err(WorldError::FormatError(format!( - "Missing field `{}` in LevelDat abilities", - key - ))), - } - } - - match tag { - nbtx::Value::Compound(mut map) => Ok(Self { - attack_mobs: get_byte_as_bool(&mut map, "attackmobs")?, - attack_players: get_byte_as_bool(&mut map, "attackplayers")?, - redstone_interact: get_byte_as_bool(&mut map, "doorsandswitches")?, - build: get_byte_as_bool(&mut map, "build")?, - mine: get_byte_as_bool(&mut map, "mine")?, - mine_instantly: get_byte_as_bool(&mut map, "instabuild")?, - flying: get_byte_as_bool(&mut map, "flying")?, - fly_speed: get_f32(&mut map, "flySpeed")?, - walk_speed: get_f32(&mut map, "walkSpeed")?, - invulnerable: get_byte_as_bool(&mut map, "invulnerable")?, - lightning: get_byte_as_bool(&mut map, "lightning")?, - mayfly: get_byte_as_bool(&mut map, "mayfly")?, - mute: get_byte_as_bool_option(&mut map, "mute")?, - no_clip: get_byte_as_bool_option(&mut map, "noclip")?, - open_containers: get_byte_as_bool(&mut map, "opencontainers")?, - world_builder: get_byte_as_bool_option(&mut map, "worldbuilder")?, - teleport: get_byte_as_bool(&mut map, "teleport")?, - op: get_byte_as_bool(&mut map, "op")?, - permissions_level: match get_int32_option(&mut map, "playerPermissionsLevel")? { - Some(0) => Some(PermissionLevel::Default), - Some(1) => Some(PermissionLevel::Operator), - Some(2) => Some(PermissionLevel::Admin), - Some(3) => Some(PermissionLevel::Host), - Some(4) => Some(PermissionLevel::Owner), - Some(other) => Err(WorldError::FormatError(format!( - "Value for `playerPermissionsLevel` is out of bounds, got {:?}", - other - )))?, - None => None, - }, - permissions_level_default: match get_int32_option(&mut map, "permissionsLevel")? { - Some(0) => Some(PermissionLevel::Default), - Some(1) => Some(PermissionLevel::Operator), - Some(2) => Some(PermissionLevel::Admin), - Some(3) => Some(PermissionLevel::Host), - Some(4) => Some(PermissionLevel::Owner), - Some(other) => Err(WorldError::FormatError(format!( - "Value for `playerPermissionsLevel` is out of bounds, got {:?}", - other - )))?, - None => None, - }, - }), - other => Err(WorldError::FormatError(format!( - "Expected root tag in LevelDat abilities to be of type Compound, got {:?}", - other - ))), - } - } -} diff --git a/crates/world/src/level_dat/level_dat.rs b/crates/world/src/level_dat/level_dat.rs deleted file mode 100644 index 71a380e6..00000000 --- a/crates/world/src/level_dat/level_dat.rs +++ /dev/null @@ -1,68 +0,0 @@ -use std::collections::HashMap; -use std::fs::File; -use std::io::{Cursor, Read}; -use std::path::{Path, PathBuf}; - -use byteorder::{LittleEndian, ReadBytesExt}; - -use bedrockrs_shared::world::difficulty::Difficulty; -use bedrockrs_shared::world::dimension::Dimension; - -use crate::error::WorldError; -use crate::level_dat::abilities::LevelDatAbilities; - -/// A struct representing the data found in the `level.dat` and `level.dat_old` files for -/// the Minecraft Bedrock Level Format. -/// -/// The `level.dat` is still in uncompressed NBT format. -/// The file begins with an 8-byte header, consisting of a little-endian 4-byte integer -/// indicating the version of the file, which is currently 10. It is followed by another integer -/// containing the length of the file, minus the header. -#[derive(Debug)] -pub struct LevelDat { - /// Specifies the name of the world. (NBT entry: `LevelName`) - pub level_name: String, - - /// Version of Bedrock Edition Storage Tool, currently is 10. (NBT entry: `StorageVersion`) - pub format_version: i32, - - /// The default permissions for players in the world. (NBT entry: `abilities`) - pub abilities: LevelDatAbilities, - - /// A key value pair map for each experiment that Minecraft has/had. - /// It is impossible to parse all Experiments due to frequent changes. - /// (NBT entry: `experiments`) - pub experiments: HashMap, - - /// The current difficulty setting. (NBT entry: `Difficulty`) - pub difficulty: Difficulty, - /// The dimension the player is in. (NBT entry: `Dimension`) - pub dimension: Option, - - /// If the bonus chest is enabled. (NBT entry: `bonusChestEnabled`) - pub bonus_chest_enabled: bool, - /// If the bonus chest has been placed in the world. - /// Turning this to false spawns another bonus chest near the spawn coordinates. - /// (NBT entry: `bonusChestSpawned`) - pub bonus_chest_spawned: bool, - - /// Specifies the seed of the level. (NBT entry: `RandomSeed`) - pub seed: i64, - - /// Specifies the current tick of the level. Where 20 ticks are equal to 1 second. - /// (NBT entry: `currentTick`) - pub current_tick: i64, - - /// The X coordinate of the player's spawn position. Defaults to 0. - /// (NBT entry: `SpawnX`) - pub spawn_x: i32, - /// The Y coordinate of the player's spawn position. Defaults to 64. - /// (NBT entry: `SpawnY`) - pub spawn_y: i32, - /// The Z coordinate of the player's spawn position. Defaults to 0. - /// (NBT entry: `SpawnZ`) - pub spawn_z: i32, - - /// If cheats are on. (NBT entry: `commandsEnabled`) - pub cheats: bool, -} diff --git a/crates/world/src/level_dat/mod.rs b/crates/world/src/level_dat/mod.rs deleted file mode 100644 index 41e06f39..00000000 --- a/crates/world/src/level_dat/mod.rs +++ /dev/null @@ -1,4 +0,0 @@ -pub use level_dat::*; - -pub mod abilities; -pub mod level_dat; diff --git a/crates/world/src/lib.rs b/crates/world/src/lib.rs deleted file mode 100644 index bde75af4..00000000 --- a/crates/world/src/lib.rs +++ /dev/null @@ -1,6 +0,0 @@ -pub use world::*; - -pub mod error; -pub mod level_dat; -pub mod world; -pub mod world_db; diff --git a/crates/world/src/world.rs b/crates/world/src/world.rs deleted file mode 100644 index e9062ad3..00000000 --- a/crates/world/src/world.rs +++ /dev/null @@ -1,50 +0,0 @@ -use std::path::{Path, PathBuf}; - -use crate::error::WorldError; -use crate::level_dat::LevelDat; -use crate::world_db::WorldDB; - -/// Represents a Minecraft Bedrock world. -#[derive(Debug)] -pub struct World { - pub db: WorldDB, - pub level_dat: LevelDat, - pub format_version: i32, -} - -impl World { - /// Opens an unzipped Minecraft Bedrock Edition world and returns a [`World`] object with - /// the data about the world contained in it. - pub fn open(directory: impl AsRef) -> Result { - // Convert the given path into a PathBuf - let directory: PathBuf = directory.as_ref().to_path_buf(); - - // Read the world settings/specifications from the level.dat file. - // (in world/level.dat and world/level.dat_old) - todo!("Help"); - // let (version, _, level_dat) = match LevelDat::open(&directory) { - // Ok(v) => v, - // Err(e) => { - // return Err(e); - // } - // }; - - // Read the world name from the levelname.txt file - // (in world/levelname.txt) - // Its stored twice: - // - in the levelname.txt file - // - as a field in the level.dat file (world/level.dat and world/level.dat_old) - - // Ok(World { - // // Read the LevelDB database (in world/db/*) - // db: match WorldDB::open(&PathBuf::from(&directory)) { - // Ok(v) => v, - // Err(e) => { - // return Err(WorldError::DBError(e)); - // } - // }, - // level_dat, - // format_version: 2, - // }) - } -} diff --git a/crates/world/src/world_db/key.rs b/crates/world/src/world_db/key.rs deleted file mode 100644 index 258c9ec2..00000000 --- a/crates/world/src/world_db/key.rs +++ /dev/null @@ -1,84 +0,0 @@ -use bedrockrs_shared::world::dimension::Dimension; - -// don't know what a lot of these mean, some are for world gen that we don't care about -pub enum RecordType { - Data3D, - Version, - Data2D, - Data2DLegacy, - SubChunkPrefix { y: u8 }, // -4 to 20 as of 1.18 - LegacyTerrain, - BlockEntity, - Entity, - PendingTicks, - LegacyBlockExtraData, - BiomeState, - FinalizedState, - ConversionData, - BorderBlocks, - HardcodedSpawners, - RandomTicks, - Checksums, - MetaDataHash, - GeneratedPreCavesAndCliffsBlending, - BlendingBiomeHeight, - BlendingData, - ActorDigestVersion, - LegacyVersion, -} - -impl From<&RecordType> for u8 { - fn from(value: &RecordType) -> Self { - match value { - RecordType::Data3D => 43, - RecordType::Version => 44, - RecordType::Data2D => 45, - RecordType::Data2DLegacy => 46, - RecordType::SubChunkPrefix { y: _ } => 47, - RecordType::LegacyTerrain => 48, - RecordType::BlockEntity => 49, - RecordType::Entity => 50, - RecordType::PendingTicks => 51, - RecordType::LegacyBlockExtraData => 52, - RecordType::BiomeState => 53, - RecordType::FinalizedState => 54, - RecordType::ConversionData => 55, - RecordType::BorderBlocks => 56, - RecordType::HardcodedSpawners => 57, - RecordType::RandomTicks => 58, - RecordType::Checksums => 59, - RecordType::MetaDataHash => 61, - RecordType::GeneratedPreCavesAndCliffsBlending => 62, - RecordType::BlendingBiomeHeight => 63, - RecordType::BlendingData => 64, - RecordType::ActorDigestVersion => 65, - RecordType::LegacyVersion => 76, - } - } -} - -// format: https://minecraft.wiki/w/Bedrock_Edition_level_format#Chunk_key_format -// -// Two signed 32-bit little-endian integers (x and z in chunk coordinates, respectively), -// An optional third 32-bit little-endian integer (1 for the Nether, 2 for the End, omitted for the Overworld), -// A one-byte tag specifying the type of record represented by the key (see table), and -// (for a "SubChunkPrefix" record) a one-byte subchunk index (from 0 to 15). -pub fn create_key(x: i32, z: i32, dimension: Dimension, record_type: RecordType) -> Vec { - let mut out: Vec = Vec::new(); - out.extend_from_slice(&x.to_le_bytes()); - out.extend_from_slice(&z.to_le_bytes()); - match dimension { - Dimension::Overworld => {} - dim => { - out.extend_from_slice(&(dim as i32).to_le_bytes()); - } - } - - out.push(Into::::into(&record_type)); - - if let RecordType::SubChunkPrefix { y } = record_type { - out.push(y); - } - - out -} diff --git a/crates/world/src/world_db/mod.rs b/crates/world/src/world_db/mod.rs deleted file mode 100644 index c90bdd43..00000000 --- a/crates/world/src/world_db/mod.rs +++ /dev/null @@ -1,6 +0,0 @@ -pub use key::*; -pub use world_db::WorldDB; - -pub mod key; -pub mod subchunk; -pub mod world_db; diff --git a/crates/world/src/world_db/subchunk.rs b/crates/world/src/world_db/subchunk.rs deleted file mode 100644 index 0985e86e..00000000 --- a/crates/world/src/world_db/subchunk.rs +++ /dev/null @@ -1,55 +0,0 @@ -use std::io::Cursor; - -use bedrockrs_paletted_storage::PalettedStorage; -use byteorder::ReadBytesExt; - -#[derive(Debug, Clone)] -pub struct SubChunk { - pub paletted_storage: Vec, -} - -impl SubChunk { - pub fn load(bytes: &[u8]) -> SubChunk { - let mut cur = Cursor::new(bytes); - let ver = cur.read_u8().expect("Missing subchunk version"); - match ver { - 8 | 9 => { - let mut out = SubChunk { - paletted_storage: Vec::new(), - }; - let storage_layers = cur.read_u8().expect("Missing storage layers"); - // let mut y_index = None; - if ver == 9 { - // idk if we need the y index or not yet - // y_index = Some( - cur.read_u8().expect("Missing Y index"); - // ); - } - - for _ in 0..storage_layers { - out.paletted_storage.push(PalettedStorage::decode(&mut cur)); - } - - out - } - - 1 => SubChunk { - paletted_storage: vec![PalettedStorage::decode(&mut cur)], - }, - - a => { - panic!("Unsupported subchunk version {}", a); - } - } - } - - pub fn save(&self) -> Vec { - let mut out = Vec::new(); - out.push(8u8); - out.push(self.paletted_storage.len() as u8); - for ps in &self.paletted_storage { - out.extend(ps.encode(false)); - } - out - } -} diff --git a/crates/world/src/world_db/world_db.rs b/crates/world/src/world_db/world_db.rs deleted file mode 100644 index 6afeeac9..00000000 --- a/crates/world/src/world_db/world_db.rs +++ /dev/null @@ -1,134 +0,0 @@ -use mojang_leveldb::{error::DBError, Options, ReadOptions, WriteBatch, WriteOptions, DB}; -use std::fmt::{Debug, Formatter}; -use std::path::Path; -use std::{collections::HashMap, path::PathBuf}; -use uuid::Uuid; - -use bedrockrs_shared::world::dimension::Dimension; - -use crate::error::WorldError; - -use super::subchunk::SubChunk; -use super::{create_key, RecordType}; - -pub struct WorldDB { - db: DB, -} - -const READ_OPTIONS: ReadOptions = ReadOptions { - fill_cache: true, - verify_checksums: true, -}; - -const WRITE_OPTIONS: WriteOptions = WriteOptions { sync: true }; - -impl WorldDB { - /// Opens a world from a directory. - /// - /// The leveldb database is in the `db` subdirectory. - pub fn open(directory: &Path) -> Result { - Ok(WorldDB { - db: DB::open( - &directory.join("db").display().to_string(), - Options { - compression: mojang_leveldb::CompressionType::ZlibRaw, - create_if_missing: true, - }, - )?, - }) - } - - /// Read a player's NBT data for this world - pub fn get_player( - &self, - uuid: Uuid, - ) -> Result>, WorldError> { - let mut str = uuid.to_string(); - str.insert_str(0, "player_"); - - match self.db.get(READ_OPTIONS, str.as_bytes()) { - Ok(maybe_bytes) => match maybe_bytes { - Some(bytes) => { - todo!("Fix this mess") - // match NbtTag::nbt_deserialize_vec::(&u8_bytes) { - // Ok((_, tag)) => match tag { - // NbtTag::Compound(ctag) => Ok(Some(ctag)), - // _ => Err(WorldError::FormatError( - // "Player data tag is not a compound tag".to_string(), - // )), - // }, - // Err(e) => Err(WorldError::NbtError(e)), - // } - } - None => Ok(None), - }, - Err(e) => Err(WorldError::DBError(e)), - } - } - - /// Set a player's NBT data for this world - pub fn set_player( - &mut self, - uuid: Uuid, - data: HashMap, - ) -> Result<(), WorldError> { - // let tag = NbtTag::Compound(data); - // match tag.nbt_serialize_vec::("") { - // Ok(sertag) => { - // let mut str = uuid.to_string(); - // str.insert_str(0, "player_"); - // - // let mut wb = WriteBatch::new(); - // - // wb.put(str.as_bytes(), &sertag); - // - // match self.db.write(WRITE_OPTIONS, wb) { - // Ok(()) => Ok(()), - // Err(dberr) => Err(WorldError::DBError(dberr)), - // } - // } - // Err(e) => Err(WorldError::NbtError(e)), - // } - todo!() - } - - pub fn get_subchunk( - &self, - x: i32, - y: u8, - z: i32, - dimension: Dimension, - ) -> Result, DBError> { - let bytes = self.db.get( - READ_OPTIONS, - create_key(x, z, dimension, RecordType::SubChunkPrefix { y }).as_slice(), - )?; - - Ok(bytes.map(|x| SubChunk::load(&(x.get())))) - } - - pub fn set_subchunk( - &mut self, - x: i32, - y: u8, - z: i32, - dimension: Dimension, - subchunk: SubChunk, - ) -> Result<(), DBError> { - let mut wb = WriteBatch::new(); - wb.put( - &create_key(x, z, dimension, RecordType::SubChunkPrefix { y }), - &subchunk.save(), - ); - self.db.write(WRITE_OPTIONS, wb)?; - - Ok(()) - } -} - -impl Debug for WorldDB { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - // can't be printed - write!(f, "WorldDB(...)") - } -} diff --git a/examples/common/logger.rs b/examples/common/logger.rs new file mode 100644 index 00000000..ec54975d --- /dev/null +++ b/examples/common/logger.rs @@ -0,0 +1,28 @@ +use chrono::Local; +use fern::colors::{Color, ColoredLevelConfig}; + +pub fn setup_logger() -> Result<(), log::SetLoggerError> { + // Create dispatch + let dispatch = fern::Dispatch::new(); + + // Set colors + let colors = ColoredLevelConfig::new() + .info(Color::Green) + .warn(Color::Yellow) + .error(Color::Red); + + // Set dispatch formatting + dispatch + .format(move |out, message, record| { + out.finish(format_args!( + "[{} {} {}] {}", + Local::now().format("%Y-%m-%d %H:%M:%S%.3f"), + colors.color(record.level()), + record.target(), + message + )) + }) + .level(log::LevelFilter::Trace) + .chain(std::io::stdout()) + .apply() +} diff --git a/examples/common/mod.rs b/examples/common/mod.rs new file mode 100644 index 00000000..d9917284 --- /dev/null +++ b/examples/common/mod.rs @@ -0,0 +1 @@ +pub mod logger; diff --git a/examples/proto/server.rs b/examples/proto/server.rs new file mode 100644 index 00000000..2ce064a6 --- /dev/null +++ b/examples/proto/server.rs @@ -0,0 +1,238 @@ +use bedrockrs::proto::connection::Connection; +use bedrockrs::proto::listener::Listener; +use bedrockrs_proto::compression::Compression; +use bedrockrs_proto::v662::enums::{PacketCompressionAlgorithm, PlayStatus}; +use bedrockrs_proto::v662::packets::{ + NetworkSettingsPacket, PlayStatusPacket, ResourcePackStackPacket, ResourcePacksInfoPacket, +}; +use bedrockrs_proto::v662::types::{BaseGameVersion, Experiments}; +use bedrockrs_proto::v662::GamePackets; +use bedrockrs_proto::v662::ProtoHelperV662; +use tokio::time::Instant; + +#[tokio::main] +async fn main() { + let mut listener = Listener::new_raknet( + "§5Hot Chickens in Your Area!!!".to_string(), + "bedrockrs".to_string(), + "1.0".to_string(), + 100, + 10, + "127.0.0.1:19132".parse().unwrap(), + false, + ) + .await + .unwrap(); + + listener.start().await.unwrap(); + + loop { + let conn = listener.accept().await.unwrap(); + + tokio::spawn(async move { + handle_login(conn).await; + }); + } +} + +async fn handle_login(mut conn: Connection) { + let time_start = Instant::now(); + + // NetworkSettingsRequest + conn.recv::().await.unwrap(); + println!("NetworkSettingsRequest"); + + let compression = Compression::None; + + // NetworkSettings + conn.send::(&[GamePackets::NetworkSettings(NetworkSettingsPacket { + compression_threshold: 1, + compression_algorithm: PacketCompressionAlgorithm::None, + client_throttle_enabled: false, + client_throttle_threshold: 0, + client_throttle_scalar: 0.0, + })]) + .await + .unwrap(); + println!("NetworkSettings"); + + conn.compression = Some(compression); + + // Login + conn.recv::().await.unwrap(); + println!("Login"); + + conn.send::(&[ + GamePackets::PlaySatus(PlayStatusPacket { + status: PlayStatus::LoginSuccess, + }), + GamePackets::ResourcePacksInfo(ResourcePacksInfoPacket { + resource_pack_required: false, + has_addon_packs: false, + has_scripts: false, + force_server_packs_enabled: false, + behaviour_packs: vec![], + resource_packs: vec![], + cdn_urls: vec![], + }), + GamePackets::ResourcePackStack(ResourcePackStackPacket { + texture_pack_required: false, + addon_list: vec![], + base_game_version: BaseGameVersion(String::from("1.0")), + experiments: Experiments { + experiments: vec![], + ever_toggled: false, + }, + texture_pack_list: vec![], + }), + ]) + .await + .unwrap(); + println!("PlayStatus (LoginSuccess)"); + println!("ResourcePacksInfo"); + println!("ResourcePackStack"); + + println!("{:#?}", conn.recv::().await.unwrap()); + println!("ClientCacheStatus"); + println!("{:#?}", conn.recv::().await.unwrap()); + println!("ResourcePackClientResponse"); + + // conn.send::(&[GamePackets::DisconnectPlayer(DisconnectPlayerPacket { + // reason: DisconnectReason::Unknown, + // message: Some(String::from("IDK")), + // })]) + // .await + // .unwrap(); + + // let packet1 = StartGamePacket { + // target_actor_id: ActorUniqueID(609), + // target_runtime_id: ActorRuntimeID(402), + // gamemode: Gamemode::Creative, + // position: Vec3 { + // x: 4.0, + // y: 6.0, + // z: 7.0, + // }, + // rotation: Vec2 { x: 270.0, y: 90.0 }, + // settings: LevelSettings { + // seed: 777777777777, + // spawn_settings: SpawnSettings { + // biome_type: SpawnBiomeType::Default, + // user_defined_biome_name: String::from("RandomBiome"), + // dimension: Dimension::Overworld, + // }, + // generator_type: GeneratorType::Overworld, + // gamemode: Gamemode::Creative, + // hardcore: false, + // difficulty: Difficulty::Peaceful, + // default_spawn_block: BlockPos { + // x: 100, + // y: 200, + // z: 300, + // }, + // achievements_disabled: true, + // editor_world_type: EditorWorldType::NotEditor, + // created_in_editor: false, + // exported_from_editor: false, + // day_cycle_stop_time: 2000, + // education_edition_offer: 0, + // education_features: false, + // education_product_id: String::from(""), + // rain_level: 300.0, + // lightning_level: 400.0, + // platform_locked_content: false, + // multiplayer_intended: true, + // lan_broadcasting_intended: true, + // broadcasting_settings_xbox_live: 2, + // broadcasting_settings_platform: 2, + // commands: true, + // texture_pack_required: false, + // gamerules: vec![], + // experiments: Experiments { + // experiments: vec![], + // ever_toggled: false, + // }, + // bonus_chest: false, + // start_with_map: false, + // player_permission: 3, + // server_chunk_tick_radius: 4, + // locked_behavior_packs: false, + // locked_resource_packs: false, + // from_locked_template: false, + // msa_gamertags_only: false, + // from_template: false, + // is_template_locked_settings: false, + // only_spawn_v1_villagers: false, + // persona_disabled: false, + // custom_skins_disabled: false, + // emote_chat_muted: false, + // base_game_version: BaseGameVersion(String::from("1.21.0")), + // limited_world_width: 16, + // limited_world_depth: 16, + // new_nether: true, + // edu_shared_uri_resource: EduSharedResourceUri { + // button_name: String::from(""), + // link_uri: String::from(""), + // }, + // force_experimental_gameplay: Some(true), + // chat_restriction_level: ChatRestrictionLevel::None, + // disable_player_interactions: false, + // server_id: String::from(""), + // world_id: String::from(""), + // scenario_id: String::from(""), + // }, + // level_id: String::from("UmFuZG9tIFdvcmxk"), + // level_name: String::from("Random World"), + // template_content_identity: String::from(""), + // trial: false, + // movement_settings: PlayerMovementSettings { + // authority_mode: PlayerMovementMode::Server, + // rewind_history_size: 3200, + // server_auth_block_breaking: false, + // }, + // current_level_time: 9000, + // enchantment_seed: 99000, + // blocks: vec![], + // items: vec![], + // multiplayer_correlation_id: String::from("c5d3d2cc-27fd-4221-9de6-d22c4d423d53"), + // item_stack_net_manager: false, + // server_version: String::from("1.19.2"), + // player_property_data: nbtx::Value::Compound(HashMap::new()), + // block_state_checksum: 0, + // world_template_id: Uuid::nil(), + // clientside_world_generation: false, + // block_id_hashes: true, + // network_permission: NetworkPermissions { + // server_auth_sound: false, + // }, + // }; + // + // let buf = vec![0xc2, 0x9, 0x92, 0x3, 0x2, 0x0, 0x0, 0x80, 0x40, 0x0, 0x0, 0xc0, 0x40, 0x0, 0x0, 0xe0, 0x40, 0x0, 0x0, 0x87, 0x43, 0x0, 0x0, 0xb4, 0x42, 0x71, 0xc, 0x2b, 0x17, 0xb5, 0x0, 0x0, 0x0, 0x0, 0x0, 0xb, 0x52, 0x61, 0x6e, 0x64, 0x6f, 0x6d, 0x42, 0x69, 0x6f, 0x6d, 0x65, 0x0, 0x2, 0x2, 0x0, 0x0, 0xc8, 0x1, 0xc8, 0x1, 0xd8, 0x4, 0x1, 0x0, 0x0, 0x0, 0xa0, 0x1f, 0x0, 0x0, 0x0, 0x0, 0x0, 0x96, 0x43, 0x0, 0x0, 0xc8, 0x43, 0x0, 0x1, 0x1, 0x4, 0x4, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x6, 0x4, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x6, 0x31, 0x2e, 0x32, 0x31, 0x2e, 0x30, 0x10, 0x0, 0x0, 0x0, 0x10, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x1, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x10, 0x55, 0x6d, 0x46, 0x75, 0x5a, 0x47, 0x39, 0x74, 0x49, 0x46, 0x64, 0x76, 0x63, 0x6d, 0x78, 0x6b, 0xc, 0x52, 0x61, 0x6e, 0x64, 0x6f, 0x6d, 0x20, 0x57, 0x6f, 0x72, 0x6c, 0x64, 0x0, 0x0, 0x2, 0x80, 0x32, 0x0, 0x28, 0x23, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0xf0, 0x8a, 0xc, 0x0, 0x0, 0x24, 0x63, 0x35, 0x64, 0x33, 0x64, 0x32, 0x63, 0x63, 0x2d, 0x32, 0x37, 0x66, 0x64, 0x2d, 0x34, 0x32, 0x32, 0x31, 0x2d, 0x39, 0x64, 0x65, 0x36, 0x2d, 0x64, 0x32, 0x32, 0x63, 0x34, 0x64, 0x34, 0x32, 0x33, 0x64, 0x35, 0x33, 0x0, 0x6, 0x31, 0x2e, 0x31, 0x39, 0x2e, 0x32, 0xa, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0]; + // println!("{buf:?}"); + // let mut buf = vec![]; + // packet1.proto_serialize(&mut buf).unwrap(); + // println!("{buf:?}"); + // + // conn.send(&[GamePackets::StartGame(packet1)]).await.unwrap(); + // println!("StartGame"); + + // conn.send(&[GamePackets::PlayStatus(PlayStatusPacket { + // status: PlayStatusType::PlayerSpawn, + // })]) + // .await.unwrap(); + // println!("PlayStatusPacket (PlayerSpawn)"); + + let time_end = Instant::now(); + + println!("{:?}", time_end.duration_since(time_start)); + + loop { + let res = conn.recv::().await; + + if let Ok(packet) = res { + println!("{:?}", packet); + } else { + break; + } + } +} diff --git a/examples/proto_parsing.rs b/examples/proto_parsing.rs new file mode 100644 index 00000000..327d22fe --- /dev/null +++ b/examples/proto_parsing.rs @@ -0,0 +1,22 @@ +mod common; + +use crate::common::logger::setup_logger; +use bedrockrs::proto::decode_gamepackets; +use bedrockrs::proto::v729::helper::ProtoHelperV729; +use bedrockrs_proto::compression::Compression; + +fn main() { + setup_logger().unwrap(); + + let bytes = vec![ + 1, 0, 0, 2, 254, 243, 252, 35, 32, 10, 0, 0, 123, 34, 99, 104, 97, 105, 110, 34, 58, 91, + 34, 101, 121, 74, 104, 98, 71, 99, 105, 79, 105, 74, 70, 85, 122, 77, 52, 78, 67, 73, 115, + 73, 110, 103, 49, 100, 83, 73, 54, 73, 107, 49, 73, 87, 88, 100, 70, 81, 86, 108, 73, 83, + 50, 57, 97, 83, 88, 112, 113, 77, 69, 78, 66, 85, 86, 108, 71, 83, 122, 82, 70, 82, 85, 70, + 68, 83, 85, 82, 90, 90, 48, 70, 70, 76, 50, 82, 89, + ]; + + let result = decode_gamepackets::(bytes, Some(&Compression::None), None); + + println!("{:?}", result); +} diff --git a/src/lib.rs b/src/lib.rs index 9098724a..a44a60dc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,15 +4,9 @@ pub mod core { pub use ::bedrockrs_shared::*; } -#[cfg(feature = "proto")] -pub mod proto { - pub use ::bedrockrs_proto::*; - pub use ::bedrockrs_proto_core::GamePacket; - - pub mod codec { - pub use ::bedrockrs_proto_core::error::ProtoCodecError; - pub use ::bedrockrs_proto_core::ProtoCodec; - } +#[cfg(feature = "level")] +pub mod level { + pub use ::bedrockrs_level::*; } #[cfg(feature = "addon")] @@ -20,15 +14,23 @@ pub mod addon { pub use ::bedrockrs_addon::*; } -#[cfg(feature = "world")] -pub mod world { - pub use ::bedrockrs_world::*; +#[cfg(feature = "proto")] +pub mod proto { + pub use ::bedrockrs_proto::*; + pub use ::bedrockrs_proto_core::*; - pub mod palette { - pub use ::bedrockrs_paletted_storage::*; + pub mod error { + pub use ::bedrockrs_proto::error::*; + pub use ::bedrockrs_proto_core::error::*; } } +#[cfg(feature = "server")] +pub mod server { + pub use ::bedrockrs_server::*; +} + +#[cfg(feature = "form")] pub mod form { pub use ::bedrockrs_form::*; }