diff --git a/Cargo.toml b/Cargo.toml index 2ecd58a94..85d9cf48e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,80 +9,18 @@ readme = "README.md" license.workspace = true keywords = ["minecraft", "gamedev", "server", "ecs"] categories = ["game-engines"] -include = ["/src", "/benches", "/examples", "/README.md", "/LICENSE.txt"] -[features] -default = [ - "advancement", - "anvil", - "boss_bar", - "inventory", - "log", - "network", - "player_list", - "scoreboard", - "world_border", - "command", - "weather", - "testing", -] -advancement = ["dep:valence_advancement"] -anvil = ["dep:valence_anvil"] -boss_bar = ["dep:valence_boss_bar"] -inventory = ["dep:valence_inventory"] -log = ["dep:bevy_log"] -network = ["dep:valence_network"] -player_list = ["dep:valence_player_list"] -scoreboard = ["dep:valence_scoreboard"] -world_border = ["dep:valence_world_border"] -command = ["dep:valence_command", "dep:valence_command_macros"] -weather = ["dep:valence_weather"] -testing = [] +[lints] +workspace = true [dependencies] anyhow.workspace = true -bevy_app.workspace = true -bevy_ecs.workspace = true -bevy_log = { workspace = true, optional = true } -bytes.workspace = true -rand.workspace = true +evenio = { path = "/home/rj/dev/evenio", version = "0.3.0" } +monoio.workspace = true uuid.workspace = true -valence_advancement = { workspace = true, optional = true } -valence_anvil = { workspace = true, optional = true, features = [ - "bevy_plugin", -] } -valence_boss_bar = { workspace = true, optional = true } -valence_command = { workspace = true, optional = true } -valence_command_macros = { workspace = true, optional = true } -valence_ident_macros.workspace = true -valence_ident.workspace = true -valence_inventory = { workspace = true, optional = true } -valence_lang.workspace = true -valence_network = { workspace = true, optional = true } -valence_player_list = { workspace = true, optional = true } -valence_registry.workspace = true -valence_scoreboard = { workspace = true, optional = true } -valence_server.workspace = true -valence_text.workspace = true -valence_weather = { workspace = true, optional = true } -valence_world_border = { workspace = true, optional = true } - -[dev-dependencies] -anyhow.workspace = true -clap.workspace = true -criterion.workspace = true -flume.workspace = true -noise.workspace = true # For the terrain example. -tracing.workspace = true - -[dev-dependencies.reqwest] -workspace = true -default-features = false -features = ["rustls-tls", "blocking", "stream"] +serde = { workspace = true, features = ["derive"] } -[[bench]] -name = "main" -harness = false +#### WORKSPACE #### [profile.dev.package."*"] opt-level = 3 @@ -91,119 +29,157 @@ opt-level = 3 opt-level = 1 [workspace] -members = ["crates/*", "tools/*"] -exclude = [] +members = ["crates/*"] resolver = "2" [workspace.package] -version = "0.2.0-alpha.1+mc.1.20.1" +version = "0.2.0-alpha.1+mc.1.20.4" edition = "2021" repository = "https://github.com/valence-rs/valence" documentation = "https://docs.rs/valence/" license = "MIT" [workspace.dependencies] -aes = "0.8.2" -anyhow = { version = "1.0.70", features = ["backtrace"] } -approx = "0.5.1" -arrayvec = "0.7.2" -async-trait = "0.1.60" -atty = "0.2.14" -base64 = "0.21.0" -bevy_app = { version = "0.12", default-features = false } -bevy_derive = "0.12" -bevy_ecs = { version = "0.12", default-features = false, features = [ - "multi-threaded", -] } -bevy_hierarchy = { version = "0.12", default-features = false } -bevy_log = { version = "0.12" } -bevy_mod_debugdump = { version = "0.9.0", default-features = false } -bevy_utils = { version = "0.12" } -bitfield-struct = "0.5.3" -bitvec = "1.0.1" -byteorder = "1.4.3" -bytes = "1.2.1" +aes = "0.8.4" +anyhow = "1.0.80" +base64 = "0.21.7" +bitfield-struct = "0.6.0" +byteorder = "1.5.0" +bytes = "1.5.0" cesu8 = "1.1.0" cfb8 = "0.8.1" -clap = { version = "4.0.30", features = ["derive"] } -criterion = "0.5.1" -derive_more = "1.0.0-beta.3" -directories = "5.0.0" -eframe = { version = "0.22.0", default-features = false } -egui = "0.22.0" -egui_dock = "0.6" -flate2 = "1.0.24" -flume = "0.11.0" -fs_extra = "1.2.0" +derive_more = "1.0.0-beta.6" +flate2 = "1.0.28" glam = "0.25.0" heck = "0.5.0-rc.1" -hmac = "0.12.1" -image = "0.24.6" -indexmap = "2.2.1" -itertools = "0.12.0" +indexmap = "2.2.2" java_string = { path = "crates/java_string", version = "0.1.2" } -lru = "0.12.0" -noise = "0.8.2" -num = "0.4.0" -num-bigint = "0.4.3" -owo-colors = "3.5.0" -ordered-float = "4.1.1" -parking_lot = "0.12.1" -paste = "1.0.11" -petgraph = "0.6.3" -pretty_assertions = "1.3.0" -proc-macro2 = "1.0.56" -quote = "1.0.26" +monoio = "0.2.2" +num-derive = "0.4.2" +num-traits = "0.2.18" +pretty_assertions = "1.4.0" +proc-macro2 = "1.0.78" +quote = "1.0.35" rand = "0.8.5" -rayon = "1.7.0" -regex = "1.6.0" -reqwest = { version = "0.11.12", default-features = false } -rfd = "0.11.3" -rsa = "0.9.2" -rsa-der = "0.3.0" -rustc-hash = "1.1.0" -serde = "1.0.160" -serde-value = "0.7.0" -serde_json = "1.0.96" -sha1 = "0.10.5" -sha2 = "0.10.6" -syn = "2.0.15" -syntect = { version = "5.0.0", default-features = false } -tempfile = "3.3.0" -thiserror = "1.0.40" -time = "0.3.17" -tokio = { version = "1.27.0", features = ["full"] } -toml = "0.7.2" -tracing = "0.1.37" -tracing-subscriber = "0.3.16" -url = { version = "2.2.2", features = ["serde"] } -uuid = "1.3.1" -valence = { path = ".", version = "0.2.0-alpha.1" } -valence_advancement = { path = "crates/valence_advancement", version = "0.2.0-alpha.1" } -valence_anvil = { path = "crates/valence_anvil", version = "0.1.0" } -valence_boss_bar = { path = "crates/valence_boss_bar", version = "0.2.0-alpha.1" } +serde = "1.0.196" +serde_json = "1.0.113" +syn = { version = "2.0.48", features = ["full"] } +thiserror = "1.0.56" +url = { version = "2.5.0", features = ["serde"] } +uuid = "1.7.0" valence_build_utils = { path = "crates/valence_build_utils", version = "0.2.0-alpha.1" } -valence_command = { path = "crates/valence_command", version = "0.2.0-alpha.1" } -valence_command_macros = { path = "crates/valence_command_macros", version = "0.2.0-alpha.1" } -valence_entity = { path = "crates/valence_entity", version = "0.2.0-alpha.1" } -valence_generated = { path = "crates/valence_generated", version = "0.2.0-alpha.1" } +# valence_generated = { path = "crates/valence_generated", version = "0.2.0-alpha.1" } valence_ident = { path = "crates/valence_ident", version = "0.2.0-alpha.1" } valence_ident_macros = { path = "crates/valence_ident_macros", version = "0.2.0-alpha.1" } -valence_inventory = { path = "crates/valence_inventory", version = "0.2.0-alpha.1" } -valence_lang = { path = "crates/valence_lang", version = "0.2.0-alpha.1" } valence_math = { path = "crates/valence_math", version = "0.2.0-alpha.1" } -valence_nbt = { path = "crates/valence_nbt", features = [ - "uuid", -], version = "0.8.0" } -valence_network = { path = "crates/valence_network", version = "0.2.0-alpha.1" } -valence_player_list = { path = "crates/valence_player_list", version = "0.2.0-alpha.1" } +valence_nbt = { path = "crates/valence_nbt", version = "0.8.0" } valence_protocol = { path = "crates/valence_protocol", version = "0.2.0-alpha.1" } valence_protocol_macros = { path = "crates/valence_protocol_macros", version = "0.2.0-alpha.1" } -valence_registry = { path = "crates/valence_registry", version = "0.2.0-alpha.1" } -valence_scoreboard = { path = "crates/valence_scoreboard", version = "0.2.0-alpha.1" } -valence_server = { path = "crates/valence_server", version = "0.2.0-alpha.1" } -valence_server_common = { path = "crates/valence_server_common", version = "0.2.0-alpha.1" } valence_text = { path = "crates/valence_text", version = "0.2.0-alpha.1" } -valence_weather = { path = "crates/valence_weather", version = "0.2.0-alpha.1" } -valence_world_border = { path = "crates/valence_world_border", version = "0.2.0-alpha.1" } -zip = "0.6.3" + +[workspace.lints.rust] +elided_lifetimes_in_paths = "allow" # Warned by `future_incompatible`. +future_incompatible = "warn" +missing_debug_implementations = "warn" +# missing_docs = "warn" +nonstandard_style = "warn" +rust_2018_idioms = "warn" +trivial_numeric_casts = "warn" +unreachable_pub = "warn" +unused_import_braces = "warn" +unused_lifetimes = "warn" + +[workspace.lints.clippy] +alloc_instead_of_core = "warn" +as_ptr_cast_mut = "warn" +as_underscore = "warn" +bool_to_int_with_if = "warn" +case_sensitive_file_extension_comparisons = "warn" +cast_lossless = "warn" +checked_conversions = "warn" +cloned_instead_of_copied = "warn" +copy_iterator = "warn" +dbg_macro = "warn" +doc_link_with_quotes = "warn" +doc_markdown = "warn" +empty_enum_variants_with_brackets = "warn" +empty_structs_with_brackets = "warn" +explicit_deref_methods = "warn" +explicit_into_iter_loop = "warn" +explicit_iter_loop = "warn" +filter_map_next = "warn" +flat_map_option = "warn" +format_push_string = "warn" +from_iter_instead_of_collect = "warn" +get_unwrap = "warn" +if_then_some_else_none = "warn" +ignored_unit_patterns = "warn" +implicit_clone = "warn" +inconsistent_struct_constructor = "warn" +inefficient_to_string = "warn" +infinite_loop = "warn" +into_iter_without_iter = "warn" +invalid_upcast_comparisons = "warn" +iter_filter_is_ok = "warn" +iter_filter_is_some = "warn" +iter_not_returning_iterator = "warn" +iter_over_hash_type = "warn" # Requires justification +iter_without_into_iter = "warn" +large_stack_arrays = "warn" +large_types_passed_by_value = "warn" +macro_use_imports = "warn" +manual_assert = "warn" +manual_instant_elapsed = "warn" +manual_is_variant_and = "warn" +manual_let_else = "warn" +manual_ok_or = "warn" +manual_string_new = "warn" +map_unwrap_or = "warn" +match_bool = "warn" +match_wildcard_for_single_variants = "warn" +mismatching_type_param_order = "warn" +missing_fields_in_debug = "warn" +mixed_read_write_in_expression = "warn" +mod_module_files = "warn" +# multiple_inherent_impl = "warn" +mut_mut = "warn" +mutex_atomic = "warn" +needless_bitwise_bool = "warn" +needless_continue = "warn" +needless_for_each = "warn" +needless_raw_string_hashes = "warn" +needless_raw_strings = "warn" +negative_feature_names = "warn" +no_mangle_with_rust_abi = "warn" +option_as_ref_cloned = "warn" +pub_underscore_fields = "warn" +rc_buffer = "warn" +rc_mutex = "warn" +redundant_else = "warn" +redundant_feature_names = "warn" +ref_patterns = "warn" +rest_pat_in_fully_bound_structs = "warn" +semicolon_outside_block = "warn" +str_to_string = "warn" +string_lit_chars_any = "warn" +string_to_string = "warn" +struct_field_names = "warn" +tests_outside_test_module = "warn" +todo = "warn" +trivially_copy_pass_by_ref = "warn" +try_err = "warn" +# undocumented_unsafe_blocks = "warn" +uninlined_format_args = "warn" +unnecessary_join = "warn" +# unnecessary_safety_doc = "warn" +unnecessary_self_imports = "warn" +unneeded_field_pattern = "warn" +unnested_or_patterns = "warn" +unseparated_literal_suffix = "warn" +unused_self = "warn" +used_underscore_binding = "warn" +wildcard_dependencies = "warn" +zero_sized_map_values = "warn" + +[workspace.lints.rustdoc] +unescaped_backticks = "warn" diff --git a/clippy.toml b/clippy.toml new file mode 100644 index 000000000..0ac765717 --- /dev/null +++ b/clippy.toml @@ -0,0 +1 @@ +semicolon-outside-block-ignore-multiline = true diff --git a/crates/java_string/Cargo.toml b/crates/java_string/Cargo.toml index 0465f63c2..b555e5a8c 100644 --- a/crates/java_string/Cargo.toml +++ b/crates/java_string/Cargo.toml @@ -14,3 +14,6 @@ serde = ["dep:serde"] [dependencies] serde = { workspace = true, optional = true } + +[lints] +workspace = true diff --git a/crates/java_string/src/cesu8.rs b/crates/java_string/src/cesu8.rs index eb94ee6c1..34ee4a1b1 100644 --- a/crates/java_string/src/cesu8.rs +++ b/crates/java_string/src/cesu8.rs @@ -114,7 +114,7 @@ impl JavaStr { impl JavaString { /// Converts from Java's [modified UTF-8](https://docs.oracle.com/javase/8/docs/api/java/io/DataInput.html#modified-utf-8) format to a `JavaString`. /// - /// See [JavaStr::from_modified_utf8]. + /// See [`JavaStr::from_modified_utf8`]. #[inline] pub fn from_modified_utf8(bytes: Vec) -> Result { match JavaString::from_full_utf8(bytes) { @@ -184,6 +184,7 @@ impl JavaString { } 3 => { let third = next_cont!(Some(2)); + #[allow(clippy::unnested_or_patterns)] // Justification: readability match (first, second) { // These are valid UTF-8, so pass them through. (0xe0, 0xa0..=0xbf) @@ -227,7 +228,7 @@ impl JavaString { /// Converts to Java's [modified UTF-8](https://docs.oracle.com/javase/8/docs/api/java/io/DataInput.html#modified-utf-8) format. /// - /// See [JavaStr::to_modified_utf8]. + /// See [`JavaStr::to_modified_utf8`]. #[inline] #[must_use] pub fn into_modified_utf8(self) -> Vec { @@ -241,7 +242,7 @@ impl JavaString { #[inline] fn dec_surrogate(second: u8, third: u8) -> u32 { - 0xd000 | ((second & CONT_MASK) as u32) << 6 | (third & CONT_MASK) as u32 + 0xd000 | u32::from(second & CONT_MASK) << 6 | u32::from(third & CONT_MASK) } #[inline] @@ -255,7 +256,7 @@ fn dec_surrogates(second: u8, third: u8, fifth: u8, sixth: u8) -> [u8; 4] { // Convert to UTF-8. // 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx [ - 0b1111_0000u8 | ((c & 0b1_1100_0000_0000_0000_0000) >> 18) as u8, + 0b1111_0000_u8 | ((c & 0b1_1100_0000_0000_0000_0000) >> 18) as u8, TAG_CONT | ((c & 0b0_0011_1111_0000_0000_0000) >> 12) as u8, TAG_CONT | ((c & 0b0_0000_0000_1111_1100_0000) >> 6) as u8, TAG_CONT | (c & 0b0_0000_0000_0000_0011_1111) as u8, diff --git a/crates/java_string/src/char.rs b/crates/java_string/src/char.rs index f338a25c4..f21e7d7b7 100644 --- a/crates/java_string/src/char.rs +++ b/crates/java_string/src/char.rs @@ -170,7 +170,7 @@ impl JavaCodePoint { } /// Encodes this `JavaCodePoint` into semi UTF-8, that is, UTF-8 with - /// surrogate code points. See also [char::encode_utf8]. + /// surrogate code points. See also [`char::encode_utf8`]. /// /// ``` /// # use java_string::JavaCodePoint; diff --git a/crates/java_string/src/iter.rs b/crates/java_string/src/iter.rs index 3762f6d72..f93605393 100644 --- a/crates/java_string/src/iter.rs +++ b/crates/java_string/src/iter.rs @@ -649,17 +649,17 @@ where } match self.next_match_back() { - Some((index, len)) => unsafe { + Some((index, len)) => { // SAFETY: pattern guarantees valid indices - let elt = self.haystack.get_unchecked(index + len..self.end); + let elt = unsafe { self.haystack.get_unchecked(index + len..self.end) }; self.end = index + len; Some(elt) - }, - None => unsafe { - // SAFETY: `self.start` and `self.end` always lie on unicode boundaries. + } + None => { self.finished = true; - Some(self.haystack.get_unchecked(self.start..self.end)) - }, + // SAFETY: `self.start` and `self.end` always lie on unicode boundaries. + Some(unsafe { self.haystack.get_unchecked(self.start..self.end) }) + } } } } diff --git a/crates/java_string/src/owned.rs b/crates/java_string/src/owned.rs index 786855b58..060346c10 100644 --- a/crates/java_string/src/owned.rs +++ b/crates/java_string/src/owned.rs @@ -199,7 +199,7 @@ impl JavaString { /// assert!(string_with_error.into_string().is_err()); /// ``` pub fn into_string(self) -> Result { - run_utf8_full_validation_from_semi(self.as_bytes()).map(|_| unsafe { + run_utf8_full_validation_from_semi(self.as_bytes()).map(|()| unsafe { // SAFETY: validation succeeded self.into_string_unchecked() }) @@ -357,9 +357,8 @@ impl JavaString { /// ``` #[inline] pub fn remove(&mut self, idx: usize) -> JavaCodePoint { - let ch = match self[idx..].chars().next() { - Some(ch) => ch, - None => panic!("cannot remove a char from the end of a string"), + let Some(ch) = self[idx..].chars().next() else { + panic!("cannot remove a char from the end of a string") }; let next = idx + ch.len_utf8(); @@ -829,13 +828,13 @@ impl Extend for JavaString { impl<'a> Extend<&'a char> for JavaString { fn extend>(&mut self, iter: T) { - self.extend(iter.into_iter().cloned()) + self.extend(iter.into_iter().copied()) } } impl<'a> Extend<&'a JavaCodePoint> for JavaString { fn extend>(&mut self, iter: T) { - self.extend(iter.into_iter().cloned()) + self.extend(iter.into_iter().copied()) } } diff --git a/crates/java_string/src/pattern.rs b/crates/java_string/src/pattern.rs index 06cc78041..a17d374a9 100644 --- a/crates/java_string/src/pattern.rs +++ b/crates/java_string/src/pattern.rs @@ -32,21 +32,13 @@ unsafe impl JavaStrPattern for char { #[inline] fn prefix_len_in(&mut self, haystack: &JavaStr) -> Option { let ch = haystack.chars().next()?; - if ch == *self { - Some(ch.len_utf8()) - } else { - None - } + (ch == *self).then(|| ch.len_utf8()) } #[inline] fn suffix_len_in(&mut self, haystack: &JavaStr) -> Option { let ch = haystack.chars().next_back()?; - if ch == *self { - Some(ch.len_utf8()) - } else { - None - } + (ch == *self).then(|| ch.len_utf8()) } #[inline] @@ -68,21 +60,13 @@ unsafe impl JavaStrPattern for JavaCodePoint { #[inline] fn prefix_len_in(&mut self, haystack: &JavaStr) -> Option { let ch = haystack.chars().next()?; - if ch == *self { - Some(ch.len_utf8()) - } else { - None - } + (ch == *self).then(|| ch.len_utf8()) } #[inline] fn suffix_len_in(&mut self, haystack: &JavaStr) -> Option { let ch = haystack.chars().next_back()?; - if ch == *self { - Some(ch.len_utf8()) - } else { - None - } + (ch == *self).then(|| ch.len_utf8()) } #[inline] @@ -103,20 +87,18 @@ unsafe impl JavaStrPattern for JavaCodePoint { unsafe impl JavaStrPattern for &str { #[inline] fn prefix_len_in(&mut self, haystack: &JavaStr) -> Option { - if haystack.as_bytes().starts_with(self.as_bytes()) { - Some(self.len()) - } else { - None - } + haystack + .as_bytes() + .starts_with(self.as_bytes()) + .then_some(self.len()) } #[inline] fn suffix_len_in(&mut self, haystack: &JavaStr) -> Option { - if haystack.as_bytes().ends_with(self.as_bytes()) { - Some(self.len()) - } else { - None - } + haystack + .as_bytes() + .ends_with(self.as_bytes()) + .then_some(self.len()) } #[inline] @@ -133,20 +115,18 @@ unsafe impl JavaStrPattern for &str { unsafe impl JavaStrPattern for &JavaStr { #[inline] fn prefix_len_in(&mut self, haystack: &JavaStr) -> Option { - if haystack.as_bytes().starts_with(self.as_bytes()) { - Some(self.len()) - } else { - None - } + haystack + .as_bytes() + .starts_with(self.as_bytes()) + .then(|| self.len()) } #[inline] fn suffix_len_in(&mut self, haystack: &JavaStr) -> Option { - if haystack.as_bytes().ends_with(self.as_bytes()) { - Some(self.len()) - } else { - None - } + haystack + .as_bytes() + .ends_with(self.as_bytes()) + .then(|| self.len()) } #[inline] @@ -167,21 +147,13 @@ where #[inline] fn prefix_len_in(&mut self, haystack: &JavaStr) -> Option { let ch = haystack.chars().next()?; - if self(ch) { - Some(ch.len_utf8()) - } else { - None - } + self(ch).then(|| ch.len_utf8()) } #[inline] fn suffix_len_in(&mut self, haystack: &JavaStr) -> Option { let ch = haystack.chars().next_back()?; - if self(ch) { - Some(ch.len_utf8()) - } else { - None - } + self(ch).then(|| ch.len_utf8()) } #[inline] @@ -205,21 +177,13 @@ unsafe impl JavaStrPattern for &[char] { #[inline] fn prefix_len_in(&mut self, haystack: &JavaStr) -> Option { let ch = haystack.chars().next()?; - if self.iter().any(|c| ch == *c) { - Some(ch.len_utf8()) - } else { - None - } + self.iter().any(|c| ch == *c).then(|| ch.len_utf8()) } #[inline] fn suffix_len_in(&mut self, haystack: &JavaStr) -> Option { let ch = haystack.chars().next_back()?; - if self.iter().any(|c| ch == *c) { - Some(ch.len_utf8()) - } else { - None - } + self.iter().any(|c| ch == *c).then(|| ch.len_utf8()) } #[inline] @@ -243,21 +207,13 @@ unsafe impl JavaStrPattern for &[JavaCodePoint] { #[inline] fn prefix_len_in(&mut self, haystack: &JavaStr) -> Option { let ch = haystack.chars().next()?; - if self.contains(&ch) { - Some(ch.len_utf8()) - } else { - None - } + self.contains(&ch).then(|| ch.len_utf8()) } #[inline] fn suffix_len_in(&mut self, haystack: &JavaStr) -> Option { let ch = haystack.chars().next_back()?; - if self.contains(&ch) { - Some(ch.len_utf8()) - } else { - None - } + self.contains(&ch).then(|| ch.len_utf8()) } #[inline] diff --git a/crates/java_string/src/serde.rs b/crates/java_string/src/serde.rs index e1c152d11..44281c4fe 100644 --- a/crates/java_string/src/serde.rs +++ b/crates/java_string/src/serde.rs @@ -175,7 +175,7 @@ impl<'de> Visitor<'de> for JavaCodePointVisitor { where E: Error, { - self.visit_i32(v as i32) + self.visit_i32(v.into()) } #[inline] @@ -183,7 +183,7 @@ impl<'de> Visitor<'de> for JavaCodePointVisitor { where E: Error, { - self.visit_i32(v as i32) + self.visit_i32(v.into()) } fn visit_i32(self, v: i32) -> Result @@ -191,7 +191,7 @@ impl<'de> Visitor<'de> for JavaCodePointVisitor { E: Error, { if v < 0 { - Err(Error::invalid_value(Unexpected::Signed(v as i64), &self)) + Err(Error::invalid_value(Unexpected::Signed(v.into()), &self)) } else { self.visit_u32(v as u32) } @@ -213,7 +213,7 @@ impl<'de> Visitor<'de> for JavaCodePointVisitor { where E: Error, { - self.visit_u32(v as u32) + self.visit_u32(v.into()) } #[inline] @@ -221,7 +221,7 @@ impl<'de> Visitor<'de> for JavaCodePointVisitor { where E: Error, { - self.visit_u32(v as u32) + self.visit_u32(v.into()) } fn visit_u32(self, v: u32) -> Result @@ -229,17 +229,16 @@ impl<'de> Visitor<'de> for JavaCodePointVisitor { E: Error, { JavaCodePoint::from_u32(v) - .ok_or_else(|| Error::invalid_value(Unexpected::Unsigned(v as u64), &self)) + .ok_or_else(|| Error::invalid_value(Unexpected::Unsigned(v.into()), &self)) } fn visit_u64(self, v: u64) -> Result where E: Error, { - if v > u32::MAX as u64 { - Err(Error::invalid_value(Unexpected::Unsigned(v), &self)) - } else { - self.visit_u32(v as u32) + match u32::try_from(v) { + Ok(v) => self.visit_u32(v), + Err(_) => Err(Error::invalid_value(Unexpected::Unsigned(v), &self)) } } diff --git a/crates/java_string/src/slice.rs b/crates/java_string/src/slice.rs index d5dfd17ca..ad976ed40 100644 --- a/crates/java_string/src/slice.rs +++ b/crates/java_string/src/slice.rs @@ -23,8 +23,8 @@ use crate::{ SplitInclusive, SplitN, SplitTerminator, SplitWhitespace, Utf8Error, }; -#[repr(transparent)] #[derive(PartialEq, Eq, PartialOrd, Ord)] +#[repr(transparent)] pub struct JavaStr { inner: [u8], } @@ -1435,7 +1435,7 @@ impl JavaStr { self.transform_string(str::to_lowercase, |ch| ch) } - /// See [str::to_uppercase]. + /// See [`str::to_uppercase`]. /// /// ``` /// # use java_string::{JavaCodePoint, JavaStr, JavaString}; @@ -1459,21 +1459,21 @@ impl JavaStr { self.transform_string(str::to_uppercase, |ch| ch) } - /// See [str::trim]. + /// See [`str::trim`]. #[inline] #[must_use] pub fn trim(&self) -> &JavaStr { self.trim_matches(|c: JavaCodePoint| c.is_whitespace()) } - /// See [str::trim_end]. + /// See [`str::trim_end`]. #[inline] #[must_use] pub fn trim_end(&self) -> &JavaStr { self.trim_end_matches(|c: JavaCodePoint| c.is_whitespace()) } - /// See [str::trim_end_matches]. + /// See [`str::trim_end_matches`]. /// /// ``` /// # use java_string::{JavaCodePoint, JavaStr}; @@ -1509,7 +1509,7 @@ impl JavaStr { str } - /// See [str::trim_matches]. + /// See [`str::trim_matches`]. /// /// ``` /// # use java_string::{JavaCodePoint, JavaStr}; @@ -1549,14 +1549,14 @@ impl JavaStr { str } - /// See [str::trim_start]. + /// See [`str::trim_start`]. #[inline] #[must_use] pub fn trim_start(&self) -> &JavaStr { self.trim_start_matches(|c: JavaCodePoint| c.is_whitespace()) } - /// See [str::trim_start_matches]. + /// See [`str::trim_start_matches`]. /// /// ``` /// # use java_string::{JavaCodePoint, JavaStr}; @@ -1987,35 +1987,35 @@ impl PartialEq for str { impl<'a> PartialEq for &'a str { #[inline] fn eq(&self, other: &JavaStr) -> bool { - *self == other + self.as_bytes() == &other.inner } } impl PartialEq for JavaStr { #[inline] fn eq(&self, other: &str) -> bool { - self == JavaStr::from_str(other) + &self.inner == other.as_bytes() } } impl<'a> PartialEq<&'a str> for JavaStr { #[inline] fn eq(&self, other: &&'a str) -> bool { - self == *other + &self.inner == other.as_bytes() } } impl<'a> PartialEq for &'a JavaStr { #[inline] fn eq(&self, other: &JavaStr) -> bool { - *self == other + self.inner == other.inner } } impl<'a> PartialEq<&'a JavaStr> for JavaStr { #[inline] fn eq(&self, other: &&'a JavaStr) -> bool { - self == *other + self.inner == other.inner } } @@ -2067,20 +2067,14 @@ pub unsafe trait JavaStrSliceIndex: private_slice_index::Sealed + Sized { #[inline] fn get(self, slice: &JavaStr) -> Option<&JavaStr> { - if self.check_bounds(slice) { - Some(unsafe { &*self.get_unchecked(slice) }) - } else { - None - } + self.check_bounds(slice) + .then(|| unsafe { &*self.get_unchecked(slice) }) } #[inline] fn get_mut(self, slice: &mut JavaStr) -> Option<&mut JavaStr> { - if self.check_bounds(slice) { - Some(unsafe { &mut *self.get_unchecked_mut(slice) }) - } else { - None - } + self.check_bounds(slice) + .then(|| unsafe { &mut *self.get_unchecked_mut(slice) }) } #[inline] diff --git a/crates/java_string/src/validations.rs b/crates/java_string/src/validations.rs index 102783f55..d901863f3 100644 --- a/crates/java_string/src/validations.rs +++ b/crates/java_string/src/validations.rs @@ -31,7 +31,7 @@ pub(crate) unsafe fn next_code_point<'a, I: Iterator>(bytes: &mut // Decode UTF-8 let x = *bytes.next()?; if x < 128 { - return Some(x as u32); + return Some(x.into()); } // Multibyte case follows @@ -48,7 +48,7 @@ pub(crate) unsafe fn next_code_point<'a, I: Iterator>(bytes: &mut // SAFETY: `bytes` produces an UTF-8-like string, // so the iterator must produce a value here. let z = unsafe { *bytes.next().unwrap_unchecked() }; - let y_z = utf8_acc_cont_byte((y & CONT_MASK) as u32, z); + let y_z = utf8_acc_cont_byte((y & CONT_MASK).into(), z); ch = init << 12 | y_z; if x >= 0xf0 { // [x y z w] case @@ -72,7 +72,7 @@ pub(crate) unsafe fn next_code_point_reverse<'a, I: DoubleEndedIterator Option { // Decode UTF-8 let w = match *bytes.next_back()? { - next_byte if next_byte < 128 => return Some(next_byte as u32), + next_byte if next_byte < 128 => return Some(next_byte.into()), back_byte => back_byte, }; @@ -258,7 +258,7 @@ pub(crate) const fn utf8_char_width(first_byte: u8) -> usize { 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ]; - UTF8_CHAR_WIDTH[first_byte as usize] as _ + UTF8_CHAR_WIDTH[first_byte as usize] as usize } #[inline] @@ -284,11 +284,7 @@ pub(crate) fn slice_error_fail(s: &JavaStr, begin: usize, end: usize) -> ! { // 2. begin <= end assert!( begin <= end, - "begin <= end ({} <= {}) when slicing `{}`{}", - begin, - end, - s_trunc, - ellipsis + "begin <= end ({begin} <= {end}) when slicing `{s_trunc}`{ellipsis}", ); // 3. character boundary @@ -303,8 +299,8 @@ pub(crate) fn slice_error_fail(s: &JavaStr, begin: usize, end: usize) -> ! { let ch = s[char_start..].chars().next().unwrap(); let char_range = char_start..char_start + ch.len_utf8(); panic!( - "byte index {} is not a char boundary; it is inside {:?} (bytes {:?}) of `{}`{}", - index, ch, char_range, s_trunc, ellipsis + "byte index {index} is not a char boundary; it is inside {ch:?} (bytes {char_range:?}) of \ + `{s_trunc}`{ellipsis}", ); } diff --git a/crates/valence_build_utils/src/lib.rs b/crates/valence_build_utils/src/lib.rs index 775f82a75..2128625d6 100644 --- a/crates/valence_build_utils/src/lib.rs +++ b/crates/valence_build_utils/src/lib.rs @@ -24,6 +24,14 @@ use std::{env, fs}; use anyhow::Context; use proc_macro2::{Ident, Span, TokenStream}; +/// Write a Rust file to the build script output directory. The file is formatted if `rustfmt` is available. +/// +/// To include the file outside the build script, use +/// +/// ```ignore +/// include!(concat!(env!("OUT_DIR"), "/name_of_the_file.rs")); +/// ```` +/// Where `name_of_the_file.rs` is the value of `out_file`. pub fn write_generated_file(content: TokenStream, out_file: &str) -> anyhow::Result<()> { let out_dir = env::var_os("OUT_DIR").context("failed to get OUT_DIR env var")?; let path = Path::new(&out_dir).join(out_file); @@ -40,6 +48,10 @@ pub fn write_generated_file(content: TokenStream, out_file: &str) -> anyhow::Res /// Parses a [`proc_macro2::Ident`] from a `str`. Rust keywords are prepended /// with underscores to make them valid identifiers. +/// +/// # Panics +/// +/// Panics if a valid identifier could not be formed. pub fn ident(s: impl AsRef) -> Ident { let s = s.as_ref().trim(); diff --git a/crates/valence_ident/Cargo.toml b/crates/valence_ident/Cargo.toml index 09b5220ab..13887a8ce 100644 --- a/crates/valence_ident/Cargo.toml +++ b/crates/valence_ident/Cargo.toml @@ -12,3 +12,6 @@ license.workspace = true thiserror.workspace = true serde.workspace = true valence_ident_macros.workspace = true + +[lints] +workspace = true diff --git a/crates/valence_ident/src/lib.rs b/crates/valence_ident/src/lib.rs index 10925f0e9..994cfac85 100644 --- a/crates/valence_ident/src/lib.rs +++ b/crates/valence_ident/src/lib.rs @@ -57,7 +57,7 @@ pub struct Ident { pub struct IdentError(pub String); impl<'a> Ident> { - pub fn new(string: impl Into>) -> Result { + pub fn new>>(string: S) -> Result { parse(string.into()) } } diff --git a/crates/valence_ident_macros/Cargo.toml b/crates/valence_ident_macros/Cargo.toml index f83651c8c..98f26bb90 100644 --- a/crates/valence_ident_macros/Cargo.toml +++ b/crates/valence_ident_macros/Cargo.toml @@ -15,3 +15,6 @@ proc-macro = true proc-macro2.workspace = true quote.workspace = true syn = { workspace = true, features = ["full"] } + +[lints] +workspace = true diff --git a/crates/valence_nbt/Cargo.toml b/crates/valence_nbt/Cargo.toml index 3c60fd038..bdef82083 100644 --- a/crates/valence_nbt/Cargo.toml +++ b/crates/valence_nbt/Cargo.toml @@ -13,7 +13,6 @@ repository.workspace = true binary = ["dep:byteorder", "dep:cesu8"] java_string = ["dep:java_string"] snbt = [] -# When enabled, the order of fields in compounds are preserved. preserve_order = ["dep:indexmap"] serde = ["dep:serde", "dep:thiserror", "indexmap?/serde"] @@ -30,3 +29,6 @@ valence_ident = { workspace = true, optional = true } [dev-dependencies] pretty_assertions.workspace = true serde_json.workspace = true + +[lints] +workspace = true diff --git a/crates/valence_nbt/src/binary.rs b/crates/valence_nbt/src/binary.rs index d17f95a37..8aa6bd15e 100644 --- a/crates/valence_nbt/src/binary.rs +++ b/crates/valence_nbt/src/binary.rs @@ -18,13 +18,13 @@ //! //! let mut buf = vec![]; //! -//! to_binary(&c, &mut buf, "").unwrap(); +//! to_binary(&mut buf, "", &c).unwrap(); //! ``` //! //! Decode NBT data from its binary form. //! //! ``` -//! use valence_nbt::{compound, from_binary, Compound}; +//! use valence_nbt::{compound, from_binary, Compound, Value}; //! //! let some_bytes = [10, 0, 0, 3, 0, 3, 105, 110, 116, 0, 0, 222, 173, 0]; //! @@ -32,22 +32,20 @@ //! "int" => 0xdead //! }; //! -//! let (nbt, root_name) = from_binary(&mut some_bytes.as_slice()).unwrap(); +//! let (root_name, nbt) = from_binary(&mut some_bytes.as_slice()).unwrap().unwrap(); //! -//! assert_eq!(nbt, expected_value); +//! assert_eq!(nbt, Value::from(expected_value)); //! assert_eq!(root_name, ""); //! ``` mod decode; mod encode; -mod error; mod modified_utf8; #[cfg(test)] mod tests; pub use decode::{from_binary, FromModifiedUtf8, FromModifiedUtf8Error}; -pub use encode::{to_binary, written_size, ToModifiedUtf8}; -pub use error::*; +pub use encode::{to_binary, ToModifiedUtf8}; use crate::Tag; diff --git a/crates/valence_nbt/src/binary/decode.rs b/crates/valence_nbt/src/binary/decode.rs index 607132084..1462fc522 100644 --- a/crates/valence_nbt/src/binary/decode.rs +++ b/crates/valence_nbt/src/binary/decode.rs @@ -1,50 +1,47 @@ use std::borrow::Cow; use std::hash::Hash; -use std::{fmt, mem}; +use std::{fmt, io, mem}; -use byteorder::{BigEndian, ReadBytesExt}; - -use super::{Error, Result}; +use crate::conv::u8_slice_as_i8_slice; use crate::tag::Tag; -use crate::{Compound, List, Value}; +use crate::{Compound, Error, List, Result, Value}; -/// Decodes uncompressed NBT binary data from the provided slice. +/// Decode an NBT value from the given buffer of bytes. /// -/// The string returned in the tuple is the name of the root compound -/// (typically the empty string). -pub fn from_binary<'de, S>(slice: &mut &'de [u8]) -> Result<(Compound, S)> +/// Returns both the root NBT value and the root name (typically the empty +/// string). If the root value is of type [`Tag::End`], then `None` is returned. +/// If the data is malformed or the reader returns an error, then an error is +/// returned. +pub fn from_binary<'a, S>(reader: impl ReadBytes<'a>) -> Result)>> where - S: FromModifiedUtf8<'de> + Hash + Ord, + S: FromModifiedUtf8<'a> + Hash + Ord, { - let mut state = DecodeState { slice, depth: 0 }; + let mut state = DecodeState { reader, depth: 0 }; - let root_tag = state.read_tag()?; + let tag = state.read_tag()?; - if root_tag != Tag::Compound { - return Err(Error::new_owned(format!( - "expected root tag for compound (got {})", - root_tag.name(), - ))); + if tag == Tag::End { + return Ok(None); } - let root_name = state.read_string::()?; - let root = state.read_compound()?; + let name = state.read_string::()?; + let value = state.read_value::(tag)?; debug_assert_eq!(state.depth, 0); - Ok((root, root_name)) + Ok(Some((name, value))) } /// Maximum recursion depth to prevent overflowing the call stack. const MAX_DEPTH: usize = 512; -struct DecodeState<'a, 'de> { - slice: &'a mut &'de [u8], +struct DecodeState { + reader: R, /// Current recursion depth. depth: usize, } -impl<'de> DecodeState<'_, 'de> { +impl<'a, R: ReadBytes<'a>> DecodeState { #[inline] fn check_depth(&mut self, f: impl FnOnce(&mut Self) -> Result) -> Result { if self.depth >= MAX_DEPTH { @@ -58,7 +55,7 @@ impl<'de> DecodeState<'_, 'de> { } fn read_tag(&mut self) -> Result { - match self.slice.read_u8()? { + match self.read_byte()? { 0 => Ok(Tag::End), 1 => Ok(Tag::Byte), 2 => Ok(Tag::Short), @@ -76,53 +73,69 @@ impl<'de> DecodeState<'_, 'de> { } } + /// Read a value identified by the given tag. + /// + /// # Panics + /// + /// Panics if the tag is [`Tag::End`]. + #[track_caller] fn read_value(&mut self, tag: Tag) -> Result> where - S: FromModifiedUtf8<'de> + Hash + Ord, + S: FromModifiedUtf8<'a> + Hash + Ord, { - match tag { - Tag::End => unreachable!("illegal TAG_End argument"), - Tag::Byte => Ok(self.read_byte()?.into()), - Tag::Short => Ok(self.read_short()?.into()), - Tag::Int => Ok(self.read_int()?.into()), - Tag::Long => Ok(self.read_long()?.into()), - Tag::Float => Ok(self.read_float()?.into()), - Tag::Double => Ok(self.read_double()?.into()), - Tag::ByteArray => Ok(self.read_byte_array()?.into()), - Tag::String => Ok(Value::String(self.read_string::()?)), - Tag::List => self.check_depth(|st| Ok(st.read_any_list::()?.into())), - Tag::Compound => self.check_depth(|st| Ok(st.read_compound::()?.into())), - Tag::IntArray => Ok(self.read_int_array()?.into()), - Tag::LongArray => Ok(self.read_long_array()?.into()), - } + Ok(match tag { + Tag::End => panic!("cannot read value of Tag_END"), + Tag::Byte => self.read_byte()?.into(), + Tag::Short => self.read_short()?.into(), + Tag::Int => self.read_int()?.into(), + Tag::Long => self.read_long()?.into(), + Tag::Float => self.read_float()?.into(), + Tag::Double => self.read_double()?.into(), + Tag::ByteArray => self.read_byte_array()?.into(), + Tag::String => Value::String(self.read_string::()?), + Tag::List => self.check_depth(|st| st.read_any_list::())?.into(), + Tag::Compound => self.check_depth(|st| st.read_compound::())?.into(), + Tag::IntArray => self.read_int_array()?.into(), + Tag::LongArray => self.read_long_array()?.into(), + }) } fn read_byte(&mut self) -> Result { - Ok(self.slice.read_i8()?) + Ok(self.reader.read_bytes(1)?[0] as i8) } fn read_short(&mut self) -> Result { - Ok(self.slice.read_i16::()?) + Ok(i16::from_be_bytes( + self.reader.read_bytes(2)?.try_into().unwrap(), + )) } fn read_int(&mut self) -> Result { - Ok(self.slice.read_i32::()?) + Ok(i32::from_be_bytes( + self.reader.read_bytes(4)?.try_into().unwrap(), + )) } fn read_long(&mut self) -> Result { - Ok(self.slice.read_i64::()?) + Ok(i64::from_be_bytes( + self.reader.read_bytes(8)?.try_into().unwrap(), + )) } fn read_float(&mut self) -> Result { - Ok(self.slice.read_f32::()?) + Ok(f32::from_be_bytes( + self.reader.read_bytes(4)?.try_into().unwrap(), + )) } fn read_double(&mut self) -> Result { - Ok(self.slice.read_f64::()?) + Ok(f64::from_be_bytes( + self.reader.read_bytes(8)?.try_into().unwrap(), + )) } fn read_byte_array(&mut self) -> Result> { - let len = self.slice.read_i32::()?; + let len = self.read_int()?; if len.is_negative() { return Err(Error::new_owned(format!( @@ -130,46 +143,38 @@ impl<'de> DecodeState<'_, 'de> { ))); } - if len as usize > self.slice.len() { + if len as usize > self.reader.remaining() { return Err(Error::new_owned(format!( "byte array length of {len} exceeds remainder of input" ))); } - let (left, right) = self.slice.split_at(len as usize); + let slice = u8_slice_as_i8_slice(self.reader.read_bytes(len as usize)?); - let array = left.iter().map(|b| *b as i8).collect(); - *self.slice = right; + debug_assert_eq!(slice.len(), len as usize); - Ok(array) + Ok(slice.into()) } fn read_string(&mut self) -> Result where - S: FromModifiedUtf8<'de>, + S: FromModifiedUtf8<'a>, { - let len = self.slice.read_u16::()?.into(); + let len = self.read_short()? as usize; - if len > self.slice.len() { + if len > self.reader.remaining() { return Err(Error::new_owned(format!( "string of length {len} exceeds remainder of input" ))); } - let (left, right) = self.slice.split_at(len); - - match S::from_modified_utf8(left) { - Ok(str) => { - *self.slice = right; - Ok(str) - } - Err(_) => Err(Error::new_static("could not decode modified UTF-8 data")), - } + S::from_modified_utf8(self.reader.read_bytes(len)?) + .map_err(|_| Error::new_static("could not decode modified UTF-8 data")) } fn read_any_list(&mut self) -> Result> where - S: FromModifiedUtf8<'de> + Hash + Ord, + S: FromModifiedUtf8<'a> + Hash + Ord, { match self.read_tag()? { Tag::End => match self.read_int()? { @@ -178,49 +183,40 @@ impl<'de> DecodeState<'_, 'de> { "TAG_End list with nonzero length of {len}" ))), }, - Tag::Byte => Ok(self.read_list(Tag::Byte, 1, |st| st.read_byte())?.into()), - Tag::Short => Ok(self.read_list(Tag::Short, 2, |st| st.read_short())?.into()), - Tag::Int => Ok(self.read_list(Tag::Int, 4, |st| st.read_int())?.into()), - Tag::Long => Ok(self.read_list(Tag::Long, 8, |st| st.read_long())?.into()), - Tag::Float => Ok(self.read_list(Tag::Float, 4, |st| st.read_float())?.into()), - Tag::Double => Ok(self - .read_list(Tag::Double, 8, |st| st.read_double())? - .into()), + Tag::Byte => Ok(self.read_list(Tag::Byte, |st| st.read_byte())?.into()), + Tag::Short => Ok(self.read_list(Tag::Short, |st| st.read_short())?.into()), + Tag::Int => Ok(self.read_list(Tag::Int, |st| st.read_int())?.into()), + Tag::Long => Ok(self.read_list(Tag::Long, |st| st.read_long())?.into()), + Tag::Float => Ok(self.read_list(Tag::Float, |st| st.read_float())?.into()), + Tag::Double => Ok(self.read_list(Tag::Double, |st| st.read_double())?.into()), Tag::ByteArray => Ok(self - .read_list(Tag::ByteArray, 0, |st| st.read_byte_array())? + .read_list(Tag::ByteArray, |st| st.read_byte_array())? .into()), Tag::String => Ok(List::String( - self.read_list(Tag::String, 0, |st| st.read_string::())?, + self.read_list(Tag::String, |st| st.read_string::())?, )), Tag::List => self.check_depth(|st| { Ok(st - .read_list(Tag::List, 0, |st| st.read_any_list::())? + .read_list(Tag::List, |st| st.read_any_list::())? .into()) }), Tag::Compound => self.check_depth(|st| { Ok(st - .read_list(Tag::Compound, 0, |st| st.read_compound::())? + .read_list(Tag::Compound, |st| st.read_compound::())? .into()) }), Tag::IntArray => Ok(self - .read_list(Tag::IntArray, 0, |st| st.read_int_array())? + .read_list(Tag::IntArray, |st| st.read_int_array())? .into()), Tag::LongArray => Ok(self - .read_list(Tag::LongArray, 0, |st| st.read_long_array())? + .read_list(Tag::LongArray, |st| st.read_long_array())? .into()), } } /// Assumes the element tag has already been read. - /// - /// `min_elem_size` is the minimum size of the list element when encoded. #[inline] - fn read_list( - &mut self, - elem_type: Tag, - elem_size: usize, - mut read_elem: F, - ) -> Result> + fn read_list(&mut self, elem_type: Tag, mut read_elem: F) -> Result> where F: FnMut(&mut Self) -> Result, { @@ -233,16 +229,7 @@ impl<'de> DecodeState<'_, 'de> { ))); } - // Ensure we don't reserve more than the maximum amount of memory required given - // the size of the remaining input. - if len as u64 * elem_size as u64 > self.slice.len() as u64 { - return Err(Error::new_owned(format!( - "{} list of length {len} exceeds remainder of input", - elem_type.name() - ))); - } - - let mut list = Vec::with_capacity(if elem_size == 0 { 0 } else { len as usize }); + let mut list = Vec::with_capacity(cautious_capacity::(len as usize)); for _ in 0..len { list.push(read_elem(self)?); @@ -253,7 +240,7 @@ impl<'de> DecodeState<'_, 'de> { fn read_compound(&mut self) -> Result> where - S: FromModifiedUtf8<'de> + Hash + Ord, + S: FromModifiedUtf8<'a> + Hash + Ord, { let mut compound = Compound::new(); @@ -276,13 +263,15 @@ impl<'de> DecodeState<'_, 'de> { ))); } - if len as u64 * mem::size_of::() as u64 > self.slice.len() as u64 { + if len as u64 * 4 > self.reader.remaining() as u64 { return Err(Error::new_owned(format!( "int array of length {len} exceeds remainder of input" ))); } let mut array = Vec::with_capacity(len as usize); + + // TODO: SIMDify the endian swapping? for _ in 0..len { array.push(self.read_int()?); } @@ -299,13 +288,15 @@ impl<'de> DecodeState<'_, 'de> { ))); } - if len as u64 * mem::size_of::() as u64 > self.slice.len() as u64 { + if len as u64 * 8 > self.reader.remaining() as u64 { return Err(Error::new_owned(format!( "long array of length {len} exceeds remainder of input" ))); } let mut array = Vec::with_capacity(len as usize); + + // TODO: SIMDify the endian swapping? for _ in 0..len { array.push(self.read_long()?); } @@ -314,60 +305,123 @@ impl<'de> DecodeState<'_, 'de> { } } -#[derive(Copy, Clone, Debug)] -pub struct FromModifiedUtf8Error; +/// Prevents preallocating too much memory in case we get a malicious or invalid +/// sequence length. +fn cautious_capacity(size_hint: usize) -> usize { + // TODO: How large can we make this? + const MAX_PREALLOC_BYTES: usize = 2048; -impl fmt::Display for FromModifiedUtf8Error { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str("could not decode modified UTF-8 data") + if mem::size_of::() == 0 { + 0 + } else { + size_hint.min(MAX_PREALLOC_BYTES / mem::size_of::()) } } -impl std::error::Error for FromModifiedUtf8Error {} +pub trait ReadBytes<'a> { + fn read_bytes(&mut self, count: usize) -> io::Result<&'a [u8]>; + + /// Returns the number of remaining bytes in the input. + fn remaining(&self) -> usize; +} + +impl<'a, T> ReadBytes<'a> for &mut T +where + T: ReadBytes<'a>, +{ + fn read_bytes(&mut self, count: usize) -> io::Result<&'a [u8]> { + (**self).read_bytes(count) + } + + fn remaining(&self) -> usize { + (**self).remaining() + } +} + +impl<'a> ReadBytes<'a> for &'a [u8] { + fn read_bytes(&mut self, count: usize) -> io::Result<&'a [u8]> { + if count > self.len() { + return Err(io::ErrorKind::UnexpectedEof.into()); + } + + let (l, r) = self.split_at(count); + *self = r; + Ok(l) + } + + fn remaining(&self) -> usize { + self.len() + } +} + +impl<'a> ReadBytes<'a> for io::Cursor<&'a [u8]> { + fn read_bytes(&mut self, count: usize) -> io::Result<&'a [u8]> { + let remaining_slice = + &self.get_ref()[self.position().min(self.get_ref().len() as u64) as usize..]; + + if count > remaining_slice.len() { + return Err(io::ErrorKind::UnexpectedEof.into()); + } + + self.set_position(self.position() + count as u64); + + Ok(&remaining_slice[..count]) + } + + fn remaining(&self) -> usize { + self.get_ref().len() - self.position() as usize + } +} -/// A string type which can be decoded from Java's [modified UTF-8](https://docs.oracle.com/javase/8/docs/api/java/io/DataInput.html#modified-utf-8). pub trait FromModifiedUtf8<'de>: Sized { - fn from_modified_utf8( - modified_utf8: &'de [u8], - ) -> std::result::Result; + fn from_modified_utf8(bytes: &'de [u8]) -> Result; } -impl<'de> FromModifiedUtf8<'de> for Cow<'de, str> { - fn from_modified_utf8( - modified_utf8: &'de [u8], - ) -> std::result::Result { - cesu8::from_java_cesu8(modified_utf8).map_err(move |_| FromModifiedUtf8Error) +impl<'a> FromModifiedUtf8<'a> for Cow<'a, str> { + fn from_modified_utf8(bytes: &'a [u8]) -> Result { + cesu8::from_java_cesu8(bytes).map_err(move |_| FromModifiedUtf8Error) } } -impl<'de> FromModifiedUtf8<'de> for String { - fn from_modified_utf8( - modified_utf8: &'de [u8], - ) -> std::result::Result { - match cesu8::from_java_cesu8(modified_utf8) { +impl<'a> FromModifiedUtf8<'a> for String { + fn from_modified_utf8(bytes: &'a [u8]) -> Result { + match cesu8::from_java_cesu8(bytes) { Ok(str) => Ok(str.into_owned()), Err(_) => Err(FromModifiedUtf8Error), } } } +impl<'a> FromModifiedUtf8<'a> for Box { + fn from_modified_utf8(bytes: &'a [u8]) -> Result { + String::from_modified_utf8(bytes).map(|s| s.into()) + } +} + #[cfg(feature = "java_string")] -impl<'de> FromModifiedUtf8<'de> for Cow<'de, java_string::JavaStr> { - fn from_modified_utf8( - modified_utf8: &'de [u8], - ) -> std::result::Result { - java_string::JavaStr::from_modified_utf8(modified_utf8).map_err(|_| FromModifiedUtf8Error) +impl<'a> FromModifiedUtf8<'a> for Cow<'a, java_string::JavaStr> { + fn from_modified_utf8(bytes: &'a [u8]) -> Result { + java_string::JavaStr::from_modified_utf8(bytes).map_err(|_| FromModifiedUtf8Error) } } #[cfg(feature = "java_string")] -impl<'de> FromModifiedUtf8<'de> for java_string::JavaString { - fn from_modified_utf8( - modified_utf8: &'de [u8], - ) -> std::result::Result { - match java_string::JavaStr::from_modified_utf8(modified_utf8) { +impl<'a> FromModifiedUtf8<'a> for java_string::JavaString { + fn from_modified_utf8(bytes: &'a [u8]) -> Result { + match java_string::JavaStr::from_modified_utf8(bytes) { Ok(str) => Ok(str.into_owned()), Err(_) => Err(FromModifiedUtf8Error), } } } + +#[derive(Copy, Clone, Debug)] +pub struct FromModifiedUtf8Error; + +impl fmt::Display for FromModifiedUtf8Error { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("could not decode modified UTF-8 string") + } +} + +impl std::error::Error for FromModifiedUtf8Error {} diff --git a/crates/valence_nbt/src/binary/encode.rs b/crates/valence_nbt/src/binary/encode.rs index 8cc50b811..0caa15272 100644 --- a/crates/valence_nbt/src/binary/encode.rs +++ b/crates/valence_nbt/src/binary/encode.rs @@ -1,106 +1,31 @@ use std::borrow::Cow; use std::hash::Hash; -use std::io::Write; +use std::io::{self, Write}; use byteorder::{BigEndian, WriteBytesExt}; -use super::{modified_utf8, Error, Result}; +use super::modified_utf8; use crate::conv::i8_slice_as_u8_slice; use crate::tag::Tag; -use crate::{Compound, List, Value}; - -/// Encodes uncompressed NBT binary data to the provided writer. -/// -/// Only compounds are permitted at the top level. This is why the function -/// accepts a [`Compound`] reference rather than a [`Value`]. -/// -/// Additionally, the root compound can be given a name. Typically the empty -/// string `""` is used. -pub fn to_binary(comp: &Compound, writer: W, root_name: &R) -> Result<()> +use crate::value::ValueRef; +use crate::{Compound, Error, List, Result}; + +/// Encode binary NBT data to the given writer. +pub fn to_binary<'a, S>( + writer: impl Write, + root_name: &(impl ToModifiedUtf8 + ?Sized), + value: impl Into>, +) -> Result<()> where - W: Write, - S: ToModifiedUtf8 + Hash + Ord, - R: ToModifiedUtf8 + ?Sized, + S: ToModifiedUtf8 + Hash + Ord + 'a, { + let value = value.into(); + let mut state = EncodeState { writer }; - state.write_tag(Tag::Compound)?; + state.write_tag(value.tag())?; state.write_string(root_name)?; - state.write_compound(comp)?; - - Ok(()) -} - -/// Returns the number of bytes that will be written when -/// [`to_binary`] is called with this compound and root name. -/// -/// If `to_binary` results in `Ok`, the exact number of bytes -/// reported by this function will have been written. If the result is -/// `Err`, then the reported count will be greater than or equal to the -/// number of bytes that have actually been written. -pub fn written_size(comp: &Compound, root_name: &R) -> usize -where - S: ToModifiedUtf8 + Hash + Ord, - R: ToModifiedUtf8 + ?Sized, -{ - fn value_size(val: &Value) -> usize - where - S: ToModifiedUtf8 + Hash + Ord, - { - match val { - Value::Byte(_) => 1, - Value::Short(_) => 2, - Value::Int(_) => 4, - Value::Long(_) => 8, - Value::Float(_) => 4, - Value::Double(_) => 8, - Value::ByteArray(v) => 4 + v.len(), - Value::String(v) => string_size(v), - Value::List(v) => list_size(v), - Value::Compound(v) => compound_size(v), - Value::IntArray(v) => 4 + v.len() * 4, - Value::LongArray(v) => 4 + v.len() * 8, - } - } - - fn list_size(l: &List) -> usize - where - S: ToModifiedUtf8 + Hash + Ord, - { - let elems_size = match l { - List::End => 0, - List::Byte(v) => v.len(), - List::Short(v) => v.len() * 2, - List::Int(v) => v.len() * 4, - List::Long(v) => v.len() * 8, - List::Float(v) => v.len() * 4, - List::Double(v) => v.len() * 8, - List::ByteArray(v) => v.iter().map(|b| 4 + b.len()).sum(), - List::String(v) => v.iter().map(|s| string_size(s)).sum(), - List::List(v) => v.iter().map(list_size).sum(), - List::Compound(v) => v.iter().map(compound_size).sum(), - List::IntArray(v) => v.iter().map(|i| 4 + i.len() * 4).sum(), - List::LongArray(v) => v.iter().map(|l| 4 + l.len() * 8).sum(), - }; - - 1 + 4 + elems_size - } - - fn string_size(s: &S) -> usize { - 2 + s.modified_uf8_len() - } - - fn compound_size(c: &Compound) -> usize - where - S: ToModifiedUtf8 + Hash + Ord, - { - c.iter() - .map(|(k, v)| 1 + string_size(k) + value_size(v)) - .sum::() - + 1 - } - - 1 + string_size(root_name) + compound_size(comp) + state.write_value(value) } struct EncodeState { @@ -112,23 +37,23 @@ impl EncodeState { Ok(self.writer.write_u8(tag as u8)?) } - fn write_value(&mut self, v: &Value) -> Result<()> + fn write_value(&mut self, v: ValueRef) -> Result<()> where S: ToModifiedUtf8 + Hash + Ord, { match v { - Value::Byte(v) => self.write_byte(*v), - Value::Short(v) => self.write_short(*v), - Value::Int(v) => self.write_int(*v), - Value::Long(v) => self.write_long(*v), - Value::Float(v) => self.write_float(*v), - Value::Double(v) => self.write_double(*v), - Value::ByteArray(v) => self.write_byte_array(v), - Value::String(v) => self.write_string(v), - Value::List(v) => self.write_any_list(v), - Value::Compound(v) => self.write_compound(v), - Value::IntArray(v) => self.write_int_array(v), - Value::LongArray(v) => self.write_long_array(v), + ValueRef::Byte(v) => self.write_byte(*v), + ValueRef::Short(v) => self.write_short(*v), + ValueRef::Int(v) => self.write_int(*v), + ValueRef::Long(v) => self.write_long(*v), + ValueRef::Float(v) => self.write_float(*v), + ValueRef::Double(v) => self.write_double(*v), + ValueRef::ByteArray(v) => self.write_byte_array(v), + ValueRef::String(v) => self.write_string(v), + ValueRef::List(v) => self.write_any_list(v), + ValueRef::Compound(v) => self.write_compound(v), + ValueRef::IntArray(v) => self.write_int_array(v), + ValueRef::LongArray(v) => self.write_long_array(v), } } @@ -170,7 +95,10 @@ impl EncodeState { Ok(self.writer.write_all(i8_slice_as_u8_slice(bytes))?) } - fn write_string(&mut self, s: &S) -> Result<()> { + fn write_string(&mut self, s: &S) -> Result<()> + where + S: ToModifiedUtf8 + ?Sized, + { let len = s.modified_uf8_len(); match len.try_into() { @@ -259,10 +187,10 @@ impl EncodeState { where S: ToModifiedUtf8 + Hash + Ord, { - for (k, v) in c.iter() { + for (k, v) in c { self.write_tag(v.tag())?; self.write_string(k)?; - self.write_value(v)?; + self.write_value(v.into())?; } self.write_tag(Tag::End)?; @@ -309,7 +237,7 @@ impl EncodeState { /// A string type which can be encoded into Java's [modified UTF-8](https://docs.oracle.com/javase/8/docs/api/java/io/DataInput.html#modified-utf-8). pub trait ToModifiedUtf8 { fn modified_uf8_len(&self) -> usize; - fn to_modified_utf8(&self, encoded_len: usize, writer: W) -> std::io::Result<()>; + fn to_modified_utf8(&self, encoded_len: usize, writer: W) -> io::Result<()>; } impl ToModifiedUtf8 for str { @@ -317,7 +245,7 @@ impl ToModifiedUtf8 for str { modified_utf8::encoded_len(self.as_bytes()) } - fn to_modified_utf8(&self, encoded_len: usize, mut writer: W) -> std::io::Result<()> { + fn to_modified_utf8(&self, encoded_len: usize, mut writer: W) -> io::Result<()> { // Conversion to modified UTF-8 always increases the size of the string. // If the new len is equal to the original len, we know it doesn't need // to be re-encoded. @@ -335,7 +263,7 @@ impl ToModifiedUtf8 for Cow<'_, str> { str::modified_uf8_len(self) } - fn to_modified_utf8(&self, encoded_len: usize, writer: W) -> std::io::Result<()> { + fn to_modified_utf8(&self, encoded_len: usize, writer: W) -> io::Result<()> { str::to_modified_utf8(self, encoded_len, writer) } } @@ -346,7 +274,17 @@ impl ToModifiedUtf8 for String { str::modified_uf8_len(self) } - fn to_modified_utf8(&self, encoded_len: usize, writer: W) -> std::io::Result<()> { + fn to_modified_utf8(&self, encoded_len: usize, writer: W) -> io::Result<()> { + str::to_modified_utf8(self, encoded_len, writer) + } +} + +impl ToModifiedUtf8 for Box { + fn modified_uf8_len(&self) -> usize { + str::modified_uf8_len(self) + } + + fn to_modified_utf8(&self, encoded_len: usize, writer: W) -> io::Result<()> { str::to_modified_utf8(self, encoded_len, writer) } } @@ -357,11 +295,7 @@ impl ToModifiedUtf8 for java_string::JavaStr { modified_utf8::encoded_len(self.as_bytes()) } - fn to_modified_utf8( - &self, - _encoded_len: usize, - mut writer: W, - ) -> std::io::Result<()> { + fn to_modified_utf8(&self, _encoded_len: usize, mut writer: W) -> io::Result<()> { writer.write_all(&self.to_modified_utf8()) } } @@ -373,7 +307,7 @@ impl ToModifiedUtf8 for Cow<'_, java_string::JavaStr> { java_string::JavaStr::modified_uf8_len(self) } - fn to_modified_utf8(&self, encoded_len: usize, writer: W) -> std::io::Result<()> { + fn to_modified_utf8(&self, encoded_len: usize, writer: W) -> io::Result<()> { ::to_modified_utf8(self, encoded_len, writer) } } @@ -385,7 +319,7 @@ impl ToModifiedUtf8 for java_string::JavaString { java_string::JavaStr::modified_uf8_len(self) } - fn to_modified_utf8(&self, encoded_len: usize, writer: W) -> std::io::Result<()> { + fn to_modified_utf8(&self, encoded_len: usize, writer: W) -> io::Result<()> { ::to_modified_utf8(self, encoded_len, writer) } } diff --git a/crates/valence_nbt/src/binary/modified_utf8.rs b/crates/valence_nbt/src/binary/modified_utf8.rs index 491745de5..9ee56f77b 100644 --- a/crates/valence_nbt/src/binary/modified_utf8.rs +++ b/crates/valence_nbt/src/binary/modified_utf8.rs @@ -17,7 +17,7 @@ pub(crate) fn write_modified_utf8(mut writer: impl Write, text: &str) -> io::Res while i < bytes.len() { match bytes[i] { 0 => { - writer.write_u16::(0xc080)?; + writer.write_u16::(0xC080)?; i += 1; } b @ 1..=127 => { @@ -35,8 +35,8 @@ pub(crate) fn write_modified_utf8(mut writer: impl Write, text: &str) -> io::Res let s = unsafe { from_utf8_unchecked(&bytes[i..i + w]) }; let c = s.chars().next().unwrap() as u32 - 0x10000; - let s0 = ((c >> 10) as u16) | 0xd800; - let s1 = ((c & 0x3ff) as u16) | 0xdc00; + let s0 = ((c >> 10) as u16) | 0xD800; + let s1 = ((c & 0x3FF) as u16) | 0xDC00; writer.write_all(encode_surrogate(s0).as_slice())?; writer.write_all(encode_surrogate(s1).as_slice())?; @@ -62,13 +62,13 @@ const fn utf8_char_width(first_byte: u8) -> usize { 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ]; - UTF8_CHAR_WIDTH[first_byte as usize] as _ + UTF8_CHAR_WIDTH[first_byte as usize] as usize } fn encode_surrogate(surrogate: u16) -> [u8; 3] { - debug_assert!((0xd800..=0xdfff).contains(&surrogate)); + debug_assert!((0xD800..=0xDFFF).contains(&surrogate)); - const TAG_CONT_U8: u8 = 0b1000_0000u8; + const TAG_CONT_U8: u8 = 0b1000_0000_u8; [ 0b11100000 | ((surrogate & 0b11110000_00000000) >> 12) as u8, TAG_CONT_U8 | ((surrogate & 0b00001111_11000000) >> 6) as u8, diff --git a/crates/valence_nbt/src/binary/tests.rs b/crates/valence_nbt/src/binary/tests.rs index 837487ef2..635b182f8 100644 --- a/crates/valence_nbt/src/binary/tests.rs +++ b/crates/valence_nbt/src/binary/tests.rs @@ -1,4 +1,3 @@ -use crate::binary::written_size; use crate::tag::Tag; use crate::{compound, from_binary, to_binary, Compound, List, Value}; @@ -10,14 +9,14 @@ fn round_trip() { let compound = example_compound(); - to_binary(&compound, &mut buf, ROOT_NAME).unwrap(); + to_binary(&mut buf, ROOT_NAME, &compound).unwrap(); println!("{buf:?}"); - let (decoded, root_name) = crate::from_binary(&mut buf.as_slice()).unwrap(); + let (root_name, decoded) = from_binary(&mut buf.as_slice()).unwrap().unwrap(); assert_eq!(root_name, ROOT_NAME); - assert_eq!(compound, decoded); + assert_eq!(Value::from(compound), decoded); } #[test] @@ -29,7 +28,7 @@ fn check_min_sizes() { let dbg = format!("{min_val:?}"); let mut buf = vec![]; - to_binary(&compound!("" => min_val), &mut buf, "").unwrap(); + to_binary(&mut buf, "", &compound!("" => min_val)).unwrap(); assert_eq!( expected_size, @@ -88,16 +87,6 @@ fn deeply_nested_list_decode() { let _ = from_binary::(&mut buf.as_slice()); } -#[test] -fn correct_length() { - let c = example_compound(); - - let mut buf = vec![]; - to_binary(&c, &mut buf, "abc").unwrap(); - - assert_eq!(written_size(&c, "abc"), buf.len()); -} - fn example_compound() -> Compound { fn inner() -> Compound { compound! { diff --git a/crates/valence_nbt/src/compound.rs b/crates/valence_nbt/src/compound.rs index 636bb2194..913cae533 100644 --- a/crates/valence_nbt/src/compound.rs +++ b/crates/valence_nbt/src/compound.rs @@ -219,8 +219,8 @@ where use indexmap::map::Entry as EntryImpl; match self.map.entry(k.into()) { - EntryImpl::Vacant(ve) => Entry::Vacant(VacantEntry { ve }), - EntryImpl::Occupied(oe) => Entry::Occupied(OccupiedEntry { oe }), + EntryImpl::Vacant(ve) => Entry::Vacant(VacantEntry { entry: ve }), + EntryImpl::Occupied(oe) => Entry::Occupied(OccupiedEntry { entry: oe }), } } @@ -421,7 +421,7 @@ where } } - pub fn or_insert(self, default: impl Into>) -> &'a mut Value { + pub fn or_insert>>(self, default: V) -> &'a mut Value { match self { Entry::Vacant(ve) => ve.insert(default), Entry::Occupied(oe) => oe.into_mut(), @@ -453,11 +453,23 @@ where } } +impl fmt::Debug for Entry<'_, S> +where + S: fmt::Debug + Ord, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::Vacant(entry) => f.debug_tuple("Vacant").field(entry).finish(), + Self::Occupied(entry) => f.debug_tuple("Occupied").field(entry).finish(), + } + } +} + pub struct VacantEntry<'a, S = String> { #[cfg(not(feature = "preserve_order"))] - ve: std::collections::btree_map::VacantEntry<'a, S, Value>, + entry: std::collections::btree_map::VacantEntry<'a, S, Value>, #[cfg(feature = "preserve_order")] - ve: indexmap::map::VacantEntry<'a, S, Value>, + entry: indexmap::map::VacantEntry<'a, S, Value>, } impl<'a, S> VacantEntry<'a, S> @@ -465,19 +477,30 @@ where S: Ord + Hash, { pub fn key(&self) -> &S { - self.ve.key() + self.entry.key() + } + + pub fn insert>>(self, v: V) -> &'a mut Value { + self.entry.insert(v.into()) } +} - pub fn insert(self, v: impl Into>) -> &'a mut Value { - self.ve.insert(v.into()) +impl fmt::Debug for VacantEntry<'_, S> +where + S: fmt::Debug + Ord, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("VacantEntry") + .field("entry", &self.entry) + .finish() } } pub struct OccupiedEntry<'a, S = String> { #[cfg(not(feature = "preserve_order"))] - oe: std::collections::btree_map::OccupiedEntry<'a, S, Value>, + entry: std::collections::btree_map::OccupiedEntry<'a, S, Value>, #[cfg(feature = "preserve_order")] - oe: indexmap::map::OccupiedEntry<'a, S, Value>, + entry: indexmap::map::OccupiedEntry<'a, S, Value>, } impl<'a, S> OccupiedEntry<'a, S> @@ -485,40 +508,51 @@ where S: Hash + Ord, { pub fn key(&self) -> &S { - self.oe.key() + self.entry.key() } pub fn get(&self) -> &Value { - self.oe.get() + self.entry.get() } pub fn get_mut(&mut self) -> &mut Value { - self.oe.get_mut() + self.entry.get_mut() } pub fn into_mut(self) -> &'a mut Value { - self.oe.into_mut() + self.entry.into_mut() } - pub fn insert(&mut self, v: impl Into>) -> Value { - self.oe.insert(v.into()) + pub fn insert>>(&mut self, v: V) -> Value { + self.entry.insert(v.into()) } pub fn remove(self) -> Value { #[cfg(feature = "preserve_order")] return self.swap_remove(); #[cfg(not(feature = "preserve_order"))] - return self.oe.remove(); + return self.entry.remove(); } #[cfg(feature = "preserve_order")] pub fn swap_remove(self) -> Value { - self.oe.swap_remove() + self.entry.swap_remove() } #[cfg(feature = "preserve_order")] pub fn shift_remove(self) -> Value { - self.oe.shift_remove() + self.entry.shift_remove() + } +} + +impl fmt::Debug for OccupiedEntry<'_, S> +where + S: fmt::Debug + Ord, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("OccupiedEntry") + .field("entry", &self.entry) + .finish() } } @@ -588,7 +622,7 @@ impl<'a, S> IntoIterator for &'a Compound { } } -#[derive(Clone)] +#[derive(Clone, Debug)] pub struct Iter<'a, S = String> { #[cfg(not(feature = "preserve_order"))] iter: std::collections::btree_map::Iter<'a, S, Value>, @@ -609,6 +643,7 @@ impl<'a, S> IntoIterator for &'a mut Compound { } } +#[derive(Debug)] pub struct IterMut<'a, S = String> { #[cfg(not(feature = "preserve_order"))] iter: std::collections::btree_map::IterMut<'a, S, Value>, @@ -629,6 +664,7 @@ impl IntoIterator for Compound { } } +#[derive(Debug)] pub struct IntoIter { #[cfg(not(feature = "preserve_order"))] iter: std::collections::btree_map::IntoIter>, @@ -638,7 +674,7 @@ pub struct IntoIter { impl_iterator_traits!((IntoIter) => (S, Value)); -#[derive(Clone)] +#[derive(Clone, Debug)] pub struct Keys<'a, S = String> { #[cfg(not(feature = "preserve_order"))] iter: std::collections::btree_map::Keys<'a, S, Value>, @@ -648,7 +684,7 @@ pub struct Keys<'a, S = String> { impl_iterator_traits!((Keys<'a, S>) => &'a S); -#[derive(Clone)] +#[derive(Clone, Debug)] pub struct Values<'a, S = String> { #[cfg(not(feature = "preserve_order"))] iter: std::collections::btree_map::Values<'a, S, Value>, @@ -658,6 +694,7 @@ pub struct Values<'a, S = String> { impl_iterator_traits!((Values<'a, S>) => &'a Value); +#[derive(Debug)] pub struct ValuesMut<'a, S = String> { #[cfg(not(feature = "preserve_order"))] iter: std::collections::btree_map::ValuesMut<'a, S, Value>, diff --git a/crates/valence_nbt/src/binary/error.rs b/crates/valence_nbt/src/error.rs similarity index 95% rename from crates/valence_nbt/src/binary/error.rs rename to crates/valence_nbt/src/error.rs index 8c5c4efaf..665a6a27c 100644 --- a/crates/valence_nbt/src/binary/error.rs +++ b/crates/valence_nbt/src/error.rs @@ -2,7 +2,7 @@ use std::error::Error as StdError; use std::fmt::{Display, Formatter}; use std::io; -pub type Result = std::result::Result; +pub type Result = std::result::Result; /// Errors that can occur when encoding or decoding binary NBT. #[derive(Debug)] diff --git a/crates/valence_nbt/src/lib.rs b/crates/valence_nbt/src/lib.rs index f422dc9dd..957cfd141 100644 --- a/crates/valence_nbt/src/lib.rs +++ b/crates/valence_nbt/src/lib.rs @@ -1,37 +1,28 @@ #![doc = include_str!("../README.md")] -#![deny( - rustdoc::broken_intra_doc_links, - rustdoc::private_intra_doc_links, - rustdoc::missing_crate_level_docs, - rustdoc::invalid_codeblock_attributes, - rustdoc::invalid_rust_codeblocks, - rustdoc::bare_urls, - rustdoc::invalid_html_tags -)] -#![warn( - trivial_casts, - trivial_numeric_casts, - unused_lifetimes, - unused_import_braces, - unreachable_pub, - clippy::dbg_macro -)] +// Run locally with `RUSTDOCFLAGS="--cfg docsrs" cargo +nightly doc --all-features --open` +#![cfg_attr(docsrs, feature(doc_cfg))] #[cfg(feature = "binary")] +#[cfg_attr(docsrs, doc(cfg(feature = "binary")))] pub use binary::{from_binary, to_binary}; pub use compound::Compound; +pub use error::*; pub use list::List; -pub use tag::Tag; +pub use tag::*; pub use value::Value; #[cfg(feature = "binary")] +#[cfg_attr(docsrs, doc(cfg(feature = "binary")))] pub mod binary; pub mod compound; pub mod conv; +mod error; pub mod list; #[cfg(feature = "serde")] +#[cfg_attr(docsrs, doc(cfg(feature = "serde")))] pub mod serde; #[cfg(feature = "snbt")] +#[cfg_attr(docsrs, doc(cfg(feature = "snbt")))] pub mod snbt; mod tag; pub mod value; @@ -102,6 +93,7 @@ macro_rules! compound { /// /// [`JavaString`]: java_string::JavaString #[cfg(feature = "java_string")] +#[cfg_attr(docsrs, doc(cfg(feature = "java_string")))] #[macro_export] macro_rules! jcompound { ($($key:expr => $value:expr),* $(,)?) => { diff --git a/crates/valence_nbt/src/list.rs b/crates/valence_nbt/src/list.rs index 8068d9d72..1592501fc 100644 --- a/crates/valence_nbt/src/list.rs +++ b/crates/valence_nbt/src/list.rs @@ -161,7 +161,7 @@ impl List { /// multiple types inside it). Returns `true` if the value was added, /// `false` otherwise. #[must_use] - pub fn try_push(&mut self, value: impl Into>) -> bool { + pub fn try_push>>(&mut self, value: V) -> bool { let value = value.into(); match self { List::End => { @@ -276,7 +276,7 @@ impl List { /// /// Panics if the index is greater than the length of the list. #[must_use] - pub fn try_insert(&mut self, index: usize, value: impl Into>) -> bool { + pub fn try_insert>>(&mut self, index: usize, value: V) -> bool { let value = value.into(); #[cold] @@ -662,10 +662,12 @@ impl<'a, S> IntoIterator for &'a mut List { } /// The owned iterator type for [`List`]. +#[derive(Clone, Debug)] pub struct IntoIter { inner: IntoIterInner, } +#[derive(Clone, Debug)] enum IntoIterInner { End, Byte(std::vec::IntoIter), @@ -686,78 +688,78 @@ impl Iterator for IntoIter { type Item = Value; fn next(&mut self) -> Option { - match self.inner { + match &mut self.inner { IntoIterInner::End => None, - IntoIterInner::Byte(ref mut i) => i.next().map(Value::Byte), - IntoIterInner::Short(ref mut i) => i.next().map(Value::Short), - IntoIterInner::Int(ref mut i) => i.next().map(Value::Int), - IntoIterInner::Long(ref mut i) => i.next().map(Value::Long), - IntoIterInner::Float(ref mut i) => i.next().map(Value::Float), - IntoIterInner::Double(ref mut i) => i.next().map(Value::Double), - IntoIterInner::ByteArray(ref mut i) => i.next().map(Value::ByteArray), - IntoIterInner::String(ref mut i) => i.next().map(Value::String), - IntoIterInner::List(ref mut i) => i.next().map(Value::List), - IntoIterInner::Compound(ref mut i) => i.next().map(Value::Compound), - IntoIterInner::IntArray(ref mut i) => i.next().map(Value::IntArray), - IntoIterInner::LongArray(ref mut i) => i.next().map(Value::LongArray), + IntoIterInner::Byte(i) => i.next().map(Value::Byte), + IntoIterInner::Short(i) => i.next().map(Value::Short), + IntoIterInner::Int(i) => i.next().map(Value::Int), + IntoIterInner::Long(i) => i.next().map(Value::Long), + IntoIterInner::Float(i) => i.next().map(Value::Float), + IntoIterInner::Double(i) => i.next().map(Value::Double), + IntoIterInner::ByteArray(i) => i.next().map(Value::ByteArray), + IntoIterInner::String(i) => i.next().map(Value::String), + IntoIterInner::List(i) => i.next().map(Value::List), + IntoIterInner::Compound(i) => i.next().map(Value::Compound), + IntoIterInner::IntArray(i) => i.next().map(Value::IntArray), + IntoIterInner::LongArray(i) => i.next().map(Value::LongArray), } } fn size_hint(&self) -> (usize, Option) { - match self.inner { + match &self.inner { IntoIterInner::End => (0, Some(0)), - IntoIterInner::Byte(ref i) => i.size_hint(), - IntoIterInner::Short(ref i) => i.size_hint(), - IntoIterInner::Int(ref i) => i.size_hint(), - IntoIterInner::Long(ref i) => i.size_hint(), - IntoIterInner::Float(ref i) => i.size_hint(), - IntoIterInner::Double(ref i) => i.size_hint(), - IntoIterInner::ByteArray(ref i) => i.size_hint(), - IntoIterInner::String(ref i) => i.size_hint(), - IntoIterInner::List(ref i) => i.size_hint(), - IntoIterInner::Compound(ref i) => i.size_hint(), - IntoIterInner::IntArray(ref i) => i.size_hint(), - IntoIterInner::LongArray(ref i) => i.size_hint(), + IntoIterInner::Byte(i) => i.size_hint(), + IntoIterInner::Short(i) => i.size_hint(), + IntoIterInner::Int(i) => i.size_hint(), + IntoIterInner::Long(i) => i.size_hint(), + IntoIterInner::Float(i) => i.size_hint(), + IntoIterInner::Double(i) => i.size_hint(), + IntoIterInner::ByteArray(i) => i.size_hint(), + IntoIterInner::String(i) => i.size_hint(), + IntoIterInner::List(i) => i.size_hint(), + IntoIterInner::Compound(i) => i.size_hint(), + IntoIterInner::IntArray(i) => i.size_hint(), + IntoIterInner::LongArray(i) => i.size_hint(), } } } impl DoubleEndedIterator for IntoIter { fn next_back(&mut self) -> Option { - match self.inner { + match &mut self.inner { IntoIterInner::End => None, - IntoIterInner::Byte(ref mut i) => i.next_back().map(Value::Byte), - IntoIterInner::Short(ref mut i) => i.next_back().map(Value::Short), - IntoIterInner::Int(ref mut i) => i.next_back().map(Value::Int), - IntoIterInner::Long(ref mut i) => i.next_back().map(Value::Long), - IntoIterInner::Float(ref mut i) => i.next_back().map(Value::Float), - IntoIterInner::Double(ref mut i) => i.next_back().map(Value::Double), - IntoIterInner::ByteArray(ref mut i) => i.next_back().map(Value::ByteArray), - IntoIterInner::String(ref mut i) => i.next_back().map(Value::String), - IntoIterInner::List(ref mut i) => i.next_back().map(Value::List), - IntoIterInner::Compound(ref mut i) => i.next_back().map(Value::Compound), - IntoIterInner::IntArray(ref mut i) => i.next_back().map(Value::IntArray), - IntoIterInner::LongArray(ref mut i) => i.next_back().map(Value::LongArray), + IntoIterInner::Byte(i) => i.next_back().map(Value::Byte), + IntoIterInner::Short(i) => i.next_back().map(Value::Short), + IntoIterInner::Int(i) => i.next_back().map(Value::Int), + IntoIterInner::Long(i) => i.next_back().map(Value::Long), + IntoIterInner::Float(i) => i.next_back().map(Value::Float), + IntoIterInner::Double(i) => i.next_back().map(Value::Double), + IntoIterInner::ByteArray(i) => i.next_back().map(Value::ByteArray), + IntoIterInner::String(i) => i.next_back().map(Value::String), + IntoIterInner::List(i) => i.next_back().map(Value::List), + IntoIterInner::Compound(i) => i.next_back().map(Value::Compound), + IntoIterInner::IntArray(i) => i.next_back().map(Value::IntArray), + IntoIterInner::LongArray(i) => i.next_back().map(Value::LongArray), } } } impl ExactSizeIterator for IntoIter { fn len(&self) -> usize { - match self.inner { + match &self.inner { IntoIterInner::End => 0, - IntoIterInner::Byte(ref i) => i.len(), - IntoIterInner::Short(ref i) => i.len(), - IntoIterInner::Int(ref i) => i.len(), - IntoIterInner::Long(ref i) => i.len(), - IntoIterInner::Float(ref i) => i.len(), - IntoIterInner::Double(ref i) => i.len(), - IntoIterInner::ByteArray(ref i) => i.len(), - IntoIterInner::String(ref i) => i.len(), - IntoIterInner::List(ref i) => i.len(), - IntoIterInner::Compound(ref i) => i.len(), - IntoIterInner::IntArray(ref i) => i.len(), - IntoIterInner::LongArray(ref i) => i.len(), + IntoIterInner::Byte(i) => i.len(), + IntoIterInner::Short(i) => i.len(), + IntoIterInner::Int(i) => i.len(), + IntoIterInner::Long(i) => i.len(), + IntoIterInner::Float(i) => i.len(), + IntoIterInner::Double(i) => i.len(), + IntoIterInner::ByteArray(i) => i.len(), + IntoIterInner::String(i) => i.len(), + IntoIterInner::List(i) => i.len(), + IntoIterInner::Compound(i) => i.len(), + IntoIterInner::IntArray(i) => i.len(), + IntoIterInner::LongArray(i) => i.len(), } } } @@ -765,10 +767,12 @@ impl ExactSizeIterator for IntoIter { impl FusedIterator for IntoIter {} /// The borrowing iterator type for [`List`]. +#[derive(Clone, Debug)] pub struct Iter<'a, S = String> { inner: IterInner<'a, S>, } +#[derive(Clone, Debug)] enum IterInner<'a, S> { End, Byte(std::slice::Iter<'a, i8>), @@ -789,82 +793,78 @@ impl<'a, S> Iterator for Iter<'a, S> { type Item = ValueRef<'a, S>; fn next(&mut self) -> Option { - match self.inner { + match &mut self.inner { IterInner::End => None, - IterInner::Byte(ref mut i) => i.next().map(ValueRef::Byte), - IterInner::Short(ref mut i) => i.next().map(ValueRef::Short), - IterInner::Int(ref mut i) => i.next().map(ValueRef::Int), - IterInner::Long(ref mut i) => i.next().map(ValueRef::Long), - IterInner::Float(ref mut i) => i.next().map(ValueRef::Float), - IterInner::Double(ref mut i) => i.next().map(ValueRef::Double), - IterInner::ByteArray(ref mut i) => i.next().map(|arr| ValueRef::ByteArray(&arr[..])), - IterInner::String(ref mut i) => i.next().map(ValueRef::String), - IterInner::List(ref mut i) => i.next().map(ValueRef::List), - IterInner::Compound(ref mut i) => i.next().map(ValueRef::Compound), - IterInner::IntArray(ref mut i) => i.next().map(|arr| ValueRef::IntArray(&arr[..])), - IterInner::LongArray(ref mut i) => i.next().map(|arr| ValueRef::LongArray(&arr[..])), + IterInner::Byte(i) => i.next().map(ValueRef::Byte), + IterInner::Short(i) => i.next().map(ValueRef::Short), + IterInner::Int(i) => i.next().map(ValueRef::Int), + IterInner::Long(i) => i.next().map(ValueRef::Long), + IterInner::Float(i) => i.next().map(ValueRef::Float), + IterInner::Double(i) => i.next().map(ValueRef::Double), + IterInner::ByteArray(i) => i.next().map(|arr| ValueRef::ByteArray(&arr[..])), + IterInner::String(i) => i.next().map(ValueRef::String), + IterInner::List(i) => i.next().map(ValueRef::List), + IterInner::Compound(i) => i.next().map(ValueRef::Compound), + IterInner::IntArray(i) => i.next().map(|arr| ValueRef::IntArray(&arr[..])), + IterInner::LongArray(i) => i.next().map(|arr| ValueRef::LongArray(&arr[..])), } } fn size_hint(&self) -> (usize, Option) { - match self.inner { + match &self.inner { IterInner::End => (0, Some(0)), - IterInner::Byte(ref i) => i.size_hint(), - IterInner::Short(ref i) => i.size_hint(), - IterInner::Int(ref i) => i.size_hint(), - IterInner::Long(ref i) => i.size_hint(), - IterInner::Float(ref i) => i.size_hint(), - IterInner::Double(ref i) => i.size_hint(), - IterInner::ByteArray(ref i) => i.size_hint(), - IterInner::String(ref i) => i.size_hint(), - IterInner::List(ref i) => i.size_hint(), - IterInner::Compound(ref i) => i.size_hint(), - IterInner::IntArray(ref i) => i.size_hint(), - IterInner::LongArray(ref i) => i.size_hint(), + IterInner::Byte(i) => i.size_hint(), + IterInner::Short(i) => i.size_hint(), + IterInner::Int(i) => i.size_hint(), + IterInner::Long(i) => i.size_hint(), + IterInner::Float(i) => i.size_hint(), + IterInner::Double(i) => i.size_hint(), + IterInner::ByteArray(i) => i.size_hint(), + IterInner::String(i) => i.size_hint(), + IterInner::List(i) => i.size_hint(), + IterInner::Compound(i) => i.size_hint(), + IterInner::IntArray(i) => i.size_hint(), + IterInner::LongArray(i) => i.size_hint(), } } } impl DoubleEndedIterator for Iter<'_, S> { fn next_back(&mut self) -> Option { - match self.inner { + match &mut self.inner { IterInner::End => None, - IterInner::Byte(ref mut i) => i.next_back().map(ValueRef::Byte), - IterInner::Short(ref mut i) => i.next_back().map(ValueRef::Short), - IterInner::Int(ref mut i) => i.next_back().map(ValueRef::Int), - IterInner::Long(ref mut i) => i.next_back().map(ValueRef::Long), - IterInner::Float(ref mut i) => i.next_back().map(ValueRef::Float), - IterInner::Double(ref mut i) => i.next_back().map(ValueRef::Double), - IterInner::ByteArray(ref mut i) => { - i.next_back().map(|arr| ValueRef::ByteArray(&arr[..])) - } - IterInner::String(ref mut i) => i.next_back().map(ValueRef::String), - IterInner::List(ref mut i) => i.next_back().map(ValueRef::List), - IterInner::Compound(ref mut i) => i.next_back().map(ValueRef::Compound), - IterInner::IntArray(ref mut i) => i.next_back().map(|arr| ValueRef::IntArray(&arr[..])), - IterInner::LongArray(ref mut i) => { - i.next_back().map(|arr| ValueRef::LongArray(&arr[..])) - } + IterInner::Byte(i) => i.next_back().map(ValueRef::Byte), + IterInner::Short(i) => i.next_back().map(ValueRef::Short), + IterInner::Int(i) => i.next_back().map(ValueRef::Int), + IterInner::Long(i) => i.next_back().map(ValueRef::Long), + IterInner::Float(i) => i.next_back().map(ValueRef::Float), + IterInner::Double(i) => i.next_back().map(ValueRef::Double), + IterInner::ByteArray(i) => i.next_back().map(|arr| ValueRef::ByteArray(&arr[..])), + IterInner::String(i) => i.next_back().map(ValueRef::String), + IterInner::List(i) => i.next_back().map(ValueRef::List), + IterInner::Compound(i) => i.next_back().map(ValueRef::Compound), + IterInner::IntArray(i) => i.next_back().map(|arr| ValueRef::IntArray(&arr[..])), + IterInner::LongArray(i) => i.next_back().map(|arr| ValueRef::LongArray(&arr[..])), } } } impl ExactSizeIterator for Iter<'_, S> { fn len(&self) -> usize { - match self.inner { + match &self.inner { IterInner::End => 0, - IterInner::Byte(ref i) => i.len(), - IterInner::Short(ref i) => i.len(), - IterInner::Int(ref i) => i.len(), - IterInner::Long(ref i) => i.len(), - IterInner::Float(ref i) => i.len(), - IterInner::Double(ref i) => i.len(), - IterInner::ByteArray(ref i) => i.len(), - IterInner::String(ref i) => i.len(), - IterInner::List(ref i) => i.len(), - IterInner::Compound(ref i) => i.len(), - IterInner::IntArray(ref i) => i.len(), - IterInner::LongArray(ref i) => i.len(), + IterInner::Byte(i) => i.len(), + IterInner::Short(i) => i.len(), + IterInner::Int(i) => i.len(), + IterInner::Long(i) => i.len(), + IterInner::Float(i) => i.len(), + IterInner::Double(i) => i.len(), + IterInner::ByteArray(i) => i.len(), + IterInner::String(i) => i.len(), + IterInner::List(i) => i.len(), + IterInner::Compound(i) => i.len(), + IterInner::IntArray(i) => i.len(), + IterInner::LongArray(i) => i.len(), } } } @@ -872,10 +872,12 @@ impl ExactSizeIterator for Iter<'_, S> { impl FusedIterator for Iter<'_, S> {} /// The mutable borrowing iterator type for [`List`]. +#[derive(Debug)] pub struct IterMut<'a, S = String> { inner: IterMutInner<'a, S>, } +#[derive(Debug)] enum IterMutInner<'a, S> { End, Byte(std::slice::IterMut<'a, i8>), @@ -896,78 +898,78 @@ impl<'a, S> Iterator for IterMut<'a, S> { type Item = ValueMut<'a, S>; fn next(&mut self) -> Option { - match self.inner { + match &mut self.inner { IterMutInner::End => None, - IterMutInner::Byte(ref mut i) => i.next().map(ValueMut::Byte), - IterMutInner::Short(ref mut i) => i.next().map(ValueMut::Short), - IterMutInner::Int(ref mut i) => i.next().map(ValueMut::Int), - IterMutInner::Long(ref mut i) => i.next().map(ValueMut::Long), - IterMutInner::Float(ref mut i) => i.next().map(ValueMut::Float), - IterMutInner::Double(ref mut i) => i.next().map(ValueMut::Double), - IterMutInner::ByteArray(ref mut i) => i.next().map(ValueMut::ByteArray), - IterMutInner::String(ref mut i) => i.next().map(ValueMut::String), - IterMutInner::List(ref mut i) => i.next().map(ValueMut::List), - IterMutInner::Compound(ref mut i) => i.next().map(ValueMut::Compound), - IterMutInner::IntArray(ref mut i) => i.next().map(ValueMut::IntArray), - IterMutInner::LongArray(ref mut i) => i.next().map(ValueMut::LongArray), + IterMutInner::Byte(i) => i.next().map(ValueMut::Byte), + IterMutInner::Short(i) => i.next().map(ValueMut::Short), + IterMutInner::Int(i) => i.next().map(ValueMut::Int), + IterMutInner::Long(i) => i.next().map(ValueMut::Long), + IterMutInner::Float(i) => i.next().map(ValueMut::Float), + IterMutInner::Double(i) => i.next().map(ValueMut::Double), + IterMutInner::ByteArray(i) => i.next().map(ValueMut::ByteArray), + IterMutInner::String(i) => i.next().map(ValueMut::String), + IterMutInner::List(i) => i.next().map(ValueMut::List), + IterMutInner::Compound(i) => i.next().map(ValueMut::Compound), + IterMutInner::IntArray(i) => i.next().map(ValueMut::IntArray), + IterMutInner::LongArray(i) => i.next().map(ValueMut::LongArray), } } fn size_hint(&self) -> (usize, Option) { - match self.inner { + match &self.inner { IterMutInner::End => (0, Some(0)), - IterMutInner::Byte(ref i) => i.size_hint(), - IterMutInner::Short(ref i) => i.size_hint(), - IterMutInner::Int(ref i) => i.size_hint(), - IterMutInner::Long(ref i) => i.size_hint(), - IterMutInner::Float(ref i) => i.size_hint(), - IterMutInner::Double(ref i) => i.size_hint(), - IterMutInner::ByteArray(ref i) => i.size_hint(), - IterMutInner::String(ref i) => i.size_hint(), - IterMutInner::List(ref i) => i.size_hint(), - IterMutInner::Compound(ref i) => i.size_hint(), - IterMutInner::IntArray(ref i) => i.size_hint(), - IterMutInner::LongArray(ref i) => i.size_hint(), + IterMutInner::Byte(i) => i.size_hint(), + IterMutInner::Short(i) => i.size_hint(), + IterMutInner::Int(i) => i.size_hint(), + IterMutInner::Long(i) => i.size_hint(), + IterMutInner::Float(i) => i.size_hint(), + IterMutInner::Double(i) => i.size_hint(), + IterMutInner::ByteArray(i) => i.size_hint(), + IterMutInner::String(i) => i.size_hint(), + IterMutInner::List(i) => i.size_hint(), + IterMutInner::Compound(i) => i.size_hint(), + IterMutInner::IntArray(i) => i.size_hint(), + IterMutInner::LongArray(i) => i.size_hint(), } } } impl DoubleEndedIterator for IterMut<'_, S> { fn next_back(&mut self) -> Option { - match self.inner { + match &mut self.inner { IterMutInner::End => None, - IterMutInner::Byte(ref mut i) => i.next_back().map(ValueMut::Byte), - IterMutInner::Short(ref mut i) => i.next_back().map(ValueMut::Short), - IterMutInner::Int(ref mut i) => i.next_back().map(ValueMut::Int), - IterMutInner::Long(ref mut i) => i.next_back().map(ValueMut::Long), - IterMutInner::Float(ref mut i) => i.next_back().map(ValueMut::Float), - IterMutInner::Double(ref mut i) => i.next_back().map(ValueMut::Double), - IterMutInner::ByteArray(ref mut i) => i.next_back().map(ValueMut::ByteArray), - IterMutInner::String(ref mut i) => i.next_back().map(ValueMut::String), - IterMutInner::List(ref mut i) => i.next_back().map(ValueMut::List), - IterMutInner::Compound(ref mut i) => i.next_back().map(ValueMut::Compound), - IterMutInner::IntArray(ref mut i) => i.next_back().map(ValueMut::IntArray), - IterMutInner::LongArray(ref mut i) => i.next_back().map(ValueMut::LongArray), + IterMutInner::Byte(i) => i.next_back().map(ValueMut::Byte), + IterMutInner::Short(i) => i.next_back().map(ValueMut::Short), + IterMutInner::Int(i) => i.next_back().map(ValueMut::Int), + IterMutInner::Long(i) => i.next_back().map(ValueMut::Long), + IterMutInner::Float(i) => i.next_back().map(ValueMut::Float), + IterMutInner::Double(i) => i.next_back().map(ValueMut::Double), + IterMutInner::ByteArray(i) => i.next_back().map(ValueMut::ByteArray), + IterMutInner::String(i) => i.next_back().map(ValueMut::String), + IterMutInner::List(i) => i.next_back().map(ValueMut::List), + IterMutInner::Compound(i) => i.next_back().map(ValueMut::Compound), + IterMutInner::IntArray(i) => i.next_back().map(ValueMut::IntArray), + IterMutInner::LongArray(i) => i.next_back().map(ValueMut::LongArray), } } } impl ExactSizeIterator for IterMut<'_, S> { fn len(&self) -> usize { - match self.inner { + match &self.inner { IterMutInner::End => 0, - IterMutInner::Byte(ref i) => i.len(), - IterMutInner::Short(ref i) => i.len(), - IterMutInner::Int(ref i) => i.len(), - IterMutInner::Long(ref i) => i.len(), - IterMutInner::Float(ref i) => i.len(), - IterMutInner::Double(ref i) => i.len(), - IterMutInner::ByteArray(ref i) => i.len(), - IterMutInner::String(ref i) => i.len(), - IterMutInner::List(ref i) => i.len(), - IterMutInner::Compound(ref i) => i.len(), - IterMutInner::IntArray(ref i) => i.len(), - IterMutInner::LongArray(ref i) => i.len(), + IterMutInner::Byte(i) => i.len(), + IterMutInner::Short(i) => i.len(), + IterMutInner::Int(i) => i.len(), + IterMutInner::Long(i) => i.len(), + IterMutInner::Float(i) => i.len(), + IterMutInner::Double(i) => i.len(), + IterMutInner::ByteArray(i) => i.len(), + IterMutInner::String(i) => i.len(), + IterMutInner::List(i) => i.len(), + IterMutInner::Compound(i) => i.len(), + IterMutInner::IntArray(i) => i.len(), + IterMutInner::LongArray(i) => i.len(), } } } diff --git a/crates/valence_nbt/src/serde.rs b/crates/valence_nbt/src/serde.rs index 8159f5d7d..793cb26c6 100644 --- a/crates/valence_nbt/src/serde.rs +++ b/crates/valence_nbt/src/serde.rs @@ -1,31 +1,20 @@ use std::fmt; pub use ser::*; -use thiserror::Error; + +use crate::Error; mod de; mod ser; #[cfg(test)] mod tests; -/// Errors that can occur while serializing or deserializing. -#[derive(Clone, Error, Debug)] -#[error("{0}")] - -pub struct Error(Box); - -impl Error { - fn new(s: impl Into>) -> Self { - Self(s.into()) - } -} - impl serde::de::Error for Error { fn custom(msg: T) -> Self where T: fmt::Display, { - Self::new(format!("{msg}")) + Self::new_owned(format!("{msg}")) } } @@ -34,6 +23,6 @@ impl serde::ser::Error for Error { where T: fmt::Display, { - Self::new(format!("{msg}")) + Self::new_owned(format!("{msg}")) } } diff --git a/crates/valence_nbt/src/serde/de.rs b/crates/valence_nbt/src/serde/de.rs index 0c5b280f1..e3826d782 100644 --- a/crates/valence_nbt/src/serde/de.rs +++ b/crates/valence_nbt/src/serde/de.rs @@ -37,7 +37,7 @@ where where E: de::Error, { - Ok(Value::Byte(v as _)) + Ok(Value::Byte(v.into())) } fn visit_i8(self, v: i8) -> Result @@ -72,28 +72,28 @@ where where E: de::Error, { - Ok(Value::Byte(v as _)) + Ok(Value::Byte(v as i8)) } fn visit_u16(self, v: u16) -> Result where E: de::Error, { - Ok(Value::Short(v as _)) + Ok(Value::Short(v as i16)) } fn visit_u32(self, v: u32) -> Result where E: de::Error, { - Ok(Value::Int(v as _)) + Ok(Value::Int(v as i32)) } fn visit_u64(self, v: u64) -> Result where E: de::Error, { - Ok(Value::Long(v as _)) + Ok(Value::Long(v as i64)) } fn visit_f32(self, v: f32) -> Result diff --git a/crates/valence_nbt/src/serde/ser.rs b/crates/valence_nbt/src/serde/ser.rs index 25bfca896..99f51902c 100644 --- a/crates/valence_nbt/src/serde/ser.rs +++ b/crates/valence_nbt/src/serde/ser.rs @@ -61,11 +61,12 @@ where macro_rules! unsupported { ($lit:literal) => { - Err(Error::new(concat!("unsupported type: ", $lit))) + Err(Error::new_static(concat!("unsupported type: ", $lit))) }; } /// [`Serializer`] whose output is [`Compound`]. +#[derive(Debug)] pub struct CompoundSerializer; impl Serializer for CompoundSerializer { @@ -267,7 +268,7 @@ impl Serializer for ValueSerializer { type SerializeStructVariant = Impossible; fn serialize_bool(self, v: bool) -> Result { - Ok(Value::Byte(v as _)) + Ok(Value::Byte(v.into())) } fn serialize_i8(self, v: i8) -> Result { @@ -287,19 +288,19 @@ impl Serializer for ValueSerializer { } fn serialize_u8(self, v: u8) -> Result { - Ok(Value::Byte(v as _)) + Ok(Value::Byte(v as i8)) } fn serialize_u16(self, v: u16) -> Result { - Ok(Value::Short(v as _)) + Ok(Value::Short(v as i16)) } fn serialize_u32(self, v: u32) -> Result { - Ok(Value::Int(v as _)) + Ok(Value::Int(v as i32)) } fn serialize_u64(self, v: u64) -> Result { - Ok(Value::Long(v as _)) + Ok(Value::Long(v as i64)) } fn serialize_f32(self, v: f32) -> Result { @@ -457,7 +458,7 @@ impl SerializeSeq for ValueSerializeSeq { $vec.push(val); Ok(()) } - _ => Err(Error::new(concat!( + _ => Err(Error::new_static(concat!( "heterogeneous NBT list (expected `", stringify!($variant), "` element)" @@ -526,6 +527,7 @@ impl SerializeSeq for ValueSerializeSeq { } #[doc(hidden)] +#[derive(Debug)] pub struct GenericSerializeMap { /// Temp storage for `serialize_key`. key: Option, @@ -565,7 +567,7 @@ where self.key = Some(s); Ok(()) } - _ => Err(Error::new("invalid map key type (expected string)")), + _ => Err(Error::new_static("invalid map key type (expected string)")), } } @@ -587,6 +589,7 @@ where } #[doc(hidden)] +#[derive(Debug)] pub struct GenericSerializeStruct { c: Compound, _marker: PhantomData, diff --git a/crates/valence_nbt/src/snbt.rs b/crates/valence_nbt/src/snbt.rs index e207da762..e3b796d6c 100644 --- a/crates/valence_nbt/src/snbt.rs +++ b/crates/valence_nbt/src/snbt.rs @@ -45,15 +45,15 @@ impl Display for SnbtErrorKind { #[derive(Debug, Clone, PartialEq, Eq, Copy)] pub struct SnbtError { - pub error_type: SnbtErrorKind, + pub kind: SnbtErrorKind, pub line: usize, pub column: usize, } impl SnbtError { - pub fn new(error_type: SnbtErrorKind, line: usize, column: usize) -> Self { + pub fn new(kind: SnbtErrorKind, line: usize, column: usize) -> Self { Self { - error_type, + kind, line, column, } @@ -62,7 +62,7 @@ impl SnbtError { impl Display for SnbtError { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - write!(f, "@ {},{}: {}", self.line, self.column, self.error_type) + write!(f, "@ {},{}: {}", self.line, self.column, self.kind) } } @@ -70,6 +70,7 @@ impl Error for SnbtError {} type Result = std::result::Result; +#[derive(Debug)] pub struct SnbtReader<'a> { line: usize, column: usize, @@ -444,6 +445,7 @@ pub fn from_snbt_str(snbt: &str) -> Result { SnbtReader::new(snbt).read() } +#[derive(Debug)] pub struct SnbtWriter<'a> { output: &'a mut String, } @@ -549,7 +551,7 @@ impl<'a> SnbtWriter<'a> { self.output.push('{'); let mut first = true; - for (k, v) in compound.iter() { + for (k, v) in compound { if !first { self.output.push(','); } diff --git a/crates/valence_nbt/src/tag.rs b/crates/valence_nbt/src/tag.rs index 4bc9e2639..ecb30f322 100644 --- a/crates/valence_nbt/src/tag.rs +++ b/crates/valence_nbt/src/tag.rs @@ -1,5 +1,6 @@ /// One of the possible NBT data types. #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)] +#[repr(u8)] pub enum Tag { // Variant order is significant! End, diff --git a/crates/valence_nbt/src/value.rs b/crates/valence_nbt/src/value.rs index 4cb30661e..4d2d7956e 100644 --- a/crates/valence_nbt/src/value.rs +++ b/crates/valence_nbt/src/value.rs @@ -315,7 +315,7 @@ impl<'a, S> ValueMut<'a, S> { /// Bools are usually represented as `0` or `1` bytes in NBT. impl From for Value { fn from(b: bool) -> Self { - Value::Byte(b as _) + Value::Byte(b.into()) } } diff --git a/crates/valence_protocol/Cargo.toml b/crates/valence_protocol/Cargo.toml index bee995eca..a2be4c5a1 100644 --- a/crates/valence_protocol/Cargo.toml +++ b/crates/valence_protocol/Cargo.toml @@ -13,28 +13,38 @@ encryption = ["dep:aes", "dep:cfb8"] compression = ["dep:flate2"] [dependencies] -bevy_ecs.workspace = true # TODO: make this optional valence_math.workspace = true -valence_generated.workspace = true +# valence_generated.workspace = true valence_text.workspace = true valence_nbt = { workspace = true, features = ["binary"] } valence_protocol_macros.workspace = true anyhow.workspace = true thiserror.workspace = true serde = { workspace = true, features = ["derive"] } -byteorder.workspace = true +# byteorder.workspace = true uuid.workspace = true valence_ident.workspace = true base64.workspace = true url.workspace = true serde_json.workspace = true -tracing.workspace = true +# tracing.workspace = true bytes.workspace = true bitfield-struct.workspace = true -derive_more = { workspace = true, features = ["from", "into", "deref", "deref_mut", "as_ref"] } +# derive_more = { workspace = true, features = ["try_from", "from", "into", "deref", "deref_mut", "as_ref"] } +num-derive.workspace = true +num-traits.workspace = true cfb8 = { workspace = true, optional = true } flate2 = { workspace = true, optional = true } aes = { workspace = true, optional = true } [dev-dependencies] rand.workspace = true + +[build-dependencies] +valence_build_utils.workspace = true +heck.workspace = true +proc-macro2.workspace = true +serde = { workspace = true, features = ["derive"] } +serde_json.workspace = true +quote.workspace = true +anyhow.workspace = true \ No newline at end of file diff --git a/crates/valence_protocol/build.rs b/crates/valence_protocol/build.rs new file mode 100644 index 000000000..c5852ed07 --- /dev/null +++ b/crates/valence_protocol/build.rs @@ -0,0 +1,53 @@ +use std::collections::BTreeMap; + +use heck::ToShoutySnakeCase; +use proc_macro2::TokenStream; +use quote::quote; +use serde::Deserialize; +use valence_build_utils::{ident, rerun_if_changed, write_generated_file}; + +#[derive(Deserialize)] +struct Packet { + name: String, + side: String, + state: String, + id: i32, +} + +fn main() -> anyhow::Result<()> { + rerun_if_changed(["extracted/packets.json"]); + + let packets: Vec = serde_json::from_str(include_str!("extracted/packets.json"))?; + + let mut states: BTreeMap = BTreeMap::new(); + + for packet in packets { + let stripped_name = packet.name.strip_suffix("Packet").unwrap_or(&packet.name); + + let name_ident = ident(stripped_name.to_shouty_snake_case()); + let id = packet.id; + + let doc = format!("Side: {}\n\nState: {}", packet.side, packet.state); + + states.entry(packet.state).or_default().extend(quote! { + #[doc = #doc] + pub const #name_ident: i32 = #id; + }); + } + + let out = states + .into_iter() + .map(|(state, consts)| { + let state = ident(state); + quote! { + pub mod #state { + #consts + } + } + }) + .collect(); + + write_generated_file(out, "packet_id.rs")?; + + Ok(()) +} diff --git a/crates/valence_protocol/extracted/packets.json b/crates/valence_protocol/extracted/packets.json new file mode 100644 index 000000000..41d97765b --- /dev/null +++ b/crates/valence_protocol/extracted/packets.json @@ -0,0 +1,1214 @@ +[ + { + "name": "HandshakeC2SPacket", + "state": "handshaking", + "side": "serverbound", + "id": 0 + }, + { + "name": "TeleportConfirmC2SPacket", + "state": "play", + "side": "serverbound", + "id": 0 + }, + { + "name": "QueryBlockNbtC2SPacket", + "state": "play", + "side": "serverbound", + "id": 1 + }, + { + "name": "UpdateDifficultyC2SPacket", + "state": "play", + "side": "serverbound", + "id": 2 + }, + { + "name": "MessageAcknowledgmentC2SPacket", + "state": "play", + "side": "serverbound", + "id": 3 + }, + { + "name": "CommandExecutionC2SPacket", + "state": "play", + "side": "serverbound", + "id": 4 + }, + { + "name": "ChatMessageC2SPacket", + "state": "play", + "side": "serverbound", + "id": 5 + }, + { + "name": "PlayerSessionC2SPacket", + "state": "play", + "side": "serverbound", + "id": 6 + }, + { + "name": "AcknowledgeChunksC2SPacket", + "state": "play", + "side": "serverbound", + "id": 7 + }, + { + "name": "ClientStatusC2SPacket", + "state": "play", + "side": "serverbound", + "id": 8 + }, + { + "name": "ClientOptionsC2SPacket", + "state": "play", + "side": "serverbound", + "id": 9 + }, + { + "name": "RequestCommandCompletionsC2SPacket", + "state": "play", + "side": "serverbound", + "id": 10 + }, + { + "name": "AcknowledgeReconfigurationC2SPacket", + "state": "play", + "side": "serverbound", + "id": 11 + }, + { + "name": "ButtonClickC2SPacket", + "state": "play", + "side": "serverbound", + "id": 12 + }, + { + "name": "ClickSlotC2SPacket", + "state": "play", + "side": "serverbound", + "id": 13 + }, + { + "name": "CloseHandledScreenC2SPacket", + "state": "play", + "side": "serverbound", + "id": 14 + }, + { + "name": "SlotChangedStateC2SPacket", + "state": "play", + "side": "serverbound", + "id": 15 + }, + { + "name": "CustomPayloadC2SPacket", + "state": "play", + "side": "serverbound", + "id": 16 + }, + { + "name": "BookUpdateC2SPacket", + "state": "play", + "side": "serverbound", + "id": 17 + }, + { + "name": "QueryEntityNbtC2SPacket", + "state": "play", + "side": "serverbound", + "id": 18 + }, + { + "name": "PlayerInteractEntityC2SPacket", + "state": "play", + "side": "serverbound", + "id": 19 + }, + { + "name": "JigsawGeneratingC2SPacket", + "state": "play", + "side": "serverbound", + "id": 20 + }, + { + "name": "KeepAliveC2SPacket", + "state": "play", + "side": "serverbound", + "id": 21 + }, + { + "name": "UpdateDifficultyLockC2SPacket", + "state": "play", + "side": "serverbound", + "id": 22 + }, + { + "name": "PositionAndOnGround", + "state": "play", + "side": "serverbound", + "id": 23 + }, + { + "name": "Full", + "state": "play", + "side": "serverbound", + "id": 24 + }, + { + "name": "LookAndOnGround", + "state": "play", + "side": "serverbound", + "id": 25 + }, + { + "name": "OnGroundOnly", + "state": "play", + "side": "serverbound", + "id": 26 + }, + { + "name": "VehicleMoveC2SPacket", + "state": "play", + "side": "serverbound", + "id": 27 + }, + { + "name": "BoatPaddleStateC2SPacket", + "state": "play", + "side": "serverbound", + "id": 28 + }, + { + "name": "PickFromInventoryC2SPacket", + "state": "play", + "side": "serverbound", + "id": 29 + }, + { + "name": "QueryPingC2SPacket", + "state": "play", + "side": "serverbound", + "id": 30 + }, + { + "name": "CraftRequestC2SPacket", + "state": "play", + "side": "serverbound", + "id": 31 + }, + { + "name": "UpdatePlayerAbilitiesC2SPacket", + "state": "play", + "side": "serverbound", + "id": 32 + }, + { + "name": "PlayerActionC2SPacket", + "state": "play", + "side": "serverbound", + "id": 33 + }, + { + "name": "ClientCommandC2SPacket", + "state": "play", + "side": "serverbound", + "id": 34 + }, + { + "name": "PlayerInputC2SPacket", + "state": "play", + "side": "serverbound", + "id": 35 + }, + { + "name": "CommonPongC2SPacket", + "state": "play", + "side": "serverbound", + "id": 36 + }, + { + "name": "RecipeCategoryOptionsC2SPacket", + "state": "play", + "side": "serverbound", + "id": 37 + }, + { + "name": "RecipeBookDataC2SPacket", + "state": "play", + "side": "serverbound", + "id": 38 + }, + { + "name": "RenameItemC2SPacket", + "state": "play", + "side": "serverbound", + "id": 39 + }, + { + "name": "ResourcePackStatusC2SPacket", + "state": "play", + "side": "serverbound", + "id": 40 + }, + { + "name": "AdvancementTabC2SPacket", + "state": "play", + "side": "serverbound", + "id": 41 + }, + { + "name": "SelectMerchantTradeC2SPacket", + "state": "play", + "side": "serverbound", + "id": 42 + }, + { + "name": "UpdateBeaconC2SPacket", + "state": "play", + "side": "serverbound", + "id": 43 + }, + { + "name": "UpdateSelectedSlotC2SPacket", + "state": "play", + "side": "serverbound", + "id": 44 + }, + { + "name": "UpdateCommandBlockC2SPacket", + "state": "play", + "side": "serverbound", + "id": 45 + }, + { + "name": "UpdateCommandBlockMinecartC2SPacket", + "state": "play", + "side": "serverbound", + "id": 46 + }, + { + "name": "CreativeInventoryActionC2SPacket", + "state": "play", + "side": "serverbound", + "id": 47 + }, + { + "name": "UpdateJigsawC2SPacket", + "state": "play", + "side": "serverbound", + "id": 48 + }, + { + "name": "UpdateStructureBlockC2SPacket", + "state": "play", + "side": "serverbound", + "id": 49 + }, + { + "name": "UpdateSignC2SPacket", + "state": "play", + "side": "serverbound", + "id": 50 + }, + { + "name": "HandSwingC2SPacket", + "state": "play", + "side": "serverbound", + "id": 51 + }, + { + "name": "SpectatorTeleportC2SPacket", + "state": "play", + "side": "serverbound", + "id": 52 + }, + { + "name": "PlayerInteractBlockC2SPacket", + "state": "play", + "side": "serverbound", + "id": 53 + }, + { + "name": "PlayerInteractItemC2SPacket", + "state": "play", + "side": "serverbound", + "id": 54 + }, + { + "name": "BundleSplitterPacket", + "state": "play", + "side": "clientbound", + "id": 0 + }, + { + "name": "EntitySpawnS2CPacket", + "state": "play", + "side": "clientbound", + "id": 1 + }, + { + "name": "ExperienceOrbSpawnS2CPacket", + "state": "play", + "side": "clientbound", + "id": 2 + }, + { + "name": "EntityAnimationS2CPacket", + "state": "play", + "side": "clientbound", + "id": 3 + }, + { + "name": "StatisticsS2CPacket", + "state": "play", + "side": "clientbound", + "id": 4 + }, + { + "name": "PlayerActionResponseS2CPacket", + "state": "play", + "side": "clientbound", + "id": 5 + }, + { + "name": "BlockBreakingProgressS2CPacket", + "state": "play", + "side": "clientbound", + "id": 6 + }, + { + "name": "BlockEntityUpdateS2CPacket", + "state": "play", + "side": "clientbound", + "id": 7 + }, + { + "name": "BlockEventS2CPacket", + "state": "play", + "side": "clientbound", + "id": 8 + }, + { + "name": "BlockUpdateS2CPacket", + "state": "play", + "side": "clientbound", + "id": 9 + }, + { + "name": "BossBarS2CPacket", + "state": "play", + "side": "clientbound", + "id": 10 + }, + { + "name": "DifficultyS2CPacket", + "state": "play", + "side": "clientbound", + "id": 11 + }, + { + "name": "ChunkSentS2CPacket", + "state": "play", + "side": "clientbound", + "id": 12 + }, + { + "name": "StartChunkSendS2CPacket", + "state": "play", + "side": "clientbound", + "id": 13 + }, + { + "name": "ChunkBiomeDataS2CPacket", + "state": "play", + "side": "clientbound", + "id": 14 + }, + { + "name": "ClearTitleS2CPacket", + "state": "play", + "side": "clientbound", + "id": 15 + }, + { + "name": "CommandSuggestionsS2CPacket", + "state": "play", + "side": "clientbound", + "id": 16 + }, + { + "name": "CommandTreeS2CPacket", + "state": "play", + "side": "clientbound", + "id": 17 + }, + { + "name": "CloseScreenS2CPacket", + "state": "play", + "side": "clientbound", + "id": 18 + }, + { + "name": "InventoryS2CPacket", + "state": "play", + "side": "clientbound", + "id": 19 + }, + { + "name": "ScreenHandlerPropertyUpdateS2CPacket", + "state": "play", + "side": "clientbound", + "id": 20 + }, + { + "name": "ScreenHandlerSlotUpdateS2CPacket", + "state": "play", + "side": "clientbound", + "id": 21 + }, + { + "name": "CooldownUpdateS2CPacket", + "state": "play", + "side": "clientbound", + "id": 22 + }, + { + "name": "ChatSuggestionsS2CPacket", + "state": "play", + "side": "clientbound", + "id": 23 + }, + { + "name": "CustomPayloadS2CPacket", + "state": "play", + "side": "clientbound", + "id": 24 + }, + { + "name": "EntityDamageS2CPacket", + "state": "play", + "side": "clientbound", + "id": 25 + }, + { + "name": "RemoveMessageS2CPacket", + "state": "play", + "side": "clientbound", + "id": 26 + }, + { + "name": "DisconnectS2CPacket", + "state": "play", + "side": "clientbound", + "id": 27 + }, + { + "name": "ProfilelessChatMessageS2CPacket", + "state": "play", + "side": "clientbound", + "id": 28 + }, + { + "name": "EntityStatusS2CPacket", + "state": "play", + "side": "clientbound", + "id": 29 + }, + { + "name": "ExplosionS2CPacket", + "state": "play", + "side": "clientbound", + "id": 30 + }, + { + "name": "UnloadChunkS2CPacket", + "state": "play", + "side": "clientbound", + "id": 31 + }, + { + "name": "GameStateChangeS2CPacket", + "state": "play", + "side": "clientbound", + "id": 32 + }, + { + "name": "OpenHorseScreenS2CPacket", + "state": "play", + "side": "clientbound", + "id": 33 + }, + { + "name": "DamageTiltS2CPacket", + "state": "play", + "side": "clientbound", + "id": 34 + }, + { + "name": "WorldBorderInitializeS2CPacket", + "state": "play", + "side": "clientbound", + "id": 35 + }, + { + "name": "KeepAliveS2CPacket", + "state": "play", + "side": "clientbound", + "id": 36 + }, + { + "name": "ChunkDataS2CPacket", + "state": "play", + "side": "clientbound", + "id": 37 + }, + { + "name": "WorldEventS2CPacket", + "state": "play", + "side": "clientbound", + "id": 38 + }, + { + "name": "ParticleS2CPacket", + "state": "play", + "side": "clientbound", + "id": 39 + }, + { + "name": "LightUpdateS2CPacket", + "state": "play", + "side": "clientbound", + "id": 40 + }, + { + "name": "GameJoinS2CPacket", + "state": "play", + "side": "clientbound", + "id": 41 + }, + { + "name": "MapUpdateS2CPacket", + "state": "play", + "side": "clientbound", + "id": 42 + }, + { + "name": "SetTradeOffersS2CPacket", + "state": "play", + "side": "clientbound", + "id": 43 + }, + { + "name": "MoveRelative", + "state": "play", + "side": "clientbound", + "id": 44 + }, + { + "name": "RotateAndMoveRelative", + "state": "play", + "side": "clientbound", + "id": 45 + }, + { + "name": "Rotate", + "state": "play", + "side": "clientbound", + "id": 46 + }, + { + "name": "VehicleMoveS2CPacket", + "state": "play", + "side": "clientbound", + "id": 47 + }, + { + "name": "OpenWrittenBookS2CPacket", + "state": "play", + "side": "clientbound", + "id": 48 + }, + { + "name": "OpenScreenS2CPacket", + "state": "play", + "side": "clientbound", + "id": 49 + }, + { + "name": "SignEditorOpenS2CPacket", + "state": "play", + "side": "clientbound", + "id": 50 + }, + { + "name": "CommonPingS2CPacket", + "state": "play", + "side": "clientbound", + "id": 51 + }, + { + "name": "PingResultS2CPacket", + "state": "play", + "side": "clientbound", + "id": 52 + }, + { + "name": "CraftFailedResponseS2CPacket", + "state": "play", + "side": "clientbound", + "id": 53 + }, + { + "name": "PlayerAbilitiesS2CPacket", + "state": "play", + "side": "clientbound", + "id": 54 + }, + { + "name": "ChatMessageS2CPacket", + "state": "play", + "side": "clientbound", + "id": 55 + }, + { + "name": "EndCombatS2CPacket", + "state": "play", + "side": "clientbound", + "id": 56 + }, + { + "name": "EnterCombatS2CPacket", + "state": "play", + "side": "clientbound", + "id": 57 + }, + { + "name": "DeathMessageS2CPacket", + "state": "play", + "side": "clientbound", + "id": 58 + }, + { + "name": "PlayerRemoveS2CPacket", + "state": "play", + "side": "clientbound", + "id": 59 + }, + { + "name": "PlayerListS2CPacket", + "state": "play", + "side": "clientbound", + "id": 60 + }, + { + "name": "LookAtS2CPacket", + "state": "play", + "side": "clientbound", + "id": 61 + }, + { + "name": "PlayerPositionLookS2CPacket", + "state": "play", + "side": "clientbound", + "id": 62 + }, + { + "name": "UnlockRecipesS2CPacket", + "state": "play", + "side": "clientbound", + "id": 63 + }, + { + "name": "EntitiesDestroyS2CPacket", + "state": "play", + "side": "clientbound", + "id": 64 + }, + { + "name": "RemoveEntityStatusEffectS2CPacket", + "state": "play", + "side": "clientbound", + "id": 65 + }, + { + "name": "ScoreboardScoreResetS2CPacket", + "state": "play", + "side": "clientbound", + "id": 66 + }, + { + "name": "ResourcePackRemoveS2CPacket", + "state": "play", + "side": "clientbound", + "id": 67 + }, + { + "name": "ResourcePackSendS2CPacket", + "state": "play", + "side": "clientbound", + "id": 68 + }, + { + "name": "PlayerRespawnS2CPacket", + "state": "play", + "side": "clientbound", + "id": 69 + }, + { + "name": "EntitySetHeadYawS2CPacket", + "state": "play", + "side": "clientbound", + "id": 70 + }, + { + "name": "ChunkDeltaUpdateS2CPacket", + "state": "play", + "side": "clientbound", + "id": 71 + }, + { + "name": "SelectAdvancementTabS2CPacket", + "state": "play", + "side": "clientbound", + "id": 72 + }, + { + "name": "ServerMetadataS2CPacket", + "state": "play", + "side": "clientbound", + "id": 73 + }, + { + "name": "OverlayMessageS2CPacket", + "state": "play", + "side": "clientbound", + "id": 74 + }, + { + "name": "WorldBorderCenterChangedS2CPacket", + "state": "play", + "side": "clientbound", + "id": 75 + }, + { + "name": "WorldBorderInterpolateSizeS2CPacket", + "state": "play", + "side": "clientbound", + "id": 76 + }, + { + "name": "WorldBorderSizeChangedS2CPacket", + "state": "play", + "side": "clientbound", + "id": 77 + }, + { + "name": "WorldBorderWarningTimeChangedS2CPacket", + "state": "play", + "side": "clientbound", + "id": 78 + }, + { + "name": "WorldBorderWarningBlocksChangedS2CPacket", + "state": "play", + "side": "clientbound", + "id": 79 + }, + { + "name": "SetCameraEntityS2CPacket", + "state": "play", + "side": "clientbound", + "id": 80 + }, + { + "name": "UpdateSelectedSlotS2CPacket", + "state": "play", + "side": "clientbound", + "id": 81 + }, + { + "name": "ChunkRenderDistanceCenterS2CPacket", + "state": "play", + "side": "clientbound", + "id": 82 + }, + { + "name": "ChunkLoadDistanceS2CPacket", + "state": "play", + "side": "clientbound", + "id": 83 + }, + { + "name": "PlayerSpawnPositionS2CPacket", + "state": "play", + "side": "clientbound", + "id": 84 + }, + { + "name": "ScoreboardDisplayS2CPacket", + "state": "play", + "side": "clientbound", + "id": 85 + }, + { + "name": "EntityTrackerUpdateS2CPacket", + "state": "play", + "side": "clientbound", + "id": 86 + }, + { + "name": "EntityAttachS2CPacket", + "state": "play", + "side": "clientbound", + "id": 87 + }, + { + "name": "EntityVelocityUpdateS2CPacket", + "state": "play", + "side": "clientbound", + "id": 88 + }, + { + "name": "EntityEquipmentUpdateS2CPacket", + "state": "play", + "side": "clientbound", + "id": 89 + }, + { + "name": "ExperienceBarUpdateS2CPacket", + "state": "play", + "side": "clientbound", + "id": 90 + }, + { + "name": "HealthUpdateS2CPacket", + "state": "play", + "side": "clientbound", + "id": 91 + }, + { + "name": "ScoreboardObjectiveUpdateS2CPacket", + "state": "play", + "side": "clientbound", + "id": 92 + }, + { + "name": "EntityPassengersSetS2CPacket", + "state": "play", + "side": "clientbound", + "id": 93 + }, + { + "name": "TeamS2CPacket", + "state": "play", + "side": "clientbound", + "id": 94 + }, + { + "name": "ScoreboardScoreUpdateS2CPacket", + "state": "play", + "side": "clientbound", + "id": 95 + }, + { + "name": "SimulationDistanceS2CPacket", + "state": "play", + "side": "clientbound", + "id": 96 + }, + { + "name": "SubtitleS2CPacket", + "state": "play", + "side": "clientbound", + "id": 97 + }, + { + "name": "WorldTimeUpdateS2CPacket", + "state": "play", + "side": "clientbound", + "id": 98 + }, + { + "name": "TitleS2CPacket", + "state": "play", + "side": "clientbound", + "id": 99 + }, + { + "name": "TitleFadeS2CPacket", + "state": "play", + "side": "clientbound", + "id": 100 + }, + { + "name": "PlaySoundFromEntityS2CPacket", + "state": "play", + "side": "clientbound", + "id": 101 + }, + { + "name": "PlaySoundS2CPacket", + "state": "play", + "side": "clientbound", + "id": 102 + }, + { + "name": "EnterReconfigurationS2CPacket", + "state": "play", + "side": "clientbound", + "id": 103 + }, + { + "name": "StopSoundS2CPacket", + "state": "play", + "side": "clientbound", + "id": 104 + }, + { + "name": "GameMessageS2CPacket", + "state": "play", + "side": "clientbound", + "id": 105 + }, + { + "name": "PlayerListHeaderS2CPacket", + "state": "play", + "side": "clientbound", + "id": 106 + }, + { + "name": "NbtQueryResponseS2CPacket", + "state": "play", + "side": "clientbound", + "id": 107 + }, + { + "name": "ItemPickupAnimationS2CPacket", + "state": "play", + "side": "clientbound", + "id": 108 + }, + { + "name": "EntityPositionS2CPacket", + "state": "play", + "side": "clientbound", + "id": 109 + }, + { + "name": "UpdateTickRateS2CPacket", + "state": "play", + "side": "clientbound", + "id": 110 + }, + { + "name": "TickStepS2CPacket", + "state": "play", + "side": "clientbound", + "id": 111 + }, + { + "name": "AdvancementUpdateS2CPacket", + "state": "play", + "side": "clientbound", + "id": 112 + }, + { + "name": "EntityAttributesS2CPacket", + "state": "play", + "side": "clientbound", + "id": 113 + }, + { + "name": "EntityStatusEffectS2CPacket", + "state": "play", + "side": "clientbound", + "id": 114 + }, + { + "name": "SynchronizeRecipesS2CPacket", + "state": "play", + "side": "clientbound", + "id": 115 + }, + { + "name": "SynchronizeTagsS2CPacket", + "state": "play", + "side": "clientbound", + "id": 116 + }, + { + "name": "QueryRequestC2SPacket", + "state": "status", + "side": "serverbound", + "id": 0 + }, + { + "name": "QueryPingC2SPacket", + "state": "status", + "side": "serverbound", + "id": 1 + }, + { + "name": "QueryResponseS2CPacket", + "state": "status", + "side": "clientbound", + "id": 0 + }, + { + "name": "PingResultS2CPacket", + "state": "status", + "side": "clientbound", + "id": 1 + }, + { + "name": "LoginHelloC2SPacket", + "state": "login", + "side": "serverbound", + "id": 0 + }, + { + "name": "LoginKeyC2SPacket", + "state": "login", + "side": "serverbound", + "id": 1 + }, + { + "name": "LoginQueryResponseC2SPacket", + "state": "login", + "side": "serverbound", + "id": 2 + }, + { + "name": "EnterConfigurationC2SPacket", + "state": "login", + "side": "serverbound", + "id": 3 + }, + { + "name": "LoginDisconnectS2CPacket", + "state": "login", + "side": "clientbound", + "id": 0 + }, + { + "name": "LoginHelloS2CPacket", + "state": "login", + "side": "clientbound", + "id": 1 + }, + { + "name": "LoginSuccessS2CPacket", + "state": "login", + "side": "clientbound", + "id": 2 + }, + { + "name": "LoginCompressionS2CPacket", + "state": "login", + "side": "clientbound", + "id": 3 + }, + { + "name": "LoginQueryRequestS2CPacket", + "state": "login", + "side": "clientbound", + "id": 4 + }, + { + "name": "ClientOptionsC2SPacket", + "state": "configuration", + "side": "serverbound", + "id": 0 + }, + { + "name": "CustomPayloadC2SPacket", + "state": "configuration", + "side": "serverbound", + "id": 1 + }, + { + "name": "ReadyC2SPacket", + "state": "configuration", + "side": "serverbound", + "id": 2 + }, + { + "name": "KeepAliveC2SPacket", + "state": "configuration", + "side": "serverbound", + "id": 3 + }, + { + "name": "CommonPongC2SPacket", + "state": "configuration", + "side": "serverbound", + "id": 4 + }, + { + "name": "ResourcePackStatusC2SPacket", + "state": "configuration", + "side": "serverbound", + "id": 5 + }, + { + "name": "CustomPayloadS2CPacket", + "state": "configuration", + "side": "clientbound", + "id": 0 + }, + { + "name": "DisconnectS2CPacket", + "state": "configuration", + "side": "clientbound", + "id": 1 + }, + { + "name": "ReadyS2CPacket", + "state": "configuration", + "side": "clientbound", + "id": 2 + }, + { + "name": "KeepAliveS2CPacket", + "state": "configuration", + "side": "clientbound", + "id": 3 + }, + { + "name": "CommonPingS2CPacket", + "state": "configuration", + "side": "clientbound", + "id": 4 + }, + { + "name": "DynamicRegistriesS2CPacket", + "state": "configuration", + "side": "clientbound", + "id": 5 + }, + { + "name": "ResourcePackRemoveS2CPacket", + "state": "configuration", + "side": "clientbound", + "id": 6 + }, + { + "name": "ResourcePackSendS2CPacket", + "state": "configuration", + "side": "clientbound", + "id": 7 + }, + { + "name": "FeaturesS2CPacket", + "state": "configuration", + "side": "clientbound", + "id": 8 + }, + { + "name": "SynchronizeTagsS2CPacket", + "state": "configuration", + "side": "clientbound", + "id": 9 + } +] \ No newline at end of file diff --git a/crates/valence_protocol/src/lib.rs b/crates/valence_protocol/src/lib.rs index e200795d8..5015f8421 100644 --- a/crates/valence_protocol/src/lib.rs +++ b/crates/valence_protocol/src/lib.rs @@ -1,473 +1,453 @@ -#![doc = include_str!("../README.md")] -#![deny( - rustdoc::broken_intra_doc_links, - rustdoc::private_intra_doc_links, - rustdoc::missing_crate_level_docs, - rustdoc::invalid_codeblock_attributes, - rustdoc::invalid_rust_codeblocks, - rustdoc::bare_urls, - rustdoc::invalid_html_tags -)] -#![warn( - trivial_casts, - trivial_numeric_casts, - unused_lifetimes, - unused_import_braces, - unreachable_pub, - clippy::dbg_macro -)] - -/// Used only by macros. Not public API. -#[doc(hidden)] -pub mod __private { - pub use anyhow::{anyhow, bail, ensure, Context, Result}; - - pub use crate::var_int::VarInt; - pub use crate::{Decode, Encode, Packet}; -} +use std::io::{Cursor, Write}; +use std::mem::{self, MaybeUninit}; + +use anyhow::{anyhow, bail, ensure, Context}; +use num_traits::{FromPrimitive, ToPrimitive}; + +use crate::var_int::VarIntReadError; -// This allows us to use our own proc macros internally. -extern crate self as valence_protocol; - -mod array; -mod biome_pos; -mod bit_set; -pub mod block_pos; -mod bounded; -mod byte_angle; -pub mod chunk_pos; -pub mod chunk_section_pos; -pub mod decode; -mod difficulty; -mod direction; -pub mod encode; -pub mod game_mode; -mod global_pos; -mod hand; -mod impls; -pub mod item; pub mod packets; -pub mod profile; -mod raw; -pub mod sound; pub mod var_int; -mod var_long; -mod velocity; - -use std::io::Write; - -use anyhow::Context; -pub use array::FixedArray; -pub use biome_pos::BiomePos; -pub use bit_set::FixedBitSet; -pub use block::{BlockKind, BlockState}; -pub use block_pos::BlockPos; -pub use bounded::Bounded; -pub use byte_angle::ByteAngle; -pub use chunk_pos::ChunkPos; -pub use chunk_section_pos::ChunkSectionPos; -pub use decode::PacketDecoder; -use derive_more::{From, Into}; -pub use difficulty::Difficulty; -pub use direction::Direction; -pub use encode::{PacketEncoder, WritePacket}; -pub use game_mode::GameMode; -pub use global_pos::GlobalPos; -pub use hand::Hand; -pub use ident::ident; -pub use item::{ItemKind, ItemStack}; -pub use packets::play::particle_s2c::Particle; -pub use raw::RawBytes; -use serde::{Deserialize, Serialize}; -pub use sound::Sound; -pub use text::Text; -pub use valence_generated::{block, packet_id, status_effects}; -pub use valence_ident::Ident; -pub use valence_protocol_macros::{Decode, Encode, Packet}; -pub use var_int::VarInt; -pub use var_long::VarLong; -pub use velocity::Velocity; -pub use { - anyhow, bytes, uuid, valence_ident as ident, valence_math as math, valence_nbt as nbt, - valence_text as text, -}; - -/// The maximum number of bytes in a single Minecraft packet. -pub const MAX_PACKET_SIZE: i32 = 2097152; - -/// The Minecraft protocol version this library currently targets. -pub const PROTOCOL_VERSION: i32 = 763; - -/// The stringified name of the Minecraft version this library currently -/// targets. -pub const MINECRAFT_VERSION: &str = "1.20.1"; - -/// How large a packet should be before it is compressed by the packet encoder. -/// -/// If the inner value is >= 0, then packets with encoded lengths >= to this -/// value will be compressed. If the value is negative, then compression is -/// disabled and no packets are compressed. -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, From, Into)] -pub struct CompressionThreshold(pub i32); - -impl CompressionThreshold { - /// No compression. - pub const DEFAULT: Self = Self(-1); +mod id { + include!(concat!(env!("OUT_DIR"), "/packet_id.rs")); +} + +pub trait Packet { + type Output<'a>; + + fn read_body<'a>(r: &mut impl McRead<'a>) -> anyhow::Result>; + + fn write_body(&self, w: &mut impl McWrite) -> anyhow::Result<()>; +} + +pub trait PacketMeta { + const ID: i32; } -/// No compression. -impl Default for CompressionThreshold { - fn default() -> Self { - Self::DEFAULT +pub trait PacketState {} + +pub trait PacketSide {} + +pub struct Handshaking; + +impl PacketState for Handshaking {} + +pub struct Status; + +impl PacketState for Status {} + +pub struct Login; + +impl PacketState for Login {} + +pub struct Configuration; + +impl PacketState for Configuration {} + +pub struct Serverbound; + +impl PacketSide for Serverbound {} +pub struct Clientbound; + +impl PacketSide for Clientbound {} + +pub trait McWrite { + /// Write a slice of bytes directly to the output without a length prefix. + fn write_bytes(&mut self, bytes: &[u8]) -> anyhow::Result<()>; + + fn write_byte_slice(&mut self, bytes: &[u8]) -> anyhow::Result<()> { + let len: i32 = bytes + .len() + .try_into() + .context("byte slice length exceeds `i32::MAX`")?; + + self.write_var_int(len)?; + self.write_bytes(bytes) + } + + /// Write a `str`. Errors if the string is longer than + /// [`DEFAULT_MAX_STRING_LENGTH`] in UTF-16 chars. + fn write_str(&mut self, str: &str) -> anyhow::Result<()> { + self.write_str_bounded(str, DEFAULT_MAX_STRING_LENGTH) + } + + fn write_str_bounded(&mut self, str: &str, max_char_count: u32) -> anyhow::Result<()> { + let char_count = str.encode_utf16().count(); + + ensure!( + char_count <= max_char_count as usize, + "utf-16 char count of string ({char_count}) exceeds maximum of {max_char_count}" + ); + + let len: i32 = str + .len() + .try_into() + .context("string length not representable as `i32`")?; + + self.write_var_int(len)?; + self.write_bytes(str.as_bytes()) + } + + fn write_enum(&mut self, val: &T) -> anyhow::Result<()> { + self.write_var_int(val.to_i32().context("enum not representable as `i32`")?) + } + + /// Write a variable length integer. + fn write_var_int(&mut self, int: i32) -> anyhow::Result<()> { + var_int::write_var_int(int, |b| self.write_bytes(&[b])) + } + + fn write_var_long(&mut self, int: i64) -> anyhow::Result<()> { + var_int::write_var_long(int, |b| self.write_bytes(&[b])) + } + + fn write_u8(&mut self, int: u8) -> anyhow::Result<()> { + self.write_bytes(&[int]) + } + + fn write_i8(&mut self, int: i8) -> anyhow::Result<()> { + self.write_bytes(&[int as u8]) + } + + fn write_u16(&mut self, int: u16) -> anyhow::Result<()> { + self.write_bytes(&int.to_be_bytes()) + } + + fn write_i16(&mut self, int: i16) -> anyhow::Result<()> { + self.write_bytes(&int.to_be_bytes()) + } + + fn write_u32(&mut self, int: u32) -> anyhow::Result<()> { + self.write_bytes(&int.to_be_bytes()) + } + + fn write_i32(&mut self, int: i32) -> anyhow::Result<()> { + self.write_bytes(&int.to_be_bytes()) + } + + fn write_u64(&mut self, int: u64) -> anyhow::Result<()> { + self.write_bytes(&int.to_be_bytes()) + } + + fn write_i64(&mut self, int: i64) -> anyhow::Result<()> { + self.write_bytes(&int.to_be_bytes()) + } + + fn write_u128(&mut self, int: u128) -> anyhow::Result<()> { + self.write_bytes(&int.to_be_bytes()) + } + + fn write_i128(&mut self, int: i128) -> anyhow::Result<()> { + self.write_bytes(&int.to_be_bytes()) + } + + fn write_f32(&mut self, int: f32) -> anyhow::Result<()> { + self.write_bytes(&int.to_be_bytes()) + } + + fn write_f64(&mut self, int: f64) -> anyhow::Result<()> { + self.write_bytes(&int.to_be_bytes()) } } -/// The `Encode` trait allows objects to be written to the Minecraft protocol. -/// It is the inverse of [`Decode`]. -/// -/// # Deriving -/// -/// This trait can be implemented automatically for structs and enums by using -/// the [`Encode`][macro] derive macro. All components of the type must -/// implement `Encode`. Components are encoded in the order they appear in the -/// type definition. -/// -/// For enums, the variant to encode is marked by a leading [`VarInt`] -/// discriminant (tag). The discriminant value can be changed using the -/// `#[packet(tag = ...)]` attribute on the variant in question. Discriminant -/// values are assigned to variants using rules similar to regular enum -/// discriminants. -/// -/// ``` -/// use valence_protocol::Encode; -/// -/// #[derive(Encode)] -/// struct MyStruct<'a> { -/// first: i32, -/// second: &'a str, -/// third: [f64; 3], -/// } -/// -/// #[derive(Encode)] -/// enum MyEnum { -/// First, // tag = 0 -/// Second, // tag = 1 -/// #[packet(tag = 25)] -/// Third, // tag = 25 -/// Fourth, // tag = 26 -/// } -/// -/// let value = MyStruct { -/// first: 10, -/// second: "hello", -/// third: [1.5, 3.14, 2.718], -/// }; -/// -/// let mut buf = vec![]; -/// value.encode(&mut buf).unwrap(); -/// -/// println!("{buf:?}"); -/// ``` -/// -/// [macro]: valence_protocol_macros::Encode -/// [`VarInt`]: var_int::VarInt -pub trait Encode { - /// Writes this object to the provided writer. - /// - /// If this type also implements [`Decode`] then successful calls to this - /// function returning `Ok(())` must always successfully [`decode`] using - /// the data that was written to the writer. The exact number of bytes - /// that were originally written must be consumed during the decoding. - /// - /// [`decode`]: Decode::decode - fn encode(&self, w: impl Write) -> anyhow::Result<()>; - - /// Like [`Encode::encode`], except that a whole slice of values is encoded. - /// - /// This method must be semantically equivalent to encoding every element of - /// the slice in sequence with no leading length prefix (which is exactly - /// what the default implementation does), but a more efficient - /// implementation may be used. - /// - /// This method is important for some types like `u8` where the entire slice - /// can be encoded in a single call to [`write_all`]. Because impl - /// specialization is unavailable in stable Rust at the time of writing, - /// we must make the slice specialization part of this trait. - /// - /// [`write_all`]: Write::write_all - fn encode_slice(slice: &[Self], mut w: impl Write) -> anyhow::Result<()> +/// A source of contiguous bytes for Minecraft packets to read from. The +/// interface is similar to Minecraft's `PacketByteBuf` class. +pub trait McRead<'a> { + fn read_bytes(&mut self, count: usize) -> anyhow::Result<&'a [u8]>; + + fn read_bytes_const(&mut self) -> anyhow::Result<&'a [u8; N]> { + Ok(self.read_bytes(N)?.try_into().expect("invalid slice len")) + } + + /// Read an array of values from the input. The array is not length + /// prefixed. + fn read_array(&mut self, mut f: F) -> anyhow::Result<[T; N]> where - Self: Sized, + F: FnMut(&mut Self) -> anyhow::Result, { - for value in slice { - value.encode(&mut w)?; + // TODO: use std::array::try_from_fn when stabilized. + + struct Guard { + array: [MaybeUninit; N], + initialized: usize, } - Ok(()) + impl Drop for Guard { + fn drop(&mut self) { + unsafe { std::ptr::drop_in_place(self.array.as_mut_slice()) }; + } + } + + // This is what `ArrayVec::new` does. + let initial_array: [MaybeUninit; N] = unsafe { MaybeUninit::uninit().assume_init() }; + + let mut guard = Guard { + array: initial_array, + initialized: 0, + }; + + while guard.initialized < N { + *unsafe { guard.array.get_unchecked_mut(guard.initialized) } = + MaybeUninit::new(f(self)?); + + guard.initialized += 1; + } + + let res: [T; N] = unsafe { std::mem::transmute_copy(&guard.array) }; + + std::mem::forget(guard); + + Ok(res) } -} -/// The `Decode` trait allows objects to be read from the Minecraft protocol. It -/// is the inverse of [`Encode`]. -/// -/// `Decode` is parameterized by a lifetime. This allows the decoded value to -/// borrow data from the byte slice it was read from. -/// -/// # Deriving -/// -/// This trait can be implemented automatically for structs and enums by using -/// the [`Decode`][macro] derive macro. All components of the type must -/// implement `Decode`. Components are decoded in the order they appear in the -/// type definition. -/// -/// For enums, the variant to decode is determined by a leading [`VarInt`] -/// discriminant (tag). The discriminant value can be changed using the -/// `#[packet(tag = ...)]` attribute on the variant in question. Discriminant -/// values are assigned to variants using rules similar to regular enum -/// discriminants. -/// -/// ``` -/// use valence_protocol::Decode; -/// -/// #[derive(PartialEq, Debug, Decode)] -/// struct MyStruct { -/// first: i32, -/// second: MyEnum, -/// } -/// -/// #[derive(PartialEq, Debug, Decode)] -/// enum MyEnum { -/// First, // tag = 0 -/// Second, // tag = 1 -/// #[packet(tag = 25)] -/// Third, // tag = 25 -/// Fourth, // tag = 26 -/// } -/// -/// let mut r: &[u8] = &[0, 0, 0, 0, 26]; -/// -/// let value = MyStruct::decode(&mut r).unwrap(); -/// let expected = MyStruct { -/// first: 0, -/// second: MyEnum::Fourth, -/// }; -/// -/// assert_eq!(value, expected); -/// assert!(r.is_empty()); -/// ``` -/// -/// [macro]: valence_protocol_macros::Decode -/// [`VarInt`]: var_int::VarInt -pub trait Decode<'a>: Sized { - /// Reads this object from the provided byte slice. - /// - /// Implementations of `Decode` are expected to shrink the slice from the - /// front as bytes are read. - fn decode(r: &mut &'a [u8]) -> anyhow::Result; -} + /// Read a varint-prefixed slice of bytes. There is no length limit. + fn read_byte_slice(&mut self) -> anyhow::Result<&'a [u8]> { + let len: u32 = self + .read_var_int()? + .try_into() + .context("negative byte slice length")?; -/// Types considered to be Minecraft packets. -/// -/// In serialized form, a packet begins with a [`VarInt`] packet ID followed by -/// the body of the packet. If present, the implementations of [`Encode`] and -/// [`Decode`] on `Self` are expected to only encode/decode the _body_ of this -/// packet without the leading ID. -pub trait Packet: std::fmt::Debug { - /// The leading VarInt ID of this packet. - const ID: i32; - /// The name of this packet for debugging purposes. - const NAME: &'static str; - /// The side this packet is intended for. - const SIDE: PacketSide; - /// The state in which this packet is used. - const STATE: PacketState; - - /// Encodes this packet's VarInt ID first, followed by the packet's body. - fn encode_with_id(&self, mut w: impl Write) -> anyhow::Result<()> + self.read_bytes(len as usize) + } + + fn read_str(&mut self) -> anyhow::Result<&'a str> { + self.read_str_bounded(DEFAULT_MAX_STRING_LENGTH) + } + + fn read_str_bounded(&mut self, max_char_count: u32) -> anyhow::Result<&'a str> { + let len: u32 = self + .read_var_int()? + .try_into() + .context("negative string length")?; + + let max_bytes_per_char = 4; + let max_byte_len = max_char_count * max_bytes_per_char; + + ensure!( + len <= max_byte_len, + "string byte length of {len} exceeds maximum of {max_byte_len}" + ); + + let str = std::str::from_utf8(self.read_bytes(len as usize)?)?; + + let utf16_char_count = str.encode_utf16().count(); + + ensure!( + utf16_char_count <= max_char_count as usize, + "UTF-16 string length of {utf16_char_count} exceeds maximum of {max_char_count}" + ); + + Ok(str) + } + + fn read_enum(&mut self) -> anyhow::Result { + let discriminant = self.read_var_int()?; + T::from_i32(discriminant).context("failed to decode enum") + } + + fn read_option(&mut self, f: F) -> anyhow::Result> where - Self: Encode, + F: FnOnce(&mut Self) -> anyhow::Result, { - VarInt(Self::ID) - .encode(&mut w) - .context("failed to encode packet ID")?; - - self.encode(w) + self.read_bool()?.then(|| f(self)).transpose() } -} -/// The side a packet is intended for. -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Serialize, Deserialize)] -pub enum PacketSide { - /// Server -> Client - Clientbound, - /// Client -> Server - Serverbound, -} + fn read_collection(&mut self, cf: CF, mut f: F) -> anyhow::Result + where + C: Extend, + CF: FnOnce(usize) -> C, + F: FnMut(&mut Self) -> anyhow::Result, + { + let len = self.read_var_int()?; + let len: usize = len.try_into().context("invalid collection length")?; -/// The statein which a packet is used. -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Serialize, Deserialize)] -pub enum PacketState { - Handshaking, - Status, - Login, - Play, -} + let mut collection = cf(cautious_capacity::(len)); -#[allow(dead_code)] -#[cfg(test)] -mod tests { - use std::borrow::Cow; + for _ in 0..len { + collection.extend([f(self)?]); + } - use bytes::BytesMut; + Ok(collection) + } - use super::*; - use crate::block_pos::BlockPos; - use crate::decode::PacketDecoder; - use crate::encode::PacketEncoder; - use crate::hand::Hand; - use crate::item::{ItemKind, ItemStack}; - use crate::text::{IntoText, Text}; - use crate::var_int::VarInt; - use crate::var_long::VarLong; - use crate::Ident; - - #[derive(Encode, Decode, Packet, Debug)] - #[packet(id = 1, side = PacketSide::Clientbound)] - struct RegularStruct { - foo: i32, - bar: bool, - baz: f64, - } - - #[derive(Encode, Decode, Packet, Debug)] - #[packet(id = 2, side = PacketSide::Clientbound)] - struct UnitStruct; - - #[derive(Encode, Decode, Packet, Debug)] - #[packet(id = 3, side = PacketSide::Clientbound)] - struct EmptyStruct {} - - #[derive(Encode, Decode, Packet, Debug)] - #[packet(id = 4, side = PacketSide::Clientbound)] - struct TupleStruct(i32, bool, f64); - - #[derive(Encode, Decode, Packet, Debug)] - #[packet(id = 5, side = PacketSide::Clientbound)] - struct StructWithGenerics<'z, T = ()> { - foo: &'z str, - bar: T, - } - - #[derive(Encode, Decode, Packet, Debug)] - #[packet(id = 6, side = PacketSide::Clientbound)] - struct TupleStructWithGenerics<'z, T = ()>(&'z str, i32, T); - - #[allow(unconditional_recursion, clippy::extra_unused_type_parameters)] - fn assert_has_impls<'a, T>() + fn read_vec(&mut self, f: F) -> anyhow::Result> where - T: Encode + Decode<'a> + Packet, + F: FnMut(&mut Self) -> anyhow::Result, { - assert_has_impls::(); - assert_has_impls::(); - assert_has_impls::(); - assert_has_impls::(); - assert_has_impls::(); - assert_has_impls::(); + self.read_collection(Vec::with_capacity, f) } - #[test] - fn packet_name() { - assert_eq!(RegularStruct::NAME, "RegularStruct"); - assert_eq!(UnitStruct::NAME, "UnitStruct"); - assert_eq!(StructWithGenerics::<()>::NAME, "StructWithGenerics"); - } - - #[cfg(feature = "encryption")] - const CRYPT_KEY: [u8; 16] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]; - - #[derive(PartialEq, Debug, Encode, Decode, Packet)] - #[packet(id = 42, side = PacketSide::Clientbound)] - struct TestPacket<'a> { - a: bool, - b: u8, - c: i32, - d: f32, - e: f64, - f: BlockPos, - g: Hand, - h: Ident>, - i: ItemStack, - j: Text, - k: VarInt, - l: VarLong, - m: &'a str, - n: &'a [u8; 10], - o: [u128; 3], - } - - impl<'a> TestPacket<'a> { - fn new(string: &'a str) -> Self { - Self { - a: true, - b: 12, - c: -999, - d: 5.001, - e: 1e10, - f: BlockPos::new(1, 2, 3), - g: Hand::Off, - h: Ident::new("minecraft:whatever").unwrap(), - i: ItemStack::new(ItemKind::WoodenSword, 12, None), - j: "my ".into_text() + "fancy".italic() + " text", - k: VarInt(123), - l: VarLong(456), - m: string, - n: &[7; 10], - o: [123456789; 3], - } + fn read_var_int(&mut self) -> anyhow::Result { + match var_int::read_var_int(|| self.read_u8()) { + Ok(int) => Ok(int), + Err(VarIntReadError::ReadError(e)) => Err(e), + Err(e @ VarIntReadError::TooLarge) => bail!(e), } } - fn check_test_packet(dec: &mut PacketDecoder, string: &str) { - let frame = dec.try_next_packet().unwrap().unwrap(); + fn read_var_long(&mut self) -> anyhow::Result { + match var_int::read_var_long(|| self.read_u8()) { + Ok(int) => Ok(int), + Err(VarIntReadError::ReadError(e)) => Err(e), + Err(e @ VarIntReadError::TooLarge) => Err(anyhow!(e)), + } + } - let pkt = frame.decode::().unwrap(); + fn read_bool(&mut self) -> anyhow::Result { + let byte = self.read_u8()?; + ensure!(byte <= 1, "boolean byte is not zero or one (got {byte})"); + Ok(byte == 1) + } - assert_eq!(&pkt, &TestPacket::new(string)); + fn read_u8(&mut self) -> anyhow::Result { + let &[byte] = self.read_bytes_const()?; + Ok(byte) } - #[test] - fn packets_round_trip() { - let mut buf = BytesMut::new(); + fn read_i8(&mut self) -> anyhow::Result { + let &[byte] = self.read_bytes_const()?; + Ok(byte as i8) + } + + fn read_u16(&mut self) -> anyhow::Result { + Ok(u16::from_be_bytes(*self.read_bytes_const()?)) + } + + fn read_i16(&mut self) -> anyhow::Result { + Ok(i16::from_be_bytes(*self.read_bytes_const()?)) + } + + fn read_u32(&mut self) -> anyhow::Result { + Ok(u32::from_be_bytes(*self.read_bytes_const()?)) + } + + fn read_i32(&mut self) -> anyhow::Result { + Ok(i32::from_be_bytes(*self.read_bytes_const()?)) + } + + fn read_u64(&mut self) -> anyhow::Result { + Ok(u64::from_be_bytes(*self.read_bytes_const()?)) + } + + fn read_i64(&mut self) -> anyhow::Result { + Ok(i64::from_be_bytes(*self.read_bytes_const()?)) + } + + fn read_u128(&mut self) -> anyhow::Result { + Ok(u128::from_be_bytes(*self.read_bytes_const()?)) + } + + fn read_i128(&mut self) -> anyhow::Result { + Ok(i128::from_be_bytes(*self.read_bytes_const()?)) + } + + fn read_f32(&mut self) -> anyhow::Result { + Ok(f32::from_be_bytes(*self.read_bytes_const()?)) + } - let mut enc = PacketEncoder::new(); + fn read_f64(&mut self) -> anyhow::Result { + Ok(f64::from_be_bytes(*self.read_bytes_const()?)) + } +} - enc.append_packet(&TestPacket::new("first")).unwrap(); - #[cfg(feature = "compression")] - enc.set_compression(0.into()); - enc.append_packet(&TestPacket::new("second")).unwrap(); - buf.unsplit(enc.take()); - #[cfg(feature = "encryption")] - enc.enable_encryption(&CRYPT_KEY); - enc.append_packet(&TestPacket::new("third")).unwrap(); - enc.prepend_packet(&TestPacket::new("fourth")).unwrap(); +pub const DEFAULT_MAX_STRING_LENGTH: u32 = 32767; - buf.unsplit(enc.take()); +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default, Debug)] +pub struct McWriter(pub W); - let mut dec = PacketDecoder::new(); +impl McWrite for McWriter { + fn write_bytes(&mut self, bytes: &[u8]) -> anyhow::Result<()> { + self.0.write_all(bytes).map_err(|e| e.into()) + } +} - dec.queue_bytes(buf); +impl From for McWriter { + fn from(value: W) -> Self { + Self(value) + } +} - check_test_packet(&mut dec, "first"); +impl<'a> McRead<'a> for Cursor<&'a [u8]> { + fn read_bytes(&mut self, count: usize) -> anyhow::Result<&'a [u8]> { + let remaining_slice = + &self.get_ref()[self.position().min(self.get_ref().len() as u64) as usize..]; - #[cfg(feature = "compression")] - dec.set_compression(0.into()); + ensure!( + remaining_slice.len() <= count, + "attempt to read {count} bytes, but cursor has {} bytes remaining", + remaining_slice.len() + ); - check_test_packet(&mut dec, "second"); + self.set_position(self.position() + count as u64); - #[cfg(feature = "encryption")] - dec.enable_encryption(&CRYPT_KEY); + Ok(&remaining_slice[..count]) + } +} - check_test_packet(&mut dec, "fourth"); - check_test_packet(&mut dec, "third"); +impl<'a> McRead<'a> for &'a [u8] { + fn read_bytes(&mut self, count: usize) -> anyhow::Result<&'a [u8]> { + ensure!( + count <= self.len(), + "attempt to read {count} bytes, but slice has length of {}", + self.len() + ); + + let (l, r) = self.split_at(count); + *self = r; + Ok(l) + } +} + +/// Prevents preallocating too much memory in case we get a malicious or invalid +/// sequence length. +fn cautious_capacity(size_hint: usize) -> usize { + const MAX_PREALLOC_BYTES: usize = 1024 * 1024; + + if mem::size_of::() == 0 { + 0 + } else { + size_hint.min(MAX_PREALLOC_BYTES / mem::size_of::()) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn write_read_array() { + let mut buf: McWriter> = McWriter(vec![]); + + buf.write_str("abc").unwrap(); + buf.write_str("123").unwrap(); + + let mut reader = buf.0.as_slice(); + + let res: [String; 2] = reader + .read_array(|r| r.read_str().map(String::from)) + .unwrap(); + + let _: [&str; 0] = reader.read_array(|r| r.read_str()).unwrap(); + + assert_eq!(&res, &["abc", "123"]); + } + + #[test] + #[should_panic = "expect the unexpected"] + fn read_array_panic() { + let mut buf: McWriter> = McWriter(vec![]); + + buf.write_str("abc").unwrap(); + buf.write_str("123").unwrap(); + + let mut reader = buf.0.as_slice(); + + let _: [String; 2] = reader + .read_array(|r| { + let s = r.read_str()?; + assert_eq!(s, "abc", "expect the unexpected"); + Ok(s.into()) + }) + .unwrap(); } } diff --git a/crates/valence_protocol/src/packets.rs b/crates/valence_protocol/src/packets.rs index 447c55149..df0bb1a57 100644 --- a/crates/valence_protocol/src/packets.rs +++ b/crates/valence_protocol/src/packets.rs @@ -1,366 +1,9 @@ -//! All of Minecraft's network packets. -//! -//! Packets are grouped in submodules according to the protocol stage they're -//! used in. Names are derived from the FabricMC Yarn mappings for consistency. +pub mod handshake_c2s; +pub mod ping_result_s2c; +pub mod query_request_c2s; +pub mod query_response_s2c; +pub mod query_ping_c2s; -pub mod handshaking { - pub mod handshake_c2s; - pub use handshake_c2s::HandshakeC2s; -} +pub use handshake_c2s::HandshakeC2s; -pub mod login { - pub mod login_compression_s2c; - pub use login_compression_s2c::LoginCompressionS2c; - pub mod login_disconnect_s2c; - pub use login_disconnect_s2c::LoginDisconnectS2c; - pub mod login_hello_c2s; - pub use login_hello_c2s::LoginHelloC2s; - pub mod login_hello_s2c; - pub use login_hello_s2c::LoginHelloS2c; - pub mod login_key_c2s; - pub use login_key_c2s::LoginKeyC2s; - pub mod login_query_request_s2c; - pub use login_query_request_s2c::LoginQueryRequestS2c; - pub mod login_query_response_c2s; - pub use login_query_response_c2s::LoginQueryResponseC2s; - pub mod login_success_s2c; - pub use login_success_s2c::LoginSuccessS2c; -} -pub mod play { - pub mod advancement_tab_c2s; - pub use advancement_tab_c2s::AdvancementTabC2s; - pub mod advancement_update_s2c; - pub use advancement_update_s2c::AdvancementUpdateS2c; - pub mod block_breaking_progress_s2c; - pub use block_breaking_progress_s2c::BlockBreakingProgressS2c; - pub mod block_entity_update_s2c; - pub use block_entity_update_s2c::BlockEntityUpdateS2c; - pub mod block_event_s2c; - pub use block_event_s2c::BlockEventS2c; - pub mod block_update_s2c; - pub use block_update_s2c::BlockUpdateS2c; - pub mod boat_paddle_state_c2s; - pub use boat_paddle_state_c2s::BoatPaddleStateC2s; - pub mod book_update_c2s; - pub use book_update_c2s::BookUpdateC2s; - pub mod boss_bar_s2c; - pub use boss_bar_s2c::BossBarS2c; - pub mod bundle_splitter_s2c; - pub use bundle_splitter_s2c::BundleSplitterS2c; - pub mod button_click_c2s; - pub use button_click_c2s::ButtonClickC2s; - pub mod chat_message_c2s; - pub use chat_message_c2s::ChatMessageC2s; - pub mod chat_message_s2c; - pub use chat_message_s2c::ChatMessageS2c; - pub mod chat_suggestions_s2c; - pub use chat_suggestions_s2c::ChatSuggestionsS2c; - pub mod chunk_biome_data_s2c; - pub use chunk_biome_data_s2c::ChunkBiomeDataS2c; - pub mod chunk_data_s2c; - pub use chunk_data_s2c::ChunkDataS2c; - pub mod chunk_delta_update_s2c; - pub use chunk_delta_update_s2c::ChunkDeltaUpdateS2c; - pub mod chunk_load_distance_s2c; - pub use chunk_load_distance_s2c::ChunkLoadDistanceS2c; - pub mod chunk_render_distance_center_s2c; - pub use chunk_render_distance_center_s2c::ChunkRenderDistanceCenterS2c; - pub mod clear_title_s2c; - pub use clear_title_s2c::ClearTitleS2c; - pub mod click_slot_c2s; - pub use click_slot_c2s::ClickSlotC2s; - pub mod client_command_c2s; - pub use client_command_c2s::ClientCommandC2s; - pub mod client_settings_c2s; - pub use client_settings_c2s::ClientSettingsC2s; - pub mod client_status_c2s; - pub use client_status_c2s::ClientStatusC2s; - pub mod close_handled_screen_c2s; - pub use close_handled_screen_c2s::CloseHandledScreenC2s; - pub mod close_screen_s2c; - pub use close_screen_s2c::CloseScreenS2c; - pub mod command_execution_c2s; - pub use command_execution_c2s::CommandExecutionC2s; - pub mod command_suggestions_s2c; - pub use command_suggestions_s2c::CommandSuggestionsS2c; - pub mod command_tree_s2c; - pub use command_tree_s2c::CommandTreeS2c; - pub mod cooldown_update_s2c; - pub use cooldown_update_s2c::CooldownUpdateS2c; - pub mod craft_failed_response_s2c; - pub use craft_failed_response_s2c::CraftFailedResponseS2c; - pub mod craft_request_c2s; - pub use craft_request_c2s::CraftRequestC2s; - pub mod creative_inventory_action_c2s; - pub use creative_inventory_action_c2s::CreativeInventoryActionC2s; - pub mod custom_payload_c2s; - pub use custom_payload_c2s::CustomPayloadC2s; - pub mod custom_payload_s2c; - pub use custom_payload_s2c::CustomPayloadS2c; - pub mod damage_tilt_s2c; - pub use damage_tilt_s2c::DamageTiltS2c; - pub mod death_message_s2c; - pub use death_message_s2c::DeathMessageS2c; - pub mod difficulty_s2c; - pub use difficulty_s2c::DifficultyS2c; - pub mod disconnect_s2c; - pub use disconnect_s2c::DisconnectS2c; - pub mod end_combat_s2c; - pub use end_combat_s2c::EndCombatS2c; - pub mod enter_combat_s2c; - pub use enter_combat_s2c::EnterCombatS2c; - pub mod entities_destroy_s2c; - pub use entities_destroy_s2c::EntitiesDestroyS2c; - pub mod entity_animation_s2c; - pub use entity_animation_s2c::EntityAnimationS2c; - pub mod entity_attach_s2c; - pub use entity_attach_s2c::EntityAttachS2c; - pub mod entity_attributes_s2c; - pub use entity_attributes_s2c::EntityAttributesS2c; - pub mod entity_damage_s2c; - pub use entity_damage_s2c::EntityDamageS2c; - pub mod entity_equipment_update_s2c; - pub use entity_equipment_update_s2c::EntityEquipmentUpdateS2c; - pub mod entity_passengers_set_s2c; - pub use entity_passengers_set_s2c::EntityPassengersSetS2c; - pub mod entity_position_s2c; - pub use entity_position_s2c::EntityPositionS2c; - pub mod entity_set_head_yaw_s2c; - pub use entity_set_head_yaw_s2c::EntitySetHeadYawS2c; - pub mod entity_spawn_s2c; - pub use entity_spawn_s2c::EntitySpawnS2c; - pub mod entity_status_effect_s2c; - pub use entity_status_effect_s2c::EntityStatusEffectS2c; - pub mod entity_status_s2c; - pub use entity_status_s2c::EntityStatusS2c; - pub mod entity_tracker_update_s2c; - pub use entity_tracker_update_s2c::EntityTrackerUpdateS2c; - pub mod entity_velocity_update_s2c; - pub use entity_velocity_update_s2c::EntityVelocityUpdateS2c; - pub mod experience_bar_update_s2c; - pub use experience_bar_update_s2c::ExperienceBarUpdateS2c; - pub mod experience_orb_spawn_s2c; - pub use experience_orb_spawn_s2c::ExperienceOrbSpawnS2c; - pub mod explosion_s2c; - pub use explosion_s2c::ExplosionS2c; - pub mod features_s2c; - pub use features_s2c::FeaturesS2c; - pub mod full_c2s; - pub use full_c2s::FullC2s; - pub mod game_join_s2c; - pub use game_join_s2c::GameJoinS2c; - pub mod game_message_s2c; - pub use game_message_s2c::GameMessageS2c; - pub mod game_state_change_s2c; - pub use game_state_change_s2c::GameStateChangeS2c; - pub mod hand_swing_c2s; - pub use hand_swing_c2s::HandSwingC2s; - pub mod health_update_s2c; - pub use health_update_s2c::HealthUpdateS2c; - pub mod inventory_s2c; - pub use inventory_s2c::InventoryS2c; - pub mod item_pickup_animation_s2c; - pub use item_pickup_animation_s2c::ItemPickupAnimationS2c; - pub mod jigsaw_generating_c2s; - pub use jigsaw_generating_c2s::JigsawGeneratingC2s; - pub mod keep_alive_c2s; - pub use keep_alive_c2s::KeepAliveC2s; - pub mod keep_alive_s2c; - pub use keep_alive_s2c::KeepAliveS2c; - pub mod light_update_s2c; - pub use light_update_s2c::LightUpdateS2c; - pub mod look_and_on_ground_c2s; - pub use look_and_on_ground_c2s::LookAndOnGroundC2s; - pub mod look_at_s2c; - pub use look_at_s2c::LookAtS2c; - pub mod map_update_s2c; - pub use map_update_s2c::MapUpdateS2c; - pub mod message_acknowledgment_c2s; - pub use message_acknowledgment_c2s::MessageAcknowledgmentC2s; - pub mod move_relative_s2c; - pub use move_relative_s2c::MoveRelativeS2c; - pub mod nbt_query_response_s2c; - pub use nbt_query_response_s2c::NbtQueryResponseS2c; - pub mod on_ground_only_c2s; - pub use on_ground_only_c2s::OnGroundOnlyC2s; - pub mod open_horse_screen_s2c; - pub use open_horse_screen_s2c::OpenHorseScreenS2c; - pub mod open_screen_s2c; - pub use open_screen_s2c::OpenScreenS2c; - pub mod open_written_book_s2c; - pub use open_written_book_s2c::OpenWrittenBookS2c; - pub mod overlay_message_s2c; - pub use overlay_message_s2c::OverlayMessageS2c; - pub mod particle_s2c; - pub use particle_s2c::ParticleS2c; - pub mod pick_from_inventory_c2s; - pub use pick_from_inventory_c2s::PickFromInventoryC2s; - pub mod play_ping_s2c; - pub use play_ping_s2c::PlayPingS2c; - pub mod play_pong_c2s; - pub use play_pong_c2s::PlayPongC2s; - pub mod play_sound_from_entity_s2c; - pub use play_sound_from_entity_s2c::PlaySoundFromEntityS2c; - pub mod play_sound_s2c; - pub use play_sound_s2c::PlaySoundS2c; - pub mod player_abilities_s2c; - pub use player_abilities_s2c::PlayerAbilitiesS2c; - pub mod player_action_c2s; - pub use player_action_c2s::PlayerActionC2s; - pub mod player_action_response_s2c; - pub use player_action_response_s2c::PlayerActionResponseS2c; - pub mod player_input_c2s; - pub use player_input_c2s::PlayerInputC2s; - pub mod player_interact_block_c2s; - pub use player_interact_block_c2s::PlayerInteractBlockC2s; - pub mod player_interact_entity_c2s; - pub use player_interact_entity_c2s::PlayerInteractEntityC2s; - pub mod player_interact_item_c2s; - pub use player_interact_item_c2s::PlayerInteractItemC2s; - pub mod player_list_header_s2c; - pub use player_list_header_s2c::PlayerListHeaderS2c; - pub mod player_list_s2c; - pub use player_list_s2c::PlayerListS2c; - pub mod player_position_look_s2c; - pub use player_position_look_s2c::PlayerPositionLookS2c; - pub mod player_remove_s2c; - pub use player_remove_s2c::PlayerRemoveS2c; - pub mod player_respawn_s2c; - pub use player_respawn_s2c::PlayerRespawnS2c; - pub mod player_session_c2s; - pub use player_session_c2s::PlayerSessionC2s; - pub mod player_spawn_position_s2c; - pub use player_spawn_position_s2c::PlayerSpawnPositionS2c; - pub mod player_spawn_s2c; - pub use player_spawn_s2c::PlayerSpawnS2c; - pub mod position_and_on_ground_c2s; - pub use position_and_on_ground_c2s::PositionAndOnGroundC2s; - pub mod profileless_chat_message_s2c; - pub use profileless_chat_message_s2c::ProfilelessChatMessageS2c; - pub mod query_block_nbt_c2s; - pub use query_block_nbt_c2s::QueryBlockNbtC2s; - pub mod query_entity_nbt_c2s; - pub use query_entity_nbt_c2s::QueryEntityNbtC2s; - pub mod recipe_book_data_c2s; - pub use recipe_book_data_c2s::RecipeBookDataC2s; - pub mod recipe_category_options_c2s; - pub use recipe_category_options_c2s::RecipeCategoryOptionsC2s; - pub mod remove_entity_status_effect_s2c; - pub use remove_entity_status_effect_s2c::RemoveEntityStatusEffectS2c; - pub mod remove_message_s2c; - pub use remove_message_s2c::RemoveMessageS2c; - pub mod rename_item_c2s; - pub use rename_item_c2s::RenameItemC2s; - pub mod request_command_completions_c2s; - pub use request_command_completions_c2s::RequestCommandCompletionsC2s; - pub mod resource_pack_send_s2c; - pub use resource_pack_send_s2c::ResourcePackSendS2c; - pub mod resource_pack_status_c2s; - pub use resource_pack_status_c2s::ResourcePackStatusC2s; - pub mod rotate_s2c; - pub use rotate_s2c::RotateS2c; - pub mod rotate_and_move_relative_s2c; - pub use rotate_and_move_relative_s2c::RotateAndMoveRelativeS2c; - pub mod scoreboard_display_s2c; - pub use scoreboard_display_s2c::ScoreboardDisplayS2c; - pub mod scoreboard_objective_update_s2c; - pub use scoreboard_objective_update_s2c::ScoreboardObjectiveUpdateS2c; - pub mod scoreboard_player_update_s2c; - pub use scoreboard_player_update_s2c::ScoreboardPlayerUpdateS2c; - pub mod screen_handler_property_update_s2c; - pub use screen_handler_property_update_s2c::ScreenHandlerPropertyUpdateS2c; - pub mod screen_handler_slot_update_s2c; - pub use screen_handler_slot_update_s2c::ScreenHandlerSlotUpdateS2c; - pub mod select_advancement_tab_s2c; - pub use select_advancement_tab_s2c::SelectAdvancementTabS2c; - pub mod select_merchant_trade_c2s; - pub use select_merchant_trade_c2s::SelectMerchantTradeC2s; - pub mod server_metadata_s2c; - pub use server_metadata_s2c::ServerMetadataS2c; - pub mod set_camera_entity_s2c; - pub use set_camera_entity_s2c::SetCameraEntityS2c; - pub mod set_trade_offers_s2c; - pub use set_trade_offers_s2c::SetTradeOffersS2c; - pub mod sign_editor_open_s2c; - pub use sign_editor_open_s2c::SignEditorOpenS2c; - pub mod simulation_distance_s2c; - pub use simulation_distance_s2c::SimulationDistanceS2c; - pub mod spectator_teleport_c2s; - pub use spectator_teleport_c2s::SpectatorTeleportC2s; - pub mod statistics_s2c; - pub use statistics_s2c::StatisticsS2c; - pub mod stop_sound_s2c; - pub use stop_sound_s2c::StopSoundS2c; - pub mod subtitle_s2c; - pub use subtitle_s2c::SubtitleS2c; - pub mod synchronize_recipes_s2c; - pub use synchronize_recipes_s2c::SynchronizeRecipesS2c; - pub mod synchronize_tags_s2c; - pub use synchronize_tags_s2c::SynchronizeTagsS2c; - pub mod team_s2c; - pub use team_s2c::TeamS2c; - pub mod teleport_confirm_c2s; - pub use teleport_confirm_c2s::TeleportConfirmC2s; - pub mod title_fade_s2c; - pub use title_fade_s2c::TitleFadeS2c; - pub mod title_s2c; - pub use title_s2c::TitleS2c; - pub mod unload_chunk_s2c; - pub use unload_chunk_s2c::UnloadChunkS2c; - pub mod unlock_recipes_s2c; - pub use unlock_recipes_s2c::UnlockRecipesS2c; - pub mod update_beacon_c2s; - pub use update_beacon_c2s::UpdateBeaconC2s; - pub mod update_command_block_c2s; - pub use update_command_block_c2s::UpdateCommandBlockC2s; - pub mod update_command_block_minecart_c2s; - pub use update_command_block_minecart_c2s::UpdateCommandBlockMinecartC2s; - pub mod update_difficulty_c2s; - pub use update_difficulty_c2s::UpdateDifficultyC2s; - pub mod update_difficulty_lock_c2s; - pub use update_difficulty_lock_c2s::UpdateDifficultyLockC2s; - pub mod update_jigsaw_c2s; - pub use update_jigsaw_c2s::UpdateJigsawC2s; - pub mod update_player_abilities_c2s; - pub use update_player_abilities_c2s::UpdatePlayerAbilitiesC2s; - pub mod update_selected_slot_c2s; - pub use update_selected_slot_c2s::UpdateSelectedSlotC2s; - pub mod update_selected_slot_s2c; - pub use update_selected_slot_s2c::UpdateSelectedSlotS2c; - pub mod update_sign_c2s; - pub use update_sign_c2s::UpdateSignC2s; - pub mod update_structure_block_c2s; - pub use update_structure_block_c2s::UpdateStructureBlockC2s; - pub mod vehicle_move_c2s; - pub use vehicle_move_c2s::VehicleMoveC2s; - pub mod vehicle_move_s2c; - pub use vehicle_move_s2c::VehicleMoveS2c; - pub mod world_border_center_changed_s2c; - pub use world_border_center_changed_s2c::WorldBorderCenterChangedS2c; - pub mod world_border_initialize_s2c; - pub use world_border_initialize_s2c::WorldBorderInitializeS2c; - pub mod world_border_interpolate_size_s2c; - pub use world_border_interpolate_size_s2c::WorldBorderInterpolateSizeS2c; - pub mod world_border_size_changed_s2c; - pub use world_border_size_changed_s2c::WorldBorderSizeChangedS2c; - pub mod world_border_warning_blocks_changed_s2c; - pub use world_border_warning_blocks_changed_s2c::WorldBorderWarningBlocksChangedS2c; - pub mod world_border_warning_time_changed_s2c; - pub use world_border_warning_time_changed_s2c::WorldBorderWarningTimeChangedS2c; - pub mod world_event_s2c; - pub use world_event_s2c::WorldEventS2c; - pub mod world_time_update_s2c; - pub use world_time_update_s2c::WorldTimeUpdateS2c; -} - -pub mod status { - pub mod query_ping_c2s; - pub use query_ping_c2s::QueryPingC2s; - pub mod query_pong_s2c; - pub use query_pong_s2c::QueryPongS2c; - pub mod query_request_c2s; - pub use query_request_c2s::QueryRequestC2s; - pub mod query_response_s2c; - pub use query_response_s2c::QueryResponseS2c; -} diff --git a/crates/valence_protocol/src/packets/handshake_c2s.rs b/crates/valence_protocol/src/packets/handshake_c2s.rs new file mode 100644 index 000000000..32b9f0a22 --- /dev/null +++ b/crates/valence_protocol/src/packets/handshake_c2s.rs @@ -0,0 +1,43 @@ +use num_derive::{FromPrimitive, ToPrimitive}; + +use crate::{Handshaking, McRead, McWrite, Packet, PacketMeta, Serverbound}; + +#[derive(Copy, Clone, Debug)] +pub struct HandshakeC2s<'a> { + pub protocol_version: i32, + pub address: &'a str, + pub port: i32, + pub intended_state: ConnectionIntent, +} + +impl Packet for HandshakeC2s<'_> { + type Output<'a> = HandshakeC2s<'a>; + + fn read_body<'a>(r: &mut impl McRead<'a>) -> anyhow::Result> { + Ok(HandshakeC2s { + protocol_version: r.read_var_int()?, + address: r.read_str_bounded(255)?, + port: r.read_var_int()?, + intended_state: r.read_enum::()?, + }) + } + + fn write_body(&self, w: &mut impl McWrite) -> anyhow::Result<()> { + w.write_var_int(self.protocol_version)?; + w.write_str(self.address)?; + w.write_var_int(self.port)?; + w.write_enum(&self.intended_state)?; + Ok(()) + } + +} + +impl PacketMeta for HandshakeC2s<'_> { + const ID: i32 = crate::id::handshaking::HANDSHAKE_C2S; +} + +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, FromPrimitive, ToPrimitive)] +pub enum ConnectionIntent { + Status = 1, + Login = 2, +} diff --git a/crates/valence_protocol/src/packets/ping_result_s2c.rs b/crates/valence_protocol/src/packets/ping_result_s2c.rs new file mode 100644 index 000000000..08139c7e1 --- /dev/null +++ b/crates/valence_protocol/src/packets/ping_result_s2c.rs @@ -0,0 +1,24 @@ +use crate::{Clientbound, McRead, McWrite, Packet, PacketMeta, Status}; + +#[derive(Copy, Clone, Debug)] +pub struct PingResultS2c { + pub start_time: i64, +} + +impl Packet for PingResultS2c { + type Output<'a> = Self; + + fn read_body<'a>(r: &mut impl McRead<'a>) -> anyhow::Result> { + Ok(Self { + start_time: r.read_i64()?, + }) + } + + fn write_body(&self, w: &mut impl McWrite) -> anyhow::Result<()> { + w.write_i64(self.start_time) + } +} + +impl PacketMeta for PingResultS2c { + const ID: i32 = crate::id::status::PING_RESULT_S2C; +} diff --git a/crates/valence_protocol/src/packets/query_ping_c2s.rs b/crates/valence_protocol/src/packets/query_ping_c2s.rs new file mode 100644 index 000000000..6b16e1ea1 --- /dev/null +++ b/crates/valence_protocol/src/packets/query_ping_c2s.rs @@ -0,0 +1,24 @@ +use crate::{McRead, McWrite, Packet, PacketMeta, Serverbound, Status}; + +#[derive(Copy, Clone, Debug)] +pub struct QueryPingC2s { + pub start_time: i64, +} + +impl Packet for QueryPingC2s { + type Output<'a> = Self; + + fn read_body<'a>(r: &mut impl McRead<'a>) -> anyhow::Result> { + Ok(Self { + start_time: r.read_i64()?, + }) + } + + fn write_body(&self, w: &mut impl McWrite) -> anyhow::Result<()> { + w.write_i64(self.start_time) + } +} + +impl PacketMeta for QueryPingC2s { + const ID: i32 = crate::id::status::QUERY_PING_C2S; +} diff --git a/crates/valence_protocol/src/packets/query_request_c2s.rs b/crates/valence_protocol/src/packets/query_request_c2s.rs new file mode 100644 index 000000000..0d96c65f6 --- /dev/null +++ b/crates/valence_protocol/src/packets/query_request_c2s.rs @@ -0,0 +1,20 @@ +use crate::{McRead, McWrite, Packet, PacketMeta, Serverbound, Status}; + +#[derive(Copy, Clone, Debug)] +pub struct QueryRequestC2s; + +impl Packet for QueryRequestC2s { + type Output<'a> = Self; + + fn read_body<'a>(_r: &mut impl McRead<'a>) -> anyhow::Result> { + Ok(Self) + } + + fn write_body(&self, _w: &mut impl McWrite) -> anyhow::Result<()> { + Ok(()) + } +} + +impl PacketMeta for QueryRequestC2s { + const ID: i32 = crate::id::status::QUERY_REQUEST_C2S; +} diff --git a/crates/valence_protocol/src/packets/query_response_s2c.rs b/crates/valence_protocol/src/packets/query_response_s2c.rs new file mode 100644 index 000000000..b7920978d --- /dev/null +++ b/crates/valence_protocol/src/packets/query_response_s2c.rs @@ -0,0 +1,24 @@ +use crate::{Clientbound, Packet, PacketMeta, Status}; + +#[derive(Copy, Clone, Debug)] +pub struct QueryResponseS2c<'a> { + pub json: &'a str +} + +impl Packet for QueryResponseS2c<'_> { + type Output<'a> = QueryResponseS2c<'a>; + + fn read_body<'a>(r: &mut impl crate::McRead<'a>) -> anyhow::Result> { + Ok(QueryResponseS2c { + json: r.read_str()?, + }) + } + + fn write_body(&self, w: &mut impl crate::McWrite) -> anyhow::Result<()> { + w.write_str(self.json) + } +} + +impl PacketMeta for QueryResponseS2c<'_> { + const ID: i32 = crate::id::status::QUERY_RESPONSE_S2C; +} diff --git a/crates/valence_protocol/src/var_int.rs b/crates/valence_protocol/src/var_int.rs index 17f1531b7..d0c35b77e 100644 --- a/crates/valence_protocol/src/var_int.rs +++ b/crates/valence_protocol/src/var_int.rs @@ -1,154 +1,97 @@ -use std::io::{Read, Write}; - -use anyhow::bail; -use byteorder::ReadBytesExt; -use derive_more::{Deref, DerefMut, From, Into}; -use serde::{Deserialize, Serialize}; use thiserror::Error; -use crate::{Decode, Encode}; - -/// An `i32` encoded with variable length. -#[derive( - Clone, - Copy, - Default, - PartialEq, - Eq, - PartialOrd, - Ord, - Hash, - Debug, - Deref, - DerefMut, - From, - Into, - Serialize, - Deserialize, -)] -#[serde(transparent)] -#[repr(transparent)] -pub struct VarInt(pub i32); - -impl VarInt { - /// The maximum number of bytes a VarInt could occupy when read from and - /// written to the Minecraft protocol. - pub const MAX_SIZE: usize = 5; - - /// Returns the exact number of bytes this varint will write when - /// [`Encode::encode`] is called, assuming no error occurs. - pub const fn written_size(self) -> usize { - match self.0 { - 0 => 1, - n => (31 - n.leading_zeros() as usize) / 7 + 1, - } - } +#[inline] +pub fn read_var_int(mut read_byte: F) -> Result> +where + F: FnMut() -> Result, +{ + let mut val = 0; + for i in 0..VAR_INT_MAX_LEN { + let byte = read_byte()?; - pub fn decode_partial(mut r: impl Read) -> Result { - let mut val = 0; - for i in 0..Self::MAX_SIZE { - let byte = r.read_u8().map_err(|_| VarIntDecodeError::Incomplete)?; - val |= (byte as i32 & 0b01111111) << (i * 7); - if byte & 0b10000000 == 0 { - return Ok(val); - } - } + val |= (byte as i32 & 0x7F) << (i * 7); - Err(VarIntDecodeError::TooLarge) + if byte & 0x80 == 0 { + return Ok(val); + } } -} -#[derive(Copy, Clone, PartialEq, Eq, Debug, Error)] -pub enum VarIntDecodeError { - #[error("incomplete VarInt decode")] - Incomplete, - #[error("VarInt is too large")] - TooLarge, + Err(VarIntReadError::TooLarge) } -impl Encode for VarInt { - // Adapted from VarInt-Simd encode - // https://github.com/as-com/varint-simd/blob/0f468783da8e181929b01b9c6e9f741c1fe09825/src/encode/mod.rs#L71 - fn encode(&self, mut w: impl Write) -> anyhow::Result<()> { - let x = self.0 as u64; - let stage1 = (x & 0x000000000000007f) - | ((x & 0x0000000000003f80) << 1) - | ((x & 0x00000000001fc000) << 2) - | ((x & 0x000000000fe00000) << 3) - | ((x & 0x00000000f0000000) << 4); - - let leading = stage1.leading_zeros(); - - let unused_bytes = (leading - 1) >> 3; - let bytes_needed = 8 - unused_bytes; - - // set all but the last MSBs - let msbs = 0x8080808080808080; - let msbmask = 0xffffffffffffffff >> (((8 - bytes_needed + 1) << 3) - 1); - - let merged = stage1 | (msbs & msbmask); - let bytes = merged.to_le_bytes(); +#[inline] +pub fn write_var_int(int: i32, mut write_byte: F) -> Result<(), E> +where + F: FnMut(u8) -> Result<(), E>, +{ + let mut int = int as u32; + + loop { + if int & 0xFFFFFF80 == 0 { + write_byte(int as u8)?; + return Ok(()); + } - w.write_all(unsafe { bytes.get_unchecked(..bytes_needed as usize) })?; + write_byte(int as u8 | 0x80)?; - Ok(()) + int >>= 7; } } -impl Decode<'_> for VarInt { - fn decode(r: &mut &[u8]) -> anyhow::Result { - let mut val = 0; - for i in 0..Self::MAX_SIZE { - let byte = r.read_u8()?; - val |= (byte as i32 & 0b01111111) << (i * 7); - if byte & 0b10000000 == 0 { - return Ok(VarInt(val)); - } +#[inline] +pub fn read_var_long(mut read_byte: F) -> Result> +where + F: FnMut() -> Result, +{ + let mut val = 0; + for i in 0..VAR_LONG_MAX_LEN { + let byte = read_byte()?; + + val |= (byte as i64 & 0x7F) << (i * 7); + + if byte & 0x80 == 0 { + return Ok(val); } - bail!("VarInt is too large") } + + Err(VarIntReadError::TooLarge) } -#[cfg(test)] -mod tests { - use rand::{thread_rng, Rng}; - - use super::*; - - #[test] - fn varint_written_size() { - let mut rng = thread_rng(); - let mut buf = vec![]; - - for n in (0..100_000) - .map(|_| rng.gen()) - .chain([0, i32::MIN, i32::MAX]) - .map(VarInt) - { - buf.clear(); - n.encode(&mut buf).unwrap(); - assert_eq!(buf.len(), n.written_size()); +#[inline] +pub fn write_var_long(int: i64, mut write_byte: F) -> Result<(), E> +where + F: FnMut(u8) -> Result<(), E>, +{ + let mut int = int as u64; + + loop { + if int & 0xFFFFFFFFFFFFFF80 == 0 { + write_byte(int as u8)?; + return Ok(()); } - } - #[test] - fn varint_round_trip() { - let mut rng = thread_rng(); - let mut buf = vec![]; + write_byte(int as u8 | 0x80)?; - for n in (0..1_000_000) - .map(|_| rng.gen()) - .chain([0, i32::MIN, i32::MAX]) - { - VarInt(n).encode(&mut buf).unwrap(); + int >>= 7; + } +} - let mut slice = buf.as_slice(); - assert!(slice.len() <= VarInt::MAX_SIZE); +/// Returns the number of bytes the varint will occupy once written. +#[inline] +pub fn var_int_len(int: i32) -> usize { + match int { + 0 => 1, + n => (31 - n.leading_zeros() as usize) / 7 + 1, + } +} - assert_eq!(n, VarInt::decode(&mut slice).unwrap().0); +pub const VAR_INT_MAX_LEN: usize = 5; +pub const VAR_LONG_MAX_LEN: usize = 10; - assert!(slice.is_empty()); - buf.clear(); - } - } +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Error)] +pub enum VarIntReadError { + #[error(transparent)] + ReadError(#[from] E), + #[error("var int is too large")] + TooLarge, } diff --git a/crates/valence_protocol_macros/src/lib.rs b/crates/valence_protocol_macros/src/lib.rs index 46c552024..15ed27376 100644 --- a/crates/valence_protocol_macros/src/lib.rs +++ b/crates/valence_protocol_macros/src/lib.rs @@ -1,21 +1,4 @@ #![doc = include_str!("../README.md")] -#![deny( - rustdoc::broken_intra_doc_links, - rustdoc::private_intra_doc_links, - rustdoc::missing_crate_level_docs, - rustdoc::invalid_codeblock_attributes, - rustdoc::invalid_rust_codeblocks, - rustdoc::bare_urls, - rustdoc::invalid_html_tags -)] -#![warn( - trivial_casts, - trivial_numeric_casts, - unused_lifetimes, - unused_import_braces, - unreachable_pub, - clippy::dbg_macro -)] use proc_macro::TokenStream as StdTokenStream; use proc_macro2::TokenStream; diff --git a/crates/valence_protocol_macros/src/packet.rs b/crates/valence_protocol_macros/src/packet.rs index 9d2cdd559..171b05f2f 100644 --- a/crates/valence_protocol_macros/src/packet.rs +++ b/crates/valence_protocol_macros/src/packet.rs @@ -2,67 +2,88 @@ use heck::ToShoutySnakeCase; use proc_macro2::{Ident, Span, TokenStream}; use quote::quote; use syn::spanned::Spanned; -use syn::{parse2, parse_quote, Attribute, DeriveInput, Error, Expr, LitInt, LitStr, Result}; +use syn::{parse2, parse_quote, Attribute, DeriveInput, Error, Expr, LitInt, LitStr, Result, Type}; use crate::add_trait_bounds; pub(super) fn derive_packet(item: TokenStream) -> Result { let mut input = parse2::(item)?; - let packet_attr = parse_packet_helper_attr(&input.attrs)?.unwrap_or_default(); + let mut output = TokenStream::new(); - let name = input.ident.clone(); + let mut helper_attrs = vec![]; - let name_str = if let Some(attr_name) = packet_attr.name { - attr_name.value() - } else { - name.to_string() - }; - - let packet_id: Expr = match packet_attr.id { - Some(expr) => expr, - None => match syn::parse_str::(&name_str.to_shouty_snake_case()) { - Ok(ident) => parse_quote!(::valence_protocol::packet_id::#ident), - Err(_) => { - return Err(Error::new( - packet_attr.span, - "missing valid `id = ...` value from `packet` attr", - )) - } - }, - }; + for attr in &input.attrs { + if let Some(helper) = parse_packet_helper_attr(attr)? { + helper_attrs.push(helper); + } + } - add_trait_bounds(&mut input.generics, quote!(::std::fmt::Debug)); + if helper_attrs.is_empty() { + helper_attrs.push(PacketAttr { + span: Span::call_site(), + id: Default::default(), + tag: Default::default(), + name: Default::default(), + side: Default::default(), + state: Default::default(), + }); + } - let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl(); + for packet_attr in helper_attrs { + let type_name = input.ident.clone(); + + let name_str = if let Some(attr_name) = packet_attr.name { + attr_name.value() + } else { + type_name.to_string() + }; + + let packet_id: Expr = match packet_attr.id { + Some(expr) => expr, + None => match syn::parse_str::(&name_str.to_shouty_snake_case()) { + Ok(ident) => parse_quote!(::valence_protocol::packet::id::#ident), + Err(_) => { + return Err(Error::new( + packet_attr.span, + "missing valid `id = ...` value from `packet` helper attribute", + )) + } + }, + }; + + add_trait_bounds(&mut input.generics, quote!(::std::fmt::Debug)); + + let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl(); + + let side = if let Some(side_attr) = packet_attr.side { + side_attr + } else if name_str.to_lowercase().ends_with("s2c") { + parse_quote!(::valence_protocol::packet::PacketS2c) + } else if name_str.to_lowercase().ends_with("c2s") { + parse_quote!(::valence_protocol::packet::PacketC2s) + } else { + return Err(Error::new( + packet_attr.span, + "missing `side = ...` value from `packet` helper attribute", + )); + }; + + let state = packet_attr + .state + .unwrap_or_else(|| parse_quote!(::valence_protocol::packet::PacketPlay)); + + output.extend(quote! { + impl #impl_generics ::valence_protocol::packet::Packet<#side, #state> for #type_name #ty_generics + #where_clause + { + const ID: i32 = #packet_id; + const NAME: &'static str = #name_str; + } + }); + } - let side = if let Some(side_attr) = packet_attr.side { - side_attr - } else if name_str.to_lowercase().ends_with("s2c") { - parse_quote!(::valence_protocol::PacketSide::Clientbound) - } else if name_str.to_lowercase().ends_with("c2s") { - parse_quote!(::valence_protocol::PacketSide::Serverbound) - } else { - return Err(Error::new( - packet_attr.span, - "missing `side = PacketSide::...` value from `packet` attribute", - )); - }; - - let state = packet_attr - .state - .unwrap_or_else(|| parse_quote!(::valence_protocol::PacketState::Play)); - - Ok(quote! { - impl #impl_generics ::valence_protocol::__private::Packet for #name #ty_generics - #where_clause - { - const ID: i32 = #packet_id; - const NAME: &'static str = #name_str; - const SIDE: ::valence_protocol::PacketSide = #side; - const STATE: ::valence_protocol::PacketState = #state; - } - }) + Ok(output) } struct PacketAttr { @@ -70,59 +91,44 @@ struct PacketAttr { id: Option, tag: Option, name: Option, - side: Option, - state: Option, + side: Option, + state: Option, } -impl Default for PacketAttr { - fn default() -> Self { - Self { - span: Span::call_site(), - id: Default::default(), - tag: Default::default(), - name: Default::default(), - side: Default::default(), - state: Default::default(), - } - } -} - -fn parse_packet_helper_attr(attrs: &[Attribute]) -> Result> { - for attr in attrs { - if attr.path().is_ident("packet") { - let mut res = PacketAttr { - span: attr.span(), - id: None, - tag: None, - name: None, - side: None, - state: None, - }; - - attr.parse_nested_meta(|meta| { - if meta.path.is_ident("id") { - res.id = Some(meta.value()?.parse::()?); - Ok(()) - } else if meta.path.is_ident("tag") { - res.tag = Some(meta.value()?.parse::()?.base10_parse::()?); - Ok(()) - } else if meta.path.is_ident("name") { - res.name = Some(meta.value()?.parse::()?); - Ok(()) - } else if meta.path.is_ident("side") { - res.side = Some(meta.value()?.parse::()?); - Ok(()) - } else if meta.path.is_ident("state") { - res.state = Some(meta.value()?.parse::()?); - Ok(()) - } else { - Err(meta.error("unrecognized packet argument")) - } - })?; +fn parse_packet_helper_attr(attr: &Attribute) -> Result> { + if attr.path().is_ident("packet") { + let mut res = PacketAttr { + span: attr.span(), + id: None, + tag: None, + name: None, + side: None, + state: None, + }; + + attr.parse_nested_meta(|meta| { + if meta.path.is_ident("id") { + res.id = Some(meta.value()?.parse::()?); + Ok(()) + } else if meta.path.is_ident("tag") { + res.tag = Some(meta.value()?.parse::()?.base10_parse::()?); + Ok(()) + } else if meta.path.is_ident("name") { + res.name = Some(meta.value()?.parse::()?); + Ok(()) + } else if meta.path.is_ident("side") { + res.side = Some(meta.value()?.parse::()?); + Ok(()) + } else if meta.path.is_ident("state") { + res.state = Some(meta.value()?.parse::()?); + Ok(()) + } else { + Err(meta.error("unrecognized #[packet(...)] argument")) + } + })?; - return Ok(Some(res)); - } + Ok(Some(res)) + } else { + Ok(None) } - - Ok(None) } diff --git a/crates/valence_text/Cargo.toml b/crates/valence_text/Cargo.toml index e1092f2ab..313a3cdd5 100644 --- a/crates/valence_text/Cargo.toml +++ b/crates/valence_text/Cargo.toml @@ -14,4 +14,7 @@ serde_json.workspace = true thiserror.workspace = true uuid = { workspace = true, features = ["serde"] } valence_ident.workspace = true -valence_nbt.workspace = true \ No newline at end of file +valence_nbt.workspace = true + +[lints] +workspace = true diff --git a/crates/valence_text/src/color.rs b/crates/valence_text/src/color.rs index c05831587..53e28821d 100644 --- a/crates/valence_text/src/color.rs +++ b/crates/valence_text/src/color.rs @@ -108,9 +108,9 @@ impl RgbColor { pub fn to_named_lossy(self) -> NamedColor { // calculates the squared distance between 2 colors fn squared_distance(c1: RgbColor, c2: RgbColor) -> i32 { - (c1.r as i32 - c2.r as i32).pow(2) - + (c1.g as i32 - c2.g as i32).pow(2) - + (c1.b as i32 - c2.b as i32).pow(2) + (i32::from(c1.r) - i32::from(c2.r).pow(2)) + + (i32::from(c1.g) - i32::from(c2.g)).pow(2) + + (i32::from(c1.b) - i32::from(c2.b)).pow(2) } [ @@ -297,7 +297,7 @@ impl TryFrom<&str> for RgbColor { impl Serialize for Color { fn serialize(&self, serializer: S) -> Result { - format!("{}", self).serialize(serializer) + format!("{self}").serialize(serializer) } } diff --git a/crates/valence_text/src/lib.rs b/crates/valence_text/src/lib.rs index 3c572c8ae..35650ea94 100644 --- a/crates/valence_text/src/lib.rs +++ b/crates/valence_text/src/lib.rs @@ -617,7 +617,7 @@ impl<'de> Deserialize<'de> for Text { } fn visit_str(self, v: &str) -> Result { - Ok(Text::text(v.to_string())) + Ok(Text::text(v.to_owned())) } fn visit_string(self, v: String) -> Result { diff --git a/extractor/build.gradle b/extractor/build.gradle index 3181fb394..3ea20aff0 100644 --- a/extractor/build.gradle +++ b/extractor/build.gradle @@ -1,5 +1,5 @@ plugins { - id 'fabric-loom' version '1.2-SNAPSHOT' + id 'fabric-loom' version '1.5-SNAPSHOT' } sourceCompatibility = JavaVersion.VERSION_17 diff --git a/extractor/copy_extractor_output.sh b/extractor/copy_extractor_output.sh index 5724b665b..3962c65d2 100755 --- a/extractor/copy_extractor_output.sh +++ b/extractor/copy_extractor_output.sh @@ -7,8 +7,9 @@ set -euxo pipefail cd "$(dirname "$0")" -cp run/valence_extractor_output/{entities,misc}.json ../crates/valence_entity/extracted/ -cp run/valence_extractor_output/{attributes,blocks,effects,items,packets,sounds}.json ../crates/valence_generated/extracted/ -cp run/valence_extractor_output/translation_keys.json ../crates/valence_lang/extracted/ -cp run/valence_extractor_output/{registry_codec.dat,tags.json} ../crates/valence_registry/extracted/ -cp run/valence_extractor_output/packets.json ../tools/packet_inspector/extracted/ +# cp run/valence_extractor_output/{entities,misc}.json ../crates/valence_entity/extracted/ +# cp run/valence_extractor_output/{attributes,blocks,effects,items,packets,sounds}.json ../crates/valence_generated/extracted/ +# cp run/valence_extractor_output/translation_keys.json ../crates/valence_lang/extracted/ +# cp run/valence_extractor_output/{registry_codec.dat,tags.json} ../crates/valence_registry/extracted/ +# cp run/valence_extractor_output/packets.json ../tools/packet_inspector/extracted/ +cp run/valence_extractor_output/packets.json ../crates/valence_protocol/extracted/ diff --git a/extractor/gradle.properties b/extractor/gradle.properties index f75e33115..58257a494 100644 --- a/extractor/gradle.properties +++ b/extractor/gradle.properties @@ -2,12 +2,12 @@ org.gradle.jvmargs=-Xmx1G # Fabric Properties # check these on https://fabricmc.net/develop -minecraft_version=1.20.1 -yarn_mappings=1.20.1+build.1 -loader_version=0.14.21 +minecraft_version=1.20.4 +yarn_mappings=1.20.4+build.3 +loader_version=0.15.6 # Mod Properties mod_version=1.0.0 maven_group=dev.00a archives_base_name=valence-extractor # Dependencies -fabric_version=0.83.0+1.20.1 +fabric_version=0.95.0+1.20.4 diff --git a/extractor/gradle/wrapper/gradle-wrapper.jar b/extractor/gradle/wrapper/gradle-wrapper.jar index 249e5832f..d64cd4917 100644 Binary files a/extractor/gradle/wrapper/gradle-wrapper.jar and b/extractor/gradle/wrapper/gradle-wrapper.jar differ diff --git a/extractor/gradle/wrapper/gradle-wrapper.properties b/extractor/gradle/wrapper/gradle-wrapper.properties index 59bc51a20..1af9e0930 100644 --- a/extractor/gradle/wrapper/gradle-wrapper.properties +++ b/extractor/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,7 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip +networkTimeout=10000 +validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/extractor/gradlew b/extractor/gradlew index a69d9cb6c..1aa94a426 100755 --- a/extractor/gradlew +++ b/extractor/gradlew @@ -55,7 +55,7 @@ # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. @@ -80,13 +80,11 @@ do esac done -APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit - -APP_NAME="Gradle" +# This is normally unused +# shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum @@ -133,22 +131,29 @@ location of your Java installation." fi else JAVACMD=java - which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." + fi fi # Increase the maximum file descriptors if we can. if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac @@ -193,11 +198,15 @@ if "$cygwin" || "$msys" ; then done fi -# Collect all arguments for the java command; -# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of -# shell script including quotes and variable substitutions, so put them in -# double quotes to make sure that they get re-expanded; and -# * put everything else in single quotes, so that it's not re-expanded. + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ diff --git a/extractor/gradlew.bat b/extractor/gradlew.bat index 53a6b238d..6689b85be 100644 --- a/extractor/gradlew.bat +++ b/extractor/gradlew.bat @@ -26,6 +26,7 @@ if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% diff --git a/extractor/src/main/java/rs/valence/extractor/DummyPlayerEntity.java b/extractor/src/main/java/rs/valence/extractor/DummyPlayerEntity.java index 9e8a4974d..b7a7d2b31 100644 --- a/extractor/src/main/java/rs/valence/extractor/DummyPlayerEntity.java +++ b/extractor/src/main/java/rs/valence/extractor/DummyPlayerEntity.java @@ -7,13 +7,18 @@ import net.minecraft.network.encryption.PlayerPublicKey; import net.minecraft.util.math.BlockPos; import net.minecraft.world.World; + +import java.util.UUID; + import org.jetbrains.annotations.Nullable; public class DummyPlayerEntity extends PlayerEntity { public static final DummyPlayerEntity INSTANCE; static { - INSTANCE = Main.magicallyInstantiate(DummyPlayerEntity.class); + INSTANCE = new DummyPlayerEntity(DummyWorld.INSTANCE, new BlockPos(0, 0, 0), 0, + new GameProfile(new UUID(0xDEADBEEF, 0xDEADBEEF), "dummy"), + null); try { var dataTrackerField = Entity.class.getDeclaredField("dataTracker"); @@ -21,12 +26,14 @@ public class DummyPlayerEntity extends PlayerEntity { dataTrackerField.set(INSTANCE, new DataTracker(INSTANCE)); INSTANCE.initDataTracker(); + INSTANCE.setHealth(20); // idk why player health is set to 1 by default } catch (NoSuchFieldException | IllegalAccessException e) { throw new RuntimeException(e); } } - private DummyPlayerEntity(World world, BlockPos pos, float yaw, GameProfile gameProfile, @Nullable PlayerPublicKey publicKey) { + private DummyPlayerEntity(World world, BlockPos pos, float yaw, GameProfile gameProfile, + @Nullable PlayerPublicKey publicKey) { super(world, pos, yaw, gameProfile); } diff --git a/extractor/src/main/java/rs/valence/extractor/DummyWorld.java b/extractor/src/main/java/rs/valence/extractor/DummyWorld.java index a33bc35c1..362574c2c 100644 --- a/extractor/src/main/java/rs/valence/extractor/DummyWorld.java +++ b/extractor/src/main/java/rs/valence/extractor/DummyWorld.java @@ -30,6 +30,7 @@ import net.minecraft.world.entity.EntityLookup; import net.minecraft.world.event.GameEvent; import net.minecraft.world.tick.QueryableTickScheduler; +import net.minecraft.world.tick.TickManager; import org.jetbrains.annotations.Nullable; import java.util.List; import java.util.function.Supplier; @@ -90,6 +91,11 @@ public Entity getEntityById(int id) { return null; } + @Override + public TickManager getTickManager() { + return null; + } + @Nullable @Override public MapState getMapState(String id) { @@ -158,7 +164,7 @@ public DynamicRegistryManager getRegistryManager() { @Override public FeatureSet getEnabledFeatures() { - return FeatureSet.of(FeatureFlags.VANILLA, FeatureFlags.BUNDLE); + return FeatureSet.of(FeatureFlags.VANILLA, FeatureFlags.BUNDLE, FeatureFlags.UPDATE_1_21); } @Override diff --git a/extractor/src/main/java/rs/valence/extractor/Main.java b/extractor/src/main/java/rs/valence/extractor/Main.java index ce183b88c..cb898e178 100644 --- a/extractor/src/main/java/rs/valence/extractor/Main.java +++ b/extractor/src/main/java/rs/valence/extractor/Main.java @@ -1,126 +1,144 @@ package rs.valence.extractor; +import com.google.gson.Gson; import com.google.gson.GsonBuilder; +import com.google.gson.JsonArray; import com.google.gson.JsonElement; -import io.netty.handler.codec.EncoderException; + import net.fabricmc.api.ModInitializer; import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents; -import net.minecraft.nbt.NbtIo; +import net.minecraft.server.MinecraftServer; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; import rs.valence.extractor.extractors.*; import sun.reflect.ReflectionFactory; -import java.io.FileWriter; +import java.io.DataOutput; +import java.io.DataOutputStream; +import java.io.FileOutputStream; import java.io.IOException; -import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.TreeMap; +import java.nio.charset.StandardCharsets; public class Main implements ModInitializer { public static final String MOD_ID = "valence_extractor"; public static final Logger LOGGER = LoggerFactory.getLogger(MOD_ID); - /** - * Magically creates an instance of a concrete class without calling its constructor. - */ - public static T magicallyInstantiate(Class clazz) { - var rf = ReflectionFactory.getReflectionFactory(); - try { - var objCon = Object.class.getDeclaredConstructor(); - var con = rf.newConstructorForSerialization(clazz, objCon); - return clazz.cast(con.newInstance()); - } catch (Throwable e) { - throw new IllegalArgumentException("Failed to magically instantiate " + clazz.getName(), e); - } - } - @Override public void onInitialize() { - LOGGER.info("Starting extractors..."); - - var extractors = new Extractor[]{ - new Attributes(), - new Blocks(), - new Effects(), - new Enchants(), - new Entities(), - new Misc(), - new Items(), - new Packets(), - new Sounds(), - new TranslationKeys(), - }; - - Path outputDirectory; - try { - outputDirectory = Files.createDirectories(Paths.get("valence_extractor_output")); - } catch (IOException e) { - LOGGER.info("Failed to create output directory.", e); - return; - } - - var gson = new GsonBuilder().setPrettyPrinting().disableHtmlEscaping().serializeNulls().create(); + ServerLifecycleEvents.SERVER_STARTING.register(server -> { + LOGGER.info("Starting extractors..."); + + var extractors = new Extractor[]{ + new Attributes(), + new Blocks(), + new Effects(), + new Enchants(), + new Entities(), + new Misc(), + new Items(), + new Packets(), + new Sounds(), + new TranslationKeys(), + new Tags(), + }; - for (var ext : extractors) { + Path outputDirectory; try { - var out = outputDirectory.resolve(ext.fileName()); - var fileWriter = new FileWriter(out.toFile(), StandardCharsets.UTF_8); - gson.toJson(ext.extract(), fileWriter); - fileWriter.close(); - LOGGER.info("Wrote " + out.toAbsolutePath()); - } catch (Exception e) { - LOGGER.error("Extractor for \"" + ext.fileName() + "\" failed.", e); + outputDirectory = Files.createDirectories(Paths.get("valence_extractor_output")); + } catch (IOException e) { + LOGGER.info("Failed to create output directory.", e); + return; } - } - ServerLifecycleEvents.SERVER_STARTING.register(server -> { - LOGGER.info("Server starting, Running startup extractors..."); - // TODO: make `Codec` implement `Extractor` - var codecExtractor = new Codec(server); - try { - var out = outputDirectory.resolve(codecExtractor.fileName()); - var compound = codecExtractor.extract(); - // read the compound byte-wise and write it to the file - try { - NbtIo.write(compound, out.toFile()); - } catch (IOException var3) { - throw new EncoderException(var3); - } + var gson = new GsonBuilder().setPrettyPrinting().disableHtmlEscaping().serializeNulls().create(); - LOGGER.info("Wrote " + out.toAbsolutePath()); - } catch (Exception e) { - LOGGER.error("Extractor for \"" + codecExtractor.fileName() + "\" failed.", e); - } - - var startupExtractors = new Extractor[]{ - new Tags(server), - }; + for (var extractor : extractors) { + var fileName = extractor.fileName(); - for (var ext : startupExtractors) { try { - var out = outputDirectory.resolve(ext.fileName()); - var fileWriter = new FileWriter(out.toFile(), StandardCharsets.UTF_8); - gson.toJson(ext.extract(), fileWriter); - fileWriter.close(); + var out = outputDirectory.resolve(fileName); + var stream = new DataOutputStream(new FileOutputStream(out.toFile())); + + extractor.extract(server, stream, gson); + + stream.close(); LOGGER.info("Wrote " + out.toAbsolutePath()); } catch (Exception e) { - LOGGER.error("Extractor for \"" + ext.fileName() + "\" failed.", e); + LOGGER.error("Extractor for \"" + fileName + "\" failed.", e); } } - LOGGER.info("Done."); + LOGGER.info("Done! Errors below this line can be ignored."); + server.shutdown(); }); } public interface Extractor { + /** The name of the file generated by this extractor. */ String fileName(); - - JsonElement extract() throws Exception; + /** Extracts the data to the provided data output. */ + void extract(MinecraftServer server, DataOutput output, Gson gson) throws Exception; } public record Pair(T left, U right) { } + + /** + * Magically creates an instance of a concrete class without calling its constructor. + */ + public static T magicallyInstantiate(Class clazz) { + var rf = ReflectionFactory.getReflectionFactory(); + try { + var objCon = Object.class.getDeclaredConstructor(); + var con = rf.newConstructorForSerialization(clazz, objCon); + return clazz.cast(con.newInstance()); + } catch (Throwable e) { + throw new IllegalArgumentException("Failed to magically instantiate " + clazz.getName(), e); + } + } + + public static void writeJson(DataOutput output, Gson gson, JsonElement element) throws IOException { + output.write(gson.toJson(element).getBytes(StandardCharsets.UTF_8)); + } + + /** + * Converts a string to PascalCase. + * + * @param str The string to convert. + * @return The converted string. + */ + public static String toPascalCase(String str) { + StringBuilder result = new StringBuilder(); + boolean capitalizeNext = true; + + for (char c : str.toCharArray()) { + if (Character.isWhitespace(c) || c == '_') { + capitalizeNext = true; + } else if (capitalizeNext) { + result.append(Character.toUpperCase(c)); + capitalizeNext = false; + } else { + result.append(Character.toLowerCase(c)); + } + } + + return result.toString(); + } + + /** + * Converts a TreeMap to a JsonArray, ignoring the keys. + */ + public static JsonArray treeMapToJsonArray(TreeMap map) { + var array = new JsonArray(); + for (var value : map.values()) { + array.add(value); + } + return array; + } } diff --git a/extractor/src/main/java/rs/valence/extractor/ValenceUtils.java b/extractor/src/main/java/rs/valence/extractor/ValenceUtils.java deleted file mode 100644 index 847da11ab..000000000 --- a/extractor/src/main/java/rs/valence/extractor/ValenceUtils.java +++ /dev/null @@ -1,34 +0,0 @@ -package rs.valence.extractor; - -/** - * Utility class for various methods. - */ -public class ValenceUtils { - private ValenceUtils() { - throw new UnsupportedOperationException("This class cannot be instantiated"); - } - - /** - * Converts a string to PascalCase. - * - * @param str The string to convert. - * @return The converted string. - */ - public static String toPascalCase(String str) { - StringBuilder result = new StringBuilder(); - boolean capitalizeNext = true; - - for (char c : str.toCharArray()) { - if (Character.isWhitespace(c) || c == '_') { - capitalizeNext = true; - } else if (capitalizeNext) { - result.append(Character.toUpperCase(c)); - capitalizeNext = false; - } else { - result.append(Character.toLowerCase(c)); - } - } - - return result.toString(); - } -} diff --git a/extractor/src/main/java/rs/valence/extractor/extractors/Attributes.java b/extractor/src/main/java/rs/valence/extractor/extractors/Attributes.java index c22654e9f..2da705891 100644 --- a/extractor/src/main/java/rs/valence/extractor/extractors/Attributes.java +++ b/extractor/src/main/java/rs/valence/extractor/extractors/Attributes.java @@ -1,14 +1,15 @@ package rs.valence.extractor.extractors; -import com.google.gson.JsonArray; -import com.google.gson.JsonElement; +import java.io.DataOutput; + +import com.google.gson.Gson; import com.google.gson.JsonObject; import net.minecraft.entity.attribute.ClampedEntityAttribute; import net.minecraft.entity.attribute.EntityAttribute; import net.minecraft.registry.Registries; +import net.minecraft.server.MinecraftServer; import rs.valence.extractor.Main; -import rs.valence.extractor.ValenceUtils; public class Attributes implements Main.Extractor { public Attributes() { @@ -20,7 +21,7 @@ public String fileName() { } @Override - public JsonElement extract() { + public void extract(MinecraftServer server, DataOutput output, Gson gson) throws Exception { var attributesJson = new JsonObject(); for (EntityAttribute attribute : Registries.ATTRIBUTE) { @@ -40,6 +41,6 @@ public JsonElement extract() { attributesJson.add(Registries.ATTRIBUTE.getId(attribute).getPath(), attributeJson); } - return attributesJson; + Main.writeJson(output, gson, attributesJson); } } \ No newline at end of file diff --git a/extractor/src/main/java/rs/valence/extractor/extractors/Blocks.java b/extractor/src/main/java/rs/valence/extractor/extractors/Blocks.java index e2dd2fdf3..4c7b08f23 100644 --- a/extractor/src/main/java/rs/valence/extractor/extractors/Blocks.java +++ b/extractor/src/main/java/rs/valence/extractor/extractors/Blocks.java @@ -1,9 +1,10 @@ package rs.valence.extractor.extractors; +import com.google.gson.Gson; import com.google.gson.JsonArray; -import com.google.gson.JsonElement; import com.google.gson.JsonObject; import net.minecraft.registry.Registries; +import net.minecraft.server.MinecraftServer; import net.minecraft.item.VerticallyAttachableBlockItem; import net.minecraft.util.math.BlockPos; import net.minecraft.world.EmptyBlockView; @@ -11,6 +12,8 @@ import rs.valence.extractor.Main; import rs.valence.extractor.mixin.ExposeWallBlock; +import java.io.DataOutput; +import java.io.IOException; import java.util.LinkedHashMap; import java.util.Locale; import java.util.Objects; @@ -25,7 +28,7 @@ public String fileName() { } @Override - public JsonElement extract() { + public void extract(MinecraftServer server, DataOutput output, Gson gson) throws IOException { var topLevelJson = new JsonObject(); var blocksJson = new JsonArray(); @@ -127,7 +130,7 @@ public JsonElement extract() { topLevelJson.add("shapes", shapesJson); topLevelJson.add("blocks", blocksJson); - return topLevelJson; + Main.writeJson(output, gson, topLevelJson); } private record Shape(double minX, double minY, double minZ, double maxX, double maxY, double maxZ) { diff --git a/extractor/src/main/java/rs/valence/extractor/extractors/Codec.java b/extractor/src/main/java/rs/valence/extractor/extractors/Codec.java index 521e2c21f..65c4888e9 100644 --- a/extractor/src/main/java/rs/valence/extractor/extractors/Codec.java +++ b/extractor/src/main/java/rs/valence/extractor/extractors/Codec.java @@ -1,8 +1,11 @@ package rs.valence.extractor.extractors; +import java.io.DataOutput; + +import com.google.gson.Gson; + import io.netty.handler.codec.EncoderException; -import net.minecraft.nbt.NbtCompound; -import net.minecraft.nbt.NbtElement; +import net.minecraft.nbt.NbtIo; import net.minecraft.nbt.NbtOps; import net.minecraft.registry.DynamicRegistryManager; import net.minecraft.registry.Registries; @@ -10,25 +13,23 @@ import net.minecraft.registry.SerializableRegistries; import net.minecraft.server.MinecraftServer; import net.minecraft.util.Util; +import rs.valence.extractor.Main.Extractor; -public class Codec { - - private static final RegistryOps REGISTRY_OPS= RegistryOps.of(NbtOps.INSTANCE, DynamicRegistryManager.of(Registries.REGISTRIES)); - private final DynamicRegistryManager.Immutable registryManager; - - public Codec(MinecraftServer server) { - this.registryManager = server.getRegistryManager(); - } +public class Codec implements Extractor { + @Override public String fileName() { return "registry_codec.dat"; } - public NbtCompound extract() { - com.mojang.serialization.Codec codec = SerializableRegistries.CODEC; - //DynamicRegistryManager.get(net.minecraft.registry.RegistryKey>) method. + @Override + public void extract(MinecraftServer server, DataOutput output, Gson gson) throws Exception { + var registryOps = RegistryOps.of(NbtOps.INSTANCE, DynamicRegistryManager.of(Registries.REGISTRIES)); + var registryManager = server.getRegistryManager(); + var codec = SerializableRegistries.CODEC; + + var nbtElement = Util.getResult(codec.encodeStart(registryOps, registryManager), (error) -> new EncoderException("Failed to encode: " + error + " " + registryManager)); - NbtElement nbtElement = Util.getResult(codec.encodeStart(REGISTRY_OPS, registryManager), (error) -> new EncoderException("Failed to encode: " + error + " " + registryManager)); - return (NbtCompound) nbtElement; + NbtIo.write(nbtElement, output); } } diff --git a/extractor/src/main/java/rs/valence/extractor/extractors/Effects.java b/extractor/src/main/java/rs/valence/extractor/extractors/Effects.java index c89de4245..0c62e0fa7 100644 --- a/extractor/src/main/java/rs/valence/extractor/extractors/Effects.java +++ b/extractor/src/main/java/rs/valence/extractor/extractors/Effects.java @@ -1,11 +1,16 @@ package rs.valence.extractor.extractors; +import java.io.DataOutput; +import java.io.IOException; + +import com.google.gson.Gson; import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; +import net.minecraft.entity.effect.StatusEffect; import net.minecraft.registry.Registries; +import net.minecraft.server.MinecraftServer; import rs.valence.extractor.Main; -import rs.valence.extractor.ValenceUtils; public class Effects implements Main.Extractor { public Effects() { @@ -17,7 +22,7 @@ public String fileName() { } @Override - public JsonElement extract() { + public void extract(MinecraftServer server, DataOutput output, Gson gson) throws IOException { var effectsJson = new JsonArray(); for (var effect : Registries.STATUS_EFFECT) { @@ -28,17 +33,18 @@ public JsonElement extract() { effectJson.addProperty("translation_key", effect.getTranslationKey()); effectJson.addProperty("color", effect.getColor()); effectJson.addProperty("instant", effect.isInstant()); - effectJson.addProperty("category", ValenceUtils.toPascalCase(effect.getCategory().name())); + effectJson.addProperty("category", Main.toPascalCase(effect.getCategory().name())); var attributeModifiersJson = new JsonArray(); for (var entry : effect.getAttributeModifiers().entrySet()) { var attributeModifierJson = new JsonObject(); + var attributeModidier = entry.getValue().createAttributeModifier(0); attributeModifierJson.addProperty("attribute", Registries.ATTRIBUTE.getRawId(entry.getKey())); - attributeModifierJson.addProperty("operation", entry.getValue().getOperation().getId()); - attributeModifierJson.addProperty("value", entry.getValue().getValue()); - attributeModifierJson.addProperty("uuid", entry.getValue().getId().toString()); + attributeModifierJson.addProperty("operation", attributeModidier.getOperation().getId()); + attributeModifierJson.addProperty("base_value", attributeModidier.getValue()); + attributeModifierJson.addProperty("uuid", entry.getValue().getUuid().toString()); attributeModifiersJson.add(attributeModifierJson); } @@ -50,6 +56,6 @@ public JsonElement extract() { effectsJson.add(effectJson); } - return effectsJson; + Main.writeJson(output, gson, effectsJson); } } diff --git a/extractor/src/main/java/rs/valence/extractor/extractors/Enchants.java b/extractor/src/main/java/rs/valence/extractor/extractors/Enchants.java index 8bf9bdb62..2235d855a 100644 --- a/extractor/src/main/java/rs/valence/extractor/extractors/Enchants.java +++ b/extractor/src/main/java/rs/valence/extractor/extractors/Enchants.java @@ -1,9 +1,13 @@ package rs.valence.extractor.extractors; +import java.io.DataOutput; +import java.io.IOException; + +import com.google.gson.Gson; import com.google.gson.JsonArray; -import com.google.gson.JsonElement; import com.google.gson.JsonObject; import net.minecraft.registry.Registries; +import net.minecraft.server.MinecraftServer; import rs.valence.extractor.Main; public class Enchants implements Main.Extractor { @@ -16,7 +20,7 @@ public String fileName() { } @Override - public JsonElement extract() { + public void extract(MinecraftServer server, DataOutput output, Gson gson) throws IOException { var enchantsJson = new JsonArray(); for (var enchant : Registries.ENCHANTMENT) { @@ -42,6 +46,6 @@ public JsonElement extract() { enchantsJson.add(enchantJson); } - return enchantsJson; + Main.writeJson(output, gson, enchantsJson); } } diff --git a/extractor/src/main/java/rs/valence/extractor/extractors/Entities.java b/extractor/src/main/java/rs/valence/extractor/extractors/Entities.java index 172d01f25..b57a1367c 100644 --- a/extractor/src/main/java/rs/valence/extractor/extractors/Entities.java +++ b/extractor/src/main/java/rs/valence/extractor/extractors/Entities.java @@ -2,6 +2,7 @@ import com.google.gson.*; +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import net.minecraft.block.BlockState; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityPose; @@ -12,6 +13,7 @@ import net.minecraft.entity.attribute.EntityAttributeInstance; import net.minecraft.entity.data.DataTracker; import net.minecraft.entity.data.TrackedData; +import net.minecraft.entity.data.TrackedDataHandler; import net.minecraft.entity.data.TrackedDataHandlerRegistry; import net.minecraft.entity.passive.CatVariant; import net.minecraft.entity.passive.FrogVariant; @@ -20,6 +22,7 @@ import net.minecraft.particle.ParticleEffect; import net.minecraft.registry.Registries; import net.minecraft.registry.entry.RegistryEntry; +import net.minecraft.server.MinecraftServer; import net.minecraft.text.Text; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.EulerAngle; @@ -28,12 +31,16 @@ import org.jetbrains.annotations.Nullable; import org.joml.Quaternionf; import org.joml.Vector3f; +import it.unimi.dsi.fastutil.ints.Int2ObjectMap; import rs.valence.extractor.ClassComparator; import rs.valence.extractor.DummyPlayerEntity; import rs.valence.extractor.DummyWorld; import rs.valence.extractor.Main; import rs.valence.extractor.Main.Pair; + +import java.io.DataOutput; +import java.io.IOException; import java.lang.reflect.ParameterizedType; import java.util.*; @@ -41,168 +48,44 @@ public class Entities implements Main.Extractor { public Entities() { } - private static Pair trackedDataToJson(TrackedData data, DataTracker tracker) { - final var handler = data.getType(); - final var val = tracker.get(data); - - if (handler == TrackedDataHandlerRegistry.BYTE) { - return new Pair<>("byte", new JsonPrimitive((Byte) val)); - } else if (handler == TrackedDataHandlerRegistry.INTEGER) { - return new Pair<>("integer", new JsonPrimitive((Integer) val)); - } else if (handler == TrackedDataHandlerRegistry.LONG) { - return new Pair<>("long", new JsonPrimitive((Long) val)); - } else if (handler == TrackedDataHandlerRegistry.FLOAT) { - return new Pair<>("float", new JsonPrimitive((Float) val)); - } else if (handler == TrackedDataHandlerRegistry.STRING) { - return new Pair<>("string", new JsonPrimitive((String) val)); - } else if (handler == TrackedDataHandlerRegistry.TEXT_COMPONENT) { - // TODO: return text as json element. - return new Pair<>("text_component", new JsonPrimitive(((Text) val).getString())); - } else if (handler == TrackedDataHandlerRegistry.OPTIONAL_TEXT_COMPONENT) { - var res = ((Optional) val).map(o -> (JsonElement) new JsonPrimitive(((Text) o).getString())) - .orElse(JsonNull.INSTANCE); - return new Pair<>("optional_text_component", res); - } else if (handler == TrackedDataHandlerRegistry.ITEM_STACK) { - // TODO - return new Pair<>("item_stack", new JsonPrimitive(((ItemStack) val).toString())); - } else if (handler == TrackedDataHandlerRegistry.BOOLEAN) { - return new Pair<>("boolean", new JsonPrimitive((Boolean) val)); - } else if (handler == TrackedDataHandlerRegistry.ROTATION) { - var json = new JsonObject(); - var ea = (EulerAngle) val; - json.addProperty("pitch", ea.getPitch()); - json.addProperty("yaw", ea.getYaw()); - json.addProperty("roll", ea.getRoll()); - return new Pair<>("rotation", json); - } else if (handler == TrackedDataHandlerRegistry.BLOCK_POS) { - var bp = (BlockPos) val; - var json = new JsonObject(); - json.addProperty("x", bp.getX()); - json.addProperty("y", bp.getY()); - json.addProperty("z", bp.getZ()); - return new Pair<>("block_pos", json); - } else if (handler == TrackedDataHandlerRegistry.OPTIONAL_BLOCK_POS) { - return new Pair<>("optional_block_pos", ((Optional) val).map(o -> { - var bp = (BlockPos) o; - var json = new JsonObject(); - json.addProperty("x", bp.getX()); - json.addProperty("y", bp.getY()); - json.addProperty("z", bp.getZ()); - return (JsonElement) json; - }).orElse(JsonNull.INSTANCE)); - } else if (handler == TrackedDataHandlerRegistry.FACING) { - return new Pair<>("facing", new JsonPrimitive(val.toString())); - } else if (handler == TrackedDataHandlerRegistry.OPTIONAL_UUID) { - var res = ((Optional) val).map(o -> (JsonElement) new JsonPrimitive(o.toString())) - .orElse(JsonNull.INSTANCE); - return new Pair<>("optional_uuid", res); - } else if (handler == TrackedDataHandlerRegistry.BLOCK_STATE) { - // TODO: get raw block state ID. - var state = (BlockState) val; - return new Pair<>("block_state", new JsonPrimitive(state.toString())); - } else if (handler == TrackedDataHandlerRegistry.OPTIONAL_BLOCK_STATE) { - // TODO: get raw block state ID. - var res = ((Optional) val).map(o -> (JsonElement) new JsonPrimitive(o.toString())) - .orElse(JsonNull.INSTANCE); - return new Pair<>("optional_block_state", res); - } else if (handler == TrackedDataHandlerRegistry.NBT_COMPOUND) { - // TODO: base64 binary representation or SNBT? - return new Pair<>("nbt_compound", new JsonPrimitive(val.toString())); - } else if (handler == TrackedDataHandlerRegistry.PARTICLE) { - var id = Registries.PARTICLE_TYPE.getId(((ParticleEffect) val).getType()); - return new Pair<>("particle", new JsonPrimitive(id.getPath())); - } else if (handler == TrackedDataHandlerRegistry.VILLAGER_DATA) { - var vd = (VillagerData) val; - var json = new JsonObject(); - var type = Registries.VILLAGER_TYPE.getId(vd.getType()).getPath(); - var profession = Registries.VILLAGER_PROFESSION.getId(vd.getProfession()).getPath(); - json.addProperty("type", type); - json.addProperty("profession", profession); - json.addProperty("level", vd.getLevel()); - return new Pair<>("villager_data", json); - } else if (handler == TrackedDataHandlerRegistry.OPTIONAL_INT) { - var opt = (OptionalInt) val; - return new Pair<>("optional_int", opt.isPresent() ? new JsonPrimitive(opt.getAsInt()) : JsonNull.INSTANCE); - } else if (handler == TrackedDataHandlerRegistry.ENTITY_POSE) { - return new Pair<>("entity_pose", new JsonPrimitive(((EntityPose) val).name().toLowerCase(Locale.ROOT))); - } else if (handler == TrackedDataHandlerRegistry.CAT_VARIANT) { - return new Pair<>("cat_variant", - new JsonPrimitive(Registries.CAT_VARIANT.getId((CatVariant) val).getPath())); - } else if (handler == TrackedDataHandlerRegistry.FROG_VARIANT) { - return new Pair<>("frog_variant", - new JsonPrimitive(Registries.FROG_VARIANT.getId((FrogVariant) val).getPath())); - } else if (handler == TrackedDataHandlerRegistry.OPTIONAL_GLOBAL_POS) { - return new Pair<>("optional_global_pos", ((Optional) val).map(o -> { - var gp = (GlobalPos) o; - var json = new JsonObject(); - json.addProperty("dimension", gp.getDimension().getValue().toString()); - - var posJson = new JsonObject(); - posJson.addProperty("x", gp.getPos().getX()); - posJson.addProperty("y", gp.getPos().getY()); - posJson.addProperty("z", gp.getPos().getZ()); - - json.add("position", posJson); - return (JsonElement) json; - }).orElse(JsonNull.INSTANCE)); - } else if (handler == TrackedDataHandlerRegistry.PAINTING_VARIANT) { - var variant = ((RegistryEntry) val).getKey().map(k -> k.getValue().getPath()).orElse(""); - return new Pair<>("painting_variant", new JsonPrimitive(variant)); - } else if (handler == TrackedDataHandlerRegistry.SNIFFER_STATE) { - return new Pair<>("sniffer_state", - new JsonPrimitive(((SnifferEntity.State) val).name().toLowerCase(Locale.ROOT))); - } else if (handler == TrackedDataHandlerRegistry.VECTOR3F) { - var vec = (Vector3f) val; - var json = new JsonObject(); - json.addProperty("x", vec.x); - json.addProperty("y", vec.y); - json.addProperty("z", vec.z); - return new Pair<>("vector3f", json); - } else if (handler == TrackedDataHandlerRegistry.QUATERNIONF) { - var quat = (Quaternionf) val; - var json = new JsonObject(); - json.addProperty("x", quat.x); - json.addProperty("y", quat.y); - json.addProperty("z", quat.z); - json.addProperty("w", quat.w); - return new Pair<>("quaternionf", json); - } else { - throw new IllegalArgumentException( - "Unexpected tracked handler of ID " + TrackedDataHandlerRegistry.getId(handler)); - } - } - @Override public String fileName() { return "entities.json"; } @Override - @SuppressWarnings("unchecked") - public JsonElement extract() throws IllegalAccessException, NoSuchFieldException { + public void extract(MinecraftServer server, DataOutput output, Gson gson) + throws IOException, IllegalAccessException, NoSuchFieldException { + var entitiesJson = new JsonObject(); - final var entityClassToType = new HashMap, EntityType>(); - for (var f : EntityType.class.getFields()) { - if (f.getType().equals(EntityType.class)) { - var entityClass = (Class) ((ParameterizedType) f.getGenericType()) - .getActualTypeArguments()[0]; - var entityType = (EntityType) f.get(null); + for (var entityClass : Entities.ENTITY_CLASS_TO_TYPE_MAP.keySet()) { + Entities.handleEntity(entityClass, entitiesJson); + } - entityClassToType.put(entityClass, entityType); - } + Main.writeJson(output, gson, entitiesJson); + } + + @SuppressWarnings("unchecked") + private static void handleEntity( + Class entityClass, + JsonObject entitiesJson) throws IllegalAccessException, NoSuchFieldException { + if (entitiesJson.get(entityClass.getSimpleName()) != null) { + // Skip if we already handled this entity. } - final var dataTrackerField = Entity.class.getDeclaredField("dataTracker"); - dataTrackerField.setAccessible(true); + var entityJson = new JsonObject(); - var entitiesMap = new TreeMap, JsonElement>(new ClassComparator()); + var parentClass = entityClass.getSuperclass(); + if (parentClass != null && Entity.class.isAssignableFrom(parentClass)) { + // If the entity has a parent class, handle that too. + handleEntity((Class) parentClass, entitiesJson); - for (var entry : entityClassToType.entrySet()) { - var entityClass = entry.getKey(); - @Nullable - var entityType = entry.getValue(); - assert entityType != null; + entityJson.addProperty("parent", parentClass.getSimpleName()); + } + var entityType = Entities.ENTITY_CLASS_TO_TYPE_MAP.get(entityClass); + // Is this a concrete entity class? + if (entityType != null) { // While we can use the tracked data registry and reflection to get the tracked // fields on entities, we won't know what their default values are because they // are assigned in the entity's constructor. @@ -210,100 +93,334 @@ public JsonElement extract() throws IllegalAccessException, NoSuchFieldException // the data tracker field from the base entity class. // We also handle player entities specially since they cannot be spawned with // EntityType#create. - final var entityInstance = entityType.equals(EntityType.PLAYER) ? DummyPlayerEntity.INSTANCE + var entityInstance = entityType.equals(EntityType.PLAYER) + ? DummyPlayerEntity.INSTANCE : entityType.create(DummyWorld.INSTANCE); - final var dataTracker = (DataTracker) dataTrackerField.get(entityInstance); + var dataTracker = entityInstance.getDataTracker(); - while (entitiesMap.get(entityClass) == null) { - var entityJson = new JsonObject(); + var dataTrackerEntriesField = DataTracker.class.getDeclaredField("entries"); + dataTrackerEntriesField.setAccessible(true); - var parent = entityClass.getSuperclass(); - var hasParent = parent != null && Entity.class.isAssignableFrom(parent); + var dataTrackerEntries = (Int2ObjectMap>) dataTrackerEntriesField.get(dataTracker); - if (hasParent) { - entityJson.addProperty("parent", parent.getSimpleName()); - } - - if (entityType != null) { - entityJson.addProperty("type", Registries.ENTITY_TYPE.getId(entityType).getPath()); + var defaultsMap = new TreeMap(); + var defaults = (Int2ObjectMap>) dataTrackerEntriesField.get(dataTracker); - entityJson.add("translation_key", new JsonPrimitive(entityType.getTranslationKey())); - } + for (var entry : defaults.int2ObjectEntrySet()) { + var fieldJson = new JsonObject(); + var trackedData = entry.getValue().getData(); + var data = Entities.trackedDataToJson(trackedData, dataTracker); + int id = trackedData.getId(); + fieldJson.addProperty("index", id); + fieldJson.add("value", data.right()); + fieldJson.addProperty("type", data.left()); + defaultsMap.put(id, fieldJson); + } + entityJson.add("defaults", Main.treeMapToJsonArray(defaultsMap)); - var fieldsJson = new JsonArray(); - for (var entityField : entityClass.getDeclaredFields()) { - if (entityField.getType().equals(TrackedData.class)) { - entityField.setAccessible(true); + if (entityInstance instanceof LivingEntity livingEntity) { + var type = (EntityType) entityType; + var defaultAttributes = DefaultAttributeRegistry.get(type); + var attributesJson = new JsonArray(); + if (defaultAttributes != null) { + var instancesField = defaultAttributes.getClass().getDeclaredField("instances"); + instancesField.setAccessible(true); + var instances = (Map) instancesField + .get(defaultAttributes); - var trackedData = (TrackedData) entityField.get(null); + for (var instance : instances.values()) { + var attribute = instance.getAttribute(); - var fieldJson = new JsonObject(); - var fieldName = entityField.getName().toLowerCase(Locale.ROOT); - fieldJson.addProperty("name", fieldName); - fieldJson.addProperty("index", trackedData.getId()); + var attributeJson = new JsonObject(); - var data = Entities.trackedDataToJson(trackedData, dataTracker); - fieldJson.addProperty("type", data.left()); - fieldJson.add("default_value", data.right()); + attributeJson.addProperty("id", Registries.ATTRIBUTE.getRawId(attribute)); + attributeJson.addProperty("name", Registries.ATTRIBUTE.getId(attribute).getPath()); + attributeJson.addProperty("base_value", instance.getBaseValue()); - fieldsJson.add(fieldJson); + attributesJson.add(attributeJson); } } - entityJson.add("fields", fieldsJson); + entityJson.add("attributes", attributesJson); + } - if (entityInstance instanceof LivingEntity livingEntity) { - var type = (EntityType) entityType; - var defaultAttributes = DefaultAttributeRegistry.get(type); - var attributesJson = new JsonArray(); - if (defaultAttributes != null) { - var instancesField = defaultAttributes.getClass().getDeclaredField("instances"); - instancesField.setAccessible(true); - var instances = (Map) instancesField - .get(defaultAttributes); + var bb = entityInstance.getBoundingBox(); + if (bb != null) { + var boundingBoxJson = new JsonObject(); - for (var instance : instances.values()) { - var attribute = instance.getAttribute(); + boundingBoxJson.addProperty("size_x", bb.getLengthX()); + boundingBoxJson.addProperty("size_y", bb.getLengthY()); + boundingBoxJson.addProperty("size_z", bb.getLengthZ()); - var attributeJson = new JsonObject(); + entityJson.add("default_bounding_box", boundingBoxJson); + } + } - attributeJson.addProperty("id", Registries.ATTRIBUTE.getRawId(attribute)); - attributeJson.addProperty("name", Registries.ATTRIBUTE.getId(attribute).getPath()); - attributeJson.addProperty("base_value", instance.getBaseValue()); + var fieldsJson = new JsonArray(); + for (var entityField : entityClass.getDeclaredFields()) { + if (entityField.getType().equals(TrackedData.class)) { + entityField.setAccessible(true); - attributesJson.add(attributeJson); - } - } - entityJson.add("attributes", attributesJson); - } + var trackedData = (TrackedData) entityField.get(null); - var bb = entityInstance.getBoundingBox(); - if (bb != null && entityType != null) { - var boundingBoxJson = new JsonObject(); + var fieldJson = new JsonObject(); + var fieldName = entityField.getName().toLowerCase(Locale.ROOT); + fieldJson.addProperty("name", fieldName); + fieldJson.addProperty("index", trackedData.getId()); - boundingBoxJson.addProperty("size_x", bb.getXLength()); - boundingBoxJson.addProperty("size_y", bb.getYLength()); - boundingBoxJson.addProperty("size_z", bb.getZLength()); + // var data = Entities.trackedDataToJson(trackedData, dataTracker); + fieldJson.addProperty("type", Entities.trackedDataHandlerName(trackedData.getType())); + // fieldJson.add("default_value", data.right()); - entityJson.add("default_bounding_box", boundingBoxJson); - } + fieldsJson.add(fieldJson); + } + } + entityJson.add("fields", fieldsJson); + + entitiesJson.add(entityClass.getSimpleName(), entityJson); + } + + private static final TreeMap, EntityType> ENTITY_CLASS_TO_TYPE_MAP = new TreeMap<>( + new ClassComparator()); + static { + for (var f : EntityType.class.getFields()) { + if (f.getType().equals(EntityType.class)) { + @SuppressWarnings("unchecked") + var entityClass = (Class) ((ParameterizedType) f.getGenericType()) + .getActualTypeArguments()[0]; - entitiesMap.put(entityClass, entityJson); + EntityType entityType; - if (!hasParent) { - break; + try { + entityType = (EntityType) f.get(null); + } catch (IllegalAccessException e) { + throw new ExceptionInInitializerError(e); } - entityClass = (Class) parent; - entityType = entityClassToType.get(entityClass); + ENTITY_CLASS_TO_TYPE_MAP.put(entityClass, entityType); } } + } - var entitiesJson = new JsonObject(); - for (var entry : entitiesMap.entrySet()) { - entitiesJson.add(entry.getKey().getSimpleName(), entry.getValue()); + private static String trackedDataHandlerName(TrackedDataHandler handler) { + if (handler == TrackedDataHandlerRegistry.BYTE) { + return "byte"; + } else if (handler == TrackedDataHandlerRegistry.INTEGER) { + return "integer"; + } else if (handler == TrackedDataHandlerRegistry.LONG) { + return "long"; + } else if (handler == TrackedDataHandlerRegistry.FLOAT) { + return "float"; + } else if (handler == TrackedDataHandlerRegistry.STRING) { + return "string"; + } else if (handler == TrackedDataHandlerRegistry.TEXT_COMPONENT) { + return "text_component"; + } else if (handler == TrackedDataHandlerRegistry.OPTIONAL_TEXT_COMPONENT) { + return "optional_text_component"; + } else if (handler == TrackedDataHandlerRegistry.ITEM_STACK) { + return "item_stack"; + } else if (handler == TrackedDataHandlerRegistry.BOOLEAN) { + return "boolean"; + } else if (handler == TrackedDataHandlerRegistry.ROTATION) { + return "rotation"; + } else if (handler == TrackedDataHandlerRegistry.BLOCK_POS) { + return "block_pos"; + } else if (handler == TrackedDataHandlerRegistry.OPTIONAL_BLOCK_POS) { + return "optional_block_pos"; + } else if (handler == TrackedDataHandlerRegistry.FACING) { + return "facing"; + } else if (handler == TrackedDataHandlerRegistry.OPTIONAL_UUID) { + return "optional_uuid"; + } else if (handler == TrackedDataHandlerRegistry.BLOCK_STATE) { + return "block_state"; + } else if (handler == TrackedDataHandlerRegistry.OPTIONAL_BLOCK_STATE) { + return "optional_block_state"; + } else if (handler == TrackedDataHandlerRegistry.NBT_COMPOUND) { + return "nbt_compound"; + } else if (handler == TrackedDataHandlerRegistry.PARTICLE) { + return "particle"; + } else if (handler == TrackedDataHandlerRegistry.VILLAGER_DATA) { + return "villager_data"; + } else if (handler == TrackedDataHandlerRegistry.OPTIONAL_INT) { + return "optional_int"; + } else if (handler == TrackedDataHandlerRegistry.ENTITY_POSE) { + return "entity_pose"; + } else if (handler == TrackedDataHandlerRegistry.CAT_VARIANT) { + return "cat_variant"; + } else if (handler == TrackedDataHandlerRegistry.FROG_VARIANT) { + return "frog_variant"; + } else if (handler == TrackedDataHandlerRegistry.OPTIONAL_GLOBAL_POS) { + return "optional_global_pos"; + } else if (handler == TrackedDataHandlerRegistry.PAINTING_VARIANT) { + return "painting_variant"; + } else if (handler == TrackedDataHandlerRegistry.SNIFFER_STATE) { + return "sniffer_state"; + } else if (handler == TrackedDataHandlerRegistry.VECTOR3F) { + return "vector3f"; + } else if (handler == TrackedDataHandlerRegistry.QUATERNIONF) { + return "quaternionf"; + } else { + throw new IllegalArgumentException( + "Unknown tracked data handler of ID " + TrackedDataHandlerRegistry.getId(handler)); + } + } + + private static Pair trackedDataToJson(TrackedData data, DataTracker tracker) { + final var val = tracker.get(data); + + String name = trackedDataHandlerName(data.getType()); + JsonElement value = null; + + switch (name) { + case "byte": + value = new JsonPrimitive((Byte) val); + break; + case "integer": + value = new JsonPrimitive((Integer) val); + break; + case "long": + value = new JsonPrimitive((Long) val); + break; + case "float": + value = new JsonPrimitive((Float) val); + break; + case "string": + value = new JsonPrimitive((String) val); + break; + case "text_component": + // TODO: return text as json element? + value = new JsonPrimitive(((Text) val).getString()); + break; + case "optional_text_component": + value = ((Optional) val).map(o -> (JsonElement) new JsonPrimitive(((Text) o).getString())) + .orElse(JsonNull.INSTANCE); + break; + case "item_stack": + // TODO + value = new JsonPrimitive(((ItemStack) val).toString()); + break; + case "boolean": + value = new JsonPrimitive((Boolean) val); + break; + case "rotation": { + var json = new JsonObject(); + var ea = (EulerAngle) val; + json.addProperty("pitch", ea.getPitch()); + json.addProperty("yaw", ea.getYaw()); + json.addProperty("roll", ea.getRoll()); + value = json; + break; + } + case "block_pos": { + var bp = (BlockPos) val; + var json = new JsonObject(); + json.addProperty("x", bp.getX()); + json.addProperty("y", bp.getY()); + json.addProperty("z", bp.getZ()); + value = json; + break; + } + case "optional_block_pos": + value = ((Optional) val).map(o -> { + var bp = (BlockPos) o; + var json = new JsonObject(); + json.addProperty("x", bp.getX()); + json.addProperty("y", bp.getY()); + json.addProperty("z", bp.getZ()); + return (JsonElement) json; + }).orElse(JsonNull.INSTANCE); + break; + case "facing": + value = new JsonPrimitive(val.toString()); + break; + case "optional_uuid": + value = ((Optional) val).map(o -> (JsonElement) new JsonPrimitive(o.toString())) + .orElse(JsonNull.INSTANCE); + break; + case "block_state": + value = new JsonPrimitive(((BlockState) val).toString()); + break; + case "optional_block_state": + value = ((Optional) val).map(o -> (JsonElement) new JsonPrimitive(o.toString())) + .orElse(JsonNull.INSTANCE); + break; + case "nbt_compound": + // TODO: base64 binary representation or SNBT? + value = new JsonPrimitive(val.toString()); + break; + case "particle": + value = new JsonPrimitive(Registries.PARTICLE_TYPE.getId(((ParticleEffect) val).getType()).getPath()); + break; + case "villager_data": { + var vd = (VillagerData) val; + var json = new JsonObject(); + var type = Registries.VILLAGER_TYPE.getId(vd.getType()).getPath(); + var profession = Registries.VILLAGER_PROFESSION.getId(vd.getProfession()).getPath(); + json.addProperty("type", type); + json.addProperty("profession", profession); + json.addProperty("level", vd.getLevel()); + value = json; + break; + } + case "optional_int": { + var opt = (OptionalInt) val; + value = opt.isPresent() ? new JsonPrimitive(opt.getAsInt()) : JsonNull.INSTANCE; + break; + } + case "entity_pose": + value = new JsonPrimitive(((EntityPose) val).name().toLowerCase(Locale.ROOT)); + break; + case "cat_variant": + value = new JsonPrimitive(Registries.CAT_VARIANT.getId((CatVariant) val).getPath()); + break; + case "frog_variant": + value = new JsonPrimitive(Registries.FROG_VARIANT.getId((FrogVariant) val).getPath()); + break; + case "optional_global_pos": + value = ((Optional) val).map(o -> { + var gp = (GlobalPos) o; + var json = new JsonObject(); + json.addProperty("dimension", gp.getDimension().getValue().toString()); + + var posJson = new JsonObject(); + posJson.addProperty("x", gp.getPos().getX()); + posJson.addProperty("y", gp.getPos().getY()); + posJson.addProperty("z", gp.getPos().getZ()); + + json.add("position", posJson); + return (JsonElement) json; + }).orElse(JsonNull.INSTANCE); + break; + case "painting_variant": + value = new JsonPrimitive( + ((RegistryEntry) val).getKey().map(k -> k.getValue().getPath()).orElse("")); + break; + case "sniffer_state": + value = new JsonPrimitive(((SnifferEntity.State) val).name().toLowerCase(Locale.ROOT)); + break; + case "vector3f": { + var vec = (Vector3f) val; + var json = new JsonObject(); + json.addProperty("x", vec.x); + json.addProperty("y", vec.y); + json.addProperty("z", vec.z); + value = json; + break; + } + case "quaternionf": { + var quat = (Quaternionf) val; + var json = new JsonObject(); + json.addProperty("x", quat.x); + json.addProperty("y", quat.y); + json.addProperty("z", quat.z); + json.addProperty("w", quat.w); + value = json; + break; + } + default: + throw new IllegalArgumentException("Unhandled tracked data handler of type \"" + name + "\""); } - return entitiesJson; + return new Pair<>(name, value); } } diff --git a/extractor/src/main/java/rs/valence/extractor/extractors/Items.java b/extractor/src/main/java/rs/valence/extractor/extractors/Items.java index ed745badb..8e2d91281 100644 --- a/extractor/src/main/java/rs/valence/extractor/extractors/Items.java +++ b/extractor/src/main/java/rs/valence/extractor/extractors/Items.java @@ -1,9 +1,12 @@ package rs.valence.extractor.extractors; +import java.io.DataOutput; + +import com.google.gson.Gson; import com.google.gson.JsonArray; -import com.google.gson.JsonElement; import com.google.gson.JsonObject; import net.minecraft.registry.Registries; +import net.minecraft.server.MinecraftServer; import rs.valence.extractor.Main; public class Items implements Main.Extractor { @@ -16,7 +19,7 @@ public String fileName() { } @Override - public JsonElement extract() throws Exception { + public void extract(MinecraftServer server, DataOutput output, Gson gson) throws Exception { var itemsJson = new JsonArray(); for (var item : Registries.ITEM) { @@ -61,6 +64,6 @@ public JsonElement extract() throws Exception { itemsJson.add(itemJson); } - return itemsJson; + Main.writeJson(output, gson, itemsJson); } } diff --git a/extractor/src/main/java/rs/valence/extractor/extractors/Misc.java b/extractor/src/main/java/rs/valence/extractor/extractors/Misc.java index f0dc34229..4e567cd1a 100644 --- a/extractor/src/main/java/rs/valence/extractor/extractors/Misc.java +++ b/extractor/src/main/java/rs/valence/extractor/extractors/Misc.java @@ -1,18 +1,19 @@ package rs.valence.extractor.extractors; -import com.google.gson.JsonElement; +import com.google.gson.Gson; import com.google.gson.JsonObject; import net.minecraft.entity.EntityPose; import net.minecraft.entity.EntityStatuses; -import net.minecraft.entity.attribute.ClampedEntityAttribute; -import net.minecraft.entity.attribute.EntityAttribute; import net.minecraft.entity.data.TrackedDataHandler; import net.minecraft.entity.data.TrackedDataHandlerRegistry; import net.minecraft.entity.passive.SnifferEntity; import net.minecraft.network.packet.s2c.play.EntityAnimationS2CPacket; import net.minecraft.registry.Registries; +import net.minecraft.server.MinecraftServer; import net.minecraft.util.math.Direction; import rs.valence.extractor.Main; + +import java.io.DataOutput; import java.lang.reflect.Modifier; import java.util.Locale; @@ -23,7 +24,7 @@ public String fileName() { } @Override - public JsonElement extract() throws Exception { + public void extract(MinecraftServer server, DataOutput output, Gson gson) throws Exception { var miscJson = new JsonObject(); var entityTypeJson = new JsonObject(); @@ -130,6 +131,6 @@ public JsonElement extract() throws Exception { } miscJson.add("tracked_data_handler", trackedDataHandlerJson); - return miscJson; + Main.writeJson(output, gson, miscJson); } } diff --git a/extractor/src/main/java/rs/valence/extractor/extractors/Packets.java b/extractor/src/main/java/rs/valence/extractor/extractors/Packets.java index 9f1ae64b9..18263c0b5 100644 --- a/extractor/src/main/java/rs/valence/extractor/extractors/Packets.java +++ b/extractor/src/main/java/rs/valence/extractor/extractors/Packets.java @@ -1,12 +1,15 @@ package rs.valence.extractor.extractors; +import com.google.gson.Gson; import com.google.gson.JsonArray; -import com.google.gson.JsonElement; import com.google.gson.JsonObject; import net.minecraft.network.NetworkSide; import net.minecraft.network.NetworkState; +import net.minecraft.server.MinecraftServer; import rs.valence.extractor.Main; +import java.io.DataOutput; +import java.io.IOException; import java.util.Locale; import java.util.TreeSet; @@ -17,19 +20,19 @@ public String fileName() { } @Override - public JsonElement extract() { + public void extract(MinecraftServer server, DataOutput output, Gson gson) throws IOException { var packetsJson = new JsonArray(); - for (var side : NetworkSide.values()) { - for (var state : NetworkState.values()) { + for (var state : NetworkState.values()) { + for (var side : NetworkSide.values()) { var map = state.getPacketIdToPacketMap(side); for (var id : new TreeSet<>(map.keySet())) { var packetJson = new JsonObject(); packetJson.addProperty("name", map.get(id.intValue()).getSimpleName()); - packetJson.addProperty("side", side.name().toLowerCase(Locale.ROOT)); packetJson.addProperty("state", state.name().toLowerCase(Locale.ROOT)); + packetJson.addProperty("side", side.name().toLowerCase(Locale.ROOT)); packetJson.addProperty("id", id); packetsJson.add(packetJson); @@ -37,6 +40,6 @@ public JsonElement extract() { } } - return packetsJson; + Main.writeJson(output, gson, packetsJson); } } diff --git a/extractor/src/main/java/rs/valence/extractor/extractors/Sounds.java b/extractor/src/main/java/rs/valence/extractor/extractors/Sounds.java index a204be726..34582e8fd 100644 --- a/extractor/src/main/java/rs/valence/extractor/extractors/Sounds.java +++ b/extractor/src/main/java/rs/valence/extractor/extractors/Sounds.java @@ -1,9 +1,13 @@ package rs.valence.extractor.extractors; +import java.io.DataOutput; +import java.io.IOException; + +import com.google.gson.Gson; import com.google.gson.JsonArray; -import com.google.gson.JsonElement; import com.google.gson.JsonObject; import net.minecraft.registry.Registries; +import net.minecraft.server.MinecraftServer; import rs.valence.extractor.Main; public class Sounds implements Main.Extractor { @@ -16,16 +20,16 @@ public String fileName() { } @Override - public JsonElement extract() throws Exception { - var itemsJson = new JsonArray(); + public void extract(MinecraftServer server, DataOutput output, Gson gson) throws IOException { + var soundsJson = new JsonArray(); for (var sound : Registries.SOUND_EVENT) { - var itemJson = new JsonObject(); - itemJson.addProperty("id", Registries.SOUND_EVENT.getRawId(sound)); - itemJson.addProperty("name", Registries.SOUND_EVENT.getId(sound).getPath()); - itemsJson.add(itemJson); + var soundJson = new JsonObject(); + soundJson.addProperty("id", Registries.SOUND_EVENT.getRawId(sound)); + soundJson.addProperty("name", Registries.SOUND_EVENT.getId(sound).getPath()); + soundsJson.add(soundJson); } - return itemsJson; + Main.writeJson(output, gson, soundsJson); } } diff --git a/extractor/src/main/java/rs/valence/extractor/extractors/Tags.java b/extractor/src/main/java/rs/valence/extractor/extractors/Tags.java index 2ef189144..f82116aa3 100644 --- a/extractor/src/main/java/rs/valence/extractor/extractors/Tags.java +++ b/extractor/src/main/java/rs/valence/extractor/extractors/Tags.java @@ -1,13 +1,11 @@ package rs.valence.extractor.extractors; +import com.google.gson.Gson; import com.google.gson.JsonArray; -import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.mojang.datafixers.util.Pair; -import net.minecraft.registry.CombinedDynamicRegistries; import net.minecraft.registry.Registry; import net.minecraft.registry.SerializableRegistries; -import net.minecraft.registry.ServerDynamicRegistryType; import net.minecraft.registry.entry.RegistryEntry; import net.minecraft.registry.entry.RegistryEntryList; import net.minecraft.server.MinecraftServer; @@ -15,15 +13,13 @@ import rs.valence.extractor.Main; import rs.valence.extractor.RegistryKeyComparator; +import java.io.DataOutput; import java.util.Map; import java.util.TreeMap; import java.util.stream.Collectors; public class Tags implements Main.Extractor { - private final CombinedDynamicRegistries dynamicRegistryManager; - - public Tags(MinecraftServer server) { - this.dynamicRegistryManager = server.getCombinedDynamicRegistries(); + public Tags() { } @Override @@ -32,15 +28,16 @@ public String fileName() { } @Override - public JsonElement extract() { + public void extract(MinecraftServer server, DataOutput output, Gson gson) throws Exception { + var dynamicRegistryManager = server.getCombinedDynamicRegistries(); + var tagsJson = new JsonObject(); - final var registryTags = - SerializableRegistries.streamRegistryManagerEntries(this.dynamicRegistryManager) - .map(registry -> Pair.of(registry.key(), serializeTags(registry.value()))) - .filter(pair -> !(pair.getSecond()).isEmpty()) - .collect(Collectors.toMap(Pair::getFirst, Pair::getSecond, (l, r) -> r, - () -> new TreeMap<>(new RegistryKeyComparator()))); + final var registryTags = SerializableRegistries.streamRegistryManagerEntries(dynamicRegistryManager) + .map(registry -> Pair.of(registry.key(), serializeTags(registry.value()))) + .filter(pair -> !(pair.getSecond()).isEmpty()) + .collect(Collectors.toMap(Pair::getFirst, Pair::getSecond, (l, r) -> r, + () -> new TreeMap<>(new RegistryKeyComparator()))); for (var registry : registryTags.entrySet()) { var registryIdent = registry.getKey().getValue().toString(); @@ -55,7 +52,7 @@ public JsonElement extract() { tagsJson.add(registryIdent, tagGroupTagsJson); } - return tagsJson; + Main.writeJson(output, gson, tagsJson); } private static Map serializeTags(Registry registry) { diff --git a/extractor/src/main/java/rs/valence/extractor/extractors/TranslationKeys.java b/extractor/src/main/java/rs/valence/extractor/extractors/TranslationKeys.java index a44ee34f0..93c54b5f2 100644 --- a/extractor/src/main/java/rs/valence/extractor/extractors/TranslationKeys.java +++ b/extractor/src/main/java/rs/valence/extractor/extractors/TranslationKeys.java @@ -1,11 +1,16 @@ package rs.valence.extractor.extractors; +import com.google.gson.Gson; import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; + +import net.minecraft.server.MinecraftServer; import net.minecraft.util.Language; import rs.valence.extractor.Main; +import java.io.DataOutput; +import java.io.IOException; import java.lang.reflect.Field; import java.util.Map; @@ -17,7 +22,7 @@ public String fileName() { } @Override - public JsonElement extract() { + public void extract(MinecraftServer server, DataOutput output, Gson gson) throws IOException { JsonArray translationsJson = new JsonArray(); Map translations = extractTranslations(); @@ -32,7 +37,7 @@ public JsonElement extract() { translationsJson.add(translationJson); } - return translationsJson; + Main.writeJson(output, gson, translationsJson); } @SuppressWarnings("unchecked") diff --git a/extractor/src/main/resources/fabric.mod.json b/extractor/src/main/resources/fabric.mod.json index 89a8967cb..87abfe5d5 100644 --- a/extractor/src/main/resources/fabric.mod.json +++ b/extractor/src/main/resources/fabric.mod.json @@ -22,7 +22,7 @@ ], "depends": { "fabricloader": ">=0.14.6", - "minecraft": "~1.20.1", + "minecraft": "~1.20.4", "java": ">=17" }, "suggests": { diff --git a/.github/FUNDING.yml b/old/.github/FUNDING.yml similarity index 100% rename from .github/FUNDING.yml rename to old/.github/FUNDING.yml diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/old/.github/ISSUE_TEMPLATE/bug_report.md similarity index 100% rename from .github/ISSUE_TEMPLATE/bug_report.md rename to old/.github/ISSUE_TEMPLATE/bug_report.md diff --git a/.github/ISSUE_TEMPLATE/config.yml b/old/.github/ISSUE_TEMPLATE/config.yml similarity index 100% rename from .github/ISSUE_TEMPLATE/config.yml rename to old/.github/ISSUE_TEMPLATE/config.yml diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/old/.github/ISSUE_TEMPLATE/feature_request.md similarity index 100% rename from .github/ISSUE_TEMPLATE/feature_request.md rename to old/.github/ISSUE_TEMPLATE/feature_request.md diff --git a/.github/dependabot.yml b/old/.github/dependabot.yml similarity index 100% rename from .github/dependabot.yml rename to old/.github/dependabot.yml diff --git a/.github/pull_request_template.md b/old/.github/pull_request_template.md similarity index 100% rename from .github/pull_request_template.md rename to old/.github/pull_request_template.md diff --git a/.github/workflows/ci-pr-comments.yml b/old/.github/workflows/ci-pr-comments.yml similarity index 100% rename from .github/workflows/ci-pr-comments.yml rename to old/.github/workflows/ci-pr-comments.yml diff --git a/.github/workflows/ci.yml b/old/.github/workflows/ci.yml similarity index 100% rename from .github/workflows/ci.yml rename to old/.github/workflows/ci.yml diff --git a/.github/workflows/website.yml b/old/.github/workflows/website.yml similarity index 100% rename from .github/workflows/website.yml rename to old/.github/workflows/website.yml diff --git a/old/.gitignore b/old/.gitignore new file mode 100644 index 000000000..a7f663825 --- /dev/null +++ b/old/.gitignore @@ -0,0 +1,18 @@ +/target +Cargo.lock +.vscode +.idea +*.iml +.gradle +/extractor/build +/extractor/out +/extractor/classes +/extractor/run +/extractor/bin +rust-mc-bot +.asset_cache/ +/velocity +flamegraph*.svg +perf.data +perf.data.old +/graph.svg diff --git a/CONTRIBUTING.md b/old/CONTRIBUTING.md similarity index 100% rename from CONTRIBUTING.md rename to old/CONTRIBUTING.md diff --git a/old/Cargo.toml b/old/Cargo.toml new file mode 100644 index 000000000..2ecd58a94 --- /dev/null +++ b/old/Cargo.toml @@ -0,0 +1,209 @@ +[package] +name = "valence" +version.workspace = true +edition.workspace = true +description = "A framework for building Minecraft servers in Rust." +documentation.workspace = true +repository.workspace = true +readme = "README.md" +license.workspace = true +keywords = ["minecraft", "gamedev", "server", "ecs"] +categories = ["game-engines"] +include = ["/src", "/benches", "/examples", "/README.md", "/LICENSE.txt"] + +[features] +default = [ + "advancement", + "anvil", + "boss_bar", + "inventory", + "log", + "network", + "player_list", + "scoreboard", + "world_border", + "command", + "weather", + "testing", +] +advancement = ["dep:valence_advancement"] +anvil = ["dep:valence_anvil"] +boss_bar = ["dep:valence_boss_bar"] +inventory = ["dep:valence_inventory"] +log = ["dep:bevy_log"] +network = ["dep:valence_network"] +player_list = ["dep:valence_player_list"] +scoreboard = ["dep:valence_scoreboard"] +world_border = ["dep:valence_world_border"] +command = ["dep:valence_command", "dep:valence_command_macros"] +weather = ["dep:valence_weather"] +testing = [] + +[dependencies] +anyhow.workspace = true +bevy_app.workspace = true +bevy_ecs.workspace = true +bevy_log = { workspace = true, optional = true } +bytes.workspace = true +rand.workspace = true +uuid.workspace = true +valence_advancement = { workspace = true, optional = true } +valence_anvil = { workspace = true, optional = true, features = [ + "bevy_plugin", +] } +valence_boss_bar = { workspace = true, optional = true } +valence_command = { workspace = true, optional = true } +valence_command_macros = { workspace = true, optional = true } +valence_ident_macros.workspace = true +valence_ident.workspace = true +valence_inventory = { workspace = true, optional = true } +valence_lang.workspace = true +valence_network = { workspace = true, optional = true } +valence_player_list = { workspace = true, optional = true } +valence_registry.workspace = true +valence_scoreboard = { workspace = true, optional = true } +valence_server.workspace = true +valence_text.workspace = true +valence_weather = { workspace = true, optional = true } +valence_world_border = { workspace = true, optional = true } + +[dev-dependencies] +anyhow.workspace = true +clap.workspace = true +criterion.workspace = true +flume.workspace = true +noise.workspace = true # For the terrain example. +tracing.workspace = true + +[dev-dependencies.reqwest] +workspace = true +default-features = false +features = ["rustls-tls", "blocking", "stream"] + +[[bench]] +name = "main" +harness = false + +[profile.dev.package."*"] +opt-level = 3 + +[profile.dev] +opt-level = 1 + +[workspace] +members = ["crates/*", "tools/*"] +exclude = [] +resolver = "2" + +[workspace.package] +version = "0.2.0-alpha.1+mc.1.20.1" +edition = "2021" +repository = "https://github.com/valence-rs/valence" +documentation = "https://docs.rs/valence/" +license = "MIT" + +[workspace.dependencies] +aes = "0.8.2" +anyhow = { version = "1.0.70", features = ["backtrace"] } +approx = "0.5.1" +arrayvec = "0.7.2" +async-trait = "0.1.60" +atty = "0.2.14" +base64 = "0.21.0" +bevy_app = { version = "0.12", default-features = false } +bevy_derive = "0.12" +bevy_ecs = { version = "0.12", default-features = false, features = [ + "multi-threaded", +] } +bevy_hierarchy = { version = "0.12", default-features = false } +bevy_log = { version = "0.12" } +bevy_mod_debugdump = { version = "0.9.0", default-features = false } +bevy_utils = { version = "0.12" } +bitfield-struct = "0.5.3" +bitvec = "1.0.1" +byteorder = "1.4.3" +bytes = "1.2.1" +cesu8 = "1.1.0" +cfb8 = "0.8.1" +clap = { version = "4.0.30", features = ["derive"] } +criterion = "0.5.1" +derive_more = "1.0.0-beta.3" +directories = "5.0.0" +eframe = { version = "0.22.0", default-features = false } +egui = "0.22.0" +egui_dock = "0.6" +flate2 = "1.0.24" +flume = "0.11.0" +fs_extra = "1.2.0" +glam = "0.25.0" +heck = "0.5.0-rc.1" +hmac = "0.12.1" +image = "0.24.6" +indexmap = "2.2.1" +itertools = "0.12.0" +java_string = { path = "crates/java_string", version = "0.1.2" } +lru = "0.12.0" +noise = "0.8.2" +num = "0.4.0" +num-bigint = "0.4.3" +owo-colors = "3.5.0" +ordered-float = "4.1.1" +parking_lot = "0.12.1" +paste = "1.0.11" +petgraph = "0.6.3" +pretty_assertions = "1.3.0" +proc-macro2 = "1.0.56" +quote = "1.0.26" +rand = "0.8.5" +rayon = "1.7.0" +regex = "1.6.0" +reqwest = { version = "0.11.12", default-features = false } +rfd = "0.11.3" +rsa = "0.9.2" +rsa-der = "0.3.0" +rustc-hash = "1.1.0" +serde = "1.0.160" +serde-value = "0.7.0" +serde_json = "1.0.96" +sha1 = "0.10.5" +sha2 = "0.10.6" +syn = "2.0.15" +syntect = { version = "5.0.0", default-features = false } +tempfile = "3.3.0" +thiserror = "1.0.40" +time = "0.3.17" +tokio = { version = "1.27.0", features = ["full"] } +toml = "0.7.2" +tracing = "0.1.37" +tracing-subscriber = "0.3.16" +url = { version = "2.2.2", features = ["serde"] } +uuid = "1.3.1" +valence = { path = ".", version = "0.2.0-alpha.1" } +valence_advancement = { path = "crates/valence_advancement", version = "0.2.0-alpha.1" } +valence_anvil = { path = "crates/valence_anvil", version = "0.1.0" } +valence_boss_bar = { path = "crates/valence_boss_bar", version = "0.2.0-alpha.1" } +valence_build_utils = { path = "crates/valence_build_utils", version = "0.2.0-alpha.1" } +valence_command = { path = "crates/valence_command", version = "0.2.0-alpha.1" } +valence_command_macros = { path = "crates/valence_command_macros", version = "0.2.0-alpha.1" } +valence_entity = { path = "crates/valence_entity", version = "0.2.0-alpha.1" } +valence_generated = { path = "crates/valence_generated", version = "0.2.0-alpha.1" } +valence_ident = { path = "crates/valence_ident", version = "0.2.0-alpha.1" } +valence_ident_macros = { path = "crates/valence_ident_macros", version = "0.2.0-alpha.1" } +valence_inventory = { path = "crates/valence_inventory", version = "0.2.0-alpha.1" } +valence_lang = { path = "crates/valence_lang", version = "0.2.0-alpha.1" } +valence_math = { path = "crates/valence_math", version = "0.2.0-alpha.1" } +valence_nbt = { path = "crates/valence_nbt", features = [ + "uuid", +], version = "0.8.0" } +valence_network = { path = "crates/valence_network", version = "0.2.0-alpha.1" } +valence_player_list = { path = "crates/valence_player_list", version = "0.2.0-alpha.1" } +valence_protocol = { path = "crates/valence_protocol", version = "0.2.0-alpha.1" } +valence_protocol_macros = { path = "crates/valence_protocol_macros", version = "0.2.0-alpha.1" } +valence_registry = { path = "crates/valence_registry", version = "0.2.0-alpha.1" } +valence_scoreboard = { path = "crates/valence_scoreboard", version = "0.2.0-alpha.1" } +valence_server = { path = "crates/valence_server", version = "0.2.0-alpha.1" } +valence_server_common = { path = "crates/valence_server_common", version = "0.2.0-alpha.1" } +valence_text = { path = "crates/valence_text", version = "0.2.0-alpha.1" } +valence_weather = { path = "crates/valence_weather", version = "0.2.0-alpha.1" } +valence_world_border = { path = "crates/valence_world_border", version = "0.2.0-alpha.1" } +zip = "0.6.3" diff --git a/README.md b/old/README.md similarity index 100% rename from README.md rename to old/README.md diff --git a/assets/depgraph.svg b/old/assets/depgraph.svg similarity index 100% rename from assets/depgraph.svg rename to old/assets/depgraph.svg diff --git a/assets/example_pack.zip b/old/assets/example_pack.zip similarity index 100% rename from assets/example_pack.zip rename to old/assets/example_pack.zip diff --git a/assets/logo-256x256.png b/old/assets/logo-256x256.png similarity index 100% rename from assets/logo-256x256.png rename to old/assets/logo-256x256.png diff --git a/assets/logo-64x64.png b/old/assets/logo-64x64.png similarity index 100% rename from assets/logo-64x64.png rename to old/assets/logo-64x64.png diff --git a/assets/logo-full.svg b/old/assets/logo-full.svg similarity index 100% rename from assets/logo-full.svg rename to old/assets/logo-full.svg diff --git a/assets/logo.svg b/old/assets/logo.svg similarity index 100% rename from assets/logo.svg rename to old/assets/logo.svg diff --git a/assets/many-players.png b/old/assets/many-players.png similarity index 100% rename from assets/many-players.png rename to old/assets/many-players.png diff --git a/assets/packet-inspector.png b/old/assets/packet-inspector.png similarity index 100% rename from assets/packet-inspector.png rename to old/assets/packet-inspector.png diff --git a/benches/anvil.rs b/old/benches/anvil.rs similarity index 100% rename from benches/anvil.rs rename to old/benches/anvil.rs diff --git a/benches/block.rs b/old/benches/block.rs similarity index 100% rename from benches/block.rs rename to old/benches/block.rs diff --git a/benches/decode_array.rs b/old/benches/decode_array.rs similarity index 100% rename from benches/decode_array.rs rename to old/benches/decode_array.rs diff --git a/benches/idle.rs b/old/benches/idle.rs similarity index 100% rename from benches/idle.rs rename to old/benches/idle.rs diff --git a/benches/main.rs b/old/benches/main.rs similarity index 100% rename from benches/main.rs rename to old/benches/main.rs diff --git a/benches/many_players.rs b/old/benches/many_players.rs similarity index 100% rename from benches/many_players.rs rename to old/benches/many_players.rs diff --git a/benches/packet.rs b/old/benches/packet.rs similarity index 100% rename from benches/packet.rs rename to old/benches/packet.rs diff --git a/benches/var_int.rs b/old/benches/var_int.rs similarity index 100% rename from benches/var_int.rs rename to old/benches/var_int.rs diff --git a/benches/var_long.rs b/old/benches/var_long.rs similarity index 100% rename from benches/var_long.rs rename to old/benches/var_long.rs diff --git a/crates/README.md b/old/crates/README.md similarity index 100% rename from crates/README.md rename to old/crates/README.md diff --git a/crates/valence_advancement/Cargo.toml b/old/crates/valence_advancement/Cargo.toml similarity index 100% rename from crates/valence_advancement/Cargo.toml rename to old/crates/valence_advancement/Cargo.toml diff --git a/crates/valence_advancement/README.md b/old/crates/valence_advancement/README.md similarity index 100% rename from crates/valence_advancement/README.md rename to old/crates/valence_advancement/README.md diff --git a/crates/valence_advancement/src/event.rs b/old/crates/valence_advancement/src/event.rs similarity index 100% rename from crates/valence_advancement/src/event.rs rename to old/crates/valence_advancement/src/event.rs diff --git a/crates/valence_advancement/src/lib.rs b/old/crates/valence_advancement/src/lib.rs similarity index 100% rename from crates/valence_advancement/src/lib.rs rename to old/crates/valence_advancement/src/lib.rs diff --git a/crates/valence_anvil/Cargo.toml b/old/crates/valence_anvil/Cargo.toml similarity index 100% rename from crates/valence_anvil/Cargo.toml rename to old/crates/valence_anvil/Cargo.toml diff --git a/crates/valence_anvil/README.md b/old/crates/valence_anvil/README.md similarity index 100% rename from crates/valence_anvil/README.md rename to old/crates/valence_anvil/README.md diff --git a/crates/valence_anvil/src/bevy.rs b/old/crates/valence_anvil/src/bevy.rs similarity index 100% rename from crates/valence_anvil/src/bevy.rs rename to old/crates/valence_anvil/src/bevy.rs diff --git a/crates/valence_anvil/src/lib.rs b/old/crates/valence_anvil/src/lib.rs similarity index 100% rename from crates/valence_anvil/src/lib.rs rename to old/crates/valence_anvil/src/lib.rs diff --git a/crates/valence_anvil/src/parsing.rs b/old/crates/valence_anvil/src/parsing.rs similarity index 100% rename from crates/valence_anvil/src/parsing.rs rename to old/crates/valence_anvil/src/parsing.rs diff --git a/crates/valence_boss_bar/Cargo.toml b/old/crates/valence_boss_bar/Cargo.toml similarity index 100% rename from crates/valence_boss_bar/Cargo.toml rename to old/crates/valence_boss_bar/Cargo.toml diff --git a/crates/valence_boss_bar/README.md b/old/crates/valence_boss_bar/README.md similarity index 100% rename from crates/valence_boss_bar/README.md rename to old/crates/valence_boss_bar/README.md diff --git a/crates/valence_boss_bar/src/components.rs b/old/crates/valence_boss_bar/src/components.rs similarity index 100% rename from crates/valence_boss_bar/src/components.rs rename to old/crates/valence_boss_bar/src/components.rs diff --git a/crates/valence_boss_bar/src/lib.rs b/old/crates/valence_boss_bar/src/lib.rs similarity index 100% rename from crates/valence_boss_bar/src/lib.rs rename to old/crates/valence_boss_bar/src/lib.rs diff --git a/old/crates/valence_build_utils/Cargo.toml b/old/crates/valence_build_utils/Cargo.toml new file mode 100644 index 000000000..7a928faaf --- /dev/null +++ b/old/crates/valence_build_utils/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "valence_build_utils" +description = "Common build script utilities for Valence" +readme = "README.md" +version.workspace = true +edition.workspace = true +repository.workspace = true +documentation.workspace = true +license.workspace = true + +[dependencies] +anyhow.workspace = true +syn.workspace = true +proc-macro2.workspace = true diff --git a/old/crates/valence_build_utils/README.md b/old/crates/valence_build_utils/README.md new file mode 100644 index 000000000..fa275e1a7 --- /dev/null +++ b/old/crates/valence_build_utils/README.md @@ -0,0 +1,3 @@ +# valence_build_utils + +Common code used in build scripts. diff --git a/old/crates/valence_build_utils/src/lib.rs b/old/crates/valence_build_utils/src/lib.rs new file mode 100644 index 000000000..775f82a75 --- /dev/null +++ b/old/crates/valence_build_utils/src/lib.rs @@ -0,0 +1,62 @@ +#![doc = include_str!("../README.md")] +#![deny( + rustdoc::broken_intra_doc_links, + rustdoc::private_intra_doc_links, + rustdoc::missing_crate_level_docs, + rustdoc::invalid_codeblock_attributes, + rustdoc::invalid_rust_codeblocks, + rustdoc::bare_urls, + rustdoc::invalid_html_tags +)] +#![warn( + trivial_casts, + trivial_numeric_casts, + unused_lifetimes, + unused_import_braces, + unreachable_pub, + clippy::dbg_macro +)] + +use std::path::Path; +use std::process::Command; +use std::{env, fs}; + +use anyhow::Context; +use proc_macro2::{Ident, Span, TokenStream}; + +pub fn write_generated_file(content: TokenStream, out_file: &str) -> anyhow::Result<()> { + let out_dir = env::var_os("OUT_DIR").context("failed to get OUT_DIR env var")?; + let path = Path::new(&out_dir).join(out_file); + let code = content.to_string(); + + fs::write(&path, code)?; + + // Try to format the output for debugging purposes. + // Doesn't matter if rustfmt is unavailable. + let _ = Command::new("rustfmt").arg(path).output(); + + Ok(()) +} + +/// Parses a [`proc_macro2::Ident`] from a `str`. Rust keywords are prepended +/// with underscores to make them valid identifiers. +pub fn ident(s: impl AsRef) -> Ident { + let s = s.as_ref().trim(); + + // Parse the ident from a str. If the string is a Rust keyword, stick an + // underscore in front. + syn::parse_str::(s) + .unwrap_or_else(|_| Ident::new(format!("_{s}").as_str(), Span::call_site())) +} + +#[track_caller] +pub fn rerun_if_changed(files: [&str; N]) { + for file in files { + assert!( + Path::new(file).exists(), + "File \"{file}\" does not exist. Did you forget to update the path?" + ); + + println!("cargo:rerun-if-changed={file}"); + } +} diff --git a/crates/valence_command/Cargo.toml b/old/crates/valence_command/Cargo.toml similarity index 100% rename from crates/valence_command/Cargo.toml rename to old/crates/valence_command/Cargo.toml diff --git a/crates/valence_command/README.md b/old/crates/valence_command/README.md similarity index 100% rename from crates/valence_command/README.md rename to old/crates/valence_command/README.md diff --git a/crates/valence_command/src/graph.rs b/old/crates/valence_command/src/graph.rs similarity index 100% rename from crates/valence_command/src/graph.rs rename to old/crates/valence_command/src/graph.rs diff --git a/crates/valence_command/src/handler.rs b/old/crates/valence_command/src/handler.rs similarity index 100% rename from crates/valence_command/src/handler.rs rename to old/crates/valence_command/src/handler.rs diff --git a/crates/valence_command/src/lib.rs b/old/crates/valence_command/src/lib.rs similarity index 100% rename from crates/valence_command/src/lib.rs rename to old/crates/valence_command/src/lib.rs diff --git a/crates/valence_command/src/manager.rs b/old/crates/valence_command/src/manager.rs similarity index 100% rename from crates/valence_command/src/manager.rs rename to old/crates/valence_command/src/manager.rs diff --git a/crates/valence_command/src/modifier_value.rs b/old/crates/valence_command/src/modifier_value.rs similarity index 100% rename from crates/valence_command/src/modifier_value.rs rename to old/crates/valence_command/src/modifier_value.rs diff --git a/crates/valence_command/src/parsers.rs b/old/crates/valence_command/src/parsers.rs similarity index 100% rename from crates/valence_command/src/parsers.rs rename to old/crates/valence_command/src/parsers.rs diff --git a/crates/valence_command/src/parsers/angle.rs b/old/crates/valence_command/src/parsers/angle.rs similarity index 100% rename from crates/valence_command/src/parsers/angle.rs rename to old/crates/valence_command/src/parsers/angle.rs diff --git a/crates/valence_command/src/parsers/block_pos.rs b/old/crates/valence_command/src/parsers/block_pos.rs similarity index 100% rename from crates/valence_command/src/parsers/block_pos.rs rename to old/crates/valence_command/src/parsers/block_pos.rs diff --git a/crates/valence_command/src/parsers/bool.rs b/old/crates/valence_command/src/parsers/bool.rs similarity index 100% rename from crates/valence_command/src/parsers/bool.rs rename to old/crates/valence_command/src/parsers/bool.rs diff --git a/crates/valence_command/src/parsers/color.rs b/old/crates/valence_command/src/parsers/color.rs similarity index 100% rename from crates/valence_command/src/parsers/color.rs rename to old/crates/valence_command/src/parsers/color.rs diff --git a/crates/valence_command/src/parsers/column_pos.rs b/old/crates/valence_command/src/parsers/column_pos.rs similarity index 100% rename from crates/valence_command/src/parsers/column_pos.rs rename to old/crates/valence_command/src/parsers/column_pos.rs diff --git a/crates/valence_command/src/parsers/entity_anchor.rs b/old/crates/valence_command/src/parsers/entity_anchor.rs similarity index 100% rename from crates/valence_command/src/parsers/entity_anchor.rs rename to old/crates/valence_command/src/parsers/entity_anchor.rs diff --git a/crates/valence_command/src/parsers/entity_selector.rs b/old/crates/valence_command/src/parsers/entity_selector.rs similarity index 100% rename from crates/valence_command/src/parsers/entity_selector.rs rename to old/crates/valence_command/src/parsers/entity_selector.rs diff --git a/crates/valence_command/src/parsers/gamemode.rs b/old/crates/valence_command/src/parsers/gamemode.rs similarity index 100% rename from crates/valence_command/src/parsers/gamemode.rs rename to old/crates/valence_command/src/parsers/gamemode.rs diff --git a/crates/valence_command/src/parsers/inventory_slot.rs b/old/crates/valence_command/src/parsers/inventory_slot.rs similarity index 100% rename from crates/valence_command/src/parsers/inventory_slot.rs rename to old/crates/valence_command/src/parsers/inventory_slot.rs diff --git a/crates/valence_command/src/parsers/numbers.rs b/old/crates/valence_command/src/parsers/numbers.rs similarity index 100% rename from crates/valence_command/src/parsers/numbers.rs rename to old/crates/valence_command/src/parsers/numbers.rs diff --git a/crates/valence_command/src/parsers/rotation.rs b/old/crates/valence_command/src/parsers/rotation.rs similarity index 100% rename from crates/valence_command/src/parsers/rotation.rs rename to old/crates/valence_command/src/parsers/rotation.rs diff --git a/crates/valence_command/src/parsers/score_holder.rs b/old/crates/valence_command/src/parsers/score_holder.rs similarity index 100% rename from crates/valence_command/src/parsers/score_holder.rs rename to old/crates/valence_command/src/parsers/score_holder.rs diff --git a/crates/valence_command/src/parsers/strings.rs b/old/crates/valence_command/src/parsers/strings.rs similarity index 100% rename from crates/valence_command/src/parsers/strings.rs rename to old/crates/valence_command/src/parsers/strings.rs diff --git a/crates/valence_command/src/parsers/swizzle.rs b/old/crates/valence_command/src/parsers/swizzle.rs similarity index 100% rename from crates/valence_command/src/parsers/swizzle.rs rename to old/crates/valence_command/src/parsers/swizzle.rs diff --git a/crates/valence_command/src/parsers/time.rs b/old/crates/valence_command/src/parsers/time.rs similarity index 100% rename from crates/valence_command/src/parsers/time.rs rename to old/crates/valence_command/src/parsers/time.rs diff --git a/crates/valence_command/src/parsers/vec2.rs b/old/crates/valence_command/src/parsers/vec2.rs similarity index 100% rename from crates/valence_command/src/parsers/vec2.rs rename to old/crates/valence_command/src/parsers/vec2.rs diff --git a/crates/valence_command/src/parsers/vec3.rs b/old/crates/valence_command/src/parsers/vec3.rs similarity index 100% rename from crates/valence_command/src/parsers/vec3.rs rename to old/crates/valence_command/src/parsers/vec3.rs diff --git a/crates/valence_command/src/scopes.rs b/old/crates/valence_command/src/scopes.rs similarity index 100% rename from crates/valence_command/src/scopes.rs rename to old/crates/valence_command/src/scopes.rs diff --git a/crates/valence_command_macros/Cargo.toml b/old/crates/valence_command_macros/Cargo.toml similarity index 100% rename from crates/valence_command_macros/Cargo.toml rename to old/crates/valence_command_macros/Cargo.toml diff --git a/crates/valence_command_macros/README.md b/old/crates/valence_command_macros/README.md similarity index 100% rename from crates/valence_command_macros/README.md rename to old/crates/valence_command_macros/README.md diff --git a/crates/valence_command_macros/src/lib.rs b/old/crates/valence_command_macros/src/lib.rs similarity index 100% rename from crates/valence_command_macros/src/lib.rs rename to old/crates/valence_command_macros/src/lib.rs diff --git a/crates/valence_entity/Cargo.toml b/old/crates/valence_entity/Cargo.toml similarity index 100% rename from crates/valence_entity/Cargo.toml rename to old/crates/valence_entity/Cargo.toml diff --git a/crates/valence_entity/README.md b/old/crates/valence_entity/README.md similarity index 100% rename from crates/valence_entity/README.md rename to old/crates/valence_entity/README.md diff --git a/crates/valence_entity/build.rs b/old/crates/valence_entity/build.rs similarity index 100% rename from crates/valence_entity/build.rs rename to old/crates/valence_entity/build.rs diff --git a/crates/valence_entity/extracted/entities.json b/old/crates/valence_entity/extracted/entities.json similarity index 100% rename from crates/valence_entity/extracted/entities.json rename to old/crates/valence_entity/extracted/entities.json diff --git a/crates/valence_entity/extracted/misc.json b/old/crates/valence_entity/extracted/misc.json similarity index 100% rename from crates/valence_entity/extracted/misc.json rename to old/crates/valence_entity/extracted/misc.json diff --git a/crates/valence_entity/src/active_status_effects.rs b/old/crates/valence_entity/src/active_status_effects.rs similarity index 100% rename from crates/valence_entity/src/active_status_effects.rs rename to old/crates/valence_entity/src/active_status_effects.rs diff --git a/crates/valence_entity/src/attributes.rs b/old/crates/valence_entity/src/attributes.rs similarity index 100% rename from crates/valence_entity/src/attributes.rs rename to old/crates/valence_entity/src/attributes.rs diff --git a/crates/valence_entity/src/flags.rs b/old/crates/valence_entity/src/flags.rs similarity index 100% rename from crates/valence_entity/src/flags.rs rename to old/crates/valence_entity/src/flags.rs diff --git a/crates/valence_entity/src/hitbox.rs b/old/crates/valence_entity/src/hitbox.rs similarity index 100% rename from crates/valence_entity/src/hitbox.rs rename to old/crates/valence_entity/src/hitbox.rs diff --git a/crates/valence_entity/src/lib.rs b/old/crates/valence_entity/src/lib.rs similarity index 100% rename from crates/valence_entity/src/lib.rs rename to old/crates/valence_entity/src/lib.rs diff --git a/crates/valence_entity/src/manager.rs b/old/crates/valence_entity/src/manager.rs similarity index 100% rename from crates/valence_entity/src/manager.rs rename to old/crates/valence_entity/src/manager.rs diff --git a/crates/valence_entity/src/query.rs b/old/crates/valence_entity/src/query.rs similarity index 100% rename from crates/valence_entity/src/query.rs rename to old/crates/valence_entity/src/query.rs diff --git a/crates/valence_entity/src/tracked_data.rs b/old/crates/valence_entity/src/tracked_data.rs similarity index 100% rename from crates/valence_entity/src/tracked_data.rs rename to old/crates/valence_entity/src/tracked_data.rs diff --git a/crates/valence_generated/Cargo.toml b/old/crates/valence_generated/Cargo.toml similarity index 100% rename from crates/valence_generated/Cargo.toml rename to old/crates/valence_generated/Cargo.toml diff --git a/crates/valence_generated/README.md b/old/crates/valence_generated/README.md similarity index 100% rename from crates/valence_generated/README.md rename to old/crates/valence_generated/README.md diff --git a/crates/valence_generated/build/attributes.rs b/old/crates/valence_generated/build/attributes.rs similarity index 100% rename from crates/valence_generated/build/attributes.rs rename to old/crates/valence_generated/build/attributes.rs diff --git a/crates/valence_generated/build/block.rs b/old/crates/valence_generated/build/block.rs similarity index 100% rename from crates/valence_generated/build/block.rs rename to old/crates/valence_generated/build/block.rs diff --git a/crates/valence_generated/build/chunk_view.rs b/old/crates/valence_generated/build/chunk_view.rs similarity index 100% rename from crates/valence_generated/build/chunk_view.rs rename to old/crates/valence_generated/build/chunk_view.rs diff --git a/crates/valence_generated/build/item.rs b/old/crates/valence_generated/build/item.rs similarity index 100% rename from crates/valence_generated/build/item.rs rename to old/crates/valence_generated/build/item.rs diff --git a/crates/valence_generated/build/main.rs b/old/crates/valence_generated/build/main.rs similarity index 100% rename from crates/valence_generated/build/main.rs rename to old/crates/valence_generated/build/main.rs diff --git a/crates/valence_generated/build/packet_id.rs b/old/crates/valence_generated/build/packet_id.rs similarity index 100% rename from crates/valence_generated/build/packet_id.rs rename to old/crates/valence_generated/build/packet_id.rs diff --git a/crates/valence_generated/build/sound.rs b/old/crates/valence_generated/build/sound.rs similarity index 100% rename from crates/valence_generated/build/sound.rs rename to old/crates/valence_generated/build/sound.rs diff --git a/crates/valence_generated/build/status_effects.rs b/old/crates/valence_generated/build/status_effects.rs similarity index 100% rename from crates/valence_generated/build/status_effects.rs rename to old/crates/valence_generated/build/status_effects.rs diff --git a/crates/valence_generated/extracted/attributes.json b/old/crates/valence_generated/extracted/attributes.json similarity index 100% rename from crates/valence_generated/extracted/attributes.json rename to old/crates/valence_generated/extracted/attributes.json diff --git a/crates/valence_generated/extracted/blocks.json b/old/crates/valence_generated/extracted/blocks.json similarity index 100% rename from crates/valence_generated/extracted/blocks.json rename to old/crates/valence_generated/extracted/blocks.json diff --git a/crates/valence_generated/extracted/effects.json b/old/crates/valence_generated/extracted/effects.json similarity index 100% rename from crates/valence_generated/extracted/effects.json rename to old/crates/valence_generated/extracted/effects.json diff --git a/crates/valence_generated/extracted/items.json b/old/crates/valence_generated/extracted/items.json similarity index 100% rename from crates/valence_generated/extracted/items.json rename to old/crates/valence_generated/extracted/items.json diff --git a/crates/valence_generated/extracted/packets.json b/old/crates/valence_generated/extracted/packets.json similarity index 100% rename from crates/valence_generated/extracted/packets.json rename to old/crates/valence_generated/extracted/packets.json diff --git a/crates/valence_generated/extracted/sounds.json b/old/crates/valence_generated/extracted/sounds.json similarity index 100% rename from crates/valence_generated/extracted/sounds.json rename to old/crates/valence_generated/extracted/sounds.json diff --git a/crates/valence_generated/src/block.rs b/old/crates/valence_generated/src/block.rs similarity index 100% rename from crates/valence_generated/src/block.rs rename to old/crates/valence_generated/src/block.rs diff --git a/crates/valence_generated/src/lib.rs b/old/crates/valence_generated/src/lib.rs similarity index 100% rename from crates/valence_generated/src/lib.rs rename to old/crates/valence_generated/src/lib.rs diff --git a/crates/valence_inventory/Cargo.toml b/old/crates/valence_inventory/Cargo.toml similarity index 100% rename from crates/valence_inventory/Cargo.toml rename to old/crates/valence_inventory/Cargo.toml diff --git a/crates/valence_inventory/README.md b/old/crates/valence_inventory/README.md similarity index 100% rename from crates/valence_inventory/README.md rename to old/crates/valence_inventory/README.md diff --git a/crates/valence_inventory/src/lib.rs b/old/crates/valence_inventory/src/lib.rs similarity index 100% rename from crates/valence_inventory/src/lib.rs rename to old/crates/valence_inventory/src/lib.rs diff --git a/crates/valence_inventory/src/player_inventory.rs b/old/crates/valence_inventory/src/player_inventory.rs similarity index 100% rename from crates/valence_inventory/src/player_inventory.rs rename to old/crates/valence_inventory/src/player_inventory.rs diff --git a/crates/valence_inventory/src/validate.rs b/old/crates/valence_inventory/src/validate.rs similarity index 100% rename from crates/valence_inventory/src/validate.rs rename to old/crates/valence_inventory/src/validate.rs diff --git a/crates/valence_lang/Cargo.toml b/old/crates/valence_lang/Cargo.toml similarity index 100% rename from crates/valence_lang/Cargo.toml rename to old/crates/valence_lang/Cargo.toml diff --git a/crates/valence_lang/README.md b/old/crates/valence_lang/README.md similarity index 100% rename from crates/valence_lang/README.md rename to old/crates/valence_lang/README.md diff --git a/crates/valence_lang/build.rs b/old/crates/valence_lang/build.rs similarity index 100% rename from crates/valence_lang/build.rs rename to old/crates/valence_lang/build.rs diff --git a/crates/valence_lang/extracted/translation_keys.json b/old/crates/valence_lang/extracted/translation_keys.json similarity index 100% rename from crates/valence_lang/extracted/translation_keys.json rename to old/crates/valence_lang/extracted/translation_keys.json diff --git a/crates/valence_lang/src/lib.rs b/old/crates/valence_lang/src/lib.rs similarity index 100% rename from crates/valence_lang/src/lib.rs rename to old/crates/valence_lang/src/lib.rs diff --git a/old/crates/valence_math/Cargo.toml b/old/crates/valence_math/Cargo.toml new file mode 100644 index 000000000..08badf18c --- /dev/null +++ b/old/crates/valence_math/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "valence_math" +description = "Math for Valence" +readme = "README.md" +version.workspace = true +edition.workspace = true +repository.workspace = true +documentation.workspace = true +license.workspace = true + +[dependencies] +glam.workspace = true diff --git a/old/crates/valence_math/README.md b/old/crates/valence_math/README.md new file mode 100644 index 000000000..d7f7f9189 --- /dev/null +++ b/old/crates/valence_math/README.md @@ -0,0 +1,6 @@ +# valence_math + +Common math utilities for Valence. + +This crate re-exports the contents of [`glam`](https://docs.rs/glam/latest/glam/) along with our own types such as [`Aabb`]. +For more information, please see `glam`'s documentation. diff --git a/old/crates/valence_math/src/aabb.rs b/old/crates/valence_math/src/aabb.rs new file mode 100644 index 000000000..48b02e2f7 --- /dev/null +++ b/old/crates/valence_math/src/aabb.rs @@ -0,0 +1,214 @@ +use std::ops::{Add, Sub}; + +use glam::DVec3; + +/// A three-dimensional axis-aligned bounding box, or "AABB". +/// +/// The AABB is defined by two points—`min` and `max`. `min` is less than or +/// equal to `max` componentwise. +#[derive(Copy, Clone, PartialEq, Default, Debug)] +pub struct Aabb { + min: DVec3, + max: DVec3, +} + +impl Aabb { + pub const ZERO: Self = Self { + min: DVec3::ZERO, + max: DVec3::ZERO, + }; + + /// Constructs a new AABB from `min` and `max` points. + /// + /// # Panics + /// + /// Panics if `debug_assertions` are enabled and `min` is not less than or + /// equal to `max` componentwise. + #[cfg_attr(debug_assertions, track_caller)] + pub fn new(min: DVec3, max: DVec3) -> Self { + debug_assert!( + min.x <= max.x && min.y <= max.y && min.z <= max.z, + "`min` must be less than or equal to `max` componentwise (min = {min}, max = {max})" + ); + + Self { min, max } + } + + // TODO: remove when the assertion in `new` can be done in a `const` context. + #[doc(hidden)] + pub const fn new_unchecked(min: DVec3, max: DVec3) -> Self { + Self { min, max } + } + + /// Returns a new AABB containing a single point `p`. + pub fn new_point(p: DVec3) -> Self { + Self::new(p, p) + } + + pub fn from_bottom_size(bottom: DVec3, size: DVec3) -> Self { + Self::new( + DVec3 { + x: bottom.x - size.x / 2.0, + y: bottom.y, + z: bottom.z - size.z / 2.0, + }, + DVec3 { + x: bottom.x + size.x / 2.0, + y: bottom.y + size.y, + z: bottom.z + size.z / 2.0, + }, + ) + } + + pub const fn min(self) -> DVec3 { + self.min + } + + pub const fn max(self) -> DVec3 { + self.max + } + + pub fn union(self, other: Self) -> Self { + Self::new(self.min.min(other.min), self.max.max(other.max)) + } + + pub fn intersects(self, other: Self) -> bool { + self.max.x >= other.min.x + && other.max.x >= self.min.x + && self.max.y >= other.min.y + && other.max.y >= self.min.y + && self.max.z >= other.min.z + && other.max.z >= self.min.z + } + + /// Does this bounding box contain the given point? + pub fn contains_point(self, p: DVec3) -> bool { + self.min.x <= p.x + && self.min.y <= p.y + && self.min.z <= p.z + && self.max.x >= p.x + && self.max.y >= p.y + && self.max.z >= p.z + } + + /// Returns the closest point in the AABB to the given point. + pub fn projected_point(self, p: DVec3) -> DVec3 { + p.clamp(self.min, self.max) + } + + /// Returns the smallest distance from the AABB to the point. + pub fn distance_to_point(self, p: DVec3) -> f64 { + self.projected_point(p).distance(p) + } + + /// Calculates the intersection between this AABB and a ray + /// defined by its `origin` point and `direction` vector. + /// + /// If an intersection occurs, `Some([near, far])` is returned. `near` and + /// `far` are the values of `t` in the equation `origin + t * direction = + /// point` where `point` is the nearest or furthest intersection point to + /// the `origin`. If no intersection occurs, then `None` is returned. + /// + /// In other words, if `direction` is normalized, then `near` and `far` are + /// the distances to the nearest and furthest intersection points. + pub fn ray_intersection(self, origin: DVec3, direction: DVec3) -> Option<[f64; 2]> { + let mut near: f64 = 0.0; + let mut far = f64::INFINITY; + + for i in 0..3 { + // Rust's definition of `min` and `max` properly handle the NaNs these + // computations may produce. + let t0 = (self.min[i] - origin[i]) / direction[i]; + let t1 = (self.max[i] - origin[i]) / direction[i]; + + near = near.max(t0.min(t1)); + far = far.min(t0.max(t1)); + } + + if near <= far { + Some([near, far]) + } else { + None + } + } +} + +impl Add for Aabb { + type Output = Aabb; + + fn add(self, rhs: DVec3) -> Self::Output { + Self::new(self.min + rhs, self.max + rhs) + } +} + +impl Add for DVec3 { + type Output = Aabb; + + fn add(self, rhs: Aabb) -> Self::Output { + rhs + self + } +} + +impl Sub for Aabb { + type Output = Aabb; + + fn sub(self, rhs: DVec3) -> Self::Output { + Self::new(self.min - rhs, self.max - rhs) + } +} + +impl Sub for DVec3 { + type Output = Aabb; + + fn sub(self, rhs: Aabb) -> Self::Output { + rhs - self + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn ray_intersect_edge_cases() { + let bb = Aabb::new([0.0, 0.0, 0.0].into(), [1.0, 1.0, 1.0].into()); + + let ros = [ + // On a corner + DVec3::new(0.0, 0.0, 0.0), + // Outside + DVec3::new(-0.5, 0.5, -0.5), + // In the center + DVec3::new(0.5, 0.5, 0.5), + // On an edge + DVec3::new(0.0, 0.5, 0.0), + // On a face + DVec3::new(0.0, 0.5, 0.5), + // Outside slabs + DVec3::new(-2.0, -2.0, -2.0), + ]; + + let rds = [ + DVec3::new(1.0, 0.0, 0.0), + DVec3::new(-1.0, 0.0, 0.0), + DVec3::new(0.0, 1.0, 0.0), + DVec3::new(0.0, -1.0, 0.0), + DVec3::new(0.0, 0.0, 1.0), + DVec3::new(0.0, 0.0, -1.0), + ]; + + assert!(rds.iter().all(|d| d.is_normalized())); + + for ro in ros { + for rd in rds { + if let Some([near, far]) = bb.ray_intersection(ro, rd) { + assert!(near.is_finite()); + assert!(far.is_finite()); + assert!(near <= far); + assert!(near >= 0.0); + assert!(far >= 0.0); + } + } + } + } +} diff --git a/old/crates/valence_math/src/lib.rs b/old/crates/valence_math/src/lib.rs new file mode 100644 index 000000000..bf3db2c01 --- /dev/null +++ b/old/crates/valence_math/src/lib.rs @@ -0,0 +1,6 @@ +#![doc = include_str!("../README.md")] + +mod aabb; + +pub use aabb::Aabb; +pub use glam::*; diff --git a/crates/valence_network/Cargo.toml b/old/crates/valence_network/Cargo.toml similarity index 100% rename from crates/valence_network/Cargo.toml rename to old/crates/valence_network/Cargo.toml diff --git a/crates/valence_network/README.md b/old/crates/valence_network/README.md similarity index 100% rename from crates/valence_network/README.md rename to old/crates/valence_network/README.md diff --git a/crates/valence_network/src/byte_channel.rs b/old/crates/valence_network/src/byte_channel.rs similarity index 100% rename from crates/valence_network/src/byte_channel.rs rename to old/crates/valence_network/src/byte_channel.rs diff --git a/crates/valence_network/src/connect.rs b/old/crates/valence_network/src/connect.rs similarity index 100% rename from crates/valence_network/src/connect.rs rename to old/crates/valence_network/src/connect.rs diff --git a/crates/valence_network/src/legacy_ping.rs b/old/crates/valence_network/src/legacy_ping.rs similarity index 100% rename from crates/valence_network/src/legacy_ping.rs rename to old/crates/valence_network/src/legacy_ping.rs diff --git a/crates/valence_network/src/lib.rs b/old/crates/valence_network/src/lib.rs similarity index 100% rename from crates/valence_network/src/lib.rs rename to old/crates/valence_network/src/lib.rs diff --git a/crates/valence_network/src/packet_io.rs b/old/crates/valence_network/src/packet_io.rs similarity index 100% rename from crates/valence_network/src/packet_io.rs rename to old/crates/valence_network/src/packet_io.rs diff --git a/crates/valence_player_list/Cargo.toml b/old/crates/valence_player_list/Cargo.toml similarity index 100% rename from crates/valence_player_list/Cargo.toml rename to old/crates/valence_player_list/Cargo.toml diff --git a/crates/valence_player_list/README.md b/old/crates/valence_player_list/README.md similarity index 100% rename from crates/valence_player_list/README.md rename to old/crates/valence_player_list/README.md diff --git a/crates/valence_player_list/src/lib.rs b/old/crates/valence_player_list/src/lib.rs similarity index 100% rename from crates/valence_player_list/src/lib.rs rename to old/crates/valence_player_list/src/lib.rs diff --git a/old/crates/valence_protocol/Cargo.toml b/old/crates/valence_protocol/Cargo.toml new file mode 100644 index 000000000..bee995eca --- /dev/null +++ b/old/crates/valence_protocol/Cargo.toml @@ -0,0 +1,40 @@ +[package] +name = "valence_protocol" +description = "Protocol library for Minecraft: Java Edition" +readme = "README.md" +version.workspace = true +edition.workspace = true +repository.workspace = true +documentation.workspace = true +license.workspace = true + +[features] +encryption = ["dep:aes", "dep:cfb8"] +compression = ["dep:flate2"] + +[dependencies] +bevy_ecs.workspace = true # TODO: make this optional +valence_math.workspace = true +valence_generated.workspace = true +valence_text.workspace = true +valence_nbt = { workspace = true, features = ["binary"] } +valence_protocol_macros.workspace = true +anyhow.workspace = true +thiserror.workspace = true +serde = { workspace = true, features = ["derive"] } +byteorder.workspace = true +uuid.workspace = true +valence_ident.workspace = true +base64.workspace = true +url.workspace = true +serde_json.workspace = true +tracing.workspace = true +bytes.workspace = true +bitfield-struct.workspace = true +derive_more = { workspace = true, features = ["from", "into", "deref", "deref_mut", "as_ref"] } +cfb8 = { workspace = true, optional = true } +flate2 = { workspace = true, optional = true } +aes = { workspace = true, optional = true } + +[dev-dependencies] +rand.workspace = true diff --git a/crates/valence_protocol/README.md b/old/crates/valence_protocol/README.md similarity index 100% rename from crates/valence_protocol/README.md rename to old/crates/valence_protocol/README.md diff --git a/crates/valence_protocol/src/array.rs b/old/crates/valence_protocol/src/array.rs similarity index 100% rename from crates/valence_protocol/src/array.rs rename to old/crates/valence_protocol/src/array.rs diff --git a/crates/valence_protocol/src/biome_pos.rs b/old/crates/valence_protocol/src/biome_pos.rs similarity index 100% rename from crates/valence_protocol/src/biome_pos.rs rename to old/crates/valence_protocol/src/biome_pos.rs diff --git a/crates/valence_protocol/src/bit_set.rs b/old/crates/valence_protocol/src/bit_set.rs similarity index 100% rename from crates/valence_protocol/src/bit_set.rs rename to old/crates/valence_protocol/src/bit_set.rs diff --git a/crates/valence_protocol/src/block_pos.rs b/old/crates/valence_protocol/src/block_pos.rs similarity index 100% rename from crates/valence_protocol/src/block_pos.rs rename to old/crates/valence_protocol/src/block_pos.rs diff --git a/crates/valence_protocol/src/bounded.rs b/old/crates/valence_protocol/src/bounded.rs similarity index 100% rename from crates/valence_protocol/src/bounded.rs rename to old/crates/valence_protocol/src/bounded.rs diff --git a/crates/valence_protocol/src/byte_angle.rs b/old/crates/valence_protocol/src/byte_angle.rs similarity index 100% rename from crates/valence_protocol/src/byte_angle.rs rename to old/crates/valence_protocol/src/byte_angle.rs diff --git a/crates/valence_protocol/src/chunk_pos.rs b/old/crates/valence_protocol/src/chunk_pos.rs similarity index 100% rename from crates/valence_protocol/src/chunk_pos.rs rename to old/crates/valence_protocol/src/chunk_pos.rs diff --git a/crates/valence_protocol/src/chunk_section_pos.rs b/old/crates/valence_protocol/src/chunk_section_pos.rs similarity index 100% rename from crates/valence_protocol/src/chunk_section_pos.rs rename to old/crates/valence_protocol/src/chunk_section_pos.rs diff --git a/crates/valence_protocol/src/decode.rs b/old/crates/valence_protocol/src/decode.rs similarity index 100% rename from crates/valence_protocol/src/decode.rs rename to old/crates/valence_protocol/src/decode.rs diff --git a/crates/valence_protocol/src/difficulty.rs b/old/crates/valence_protocol/src/difficulty.rs similarity index 100% rename from crates/valence_protocol/src/difficulty.rs rename to old/crates/valence_protocol/src/difficulty.rs diff --git a/crates/valence_protocol/src/direction.rs b/old/crates/valence_protocol/src/direction.rs similarity index 100% rename from crates/valence_protocol/src/direction.rs rename to old/crates/valence_protocol/src/direction.rs diff --git a/crates/valence_protocol/src/encode.rs b/old/crates/valence_protocol/src/encode.rs similarity index 100% rename from crates/valence_protocol/src/encode.rs rename to old/crates/valence_protocol/src/encode.rs diff --git a/crates/valence_protocol/src/game_mode.rs b/old/crates/valence_protocol/src/game_mode.rs similarity index 100% rename from crates/valence_protocol/src/game_mode.rs rename to old/crates/valence_protocol/src/game_mode.rs diff --git a/crates/valence_protocol/src/global_pos.rs b/old/crates/valence_protocol/src/global_pos.rs similarity index 100% rename from crates/valence_protocol/src/global_pos.rs rename to old/crates/valence_protocol/src/global_pos.rs diff --git a/crates/valence_protocol/src/hand.rs b/old/crates/valence_protocol/src/hand.rs similarity index 100% rename from crates/valence_protocol/src/hand.rs rename to old/crates/valence_protocol/src/hand.rs diff --git a/crates/valence_protocol/src/impls.rs b/old/crates/valence_protocol/src/impls.rs similarity index 100% rename from crates/valence_protocol/src/impls.rs rename to old/crates/valence_protocol/src/impls.rs diff --git a/crates/valence_protocol/src/impls/map.rs b/old/crates/valence_protocol/src/impls/map.rs similarity index 100% rename from crates/valence_protocol/src/impls/map.rs rename to old/crates/valence_protocol/src/impls/map.rs diff --git a/crates/valence_protocol/src/impls/math.rs b/old/crates/valence_protocol/src/impls/math.rs similarity index 100% rename from crates/valence_protocol/src/impls/math.rs rename to old/crates/valence_protocol/src/impls/math.rs diff --git a/crates/valence_protocol/src/impls/other.rs b/old/crates/valence_protocol/src/impls/other.rs similarity index 100% rename from crates/valence_protocol/src/impls/other.rs rename to old/crates/valence_protocol/src/impls/other.rs diff --git a/crates/valence_protocol/src/impls/pointer.rs b/old/crates/valence_protocol/src/impls/pointer.rs similarity index 100% rename from crates/valence_protocol/src/impls/pointer.rs rename to old/crates/valence_protocol/src/impls/pointer.rs diff --git a/crates/valence_protocol/src/impls/primitive.rs b/old/crates/valence_protocol/src/impls/primitive.rs similarity index 100% rename from crates/valence_protocol/src/impls/primitive.rs rename to old/crates/valence_protocol/src/impls/primitive.rs diff --git a/crates/valence_protocol/src/impls/sequence.rs b/old/crates/valence_protocol/src/impls/sequence.rs similarity index 100% rename from crates/valence_protocol/src/impls/sequence.rs rename to old/crates/valence_protocol/src/impls/sequence.rs diff --git a/crates/valence_protocol/src/impls/string.rs b/old/crates/valence_protocol/src/impls/string.rs similarity index 100% rename from crates/valence_protocol/src/impls/string.rs rename to old/crates/valence_protocol/src/impls/string.rs diff --git a/crates/valence_protocol/src/impls/tuple.rs b/old/crates/valence_protocol/src/impls/tuple.rs similarity index 100% rename from crates/valence_protocol/src/impls/tuple.rs rename to old/crates/valence_protocol/src/impls/tuple.rs diff --git a/crates/valence_protocol/src/item.rs b/old/crates/valence_protocol/src/item.rs similarity index 100% rename from crates/valence_protocol/src/item.rs rename to old/crates/valence_protocol/src/item.rs diff --git a/old/crates/valence_protocol/src/lib.rs b/old/crates/valence_protocol/src/lib.rs new file mode 100644 index 000000000..e200795d8 --- /dev/null +++ b/old/crates/valence_protocol/src/lib.rs @@ -0,0 +1,473 @@ +#![doc = include_str!("../README.md")] +#![deny( + rustdoc::broken_intra_doc_links, + rustdoc::private_intra_doc_links, + rustdoc::missing_crate_level_docs, + rustdoc::invalid_codeblock_attributes, + rustdoc::invalid_rust_codeblocks, + rustdoc::bare_urls, + rustdoc::invalid_html_tags +)] +#![warn( + trivial_casts, + trivial_numeric_casts, + unused_lifetimes, + unused_import_braces, + unreachable_pub, + clippy::dbg_macro +)] + +/// Used only by macros. Not public API. +#[doc(hidden)] +pub mod __private { + pub use anyhow::{anyhow, bail, ensure, Context, Result}; + + pub use crate::var_int::VarInt; + pub use crate::{Decode, Encode, Packet}; +} + +// This allows us to use our own proc macros internally. +extern crate self as valence_protocol; + +mod array; +mod biome_pos; +mod bit_set; +pub mod block_pos; +mod bounded; +mod byte_angle; +pub mod chunk_pos; +pub mod chunk_section_pos; +pub mod decode; +mod difficulty; +mod direction; +pub mod encode; +pub mod game_mode; +mod global_pos; +mod hand; +mod impls; +pub mod item; +pub mod packets; +pub mod profile; +mod raw; +pub mod sound; +pub mod var_int; +mod var_long; +mod velocity; + +use std::io::Write; + +use anyhow::Context; +pub use array::FixedArray; +pub use biome_pos::BiomePos; +pub use bit_set::FixedBitSet; +pub use block::{BlockKind, BlockState}; +pub use block_pos::BlockPos; +pub use bounded::Bounded; +pub use byte_angle::ByteAngle; +pub use chunk_pos::ChunkPos; +pub use chunk_section_pos::ChunkSectionPos; +pub use decode::PacketDecoder; +use derive_more::{From, Into}; +pub use difficulty::Difficulty; +pub use direction::Direction; +pub use encode::{PacketEncoder, WritePacket}; +pub use game_mode::GameMode; +pub use global_pos::GlobalPos; +pub use hand::Hand; +pub use ident::ident; +pub use item::{ItemKind, ItemStack}; +pub use packets::play::particle_s2c::Particle; +pub use raw::RawBytes; +use serde::{Deserialize, Serialize}; +pub use sound::Sound; +pub use text::Text; +pub use valence_generated::{block, packet_id, status_effects}; +pub use valence_ident::Ident; +pub use valence_protocol_macros::{Decode, Encode, Packet}; +pub use var_int::VarInt; +pub use var_long::VarLong; +pub use velocity::Velocity; +pub use { + anyhow, bytes, uuid, valence_ident as ident, valence_math as math, valence_nbt as nbt, + valence_text as text, +}; + +/// The maximum number of bytes in a single Minecraft packet. +pub const MAX_PACKET_SIZE: i32 = 2097152; + +/// The Minecraft protocol version this library currently targets. +pub const PROTOCOL_VERSION: i32 = 763; + +/// The stringified name of the Minecraft version this library currently +/// targets. +pub const MINECRAFT_VERSION: &str = "1.20.1"; + +/// How large a packet should be before it is compressed by the packet encoder. +/// +/// If the inner value is >= 0, then packets with encoded lengths >= to this +/// value will be compressed. If the value is negative, then compression is +/// disabled and no packets are compressed. +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, From, Into)] +pub struct CompressionThreshold(pub i32); + +impl CompressionThreshold { + /// No compression. + pub const DEFAULT: Self = Self(-1); +} + +/// No compression. +impl Default for CompressionThreshold { + fn default() -> Self { + Self::DEFAULT + } +} + +/// The `Encode` trait allows objects to be written to the Minecraft protocol. +/// It is the inverse of [`Decode`]. +/// +/// # Deriving +/// +/// This trait can be implemented automatically for structs and enums by using +/// the [`Encode`][macro] derive macro. All components of the type must +/// implement `Encode`. Components are encoded in the order they appear in the +/// type definition. +/// +/// For enums, the variant to encode is marked by a leading [`VarInt`] +/// discriminant (tag). The discriminant value can be changed using the +/// `#[packet(tag = ...)]` attribute on the variant in question. Discriminant +/// values are assigned to variants using rules similar to regular enum +/// discriminants. +/// +/// ``` +/// use valence_protocol::Encode; +/// +/// #[derive(Encode)] +/// struct MyStruct<'a> { +/// first: i32, +/// second: &'a str, +/// third: [f64; 3], +/// } +/// +/// #[derive(Encode)] +/// enum MyEnum { +/// First, // tag = 0 +/// Second, // tag = 1 +/// #[packet(tag = 25)] +/// Third, // tag = 25 +/// Fourth, // tag = 26 +/// } +/// +/// let value = MyStruct { +/// first: 10, +/// second: "hello", +/// third: [1.5, 3.14, 2.718], +/// }; +/// +/// let mut buf = vec![]; +/// value.encode(&mut buf).unwrap(); +/// +/// println!("{buf:?}"); +/// ``` +/// +/// [macro]: valence_protocol_macros::Encode +/// [`VarInt`]: var_int::VarInt +pub trait Encode { + /// Writes this object to the provided writer. + /// + /// If this type also implements [`Decode`] then successful calls to this + /// function returning `Ok(())` must always successfully [`decode`] using + /// the data that was written to the writer. The exact number of bytes + /// that were originally written must be consumed during the decoding. + /// + /// [`decode`]: Decode::decode + fn encode(&self, w: impl Write) -> anyhow::Result<()>; + + /// Like [`Encode::encode`], except that a whole slice of values is encoded. + /// + /// This method must be semantically equivalent to encoding every element of + /// the slice in sequence with no leading length prefix (which is exactly + /// what the default implementation does), but a more efficient + /// implementation may be used. + /// + /// This method is important for some types like `u8` where the entire slice + /// can be encoded in a single call to [`write_all`]. Because impl + /// specialization is unavailable in stable Rust at the time of writing, + /// we must make the slice specialization part of this trait. + /// + /// [`write_all`]: Write::write_all + fn encode_slice(slice: &[Self], mut w: impl Write) -> anyhow::Result<()> + where + Self: Sized, + { + for value in slice { + value.encode(&mut w)?; + } + + Ok(()) + } +} + +/// The `Decode` trait allows objects to be read from the Minecraft protocol. It +/// is the inverse of [`Encode`]. +/// +/// `Decode` is parameterized by a lifetime. This allows the decoded value to +/// borrow data from the byte slice it was read from. +/// +/// # Deriving +/// +/// This trait can be implemented automatically for structs and enums by using +/// the [`Decode`][macro] derive macro. All components of the type must +/// implement `Decode`. Components are decoded in the order they appear in the +/// type definition. +/// +/// For enums, the variant to decode is determined by a leading [`VarInt`] +/// discriminant (tag). The discriminant value can be changed using the +/// `#[packet(tag = ...)]` attribute on the variant in question. Discriminant +/// values are assigned to variants using rules similar to regular enum +/// discriminants. +/// +/// ``` +/// use valence_protocol::Decode; +/// +/// #[derive(PartialEq, Debug, Decode)] +/// struct MyStruct { +/// first: i32, +/// second: MyEnum, +/// } +/// +/// #[derive(PartialEq, Debug, Decode)] +/// enum MyEnum { +/// First, // tag = 0 +/// Second, // tag = 1 +/// #[packet(tag = 25)] +/// Third, // tag = 25 +/// Fourth, // tag = 26 +/// } +/// +/// let mut r: &[u8] = &[0, 0, 0, 0, 26]; +/// +/// let value = MyStruct::decode(&mut r).unwrap(); +/// let expected = MyStruct { +/// first: 0, +/// second: MyEnum::Fourth, +/// }; +/// +/// assert_eq!(value, expected); +/// assert!(r.is_empty()); +/// ``` +/// +/// [macro]: valence_protocol_macros::Decode +/// [`VarInt`]: var_int::VarInt +pub trait Decode<'a>: Sized { + /// Reads this object from the provided byte slice. + /// + /// Implementations of `Decode` are expected to shrink the slice from the + /// front as bytes are read. + fn decode(r: &mut &'a [u8]) -> anyhow::Result; +} + +/// Types considered to be Minecraft packets. +/// +/// In serialized form, a packet begins with a [`VarInt`] packet ID followed by +/// the body of the packet. If present, the implementations of [`Encode`] and +/// [`Decode`] on `Self` are expected to only encode/decode the _body_ of this +/// packet without the leading ID. +pub trait Packet: std::fmt::Debug { + /// The leading VarInt ID of this packet. + const ID: i32; + /// The name of this packet for debugging purposes. + const NAME: &'static str; + /// The side this packet is intended for. + const SIDE: PacketSide; + /// The state in which this packet is used. + const STATE: PacketState; + + /// Encodes this packet's VarInt ID first, followed by the packet's body. + fn encode_with_id(&self, mut w: impl Write) -> anyhow::Result<()> + where + Self: Encode, + { + VarInt(Self::ID) + .encode(&mut w) + .context("failed to encode packet ID")?; + + self.encode(w) + } +} + +/// The side a packet is intended for. +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Serialize, Deserialize)] +pub enum PacketSide { + /// Server -> Client + Clientbound, + /// Client -> Server + Serverbound, +} + +/// The statein which a packet is used. +#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Serialize, Deserialize)] +pub enum PacketState { + Handshaking, + Status, + Login, + Play, +} + +#[allow(dead_code)] +#[cfg(test)] +mod tests { + use std::borrow::Cow; + + use bytes::BytesMut; + + use super::*; + use crate::block_pos::BlockPos; + use crate::decode::PacketDecoder; + use crate::encode::PacketEncoder; + use crate::hand::Hand; + use crate::item::{ItemKind, ItemStack}; + use crate::text::{IntoText, Text}; + use crate::var_int::VarInt; + use crate::var_long::VarLong; + use crate::Ident; + + #[derive(Encode, Decode, Packet, Debug)] + #[packet(id = 1, side = PacketSide::Clientbound)] + struct RegularStruct { + foo: i32, + bar: bool, + baz: f64, + } + + #[derive(Encode, Decode, Packet, Debug)] + #[packet(id = 2, side = PacketSide::Clientbound)] + struct UnitStruct; + + #[derive(Encode, Decode, Packet, Debug)] + #[packet(id = 3, side = PacketSide::Clientbound)] + struct EmptyStruct {} + + #[derive(Encode, Decode, Packet, Debug)] + #[packet(id = 4, side = PacketSide::Clientbound)] + struct TupleStruct(i32, bool, f64); + + #[derive(Encode, Decode, Packet, Debug)] + #[packet(id = 5, side = PacketSide::Clientbound)] + struct StructWithGenerics<'z, T = ()> { + foo: &'z str, + bar: T, + } + + #[derive(Encode, Decode, Packet, Debug)] + #[packet(id = 6, side = PacketSide::Clientbound)] + struct TupleStructWithGenerics<'z, T = ()>(&'z str, i32, T); + + #[allow(unconditional_recursion, clippy::extra_unused_type_parameters)] + fn assert_has_impls<'a, T>() + where + T: Encode + Decode<'a> + Packet, + { + assert_has_impls::(); + assert_has_impls::(); + assert_has_impls::(); + assert_has_impls::(); + assert_has_impls::(); + assert_has_impls::(); + } + + #[test] + fn packet_name() { + assert_eq!(RegularStruct::NAME, "RegularStruct"); + assert_eq!(UnitStruct::NAME, "UnitStruct"); + assert_eq!(StructWithGenerics::<()>::NAME, "StructWithGenerics"); + } + + #[cfg(feature = "encryption")] + const CRYPT_KEY: [u8; 16] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]; + + #[derive(PartialEq, Debug, Encode, Decode, Packet)] + #[packet(id = 42, side = PacketSide::Clientbound)] + struct TestPacket<'a> { + a: bool, + b: u8, + c: i32, + d: f32, + e: f64, + f: BlockPos, + g: Hand, + h: Ident>, + i: ItemStack, + j: Text, + k: VarInt, + l: VarLong, + m: &'a str, + n: &'a [u8; 10], + o: [u128; 3], + } + + impl<'a> TestPacket<'a> { + fn new(string: &'a str) -> Self { + Self { + a: true, + b: 12, + c: -999, + d: 5.001, + e: 1e10, + f: BlockPos::new(1, 2, 3), + g: Hand::Off, + h: Ident::new("minecraft:whatever").unwrap(), + i: ItemStack::new(ItemKind::WoodenSword, 12, None), + j: "my ".into_text() + "fancy".italic() + " text", + k: VarInt(123), + l: VarLong(456), + m: string, + n: &[7; 10], + o: [123456789; 3], + } + } + } + + fn check_test_packet(dec: &mut PacketDecoder, string: &str) { + let frame = dec.try_next_packet().unwrap().unwrap(); + + let pkt = frame.decode::().unwrap(); + + assert_eq!(&pkt, &TestPacket::new(string)); + } + + #[test] + fn packets_round_trip() { + let mut buf = BytesMut::new(); + + let mut enc = PacketEncoder::new(); + + enc.append_packet(&TestPacket::new("first")).unwrap(); + #[cfg(feature = "compression")] + enc.set_compression(0.into()); + enc.append_packet(&TestPacket::new("second")).unwrap(); + buf.unsplit(enc.take()); + #[cfg(feature = "encryption")] + enc.enable_encryption(&CRYPT_KEY); + enc.append_packet(&TestPacket::new("third")).unwrap(); + enc.prepend_packet(&TestPacket::new("fourth")).unwrap(); + + buf.unsplit(enc.take()); + + let mut dec = PacketDecoder::new(); + + dec.queue_bytes(buf); + + check_test_packet(&mut dec, "first"); + + #[cfg(feature = "compression")] + dec.set_compression(0.into()); + + check_test_packet(&mut dec, "second"); + + #[cfg(feature = "encryption")] + dec.enable_encryption(&CRYPT_KEY); + + check_test_packet(&mut dec, "fourth"); + check_test_packet(&mut dec, "third"); + } +} diff --git a/old/crates/valence_protocol/src/packets.rs b/old/crates/valence_protocol/src/packets.rs new file mode 100644 index 000000000..447c55149 --- /dev/null +++ b/old/crates/valence_protocol/src/packets.rs @@ -0,0 +1,366 @@ +//! All of Minecraft's network packets. +//! +//! Packets are grouped in submodules according to the protocol stage they're +//! used in. Names are derived from the FabricMC Yarn mappings for consistency. + +pub mod handshaking { + pub mod handshake_c2s; + pub use handshake_c2s::HandshakeC2s; +} + +pub mod login { + pub mod login_compression_s2c; + pub use login_compression_s2c::LoginCompressionS2c; + pub mod login_disconnect_s2c; + pub use login_disconnect_s2c::LoginDisconnectS2c; + pub mod login_hello_c2s; + pub use login_hello_c2s::LoginHelloC2s; + pub mod login_hello_s2c; + pub use login_hello_s2c::LoginHelloS2c; + pub mod login_key_c2s; + pub use login_key_c2s::LoginKeyC2s; + pub mod login_query_request_s2c; + pub use login_query_request_s2c::LoginQueryRequestS2c; + pub mod login_query_response_c2s; + pub use login_query_response_c2s::LoginQueryResponseC2s; + pub mod login_success_s2c; + pub use login_success_s2c::LoginSuccessS2c; +} + +pub mod play { + pub mod advancement_tab_c2s; + pub use advancement_tab_c2s::AdvancementTabC2s; + pub mod advancement_update_s2c; + pub use advancement_update_s2c::AdvancementUpdateS2c; + pub mod block_breaking_progress_s2c; + pub use block_breaking_progress_s2c::BlockBreakingProgressS2c; + pub mod block_entity_update_s2c; + pub use block_entity_update_s2c::BlockEntityUpdateS2c; + pub mod block_event_s2c; + pub use block_event_s2c::BlockEventS2c; + pub mod block_update_s2c; + pub use block_update_s2c::BlockUpdateS2c; + pub mod boat_paddle_state_c2s; + pub use boat_paddle_state_c2s::BoatPaddleStateC2s; + pub mod book_update_c2s; + pub use book_update_c2s::BookUpdateC2s; + pub mod boss_bar_s2c; + pub use boss_bar_s2c::BossBarS2c; + pub mod bundle_splitter_s2c; + pub use bundle_splitter_s2c::BundleSplitterS2c; + pub mod button_click_c2s; + pub use button_click_c2s::ButtonClickC2s; + pub mod chat_message_c2s; + pub use chat_message_c2s::ChatMessageC2s; + pub mod chat_message_s2c; + pub use chat_message_s2c::ChatMessageS2c; + pub mod chat_suggestions_s2c; + pub use chat_suggestions_s2c::ChatSuggestionsS2c; + pub mod chunk_biome_data_s2c; + pub use chunk_biome_data_s2c::ChunkBiomeDataS2c; + pub mod chunk_data_s2c; + pub use chunk_data_s2c::ChunkDataS2c; + pub mod chunk_delta_update_s2c; + pub use chunk_delta_update_s2c::ChunkDeltaUpdateS2c; + pub mod chunk_load_distance_s2c; + pub use chunk_load_distance_s2c::ChunkLoadDistanceS2c; + pub mod chunk_render_distance_center_s2c; + pub use chunk_render_distance_center_s2c::ChunkRenderDistanceCenterS2c; + pub mod clear_title_s2c; + pub use clear_title_s2c::ClearTitleS2c; + pub mod click_slot_c2s; + pub use click_slot_c2s::ClickSlotC2s; + pub mod client_command_c2s; + pub use client_command_c2s::ClientCommandC2s; + pub mod client_settings_c2s; + pub use client_settings_c2s::ClientSettingsC2s; + pub mod client_status_c2s; + pub use client_status_c2s::ClientStatusC2s; + pub mod close_handled_screen_c2s; + pub use close_handled_screen_c2s::CloseHandledScreenC2s; + pub mod close_screen_s2c; + pub use close_screen_s2c::CloseScreenS2c; + pub mod command_execution_c2s; + pub use command_execution_c2s::CommandExecutionC2s; + pub mod command_suggestions_s2c; + pub use command_suggestions_s2c::CommandSuggestionsS2c; + pub mod command_tree_s2c; + pub use command_tree_s2c::CommandTreeS2c; + pub mod cooldown_update_s2c; + pub use cooldown_update_s2c::CooldownUpdateS2c; + pub mod craft_failed_response_s2c; + pub use craft_failed_response_s2c::CraftFailedResponseS2c; + pub mod craft_request_c2s; + pub use craft_request_c2s::CraftRequestC2s; + pub mod creative_inventory_action_c2s; + pub use creative_inventory_action_c2s::CreativeInventoryActionC2s; + pub mod custom_payload_c2s; + pub use custom_payload_c2s::CustomPayloadC2s; + pub mod custom_payload_s2c; + pub use custom_payload_s2c::CustomPayloadS2c; + pub mod damage_tilt_s2c; + pub use damage_tilt_s2c::DamageTiltS2c; + pub mod death_message_s2c; + pub use death_message_s2c::DeathMessageS2c; + pub mod difficulty_s2c; + pub use difficulty_s2c::DifficultyS2c; + pub mod disconnect_s2c; + pub use disconnect_s2c::DisconnectS2c; + pub mod end_combat_s2c; + pub use end_combat_s2c::EndCombatS2c; + pub mod enter_combat_s2c; + pub use enter_combat_s2c::EnterCombatS2c; + pub mod entities_destroy_s2c; + pub use entities_destroy_s2c::EntitiesDestroyS2c; + pub mod entity_animation_s2c; + pub use entity_animation_s2c::EntityAnimationS2c; + pub mod entity_attach_s2c; + pub use entity_attach_s2c::EntityAttachS2c; + pub mod entity_attributes_s2c; + pub use entity_attributes_s2c::EntityAttributesS2c; + pub mod entity_damage_s2c; + pub use entity_damage_s2c::EntityDamageS2c; + pub mod entity_equipment_update_s2c; + pub use entity_equipment_update_s2c::EntityEquipmentUpdateS2c; + pub mod entity_passengers_set_s2c; + pub use entity_passengers_set_s2c::EntityPassengersSetS2c; + pub mod entity_position_s2c; + pub use entity_position_s2c::EntityPositionS2c; + pub mod entity_set_head_yaw_s2c; + pub use entity_set_head_yaw_s2c::EntitySetHeadYawS2c; + pub mod entity_spawn_s2c; + pub use entity_spawn_s2c::EntitySpawnS2c; + pub mod entity_status_effect_s2c; + pub use entity_status_effect_s2c::EntityStatusEffectS2c; + pub mod entity_status_s2c; + pub use entity_status_s2c::EntityStatusS2c; + pub mod entity_tracker_update_s2c; + pub use entity_tracker_update_s2c::EntityTrackerUpdateS2c; + pub mod entity_velocity_update_s2c; + pub use entity_velocity_update_s2c::EntityVelocityUpdateS2c; + pub mod experience_bar_update_s2c; + pub use experience_bar_update_s2c::ExperienceBarUpdateS2c; + pub mod experience_orb_spawn_s2c; + pub use experience_orb_spawn_s2c::ExperienceOrbSpawnS2c; + pub mod explosion_s2c; + pub use explosion_s2c::ExplosionS2c; + pub mod features_s2c; + pub use features_s2c::FeaturesS2c; + pub mod full_c2s; + pub use full_c2s::FullC2s; + pub mod game_join_s2c; + pub use game_join_s2c::GameJoinS2c; + pub mod game_message_s2c; + pub use game_message_s2c::GameMessageS2c; + pub mod game_state_change_s2c; + pub use game_state_change_s2c::GameStateChangeS2c; + pub mod hand_swing_c2s; + pub use hand_swing_c2s::HandSwingC2s; + pub mod health_update_s2c; + pub use health_update_s2c::HealthUpdateS2c; + pub mod inventory_s2c; + pub use inventory_s2c::InventoryS2c; + pub mod item_pickup_animation_s2c; + pub use item_pickup_animation_s2c::ItemPickupAnimationS2c; + pub mod jigsaw_generating_c2s; + pub use jigsaw_generating_c2s::JigsawGeneratingC2s; + pub mod keep_alive_c2s; + pub use keep_alive_c2s::KeepAliveC2s; + pub mod keep_alive_s2c; + pub use keep_alive_s2c::KeepAliveS2c; + pub mod light_update_s2c; + pub use light_update_s2c::LightUpdateS2c; + pub mod look_and_on_ground_c2s; + pub use look_and_on_ground_c2s::LookAndOnGroundC2s; + pub mod look_at_s2c; + pub use look_at_s2c::LookAtS2c; + pub mod map_update_s2c; + pub use map_update_s2c::MapUpdateS2c; + pub mod message_acknowledgment_c2s; + pub use message_acknowledgment_c2s::MessageAcknowledgmentC2s; + pub mod move_relative_s2c; + pub use move_relative_s2c::MoveRelativeS2c; + pub mod nbt_query_response_s2c; + pub use nbt_query_response_s2c::NbtQueryResponseS2c; + pub mod on_ground_only_c2s; + pub use on_ground_only_c2s::OnGroundOnlyC2s; + pub mod open_horse_screen_s2c; + pub use open_horse_screen_s2c::OpenHorseScreenS2c; + pub mod open_screen_s2c; + pub use open_screen_s2c::OpenScreenS2c; + pub mod open_written_book_s2c; + pub use open_written_book_s2c::OpenWrittenBookS2c; + pub mod overlay_message_s2c; + pub use overlay_message_s2c::OverlayMessageS2c; + pub mod particle_s2c; + pub use particle_s2c::ParticleS2c; + pub mod pick_from_inventory_c2s; + pub use pick_from_inventory_c2s::PickFromInventoryC2s; + pub mod play_ping_s2c; + pub use play_ping_s2c::PlayPingS2c; + pub mod play_pong_c2s; + pub use play_pong_c2s::PlayPongC2s; + pub mod play_sound_from_entity_s2c; + pub use play_sound_from_entity_s2c::PlaySoundFromEntityS2c; + pub mod play_sound_s2c; + pub use play_sound_s2c::PlaySoundS2c; + pub mod player_abilities_s2c; + pub use player_abilities_s2c::PlayerAbilitiesS2c; + pub mod player_action_c2s; + pub use player_action_c2s::PlayerActionC2s; + pub mod player_action_response_s2c; + pub use player_action_response_s2c::PlayerActionResponseS2c; + pub mod player_input_c2s; + pub use player_input_c2s::PlayerInputC2s; + pub mod player_interact_block_c2s; + pub use player_interact_block_c2s::PlayerInteractBlockC2s; + pub mod player_interact_entity_c2s; + pub use player_interact_entity_c2s::PlayerInteractEntityC2s; + pub mod player_interact_item_c2s; + pub use player_interact_item_c2s::PlayerInteractItemC2s; + pub mod player_list_header_s2c; + pub use player_list_header_s2c::PlayerListHeaderS2c; + pub mod player_list_s2c; + pub use player_list_s2c::PlayerListS2c; + pub mod player_position_look_s2c; + pub use player_position_look_s2c::PlayerPositionLookS2c; + pub mod player_remove_s2c; + pub use player_remove_s2c::PlayerRemoveS2c; + pub mod player_respawn_s2c; + pub use player_respawn_s2c::PlayerRespawnS2c; + pub mod player_session_c2s; + pub use player_session_c2s::PlayerSessionC2s; + pub mod player_spawn_position_s2c; + pub use player_spawn_position_s2c::PlayerSpawnPositionS2c; + pub mod player_spawn_s2c; + pub use player_spawn_s2c::PlayerSpawnS2c; + pub mod position_and_on_ground_c2s; + pub use position_and_on_ground_c2s::PositionAndOnGroundC2s; + pub mod profileless_chat_message_s2c; + pub use profileless_chat_message_s2c::ProfilelessChatMessageS2c; + pub mod query_block_nbt_c2s; + pub use query_block_nbt_c2s::QueryBlockNbtC2s; + pub mod query_entity_nbt_c2s; + pub use query_entity_nbt_c2s::QueryEntityNbtC2s; + pub mod recipe_book_data_c2s; + pub use recipe_book_data_c2s::RecipeBookDataC2s; + pub mod recipe_category_options_c2s; + pub use recipe_category_options_c2s::RecipeCategoryOptionsC2s; + pub mod remove_entity_status_effect_s2c; + pub use remove_entity_status_effect_s2c::RemoveEntityStatusEffectS2c; + pub mod remove_message_s2c; + pub use remove_message_s2c::RemoveMessageS2c; + pub mod rename_item_c2s; + pub use rename_item_c2s::RenameItemC2s; + pub mod request_command_completions_c2s; + pub use request_command_completions_c2s::RequestCommandCompletionsC2s; + pub mod resource_pack_send_s2c; + pub use resource_pack_send_s2c::ResourcePackSendS2c; + pub mod resource_pack_status_c2s; + pub use resource_pack_status_c2s::ResourcePackStatusC2s; + pub mod rotate_s2c; + pub use rotate_s2c::RotateS2c; + pub mod rotate_and_move_relative_s2c; + pub use rotate_and_move_relative_s2c::RotateAndMoveRelativeS2c; + pub mod scoreboard_display_s2c; + pub use scoreboard_display_s2c::ScoreboardDisplayS2c; + pub mod scoreboard_objective_update_s2c; + pub use scoreboard_objective_update_s2c::ScoreboardObjectiveUpdateS2c; + pub mod scoreboard_player_update_s2c; + pub use scoreboard_player_update_s2c::ScoreboardPlayerUpdateS2c; + pub mod screen_handler_property_update_s2c; + pub use screen_handler_property_update_s2c::ScreenHandlerPropertyUpdateS2c; + pub mod screen_handler_slot_update_s2c; + pub use screen_handler_slot_update_s2c::ScreenHandlerSlotUpdateS2c; + pub mod select_advancement_tab_s2c; + pub use select_advancement_tab_s2c::SelectAdvancementTabS2c; + pub mod select_merchant_trade_c2s; + pub use select_merchant_trade_c2s::SelectMerchantTradeC2s; + pub mod server_metadata_s2c; + pub use server_metadata_s2c::ServerMetadataS2c; + pub mod set_camera_entity_s2c; + pub use set_camera_entity_s2c::SetCameraEntityS2c; + pub mod set_trade_offers_s2c; + pub use set_trade_offers_s2c::SetTradeOffersS2c; + pub mod sign_editor_open_s2c; + pub use sign_editor_open_s2c::SignEditorOpenS2c; + pub mod simulation_distance_s2c; + pub use simulation_distance_s2c::SimulationDistanceS2c; + pub mod spectator_teleport_c2s; + pub use spectator_teleport_c2s::SpectatorTeleportC2s; + pub mod statistics_s2c; + pub use statistics_s2c::StatisticsS2c; + pub mod stop_sound_s2c; + pub use stop_sound_s2c::StopSoundS2c; + pub mod subtitle_s2c; + pub use subtitle_s2c::SubtitleS2c; + pub mod synchronize_recipes_s2c; + pub use synchronize_recipes_s2c::SynchronizeRecipesS2c; + pub mod synchronize_tags_s2c; + pub use synchronize_tags_s2c::SynchronizeTagsS2c; + pub mod team_s2c; + pub use team_s2c::TeamS2c; + pub mod teleport_confirm_c2s; + pub use teleport_confirm_c2s::TeleportConfirmC2s; + pub mod title_fade_s2c; + pub use title_fade_s2c::TitleFadeS2c; + pub mod title_s2c; + pub use title_s2c::TitleS2c; + pub mod unload_chunk_s2c; + pub use unload_chunk_s2c::UnloadChunkS2c; + pub mod unlock_recipes_s2c; + pub use unlock_recipes_s2c::UnlockRecipesS2c; + pub mod update_beacon_c2s; + pub use update_beacon_c2s::UpdateBeaconC2s; + pub mod update_command_block_c2s; + pub use update_command_block_c2s::UpdateCommandBlockC2s; + pub mod update_command_block_minecart_c2s; + pub use update_command_block_minecart_c2s::UpdateCommandBlockMinecartC2s; + pub mod update_difficulty_c2s; + pub use update_difficulty_c2s::UpdateDifficultyC2s; + pub mod update_difficulty_lock_c2s; + pub use update_difficulty_lock_c2s::UpdateDifficultyLockC2s; + pub mod update_jigsaw_c2s; + pub use update_jigsaw_c2s::UpdateJigsawC2s; + pub mod update_player_abilities_c2s; + pub use update_player_abilities_c2s::UpdatePlayerAbilitiesC2s; + pub mod update_selected_slot_c2s; + pub use update_selected_slot_c2s::UpdateSelectedSlotC2s; + pub mod update_selected_slot_s2c; + pub use update_selected_slot_s2c::UpdateSelectedSlotS2c; + pub mod update_sign_c2s; + pub use update_sign_c2s::UpdateSignC2s; + pub mod update_structure_block_c2s; + pub use update_structure_block_c2s::UpdateStructureBlockC2s; + pub mod vehicle_move_c2s; + pub use vehicle_move_c2s::VehicleMoveC2s; + pub mod vehicle_move_s2c; + pub use vehicle_move_s2c::VehicleMoveS2c; + pub mod world_border_center_changed_s2c; + pub use world_border_center_changed_s2c::WorldBorderCenterChangedS2c; + pub mod world_border_initialize_s2c; + pub use world_border_initialize_s2c::WorldBorderInitializeS2c; + pub mod world_border_interpolate_size_s2c; + pub use world_border_interpolate_size_s2c::WorldBorderInterpolateSizeS2c; + pub mod world_border_size_changed_s2c; + pub use world_border_size_changed_s2c::WorldBorderSizeChangedS2c; + pub mod world_border_warning_blocks_changed_s2c; + pub use world_border_warning_blocks_changed_s2c::WorldBorderWarningBlocksChangedS2c; + pub mod world_border_warning_time_changed_s2c; + pub use world_border_warning_time_changed_s2c::WorldBorderWarningTimeChangedS2c; + pub mod world_event_s2c; + pub use world_event_s2c::WorldEventS2c; + pub mod world_time_update_s2c; + pub use world_time_update_s2c::WorldTimeUpdateS2c; +} + +pub mod status { + pub mod query_ping_c2s; + pub use query_ping_c2s::QueryPingC2s; + pub mod query_pong_s2c; + pub use query_pong_s2c::QueryPongS2c; + pub mod query_request_c2s; + pub use query_request_c2s::QueryRequestC2s; + pub mod query_response_s2c; + pub use query_response_s2c::QueryResponseS2c; +} diff --git a/crates/valence_protocol/src/packets/handshaking/handshake_c2s.rs b/old/crates/valence_protocol/src/packets/handshaking/handshake_c2s.rs similarity index 100% rename from crates/valence_protocol/src/packets/handshaking/handshake_c2s.rs rename to old/crates/valence_protocol/src/packets/handshaking/handshake_c2s.rs diff --git a/crates/valence_protocol/src/packets/login/login_compression_s2c.rs b/old/crates/valence_protocol/src/packets/login/login_compression_s2c.rs similarity index 100% rename from crates/valence_protocol/src/packets/login/login_compression_s2c.rs rename to old/crates/valence_protocol/src/packets/login/login_compression_s2c.rs diff --git a/crates/valence_protocol/src/packets/login/login_disconnect_s2c.rs b/old/crates/valence_protocol/src/packets/login/login_disconnect_s2c.rs similarity index 100% rename from crates/valence_protocol/src/packets/login/login_disconnect_s2c.rs rename to old/crates/valence_protocol/src/packets/login/login_disconnect_s2c.rs diff --git a/crates/valence_protocol/src/packets/login/login_hello_c2s.rs b/old/crates/valence_protocol/src/packets/login/login_hello_c2s.rs similarity index 100% rename from crates/valence_protocol/src/packets/login/login_hello_c2s.rs rename to old/crates/valence_protocol/src/packets/login/login_hello_c2s.rs diff --git a/crates/valence_protocol/src/packets/login/login_hello_s2c.rs b/old/crates/valence_protocol/src/packets/login/login_hello_s2c.rs similarity index 100% rename from crates/valence_protocol/src/packets/login/login_hello_s2c.rs rename to old/crates/valence_protocol/src/packets/login/login_hello_s2c.rs diff --git a/crates/valence_protocol/src/packets/login/login_key_c2s.rs b/old/crates/valence_protocol/src/packets/login/login_key_c2s.rs similarity index 100% rename from crates/valence_protocol/src/packets/login/login_key_c2s.rs rename to old/crates/valence_protocol/src/packets/login/login_key_c2s.rs diff --git a/crates/valence_protocol/src/packets/login/login_query_request_s2c.rs b/old/crates/valence_protocol/src/packets/login/login_query_request_s2c.rs similarity index 100% rename from crates/valence_protocol/src/packets/login/login_query_request_s2c.rs rename to old/crates/valence_protocol/src/packets/login/login_query_request_s2c.rs diff --git a/crates/valence_protocol/src/packets/login/login_query_response_c2s.rs b/old/crates/valence_protocol/src/packets/login/login_query_response_c2s.rs similarity index 100% rename from crates/valence_protocol/src/packets/login/login_query_response_c2s.rs rename to old/crates/valence_protocol/src/packets/login/login_query_response_c2s.rs diff --git a/crates/valence_protocol/src/packets/login/login_success_s2c.rs b/old/crates/valence_protocol/src/packets/login/login_success_s2c.rs similarity index 100% rename from crates/valence_protocol/src/packets/login/login_success_s2c.rs rename to old/crates/valence_protocol/src/packets/login/login_success_s2c.rs diff --git a/crates/valence_protocol/src/packets/play/advancement_tab_c2s.rs b/old/crates/valence_protocol/src/packets/play/advancement_tab_c2s.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/advancement_tab_c2s.rs rename to old/crates/valence_protocol/src/packets/play/advancement_tab_c2s.rs diff --git a/crates/valence_protocol/src/packets/play/advancement_update_s2c.rs b/old/crates/valence_protocol/src/packets/play/advancement_update_s2c.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/advancement_update_s2c.rs rename to old/crates/valence_protocol/src/packets/play/advancement_update_s2c.rs diff --git a/crates/valence_protocol/src/packets/play/block_breaking_progress_s2c.rs b/old/crates/valence_protocol/src/packets/play/block_breaking_progress_s2c.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/block_breaking_progress_s2c.rs rename to old/crates/valence_protocol/src/packets/play/block_breaking_progress_s2c.rs diff --git a/crates/valence_protocol/src/packets/play/block_entity_update_s2c.rs b/old/crates/valence_protocol/src/packets/play/block_entity_update_s2c.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/block_entity_update_s2c.rs rename to old/crates/valence_protocol/src/packets/play/block_entity_update_s2c.rs diff --git a/crates/valence_protocol/src/packets/play/block_event_s2c.rs b/old/crates/valence_protocol/src/packets/play/block_event_s2c.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/block_event_s2c.rs rename to old/crates/valence_protocol/src/packets/play/block_event_s2c.rs diff --git a/crates/valence_protocol/src/packets/play/block_update_s2c.rs b/old/crates/valence_protocol/src/packets/play/block_update_s2c.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/block_update_s2c.rs rename to old/crates/valence_protocol/src/packets/play/block_update_s2c.rs diff --git a/crates/valence_protocol/src/packets/play/boat_paddle_state_c2s.rs b/old/crates/valence_protocol/src/packets/play/boat_paddle_state_c2s.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/boat_paddle_state_c2s.rs rename to old/crates/valence_protocol/src/packets/play/boat_paddle_state_c2s.rs diff --git a/crates/valence_protocol/src/packets/play/book_update_c2s.rs b/old/crates/valence_protocol/src/packets/play/book_update_c2s.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/book_update_c2s.rs rename to old/crates/valence_protocol/src/packets/play/book_update_c2s.rs diff --git a/crates/valence_protocol/src/packets/play/boss_bar_s2c.rs b/old/crates/valence_protocol/src/packets/play/boss_bar_s2c.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/boss_bar_s2c.rs rename to old/crates/valence_protocol/src/packets/play/boss_bar_s2c.rs diff --git a/crates/valence_protocol/src/packets/play/bundle_splitter_s2c.rs b/old/crates/valence_protocol/src/packets/play/bundle_splitter_s2c.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/bundle_splitter_s2c.rs rename to old/crates/valence_protocol/src/packets/play/bundle_splitter_s2c.rs diff --git a/crates/valence_protocol/src/packets/play/button_click_c2s.rs b/old/crates/valence_protocol/src/packets/play/button_click_c2s.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/button_click_c2s.rs rename to old/crates/valence_protocol/src/packets/play/button_click_c2s.rs diff --git a/crates/valence_protocol/src/packets/play/chat_message_c2s.rs b/old/crates/valence_protocol/src/packets/play/chat_message_c2s.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/chat_message_c2s.rs rename to old/crates/valence_protocol/src/packets/play/chat_message_c2s.rs diff --git a/crates/valence_protocol/src/packets/play/chat_message_s2c.rs b/old/crates/valence_protocol/src/packets/play/chat_message_s2c.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/chat_message_s2c.rs rename to old/crates/valence_protocol/src/packets/play/chat_message_s2c.rs diff --git a/crates/valence_protocol/src/packets/play/chat_suggestions_s2c.rs b/old/crates/valence_protocol/src/packets/play/chat_suggestions_s2c.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/chat_suggestions_s2c.rs rename to old/crates/valence_protocol/src/packets/play/chat_suggestions_s2c.rs diff --git a/crates/valence_protocol/src/packets/play/chunk_biome_data_s2c.rs b/old/crates/valence_protocol/src/packets/play/chunk_biome_data_s2c.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/chunk_biome_data_s2c.rs rename to old/crates/valence_protocol/src/packets/play/chunk_biome_data_s2c.rs diff --git a/crates/valence_protocol/src/packets/play/chunk_data_s2c.rs b/old/crates/valence_protocol/src/packets/play/chunk_data_s2c.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/chunk_data_s2c.rs rename to old/crates/valence_protocol/src/packets/play/chunk_data_s2c.rs diff --git a/crates/valence_protocol/src/packets/play/chunk_delta_update_s2c.rs b/old/crates/valence_protocol/src/packets/play/chunk_delta_update_s2c.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/chunk_delta_update_s2c.rs rename to old/crates/valence_protocol/src/packets/play/chunk_delta_update_s2c.rs diff --git a/crates/valence_protocol/src/packets/play/chunk_load_distance_s2c.rs b/old/crates/valence_protocol/src/packets/play/chunk_load_distance_s2c.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/chunk_load_distance_s2c.rs rename to old/crates/valence_protocol/src/packets/play/chunk_load_distance_s2c.rs diff --git a/crates/valence_protocol/src/packets/play/chunk_render_distance_center_s2c.rs b/old/crates/valence_protocol/src/packets/play/chunk_render_distance_center_s2c.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/chunk_render_distance_center_s2c.rs rename to old/crates/valence_protocol/src/packets/play/chunk_render_distance_center_s2c.rs diff --git a/crates/valence_protocol/src/packets/play/clear_title_s2c.rs b/old/crates/valence_protocol/src/packets/play/clear_title_s2c.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/clear_title_s2c.rs rename to old/crates/valence_protocol/src/packets/play/clear_title_s2c.rs diff --git a/crates/valence_protocol/src/packets/play/click_slot_c2s.rs b/old/crates/valence_protocol/src/packets/play/click_slot_c2s.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/click_slot_c2s.rs rename to old/crates/valence_protocol/src/packets/play/click_slot_c2s.rs diff --git a/crates/valence_protocol/src/packets/play/client_command_c2s.rs b/old/crates/valence_protocol/src/packets/play/client_command_c2s.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/client_command_c2s.rs rename to old/crates/valence_protocol/src/packets/play/client_command_c2s.rs diff --git a/crates/valence_protocol/src/packets/play/client_settings_c2s.rs b/old/crates/valence_protocol/src/packets/play/client_settings_c2s.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/client_settings_c2s.rs rename to old/crates/valence_protocol/src/packets/play/client_settings_c2s.rs diff --git a/crates/valence_protocol/src/packets/play/client_status_c2s.rs b/old/crates/valence_protocol/src/packets/play/client_status_c2s.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/client_status_c2s.rs rename to old/crates/valence_protocol/src/packets/play/client_status_c2s.rs diff --git a/crates/valence_protocol/src/packets/play/close_handled_screen_c2s.rs b/old/crates/valence_protocol/src/packets/play/close_handled_screen_c2s.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/close_handled_screen_c2s.rs rename to old/crates/valence_protocol/src/packets/play/close_handled_screen_c2s.rs diff --git a/crates/valence_protocol/src/packets/play/close_screen_s2c.rs b/old/crates/valence_protocol/src/packets/play/close_screen_s2c.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/close_screen_s2c.rs rename to old/crates/valence_protocol/src/packets/play/close_screen_s2c.rs diff --git a/crates/valence_protocol/src/packets/play/command_execution_c2s.rs b/old/crates/valence_protocol/src/packets/play/command_execution_c2s.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/command_execution_c2s.rs rename to old/crates/valence_protocol/src/packets/play/command_execution_c2s.rs diff --git a/crates/valence_protocol/src/packets/play/command_suggestions_s2c.rs b/old/crates/valence_protocol/src/packets/play/command_suggestions_s2c.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/command_suggestions_s2c.rs rename to old/crates/valence_protocol/src/packets/play/command_suggestions_s2c.rs diff --git a/crates/valence_protocol/src/packets/play/command_tree_s2c.rs b/old/crates/valence_protocol/src/packets/play/command_tree_s2c.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/command_tree_s2c.rs rename to old/crates/valence_protocol/src/packets/play/command_tree_s2c.rs diff --git a/crates/valence_protocol/src/packets/play/cooldown_update_s2c.rs b/old/crates/valence_protocol/src/packets/play/cooldown_update_s2c.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/cooldown_update_s2c.rs rename to old/crates/valence_protocol/src/packets/play/cooldown_update_s2c.rs diff --git a/crates/valence_protocol/src/packets/play/craft_failed_response_s2c.rs b/old/crates/valence_protocol/src/packets/play/craft_failed_response_s2c.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/craft_failed_response_s2c.rs rename to old/crates/valence_protocol/src/packets/play/craft_failed_response_s2c.rs diff --git a/crates/valence_protocol/src/packets/play/craft_request_c2s.rs b/old/crates/valence_protocol/src/packets/play/craft_request_c2s.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/craft_request_c2s.rs rename to old/crates/valence_protocol/src/packets/play/craft_request_c2s.rs diff --git a/crates/valence_protocol/src/packets/play/creative_inventory_action_c2s.rs b/old/crates/valence_protocol/src/packets/play/creative_inventory_action_c2s.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/creative_inventory_action_c2s.rs rename to old/crates/valence_protocol/src/packets/play/creative_inventory_action_c2s.rs diff --git a/crates/valence_protocol/src/packets/play/custom_payload_c2s.rs b/old/crates/valence_protocol/src/packets/play/custom_payload_c2s.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/custom_payload_c2s.rs rename to old/crates/valence_protocol/src/packets/play/custom_payload_c2s.rs diff --git a/crates/valence_protocol/src/packets/play/custom_payload_s2c.rs b/old/crates/valence_protocol/src/packets/play/custom_payload_s2c.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/custom_payload_s2c.rs rename to old/crates/valence_protocol/src/packets/play/custom_payload_s2c.rs diff --git a/crates/valence_protocol/src/packets/play/damage_tilt_s2c.rs b/old/crates/valence_protocol/src/packets/play/damage_tilt_s2c.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/damage_tilt_s2c.rs rename to old/crates/valence_protocol/src/packets/play/damage_tilt_s2c.rs diff --git a/crates/valence_protocol/src/packets/play/death_message_s2c.rs b/old/crates/valence_protocol/src/packets/play/death_message_s2c.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/death_message_s2c.rs rename to old/crates/valence_protocol/src/packets/play/death_message_s2c.rs diff --git a/crates/valence_protocol/src/packets/play/difficulty_s2c.rs b/old/crates/valence_protocol/src/packets/play/difficulty_s2c.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/difficulty_s2c.rs rename to old/crates/valence_protocol/src/packets/play/difficulty_s2c.rs diff --git a/crates/valence_protocol/src/packets/play/disconnect_s2c.rs b/old/crates/valence_protocol/src/packets/play/disconnect_s2c.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/disconnect_s2c.rs rename to old/crates/valence_protocol/src/packets/play/disconnect_s2c.rs diff --git a/crates/valence_protocol/src/packets/play/end_combat_s2c.rs b/old/crates/valence_protocol/src/packets/play/end_combat_s2c.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/end_combat_s2c.rs rename to old/crates/valence_protocol/src/packets/play/end_combat_s2c.rs diff --git a/crates/valence_protocol/src/packets/play/enter_combat_s2c.rs b/old/crates/valence_protocol/src/packets/play/enter_combat_s2c.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/enter_combat_s2c.rs rename to old/crates/valence_protocol/src/packets/play/enter_combat_s2c.rs diff --git a/crates/valence_protocol/src/packets/play/entities_destroy_s2c.rs b/old/crates/valence_protocol/src/packets/play/entities_destroy_s2c.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/entities_destroy_s2c.rs rename to old/crates/valence_protocol/src/packets/play/entities_destroy_s2c.rs diff --git a/crates/valence_protocol/src/packets/play/entity_animation_s2c.rs b/old/crates/valence_protocol/src/packets/play/entity_animation_s2c.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/entity_animation_s2c.rs rename to old/crates/valence_protocol/src/packets/play/entity_animation_s2c.rs diff --git a/crates/valence_protocol/src/packets/play/entity_attach_s2c.rs b/old/crates/valence_protocol/src/packets/play/entity_attach_s2c.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/entity_attach_s2c.rs rename to old/crates/valence_protocol/src/packets/play/entity_attach_s2c.rs diff --git a/crates/valence_protocol/src/packets/play/entity_attributes_s2c.rs b/old/crates/valence_protocol/src/packets/play/entity_attributes_s2c.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/entity_attributes_s2c.rs rename to old/crates/valence_protocol/src/packets/play/entity_attributes_s2c.rs diff --git a/crates/valence_protocol/src/packets/play/entity_damage_s2c.rs b/old/crates/valence_protocol/src/packets/play/entity_damage_s2c.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/entity_damage_s2c.rs rename to old/crates/valence_protocol/src/packets/play/entity_damage_s2c.rs diff --git a/crates/valence_protocol/src/packets/play/entity_equipment_update_s2c.rs b/old/crates/valence_protocol/src/packets/play/entity_equipment_update_s2c.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/entity_equipment_update_s2c.rs rename to old/crates/valence_protocol/src/packets/play/entity_equipment_update_s2c.rs diff --git a/crates/valence_protocol/src/packets/play/entity_passengers_set_s2c.rs b/old/crates/valence_protocol/src/packets/play/entity_passengers_set_s2c.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/entity_passengers_set_s2c.rs rename to old/crates/valence_protocol/src/packets/play/entity_passengers_set_s2c.rs diff --git a/crates/valence_protocol/src/packets/play/entity_position_s2c.rs b/old/crates/valence_protocol/src/packets/play/entity_position_s2c.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/entity_position_s2c.rs rename to old/crates/valence_protocol/src/packets/play/entity_position_s2c.rs diff --git a/crates/valence_protocol/src/packets/play/entity_set_head_yaw_s2c.rs b/old/crates/valence_protocol/src/packets/play/entity_set_head_yaw_s2c.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/entity_set_head_yaw_s2c.rs rename to old/crates/valence_protocol/src/packets/play/entity_set_head_yaw_s2c.rs diff --git a/crates/valence_protocol/src/packets/play/entity_spawn_s2c.rs b/old/crates/valence_protocol/src/packets/play/entity_spawn_s2c.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/entity_spawn_s2c.rs rename to old/crates/valence_protocol/src/packets/play/entity_spawn_s2c.rs diff --git a/crates/valence_protocol/src/packets/play/entity_status_effect_s2c.rs b/old/crates/valence_protocol/src/packets/play/entity_status_effect_s2c.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/entity_status_effect_s2c.rs rename to old/crates/valence_protocol/src/packets/play/entity_status_effect_s2c.rs diff --git a/crates/valence_protocol/src/packets/play/entity_status_s2c.rs b/old/crates/valence_protocol/src/packets/play/entity_status_s2c.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/entity_status_s2c.rs rename to old/crates/valence_protocol/src/packets/play/entity_status_s2c.rs diff --git a/crates/valence_protocol/src/packets/play/entity_tracker_update_s2c.rs b/old/crates/valence_protocol/src/packets/play/entity_tracker_update_s2c.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/entity_tracker_update_s2c.rs rename to old/crates/valence_protocol/src/packets/play/entity_tracker_update_s2c.rs diff --git a/crates/valence_protocol/src/packets/play/entity_velocity_update_s2c.rs b/old/crates/valence_protocol/src/packets/play/entity_velocity_update_s2c.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/entity_velocity_update_s2c.rs rename to old/crates/valence_protocol/src/packets/play/entity_velocity_update_s2c.rs diff --git a/crates/valence_protocol/src/packets/play/experience_bar_update_s2c.rs b/old/crates/valence_protocol/src/packets/play/experience_bar_update_s2c.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/experience_bar_update_s2c.rs rename to old/crates/valence_protocol/src/packets/play/experience_bar_update_s2c.rs diff --git a/crates/valence_protocol/src/packets/play/experience_orb_spawn_s2c.rs b/old/crates/valence_protocol/src/packets/play/experience_orb_spawn_s2c.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/experience_orb_spawn_s2c.rs rename to old/crates/valence_protocol/src/packets/play/experience_orb_spawn_s2c.rs diff --git a/crates/valence_protocol/src/packets/play/explosion_s2c.rs b/old/crates/valence_protocol/src/packets/play/explosion_s2c.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/explosion_s2c.rs rename to old/crates/valence_protocol/src/packets/play/explosion_s2c.rs diff --git a/crates/valence_protocol/src/packets/play/features_s2c.rs b/old/crates/valence_protocol/src/packets/play/features_s2c.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/features_s2c.rs rename to old/crates/valence_protocol/src/packets/play/features_s2c.rs diff --git a/crates/valence_protocol/src/packets/play/full_c2s.rs b/old/crates/valence_protocol/src/packets/play/full_c2s.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/full_c2s.rs rename to old/crates/valence_protocol/src/packets/play/full_c2s.rs diff --git a/crates/valence_protocol/src/packets/play/game_join_s2c.rs b/old/crates/valence_protocol/src/packets/play/game_join_s2c.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/game_join_s2c.rs rename to old/crates/valence_protocol/src/packets/play/game_join_s2c.rs diff --git a/crates/valence_protocol/src/packets/play/game_message_s2c.rs b/old/crates/valence_protocol/src/packets/play/game_message_s2c.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/game_message_s2c.rs rename to old/crates/valence_protocol/src/packets/play/game_message_s2c.rs diff --git a/crates/valence_protocol/src/packets/play/game_state_change_s2c.rs b/old/crates/valence_protocol/src/packets/play/game_state_change_s2c.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/game_state_change_s2c.rs rename to old/crates/valence_protocol/src/packets/play/game_state_change_s2c.rs diff --git a/crates/valence_protocol/src/packets/play/hand_swing_c2s.rs b/old/crates/valence_protocol/src/packets/play/hand_swing_c2s.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/hand_swing_c2s.rs rename to old/crates/valence_protocol/src/packets/play/hand_swing_c2s.rs diff --git a/crates/valence_protocol/src/packets/play/health_update_s2c.rs b/old/crates/valence_protocol/src/packets/play/health_update_s2c.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/health_update_s2c.rs rename to old/crates/valence_protocol/src/packets/play/health_update_s2c.rs diff --git a/crates/valence_protocol/src/packets/play/inventory_s2c.rs b/old/crates/valence_protocol/src/packets/play/inventory_s2c.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/inventory_s2c.rs rename to old/crates/valence_protocol/src/packets/play/inventory_s2c.rs diff --git a/crates/valence_protocol/src/packets/play/item_pickup_animation_s2c.rs b/old/crates/valence_protocol/src/packets/play/item_pickup_animation_s2c.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/item_pickup_animation_s2c.rs rename to old/crates/valence_protocol/src/packets/play/item_pickup_animation_s2c.rs diff --git a/crates/valence_protocol/src/packets/play/jigsaw_generating_c2s.rs b/old/crates/valence_protocol/src/packets/play/jigsaw_generating_c2s.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/jigsaw_generating_c2s.rs rename to old/crates/valence_protocol/src/packets/play/jigsaw_generating_c2s.rs diff --git a/crates/valence_protocol/src/packets/play/keep_alive_c2s.rs b/old/crates/valence_protocol/src/packets/play/keep_alive_c2s.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/keep_alive_c2s.rs rename to old/crates/valence_protocol/src/packets/play/keep_alive_c2s.rs diff --git a/crates/valence_protocol/src/packets/play/keep_alive_s2c.rs b/old/crates/valence_protocol/src/packets/play/keep_alive_s2c.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/keep_alive_s2c.rs rename to old/crates/valence_protocol/src/packets/play/keep_alive_s2c.rs diff --git a/crates/valence_protocol/src/packets/play/light_update_s2c.rs b/old/crates/valence_protocol/src/packets/play/light_update_s2c.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/light_update_s2c.rs rename to old/crates/valence_protocol/src/packets/play/light_update_s2c.rs diff --git a/crates/valence_protocol/src/packets/play/look_and_on_ground_c2s.rs b/old/crates/valence_protocol/src/packets/play/look_and_on_ground_c2s.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/look_and_on_ground_c2s.rs rename to old/crates/valence_protocol/src/packets/play/look_and_on_ground_c2s.rs diff --git a/crates/valence_protocol/src/packets/play/look_at_s2c.rs b/old/crates/valence_protocol/src/packets/play/look_at_s2c.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/look_at_s2c.rs rename to old/crates/valence_protocol/src/packets/play/look_at_s2c.rs diff --git a/crates/valence_protocol/src/packets/play/map_update_s2c.rs b/old/crates/valence_protocol/src/packets/play/map_update_s2c.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/map_update_s2c.rs rename to old/crates/valence_protocol/src/packets/play/map_update_s2c.rs diff --git a/crates/valence_protocol/src/packets/play/message_acknowledgment_c2s.rs b/old/crates/valence_protocol/src/packets/play/message_acknowledgment_c2s.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/message_acknowledgment_c2s.rs rename to old/crates/valence_protocol/src/packets/play/message_acknowledgment_c2s.rs diff --git a/crates/valence_protocol/src/packets/play/move_relative_s2c.rs b/old/crates/valence_protocol/src/packets/play/move_relative_s2c.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/move_relative_s2c.rs rename to old/crates/valence_protocol/src/packets/play/move_relative_s2c.rs diff --git a/crates/valence_protocol/src/packets/play/nbt_query_response_s2c.rs b/old/crates/valence_protocol/src/packets/play/nbt_query_response_s2c.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/nbt_query_response_s2c.rs rename to old/crates/valence_protocol/src/packets/play/nbt_query_response_s2c.rs diff --git a/crates/valence_protocol/src/packets/play/on_ground_only_c2s.rs b/old/crates/valence_protocol/src/packets/play/on_ground_only_c2s.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/on_ground_only_c2s.rs rename to old/crates/valence_protocol/src/packets/play/on_ground_only_c2s.rs diff --git a/crates/valence_protocol/src/packets/play/open_horse_screen_s2c.rs b/old/crates/valence_protocol/src/packets/play/open_horse_screen_s2c.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/open_horse_screen_s2c.rs rename to old/crates/valence_protocol/src/packets/play/open_horse_screen_s2c.rs diff --git a/crates/valence_protocol/src/packets/play/open_screen_s2c.rs b/old/crates/valence_protocol/src/packets/play/open_screen_s2c.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/open_screen_s2c.rs rename to old/crates/valence_protocol/src/packets/play/open_screen_s2c.rs diff --git a/crates/valence_protocol/src/packets/play/open_written_book_s2c.rs b/old/crates/valence_protocol/src/packets/play/open_written_book_s2c.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/open_written_book_s2c.rs rename to old/crates/valence_protocol/src/packets/play/open_written_book_s2c.rs diff --git a/crates/valence_protocol/src/packets/play/overlay_message_s2c.rs b/old/crates/valence_protocol/src/packets/play/overlay_message_s2c.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/overlay_message_s2c.rs rename to old/crates/valence_protocol/src/packets/play/overlay_message_s2c.rs diff --git a/crates/valence_protocol/src/packets/play/particle_s2c.rs b/old/crates/valence_protocol/src/packets/play/particle_s2c.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/particle_s2c.rs rename to old/crates/valence_protocol/src/packets/play/particle_s2c.rs diff --git a/crates/valence_protocol/src/packets/play/pick_from_inventory_c2s.rs b/old/crates/valence_protocol/src/packets/play/pick_from_inventory_c2s.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/pick_from_inventory_c2s.rs rename to old/crates/valence_protocol/src/packets/play/pick_from_inventory_c2s.rs diff --git a/crates/valence_protocol/src/packets/play/play_ping_s2c.rs b/old/crates/valence_protocol/src/packets/play/play_ping_s2c.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/play_ping_s2c.rs rename to old/crates/valence_protocol/src/packets/play/play_ping_s2c.rs diff --git a/crates/valence_protocol/src/packets/play/play_pong_c2s.rs b/old/crates/valence_protocol/src/packets/play/play_pong_c2s.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/play_pong_c2s.rs rename to old/crates/valence_protocol/src/packets/play/play_pong_c2s.rs diff --git a/crates/valence_protocol/src/packets/play/play_sound_from_entity_s2c.rs b/old/crates/valence_protocol/src/packets/play/play_sound_from_entity_s2c.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/play_sound_from_entity_s2c.rs rename to old/crates/valence_protocol/src/packets/play/play_sound_from_entity_s2c.rs diff --git a/crates/valence_protocol/src/packets/play/play_sound_s2c.rs b/old/crates/valence_protocol/src/packets/play/play_sound_s2c.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/play_sound_s2c.rs rename to old/crates/valence_protocol/src/packets/play/play_sound_s2c.rs diff --git a/crates/valence_protocol/src/packets/play/player_abilities_s2c.rs b/old/crates/valence_protocol/src/packets/play/player_abilities_s2c.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/player_abilities_s2c.rs rename to old/crates/valence_protocol/src/packets/play/player_abilities_s2c.rs diff --git a/crates/valence_protocol/src/packets/play/player_action_c2s.rs b/old/crates/valence_protocol/src/packets/play/player_action_c2s.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/player_action_c2s.rs rename to old/crates/valence_protocol/src/packets/play/player_action_c2s.rs diff --git a/crates/valence_protocol/src/packets/play/player_action_response_s2c.rs b/old/crates/valence_protocol/src/packets/play/player_action_response_s2c.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/player_action_response_s2c.rs rename to old/crates/valence_protocol/src/packets/play/player_action_response_s2c.rs diff --git a/crates/valence_protocol/src/packets/play/player_input_c2s.rs b/old/crates/valence_protocol/src/packets/play/player_input_c2s.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/player_input_c2s.rs rename to old/crates/valence_protocol/src/packets/play/player_input_c2s.rs diff --git a/crates/valence_protocol/src/packets/play/player_interact_block_c2s.rs b/old/crates/valence_protocol/src/packets/play/player_interact_block_c2s.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/player_interact_block_c2s.rs rename to old/crates/valence_protocol/src/packets/play/player_interact_block_c2s.rs diff --git a/crates/valence_protocol/src/packets/play/player_interact_entity_c2s.rs b/old/crates/valence_protocol/src/packets/play/player_interact_entity_c2s.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/player_interact_entity_c2s.rs rename to old/crates/valence_protocol/src/packets/play/player_interact_entity_c2s.rs diff --git a/crates/valence_protocol/src/packets/play/player_interact_item_c2s.rs b/old/crates/valence_protocol/src/packets/play/player_interact_item_c2s.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/player_interact_item_c2s.rs rename to old/crates/valence_protocol/src/packets/play/player_interact_item_c2s.rs diff --git a/crates/valence_protocol/src/packets/play/player_list_header_s2c.rs b/old/crates/valence_protocol/src/packets/play/player_list_header_s2c.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/player_list_header_s2c.rs rename to old/crates/valence_protocol/src/packets/play/player_list_header_s2c.rs diff --git a/crates/valence_protocol/src/packets/play/player_list_s2c.rs b/old/crates/valence_protocol/src/packets/play/player_list_s2c.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/player_list_s2c.rs rename to old/crates/valence_protocol/src/packets/play/player_list_s2c.rs diff --git a/crates/valence_protocol/src/packets/play/player_position_look_s2c.rs b/old/crates/valence_protocol/src/packets/play/player_position_look_s2c.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/player_position_look_s2c.rs rename to old/crates/valence_protocol/src/packets/play/player_position_look_s2c.rs diff --git a/crates/valence_protocol/src/packets/play/player_remove_s2c.rs b/old/crates/valence_protocol/src/packets/play/player_remove_s2c.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/player_remove_s2c.rs rename to old/crates/valence_protocol/src/packets/play/player_remove_s2c.rs diff --git a/crates/valence_protocol/src/packets/play/player_respawn_s2c.rs b/old/crates/valence_protocol/src/packets/play/player_respawn_s2c.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/player_respawn_s2c.rs rename to old/crates/valence_protocol/src/packets/play/player_respawn_s2c.rs diff --git a/crates/valence_protocol/src/packets/play/player_session_c2s.rs b/old/crates/valence_protocol/src/packets/play/player_session_c2s.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/player_session_c2s.rs rename to old/crates/valence_protocol/src/packets/play/player_session_c2s.rs diff --git a/crates/valence_protocol/src/packets/play/player_spawn_position_s2c.rs b/old/crates/valence_protocol/src/packets/play/player_spawn_position_s2c.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/player_spawn_position_s2c.rs rename to old/crates/valence_protocol/src/packets/play/player_spawn_position_s2c.rs diff --git a/crates/valence_protocol/src/packets/play/player_spawn_s2c.rs b/old/crates/valence_protocol/src/packets/play/player_spawn_s2c.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/player_spawn_s2c.rs rename to old/crates/valence_protocol/src/packets/play/player_spawn_s2c.rs diff --git a/crates/valence_protocol/src/packets/play/position_and_on_ground_c2s.rs b/old/crates/valence_protocol/src/packets/play/position_and_on_ground_c2s.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/position_and_on_ground_c2s.rs rename to old/crates/valence_protocol/src/packets/play/position_and_on_ground_c2s.rs diff --git a/crates/valence_protocol/src/packets/play/profileless_chat_message_s2c.rs b/old/crates/valence_protocol/src/packets/play/profileless_chat_message_s2c.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/profileless_chat_message_s2c.rs rename to old/crates/valence_protocol/src/packets/play/profileless_chat_message_s2c.rs diff --git a/crates/valence_protocol/src/packets/play/query_block_nbt_c2s.rs b/old/crates/valence_protocol/src/packets/play/query_block_nbt_c2s.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/query_block_nbt_c2s.rs rename to old/crates/valence_protocol/src/packets/play/query_block_nbt_c2s.rs diff --git a/crates/valence_protocol/src/packets/play/query_entity_nbt_c2s.rs b/old/crates/valence_protocol/src/packets/play/query_entity_nbt_c2s.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/query_entity_nbt_c2s.rs rename to old/crates/valence_protocol/src/packets/play/query_entity_nbt_c2s.rs diff --git a/crates/valence_protocol/src/packets/play/recipe_book_data_c2s.rs b/old/crates/valence_protocol/src/packets/play/recipe_book_data_c2s.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/recipe_book_data_c2s.rs rename to old/crates/valence_protocol/src/packets/play/recipe_book_data_c2s.rs diff --git a/crates/valence_protocol/src/packets/play/recipe_category_options_c2s.rs b/old/crates/valence_protocol/src/packets/play/recipe_category_options_c2s.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/recipe_category_options_c2s.rs rename to old/crates/valence_protocol/src/packets/play/recipe_category_options_c2s.rs diff --git a/crates/valence_protocol/src/packets/play/remove_entity_status_effect_s2c.rs b/old/crates/valence_protocol/src/packets/play/remove_entity_status_effect_s2c.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/remove_entity_status_effect_s2c.rs rename to old/crates/valence_protocol/src/packets/play/remove_entity_status_effect_s2c.rs diff --git a/crates/valence_protocol/src/packets/play/remove_message_s2c.rs b/old/crates/valence_protocol/src/packets/play/remove_message_s2c.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/remove_message_s2c.rs rename to old/crates/valence_protocol/src/packets/play/remove_message_s2c.rs diff --git a/crates/valence_protocol/src/packets/play/rename_item_c2s.rs b/old/crates/valence_protocol/src/packets/play/rename_item_c2s.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/rename_item_c2s.rs rename to old/crates/valence_protocol/src/packets/play/rename_item_c2s.rs diff --git a/crates/valence_protocol/src/packets/play/request_command_completions_c2s.rs b/old/crates/valence_protocol/src/packets/play/request_command_completions_c2s.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/request_command_completions_c2s.rs rename to old/crates/valence_protocol/src/packets/play/request_command_completions_c2s.rs diff --git a/crates/valence_protocol/src/packets/play/resource_pack_send_s2c.rs b/old/crates/valence_protocol/src/packets/play/resource_pack_send_s2c.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/resource_pack_send_s2c.rs rename to old/crates/valence_protocol/src/packets/play/resource_pack_send_s2c.rs diff --git a/crates/valence_protocol/src/packets/play/resource_pack_status_c2s.rs b/old/crates/valence_protocol/src/packets/play/resource_pack_status_c2s.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/resource_pack_status_c2s.rs rename to old/crates/valence_protocol/src/packets/play/resource_pack_status_c2s.rs diff --git a/crates/valence_protocol/src/packets/play/rotate_and_move_relative_s2c.rs b/old/crates/valence_protocol/src/packets/play/rotate_and_move_relative_s2c.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/rotate_and_move_relative_s2c.rs rename to old/crates/valence_protocol/src/packets/play/rotate_and_move_relative_s2c.rs diff --git a/crates/valence_protocol/src/packets/play/rotate_s2c.rs b/old/crates/valence_protocol/src/packets/play/rotate_s2c.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/rotate_s2c.rs rename to old/crates/valence_protocol/src/packets/play/rotate_s2c.rs diff --git a/crates/valence_protocol/src/packets/play/scoreboard_display_s2c.rs b/old/crates/valence_protocol/src/packets/play/scoreboard_display_s2c.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/scoreboard_display_s2c.rs rename to old/crates/valence_protocol/src/packets/play/scoreboard_display_s2c.rs diff --git a/crates/valence_protocol/src/packets/play/scoreboard_objective_update_s2c.rs b/old/crates/valence_protocol/src/packets/play/scoreboard_objective_update_s2c.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/scoreboard_objective_update_s2c.rs rename to old/crates/valence_protocol/src/packets/play/scoreboard_objective_update_s2c.rs diff --git a/crates/valence_protocol/src/packets/play/scoreboard_player_update_s2c.rs b/old/crates/valence_protocol/src/packets/play/scoreboard_player_update_s2c.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/scoreboard_player_update_s2c.rs rename to old/crates/valence_protocol/src/packets/play/scoreboard_player_update_s2c.rs diff --git a/crates/valence_protocol/src/packets/play/screen_handler_property_update_s2c.rs b/old/crates/valence_protocol/src/packets/play/screen_handler_property_update_s2c.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/screen_handler_property_update_s2c.rs rename to old/crates/valence_protocol/src/packets/play/screen_handler_property_update_s2c.rs diff --git a/crates/valence_protocol/src/packets/play/screen_handler_slot_update_s2c.rs b/old/crates/valence_protocol/src/packets/play/screen_handler_slot_update_s2c.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/screen_handler_slot_update_s2c.rs rename to old/crates/valence_protocol/src/packets/play/screen_handler_slot_update_s2c.rs diff --git a/crates/valence_protocol/src/packets/play/select_advancement_tab_s2c.rs b/old/crates/valence_protocol/src/packets/play/select_advancement_tab_s2c.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/select_advancement_tab_s2c.rs rename to old/crates/valence_protocol/src/packets/play/select_advancement_tab_s2c.rs diff --git a/crates/valence_protocol/src/packets/play/select_merchant_trade_c2s.rs b/old/crates/valence_protocol/src/packets/play/select_merchant_trade_c2s.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/select_merchant_trade_c2s.rs rename to old/crates/valence_protocol/src/packets/play/select_merchant_trade_c2s.rs diff --git a/crates/valence_protocol/src/packets/play/server_metadata_s2c.rs b/old/crates/valence_protocol/src/packets/play/server_metadata_s2c.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/server_metadata_s2c.rs rename to old/crates/valence_protocol/src/packets/play/server_metadata_s2c.rs diff --git a/crates/valence_protocol/src/packets/play/set_camera_entity_s2c.rs b/old/crates/valence_protocol/src/packets/play/set_camera_entity_s2c.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/set_camera_entity_s2c.rs rename to old/crates/valence_protocol/src/packets/play/set_camera_entity_s2c.rs diff --git a/crates/valence_protocol/src/packets/play/set_trade_offers_s2c.rs b/old/crates/valence_protocol/src/packets/play/set_trade_offers_s2c.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/set_trade_offers_s2c.rs rename to old/crates/valence_protocol/src/packets/play/set_trade_offers_s2c.rs diff --git a/crates/valence_protocol/src/packets/play/sign_editor_open_s2c.rs b/old/crates/valence_protocol/src/packets/play/sign_editor_open_s2c.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/sign_editor_open_s2c.rs rename to old/crates/valence_protocol/src/packets/play/sign_editor_open_s2c.rs diff --git a/crates/valence_protocol/src/packets/play/simulation_distance_s2c.rs b/old/crates/valence_protocol/src/packets/play/simulation_distance_s2c.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/simulation_distance_s2c.rs rename to old/crates/valence_protocol/src/packets/play/simulation_distance_s2c.rs diff --git a/crates/valence_protocol/src/packets/play/spectator_teleport_c2s.rs b/old/crates/valence_protocol/src/packets/play/spectator_teleport_c2s.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/spectator_teleport_c2s.rs rename to old/crates/valence_protocol/src/packets/play/spectator_teleport_c2s.rs diff --git a/crates/valence_protocol/src/packets/play/statistics_s2c.rs b/old/crates/valence_protocol/src/packets/play/statistics_s2c.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/statistics_s2c.rs rename to old/crates/valence_protocol/src/packets/play/statistics_s2c.rs diff --git a/crates/valence_protocol/src/packets/play/stop_sound_s2c.rs b/old/crates/valence_protocol/src/packets/play/stop_sound_s2c.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/stop_sound_s2c.rs rename to old/crates/valence_protocol/src/packets/play/stop_sound_s2c.rs diff --git a/crates/valence_protocol/src/packets/play/subtitle_s2c.rs b/old/crates/valence_protocol/src/packets/play/subtitle_s2c.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/subtitle_s2c.rs rename to old/crates/valence_protocol/src/packets/play/subtitle_s2c.rs diff --git a/crates/valence_protocol/src/packets/play/synchronize_recipes_s2c.rs b/old/crates/valence_protocol/src/packets/play/synchronize_recipes_s2c.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/synchronize_recipes_s2c.rs rename to old/crates/valence_protocol/src/packets/play/synchronize_recipes_s2c.rs diff --git a/crates/valence_protocol/src/packets/play/synchronize_tags_s2c.rs b/old/crates/valence_protocol/src/packets/play/synchronize_tags_s2c.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/synchronize_tags_s2c.rs rename to old/crates/valence_protocol/src/packets/play/synchronize_tags_s2c.rs diff --git a/crates/valence_protocol/src/packets/play/team_s2c.rs b/old/crates/valence_protocol/src/packets/play/team_s2c.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/team_s2c.rs rename to old/crates/valence_protocol/src/packets/play/team_s2c.rs diff --git a/crates/valence_protocol/src/packets/play/teleport_confirm_c2s.rs b/old/crates/valence_protocol/src/packets/play/teleport_confirm_c2s.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/teleport_confirm_c2s.rs rename to old/crates/valence_protocol/src/packets/play/teleport_confirm_c2s.rs diff --git a/crates/valence_protocol/src/packets/play/title_fade_s2c.rs b/old/crates/valence_protocol/src/packets/play/title_fade_s2c.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/title_fade_s2c.rs rename to old/crates/valence_protocol/src/packets/play/title_fade_s2c.rs diff --git a/crates/valence_protocol/src/packets/play/title_s2c.rs b/old/crates/valence_protocol/src/packets/play/title_s2c.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/title_s2c.rs rename to old/crates/valence_protocol/src/packets/play/title_s2c.rs diff --git a/crates/valence_protocol/src/packets/play/unload_chunk_s2c.rs b/old/crates/valence_protocol/src/packets/play/unload_chunk_s2c.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/unload_chunk_s2c.rs rename to old/crates/valence_protocol/src/packets/play/unload_chunk_s2c.rs diff --git a/crates/valence_protocol/src/packets/play/unlock_recipes_s2c.rs b/old/crates/valence_protocol/src/packets/play/unlock_recipes_s2c.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/unlock_recipes_s2c.rs rename to old/crates/valence_protocol/src/packets/play/unlock_recipes_s2c.rs diff --git a/crates/valence_protocol/src/packets/play/update_beacon_c2s.rs b/old/crates/valence_protocol/src/packets/play/update_beacon_c2s.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/update_beacon_c2s.rs rename to old/crates/valence_protocol/src/packets/play/update_beacon_c2s.rs diff --git a/crates/valence_protocol/src/packets/play/update_command_block_c2s.rs b/old/crates/valence_protocol/src/packets/play/update_command_block_c2s.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/update_command_block_c2s.rs rename to old/crates/valence_protocol/src/packets/play/update_command_block_c2s.rs diff --git a/crates/valence_protocol/src/packets/play/update_command_block_minecart_c2s.rs b/old/crates/valence_protocol/src/packets/play/update_command_block_minecart_c2s.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/update_command_block_minecart_c2s.rs rename to old/crates/valence_protocol/src/packets/play/update_command_block_minecart_c2s.rs diff --git a/crates/valence_protocol/src/packets/play/update_difficulty_c2s.rs b/old/crates/valence_protocol/src/packets/play/update_difficulty_c2s.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/update_difficulty_c2s.rs rename to old/crates/valence_protocol/src/packets/play/update_difficulty_c2s.rs diff --git a/crates/valence_protocol/src/packets/play/update_difficulty_lock_c2s.rs b/old/crates/valence_protocol/src/packets/play/update_difficulty_lock_c2s.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/update_difficulty_lock_c2s.rs rename to old/crates/valence_protocol/src/packets/play/update_difficulty_lock_c2s.rs diff --git a/crates/valence_protocol/src/packets/play/update_jigsaw_c2s.rs b/old/crates/valence_protocol/src/packets/play/update_jigsaw_c2s.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/update_jigsaw_c2s.rs rename to old/crates/valence_protocol/src/packets/play/update_jigsaw_c2s.rs diff --git a/crates/valence_protocol/src/packets/play/update_player_abilities_c2s.rs b/old/crates/valence_protocol/src/packets/play/update_player_abilities_c2s.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/update_player_abilities_c2s.rs rename to old/crates/valence_protocol/src/packets/play/update_player_abilities_c2s.rs diff --git a/crates/valence_protocol/src/packets/play/update_selected_slot_c2s.rs b/old/crates/valence_protocol/src/packets/play/update_selected_slot_c2s.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/update_selected_slot_c2s.rs rename to old/crates/valence_protocol/src/packets/play/update_selected_slot_c2s.rs diff --git a/crates/valence_protocol/src/packets/play/update_selected_slot_s2c.rs b/old/crates/valence_protocol/src/packets/play/update_selected_slot_s2c.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/update_selected_slot_s2c.rs rename to old/crates/valence_protocol/src/packets/play/update_selected_slot_s2c.rs diff --git a/crates/valence_protocol/src/packets/play/update_sign_c2s.rs b/old/crates/valence_protocol/src/packets/play/update_sign_c2s.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/update_sign_c2s.rs rename to old/crates/valence_protocol/src/packets/play/update_sign_c2s.rs diff --git a/crates/valence_protocol/src/packets/play/update_structure_block_c2s.rs b/old/crates/valence_protocol/src/packets/play/update_structure_block_c2s.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/update_structure_block_c2s.rs rename to old/crates/valence_protocol/src/packets/play/update_structure_block_c2s.rs diff --git a/crates/valence_protocol/src/packets/play/vehicle_move_c2s.rs b/old/crates/valence_protocol/src/packets/play/vehicle_move_c2s.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/vehicle_move_c2s.rs rename to old/crates/valence_protocol/src/packets/play/vehicle_move_c2s.rs diff --git a/crates/valence_protocol/src/packets/play/vehicle_move_s2c.rs b/old/crates/valence_protocol/src/packets/play/vehicle_move_s2c.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/vehicle_move_s2c.rs rename to old/crates/valence_protocol/src/packets/play/vehicle_move_s2c.rs diff --git a/crates/valence_protocol/src/packets/play/world_border_center_changed_s2c.rs b/old/crates/valence_protocol/src/packets/play/world_border_center_changed_s2c.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/world_border_center_changed_s2c.rs rename to old/crates/valence_protocol/src/packets/play/world_border_center_changed_s2c.rs diff --git a/crates/valence_protocol/src/packets/play/world_border_initialize_s2c.rs b/old/crates/valence_protocol/src/packets/play/world_border_initialize_s2c.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/world_border_initialize_s2c.rs rename to old/crates/valence_protocol/src/packets/play/world_border_initialize_s2c.rs diff --git a/crates/valence_protocol/src/packets/play/world_border_interpolate_size_s2c.rs b/old/crates/valence_protocol/src/packets/play/world_border_interpolate_size_s2c.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/world_border_interpolate_size_s2c.rs rename to old/crates/valence_protocol/src/packets/play/world_border_interpolate_size_s2c.rs diff --git a/crates/valence_protocol/src/packets/play/world_border_size_changed_s2c.rs b/old/crates/valence_protocol/src/packets/play/world_border_size_changed_s2c.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/world_border_size_changed_s2c.rs rename to old/crates/valence_protocol/src/packets/play/world_border_size_changed_s2c.rs diff --git a/crates/valence_protocol/src/packets/play/world_border_warning_blocks_changed_s2c.rs b/old/crates/valence_protocol/src/packets/play/world_border_warning_blocks_changed_s2c.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/world_border_warning_blocks_changed_s2c.rs rename to old/crates/valence_protocol/src/packets/play/world_border_warning_blocks_changed_s2c.rs diff --git a/crates/valence_protocol/src/packets/play/world_border_warning_time_changed_s2c.rs b/old/crates/valence_protocol/src/packets/play/world_border_warning_time_changed_s2c.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/world_border_warning_time_changed_s2c.rs rename to old/crates/valence_protocol/src/packets/play/world_border_warning_time_changed_s2c.rs diff --git a/crates/valence_protocol/src/packets/play/world_event_s2c.rs b/old/crates/valence_protocol/src/packets/play/world_event_s2c.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/world_event_s2c.rs rename to old/crates/valence_protocol/src/packets/play/world_event_s2c.rs diff --git a/crates/valence_protocol/src/packets/play/world_time_update_s2c.rs b/old/crates/valence_protocol/src/packets/play/world_time_update_s2c.rs similarity index 100% rename from crates/valence_protocol/src/packets/play/world_time_update_s2c.rs rename to old/crates/valence_protocol/src/packets/play/world_time_update_s2c.rs diff --git a/crates/valence_protocol/src/packets/status.rs b/old/crates/valence_protocol/src/packets/status.rs similarity index 100% rename from crates/valence_protocol/src/packets/status.rs rename to old/crates/valence_protocol/src/packets/status.rs diff --git a/crates/valence_protocol/src/packets/status/query_ping_c2s.rs b/old/crates/valence_protocol/src/packets/status/query_ping_c2s.rs similarity index 100% rename from crates/valence_protocol/src/packets/status/query_ping_c2s.rs rename to old/crates/valence_protocol/src/packets/status/query_ping_c2s.rs diff --git a/crates/valence_protocol/src/packets/status/query_pong_s2c.rs b/old/crates/valence_protocol/src/packets/status/query_pong_s2c.rs similarity index 100% rename from crates/valence_protocol/src/packets/status/query_pong_s2c.rs rename to old/crates/valence_protocol/src/packets/status/query_pong_s2c.rs diff --git a/crates/valence_protocol/src/packets/status/query_request_c2s.rs b/old/crates/valence_protocol/src/packets/status/query_request_c2s.rs similarity index 100% rename from crates/valence_protocol/src/packets/status/query_request_c2s.rs rename to old/crates/valence_protocol/src/packets/status/query_request_c2s.rs diff --git a/crates/valence_protocol/src/packets/status/query_response_s2c.rs b/old/crates/valence_protocol/src/packets/status/query_response_s2c.rs similarity index 100% rename from crates/valence_protocol/src/packets/status/query_response_s2c.rs rename to old/crates/valence_protocol/src/packets/status/query_response_s2c.rs diff --git a/crates/valence_protocol/src/profile.rs b/old/crates/valence_protocol/src/profile.rs similarity index 100% rename from crates/valence_protocol/src/profile.rs rename to old/crates/valence_protocol/src/profile.rs diff --git a/crates/valence_protocol/src/raw.rs b/old/crates/valence_protocol/src/raw.rs similarity index 100% rename from crates/valence_protocol/src/raw.rs rename to old/crates/valence_protocol/src/raw.rs diff --git a/crates/valence_protocol/src/sound.rs b/old/crates/valence_protocol/src/sound.rs similarity index 100% rename from crates/valence_protocol/src/sound.rs rename to old/crates/valence_protocol/src/sound.rs diff --git a/old/crates/valence_protocol/src/var_int.rs b/old/crates/valence_protocol/src/var_int.rs new file mode 100644 index 000000000..17f1531b7 --- /dev/null +++ b/old/crates/valence_protocol/src/var_int.rs @@ -0,0 +1,154 @@ +use std::io::{Read, Write}; + +use anyhow::bail; +use byteorder::ReadBytesExt; +use derive_more::{Deref, DerefMut, From, Into}; +use serde::{Deserialize, Serialize}; +use thiserror::Error; + +use crate::{Decode, Encode}; + +/// An `i32` encoded with variable length. +#[derive( + Clone, + Copy, + Default, + PartialEq, + Eq, + PartialOrd, + Ord, + Hash, + Debug, + Deref, + DerefMut, + From, + Into, + Serialize, + Deserialize, +)] +#[serde(transparent)] +#[repr(transparent)] +pub struct VarInt(pub i32); + +impl VarInt { + /// The maximum number of bytes a VarInt could occupy when read from and + /// written to the Minecraft protocol. + pub const MAX_SIZE: usize = 5; + + /// Returns the exact number of bytes this varint will write when + /// [`Encode::encode`] is called, assuming no error occurs. + pub const fn written_size(self) -> usize { + match self.0 { + 0 => 1, + n => (31 - n.leading_zeros() as usize) / 7 + 1, + } + } + + pub fn decode_partial(mut r: impl Read) -> Result { + let mut val = 0; + for i in 0..Self::MAX_SIZE { + let byte = r.read_u8().map_err(|_| VarIntDecodeError::Incomplete)?; + val |= (byte as i32 & 0b01111111) << (i * 7); + if byte & 0b10000000 == 0 { + return Ok(val); + } + } + + Err(VarIntDecodeError::TooLarge) + } +} + +#[derive(Copy, Clone, PartialEq, Eq, Debug, Error)] +pub enum VarIntDecodeError { + #[error("incomplete VarInt decode")] + Incomplete, + #[error("VarInt is too large")] + TooLarge, +} + +impl Encode for VarInt { + // Adapted from VarInt-Simd encode + // https://github.com/as-com/varint-simd/blob/0f468783da8e181929b01b9c6e9f741c1fe09825/src/encode/mod.rs#L71 + fn encode(&self, mut w: impl Write) -> anyhow::Result<()> { + let x = self.0 as u64; + let stage1 = (x & 0x000000000000007f) + | ((x & 0x0000000000003f80) << 1) + | ((x & 0x00000000001fc000) << 2) + | ((x & 0x000000000fe00000) << 3) + | ((x & 0x00000000f0000000) << 4); + + let leading = stage1.leading_zeros(); + + let unused_bytes = (leading - 1) >> 3; + let bytes_needed = 8 - unused_bytes; + + // set all but the last MSBs + let msbs = 0x8080808080808080; + let msbmask = 0xffffffffffffffff >> (((8 - bytes_needed + 1) << 3) - 1); + + let merged = stage1 | (msbs & msbmask); + let bytes = merged.to_le_bytes(); + + w.write_all(unsafe { bytes.get_unchecked(..bytes_needed as usize) })?; + + Ok(()) + } +} + +impl Decode<'_> for VarInt { + fn decode(r: &mut &[u8]) -> anyhow::Result { + let mut val = 0; + for i in 0..Self::MAX_SIZE { + let byte = r.read_u8()?; + val |= (byte as i32 & 0b01111111) << (i * 7); + if byte & 0b10000000 == 0 { + return Ok(VarInt(val)); + } + } + bail!("VarInt is too large") + } +} + +#[cfg(test)] +mod tests { + use rand::{thread_rng, Rng}; + + use super::*; + + #[test] + fn varint_written_size() { + let mut rng = thread_rng(); + let mut buf = vec![]; + + for n in (0..100_000) + .map(|_| rng.gen()) + .chain([0, i32::MIN, i32::MAX]) + .map(VarInt) + { + buf.clear(); + n.encode(&mut buf).unwrap(); + assert_eq!(buf.len(), n.written_size()); + } + } + + #[test] + fn varint_round_trip() { + let mut rng = thread_rng(); + let mut buf = vec![]; + + for n in (0..1_000_000) + .map(|_| rng.gen()) + .chain([0, i32::MIN, i32::MAX]) + { + VarInt(n).encode(&mut buf).unwrap(); + + let mut slice = buf.as_slice(); + assert!(slice.len() <= VarInt::MAX_SIZE); + + assert_eq!(n, VarInt::decode(&mut slice).unwrap().0); + + assert!(slice.is_empty()); + buf.clear(); + } + } +} diff --git a/crates/valence_protocol/src/var_long.rs b/old/crates/valence_protocol/src/var_long.rs similarity index 100% rename from crates/valence_protocol/src/var_long.rs rename to old/crates/valence_protocol/src/var_long.rs diff --git a/crates/valence_protocol/src/velocity.rs b/old/crates/valence_protocol/src/velocity.rs similarity index 100% rename from crates/valence_protocol/src/velocity.rs rename to old/crates/valence_protocol/src/velocity.rs diff --git a/old/crates/valence_protocol_macros/Cargo.toml b/old/crates/valence_protocol_macros/Cargo.toml new file mode 100644 index 000000000..5f9bf9354 --- /dev/null +++ b/old/crates/valence_protocol_macros/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "valence_protocol_macros" +description = "Procedural macros for valence_protocol" +readme = "README.md" +version.workspace = true +edition.workspace = true +repository.workspace = true +documentation.workspace = true +license.workspace = true + +[lib] +proc-macro = true + +[dependencies] +proc-macro2.workspace = true +quote.workspace = true +syn = { workspace = true, features = ["full"] } +heck.workspace = true diff --git a/old/crates/valence_protocol_macros/README.md b/old/crates/valence_protocol_macros/README.md new file mode 100644 index 000000000..fc74027cc --- /dev/null +++ b/old/crates/valence_protocol_macros/README.md @@ -0,0 +1,3 @@ +# valence_protocol_macros + +Procedural macros for `valence_protocol` diff --git a/old/crates/valence_protocol_macros/src/decode.rs b/old/crates/valence_protocol_macros/src/decode.rs new file mode 100644 index 000000000..15f45e838 --- /dev/null +++ b/old/crates/valence_protocol_macros/src/decode.rs @@ -0,0 +1,167 @@ +use proc_macro2::TokenStream; +use quote::quote; +use syn::spanned::Spanned; +use syn::{parse2, parse_quote, Data, DeriveInput, Error, Fields, Result}; + +use crate::{add_trait_bounds, decode_split_for_impl, pair_variants_with_discriminants}; + +pub(super) fn derive_decode(item: TokenStream) -> Result { + let mut input = parse2::(item)?; + + let input_name = input.ident; + + if input.generics.lifetimes().count() > 1 { + return Err(Error::new( + input.generics.params.span(), + "type deriving `Decode` must have no more than one lifetime", + )); + } + + // Use the lifetime specified in the type definition or just use `'a` if not + // present. + let lifetime = input + .generics + .lifetimes() + .next() + .map(|l| l.lifetime.clone()) + .unwrap_or_else(|| parse_quote!('a)); + + match input.data { + Data::Struct(struct_) => { + let decode_fields = match struct_.fields { + Fields::Named(fields) => { + let init = fields.named.iter().map(|f| { + let name = f.ident.as_ref().unwrap(); + let ctx = format!("failed to decode field `{name}` in `{input_name}`"); + quote! { + #name: Decode::decode(_r).context(#ctx)?, + } + }); + + quote! { + Self { + #(#init)* + } + } + } + Fields::Unnamed(fields) => { + let init = (0..fields.unnamed.len()) + .map(|i| { + let ctx = format!("failed to decode field `{i}` in `{input_name}`"); + quote! { + Decode::decode(_r).context(#ctx)?, + } + }) + .collect::(); + + quote! { + Self(#init) + } + } + Fields::Unit => quote!(Self), + }; + + add_trait_bounds( + &mut input.generics, + quote!(::valence_protocol::__private::Decode<#lifetime>), + ); + + let (impl_generics, ty_generics, where_clause) = + decode_split_for_impl(input.generics, lifetime.clone()); + + Ok(quote! { + #[allow(unused_imports)] + impl #impl_generics ::valence_protocol::__private::Decode<#lifetime> for #input_name #ty_generics + #where_clause + { + fn decode(_r: &mut &#lifetime [u8]) -> ::valence_protocol::__private::Result { + use ::valence_protocol::__private::{Decode, Context, ensure}; + + Ok(#decode_fields) + } + } + }) + } + Data::Enum(enum_) => { + let variants = pair_variants_with_discriminants(enum_.variants)?; + + let decode_arms = variants + .iter() + .map(|(disc, variant)| { + let name = &variant.ident; + + match &variant.fields { + Fields::Named(fields) => { + let fields = fields + .named + .iter() + .map(|f| { + let field = f.ident.as_ref().unwrap(); + let ctx = format!( + "failed to decode field `{field}` in variant `{name}` in \ + `{input_name}`", + ); + quote! { + #field: Decode::decode(_r).context(#ctx)?, + } + }) + .collect::(); + + quote! { + #disc => Ok(Self::#name { #fields }), + } + } + Fields::Unnamed(fields) => { + let init = (0..fields.unnamed.len()) + .map(|i| { + let ctx = format!( + "failed to decode field `{i}` in variant `{name}` in \ + `{input_name}`", + ); + quote! { + Decode::decode(_r).context(#ctx)?, + } + }) + .collect::(); + + quote! { + #disc => Ok(Self::#name(#init)), + } + } + Fields::Unit => quote!(#disc => Ok(Self::#name),), + } + }) + .collect::(); + + add_trait_bounds( + &mut input.generics, + quote!(::valence_protocol::__private::Decode<#lifetime>), + ); + + let (impl_generics, ty_generics, where_clause) = + decode_split_for_impl(input.generics, lifetime.clone()); + + Ok(quote! { + #[allow(unused_imports)] + impl #impl_generics ::valence_protocol::__private::Decode<#lifetime> for #input_name #ty_generics + #where_clause + { + fn decode(_r: &mut &#lifetime [u8]) -> ::valence_protocol::__private::Result { + use ::valence_protocol::__private::{Decode, Context, VarInt, bail}; + + let ctx = concat!("failed to decode enum discriminant in `", stringify!(#input_name), "`"); + let disc = VarInt::decode(_r).context(ctx)?.0; + match disc { + #decode_arms + n => bail!("unexpected enum discriminant {} in `{}`", disc, stringify!(#input_name)), + } + } + } + }) + } + Data::Union(u) => Err(Error::new( + u.union_token.span(), + "cannot derive `Decode` on unions", + )), + } +} diff --git a/old/crates/valence_protocol_macros/src/encode.rs b/old/crates/valence_protocol_macros/src/encode.rs new file mode 100644 index 000000000..101048e0c --- /dev/null +++ b/old/crates/valence_protocol_macros/src/encode.rs @@ -0,0 +1,165 @@ +use proc_macro2::{Ident, Span, TokenStream}; +use quote::quote; +use syn::spanned::Spanned; +use syn::{parse2, Data, DeriveInput, Error, Fields, LitInt, Result}; + +use crate::{add_trait_bounds, pair_variants_with_discriminants}; + +pub(super) fn derive_encode(item: TokenStream) -> Result { + let mut input = parse2::(item)?; + + let input_name = input.ident; + + add_trait_bounds( + &mut input.generics, + quote!(::valence_protocol::__private::Encode), + ); + + let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl(); + + match input.data { + Data::Struct(struct_) => { + let encode_fields = match &struct_.fields { + Fields::Named(fields) => fields + .named + .iter() + .map(|f| { + let name = &f.ident.as_ref().unwrap(); + let ctx = format!("failed to encode field `{name}` in `{input_name}`"); + quote! { + self.#name.encode(&mut _w).context(#ctx)?; + } + }) + .collect(), + Fields::Unnamed(fields) => (0..fields.unnamed.len()) + .map(|i| { + let lit = LitInt::new(&i.to_string(), Span::call_site()); + let ctx = format!("failed to encode field `{lit}` in `{input_name}`"); + quote! { + self.#lit.encode(&mut _w).context(#ctx)?; + } + }) + .collect(), + Fields::Unit => TokenStream::new(), + }; + + Ok(quote! { + #[allow(unused_imports)] + impl #impl_generics ::valence_protocol::__private::Encode for #input_name #ty_generics + #where_clause + { + fn encode(&self, mut _w: impl ::std::io::Write) -> ::valence_protocol::__private::Result<()> { + use ::valence_protocol::__private::{Encode, Context}; + + #encode_fields + + Ok(()) + } + } + }) + } + Data::Enum(enum_) => { + let variants = pair_variants_with_discriminants(enum_.variants)?; + + let encode_arms = variants + .iter() + .map(|(disc, variant)| { + let variant_name = &variant.ident; + + let disc_ctx = format!( + "failed to encode enum discriminant {disc} for variant `{variant_name}` \ + in `{input_name}`", + ); + + match &variant.fields { + Fields::Named(fields) => { + let field_names = fields + .named + .iter() + .map(|f| f.ident.as_ref().unwrap()) + .collect::>(); + + let encode_fields = field_names + .iter() + .map(|name| { + let ctx = format!( + "failed to encode field `{name}` in variant \ + `{variant_name}` in `{input_name}`", + ); + + quote! { + #name.encode(&mut _w).context(#ctx)?; + } + }) + .collect::(); + + quote! { + Self::#variant_name { #(#field_names,)* } => { + VarInt(#disc).encode(&mut _w).context(#disc_ctx)?; + + #encode_fields + Ok(()) + } + } + } + Fields::Unnamed(fields) => { + let field_names = (0..fields.unnamed.len()) + .map(|i| Ident::new(&format!("_{i}"), Span::call_site())) + .collect::>(); + + let encode_fields = field_names + .iter() + .map(|name| { + let ctx = format!( + "failed to encode field `{name}` in variant \ + `{variant_name}` in `{input_name}`" + ); + + quote! { + #name.encode(&mut _w).context(#ctx)?; + } + }) + .collect::(); + + quote! { + Self::#variant_name(#(#field_names,)*) => { + VarInt(#disc).encode(&mut _w).context(#disc_ctx)?; + + #encode_fields + Ok(()) + } + } + } + Fields::Unit => quote! { + Self::#variant_name => Ok( + VarInt(#disc) + .encode(&mut _w) + .context(#disc_ctx)? + ), + }, + } + }) + .collect::(); + + Ok(quote! { + #[allow(unused_imports, unreachable_code)] + impl #impl_generics ::valence_protocol::__private::Encode for #input_name #ty_generics + #where_clause + { + fn encode(&self, mut _w: impl ::std::io::Write) -> ::valence_protocol::__private::Result<()> { + use ::valence_protocol::__private::{Encode, VarInt, Context}; + + match self { + #encode_arms + _ => unreachable!(), + } + } + } + }) + } + Data::Union(u) => Err(Error::new( + u.union_token.span(), + "cannot derive `Encode` on unions", + )), + } +} diff --git a/old/crates/valence_protocol_macros/src/lib.rs b/old/crates/valence_protocol_macros/src/lib.rs new file mode 100644 index 000000000..46c552024 --- /dev/null +++ b/old/crates/valence_protocol_macros/src/lib.rs @@ -0,0 +1,125 @@ +#![doc = include_str!("../README.md")] +#![deny( + rustdoc::broken_intra_doc_links, + rustdoc::private_intra_doc_links, + rustdoc::missing_crate_level_docs, + rustdoc::invalid_codeblock_attributes, + rustdoc::invalid_rust_codeblocks, + rustdoc::bare_urls, + rustdoc::invalid_html_tags +)] +#![warn( + trivial_casts, + trivial_numeric_casts, + unused_lifetimes, + unused_import_braces, + unreachable_pub, + clippy::dbg_macro +)] + +use proc_macro::TokenStream as StdTokenStream; +use proc_macro2::TokenStream; +use quote::ToTokens; +use syn::{ + parse_quote, Attribute, GenericParam, Generics, Lifetime, LifetimeParam, LitInt, Result, + Variant, +}; + +mod decode; +mod encode; +mod packet; + +#[proc_macro_derive(Encode, attributes(packet))] +pub fn derive_encode(item: StdTokenStream) -> StdTokenStream { + match encode::derive_encode(item.into()) { + Ok(tokens) => tokens.into(), + Err(e) => e.into_compile_error().into(), + } +} + +#[proc_macro_derive(Decode, attributes(packet))] +pub fn derive_decode(item: StdTokenStream) -> StdTokenStream { + match decode::derive_decode(item.into()) { + Ok(tokens) => tokens.into(), + Err(e) => e.into_compile_error().into(), + } +} + +#[proc_macro_derive(Packet, attributes(packet))] +pub fn derive_packet(item: StdTokenStream) -> StdTokenStream { + match packet::derive_packet(item.into()) { + Ok(tokens) => tokens.into(), + Err(e) => e.into_compile_error().into(), + } +} + +fn pair_variants_with_discriminants( + variants: impl IntoIterator, +) -> Result> { + let mut discriminant = 0; + variants + .into_iter() + .map(|v| { + if let Some(i) = parse_tag_attr(&v.attrs)? { + discriminant = i; + } + + let pair = (discriminant, v); + discriminant += 1; + Ok(pair) + }) + .collect::>() +} + +fn parse_tag_attr(attrs: &[Attribute]) -> Result> { + for attr in attrs { + if attr.path().is_ident("packet") { + let mut res = 0; + + attr.parse_nested_meta(|meta| { + if meta.path.is_ident("tag") { + res = meta.value()?.parse::()?.base10_parse::()?; + Ok(()) + } else { + Err(meta.error("unrecognized argument")) + } + })?; + + return Ok(Some(res)); + } + } + + Ok(None) +} + +/// Adding our lifetime to the generics before calling `.split_for_impl()` would +/// also add it to the resulting ty_generics, which we don't want. So I'm doing +/// this hack. +fn decode_split_for_impl( + mut generics: Generics, + lifetime: Lifetime, +) -> (TokenStream, TokenStream, TokenStream) { + let (impl_generics, ty_generics, where_clause) = generics.split_for_impl(); + + let mut impl_generics = impl_generics.to_token_stream(); + let ty_generics = ty_generics.to_token_stream(); + let where_clause = where_clause.to_token_stream(); + + if generics.lifetimes().next().is_none() { + generics + .params + .push(GenericParam::Lifetime(LifetimeParam::new(lifetime))); + + impl_generics = generics.split_for_impl().0.to_token_stream(); + } + + (impl_generics, ty_generics, where_clause) +} + +fn add_trait_bounds(generics: &mut Generics, trait_: TokenStream) { + for param in &mut generics.params { + if let GenericParam::Type(type_param) = param { + type_param.bounds.push(parse_quote!(#trait_)) + } + } +} diff --git a/old/crates/valence_protocol_macros/src/packet.rs b/old/crates/valence_protocol_macros/src/packet.rs new file mode 100644 index 000000000..9d2cdd559 --- /dev/null +++ b/old/crates/valence_protocol_macros/src/packet.rs @@ -0,0 +1,128 @@ +use heck::ToShoutySnakeCase; +use proc_macro2::{Ident, Span, TokenStream}; +use quote::quote; +use syn::spanned::Spanned; +use syn::{parse2, parse_quote, Attribute, DeriveInput, Error, Expr, LitInt, LitStr, Result}; + +use crate::add_trait_bounds; + +pub(super) fn derive_packet(item: TokenStream) -> Result { + let mut input = parse2::(item)?; + + let packet_attr = parse_packet_helper_attr(&input.attrs)?.unwrap_or_default(); + + let name = input.ident.clone(); + + let name_str = if let Some(attr_name) = packet_attr.name { + attr_name.value() + } else { + name.to_string() + }; + + let packet_id: Expr = match packet_attr.id { + Some(expr) => expr, + None => match syn::parse_str::(&name_str.to_shouty_snake_case()) { + Ok(ident) => parse_quote!(::valence_protocol::packet_id::#ident), + Err(_) => { + return Err(Error::new( + packet_attr.span, + "missing valid `id = ...` value from `packet` attr", + )) + } + }, + }; + + add_trait_bounds(&mut input.generics, quote!(::std::fmt::Debug)); + + let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl(); + + let side = if let Some(side_attr) = packet_attr.side { + side_attr + } else if name_str.to_lowercase().ends_with("s2c") { + parse_quote!(::valence_protocol::PacketSide::Clientbound) + } else if name_str.to_lowercase().ends_with("c2s") { + parse_quote!(::valence_protocol::PacketSide::Serverbound) + } else { + return Err(Error::new( + packet_attr.span, + "missing `side = PacketSide::...` value from `packet` attribute", + )); + }; + + let state = packet_attr + .state + .unwrap_or_else(|| parse_quote!(::valence_protocol::PacketState::Play)); + + Ok(quote! { + impl #impl_generics ::valence_protocol::__private::Packet for #name #ty_generics + #where_clause + { + const ID: i32 = #packet_id; + const NAME: &'static str = #name_str; + const SIDE: ::valence_protocol::PacketSide = #side; + const STATE: ::valence_protocol::PacketState = #state; + } + }) +} + +struct PacketAttr { + span: Span, + id: Option, + tag: Option, + name: Option, + side: Option, + state: Option, +} + +impl Default for PacketAttr { + fn default() -> Self { + Self { + span: Span::call_site(), + id: Default::default(), + tag: Default::default(), + name: Default::default(), + side: Default::default(), + state: Default::default(), + } + } +} + +fn parse_packet_helper_attr(attrs: &[Attribute]) -> Result> { + for attr in attrs { + if attr.path().is_ident("packet") { + let mut res = PacketAttr { + span: attr.span(), + id: None, + tag: None, + name: None, + side: None, + state: None, + }; + + attr.parse_nested_meta(|meta| { + if meta.path.is_ident("id") { + res.id = Some(meta.value()?.parse::()?); + Ok(()) + } else if meta.path.is_ident("tag") { + res.tag = Some(meta.value()?.parse::()?.base10_parse::()?); + Ok(()) + } else if meta.path.is_ident("name") { + res.name = Some(meta.value()?.parse::()?); + Ok(()) + } else if meta.path.is_ident("side") { + res.side = Some(meta.value()?.parse::()?); + Ok(()) + } else if meta.path.is_ident("state") { + res.state = Some(meta.value()?.parse::()?); + Ok(()) + } else { + Err(meta.error("unrecognized packet argument")) + } + })?; + + return Ok(Some(res)); + } + } + + Ok(None) +} diff --git a/crates/valence_registry/Cargo.toml b/old/crates/valence_registry/Cargo.toml similarity index 100% rename from crates/valence_registry/Cargo.toml rename to old/crates/valence_registry/Cargo.toml diff --git a/crates/valence_registry/README.md b/old/crates/valence_registry/README.md similarity index 100% rename from crates/valence_registry/README.md rename to old/crates/valence_registry/README.md diff --git a/crates/valence_registry/extracted/registry_codec.dat b/old/crates/valence_registry/extracted/registry_codec.dat similarity index 100% rename from crates/valence_registry/extracted/registry_codec.dat rename to old/crates/valence_registry/extracted/registry_codec.dat diff --git a/crates/valence_registry/extracted/tags.json b/old/crates/valence_registry/extracted/tags.json similarity index 100% rename from crates/valence_registry/extracted/tags.json rename to old/crates/valence_registry/extracted/tags.json diff --git a/crates/valence_registry/src/biome.rs b/old/crates/valence_registry/src/biome.rs similarity index 100% rename from crates/valence_registry/src/biome.rs rename to old/crates/valence_registry/src/biome.rs diff --git a/crates/valence_registry/src/codec.rs b/old/crates/valence_registry/src/codec.rs similarity index 100% rename from crates/valence_registry/src/codec.rs rename to old/crates/valence_registry/src/codec.rs diff --git a/crates/valence_registry/src/dimension_type.rs b/old/crates/valence_registry/src/dimension_type.rs similarity index 100% rename from crates/valence_registry/src/dimension_type.rs rename to old/crates/valence_registry/src/dimension_type.rs diff --git a/crates/valence_registry/src/lib.rs b/old/crates/valence_registry/src/lib.rs similarity index 100% rename from crates/valence_registry/src/lib.rs rename to old/crates/valence_registry/src/lib.rs diff --git a/crates/valence_registry/src/tags.rs b/old/crates/valence_registry/src/tags.rs similarity index 100% rename from crates/valence_registry/src/tags.rs rename to old/crates/valence_registry/src/tags.rs diff --git a/crates/valence_scoreboard/Cargo.toml b/old/crates/valence_scoreboard/Cargo.toml similarity index 100% rename from crates/valence_scoreboard/Cargo.toml rename to old/crates/valence_scoreboard/Cargo.toml diff --git a/crates/valence_scoreboard/README.md b/old/crates/valence_scoreboard/README.md similarity index 100% rename from crates/valence_scoreboard/README.md rename to old/crates/valence_scoreboard/README.md diff --git a/crates/valence_scoreboard/src/components.rs b/old/crates/valence_scoreboard/src/components.rs similarity index 100% rename from crates/valence_scoreboard/src/components.rs rename to old/crates/valence_scoreboard/src/components.rs diff --git a/crates/valence_scoreboard/src/lib.rs b/old/crates/valence_scoreboard/src/lib.rs similarity index 100% rename from crates/valence_scoreboard/src/lib.rs rename to old/crates/valence_scoreboard/src/lib.rs diff --git a/crates/valence_server/Cargo.toml b/old/crates/valence_server/Cargo.toml similarity index 100% rename from crates/valence_server/Cargo.toml rename to old/crates/valence_server/Cargo.toml diff --git a/crates/valence_server/README.md b/old/crates/valence_server/README.md similarity index 100% rename from crates/valence_server/README.md rename to old/crates/valence_server/README.md diff --git a/crates/valence_server/src/abilities.rs b/old/crates/valence_server/src/abilities.rs similarity index 100% rename from crates/valence_server/src/abilities.rs rename to old/crates/valence_server/src/abilities.rs diff --git a/crates/valence_server/src/action.rs b/old/crates/valence_server/src/action.rs similarity index 100% rename from crates/valence_server/src/action.rs rename to old/crates/valence_server/src/action.rs diff --git a/crates/valence_server/src/brand.rs b/old/crates/valence_server/src/brand.rs similarity index 100% rename from crates/valence_server/src/brand.rs rename to old/crates/valence_server/src/brand.rs diff --git a/crates/valence_server/src/chunk_view.rs b/old/crates/valence_server/src/chunk_view.rs similarity index 100% rename from crates/valence_server/src/chunk_view.rs rename to old/crates/valence_server/src/chunk_view.rs diff --git a/crates/valence_server/src/client.rs b/old/crates/valence_server/src/client.rs similarity index 100% rename from crates/valence_server/src/client.rs rename to old/crates/valence_server/src/client.rs diff --git a/crates/valence_server/src/client_command.rs b/old/crates/valence_server/src/client_command.rs similarity index 100% rename from crates/valence_server/src/client_command.rs rename to old/crates/valence_server/src/client_command.rs diff --git a/crates/valence_server/src/client_settings.rs b/old/crates/valence_server/src/client_settings.rs similarity index 100% rename from crates/valence_server/src/client_settings.rs rename to old/crates/valence_server/src/client_settings.rs diff --git a/crates/valence_server/src/custom_payload.rs b/old/crates/valence_server/src/custom_payload.rs similarity index 100% rename from crates/valence_server/src/custom_payload.rs rename to old/crates/valence_server/src/custom_payload.rs diff --git a/crates/valence_server/src/event_loop.rs b/old/crates/valence_server/src/event_loop.rs similarity index 100% rename from crates/valence_server/src/event_loop.rs rename to old/crates/valence_server/src/event_loop.rs diff --git a/crates/valence_server/src/hand_swing.rs b/old/crates/valence_server/src/hand_swing.rs similarity index 100% rename from crates/valence_server/src/hand_swing.rs rename to old/crates/valence_server/src/hand_swing.rs diff --git a/crates/valence_server/src/interact_block.rs b/old/crates/valence_server/src/interact_block.rs similarity index 100% rename from crates/valence_server/src/interact_block.rs rename to old/crates/valence_server/src/interact_block.rs diff --git a/crates/valence_server/src/interact_entity.rs b/old/crates/valence_server/src/interact_entity.rs similarity index 100% rename from crates/valence_server/src/interact_entity.rs rename to old/crates/valence_server/src/interact_entity.rs diff --git a/crates/valence_server/src/interact_item.rs b/old/crates/valence_server/src/interact_item.rs similarity index 100% rename from crates/valence_server/src/interact_item.rs rename to old/crates/valence_server/src/interact_item.rs diff --git a/crates/valence_server/src/keepalive.rs b/old/crates/valence_server/src/keepalive.rs similarity index 100% rename from crates/valence_server/src/keepalive.rs rename to old/crates/valence_server/src/keepalive.rs diff --git a/crates/valence_server/src/layer.rs b/old/crates/valence_server/src/layer.rs similarity index 100% rename from crates/valence_server/src/layer.rs rename to old/crates/valence_server/src/layer.rs diff --git a/crates/valence_server/src/layer/bvh.rs b/old/crates/valence_server/src/layer/bvh.rs similarity index 100% rename from crates/valence_server/src/layer/bvh.rs rename to old/crates/valence_server/src/layer/bvh.rs diff --git a/crates/valence_server/src/layer/chunk.rs b/old/crates/valence_server/src/layer/chunk.rs similarity index 100% rename from crates/valence_server/src/layer/chunk.rs rename to old/crates/valence_server/src/layer/chunk.rs diff --git a/crates/valence_server/src/layer/chunk/chunk.rs b/old/crates/valence_server/src/layer/chunk/chunk.rs similarity index 100% rename from crates/valence_server/src/layer/chunk/chunk.rs rename to old/crates/valence_server/src/layer/chunk/chunk.rs diff --git a/crates/valence_server/src/layer/chunk/loaded.rs b/old/crates/valence_server/src/layer/chunk/loaded.rs similarity index 100% rename from crates/valence_server/src/layer/chunk/loaded.rs rename to old/crates/valence_server/src/layer/chunk/loaded.rs diff --git a/crates/valence_server/src/layer/chunk/paletted_container.rs b/old/crates/valence_server/src/layer/chunk/paletted_container.rs similarity index 100% rename from crates/valence_server/src/layer/chunk/paletted_container.rs rename to old/crates/valence_server/src/layer/chunk/paletted_container.rs diff --git a/crates/valence_server/src/layer/chunk/unloaded.rs b/old/crates/valence_server/src/layer/chunk/unloaded.rs similarity index 100% rename from crates/valence_server/src/layer/chunk/unloaded.rs rename to old/crates/valence_server/src/layer/chunk/unloaded.rs diff --git a/crates/valence_server/src/layer/entity.rs b/old/crates/valence_server/src/layer/entity.rs similarity index 100% rename from crates/valence_server/src/layer/entity.rs rename to old/crates/valence_server/src/layer/entity.rs diff --git a/crates/valence_server/src/layer/message.rs b/old/crates/valence_server/src/layer/message.rs similarity index 100% rename from crates/valence_server/src/layer/message.rs rename to old/crates/valence_server/src/layer/message.rs diff --git a/crates/valence_server/src/lib.rs b/old/crates/valence_server/src/lib.rs similarity index 100% rename from crates/valence_server/src/lib.rs rename to old/crates/valence_server/src/lib.rs diff --git a/crates/valence_server/src/message.rs b/old/crates/valence_server/src/message.rs similarity index 100% rename from crates/valence_server/src/message.rs rename to old/crates/valence_server/src/message.rs diff --git a/crates/valence_server/src/movement.rs b/old/crates/valence_server/src/movement.rs similarity index 100% rename from crates/valence_server/src/movement.rs rename to old/crates/valence_server/src/movement.rs diff --git a/crates/valence_server/src/op_level.rs b/old/crates/valence_server/src/op_level.rs similarity index 100% rename from crates/valence_server/src/op_level.rs rename to old/crates/valence_server/src/op_level.rs diff --git a/crates/valence_server/src/resource_pack.rs b/old/crates/valence_server/src/resource_pack.rs similarity index 100% rename from crates/valence_server/src/resource_pack.rs rename to old/crates/valence_server/src/resource_pack.rs diff --git a/crates/valence_server/src/spawn.rs b/old/crates/valence_server/src/spawn.rs similarity index 100% rename from crates/valence_server/src/spawn.rs rename to old/crates/valence_server/src/spawn.rs diff --git a/crates/valence_server/src/status.rs b/old/crates/valence_server/src/status.rs similarity index 100% rename from crates/valence_server/src/status.rs rename to old/crates/valence_server/src/status.rs diff --git a/crates/valence_server/src/status_effect.rs b/old/crates/valence_server/src/status_effect.rs similarity index 100% rename from crates/valence_server/src/status_effect.rs rename to old/crates/valence_server/src/status_effect.rs diff --git a/crates/valence_server/src/teleport.rs b/old/crates/valence_server/src/teleport.rs similarity index 100% rename from crates/valence_server/src/teleport.rs rename to old/crates/valence_server/src/teleport.rs diff --git a/crates/valence_server/src/title.rs b/old/crates/valence_server/src/title.rs similarity index 100% rename from crates/valence_server/src/title.rs rename to old/crates/valence_server/src/title.rs diff --git a/crates/valence_server_common/Cargo.toml b/old/crates/valence_server_common/Cargo.toml similarity index 100% rename from crates/valence_server_common/Cargo.toml rename to old/crates/valence_server_common/Cargo.toml diff --git a/crates/valence_server_common/README.md b/old/crates/valence_server_common/README.md similarity index 100% rename from crates/valence_server_common/README.md rename to old/crates/valence_server_common/README.md diff --git a/crates/valence_server_common/src/despawn.rs b/old/crates/valence_server_common/src/despawn.rs similarity index 100% rename from crates/valence_server_common/src/despawn.rs rename to old/crates/valence_server_common/src/despawn.rs diff --git a/crates/valence_server_common/src/lib.rs b/old/crates/valence_server_common/src/lib.rs similarity index 100% rename from crates/valence_server_common/src/lib.rs rename to old/crates/valence_server_common/src/lib.rs diff --git a/crates/valence_server_common/src/uuid.rs b/old/crates/valence_server_common/src/uuid.rs similarity index 100% rename from crates/valence_server_common/src/uuid.rs rename to old/crates/valence_server_common/src/uuid.rs diff --git a/crates/valence_spatial/Cargo.toml b/old/crates/valence_spatial/Cargo.toml similarity index 100% rename from crates/valence_spatial/Cargo.toml rename to old/crates/valence_spatial/Cargo.toml diff --git a/crates/valence_spatial/README.md b/old/crates/valence_spatial/README.md similarity index 100% rename from crates/valence_spatial/README.md rename to old/crates/valence_spatial/README.md diff --git a/crates/valence_spatial/src/bvh.rs b/old/crates/valence_spatial/src/bvh.rs similarity index 100% rename from crates/valence_spatial/src/bvh.rs rename to old/crates/valence_spatial/src/bvh.rs diff --git a/crates/valence_spatial/src/lib.rs b/old/crates/valence_spatial/src/lib.rs similarity index 100% rename from crates/valence_spatial/src/lib.rs rename to old/crates/valence_spatial/src/lib.rs diff --git a/crates/valence_weather/Cargo.toml b/old/crates/valence_weather/Cargo.toml similarity index 100% rename from crates/valence_weather/Cargo.toml rename to old/crates/valence_weather/Cargo.toml diff --git a/crates/valence_weather/README.md b/old/crates/valence_weather/README.md similarity index 100% rename from crates/valence_weather/README.md rename to old/crates/valence_weather/README.md diff --git a/crates/valence_weather/src/lib.rs b/old/crates/valence_weather/src/lib.rs similarity index 100% rename from crates/valence_weather/src/lib.rs rename to old/crates/valence_weather/src/lib.rs diff --git a/crates/valence_weather/src/packet.rs b/old/crates/valence_weather/src/packet.rs similarity index 100% rename from crates/valence_weather/src/packet.rs rename to old/crates/valence_weather/src/packet.rs diff --git a/crates/valence_world_border/Cargo.toml b/old/crates/valence_world_border/Cargo.toml similarity index 100% rename from crates/valence_world_border/Cargo.toml rename to old/crates/valence_world_border/Cargo.toml diff --git a/crates/valence_world_border/README.md b/old/crates/valence_world_border/README.md similarity index 100% rename from crates/valence_world_border/README.md rename to old/crates/valence_world_border/README.md diff --git a/crates/valence_world_border/src/lib.rs b/old/crates/valence_world_border/src/lib.rs similarity index 100% rename from crates/valence_world_border/src/lib.rs rename to old/crates/valence_world_border/src/lib.rs diff --git a/examples/advancement.rs b/old/examples/advancement.rs similarity index 100% rename from examples/advancement.rs rename to old/examples/advancement.rs diff --git a/examples/anvil_loading.rs b/old/examples/anvil_loading.rs similarity index 100% rename from examples/anvil_loading.rs rename to old/examples/anvil_loading.rs diff --git a/examples/bench_players.rs b/old/examples/bench_players.rs similarity index 100% rename from examples/bench_players.rs rename to old/examples/bench_players.rs diff --git a/examples/biomes.rs b/old/examples/biomes.rs similarity index 100% rename from examples/biomes.rs rename to old/examples/biomes.rs diff --git a/examples/block_entities.rs b/old/examples/block_entities.rs similarity index 100% rename from examples/block_entities.rs rename to old/examples/block_entities.rs diff --git a/examples/boss_bar.rs b/old/examples/boss_bar.rs similarity index 100% rename from examples/boss_bar.rs rename to old/examples/boss_bar.rs diff --git a/examples/building.rs b/old/examples/building.rs similarity index 100% rename from examples/building.rs rename to old/examples/building.rs diff --git a/examples/chest.rs b/old/examples/chest.rs similarity index 100% rename from examples/chest.rs rename to old/examples/chest.rs diff --git a/examples/combat.rs b/old/examples/combat.rs similarity index 100% rename from examples/combat.rs rename to old/examples/combat.rs diff --git a/examples/command.rs b/old/examples/command.rs similarity index 100% rename from examples/command.rs rename to old/examples/command.rs diff --git a/examples/cow_sphere.rs b/old/examples/cow_sphere.rs similarity index 100% rename from examples/cow_sphere.rs rename to old/examples/cow_sphere.rs diff --git a/examples/ctf.rs b/old/examples/ctf.rs similarity index 100% rename from examples/ctf.rs rename to old/examples/ctf.rs diff --git a/examples/custom_npc.rs b/old/examples/custom_npc.rs similarity index 100% rename from examples/custom_npc.rs rename to old/examples/custom_npc.rs diff --git a/examples/death.rs b/old/examples/death.rs similarity index 100% rename from examples/death.rs rename to old/examples/death.rs diff --git a/examples/entity_hitbox.rs b/old/examples/entity_hitbox.rs similarity index 100% rename from examples/entity_hitbox.rs rename to old/examples/entity_hitbox.rs diff --git a/examples/game_of_life.rs b/old/examples/game_of_life.rs similarity index 100% rename from examples/game_of_life.rs rename to old/examples/game_of_life.rs diff --git a/examples/parkour.rs b/old/examples/parkour.rs similarity index 100% rename from examples/parkour.rs rename to old/examples/parkour.rs diff --git a/examples/particles.rs b/old/examples/particles.rs similarity index 100% rename from examples/particles.rs rename to old/examples/particles.rs diff --git a/examples/player_list.rs b/old/examples/player_list.rs similarity index 100% rename from examples/player_list.rs rename to old/examples/player_list.rs diff --git a/examples/potions.rs b/old/examples/potions.rs similarity index 100% rename from examples/potions.rs rename to old/examples/potions.rs diff --git a/examples/resource_pack.rs b/old/examples/resource_pack.rs similarity index 100% rename from examples/resource_pack.rs rename to old/examples/resource_pack.rs diff --git a/examples/server_list_ping.rs b/old/examples/server_list_ping.rs similarity index 100% rename from examples/server_list_ping.rs rename to old/examples/server_list_ping.rs diff --git a/examples/terrain.rs b/old/examples/terrain.rs similarity index 100% rename from examples/terrain.rs rename to old/examples/terrain.rs diff --git a/examples/text.rs b/old/examples/text.rs similarity index 100% rename from examples/text.rs rename to old/examples/text.rs diff --git a/examples/weather.rs b/old/examples/weather.rs similarity index 100% rename from examples/weather.rs rename to old/examples/weather.rs diff --git a/examples/world_border.rs b/old/examples/world_border.rs similarity index 100% rename from examples/world_border.rs rename to old/examples/world_border.rs diff --git a/old/src/lib.rs b/old/src/lib.rs new file mode 100644 index 000000000..7a3dbfd8e --- /dev/null +++ b/old/src/lib.rs @@ -0,0 +1,258 @@ +#![cfg_attr( + unstable_doc, + doc = "**❗ NOTE:** This documentation is sourced from the `main` branch. If you're looking for the most recent stable release, go [here](https://docs.rs/valence/latest/valence/).\n\n---\n" +)] +#![doc = include_str!("../README.md")] +#![doc( + html_logo_url = "https://raw.githubusercontent.com/valence-rs/valence/main/assets/logo.svg", + html_favicon_url = "https://raw.githubusercontent.com/valence-rs/valence/main/assets/logo.svg" +)] +#![deny( + rustdoc::broken_intra_doc_links, + rustdoc::private_intra_doc_links, + rustdoc::missing_crate_level_docs, + rustdoc::invalid_codeblock_attributes, + rustdoc::invalid_rust_codeblocks, + rustdoc::bare_urls, + rustdoc::invalid_html_tags +)] +#![warn( + trivial_casts, + trivial_numeric_casts, + unused_lifetimes, + unused_import_braces, + unreachable_pub, + clippy::dbg_macro +)] + +use bevy_app::{PluginGroup, PluginGroupBuilder}; + +#[cfg(feature = "testing")] +pub mod testing; + +#[cfg(test)] +mod tests; + +#[cfg(feature = "log")] +pub use bevy_log as log; +use registry::biome::BiomePlugin; +use registry::dimension_type::DimensionTypePlugin; +#[cfg(feature = "advancement")] +pub use valence_advancement as advancement; +#[cfg(feature = "anvil")] +pub use valence_anvil as anvil; +#[cfg(feature = "boss_bar")] +pub use valence_boss_bar as boss_bar; +#[cfg(feature = "command")] +pub use valence_command as command; +#[cfg(feature = "command")] +pub use valence_command_macros as command_macros; +#[cfg(feature = "inventory")] +pub use valence_inventory as inventory; +pub use valence_lang as lang; +#[cfg(feature = "network")] +pub use valence_network as network; +#[cfg(feature = "player_list")] +pub use valence_player_list as player_list; +use valence_registry::RegistryPlugin; +#[cfg(feature = "scoreboard")] +pub use valence_scoreboard as scoreboard; +use valence_server::abilities::AbilitiesPlugin; +use valence_server::action::ActionPlugin; +use valence_server::client::ClientPlugin; +use valence_server::client_command::ClientCommandPlugin; +use valence_server::client_settings::ClientSettingsPlugin; +use valence_server::custom_payload::CustomPayloadPlugin; +use valence_server::entity::hitbox::HitboxPlugin; +use valence_server::entity::EntityPlugin; +use valence_server::event_loop::EventLoopPlugin; +use valence_server::hand_swing::HandSwingPlugin; +use valence_server::interact_block::InteractBlockPlugin; +use valence_server::interact_entity::InteractEntityPlugin; +use valence_server::interact_item::InteractItemPlugin; +use valence_server::keepalive::KeepalivePlugin; +use valence_server::layer::LayerPlugin; +use valence_server::message::MessagePlugin; +use valence_server::movement::MovementPlugin; +use valence_server::op_level::OpLevelPlugin; +pub use valence_server::protocol::status_effects; +use valence_server::resource_pack::ResourcePackPlugin; +use valence_server::status::StatusPlugin; +use valence_server::status_effect::StatusEffectPlugin; +use valence_server::teleport::TeleportPlugin; +pub use valence_server::*; +#[cfg(feature = "weather")] +pub use valence_weather as weather; +#[cfg(feature = "world_border")] +pub use valence_world_border as world_border; + +/// Contains the most frequently used items in Valence projects. +/// +/// This is usually glob imported like so: +/// +/// ``` +/// use valence::prelude::*; // Glob import. +/// +/// let mut app = App::new(); +/// app.add_systems(Update, || println!("yippee!")); +/// // ... +/// ``` +pub mod prelude { + pub use bevy_app::prelude::*; + pub use bevy_ecs; // Needed for bevy_ecs macros to function correctly. + pub use bevy_ecs::prelude::*; + pub use uuid::Uuid; + #[cfg(feature = "advancement")] + pub use valence_advancement::{ + event::AdvancementTabChangeEvent, Advancement, AdvancementBundle, AdvancementClientUpdate, + AdvancementCriteria, AdvancementDisplay, AdvancementFrameType, AdvancementRequirements, + }; + #[cfg(feature = "inventory")] + pub use valence_inventory::{ + CursorItem, Inventory, InventoryKind, InventoryWindow, InventoryWindowMut, OpenInventory, + }; + #[cfg(feature = "network")] + pub use valence_network::{ + ConnectionMode, ErasedNetworkCallbacks, NetworkCallbacks, NetworkSettings, NewClientInfo, + SharedNetworkState, + }; + #[cfg(feature = "player_list")] + pub use valence_player_list::{PlayerList, PlayerListEntry}; + pub use valence_registry::biome::{Biome, BiomeId, BiomeRegistry}; + pub use valence_registry::dimension_type::{DimensionType, DimensionTypeRegistry}; + pub use valence_server::action::{DiggingEvent, DiggingState}; + pub use valence_server::block::{BlockKind, BlockState, PropName, PropValue}; + pub use valence_server::client::{ + despawn_disconnected_clients, Client, Ip, OldView, OldViewDistance, Properties, Username, + View, ViewDistance, VisibleChunkLayer, VisibleEntityLayers, + }; + pub use valence_server::client_command::{ + ClientCommand, JumpWithHorseEvent, JumpWithHorseState, LeaveBedEvent, SneakEvent, + SneakState, SprintEvent, SprintState, + }; + pub use valence_server::entity::hitbox::{Hitbox, HitboxShape}; + pub use valence_server::entity::{ + EntityAnimation, EntityKind, EntityLayerId, EntityManager, EntityStatus, HeadYaw, Look, + OldEntityLayerId, OldPosition, Position, + }; + pub use valence_server::event_loop::{ + EventLoopPostUpdate, EventLoopPreUpdate, EventLoopUpdate, + }; + pub use valence_server::ident::Ident; + pub use valence_server::interact_entity::{EntityInteraction, InteractEntityEvent}; + pub use valence_server::layer::chunk::{ + Block, BlockRef, Chunk, ChunkLayer, LoadedChunk, UnloadedChunk, + }; + pub use valence_server::layer::{EntityLayer, LayerBundle}; + pub use valence_server::math::{DVec2, DVec3, Vec2, Vec3}; + pub use valence_server::message::SendMessage as _; + pub use valence_server::nbt::Compound; + pub use valence_server::protocol::packets::play::particle_s2c::Particle; + pub use valence_server::protocol::text::{Color, IntoText, Text}; + pub use valence_server::spawn::{ClientSpawnQuery, ClientSpawnQueryReadOnly, RespawnPosition}; + pub use valence_server::title::SetTitle as _; + pub use valence_server::{ + ident, BlockPos, ChunkPos, ChunkView, Despawned, Direction, GameMode, Hand, ItemKind, + ItemStack, Server, UniqueId, + }; + + pub use super::DefaultPlugins; +} + +/// This plugin group will add all the default plugins for a Valence +/// application. +/// +/// [`DefaultPlugins`] obeys Cargo feature flags. Users may exert control over +/// this plugin group by disabling `default-features` in their `Cargo.toml` and +/// enabling only those features that they wish to use. +pub struct DefaultPlugins; + +impl PluginGroup for DefaultPlugins { + fn build(self) -> PluginGroupBuilder { + #[allow(unused_mut)] + let mut group = PluginGroupBuilder::start::() + .add(ServerPlugin) + .add(RegistryPlugin) + .add(BiomePlugin) + .add(DimensionTypePlugin) + .add(EntityPlugin) + .add(HitboxPlugin) + .add(LayerPlugin) + .add(ClientPlugin) + .add(EventLoopPlugin) + .add(MovementPlugin) + .add(ClientCommandPlugin) + .add(KeepalivePlugin) + .add(InteractEntityPlugin) + .add(ClientSettingsPlugin) + .add(ActionPlugin) + .add(TeleportPlugin) + .add(MessagePlugin) + .add(CustomPayloadPlugin) + .add(HandSwingPlugin) + .add(InteractBlockPlugin) + .add(InteractItemPlugin) + .add(OpLevelPlugin) + .add(ResourcePackPlugin) + .add(StatusPlugin) + .add(StatusEffectPlugin) + .add(AbilitiesPlugin); + + #[cfg(feature = "log")] + { + group = group.add(bevy_log::LogPlugin::default()); + } + + #[cfg(feature = "network")] + { + group = group.add(valence_network::NetworkPlugin); + } + + #[cfg(feature = "player_list")] + { + group = group.add(valence_player_list::PlayerListPlugin); + } + + #[cfg(feature = "inventory")] + { + group = group.add(valence_inventory::InventoryPlugin); + } + + #[cfg(feature = "anvil")] + { + group = group.add(valence_anvil::AnvilPlugin); + } + + #[cfg(feature = "advancement")] + { + group = group.add(valence_advancement::AdvancementPlugin) + } + + #[cfg(feature = "weather")] + { + group = group.add(valence_weather::WeatherPlugin); + } + + #[cfg(feature = "world_border")] + { + group = group.add(valence_world_border::WorldBorderPlugin); + } + + #[cfg(feature = "boss_bar")] + { + group = group.add(valence_boss_bar::BossBarPlugin); + } + + #[cfg(feature = "command")] + { + group = group.add(valence_command::manager::CommandPlugin); + } + + #[cfg(feature = "scoreboard")] + { + group = group.add(valence_scoreboard::ScoreboardPlugin); + } + + group + } +} diff --git a/src/testing.rs b/old/src/testing.rs similarity index 100% rename from src/testing.rs rename to old/src/testing.rs diff --git a/src/tests.rs b/old/src/tests.rs similarity index 100% rename from src/tests.rs rename to old/src/tests.rs diff --git a/src/tests/boss_bar.rs b/old/src/tests/boss_bar.rs similarity index 100% rename from src/tests/boss_bar.rs rename to old/src/tests/boss_bar.rs diff --git a/src/tests/client.rs b/old/src/tests/client.rs similarity index 100% rename from src/tests/client.rs rename to old/src/tests/client.rs diff --git a/src/tests/example.rs b/old/src/tests/example.rs similarity index 100% rename from src/tests/example.rs rename to old/src/tests/example.rs diff --git a/src/tests/hunger.rs b/old/src/tests/hunger.rs similarity index 100% rename from src/tests/hunger.rs rename to old/src/tests/hunger.rs diff --git a/src/tests/inventory.rs b/old/src/tests/inventory.rs similarity index 100% rename from src/tests/inventory.rs rename to old/src/tests/inventory.rs diff --git a/src/tests/layer.rs b/old/src/tests/layer.rs similarity index 100% rename from src/tests/layer.rs rename to old/src/tests/layer.rs diff --git a/src/tests/player_list.rs b/old/src/tests/player_list.rs similarity index 100% rename from src/tests/player_list.rs rename to old/src/tests/player_list.rs diff --git a/src/tests/potions.rs b/old/src/tests/potions.rs similarity index 100% rename from src/tests/potions.rs rename to old/src/tests/potions.rs diff --git a/src/tests/scoreboard.rs b/old/src/tests/scoreboard.rs similarity index 100% rename from src/tests/scoreboard.rs rename to old/src/tests/scoreboard.rs diff --git a/src/tests/weather.rs b/old/src/tests/weather.rs similarity index 100% rename from src/tests/weather.rs rename to old/src/tests/weather.rs diff --git a/src/tests/world_border.rs b/old/src/tests/world_border.rs similarity index 100% rename from src/tests/world_border.rs rename to old/src/tests/world_border.rs diff --git a/tools/dump_schedule/Cargo.toml b/old/tools/dump_schedule/Cargo.toml similarity index 100% rename from tools/dump_schedule/Cargo.toml rename to old/tools/dump_schedule/Cargo.toml diff --git a/tools/dump_schedule/README.md b/old/tools/dump_schedule/README.md similarity index 100% rename from tools/dump_schedule/README.md rename to old/tools/dump_schedule/README.md diff --git a/tools/dump_schedule/src/main.rs b/old/tools/dump_schedule/src/main.rs similarity index 100% rename from tools/dump_schedule/src/main.rs rename to old/tools/dump_schedule/src/main.rs diff --git a/tools/packet_inspector/Cargo.toml b/old/tools/packet_inspector/Cargo.toml similarity index 100% rename from tools/packet_inspector/Cargo.toml rename to old/tools/packet_inspector/Cargo.toml diff --git a/tools/packet_inspector/README.md b/old/tools/packet_inspector/README.md similarity index 100% rename from tools/packet_inspector/README.md rename to old/tools/packet_inspector/README.md diff --git a/tools/packet_inspector/build.rs b/old/tools/packet_inspector/build.rs similarity index 100% rename from tools/packet_inspector/build.rs rename to old/tools/packet_inspector/build.rs diff --git a/tools/packet_inspector/extracted/packets.json b/old/tools/packet_inspector/extracted/packets.json similarity index 100% rename from tools/packet_inspector/extracted/packets.json rename to old/tools/packet_inspector/extracted/packets.json diff --git a/tools/packet_inspector/src/app.rs b/old/tools/packet_inspector/src/app.rs similarity index 100% rename from tools/packet_inspector/src/app.rs rename to old/tools/packet_inspector/src/app.rs diff --git a/tools/packet_inspector/src/app/connection.rs b/old/tools/packet_inspector/src/app/connection.rs similarity index 100% rename from tools/packet_inspector/src/app/connection.rs rename to old/tools/packet_inspector/src/app/connection.rs diff --git a/tools/packet_inspector/src/app/filter.rs b/old/tools/packet_inspector/src/app/filter.rs similarity index 100% rename from tools/packet_inspector/src/app/filter.rs rename to old/tools/packet_inspector/src/app/filter.rs diff --git a/tools/packet_inspector/src/app/hex_viewer.rs b/old/tools/packet_inspector/src/app/hex_viewer.rs similarity index 100% rename from tools/packet_inspector/src/app/hex_viewer.rs rename to old/tools/packet_inspector/src/app/hex_viewer.rs diff --git a/tools/packet_inspector/src/app/packet_list.rs b/old/tools/packet_inspector/src/app/packet_list.rs similarity index 100% rename from tools/packet_inspector/src/app/packet_list.rs rename to old/tools/packet_inspector/src/app/packet_list.rs diff --git a/tools/packet_inspector/src/app/text_viewer.rs b/old/tools/packet_inspector/src/app/text_viewer.rs similarity index 100% rename from tools/packet_inspector/src/app/text_viewer.rs rename to old/tools/packet_inspector/src/app/text_viewer.rs diff --git a/tools/packet_inspector/src/lib.rs b/old/tools/packet_inspector/src/lib.rs similarity index 100% rename from tools/packet_inspector/src/lib.rs rename to old/tools/packet_inspector/src/lib.rs diff --git a/tools/packet_inspector/src/main.rs b/old/tools/packet_inspector/src/main.rs similarity index 100% rename from tools/packet_inspector/src/main.rs rename to old/tools/packet_inspector/src/main.rs diff --git a/tools/packet_inspector/src/main_cli.rs b/old/tools/packet_inspector/src/main_cli.rs similarity index 100% rename from tools/packet_inspector/src/main_cli.rs rename to old/tools/packet_inspector/src/main_cli.rs diff --git a/tools/packet_inspector/src/packet_io.rs b/old/tools/packet_inspector/src/packet_io.rs similarity index 100% rename from tools/packet_inspector/src/packet_io.rs rename to old/tools/packet_inspector/src/packet_io.rs diff --git a/tools/packet_inspector/src/packet_registry.rs b/old/tools/packet_inspector/src/packet_registry.rs similarity index 100% rename from tools/packet_inspector/src/packet_registry.rs rename to old/tools/packet_inspector/src/packet_registry.rs diff --git a/tools/packet_inspector/src/shared_state.rs b/old/tools/packet_inspector/src/shared_state.rs similarity index 100% rename from tools/packet_inspector/src/shared_state.rs rename to old/tools/packet_inspector/src/shared_state.rs diff --git a/tools/packet_inspector/src/tri_checkbox.rs b/old/tools/packet_inspector/src/tri_checkbox.rs similarity index 100% rename from tools/packet_inspector/src/tri_checkbox.rs rename to old/tools/packet_inspector/src/tri_checkbox.rs diff --git a/tools/playground/Cargo.toml b/old/tools/playground/Cargo.toml similarity index 100% rename from tools/playground/Cargo.toml rename to old/tools/playground/Cargo.toml diff --git a/tools/playground/README.md b/old/tools/playground/README.md similarity index 100% rename from tools/playground/README.md rename to old/tools/playground/README.md diff --git a/tools/playground/build.rs b/old/tools/playground/build.rs similarity index 100% rename from tools/playground/build.rs rename to old/tools/playground/build.rs diff --git a/tools/playground/src/.gitignore b/old/tools/playground/src/.gitignore similarity index 100% rename from tools/playground/src/.gitignore rename to old/tools/playground/src/.gitignore diff --git a/tools/playground/src/extras.rs b/old/tools/playground/src/extras.rs similarity index 100% rename from tools/playground/src/extras.rs rename to old/tools/playground/src/extras.rs diff --git a/tools/playground/src/main.rs b/old/tools/playground/src/main.rs similarity index 100% rename from tools/playground/src/main.rs rename to old/tools/playground/src/main.rs diff --git a/tools/playground/src/playground.template.rs b/old/tools/playground/src/playground.template.rs similarity index 100% rename from tools/playground/src/playground.template.rs rename to old/tools/playground/src/playground.template.rs diff --git a/tools/stresser/Cargo.toml b/old/tools/stresser/Cargo.toml similarity index 100% rename from tools/stresser/Cargo.toml rename to old/tools/stresser/Cargo.toml diff --git a/tools/stresser/README.md b/old/tools/stresser/README.md similarity index 100% rename from tools/stresser/README.md rename to old/tools/stresser/README.md diff --git a/tools/stresser/src/args.rs b/old/tools/stresser/src/args.rs similarity index 100% rename from tools/stresser/src/args.rs rename to old/tools/stresser/src/args.rs diff --git a/tools/stresser/src/main.rs b/old/tools/stresser/src/main.rs similarity index 100% rename from tools/stresser/src/main.rs rename to old/tools/stresser/src/main.rs diff --git a/tools/stresser/src/stresser.rs b/old/tools/stresser/src/stresser.rs similarity index 100% rename from tools/stresser/src/stresser.rs rename to old/tools/stresser/src/stresser.rs diff --git a/rustfmt.toml b/rustfmt.toml index 7788221a5..f48e486e8 100644 --- a/rustfmt.toml +++ b/rustfmt.toml @@ -5,7 +5,7 @@ imports_granularity = "Module" group_imports = "StdExternalCrate" format_code_in_doc_comments = true format_macro_matchers = true -hex_literal_case = "Lower" +hex_literal_case = "Upper" format_strings = true use_field_init_shorthand = true use_try_shorthand = true diff --git a/src/lib.rs b/src/lib.rs index 7a3dbfd8e..e69de29bb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,258 +0,0 @@ -#![cfg_attr( - unstable_doc, - doc = "**❗ NOTE:** This documentation is sourced from the `main` branch. If you're looking for the most recent stable release, go [here](https://docs.rs/valence/latest/valence/).\n\n---\n" -)] -#![doc = include_str!("../README.md")] -#![doc( - html_logo_url = "https://raw.githubusercontent.com/valence-rs/valence/main/assets/logo.svg", - html_favicon_url = "https://raw.githubusercontent.com/valence-rs/valence/main/assets/logo.svg" -)] -#![deny( - rustdoc::broken_intra_doc_links, - rustdoc::private_intra_doc_links, - rustdoc::missing_crate_level_docs, - rustdoc::invalid_codeblock_attributes, - rustdoc::invalid_rust_codeblocks, - rustdoc::bare_urls, - rustdoc::invalid_html_tags -)] -#![warn( - trivial_casts, - trivial_numeric_casts, - unused_lifetimes, - unused_import_braces, - unreachable_pub, - clippy::dbg_macro -)] - -use bevy_app::{PluginGroup, PluginGroupBuilder}; - -#[cfg(feature = "testing")] -pub mod testing; - -#[cfg(test)] -mod tests; - -#[cfg(feature = "log")] -pub use bevy_log as log; -use registry::biome::BiomePlugin; -use registry::dimension_type::DimensionTypePlugin; -#[cfg(feature = "advancement")] -pub use valence_advancement as advancement; -#[cfg(feature = "anvil")] -pub use valence_anvil as anvil; -#[cfg(feature = "boss_bar")] -pub use valence_boss_bar as boss_bar; -#[cfg(feature = "command")] -pub use valence_command as command; -#[cfg(feature = "command")] -pub use valence_command_macros as command_macros; -#[cfg(feature = "inventory")] -pub use valence_inventory as inventory; -pub use valence_lang as lang; -#[cfg(feature = "network")] -pub use valence_network as network; -#[cfg(feature = "player_list")] -pub use valence_player_list as player_list; -use valence_registry::RegistryPlugin; -#[cfg(feature = "scoreboard")] -pub use valence_scoreboard as scoreboard; -use valence_server::abilities::AbilitiesPlugin; -use valence_server::action::ActionPlugin; -use valence_server::client::ClientPlugin; -use valence_server::client_command::ClientCommandPlugin; -use valence_server::client_settings::ClientSettingsPlugin; -use valence_server::custom_payload::CustomPayloadPlugin; -use valence_server::entity::hitbox::HitboxPlugin; -use valence_server::entity::EntityPlugin; -use valence_server::event_loop::EventLoopPlugin; -use valence_server::hand_swing::HandSwingPlugin; -use valence_server::interact_block::InteractBlockPlugin; -use valence_server::interact_entity::InteractEntityPlugin; -use valence_server::interact_item::InteractItemPlugin; -use valence_server::keepalive::KeepalivePlugin; -use valence_server::layer::LayerPlugin; -use valence_server::message::MessagePlugin; -use valence_server::movement::MovementPlugin; -use valence_server::op_level::OpLevelPlugin; -pub use valence_server::protocol::status_effects; -use valence_server::resource_pack::ResourcePackPlugin; -use valence_server::status::StatusPlugin; -use valence_server::status_effect::StatusEffectPlugin; -use valence_server::teleport::TeleportPlugin; -pub use valence_server::*; -#[cfg(feature = "weather")] -pub use valence_weather as weather; -#[cfg(feature = "world_border")] -pub use valence_world_border as world_border; - -/// Contains the most frequently used items in Valence projects. -/// -/// This is usually glob imported like so: -/// -/// ``` -/// use valence::prelude::*; // Glob import. -/// -/// let mut app = App::new(); -/// app.add_systems(Update, || println!("yippee!")); -/// // ... -/// ``` -pub mod prelude { - pub use bevy_app::prelude::*; - pub use bevy_ecs; // Needed for bevy_ecs macros to function correctly. - pub use bevy_ecs::prelude::*; - pub use uuid::Uuid; - #[cfg(feature = "advancement")] - pub use valence_advancement::{ - event::AdvancementTabChangeEvent, Advancement, AdvancementBundle, AdvancementClientUpdate, - AdvancementCriteria, AdvancementDisplay, AdvancementFrameType, AdvancementRequirements, - }; - #[cfg(feature = "inventory")] - pub use valence_inventory::{ - CursorItem, Inventory, InventoryKind, InventoryWindow, InventoryWindowMut, OpenInventory, - }; - #[cfg(feature = "network")] - pub use valence_network::{ - ConnectionMode, ErasedNetworkCallbacks, NetworkCallbacks, NetworkSettings, NewClientInfo, - SharedNetworkState, - }; - #[cfg(feature = "player_list")] - pub use valence_player_list::{PlayerList, PlayerListEntry}; - pub use valence_registry::biome::{Biome, BiomeId, BiomeRegistry}; - pub use valence_registry::dimension_type::{DimensionType, DimensionTypeRegistry}; - pub use valence_server::action::{DiggingEvent, DiggingState}; - pub use valence_server::block::{BlockKind, BlockState, PropName, PropValue}; - pub use valence_server::client::{ - despawn_disconnected_clients, Client, Ip, OldView, OldViewDistance, Properties, Username, - View, ViewDistance, VisibleChunkLayer, VisibleEntityLayers, - }; - pub use valence_server::client_command::{ - ClientCommand, JumpWithHorseEvent, JumpWithHorseState, LeaveBedEvent, SneakEvent, - SneakState, SprintEvent, SprintState, - }; - pub use valence_server::entity::hitbox::{Hitbox, HitboxShape}; - pub use valence_server::entity::{ - EntityAnimation, EntityKind, EntityLayerId, EntityManager, EntityStatus, HeadYaw, Look, - OldEntityLayerId, OldPosition, Position, - }; - pub use valence_server::event_loop::{ - EventLoopPostUpdate, EventLoopPreUpdate, EventLoopUpdate, - }; - pub use valence_server::ident::Ident; - pub use valence_server::interact_entity::{EntityInteraction, InteractEntityEvent}; - pub use valence_server::layer::chunk::{ - Block, BlockRef, Chunk, ChunkLayer, LoadedChunk, UnloadedChunk, - }; - pub use valence_server::layer::{EntityLayer, LayerBundle}; - pub use valence_server::math::{DVec2, DVec3, Vec2, Vec3}; - pub use valence_server::message::SendMessage as _; - pub use valence_server::nbt::Compound; - pub use valence_server::protocol::packets::play::particle_s2c::Particle; - pub use valence_server::protocol::text::{Color, IntoText, Text}; - pub use valence_server::spawn::{ClientSpawnQuery, ClientSpawnQueryReadOnly, RespawnPosition}; - pub use valence_server::title::SetTitle as _; - pub use valence_server::{ - ident, BlockPos, ChunkPos, ChunkView, Despawned, Direction, GameMode, Hand, ItemKind, - ItemStack, Server, UniqueId, - }; - - pub use super::DefaultPlugins; -} - -/// This plugin group will add all the default plugins for a Valence -/// application. -/// -/// [`DefaultPlugins`] obeys Cargo feature flags. Users may exert control over -/// this plugin group by disabling `default-features` in their `Cargo.toml` and -/// enabling only those features that they wish to use. -pub struct DefaultPlugins; - -impl PluginGroup for DefaultPlugins { - fn build(self) -> PluginGroupBuilder { - #[allow(unused_mut)] - let mut group = PluginGroupBuilder::start::() - .add(ServerPlugin) - .add(RegistryPlugin) - .add(BiomePlugin) - .add(DimensionTypePlugin) - .add(EntityPlugin) - .add(HitboxPlugin) - .add(LayerPlugin) - .add(ClientPlugin) - .add(EventLoopPlugin) - .add(MovementPlugin) - .add(ClientCommandPlugin) - .add(KeepalivePlugin) - .add(InteractEntityPlugin) - .add(ClientSettingsPlugin) - .add(ActionPlugin) - .add(TeleportPlugin) - .add(MessagePlugin) - .add(CustomPayloadPlugin) - .add(HandSwingPlugin) - .add(InteractBlockPlugin) - .add(InteractItemPlugin) - .add(OpLevelPlugin) - .add(ResourcePackPlugin) - .add(StatusPlugin) - .add(StatusEffectPlugin) - .add(AbilitiesPlugin); - - #[cfg(feature = "log")] - { - group = group.add(bevy_log::LogPlugin::default()); - } - - #[cfg(feature = "network")] - { - group = group.add(valence_network::NetworkPlugin); - } - - #[cfg(feature = "player_list")] - { - group = group.add(valence_player_list::PlayerListPlugin); - } - - #[cfg(feature = "inventory")] - { - group = group.add(valence_inventory::InventoryPlugin); - } - - #[cfg(feature = "anvil")] - { - group = group.add(valence_anvil::AnvilPlugin); - } - - #[cfg(feature = "advancement")] - { - group = group.add(valence_advancement::AdvancementPlugin) - } - - #[cfg(feature = "weather")] - { - group = group.add(valence_weather::WeatherPlugin); - } - - #[cfg(feature = "world_border")] - { - group = group.add(valence_world_border::WorldBorderPlugin); - } - - #[cfg(feature = "boss_bar")] - { - group = group.add(valence_boss_bar::BossBarPlugin); - } - - #[cfg(feature = "command")] - { - group = group.add(valence_command::manager::CommandPlugin); - } - - #[cfg(feature = "scoreboard")] - { - group = group.add(valence_scoreboard::ScoreboardPlugin); - } - - group - } -}