fix: apply clippy lints to workspace

also add contributors to /pumpkin command

Co-Authored-By: Fyor <90567841+fyordev@users.noreply.github.com>
Co-Authored-By: MartV0 <34748938+martv0@users.noreply.github.com>
Co-Authored-By: FabseGP <fabsegp@fabseman.space>
This commit is contained in:
Alexander Medvedev 2026-01-28 00:52:47 +01:00
parent 3776b225e4
commit fb13004b47
263 changed files with 2173 additions and 1651 deletions

View File

@ -12,6 +12,50 @@ members = [
"pumpkin-data", "pumpkin-data",
] ]
[workspace.lints.clippy]
# Groups
all = { level = "deny", priority = -1 }
# nursery = { level = "deny", priority = -1 }
pedantic = { level = "deny", priority = -1 }
cargo = { level = "deny", priority = -1 }
if_then_some_else_none = "deny"
empty_enum_variants_with_brackets = "deny"
empty_structs_with_brackets = "deny"
separated_literal_suffix = "deny"
semicolon_outside_block = "deny"
non_zero_suggestions = "deny"
string_lit_chars_any = "deny"
use_self = "deny"
useless_let_if_seq = "deny"
branches_sharing_code = "deny"
equatable_if_let = "deny"
option_if_let_else = "deny"
needless_pass_by_ref_mut = "deny"
needless_collect = "deny"
redundant_clone = "deny"
set_contains_or_insert = "deny"
significant_drop_in_scrutinee = "deny"
print_stdout = "deny"
print_stderr = "deny"
# Expected/Allowed
cargo_common_metadata = "allow"
cast_precision_loss = "allow"
multiple_crate_versions = "allow"
single_call_fn = "allow"
unreadable_literal = "allow"
cast_lossless = "allow"
cast_sign_loss = "allow"
float_cmp = "allow"
cast_possible_truncation = "allow"
cast_possible_wrap = "allow"
missing_panics_doc = "allow"
missing_errors_doc = "allow"
module_name_repetitions = "allow"
struct_excessive_bools = "allow"
[workspace.package] [workspace.package]
version = "0.1.0-dev+1.21.11" version = "0.1.0-dev+1.21.11"
edition = "2024" edition = "2024"
@ -108,7 +152,7 @@ take_mut = "0.2.2"
temp-dir = "0.1.16" temp-dir = "0.1.16"
thread_local = "1.1.9" thread_local = "1.1.9"
time = "0.3" time = "0.3"
arc-swap = "1.7" arc-swap = "1.8"
tokio-util = "0.7.18" tokio-util = "0.7.18"
toml = "0.9" toml = "0.9"
ureq = "3.1.4" ureq = "3.1.4"

View File

@ -12,3 +12,6 @@ syn .workspace = true
quote.workspace = true quote.workspace = true
proc-macro2.workspace = true proc-macro2.workspace = true
proc-macro-error2.workspace = true proc-macro-error2.workspace = true
[lints]
workspace = true

View File

@ -15,3 +15,6 @@ toml.workspace = true
[features] [features]
# Adds helper to change the config at runtime # Adds helper to change the config at runtime
test_helper = [] test_helper = []
[lints]
workspace = true

View File

@ -13,7 +13,7 @@ pub enum ChunkConfig {
impl Default for ChunkConfig { impl Default for ChunkConfig {
fn default() -> Self { fn default() -> Self {
Self::Anvil(Default::default()) Self::Anvil(AnvilChunkConfig::default())
} }
} }
@ -41,9 +41,9 @@ impl Default for ChunkCompression {
#[derive(Deserialize, Serialize, Clone, Copy)] #[derive(Deserialize, Serialize, Clone, Copy)]
pub enum Compression { pub enum Compression {
/// GZip Compression /// `GZip` Compression
GZip, GZip,
/// ZLib Compression /// `ZLib` Compression
ZLib, ZLib,
/// LZ4 Compression (since 24w04a) /// LZ4 Compression (since 24w04a)
LZ4, LZ4,

View File

@ -149,12 +149,16 @@ impl Default for BasicConfiguration {
} }
impl BasicConfiguration { impl BasicConfiguration {
#[must_use]
pub fn get_world_path(&self) -> PathBuf { pub fn get_world_path(&self) -> PathBuf {
PathBuf::from(&self.default_level_name) PathBuf::from(&self.default_level_name)
} }
} }
pub trait LoadConfiguration { pub trait LoadConfiguration {
#[must_use]
// Logger is may not ready
#[expect(clippy::print_stdout)]
fn load(config_dir: &Path) -> Self fn load(config_dir: &Path) -> Self
where where
Self: Sized + Default + Serialize + DeserializeOwned, Self: Sized + Default + Serialize + DeserializeOwned,
@ -166,14 +170,15 @@ pub trait LoadConfiguration {
let path = config_dir.join(Self::get_path()); let path = config_dir.join(Self::get_path());
let config = if path.exists() { let config = if path.exists() {
let file_content = fs::read_to_string(&path) let file_content = fs::read_to_string(&path).unwrap_or_else(|_| {
.unwrap_or_else(|_| panic!("Couldn't read configuration file at {:?}", &path)); panic!("Couldn't read configuration file at {}", path.display())
});
let parsed_toml_value: toml::Value = toml::from_str(&file_content) let parsed_toml_value: toml::Value = toml::from_str(&file_content)
.unwrap_or_else(|err| { .unwrap_or_else(|err| {
panic!( panic!(
"Couldn't parse TOML at {:?}. Reason: {}. This is probably caused by invalid TOML syntax", "Couldn't parse TOML at {}. Reason: {}. This is probably caused by invalid TOML syntax",
&path, err path.display(), err
) )
}); });
@ -186,8 +191,8 @@ pub trait LoadConfiguration {
); );
if let Err(err) = fs::write(&path, toml::to_string(&merged_config).unwrap()) { if let Err(err) = fs::write(&path, toml::to_string(&merged_config).unwrap()) {
log::warn!( log::warn!(
"Couldn't write merged config to {:?}. Reason: {}", "Couldn't write merged config to {}. Reason: {}",
&path, path.display(),
err err
); );
} }
@ -200,7 +205,7 @@ pub trait LoadConfiguration {
if let Err(err) = fs::write(&path, toml::to_string(&content).unwrap()) { if let Err(err) = fs::write(&path, toml::to_string(&content).unwrap()) {
log::warn!( log::warn!(
"Couldn't write default config to {:?}. Reason: {}", "Couldn't write default config to {:?}. Reason: {}",
&path, path.display(),
err err
); );
} }
@ -212,6 +217,7 @@ pub trait LoadConfiguration {
config config
} }
#[must_use]
fn merge_with_default_toml(parsed_toml: toml::Value) -> (Self, bool) fn merge_with_default_toml(parsed_toml: toml::Value) -> (Self, bool)
where where
Self: Sized + Default + Serialize + DeserializeOwned, Self: Sized + Default + Serialize + DeserializeOwned,
@ -221,8 +227,7 @@ pub trait LoadConfiguration {
let default_toml_value = let default_toml_value =
toml::Value::try_from(default_config).expect("Failed to parse default config"); toml::Value::try_from(default_config).expect("Failed to parse default config");
let (merged_value, changed) = let (merged_value, changed) = Self::merge_toml_values(default_toml_value, parsed_toml);
Self::merge_toml_values(default_toml_value, parsed_toml.clone());
let config = merged_value let config = merged_value
.try_into() .try_into()
@ -231,6 +236,7 @@ pub trait LoadConfiguration {
(config, changed) (config, changed)
} }
#[must_use]
fn merge_toml_values(base: toml::Value, overlay: toml::Value) -> (toml::Value, bool) { fn merge_toml_values(base: toml::Value, overlay: toml::Value) -> (toml::Value, bool) {
match (base, overlay) { match (base, overlay) {
(toml::Value::Table(mut base_table), toml::Value::Table(overlay_table)) => { (toml::Value::Table(mut base_table), toml::Value::Table(overlay_table)) => {
@ -272,7 +278,7 @@ impl LoadConfiguration for AdvancedConfiguration {
} }
fn validate(&self) { fn validate(&self) {
self.resource_pack.validate() self.resource_pack.validate();
} }
} }
@ -297,13 +303,13 @@ impl LoadConfiguration for BasicConfiguration {
assert!( assert!(
self.encryption, self.encryption,
"When online mode is enabled, encryption must be enabled" "When online mode is enabled, encryption must be enabled"
) );
} }
if self.allow_chat_reports { if self.allow_chat_reports {
assert!( assert!(
self.online_mode, self.online_mode,
"When allow_chat_reports is enabled, online_mode must be enabled" "When allow_chat_reports is enabled, online_mode must be enabled"
) );
} }
} }
} }

View File

@ -24,8 +24,8 @@ impl Default for AuthenticationConfig {
Self { Self {
enabled: true, enabled: true,
prevent_proxy_connections: false, prevent_proxy_connections: false,
player_profile: Default::default(), player_profile: PlayerProfileConfig::default(),
textures: Default::default(), textures: TextureConfig::default(),
url: None, url: None,
prevent_proxy_connection_auth_url: None, prevent_proxy_connection_auth_url: None,
services_url: None, services_url: None,
@ -75,7 +75,7 @@ impl Default for TextureConfig {
enabled: true, enabled: true,
allowed_url_schemes: vec!["http".into(), "https".into()], allowed_url_schemes: vec!["http".into(), "https".into()],
allowed_url_domains: vec![".minecraft.net".into(), ".mojang.com".into()], allowed_url_domains: vec![".minecraft.net".into(), ".mojang.com".into()],
types: Default::default(), types: TextureTypes::default(),
} }
} }
} }

View File

@ -14,7 +14,7 @@ impl Default for CompressionConfig {
fn default() -> Self { fn default() -> Self {
Self { Self {
enabled: true, enabled: true,
info: Default::default(), info: CompressionInfo::default(),
} }
} }
} }

View File

@ -13,7 +13,7 @@ impl Default for QueryConfig {
fn default() -> Self { fn default() -> Self {
Self { Self {
enabled: true, enabled: true,
address: SocketAddr::new(Ipv4Addr::new(0, 0, 0, 0).into(), 25565), address: SocketAddr::new(Ipv4Addr::UNSPECIFIED.into(), 25565),
} }
} }
} }

View File

@ -21,10 +21,10 @@ impl Default for RCONConfig {
fn default() -> Self { fn default() -> Self {
Self { Self {
enabled: false, enabled: false,
address: SocketAddr::new(Ipv4Addr::new(0, 0, 0, 0).into(), 25575), address: SocketAddr::new(Ipv4Addr::UNSPECIFIED.into(), 25575),
password: "".to_string(), password: String::new(),
max_connections: 0, max_connections: 0,
logging: Default::default(), logging: RCONLogging::default(),
} }
} }
} }

View File

@ -11,6 +11,7 @@ pub struct Op {
} }
impl Op { impl Op {
#[must_use]
pub fn new( pub fn new(
uuid: Uuid, uuid: Uuid,
name: String, name: String,

View File

@ -30,6 +30,6 @@ impl ResourcePackConfig {
assert!( assert!(
hash_len == 40, hash_len == 40,
"Resource pack SHA1 hash is the wrong length (should be 40, is {hash_len})" "Resource pack SHA1 hash is the wrong length (should be 40, is {hash_len})"
) );
} }
} }

View File

@ -22,15 +22,15 @@ impl Default for ServerLinksConfig {
Self { Self {
enabled: true, enabled: true,
bug_report: "https://github.com/Pumpkin-MC/Pumpkin/issues".to_string(), bug_report: "https://github.com/Pumpkin-MC/Pumpkin/issues".to_string(),
support: "".to_string(), support: String::new(),
status: "".to_string(), status: String::new(),
feedback: "".to_string(), feedback: String::new(),
community: "".to_string(), community: String::new(),
website: "".to_string(), website: String::new(),
forums: "".to_string(), forums: String::new(),
news: "".to_string(), news: String::new(),
announcements: "".to_string(), announcements: String::new(),
custom: Default::default(), custom: HashMap::default(),
} }
} }
} }

View File

@ -36,3 +36,7 @@ criterion.workspace = true
[[bench]] [[bench]]
name = "has_random_ticks" name = "has_random_ticks"
harness = false harness = false
# Generated files generate a lot of warns
# [lints]
# workspace = true

View File

@ -111,7 +111,7 @@ enum BiomeTree {
Branch { Branch {
parameters: [ParameterRange; 7], parameters: [ParameterRange; 7],
#[serde(rename = "subTree")] #[serde(rename = "subTree")]
nodes: Box<[BiomeTree]>, nodes: Box<[Self]>,
}, },
} }
@ -126,7 +126,7 @@ impl BiomeTree {
.unwrap() .unwrap()
.to_shouty_snake_case() .to_shouty_snake_case()
); );
let parameters = parameters.map(|range| range.into_token_stream()); let parameters = parameters.map(ParameterRange::into_token_stream);
quote! { quote! {
BiomeTree::Leaf { BiomeTree::Leaf {
parameters: [#(#parameters),*], parameters: [#(#parameters),*],
@ -137,9 +137,9 @@ impl BiomeTree {
Self::Branch { parameters, nodes } => { Self::Branch { parameters, nodes } => {
let nodes = nodes let nodes = nodes
.into_iter() .into_iter()
.map(|node| node.into_token_stream()) .map(Self::into_token_stream)
.collect::<Vec<_>>(); .collect::<Vec<_>>();
let parameters = parameters.map(|range| range.into_token_stream()); let parameters = parameters.map(ParameterRange::into_token_stream);
quote! { quote! {
BiomeTree::Branch { BiomeTree::Branch {
parameters: [#(#parameters),*], parameters: [#(#parameters),*],
@ -172,7 +172,7 @@ pub(crate) fn build() -> TokenStream {
let mut name_to_type = TokenStream::new(); let mut name_to_type = TokenStream::new();
let mut id_to_type = TokenStream::new(); let mut id_to_type = TokenStream::new();
for (name, biome) in biomes.into_iter() { for (name, biome) in biomes {
// let full_name = format!("minecraft:{name}"); // let full_name = format!("minecraft:{name}");
let format_name = format_ident!("{}", name.to_shouty_snake_case()); let format_name = format_ident!("{}", name.to_shouty_snake_case());
let has_precipitation = biome.has_precipitation; let has_precipitation = biome.has_precipitation;
@ -190,44 +190,44 @@ pub(crate) fn build() -> TokenStream {
.spawners .spawners
.monster .monster
.iter() .iter()
.map(|s| s.to_tokens()) .map(Spawner::to_tokens)
.collect(); .collect();
let ambient: Vec<_> = biome let ambient: Vec<_> = biome
.spawners .spawners
.ambient .ambient
.iter() .iter()
.map(|s| s.to_tokens()) .map(Spawner::to_tokens)
.collect(); .collect();
let axolotls: Vec<_> = biome let axolotls: Vec<_> = biome
.spawners .spawners
.axolotls .axolotls
.iter() .iter()
.map(|s| s.to_tokens()) .map(Spawner::to_tokens)
.collect(); .collect();
let creature: Vec<_> = biome let creature: Vec<_> = biome
.spawners .spawners
.creature .creature
.iter() .iter()
.map(|s| s.to_tokens()) .map(Spawner::to_tokens)
.collect(); .collect();
let misc: Vec<_> = biome.spawners.misc.iter().map(|s| s.to_tokens()).collect(); let misc: Vec<_> = biome.spawners.misc.iter().map(Spawner::to_tokens).collect();
let underground_water_creature: Vec<_> = biome let underground_water_creature: Vec<_> = biome
.spawners .spawners
.underground_water_creature .underground_water_creature
.iter() .iter()
.map(|s| s.to_tokens()) .map(Spawner::to_tokens)
.collect(); .collect();
let water_ambient: Vec<_> = biome let water_ambient: Vec<_> = biome
.spawners .spawners
.water_ambient .water_ambient
.iter() .iter()
.map(|s| s.to_tokens()) .map(Spawner::to_tokens)
.collect(); .collect();
let water_creature: Vec<_> = biome let water_creature: Vec<_> = biome
.spawners .spawners
.water_creature .water_creature
.iter() .iter()
.map(|s| s.to_tokens()) .map(Spawner::to_tokens)
.collect(); .collect();
let spawners = quote! { let spawners = quote! {

View File

@ -17,7 +17,7 @@ pub fn gen_u16_bitset(name: &str, ids: &[u16]) -> Bitset {
let mut bitset = vec![0u64; words]; let mut bitset = vec![0u64; words];
for &id in ids { for &id in ids {
let index = (id as usize) >> 6; let index = (id as usize) >> 6;
let bit = (id as u32) & 63; let bit = u32::from(id) & 63;
bitset[index] |= 1u64 << bit; bitset[index] |= 1u64 << bit;
} }
let name_uppercase = name.to_uppercase(); let name_uppercase = name.to_uppercase();

View File

@ -418,11 +418,11 @@ pub enum PistonBehavior {
impl PistonBehavior { impl PistonBehavior {
fn to_tokens(&self) -> TokenStream { fn to_tokens(&self) -> TokenStream {
match self { match self {
PistonBehavior::Normal => quote! { PistonBehavior::Normal }, Self::Normal => quote! { PistonBehavior::Normal },
PistonBehavior::Destroy => quote! { PistonBehavior::Destroy }, Self::Destroy => quote! { PistonBehavior::Destroy },
PistonBehavior::Block => quote! { PistonBehavior::Block }, Self::Block => quote! { PistonBehavior::Block },
PistonBehavior::Ignore => quote! { PistonBehavior::Ignore }, Self::Ignore => quote! { PistonBehavior::Ignore },
PistonBehavior::PushOnly => quote! { PistonBehavior::PushOnly }, Self::PushOnly => quote! { PistonBehavior::PushOnly },
} }
} }
} }
@ -447,20 +447,17 @@ impl BlockState {
let instrument = format_ident!("{}", self.instrument.to_upper_camel_case()); let instrument = format_ident!("{}", self.instrument.to_upper_camel_case());
let luminance = LitInt::new(&self.luminance.to_string(), Span::call_site()); let luminance = LitInt::new(&self.luminance.to_string(), Span::call_site());
let hardness = self.hardness; let hardness = self.hardness;
let opacity = match self.opacity { let opacity = if let Some(opacity) = self.opacity {
Some(opacity) => {
let opacity = LitInt::new(&opacity.to_string(), Span::call_site()); let opacity = LitInt::new(&opacity.to_string(), Span::call_site());
quote! { #opacity } quote! { #opacity }
} } else {
None => quote! { 0 }, quote! { 0 }
}; };
let block_entity_type = match self.block_entity_type { let block_entity_type = if let Some(block_entity_type) = self.block_entity_type {
Some(block_entity_type) => { let block_entity_type = LitInt::new(&block_entity_type.to_string(), Span::call_site());
let block_entity_type =
LitInt::new(&block_entity_type.to_string(), Span::call_site());
quote! { #block_entity_type } quote! { #block_entity_type }
} } else {
None => quote! { u16::MAX }, quote! { u16::MAX }
}; };
let collision_shapes = self let collision_shapes = self
@ -522,21 +519,19 @@ impl ToTokens for Block {
let slipperiness = &self.slipperiness; let slipperiness = &self.slipperiness;
let velocity_multiplier = &self.velocity_multiplier; let velocity_multiplier = &self.velocity_multiplier;
let jump_velocity_multiplier = &self.jump_velocity_multiplier; let jump_velocity_multiplier = &self.jump_velocity_multiplier;
let experience = match &self.experience { let experience = if let Some(exp) = &self.experience {
Some(exp) => {
let exp_tokens = exp.to_token_stream(); let exp_tokens = exp.to_token_stream();
quote! { Some(#exp_tokens) } quote! { Some(#exp_tokens) }
} } else {
None => quote! { None }, quote! { None }
}; };
// Generate state tokens // Generate state tokens
let states = self.states.iter().map(|state| state.to_tokens()); let states = self.states.iter().map(BlockState::to_tokens);
let loot_table = match &self.loot_table { let loot_table = if let Some(table) = &self.loot_table {
Some(table) => {
let table_tokens = table.to_token_stream(); let table_tokens = table.to_token_stream();
quote! { Some(#table_tokens) } quote! { Some(#table_tokens) }
} } else {
None => quote! { None }, quote! { None }
}; };
let default_state_ref: &BlockState = self let default_state_ref: &BlockState = self
@ -547,12 +542,11 @@ impl ToTokens for Block {
let mut default_state = default_state_ref.clone(); let mut default_state = default_state_ref.clone();
default_state.id = default_state_ref.id; default_state.id = default_state_ref.id;
let default_state = default_state.to_tokens(); let default_state = default_state.to_tokens();
let flammable = match &self.flammable { let flammable = if let Some(flammable) = &self.flammable {
Some(flammable) => {
let flammable_tokens = flammable.to_token_stream(); let flammable_tokens = flammable.to_token_stream();
quote! { Some(#flammable_tokens) } quote! { Some(#flammable_tokens) }
} } else {
None => quote! { None }, quote! { None }
}; };
tokens.extend(quote! { tokens.extend(quote! {
Block { Block {
@ -800,10 +794,12 @@ pub(crate) fn build() -> TokenStream {
.find(|(_, be_props)| { .find(|(_, be_props)| {
java_props_for_this_state java_props_for_this_state
.iter() .iter()
.all(|(k, v)| be_props.get(k).map(|be_v| be_v == v).unwrap_or(false)) .all(|(k, v)| be_props.get(k).is_some_and(|be_v| be_v == v))
}) })
.map(|(id, _)| *id) .map_or_else(
.unwrap_or_else(|| be_variants.first().map(|(id, _)| *id).unwrap_or(1)); || be_variants.first().map_or(1, |(id, _)| *id),
|(id, _)| *id,
);
} }
block_state_to_bedrock.push((state.id, matched_be_id)); block_state_to_bedrock.push((state.id, matched_be_id));
@ -861,12 +857,16 @@ pub(crate) fn build() -> TokenStream {
let shapes = blocks_assets let shapes = blocks_assets
.shapes .shapes
.iter() .iter()
.map(|shape| shape.to_token_stream()); .map(quote::ToTokens::to_token_stream);
let air_state_ids = quote! { #(#air_states)|* }; let air_state_ids = quote! { #(#air_states)|* };
let block_props = block_properties.iter().map(|prop| prop.to_token_stream()); let block_props = block_properties
let properties = property_enums.values().map(|prop| prop.to_token_stream()); .iter()
.map(quote::ToTokens::to_token_stream);
let properties = property_enums
.values()
.map(quote::ToTokens::to_token_stream);
let block_entity_types = blocks_assets let block_entity_types = blocks_assets
.block_entity_types .block_entity_types
@ -1181,11 +1181,7 @@ fn get_be_data_from_nbt<R: Read>(
let read_byte_safe = |reader: &mut R| -> Option<u8> { let read_byte_safe = |reader: &mut R| -> Option<u8> {
let mut buf = [0; 1]; let mut buf = [0; 1];
if reader.read_exact(&mut buf).is_ok() { reader.read_exact(&mut buf).is_ok().then(|| buf[0])
Some(buf[0])
} else {
None
}
}; };
while let Some(tag_id) = read_byte_safe(reader) { while let Some(tag_id) = read_byte_safe(reader) {
@ -1234,7 +1230,7 @@ fn get_be_data_from_nbt<R: Read>(
} }
3 => read_varint(reader).to_string(), 3 => read_varint(reader).to_string(),
8 => read_nbt_string(reader), 8 => read_nbt_string(reader),
_ => panic!("Unknown property type {} for key {}", prop_type, prop_key), _ => panic!("Unknown property type {prop_type} for key {prop_key}"),
}; };
properties.insert(prop_key, prop_val); properties.insert(prop_key, prop_val);
@ -1242,7 +1238,7 @@ fn get_be_data_from_nbt<R: Read>(
"version" => { "version" => {
read_varint(reader); read_varint(reader);
} }
_ => panic!("Unexpected root field: {}", field_name), _ => panic!("Unexpected root field: {field_name}"),
} }
} }

View File

@ -55,7 +55,7 @@ pub const OUT_DIR: &str = "src/generated";
pub fn main() { pub fn main() {
if let Err(e) = fs::create_dir_all(OUT_DIR) { if let Err(e) = fs::create_dir_all(OUT_DIR) {
eprintln!("Failed to create output directory {}: {}", OUT_DIR, e); eprintln!("Failed to create output directory {OUT_DIR}: {e}");
} }
type BuilderFn = fn() -> TokenStream; type BuilderFn = fn() -> TokenStream;
@ -115,6 +115,7 @@ pub fn main() {
}); });
} }
#[must_use]
pub fn array_to_tokenstream(array: &[String]) -> TokenStream { pub fn array_to_tokenstream(array: &[String]) -> TokenStream {
let variants = array.iter().map(|item| { let variants = array.iter().map(|item| {
let name = format_ident!("{}", item.to_pascal_case()); let name = format_ident!("{}", item.to_pascal_case());

View File

@ -13,7 +13,7 @@ pub(crate) fn build() -> TokenStream {
let variants: Vec<TokenStream> = chunk_status let variants: Vec<TokenStream> = chunk_status
.into_iter() .into_iter()
.map(|status| { .map(|status| {
let full_name = format!("minecraft:{}", status); let full_name = format!("minecraft:{status}");
let name = format_ident!("{}", status.to_pascal_case()); let name = format_ident!("{}", status.to_pascal_case());
quote! { quote! {

View File

@ -66,20 +66,18 @@ pub(crate) fn build() -> TokenStream {
}); });
let data = &entry.components; let data = &entry.components;
let death_message_type = match &data.death_message_type { let death_message_type = if let Some(msg) = &data.death_message_type {
Some(msg) => {
let msg_ident = Ident::new(&format!("{msg:?}"), proc_macro2::Span::call_site()); let msg_ident = Ident::new(&format!("{msg:?}"), proc_macro2::Span::call_site());
quote! { DeathMessageType::#msg_ident } quote! { DeathMessageType::#msg_ident }
} } else {
None => quote! { DeathMessageType::Default }, quote! { DeathMessageType::Default }
}; };
let effects = match &data.effects { let effects = if let Some(msg) = &data.effects {
Some(msg) => {
let msg_ident = Ident::new(&format!("{msg:?}"), proc_macro2::Span::call_site()); let msg_ident = Ident::new(&format!("{msg:?}"), proc_macro2::Span::call_site());
quote! { Some(DamageEffects::#msg_ident) } quote! { Some(DamageEffects::#msg_ident) }
} } else {
None => quote! { None }, quote! { None }
}; };
let exhaustion = data.exhaustion; let exhaustion = data.exhaustion;

View File

@ -22,7 +22,7 @@ pub(crate) fn build() -> TokenStream {
let strip_name = raw_name let strip_name = raw_name
.strip_prefix("minecraft:") .strip_prefix("minecraft:")
.unwrap() .unwrap()
.replace("/", "_"); .replace('/', "_");
let pascal_case = format_ident!("{}", strip_name.to_pascal_case()); let pascal_case = format_ident!("{}", strip_name.to_pascal_case());
// Enum variant // Enum variant

View File

@ -60,9 +60,10 @@ pub(crate) fn build() -> TokenStream {
.to_shouty_snake_case() .to_shouty_snake_case()
); );
let fixed_time = match dim.fixed_time { let fixed_time = if let Some(t) = dim.fixed_time {
Some(t) => quote! { Some(#t) }, quote! { Some(#t) }
None => quote! { None }, } else {
quote! { None }
}; };
let ambient_light = dim.ambient_light; let ambient_light = dim.ambient_light;
@ -77,7 +78,7 @@ pub(crate) fn build() -> TokenStream {
let minecraft_name = if name.contains(':') { let minecraft_name = if name.contains(':') {
name.clone() name.clone()
} else { } else {
format!("minecraft:{}", name) format!("minecraft:{name}")
}; };
variants.extend(quote! { variants.extend(quote! {

View File

@ -51,9 +51,9 @@ impl Modifiers {
impl MobEffectCategory { impl MobEffectCategory {
pub fn to_tokens(&self) -> TokenStream { pub fn to_tokens(&self) -> TokenStream {
match self { match self {
MobEffectCategory::BENEFICIAL => quote! { MobEffectCategory::Beneficial }, Self::BENEFICIAL => quote! { MobEffectCategory::Beneficial },
MobEffectCategory::HARMFUL => quote! { MobEffectCategory::Harmful }, Self::HARMFUL => quote! { MobEffectCategory::Harmful },
MobEffectCategory::NEUTRAL => quote! { MobEffectCategory::Neutral }, Self::NEUTRAL => quote! { MobEffectCategory::Neutral },
} }
} }
} }
@ -69,14 +69,14 @@ pub(crate) fn build() -> TokenStream {
let mut name_to_type = TokenStream::new(); let mut name_to_type = TokenStream::new();
let mut minecraft_name_to_type = TokenStream::new(); let mut minecraft_name_to_type = TokenStream::new();
for (name, effect) in effects.into_iter() { for (name, effect) in effects {
let format_name = format_ident!("{}", name.to_shouty_snake_case()); let format_name = format_ident!("{}", name.to_shouty_snake_case());
let id = effect.id; let id = effect.id;
let color = effect.color; let color = effect.color;
let translation_key = effect.translation_key; let translation_key = effect.translation_key;
let category = effect.category.to_tokens(); let category = effect.category.to_tokens();
let slots = effect.attribute_modifiers; let slots = effect.attribute_modifiers;
let slots = slots.into_iter().map(|slot| slot.get_tokens()); let slots = slots.into_iter().map(Modifiers::get_tokens);
let minecraft_name = "minecraft:".to_string() + &name; let minecraft_name = "minecraft:".to_string() + &name;
variants.extend([quote! { variants.extend([quote! {

View File

@ -37,17 +37,17 @@ pub enum AttributeModifierSlot {
impl AttributeModifierSlot { impl AttributeModifierSlot {
pub fn to_tokens(&self) -> TokenStream { pub fn to_tokens(&self) -> TokenStream {
match self { match self {
AttributeModifierSlot::Any => quote! { AttributeModifierSlot::Any }, Self::Any => quote! { AttributeModifierSlot::Any },
AttributeModifierSlot::MainHand => quote! { AttributeModifierSlot::MainHand }, Self::MainHand => quote! { AttributeModifierSlot::MainHand },
AttributeModifierSlot::OffHand => quote! { AttributeModifierSlot::OffHand }, Self::OffHand => quote! { AttributeModifierSlot::OffHand },
AttributeModifierSlot::Hand => quote! { AttributeModifierSlot::Hand }, Self::Hand => quote! { AttributeModifierSlot::Hand },
AttributeModifierSlot::Feet => quote! { AttributeModifierSlot::Feet }, Self::Feet => quote! { AttributeModifierSlot::Feet },
AttributeModifierSlot::Legs => quote! { AttributeModifierSlot::Legs }, Self::Legs => quote! { AttributeModifierSlot::Legs },
AttributeModifierSlot::Chest => quote! { AttributeModifierSlot::Chest }, Self::Chest => quote! { AttributeModifierSlot::Chest },
AttributeModifierSlot::Head => quote! { AttributeModifierSlot::Head }, Self::Head => quote! { AttributeModifierSlot::Head },
AttributeModifierSlot::Armor => quote! { AttributeModifierSlot::Armor }, Self::Armor => quote! { AttributeModifierSlot::Armor },
AttributeModifierSlot::Body => quote! { AttributeModifierSlot::Body }, Self::Body => quote! { AttributeModifierSlot::Body },
AttributeModifierSlot::Saddle => quote! { AttributeModifierSlot::Saddle }, Self::Saddle => quote! { AttributeModifierSlot::Saddle },
} }
} }
} }
@ -63,7 +63,7 @@ pub(crate) fn build() -> TokenStream {
let mut name_to_type = TokenStream::new(); let mut name_to_type = TokenStream::new();
let mut id_to_type = TokenStream::new(); let mut id_to_type = TokenStream::new();
for (name, enchantment) in enchantments.into_iter() { for (name, enchantment) in enchantments {
let id = enchantment.id; let id = enchantment.id;
let raw_name = name.strip_prefix("minecraft:").unwrap(); let raw_name = name.strip_prefix("minecraft:").unwrap();
let format_name = format_ident!("{}", raw_name.to_shouty_snake_case()); let format_name = format_ident!("{}", raw_name.to_shouty_snake_case());
@ -74,13 +74,12 @@ pub(crate) fn build() -> TokenStream {
.supported_items .supported_items
.strip_prefix("#") .strip_prefix("#")
.unwrap() .unwrap()
.replace(":", "_") .replace([':', '/'], "_")
.replace("/", "_")
.to_uppercase() .to_uppercase()
); );
let max_level = enchantment.max_level; let max_level = enchantment.max_level;
let slots = enchantment.slots; let slots = enchantment.slots;
let slots = slots.iter().map(|slot| slot.to_tokens()); let slots = slots.iter().map(AttributeModifierSlot::to_tokens);
let Translate { translate, with: _ } = &enchantment.description.0.content else { let Translate { translate, with: _ } = &enchantment.description.0.content else {
panic!() panic!()
}; };
@ -92,8 +91,7 @@ pub(crate) fn build() -> TokenStream {
exclusive_set exclusive_set
.strip_prefix("#") .strip_prefix("#")
.unwrap() .unwrap()
.replace(":", "_") .replace([':', '/'], "_")
.replace("/", "_")
.to_uppercase() .to_uppercase()
); );
variants.extend([quote! { variants.extend([quote! {

View File

@ -63,14 +63,16 @@ impl ToTokens for NamedEntityType<'_> {
let entity = self.1; let entity = self.1;
let id = LitInt::new(&entity.id.to_string(), proc_macro2::Span::call_site()); let id = LitInt::new(&entity.id.to_string(), proc_macro2::Span::call_site());
let max_health = match entity.max_health { let max_health = if let Some(mh) = entity.max_health {
Some(mh) => quote! { Some(#mh) }, quote! { Some(#mh) }
None => quote! { None }, } else {
quote! { None }
}; };
let attackable = match entity.attackable { let attackable = if let Some(a) = entity.attackable {
Some(a) => quote! { Some(#a) }, quote! { Some(#a) }
None => quote! { None }, } else {
quote! { None }
}; };
let spawn_restriction_location = match entity.spawn_restriction.location { let spawn_restriction_location = match entity.spawn_restriction.location {
@ -111,12 +113,14 @@ impl ToTokens for NamedEntityType<'_> {
let summonable = entity.summonable; let summonable = entity.summonable;
let fire_immune = entity.fire_immune; let fire_immune = entity.fire_immune;
let eye_height = entity.eye_height; let eye_height = entity.eye_height;
if entity.mob.is_none() && name != "player" { assert!(
panic!("missing field 'mob', entity name {name}"); !(entity.mob.is_none() && name != "player"),
} "missing field 'mob', entity name {name}"
if entity.limit_per_chunk.is_none() && name != "player" { );
panic!("missing field 'mob', entity name {name}"); assert!(
} !(entity.limit_per_chunk.is_none() && name != "player"),
"missing field 'mob', entity name {name}"
);
let mob = entity.mob.unwrap_or(false); let mob = entity.mob.unwrap_or(false);
let limit_per_chunk = entity.limit_per_chunk.unwrap_or(0); let limit_per_chunk = entity.limit_per_chunk.unwrap_or(0);
let can_spawn_far_from_player = entity.can_spawn_far_from_player; let can_spawn_far_from_player = entity.can_spawn_far_from_player;
@ -124,12 +128,11 @@ impl ToTokens for NamedEntityType<'_> {
let dimension0 = entity.dimension[0]; let dimension0 = entity.dimension[0];
let dimension1 = entity.dimension[1]; let dimension1 = entity.dimension[1];
let loot_table = match &entity.loot_table { let loot_table = if let Some(table) = &entity.loot_table {
Some(table) => {
let table_tokens = table.to_token_stream(); let table_tokens = table.to_token_stream();
quote! { Some(#table_tokens) } quote! { Some(#table_tokens) }
} } else {
None => quote! { None }, quote! { None }
}; };
tokens.extend(quote! { tokens.extend(quote! {
@ -165,7 +168,7 @@ pub(crate) fn build() -> TokenStream {
let mut type_from_raw_id_arms = TokenStream::new(); let mut type_from_raw_id_arms = TokenStream::new();
let mut type_from_name = TokenStream::new(); let mut type_from_name = TokenStream::new();
for (name, entity) in json.iter() { for (name, entity) in &json {
let id = entity.id as u8; let id = entity.id as u8;
let id_lit = LitInt::new(&id.to_string(), proc_macro2::Span::call_site()); let id_lit = LitInt::new(&id.to_string(), proc_macro2::Span::call_site());
let upper_name = format_ident!("{}", name.to_uppercase()); let upper_name = format_ident!("{}", name.to_uppercase());

View File

@ -57,7 +57,7 @@ impl ToTokens for PropertyStruct {
let values_index = (0..self.values.len() as u16).collect::<Vec<_>>(); let values_index = (0..self.values.len() as u16).collect::<Vec<_>>();
let ident_values = self.values.iter().map(|value| { let ident_values = self.values.iter().map(|value| {
let value_str = if value.chars().all(|c| c.is_numeric()) { let value_str = if value.chars().all(char::is_numeric) {
format!("L{value}") format!("L{value}")
} else { } else {
value.clone() value.clone()
@ -69,7 +69,7 @@ impl ToTokens for PropertyStruct {
let values_3 = ident_values.clone(); let values_3 = ident_values.clone();
let from_values = self.values.iter().map(|value| { let from_values = self.values.iter().map(|value| {
let value_str = if value.chars().all(|c| c.is_numeric()) { let value_str = if value.chars().all(char::is_numeric) {
format!("L{value}") format!("L{value}")
} else { } else {
value.clone() value.clone()
@ -80,7 +80,7 @@ impl ToTokens for PropertyStruct {
} }
}); });
let to_values = self.values.iter().map(|value| { let to_values = self.values.iter().map(|value| {
let value_str = if value.chars().all(|c| c.is_numeric()) { let value_str = if value.chars().all(char::is_numeric) {
format!("L{value}") format!("L{value}")
} else { } else {
value.clone() value.clone()
@ -512,12 +512,13 @@ pub(crate) fn build() -> TokenStream {
.entry(renamed_property.clone()) .entry(renamed_property.clone())
.or_insert_with(|| property.values.clone()); .or_insert_with(|| property.values.clone());
if expected_values != &property.values { assert!(
panic!( expected_values == &property.values,
"Enum overlap for '{}' ({:?} vs {:?})", "Enum overlap for '{}' ({:?} vs {:?})",
property.name, &property.values, expected_values property.name,
&property.values,
expected_values
); );
};
property_mapping.push(PropertyVariantMapping { property_mapping.push(PropertyVariantMapping {
original_name: property.name.clone(), original_name: property.name.clone(),
@ -591,8 +592,12 @@ pub(crate) fn build() -> TokenStream {
}); });
} }
let fluid_props = fluid_properties.iter().map(|prop| prop.to_token_stream()); let fluid_props = fluid_properties
let properties = property_enums.values().map(|prop| prop.to_token_stream()); .iter()
.map(quote::ToTokens::to_token_stream);
let properties = property_enums
.values()
.map(quote::ToTokens::to_token_stream);
quote! { quote! {
use std::hash::{Hash, Hasher}; use std::hash::{Hash, Hasher};

View File

@ -81,7 +81,7 @@ impl ToTokens for ItemComponents {
damage: #damage_lit, damage: #damage_lit,
}), }),
}); });
}; }
if let Some(md) = self.max_damage { if let Some(md) = self.max_damage {
let max_damage_lit = LitInt::new(&md.to_string(), Span::call_site()); let max_damage_lit = LitInt::new(&md.to_string(), Span::call_site());
@ -90,7 +90,7 @@ impl ToTokens for ItemComponents {
max_damage: #max_damage_lit, max_damage: #max_damage_lit,
}), }),
}); });
}; }
if let Some(modifiers) = &self.attribute_modifiers { if let Some(modifiers) = &self.attribute_modifiers {
let modifier_code = modifiers.iter().map(|modifier| { let modifier_code = modifiers.iter().map(|modifier| {
@ -122,7 +122,7 @@ impl ToTokens for ItemComponents {
attribute_modifiers: Cow::Borrowed(&[#(#modifier_code),*]) attribute_modifiers: Cow::Borrowed(&[#(#modifier_code),*])
}), }),
}); });
}; }
if let Some(tool) = &self.tool { if let Some(tool) = &self.tool {
let rules_code = tool.rules.iter().map(|rule| { let rules_code = tool.rules.iter().map(|rule| {
@ -138,10 +138,8 @@ impl ToTokens for ItemComponents {
Blocks(Cow::Borrowed(&[&Block::#ident])) Blocks(Cow::Borrowed(&[&Block::#ident]))
} }
} else if let TagType::Tag(str) = t { } else if let TagType::Tag(str) = t {
let ident = format_ident!( let ident =
"{}", format_ident!("{}", str.replace([':', '/'], "_").to_uppercase());
str.replace(":", "_").replace("/", "_").to_uppercase()
);
block_array = quote! { block_array = quote! {
Tag(&tag::Block::#ident) Tag(&tag::Block::#ident)
} }
@ -168,18 +166,16 @@ impl ToTokens for ItemComponents {
} else { } else {
unreachable!(); unreachable!();
} }
let speed = match rule.speed { let speed = if let Some(speed) = rule.speed {
Some(speed) => {
quote! { Some(#speed) } quote! { Some(#speed) }
} } else {
None => quote! { None }, quote! { None }
}; };
let correct_for_drops = match rule.correct_for_drops { let correct_for_drops = if let Some(correct_for_drops) = rule.correct_for_drops {
Some(correct_for_drops) => {
let correct_for_drops = LitBool::new(correct_for_drops, Span::call_site()); let correct_for_drops = LitBool::new(correct_for_drops, Span::call_site());
quote! { Some(#correct_for_drops) } quote! { Some(#correct_for_drops) }
} } else {
None => quote! { None }, quote! { None }
}; };
quote! { quote! {
ToolRule { ToolRule {
@ -208,7 +204,7 @@ impl ToTokens for ItemComponents {
damage_per_block: #damage_per_block, damage_per_block: #damage_per_block,
can_destroy_blocks_in_creative: #can_destroy_blocks_in_creative can_destroy_blocks_in_creative: #can_destroy_blocks_in_creative
}), }); }), });
}; }
if let Some(food) = &self.food { if let Some(food) = &self.food {
let nutrition = LitInt::new(&food.nutrition.to_string(), Span::call_site()); let nutrition = LitInt::new(&food.nutrition.to_string(), Span::call_site());
@ -222,7 +218,7 @@ impl ToTokens for ItemComponents {
saturation: #saturation, saturation: #saturation,
can_always_eat: #can_always_eat, can_always_eat: #can_always_eat,
}), }); }), });
}; }
if let Some(consumable) = &self.consumable { if let Some(consumable) = &self.consumable {
let consume_seconds = LitFloat::new( let consume_seconds = LitFloat::new(
@ -233,15 +229,15 @@ impl ToTokens for ItemComponents {
tokens.extend(quote! { (Consumable, &ConsumableImpl { tokens.extend(quote! { (Consumable, &ConsumableImpl {
consume_seconds: #consume_seconds, consume_seconds: #consume_seconds,
}), }); }), });
}; }
if self.blocks_attacks.is_some() { if self.blocks_attacks.is_some() {
tokens.extend(quote! { (BlocksAttacks, &BlocksAttacksImpl), }); tokens.extend(quote! { (BlocksAttacks, &BlocksAttacksImpl), });
}; }
if self.death_protection.is_some() { if self.death_protection.is_some() {
tokens.extend(quote! { (DeathProtection, &DeathProtectionImpl), }); tokens.extend(quote! { (DeathProtection, &DeathProtectionImpl), });
}; }
if let Some(equippable) = &self.equippable { if let Some(equippable) = &self.equippable {
let slot = match equippable.slot.as_str() { let slot = match equippable.slot.as_str() {
@ -298,7 +294,7 @@ impl ToTokens for ItemComponents {
TagType::Tag(tag) => { TagType::Tag(tag) => {
let ident = format_ident!( let ident = format_ident!(
"{}", "{}",
tag.replace(":", "_").replace("/", "_").to_uppercase() tag.replace([':', '/'], "_").to_uppercase()
); );
quote! { EntityTypeOrTag::Tag(&crate::tag::EntityType::#ident) } quote! { EntityTypeOrTag::Tag(&crate::tag::EntityType::#ident) }
} }
@ -339,7 +335,7 @@ impl ToTokens for ItemComponents {
can_be_sheared: #can_be_sheared, can_be_sheared: #can_be_sheared,
shearing_sound: #shearing_sound shearing_sound: #shearing_sound
}), }); }), });
}; }
} }
} }

View File

@ -17,16 +17,16 @@ pub struct LootTableStruct {
impl ToTokens for LootTableStruct { impl ToTokens for LootTableStruct {
fn to_tokens(&self, tokens: &mut TokenStream) { fn to_tokens(&self, tokens: &mut TokenStream) {
let loot_table_type = self.r#type.to_token_stream(); let loot_table_type = self.r#type.to_token_stream();
let random_sequence = match &self.random_sequence { let random_sequence = if let Some(seq) = &self.random_sequence {
Some(seq) => quote! { Some(#seq) }, quote! { Some(#seq) }
None => quote! { None }, } else {
quote! { None }
}; };
let pools = match &self.pools { let pools = if let Some(pools) = &self.pools {
Some(pools) => { let pool_tokens: Vec<_> = pools.iter().map(quote::ToTokens::to_token_stream).collect();
let pool_tokens: Vec<_> = pools.iter().map(|pool| pool.to_token_stream()).collect();
quote! { Some(&[#(#pool_tokens),*]) } quote! { Some(&[#(#pool_tokens),*]) }
} } else {
None => quote! { None }, quote! { None }
}; };
tokens.extend(quote! { tokens.extend(quote! {
@ -53,23 +53,21 @@ impl ToTokens for LootPoolStruct {
let entries_tokens: Vec<_> = self let entries_tokens: Vec<_> = self
.entries .entries
.iter() .iter()
.map(|entry| entry.to_token_stream()) .map(quote::ToTokens::to_token_stream)
.collect(); .collect();
let rolls = &self.rolls; let rolls = &self.rolls;
let bonus_rolls = &self.bonus_rolls; let bonus_rolls = &self.bonus_rolls;
let conditions_tokens = match &self.conditions { let conditions_tokens = if let Some(conds) = &self.conditions {
Some(conds) => { let cond_tokens: Vec<_> = conds.iter().map(quote::ToTokens::to_token_stream).collect();
let cond_tokens: Vec<_> = conds.iter().map(|c| c.to_token_stream()).collect();
quote! { Some(&[#(#cond_tokens),*]) } quote! { Some(&[#(#cond_tokens),*]) }
} } else {
None => quote! { None }, quote! { None }
}; };
let functions_tokens = match &self.functions { let functions_tokens = if let Some(fns) = &self.functions {
Some(fns) => { let cond_tokens: Vec<_> = fns.iter().map(quote::ToTokens::to_token_stream).collect();
let cond_tokens: Vec<_> = fns.iter().map(|c| c.to_token_stream()).collect();
quote! { Some(&[#(#cond_tokens),*]) } quote! { Some(&[#(#cond_tokens),*]) }
} } else {
None => quote! { None }, quote! { None }
}; };
tokens.extend(quote! { tokens.extend(quote! {
@ -108,7 +106,7 @@ pub struct AlternativeEntryStruct {
impl ToTokens for AlternativeEntryStruct { impl ToTokens for AlternativeEntryStruct {
fn to_tokens(&self, tokens: &mut TokenStream) { fn to_tokens(&self, tokens: &mut TokenStream) {
let children = self.children.iter().map(|entry| entry.to_token_stream()); let children = self.children.iter().map(quote::ToTokens::to_token_stream);
tokens.extend(quote! { tokens.extend(quote! {
AlternativeEntry { AlternativeEntry {
@ -142,28 +140,28 @@ pub enum LootPoolEntryTypesStruct {
impl ToTokens for LootPoolEntryTypesStruct { impl ToTokens for LootPoolEntryTypesStruct {
fn to_tokens(&self, tokens: &mut TokenStream) { fn to_tokens(&self, tokens: &mut TokenStream) {
match self { match self {
LootPoolEntryTypesStruct::Empty => { Self::Empty => {
tokens.extend(quote! { LootPoolEntryTypes::Empty }); tokens.extend(quote! { LootPoolEntryTypes::Empty });
} }
LootPoolEntryTypesStruct::Item(item) => { Self::Item(item) => {
tokens.extend(quote! { LootPoolEntryTypes::Item(#item) }); tokens.extend(quote! { LootPoolEntryTypes::Item(#item) });
} }
LootPoolEntryTypesStruct::LootTable => { Self::LootTable => {
tokens.extend(quote! { LootPoolEntryTypes::LootTable }); tokens.extend(quote! { LootPoolEntryTypes::LootTable });
} }
LootPoolEntryTypesStruct::Dynamic => { Self::Dynamic => {
tokens.extend(quote! { LootPoolEntryTypes::Dynamic }); tokens.extend(quote! { LootPoolEntryTypes::Dynamic });
} }
LootPoolEntryTypesStruct::Tag => { Self::Tag => {
tokens.extend(quote! { LootPoolEntryTypes::Tag }); tokens.extend(quote! { LootPoolEntryTypes::Tag });
} }
LootPoolEntryTypesStruct::Alternatives(alt) => { Self::Alternatives(alt) => {
tokens.extend(quote! { LootPoolEntryTypes::Alternatives(#alt) }); tokens.extend(quote! { LootPoolEntryTypes::Alternatives(#alt) });
} }
LootPoolEntryTypesStruct::Sequence => { Self::Sequence => {
tokens.extend(quote! { LootPoolEntryTypes::Sequence }); tokens.extend(quote! { LootPoolEntryTypes::Sequence });
} }
LootPoolEntryTypesStruct::Group => { Self::Group => {
tokens.extend(quote! { LootPoolEntryTypes::Group }); tokens.extend(quote! { LootPoolEntryTypes::Group });
} }
} }
@ -219,35 +217,35 @@ pub enum LootConditionStruct {
impl ToTokens for LootConditionStruct { impl ToTokens for LootConditionStruct {
fn to_tokens(&self, tokens: &mut TokenStream) { fn to_tokens(&self, tokens: &mut TokenStream) {
let name = match self { let name = match self {
LootConditionStruct::Inverted => quote! { LootCondition::Inverted }, Self::Inverted => quote! { LootCondition::Inverted },
LootConditionStruct::AnyOf => quote! { LootCondition::AnyOf }, Self::AnyOf => quote! { LootCondition::AnyOf },
LootConditionStruct::AllOf => quote! { LootCondition::AllOf }, Self::AllOf => quote! { LootCondition::AllOf },
LootConditionStruct::RandomChance => quote! { LootCondition::RandomChance }, Self::RandomChance => quote! { LootCondition::RandomChance },
LootConditionStruct::RandomChanceWithEnchantedBonus => { Self::RandomChanceWithEnchantedBonus => {
quote! { LootCondition::RandomChanceWithEnchantedBonus } quote! { LootCondition::RandomChanceWithEnchantedBonus }
} }
LootConditionStruct::EntityProperties => quote! { LootCondition::EntityProperties }, Self::EntityProperties => quote! { LootCondition::EntityProperties },
LootConditionStruct::KilledByPlayer => quote! { LootCondition::KilledByPlayer }, Self::KilledByPlayer => quote! { LootCondition::KilledByPlayer },
LootConditionStruct::EntityScores => quote! { LootCondition::EntityScores }, Self::EntityScores => quote! { LootCondition::EntityScores },
LootConditionStruct::BlockStateProperty { block, properties } => { Self::BlockStateProperty { block, properties } => {
let properties: Vec<_> = properties let properties: Vec<_> = properties
.iter() .iter()
.map(|(k, v)| quote! { (#k, #v) }) .map(|(k, v)| quote! { (#k, #v) })
.collect(); .collect();
quote! { LootCondition::BlockStateProperty { block: #block, properties: &[#(#properties),*] } } quote! { LootCondition::BlockStateProperty { block: #block, properties: &[#(#properties),*] } }
} }
LootConditionStruct::MatchTool => quote! { LootCondition::MatchTool }, Self::MatchTool => quote! { LootCondition::MatchTool },
LootConditionStruct::TableBonus => quote! { LootCondition::TableBonus }, Self::TableBonus => quote! { LootCondition::TableBonus },
LootConditionStruct::SurvivesExplosion => quote! { LootCondition::SurvivesExplosion }, Self::SurvivesExplosion => quote! { LootCondition::SurvivesExplosion },
LootConditionStruct::DamageSourceProperties => { Self::DamageSourceProperties => {
quote! { LootCondition::DamageSourceProperties } quote! { LootCondition::DamageSourceProperties }
} }
LootConditionStruct::LocationCheck => quote! { LootCondition::LocationCheck }, Self::LocationCheck => quote! { LootCondition::LocationCheck },
LootConditionStruct::WeatherCheck => quote! { LootCondition::WeatherCheck }, Self::WeatherCheck => quote! { LootCondition::WeatherCheck },
LootConditionStruct::Reference => quote! { LootCondition::Reference }, Self::Reference => quote! { LootCondition::Reference },
LootConditionStruct::TimeCheck => quote! { LootCondition::TimeCheck }, Self::TimeCheck => quote! { LootCondition::TimeCheck },
LootConditionStruct::ValueCheck => quote! { LootCondition::ValueCheck }, Self::ValueCheck => quote! { LootCondition::ValueCheck },
LootConditionStruct::EnchantmentActiveCheck => { Self::EnchantmentActiveCheck => {
quote! { LootCondition::EnchantmentActiveCheck } quote! { LootCondition::EnchantmentActiveCheck }
} }
}; };
@ -267,12 +265,11 @@ impl ToTokens for LootFunctionStruct {
fn to_tokens(&self, tokens: &mut TokenStream) { fn to_tokens(&self, tokens: &mut TokenStream) {
let functions_tokens = &self.content.to_token_stream(); let functions_tokens = &self.content.to_token_stream();
let conditions_tokens = match &self.conditions { let conditions_tokens = if let Some(conds) = &self.conditions {
Some(conds) => { let cond_tokens: Vec<_> = conds.iter().map(quote::ToTokens::to_token_stream).collect();
let cond_tokens: Vec<_> = conds.iter().map(|c| c.to_token_stream()).collect();
quote! { Some(&[#(#cond_tokens),*]) } quote! { Some(&[#(#cond_tokens),*]) }
} } else {
None => quote! { None }, quote! { None }
}; };
tokens.extend(quote! { tokens.extend(quote! {
@ -325,45 +322,46 @@ pub enum LootFunctionTypesStruct {
impl ToTokens for LootFunctionTypesStruct { impl ToTokens for LootFunctionTypesStruct {
fn to_tokens(&self, tokens: &mut TokenStream) { fn to_tokens(&self, tokens: &mut TokenStream) {
let name = match self { let name = match self {
LootFunctionTypesStruct::SetCount { count, add } => { Self::SetCount { count, add } => {
let count = count.to_token_stream(); let count = count.to_token_stream();
let add = add.unwrap_or(false); let add = add.unwrap_or(false);
quote! { LootFunctionTypes::SetCount { count: #count, add: #add } } quote! { LootFunctionTypes::SetCount { count: #count, add: #add } }
} }
LootFunctionTypesStruct::SetOminousBottleAmplifier => { Self::SetOminousBottleAmplifier => {
quote! { LootFunctionTypes::SetOminousBottleAmplifier } quote! { LootFunctionTypes::SetOminousBottleAmplifier }
} }
LootFunctionTypesStruct::FurnaceSmelt => { Self::FurnaceSmelt => {
quote! { LootFunctionTypes::FurnaceSmelt } quote! { LootFunctionTypes::FurnaceSmelt }
} }
LootFunctionTypesStruct::SetPotion => { Self::SetPotion => {
quote! { LootFunctionTypes::SetPotion } quote! { LootFunctionTypes::SetPotion }
} }
LootFunctionTypesStruct::EnchantedCountIncrease => { Self::EnchantedCountIncrease => {
quote! { LootFunctionTypes::EnchantedCountIncrease } quote! { LootFunctionTypes::EnchantedCountIncrease }
} }
LootFunctionTypesStruct::LimitCount { limit } => { Self::LimitCount { limit } => {
let min = match limit.min { let min = if let Some(min) = limit.min {
Some(min) => quote! { Some(#min) }, quote! { Some(#min) }
None => quote! { None }, } else {
quote! { None }
}; };
let max = match limit.max { let max = if let Some(max) = limit.max {
Some(max) => quote! { Some(#max) }, quote! { Some(#max) }
None => quote! { None }, } else {
quote! { None }
}; };
quote! { LootFunctionTypes::LimitCount { min: #min, max: #max } } quote! { LootFunctionTypes::LimitCount { min: #min, max: #max } }
} }
LootFunctionTypesStruct::ApplyBonus { Self::ApplyBonus {
enchantment, enchantment,
formula, formula,
parameters, parameters,
} => { } => {
let parameters = match parameters { let parameters = if let Some(params) = parameters {
Some(params) => {
let params = params.to_token_stream(); let params = params.to_token_stream();
quote! { Some(#params) } quote! { Some(#params) }
} } else {
None => quote! { None }, quote! { None }
}; };
quote! { quote! {
@ -374,7 +372,7 @@ impl ToTokens for LootFunctionTypesStruct {
} }
} }
} }
LootFunctionTypesStruct::CopyComponents { source, include } => { Self::CopyComponents { source, include } => {
quote! { quote! {
LootFunctionTypes::CopyComponents { LootFunctionTypes::CopyComponents {
source: #source, source: #source,
@ -382,7 +380,7 @@ impl ToTokens for LootFunctionTypesStruct {
} }
} }
} }
LootFunctionTypesStruct::CopyState { block, properties } => { Self::CopyState { block, properties } => {
quote! { quote! {
LootFunctionTypes::CopyState { LootFunctionTypes::CopyState {
block: #block, block: #block,
@ -390,7 +388,7 @@ impl ToTokens for LootFunctionTypesStruct {
} }
} }
} }
LootFunctionTypesStruct::ExplosionDecay => { Self::ExplosionDecay => {
quote! { LootFunctionTypes::ExplosionDecay } quote! { LootFunctionTypes::ExplosionDecay }
} }
}; };
@ -473,19 +471,17 @@ pub struct LootPoolEntryStruct {
impl ToTokens for LootPoolEntryStruct { impl ToTokens for LootPoolEntryStruct {
fn to_tokens(&self, tokens: &mut TokenStream) { fn to_tokens(&self, tokens: &mut TokenStream) {
let content = &self.content; let content = &self.content;
let conditions_tokens = match &self.conditions { let conditions_tokens = if let Some(conds) = &self.conditions {
Some(conds) => { let cond_tokens: Vec<_> = conds.iter().map(quote::ToTokens::to_token_stream).collect();
let cond_tokens: Vec<_> = conds.iter().map(|c| c.to_token_stream()).collect();
quote! { Some(&[#(#cond_tokens),*]) } quote! { Some(&[#(#cond_tokens),*]) }
} } else {
None => quote! { None }, quote! { None }
}; };
let functions_tokens = match &self.functions { let functions_tokens = if let Some(fns) = &self.functions {
Some(fns) => { let cond_tokens: Vec<_> = fns.iter().map(quote::ToTokens::to_token_stream).collect();
let cond_tokens: Vec<_> = fns.iter().map(|c| c.to_token_stream()).collect();
quote! { Some(&[#(#cond_tokens),*]) } quote! { Some(&[#(#cond_tokens),*]) }
} } else {
None => quote! { None }, quote! { None }
}; };
tokens.extend(quote! { tokens.extend(quote! {
@ -518,10 +514,10 @@ pub enum LootTableTypeStruct {
impl ToTokens for LootTableTypeStruct { impl ToTokens for LootTableTypeStruct {
fn to_tokens(&self, tokens: &mut TokenStream) { fn to_tokens(&self, tokens: &mut TokenStream) {
let name = match self { let name = match self {
LootTableTypeStruct::Empty => quote! { LootTableType::Empty }, Self::Empty => quote! { LootTableType::Empty },
LootTableTypeStruct::Entity => quote! { LootTableType::Entity }, Self::Entity => quote! { LootTableType::Entity },
LootTableTypeStruct::Block => quote! { LootTableType::Block }, Self::Block => quote! { LootTableType::Block },
LootTableTypeStruct::Chest => quote! { LootTableType::Chest }, Self::Chest => quote! { LootTableType::Chest },
}; };
tokens.extend(name); tokens.extend(name);

View File

@ -32,7 +32,7 @@ pub(crate) fn build() -> TokenStream {
.expect("Failed to parse message_type.json"); .expect("Failed to parse message_type.json");
let mut variants = TokenStream::new(); let mut variants = TokenStream::new();
for (name, typee) in json.iter() { for (name, typee) in &json {
let i = typee.id as u8; let i = typee.id as u8;
let name = format_ident!("{}", name.to_uppercase()); let name = format_ident!("{}", name.to_uppercase());
variants.extend([quote! { variants.extend([quote! {

View File

@ -13,7 +13,7 @@ pub(crate) fn build() -> TokenStream {
let mut variants = TokenStream::new(); let mut variants = TokenStream::new();
let mut match_variants = TokenStream::new(); let mut match_variants = TokenStream::new();
for (name, parameter) in json.iter() { for (name, parameter) in &json {
let raw_name = format!("minecraft:{name}"); let raw_name = format!("minecraft:{name}");
let simple_id = name; let simple_id = name;
let name = format_ident!("{}", name.to_uppercase()); let name = format_ident!("{}", name.to_uppercase());

View File

@ -87,7 +87,7 @@ enum SplineRepr {
#[serde(rename(deserialize = "locationFunction"))] #[serde(rename(deserialize = "locationFunction"))]
location_function: Box<DensityFunctionRepr>, location_function: Box<DensityFunctionRepr>,
locations: Box<[HashableF32]>, locations: Box<[HashableF32]>,
values: Box<[SplineRepr]>, values: Box<[Self]>,
derivatives: Box<[HashableF32]>, derivatives: Box<[HashableF32]>,
}, },
#[serde(rename(deserialize = "fixed"))] #[serde(rename(deserialize = "fixed"))]
@ -459,7 +459,7 @@ enum DensityFunctionRepr {
BlendAlpha, BlendAlpha,
BlendOffset, BlendOffset,
BlendDensity { BlendDensity {
input: Box<DensityFunctionRepr>, input: Box<Self>,
}, },
EndIslands, EndIslands,
Noise { Noise {
@ -476,11 +476,11 @@ enum DensityFunctionRepr {
}, },
ShiftedNoise { ShiftedNoise {
#[serde(rename(deserialize = "shiftX"))] #[serde(rename(deserialize = "shiftX"))]
shift_x: Box<DensityFunctionRepr>, shift_x: Box<Self>,
#[serde(rename(deserialize = "shiftY"))] #[serde(rename(deserialize = "shiftY"))]
shift_y: Box<DensityFunctionRepr>, shift_y: Box<Self>,
#[serde(rename(deserialize = "shiftZ"))] #[serde(rename(deserialize = "shiftZ"))]
shift_z: Box<DensityFunctionRepr>, shift_z: Box<Self>,
#[serde(flatten)] #[serde(flatten)]
data: ShiftedNoiseData, data: ShiftedNoiseData,
}, },
@ -490,7 +490,7 @@ enum DensityFunctionRepr {
}, },
#[serde(rename(deserialize = "WeirdScaledSampler"))] #[serde(rename(deserialize = "WeirdScaledSampler"))]
WeirdScaled { WeirdScaled {
input: Box<DensityFunctionRepr>, input: Box<Self>,
#[serde(flatten)] #[serde(flatten)]
data: WeirdScaledData, data: WeirdScaledData,
}, },
@ -498,7 +498,7 @@ enum DensityFunctionRepr {
#[serde(rename(deserialize = "Wrapping"))] #[serde(rename(deserialize = "Wrapping"))]
Wrapper { Wrapper {
#[serde(rename(deserialize = "wrapped"))] #[serde(rename(deserialize = "wrapped"))]
input: Box<DensityFunctionRepr>, input: Box<Self>,
#[serde(rename(deserialize = "type"))] #[serde(rename(deserialize = "type"))]
wrapper: WrapperType, wrapper: WrapperType,
}, },
@ -513,34 +513,34 @@ enum DensityFunctionRepr {
}, },
#[serde(rename(deserialize = "BinaryOperation"))] #[serde(rename(deserialize = "BinaryOperation"))]
Binary { Binary {
argument1: Box<DensityFunctionRepr>, argument1: Box<Self>,
argument2: Box<DensityFunctionRepr>, argument2: Box<Self>,
#[serde(flatten)] #[serde(flatten)]
data: BinaryData, data: BinaryData,
}, },
#[serde(rename(deserialize = "LinearOperation"))] #[serde(rename(deserialize = "LinearOperation"))]
Linear { Linear {
input: Box<DensityFunctionRepr>, input: Box<Self>,
#[serde(flatten)] #[serde(flatten)]
data: LinearData, data: LinearData,
}, },
#[serde(rename(deserialize = "UnaryOperation"))] #[serde(rename(deserialize = "UnaryOperation"))]
Unary { Unary {
input: Box<DensityFunctionRepr>, input: Box<Self>,
#[serde(flatten)] #[serde(flatten)]
data: UnaryData, data: UnaryData,
}, },
Clamp { Clamp {
input: Box<DensityFunctionRepr>, input: Box<Self>,
#[serde(flatten)] #[serde(flatten)]
data: ClampData, data: ClampData,
}, },
RangeChoice { RangeChoice {
input: Box<DensityFunctionRepr>, input: Box<Self>,
#[serde(rename(deserialize = "whenInRange"))] #[serde(rename(deserialize = "whenInRange"))]
when_in_range: Box<DensityFunctionRepr>, when_in_range: Box<Self>,
#[serde(rename(deserialize = "whenOutOfRange"))] #[serde(rename(deserialize = "whenOutOfRange"))]
when_out_range: Box<DensityFunctionRepr>, when_out_range: Box<Self>,
#[serde(flatten)] #[serde(flatten)]
data: RangeChoiceData, data: RangeChoiceData,
}, },
@ -720,8 +720,8 @@ impl DensityFunctionRepr {
} }
} }
Self::ClampedYGradient { data } => { Self::ClampedYGradient { data } => {
let from_y = data.from_y as f64; let from_y = f64::from(data.from_y);
let to_y = data.to_y as f64; let to_y = f64::from(data.to_y);
let from_value = &data.from_value; let from_value = &data.from_value;
let to_value = &data.to_value; let to_value = &data.to_value;

View File

@ -92,14 +92,14 @@ fn generate_mapped_consts(latest: &Packets, v7: &Packets, is_serverbound: bool)
for (phase, packets) in latest_phases { for (phase, packets) in latest_phases {
for (name, id_11) in packets { for (name, id_11) in packets {
let sanitized = name.replace("/", "_").replace("-", "_").to_uppercase(); let sanitized = name.replace(['/', '-'], "_").to_uppercase();
let const_name = format_ident!("{}_{}", phase.to_uppercase(), sanitized); let const_name = format_ident!("{}_{}", phase.to_uppercase(), sanitized);
// Check if the packet exists in 1.21.7 to get the alternate ID // Check if the packet exists in 1.21.7 to get the alternate ID
let id_7 = v7_phases let id_7 = v7_phases
.get(phase) .get(phase)
.and_then(|p| p.get(name)) .and_then(|p| p.get(name))
.cloned() .copied()
.unwrap_or(-1); .unwrap_or(-1);
// Since serverbound/clientbound are modules, we reference the PacketId in the parent scope // Since serverbound/clientbound are modules, we reference the PacketId in the parent scope

View File

@ -59,11 +59,11 @@ pub(crate) fn build() -> TokenStream {
let mut variants = TokenStream::new(); let mut variants = TokenStream::new();
let mut name_to_type = TokenStream::new(); let mut name_to_type = TokenStream::new();
for (name, potion) in potions.into_iter() { for (name, potion) in potions {
let format_name = format_ident!("{}", name.to_shouty_snake_case()); let format_name = format_ident!("{}", name.to_shouty_snake_case());
let id = potion.id; let id = potion.id;
let slots = potion.effects; let slots = potion.effects;
let slots = slots.iter().map(|slot| slot.to_tokens()); let slots = slots.iter().map(Effect::to_tokens);
variants.extend([quote! { variants.extend([quote! {
pub const #format_name: Self = Self { pub const #format_name: Self = Self {

View File

@ -81,7 +81,7 @@ pub(crate) fn build() -> TokenStream {
let item_recipes_tokens: Vec<TokenStream> = json let item_recipes_tokens: Vec<TokenStream> = json
.item_recipes .item_recipes
.into_iter() .into_iter()
.map(|recipe| recipe.get_tokens_item()) .map(Recipes::get_tokens_item)
.collect(); .collect();
let item_len = item_recipes_tokens.len(); let item_len = item_recipes_tokens.len();
@ -89,7 +89,7 @@ pub(crate) fn build() -> TokenStream {
let potion_recipes_tokens: Vec<TokenStream> = json let potion_recipes_tokens: Vec<TokenStream> = json
.potion_recipes .potion_recipes
.into_iter() .into_iter()
.map(|recipe| recipe.get_tokens_potion()) .map(Recipes::get_tokens_potion)
.collect(); .collect();
let potion_len = potion_recipes_tokens.len(); let potion_len = potion_recipes_tokens.len();

View File

@ -50,9 +50,10 @@ impl ToTokens for CookingRecipeStruct {
Some(category) => category.to_token_stream(), Some(category) => category.to_token_stream(),
None => RecipeCategoryTypes::Misc.to_token_stream(), None => RecipeCategoryTypes::Misc.to_token_stream(),
}; };
let group = match &self.group { let group = if let Some(group) = &self.group {
Some(group) => quote! { Some(#group) }, quote! { Some(#group) }
None => quote! { None }, } else {
quote! { None }
}; };
let ingredient = self.ingredient.to_token_stream(); let ingredient = self.ingredient.to_token_stream();
let cookingtime = self.cookingtime.to_token_stream(); let cookingtime = self.cookingtime.to_token_stream();
@ -88,9 +89,10 @@ impl ToTokens for CraftingShapedRecipeStruct {
Some(category) => category.to_token_stream(), Some(category) => category.to_token_stream(),
None => RecipeCategoryTypes::Misc.to_token_stream(), None => RecipeCategoryTypes::Misc.to_token_stream(),
}; };
let group = match &self.group { let group = if let Some(group) = &self.group {
Some(group) => quote! { Some(#group) }, quote! { Some(#group) }
None => quote! { None }, } else {
quote! { None }
}; };
let show_notification = self.show_notification.unwrap_or(true); let show_notification = self.show_notification.unwrap_or(true);
let key = self let key = self
@ -104,7 +106,7 @@ impl ToTokens for CraftingShapedRecipeStruct {
let pattern = self let pattern = self
.pattern .pattern
.iter() .iter()
.map(|c| c.to_token_stream()) .map(quote::ToTokens::to_token_stream)
.collect::<Vec<_>>(); .collect::<Vec<_>>();
let result = self.result.to_token_stream(); let result = self.result.to_token_stream();
@ -135,14 +137,15 @@ impl ToTokens for CraftingShapelessRecipeStruct {
Some(category) => category.to_token_stream(), Some(category) => category.to_token_stream(),
None => RecipeCategoryTypes::Misc.to_token_stream(), None => RecipeCategoryTypes::Misc.to_token_stream(),
}; };
let group = match &self.group { let group = if let Some(group) = &self.group {
Some(group) => quote! { Some(#group) }, quote! { Some(#group) }
None => quote! { None }, } else {
quote! { None }
}; };
let ingredients = self let ingredients = self
.ingredients .ingredients
.iter() .iter()
.map(|c| c.to_token_stream()) .map(quote::ToTokens::to_token_stream)
.collect::<Vec<_>>(); .collect::<Vec<_>>();
let result = self.result.to_token_stream(); let result = self.result.to_token_stream();
@ -172,9 +175,10 @@ impl ToTokens for CraftingTransmuteRecipeStruct {
Some(category) => category.to_token_stream(), Some(category) => category.to_token_stream(),
None => RecipeCategoryTypes::Misc.to_token_stream(), None => RecipeCategoryTypes::Misc.to_token_stream(),
}; };
let group = match &self.group { let group = if let Some(group) = &self.group {
Some(group) => quote! { Some(#group) }, quote! { Some(#group) }
None => quote! { None }, } else {
quote! { None }
}; };
let input = self.input.to_token_stream(); let input = self.input.to_token_stream();
let material = self.material.to_token_stream(); let material = self.material.to_token_stream();
@ -243,17 +247,17 @@ pub enum RecipeIngredientTypes {
impl ToTokens for RecipeIngredientTypes { impl ToTokens for RecipeIngredientTypes {
fn to_tokens(&self, tokens: &mut TokenStream) { fn to_tokens(&self, tokens: &mut TokenStream) {
let name = match self { let name = match self {
RecipeIngredientTypes::Simple(ingredient) => { Self::Simple(ingredient) => {
if ingredient.starts_with("#") { if ingredient.starts_with('#') {
quote! { RecipeIngredientTypes::Tagged(#ingredient) } quote! { RecipeIngredientTypes::Tagged(#ingredient) }
} else { } else {
quote! { RecipeIngredientTypes::Simple(#ingredient) } quote! { RecipeIngredientTypes::Simple(#ingredient) }
} }
} }
RecipeIngredientTypes::OneOf(ingredients) => { Self::OneOf(ingredients) => {
let ingredients = ingredients let ingredients = ingredients
.iter() .iter()
.map(|c| c.to_token_stream()) .map(quote::ToTokens::to_token_stream)
.collect::<Vec<_>>(); .collect::<Vec<_>>();
quote! { RecipeIngredientTypes::OneOf(&[#(#ingredients),*]) } quote! { RecipeIngredientTypes::OneOf(&[#(#ingredients),*]) }
} }
@ -282,22 +286,22 @@ pub enum RecipeCategoryTypes {
impl ToTokens for RecipeCategoryTypes { impl ToTokens for RecipeCategoryTypes {
fn to_tokens(&self, tokens: &mut TokenStream) { fn to_tokens(&self, tokens: &mut TokenStream) {
let name = match self { let name = match self {
RecipeCategoryTypes::Equipment => { Self::Equipment => {
quote! { RecipeCategoryTypes::Equipment } quote! { RecipeCategoryTypes::Equipment }
} }
RecipeCategoryTypes::Building => { Self::Building => {
quote! { RecipeCategoryTypes::Building } quote! { RecipeCategoryTypes::Building }
} }
RecipeCategoryTypes::Restone => { Self::Restone => {
quote! { RecipeCategoryTypes::Restone } quote! { RecipeCategoryTypes::Restone }
} }
RecipeCategoryTypes::Misc => { Self::Misc => {
quote! { RecipeCategoryTypes::Misc } quote! { RecipeCategoryTypes::Misc }
} }
RecipeCategoryTypes::Food => { Self::Food => {
quote! { RecipeCategoryTypes::Food } quote! { RecipeCategoryTypes::Food }
} }
RecipeCategoryTypes::Blocks => { Self::Blocks => {
quote! { RecipeCategoryTypes::Blocks } quote! { RecipeCategoryTypes::Blocks }
} }
}; };

View File

@ -9,8 +9,7 @@ pub(crate) fn build() -> TokenStream {
println!("cargo:rerun-if-changed=../assets/registry/1_21_11_synced_registries.json"); println!("cargo:rerun-if-changed=../assets/registry/1_21_11_synced_registries.json");
let process_version = |path: &str| -> TokenStream { let process_version = |path: &str| -> TokenStream {
let json_str = let json_str = fs::read_to_string(path).unwrap_or_else(|_| panic!("Failed to read {path}"));
fs::read_to_string(path).unwrap_or_else(|_| panic!("Failed to read {}", path));
let mut data: IndexMap<String, IndexMap<String, Value>> = let mut data: IndexMap<String, IndexMap<String, Value>> =
serde_json::from_str(&json_str).expect("Failed to parse JSON"); serde_json::from_str(&json_str).expect("Failed to parse JSON");

View File

@ -115,7 +115,7 @@ pub(crate) fn build() -> TokenStream {
let versions = vec![latest_version_key, legacy_version_key]; let versions = vec![latest_version_key, legacy_version_key];
for version in versions { for version in versions {
let file_path = format!("../assets/tags/{}_tags.json", version); let file_path = format!("../assets/tags/{version}_tags.json");
if !Path::new(&file_path).exists() { if !Path::new(&file_path).exists() {
continue; continue;
} }
@ -144,13 +144,13 @@ pub(crate) fn build() -> TokenStream {
let ids: Vec<u16> = values let ids: Vec<u16> = values
.iter() .iter()
.filter_map(|v| match key.as_str() { .filter_map(|v| match key.as_str() {
"worldgen/biome" => biomes.get(v).map(|b| b.id as u16), "worldgen/biome" => biomes.get(v).map(|b| u16::from(b.id)),
"fluid" => fluid_id_map.get(v).copied(), "fluid" => fluid_id_map.get(v).copied(),
"item" => items.get(v).map(|i| i.id), "item" => items.get(v).map(|i| i.id),
"block" => block_id_map.get(v).copied(), "block" => block_id_map.get(v).copied(),
"enchantment" => enchantments "enchantment" => enchantments
.get(&format!("minecraft:{}", v)) .get(&format!("minecraft:{v}"))
.map(|e| e.id as u16), .map(|e| u16::from(e.id)),
"entity_type" => entities.get(v).map(|e| e.id), "entity_type" => entities.get(v).map(|e| e.id),
_ => None, _ => None,
}) })

View File

@ -24,7 +24,7 @@ pub(crate) fn build() -> TokenStream {
for (name, id_11) in &data_11 { for (name, id_11) in &data_11 {
let ident = format_ident!("DATA_{}", name.to_uppercase()); let ident = format_ident!("DATA_{}", name.to_uppercase());
let id_7 = data_7.get(name).cloned().unwrap_or(255); // 255 as an 'Invalid' marker let id_7 = data_7.get(name).copied().unwrap_or(255); // 255 as an 'Invalid' marker
constants.extend(quote! { constants.extend(quote! {
pub const #ident: TrackedId = TrackedId { pub const #ident: TrackedId = TrackedId {

View File

@ -27,7 +27,7 @@ impl From<MathAxis> for Axis {
} }
} }
impl From<Axis> for MathAxis { impl From<Axis> for MathAxis {
fn from(a: Axis) -> MathAxis { fn from(a: Axis) -> Self {
match a { match a {
Axis::X => Self::X, Axis::X => Self::X,
Axis::Y => Self::Y, Axis::Y => Self::Y,
@ -55,17 +55,19 @@ impl TryFrom<i32> for BlockDirection {
} }
impl BlockDirection { impl BlockDirection {
#[must_use]
pub fn to_index(&self) -> u8 { pub fn to_index(&self) -> u8 {
match self { match self {
BlockDirection::Down => 0, Self::Down => 0,
BlockDirection::Up => 1, Self::Up => 1,
BlockDirection::North => 2, Self::North => 2,
BlockDirection::South => 3, Self::South => 3,
BlockDirection::West => 4, Self::West => 4,
BlockDirection::East => 5, Self::East => 5,
} }
} }
#[must_use]
pub fn from_index(index: u8) -> Option<Self> { pub fn from_index(index: u8) -> Option<Self> {
match index { match index {
0 => Some(Self::Down), 0 => Some(Self::Down),
@ -86,176 +88,173 @@ impl BlockDirection {
Self::horizontal()[random.next_bounded_i32(Self::horizontal().len() as i32 - 1) as usize] Self::horizontal()[random.next_bounded_i32(Self::horizontal().len() as i32 - 1) as usize]
} }
#[must_use]
pub fn by_index(index: usize) -> Option<Self> { pub fn by_index(index: usize) -> Option<Self> {
Self::all().get(index % Self::all().len()).cloned() Self::all().get(index % Self::all().len()).copied()
} }
#[must_use]
pub fn to_offset(&self) -> Vector3<i32> { pub fn to_offset(&self) -> Vector3<i32> {
match self { match self {
BlockDirection::Down => (0, -1, 0), Self::Down => (0, -1, 0),
BlockDirection::Up => (0, 1, 0), Self::Up => (0, 1, 0),
BlockDirection::North => (0, 0, -1), Self::North => (0, 0, -1),
BlockDirection::South => (0, 0, 1), Self::South => (0, 0, 1),
BlockDirection::West => (-1, 0, 0), Self::West => (-1, 0, 0),
BlockDirection::East => (1, 0, 0), Self::East => (1, 0, 0),
} }
.into() .into()
} }
pub fn opposite(&self) -> BlockDirection { #[must_use]
pub fn opposite(&self) -> Self {
match self { match self {
BlockDirection::Down => BlockDirection::Up, Self::Down => Self::Up,
BlockDirection::Up => BlockDirection::Down, Self::Up => Self::Down,
BlockDirection::North => BlockDirection::South, Self::North => Self::South,
BlockDirection::South => BlockDirection::North, Self::South => Self::North,
BlockDirection::West => BlockDirection::East, Self::West => Self::East,
BlockDirection::East => BlockDirection::West, Self::East => Self::West,
} }
} }
#[must_use]
pub fn positive(&self) -> bool { pub fn positive(&self) -> bool {
matches!(self, Self::South | Self::East | Self::Up) matches!(self, Self::South | Self::East | Self::Up)
} }
pub fn all() -> [BlockDirection; 6] { #[must_use]
pub fn all() -> [Self; 6] {
[ [
BlockDirection::Down, Self::Down,
BlockDirection::Up, Self::Up,
BlockDirection::North, Self::North,
BlockDirection::South, Self::South,
BlockDirection::West, Self::West,
BlockDirection::East, Self::East,
] ]
} }
pub fn update_order() -> [BlockDirection; 6] { #[must_use]
pub fn update_order() -> [Self; 6] {
[ [
BlockDirection::West, Self::West,
BlockDirection::East, Self::East,
BlockDirection::Down, Self::Down,
BlockDirection::Up, Self::Up,
BlockDirection::North, Self::North,
BlockDirection::South, Self::South,
] ]
} }
pub fn abstract_block_update_order() -> [BlockDirection; 6] { #[must_use]
pub fn abstract_block_update_order() -> [Self; 6] {
[ [
BlockDirection::West, Self::West,
BlockDirection::East, Self::East,
BlockDirection::North, Self::North,
BlockDirection::South, Self::South,
BlockDirection::Down, Self::Down,
BlockDirection::Up, Self::Up,
] ]
} }
pub fn horizontal() -> [BlockDirection; 4] { #[must_use]
[ pub fn horizontal() -> [Self; 4] {
BlockDirection::North, [Self::North, Self::South, Self::West, Self::East]
BlockDirection::South,
BlockDirection::West,
BlockDirection::East,
]
} }
pub fn flow_directions() -> [BlockDirection; 5] { #[must_use]
[ pub fn flow_directions() -> [Self; 5] {
BlockDirection::Down, [Self::Down, Self::North, Self::South, Self::West, Self::East]
BlockDirection::North,
BlockDirection::South,
BlockDirection::West,
BlockDirection::East,
]
} }
#[must_use]
pub fn is_horizontal(&self) -> bool { pub fn is_horizontal(&self) -> bool {
matches!( matches!(self, Self::North | Self::South | Self::West | Self::East)
self,
BlockDirection::North
| BlockDirection::South
| BlockDirection::West
| BlockDirection::East
)
} }
pub fn vertical() -> [BlockDirection; 2] { #[must_use]
[BlockDirection::Down, BlockDirection::Up] pub fn vertical() -> [Self; 2] {
[Self::Down, Self::Up]
} }
#[must_use]
pub fn to_horizontal_facing(&self) -> Option<HorizontalFacing> { pub fn to_horizontal_facing(&self) -> Option<HorizontalFacing> {
match self { match self {
BlockDirection::North => Some(HorizontalFacing::North), Self::North => Some(HorizontalFacing::North),
BlockDirection::South => Some(HorizontalFacing::South), Self::South => Some(HorizontalFacing::South),
BlockDirection::West => Some(HorizontalFacing::West), Self::West => Some(HorizontalFacing::West),
BlockDirection::East => Some(HorizontalFacing::East), Self::East => Some(HorizontalFacing::East),
_ => None, _ => None,
} }
} }
#[must_use]
pub fn to_horizontal_axis(&self) -> Option<HorizontalAxis> { pub fn to_horizontal_axis(&self) -> Option<HorizontalAxis> {
match self { match self {
BlockDirection::North | BlockDirection::South => Some(HorizontalAxis::Z), Self::North | Self::South => Some(HorizontalAxis::Z),
BlockDirection::West | BlockDirection::East => Some(HorizontalAxis::X), Self::West | Self::East => Some(HorizontalAxis::X),
_ => None, _ => None,
} }
} }
#[must_use]
pub fn to_cardinal_direction(&self) -> HorizontalFacing { pub fn to_cardinal_direction(&self) -> HorizontalFacing {
match self { match self {
BlockDirection::North => HorizontalFacing::North, Self::South => HorizontalFacing::South,
BlockDirection::South => HorizontalFacing::South, Self::West => HorizontalFacing::West,
BlockDirection::West => HorizontalFacing::West, Self::East => HorizontalFacing::East,
BlockDirection::East => HorizontalFacing::East,
_ => HorizontalFacing::North, _ => HorizontalFacing::North,
} }
} }
pub fn from_cardinal_direction(direction: HorizontalFacing) -> BlockDirection { #[must_use]
pub fn from_cardinal_direction(direction: HorizontalFacing) -> Self {
match direction { match direction {
HorizontalFacing::North => BlockDirection::North, HorizontalFacing::North => Self::North,
HorizontalFacing::South => BlockDirection::South, HorizontalFacing::South => Self::South,
HorizontalFacing::West => BlockDirection::West, HorizontalFacing::West => Self::West,
HorizontalFacing::East => BlockDirection::East, HorizontalFacing::East => Self::East,
} }
} }
#[must_use]
pub fn to_axis(&self) -> Axis { pub fn to_axis(&self) -> Axis {
match self { match self {
BlockDirection::North | BlockDirection::South => Axis::Z, Self::North | Self::South => Axis::Z,
BlockDirection::West | BlockDirection::East => Axis::X, Self::West | Self::East => Axis::X,
BlockDirection::Up | BlockDirection::Down => Axis::Y, Self::Up | Self::Down => Axis::Y,
} }
} }
#[must_use]
pub fn to_facing(&self) -> Facing { pub fn to_facing(&self) -> Facing {
match self { match self {
BlockDirection::North => Facing::North, Self::North => Facing::North,
BlockDirection::South => Facing::South, Self::South => Facing::South,
BlockDirection::West => Facing::West, Self::West => Facing::West,
BlockDirection::East => Facing::East, Self::East => Facing::East,
BlockDirection::Up => Facing::Up, Self::Up => Facing::Up,
BlockDirection::Down => Facing::Down, Self::Down => Facing::Down,
} }
} }
pub fn rotate_clockwise(&self) -> BlockDirection { #[must_use]
pub fn rotate_clockwise(&self) -> Self {
match self { match self {
BlockDirection::North => BlockDirection::East, Self::East => Self::South,
BlockDirection::East => BlockDirection::South, Self::West => Self::North,
BlockDirection::South => BlockDirection::West, Self::Up | Self::North => Self::East,
BlockDirection::West => BlockDirection::North, Self::Down | Self::South => Self::West,
BlockDirection::Up => BlockDirection::East,
BlockDirection::Down => BlockDirection::West,
} }
} }
pub fn rotate_counter_clockwise(&self) -> BlockDirection { #[must_use]
pub fn rotate_counter_clockwise(&self) -> Self {
match self { match self {
BlockDirection::North => BlockDirection::West, Self::West => Self::South,
BlockDirection::West => BlockDirection::South, Self::East => Self::North,
BlockDirection::South => BlockDirection::East, Self::Up | Self::North => Self::West,
BlockDirection::East => BlockDirection::North, Self::Down | Self::South => Self::East,
BlockDirection::Up => BlockDirection::West,
BlockDirection::Down => BlockDirection::East,
} }
} }
} }

View File

@ -52,35 +52,43 @@ pub enum PistonBehavior {
} }
impl BlockState { impl BlockState {
#[must_use]
pub const fn is_air(&self) -> bool { pub const fn is_air(&self) -> bool {
self.state_flags & IS_AIR != 0 self.state_flags & IS_AIR != 0
} }
#[must_use]
pub const fn burnable(&self) -> bool { pub const fn burnable(&self) -> bool {
self.state_flags & BURNABLE != 0 self.state_flags & BURNABLE != 0
} }
#[must_use]
pub const fn tool_required(&self) -> bool { pub const fn tool_required(&self) -> bool {
self.state_flags & TOOL_REQUIRED != 0 self.state_flags & TOOL_REQUIRED != 0
} }
#[must_use]
pub const fn sided_transparency(&self) -> bool { pub const fn sided_transparency(&self) -> bool {
self.state_flags & SIDED_TRANSPARENCY != 0 self.state_flags & SIDED_TRANSPARENCY != 0
} }
#[must_use]
pub const fn replaceable(&self) -> bool { pub const fn replaceable(&self) -> bool {
self.state_flags & REPLACEABLE != 0 self.state_flags & REPLACEABLE != 0
} }
#[must_use]
pub const fn is_liquid(&self) -> bool { pub const fn is_liquid(&self) -> bool {
self.state_flags & IS_LIQUID != 0 self.state_flags & IS_LIQUID != 0
} }
/// Returns the legacy value for whether a block is solid. /// Returns the legacy value for whether a block is solid.
#[must_use]
pub const fn is_solid(&self) -> bool { pub const fn is_solid(&self) -> bool {
self.state_flags & IS_SOLID != 0 self.state_flags & IS_SOLID != 0
} }
#[must_use]
pub const fn is_full_cube(&self) -> bool { pub const fn is_full_cube(&self) -> bool {
self.state_flags & IS_FULL_CUBE != 0 self.state_flags & IS_FULL_CUBE != 0
} }
@ -88,15 +96,18 @@ impl BlockState {
/// Returns whether the block is solid. /// Returns whether the block is solid.
/// Solid blocks conduct redstone and block redstone wire. /// Solid blocks conduct redstone and block redstone wire.
/// Non-solid blocks don't allow redstone wire on top to propagate their signal downwards in java. /// Non-solid blocks don't allow redstone wire on top to propagate their signal downwards in java.
#[must_use]
pub const fn is_solid_block(&self) -> bool { pub const fn is_solid_block(&self) -> bool {
self.state_flags & IS_SOLID_BLOCK != 0 self.state_flags & IS_SOLID_BLOCK != 0
} }
#[must_use]
pub const fn has_random_ticks(&self) -> bool { pub const fn has_random_ticks(&self) -> bool {
self.state_flags & HAS_RANDOM_TICKS != 0 self.state_flags & HAS_RANDOM_TICKS != 0
} }
///isSideSolidFullSquare() in Java! ///`isSideSolidFullSquare()` in Java!
#[must_use]
pub const fn is_side_solid(&self, side: BlockDirection) -> bool { pub const fn is_side_solid(&self, side: BlockDirection) -> bool {
match side { match side {
BlockDirection::Down => self.side_flags & DOWN_SIDE_SOLID != 0, BlockDirection::Down => self.side_flags & DOWN_SIDE_SOLID != 0,
@ -110,6 +121,7 @@ impl BlockState {
///isSideSolid(..., Direction.UP, SideShapeType.CENTER) in Java! ///isSideSolid(..., Direction.UP, SideShapeType.CENTER) in Java!
///Only valid for UP and DOWN sides ///Only valid for UP and DOWN sides
#[must_use]
pub const fn is_center_solid(&self, side: BlockDirection) -> bool { pub const fn is_center_solid(&self, side: BlockDirection) -> bool {
match side { match side {
BlockDirection::Down => self.side_flags & DOWN_CENTER_SOLID != 0, BlockDirection::Down => self.side_flags & DOWN_CENTER_SOLID != 0,
@ -118,17 +130,16 @@ impl BlockState {
} }
} }
#[must_use]
pub fn is_waterlogged(&self) -> bool { pub fn is_waterlogged(&self) -> bool {
let block = Block::from_state_id(self.id); let block = Block::from_state_id(self.id);
if let Some(props) = block.properties(self.id) { block.properties(self.id).is_some_and(|props| {
props props
.to_props() .to_props()
.iter() .iter()
.any(|(k, v)| k == &"waterlogged" && v == &"true") .any(|(k, v)| k == &"waterlogged" && v == &"true")
} else { })
false
}
} }
pub fn get_block_collision_shapes(&self) -> impl Iterator<Item = CollisionShape> + '_ { pub fn get_block_collision_shapes(&self) -> impl Iterator<Item = CollisionShape> + '_ {
@ -143,14 +154,9 @@ impl BlockState {
.iter() .iter()
.map(|&id| COLLISION_SHAPES[id as usize]); .map(|&id| COLLISION_SHAPES[id as usize]);
let water_shape = if self.is_waterlogged() { let water_shape = self.is_waterlogged().then(|| {
Some(CollisionShape::new( CollisionShape::new(Vector3::new(0.0, 0.0, 0.0), Vector3::new(1.0, 0.875, 1.0))
Vector3::new(0.0, 0.0, 0.0), });
Vector3::new(1.0, 0.875, 1.0),
))
} else {
None
};
base_shapes.chain(water_shape) base_shapes.chain(water_shape)
} }

View File

@ -18,9 +18,9 @@ use std::hash::{Hash, Hasher};
pub struct Block { pub struct Block {
/// The numeric ID used for internal registry mapping. /// The numeric ID used for internal registry mapping.
pub id: u16, pub id: u16,
/// The unique namespaced ID (e.g., "diamond_ore"). /// The unique namespaced ID (e.g., "`diamond_ore`").
pub name: &'static str, pub name: &'static str,
/// The key used for client-side localization (e.g., "block.minecraft.diamond_ore"). /// The key used for client-side localization (e.g., "`block.minecraft.diamond_ore`").
pub translation_key: &'static str, pub translation_key: &'static str,
/// How hard the block is to break. A value of -1.0 indicates an unbreakable block (e.g., Bedrock). /// How hard the block is to break. A value of -1.0 indicates an unbreakable block (e.g., Bedrock).
pub hardness: f32, pub hardness: f32,
@ -102,6 +102,7 @@ impl FromResourceLocation for &'static Block {
} }
impl Block { impl Block {
#[must_use]
pub fn is_waterlogged(&self, state_id: u16) -> bool { pub fn is_waterlogged(&self, state_id: u16) -> bool {
self.properties(state_id).is_some_and(|properties| { self.properties(state_id).is_some_and(|properties| {
properties properties

View File

@ -7,6 +7,7 @@ pub struct CollisionShape {
} }
impl CollisionShape { impl CollisionShape {
#[must_use]
pub fn to_bounding_box(&self) -> BoundingBox { pub fn to_bounding_box(&self) -> BoundingBox {
BoundingBox { BoundingBox {
min: self.min, min: self.min,
@ -14,10 +15,12 @@ impl CollisionShape {
} }
} }
#[must_use]
pub fn new(min: Vector3<f64>, max: Vector3<f64>) -> Self { pub fn new(min: Vector3<f64>, max: Vector3<f64>) -> Self {
Self { min, max } Self { min, max }
} }
#[must_use]
pub fn intersects(&self, other: &BoundingBox) -> bool { pub fn intersects(&self, other: &BoundingBox) -> bool {
self.min.x < other.max.x self.min.x < other.max.x
&& self.max.x > other.min.x && self.max.x > other.min.x
@ -27,11 +30,12 @@ impl CollisionShape {
&& self.max.z > other.min.z && self.max.z > other.min.z
} }
#[must_use]
pub fn at_pos(&self, pos: BlockPos) -> Self { pub fn at_pos(&self, pos: BlockPos) -> Self {
let vec3 = Vector3 { let vec3 = Vector3 {
x: pos.0.x as f64, x: f64::from(pos.0.x),
y: pos.0.y as f64, y: f64::from(pos.0.y),
z: pos.0.z as f64, z: f64::from(pos.0.z),
}; };
Self { Self {
min: self.min + vec3, min: self.min + vec3,

View File

@ -2,7 +2,11 @@
use crate::attributes::Attributes; use crate::attributes::Attributes;
use crate::data_component::DataComponent; use crate::data_component::DataComponent;
use crate::data_component::DataComponent::*; use crate::data_component::DataComponent::{
AttributeModifiers, BlocksAttacks, Consumable, CustomData, CustomName, Damage, DeathProtection,
Enchantments, Equippable, Food, ItemName, JukeboxPlayable, MaxDamage, MaxStackSize, Tool,
Unbreakable,
};
use crate::entity_type::EntityType; use crate::entity_type::EntityType;
use crate::tag::{Tag, Taggable}; use crate::tag::{Tag, Taggable};
use crate::{AttributeModifierSlot, Block, Enchantment}; use crate::{AttributeModifierSlot, Block, Enchantment};
@ -38,6 +42,7 @@ pub trait DataComponentImpl: Send + Sync {
fn as_any(&self) -> &dyn Any; fn as_any(&self) -> &dyn Any;
fn as_mut_any(&mut self) -> &mut dyn Any; fn as_mut_any(&mut self) -> &mut dyn Any;
} }
#[must_use]
pub fn read_data(id: DataComponent, data: &NbtTag) -> Option<Box<dyn DataComponentImpl>> { pub fn read_data(id: DataComponent, data: &NbtTag) -> Option<Box<dyn DataComponentImpl>> {
match id { match id {
MaxStackSize => Some(MaxStackSizeImpl::read_data(data)?.to_dyn()), MaxStackSize => Some(MaxStackSizeImpl::read_data(data)?.to_dyn()),
@ -116,10 +121,10 @@ impl MaxStackSizeImpl {
} }
impl DataComponentImpl for MaxStackSizeImpl { impl DataComponentImpl for MaxStackSizeImpl {
fn write_data(&self) -> NbtTag { fn write_data(&self) -> NbtTag {
NbtTag::Int(self.size as i32) NbtTag::Int(i32::from(self.size))
} }
fn get_hash(&self) -> i32 { fn get_hash(&self) -> i32 {
get_i32_hash(self.size as i32) as i32 get_i32_hash(i32::from(self.size)) as i32
} }
default_impl!(MaxStackSize); default_impl!(MaxStackSize);
@ -196,7 +201,7 @@ impl EnchantmentsImpl {
let data = &data.extract_compound()?.child_tags; let data = &data.extract_compound()?.child_tags;
let mut enc = Vec::with_capacity(data.len()); let mut enc = Vec::with_capacity(data.len());
for (name, level) in data { for (name, level) in data {
enc.push((Enchantment::from_name(name.as_str())?, level.extract_int()?)) enc.push((Enchantment::from_name(name.as_str())?, level.extract_int()?));
} }
Some(Self { Some(Self {
enchantment: Cow::from(enc), enchantment: Cow::from(enc),
@ -279,7 +284,7 @@ impl Hash for Modifier {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) { fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.r#type.hash(state); self.r#type.hash(state);
self.id.hash(state); self.id.hash(state);
unsafe { (*(&self.amount as *const f64 as *const u64)).hash(state) }; unsafe { (*(&raw const self.amount).cast::<u64>()).hash(state) };
self.operation.hash(state); self.operation.hash(state);
self.slot.hash(state); self.slot.hash(state);
} }
@ -315,7 +320,7 @@ impl DataComponentImpl for FoodImpl {
impl Hash for FoodImpl { impl Hash for FoodImpl {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) { fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.nutrition.hash(state); self.nutrition.hash(state);
unsafe { (*(&self.saturation as *const f32 as *const u32)).hash(state) }; unsafe { (*(&raw const self.saturation).cast::<u32>()).hash(state) };
self.can_always_eat.hash(state); self.can_always_eat.hash(state);
} }
} }
@ -326,6 +331,7 @@ pub struct ConsumableImpl {
} }
impl ConsumableImpl { impl ConsumableImpl {
#[must_use]
pub fn consume_ticks(&self) -> i32 { pub fn consume_ticks(&self) -> i32 {
(self.consume_seconds * 20.0) as i32 (self.consume_seconds * 20.0) as i32
} }
@ -336,7 +342,7 @@ impl DataComponentImpl for ConsumableImpl {
} }
impl Hash for ConsumableImpl { impl Hash for ConsumableImpl {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) { fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
unsafe { (*(&self.consume_seconds as *const f32 as *const u32)).hash(state) }; unsafe { (*(&raw const self.consume_seconds).cast::<u32>()).hash(state) };
} }
} }
#[derive(Clone, Debug, Hash, PartialEq)] #[derive(Clone, Debug, Hash, PartialEq)]
@ -363,7 +369,7 @@ impl Hash for ToolRule {
self.blocks.hash(state); self.blocks.hash(state);
if let Some(val) = self.speed { if let Some(val) = self.speed {
true.hash(state); true.hash(state);
unsafe { (*(&val as *const f32 as *const u32)).hash(state) }; unsafe { (*(&raw const val).cast::<u32>()).hash(state) };
} else { } else {
false.hash(state); false.hash(state);
} }
@ -383,7 +389,7 @@ impl DataComponentImpl for ToolImpl {
impl Hash for ToolImpl { impl Hash for ToolImpl {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) { fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.rules.hash(state); self.rules.hash(state);
unsafe { (*(&self.default_mining_speed as *const f32 as *const u32)).hash(state) }; unsafe { (*(&raw const self.default_mining_speed).cast::<u32>()).hash(state) };
self.damage_per_block.hash(state); self.damage_per_block.hash(state);
self.can_destroy_blocks_in_creative.hash(state); self.can_destroy_blocks_in_creative.hash(state);
} }
@ -479,6 +485,7 @@ impl EquipmentSlot {
name: Cow::Borrowed("saddle"), name: Cow::Borrowed("saddle"),
}); });
#[must_use]
pub fn get_entity_slot_id(&self) -> i32 { pub fn get_entity_slot_id(&self) -> i32 {
match self { match self {
Self::MainHand(data) => data.entity_id, Self::MainHand(data) => data.entity_id,
@ -492,6 +499,7 @@ impl EquipmentSlot {
} }
} }
#[must_use]
pub fn get_from_name(name: &str) -> Option<Self> { pub fn get_from_name(name: &str) -> Option<Self> {
match name { match name {
"mainhand" => Some(Self::MAIN_HAND), "mainhand" => Some(Self::MAIN_HAND),
@ -506,10 +514,12 @@ impl EquipmentSlot {
} }
} }
#[must_use]
pub fn get_offset_entity_slot_id(&self, offset: i32) -> i32 { pub fn get_offset_entity_slot_id(&self, offset: i32) -> i32 {
self.get_entity_slot_id() + offset self.get_entity_slot_id() + offset
} }
#[must_use]
pub fn slot_type(&self) -> EquipmentType { pub fn slot_type(&self) -> EquipmentType {
match self { match self {
Self::MainHand(data) => data.slot_type, Self::MainHand(data) => data.slot_type,
@ -523,6 +533,7 @@ impl EquipmentSlot {
} }
} }
#[must_use]
pub fn is_armor_slot(&self) -> bool { pub fn is_armor_slot(&self) -> bool {
matches!( matches!(
self.slot_type(), self.slot_type(),
@ -530,6 +541,7 @@ impl EquipmentSlot {
) )
} }
#[must_use]
pub const fn discriminant(&self) -> i8 { pub const fn discriminant(&self) -> i8 {
match self { match self {
Self::MainHand(_) => 0, Self::MainHand(_) => 0,
@ -553,12 +565,12 @@ pub enum EntityTypeOrTag {
impl Hash for EntityTypeOrTag { impl Hash for EntityTypeOrTag {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) { fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
match self { match self {
EntityTypeOrTag::Tag(tag) => { Self::Tag(tag) => {
for x in tag.0 { for x in tag.0 {
x.hash(state); x.hash(state);
} }
} }
EntityTypeOrTag::Single(entity_type) => { Self::Single(entity_type) => {
entity_type.id.hash(state); entity_type.id.hash(state);
} }
} }

View File

@ -15,3 +15,6 @@ log.workspace = true
tokio.workspace = true tokio.workspace = true
thiserror.workspace = true thiserror.workspace = true
crossbeam-utils.workspace = true crossbeam-utils.workspace = true
[lints]
workspace = true

View File

@ -17,7 +17,7 @@ const KEY_CLICK_HOTBAR_END: i8 = 9;
const SLOT_INDEX_OUTSIDE: i16 = -999; const SLOT_INDEX_OUTSIDE: i16 = -999;
impl Click { impl Click {
pub fn new(mode: SlotActionType, button: i8, slot: i16) -> Result<Self, InventoryError> { pub fn new(mode: &SlotActionType, button: i8, slot: i16) -> Result<Self, InventoryError> {
match mode { match mode {
SlotActionType::Pickup => Self::new_normal_click(button, slot), SlotActionType::Pickup => Self::new_normal_click(button, slot),
// Both buttons do the same here, so we omit it // Both buttons do the same here, so we omit it
@ -37,12 +37,11 @@ impl Click {
} }
fn new_normal_click(button: i8, slot: i16) -> Result<Self, InventoryError> { fn new_normal_click(button: i8, slot: i16) -> Result<Self, InventoryError> {
let slot = match slot { let slot = if slot == SLOT_INDEX_OUTSIDE {
SLOT_INDEX_OUTSIDE => Slot::OutsideInventory, Slot::OutsideInventory
_ => { } else {
let slot = slot.try_into().unwrap_or(0); let slot = slot.try_into().unwrap_or(0);
Slot::Normal(slot) Slot::Normal(slot)
}
}; };
let button = match button { let button = match button {
BUTTON_CLICK_LEFT => MouseClick::Left, BUTTON_CLICK_LEFT => MouseClick::Left,
@ -79,12 +78,11 @@ impl Click {
fn new_drop_item(button: i8, slot: i16) -> Result<Self, InventoryError> { fn new_drop_item(button: i8, slot: i16) -> Result<Self, InventoryError> {
let drop_type = DropType::from_i8(button)?; let drop_type = DropType::from_i8(button)?;
let slot = match slot { let slot = if slot == SLOT_INDEX_OUTSIDE {
SLOT_INDEX_OUTSIDE => Slot::OutsideInventory, Slot::OutsideInventory
_ => { } else {
let slot = slot.try_into().unwrap_or(0); let slot = slot.try_into().unwrap_or(0);
Slot::Normal(slot) Slot::Normal(slot)
}
}; };
Ok(Self { Ok(Self {
click_type: ClickType::DropType(drop_type), click_type: ClickType::DropType(drop_type),

View File

@ -16,6 +16,7 @@ pub struct CraftingInventory {
} }
impl CraftingInventory { impl CraftingInventory {
#[must_use]
pub fn new(width: u8, height: u8) -> Self { pub fn new(width: u8, height: u8) -> Self {
Self { Self {
width, width,
@ -38,7 +39,7 @@ impl Inventory for CraftingInventory {
fn is_empty(&self) -> InventoryFuture<'_, bool> { fn is_empty(&self) -> InventoryFuture<'_, bool> {
Box::pin(async move { Box::pin(async move {
for slot in self.items.iter() { for slot in &self.items {
if !slot.lock().await.is_empty() { if !slot.lock().await.is_empty() {
return false; return false;
} }
@ -89,7 +90,7 @@ impl RecipeInputInventory for CraftingInventory {
impl Clearable for CraftingInventory { impl Clearable for CraftingInventory {
fn clear(&self) -> Pin<Box<dyn Future<Output = ()> + Send + '_>> { fn clear(&self) -> Pin<Box<dyn Future<Output = ()> + Send + '_>> {
Box::pin(async move { Box::pin(async move {
for item in self.items.iter() { for item in &self.items {
*item.lock().await = ItemStack::EMPTY.clone(); *item.lock().await = ItemStack::EMPTY.clone();
} }
}) })

View File

@ -48,6 +48,7 @@ fn is_symmetrical_horizontally(pattern: &'static [&'static str]) -> bool {
true true
} }
#[expect(clippy::too_many_lines)]
async fn recipe_matches<'a>( async fn recipe_matches<'a>(
recipe: &'static CraftingRecipeTypes, recipe: &'static CraftingRecipeTypes,
input_height: usize, input_height: usize,
@ -146,7 +147,7 @@ async fn recipe_matches<'a>(
} }
// TODO: Apply components // TODO: Apply components
if matched { Some(result) } else { None } matched.then_some(result)
} }
CraftingRecipeTypes::CraftingShapeless { CraftingRecipeTypes::CraftingShapeless {
ingredients, ingredients,
@ -234,7 +235,7 @@ async fn recipe_matches<'a>(
} }
impl ResultSlot { impl ResultSlot {
fn stat_crafted(&self, _crafted_amount: u8, _player: &dyn InventoryPlayer) {} //fn stat_crafted(&self, _crafted_amount: u8, _player: &dyn InventoryPlayer) {}
pub fn new(inventory: Arc<dyn RecipeInputInventory>) -> Self { pub fn new(inventory: Arc<dyn RecipeInputInventory>) -> Self {
Self { Self {
@ -315,8 +316,7 @@ impl ResultSlot {
let result = self let result = self
.match_recipe() .match_recipe()
.await .await
.map(|x| ItemStack::from(x.0)) .map_or(ItemStack::EMPTY.clone(), |x| ItemStack::from(x.0));
.unwrap_or(ItemStack::EMPTY.clone());
*self.result.lock().await = result.clone(); *self.result.lock().await = result.clone();
result result
} }
@ -348,8 +348,8 @@ impl Slot for ResultSlot {
fn on_take_item<'a>( fn on_take_item<'a>(
&'a self, &'a self,
player: &'a dyn InventoryPlayer, _player: &'a dyn InventoryPlayer,
stack: &'a ItemStack, _stack: &'a ItemStack,
) -> BoxFuture<'a, ()> { ) -> BoxFuture<'a, ()> {
Box::pin(async move { Box::pin(async move {
for i in 0..self.inventory.size() { for i in 0..self.inventory.size() {
@ -360,7 +360,8 @@ impl Slot for ResultSlot {
stack.item_count -= 1; stack.item_count -= 1;
} }
} }
self.stat_crafted(stack.item_count, player); // TODO
//self.stat_crafted(stack.item_count, player);
self.mark_dirty().await; self.mark_dirty().await;
}) })
} }
@ -489,7 +490,7 @@ impl CraftingTableScreenHandler {
let crafting_inventory: Arc<dyn RecipeInputInventory> = let crafting_inventory: Arc<dyn RecipeInputInventory> =
Arc::new(CraftingInventory::new(3, 3)); Arc::new(CraftingInventory::new(3, 3));
let mut crafting_table_handler = CraftingTableScreenHandler { let mut crafting_table_handler = Self {
behaviour: ScreenHandlerBehaviour::new(sync_id, Some(WindowType::Crafting)), behaviour: ScreenHandlerBehaviour::new(sync_id, Some(WindowType::Crafting)),
crafting_inventory: crafting_inventory.clone(), crafting_inventory: crafting_inventory.clone(),
}; };

View File

@ -1,10 +1,10 @@
use pumpkin_world::inventory::Inventory; use pumpkin_world::inventory::Inventory;
// RecipeMatcher.java // RecipeMatcher.java
pub struct RecipeMatcher {} pub struct RecipeMatcher;
// RecipeFinder.java // RecipeFinder.java
pub struct RecipeFinder {} pub struct RecipeFinder;
// AbstractRecipeScreenHandle.java // AbstractRecipeScreenHandle.java
pub trait RecipeFinderScreenHandler {} pub trait RecipeFinderScreenHandler {}

View File

@ -65,9 +65,9 @@ impl Inventory for DoubleInventory {
fn set_stack(&self, slot: usize, stack: ItemStack) -> InventoryFuture<'_, ()> { fn set_stack(&self, slot: usize, stack: ItemStack) -> InventoryFuture<'_, ()> {
Box::pin(async move { Box::pin(async move {
if slot >= self.first.size() { if slot >= self.first.size() {
self.second.set_stack(slot - self.first.size(), stack).await self.second.set_stack(slot - self.first.size(), stack).await;
} else { } else {
self.first.set_stack(slot, stack).await self.first.set_stack(slot, stack).await;
} }
}) })
} }

View File

@ -17,6 +17,7 @@ impl Default for EntityEquipment {
} }
impl EntityEquipment { impl EntityEquipment {
#[must_use]
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
equipment: HashMap::new(), equipment: HashMap::new(),
@ -32,6 +33,7 @@ impl EntityEquipment {
.clone() .clone()
} }
#[must_use]
pub fn get(&self, slot: &EquipmentSlot) -> Arc<Mutex<ItemStack>> { pub fn get(&self, slot: &EquipmentSlot) -> Arc<Mutex<ItemStack>> {
self.equipment self.equipment
.get(slot) .get(slot)

View File

@ -26,12 +26,6 @@ impl FurnaceLikeScreenHandler {
furnace_block_entity: Arc<dyn BlockEntity>, furnace_block_entity: Arc<dyn BlockEntity>,
window_type: WindowType, window_type: WindowType,
) -> Self { ) -> Self {
let furnace_like_property_delegate = furnace_block_entity.to_property_delegate().unwrap();
let mut handler = Self {
inventory,
behaviour: ScreenHandlerBehaviour::new(sync_id, Some(window_type)),
};
struct FurnaceLikeScreenListener; struct FurnaceLikeScreenListener;
impl ScreenHandlerListener for FurnaceLikeScreenListener { impl ScreenHandlerListener for FurnaceLikeScreenListener {
fn on_property_update<'a>( fn on_property_update<'a>(
@ -43,12 +37,17 @@ impl FurnaceLikeScreenHandler {
Box::pin(async move { Box::pin(async move {
if let Some(sync_handler) = screen_handler.sync_handler.as_ref() { if let Some(sync_handler) = screen_handler.sync_handler.as_ref() {
sync_handler sync_handler
.update_property(screen_handler, property as i32, value) .update_property(screen_handler, i32::from(property), value)
.await; .await;
} }
}) })
} }
} }
let furnace_like_property_delegate = furnace_block_entity.to_property_delegate().unwrap();
let mut handler = Self {
inventory,
behaviour: ScreenHandlerBehaviour::new(sync_id, Some(window_type)),
};
// 0: Fire icon (fuel left) counting from fuel burn time down to 0 (in-game ticks) // 0: Fire icon (fuel left) counting from fuel burn time down to 0 (in-game ticks)
// 1: Maximum fuel burn time fuel burn time or 0 (in-game ticks) // 1: Maximum fuel burn time fuel burn time or 0 (in-game ticks)

View File

@ -161,7 +161,7 @@ impl ScreenHandler for GenericContainerScreenHandler {
// Re-acquire lock for insert_item (which expects &mut ItemStack) // Re-acquire lock for insert_item (which expects &mut ItemStack)
let mut slot_stack_mut = slot_stack_lock.lock().await; let mut slot_stack_mut = slot_stack_lock.lock().await;
if slot_index < (self.rows * 9) as i32 { if slot_index < i32::from(self.rows * 9) {
// Move from inventory to player area (end) // Move from inventory to player area (end)
if !self if !self
.insert_item( .insert_item(

View File

@ -19,6 +19,7 @@ use pumpkin_data::data_component_impl::EquipmentSlot;
use crate::player::player_inventory::PlayerInventory; use crate::player::player_inventory::PlayerInventory;
#[must_use]
pub fn build_equipment_slots() -> HashMap<usize, EquipmentSlot> { pub fn build_equipment_slots() -> HashMap<usize, EquipmentSlot> {
let mut equipment_slots = HashMap::new(); let mut equipment_slots = HashMap::new();
equipment_slots.insert( equipment_slots.insert(

View File

@ -21,6 +21,7 @@ impl Default for EnderChestInventory {
impl EnderChestInventory { impl EnderChestInventory {
pub const INVENTORY_SIZE: usize = 27; pub const INVENTORY_SIZE: usize = 27;
#[must_use]
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
items: from_fn(|_| Arc::new(Mutex::new(ItemStack::EMPTY.clone()))), items: from_fn(|_| Arc::new(Mutex::new(ItemStack::EMPTY.clone()))),
@ -51,7 +52,7 @@ impl Inventory for EnderChestInventory {
fn is_empty(&self) -> InventoryFuture<'_, bool> { fn is_empty(&self) -> InventoryFuture<'_, bool> {
Box::pin(async move { Box::pin(async move {
for slot in self.items.iter() { for slot in &self.items {
if !slot.lock().await.is_empty() { if !slot.lock().await.is_empty() {
return false; return false;
} }
@ -110,7 +111,7 @@ impl Inventory for EnderChestInventory {
impl Clearable for EnderChestInventory { impl Clearable for EnderChestInventory {
fn clear(&self) -> Pin<Box<dyn Future<Output = ()> + Send + '_>> { fn clear(&self) -> Pin<Box<dyn Future<Output = ()> + Send + '_>> {
Box::pin(async move { Box::pin(async move {
for item in self.items.iter() { for item in &self.items {
*item.lock().await = ItemStack::EMPTY.clone(); *item.lock().await = ItemStack::EMPTY.clone();
} }
}) })

View File

@ -58,18 +58,12 @@ impl PlayerInventory {
/// getOffHandStack in source /// getOffHandStack in source
pub async fn off_hand_item(&self) -> Arc<Mutex<ItemStack>> { pub async fn off_hand_item(&self) -> Arc<Mutex<ItemStack>> {
let slot = self let slot = self.equipment_slots.get(&Self::OFF_HAND_SLOT).unwrap();
.equipment_slots
.get(&PlayerInventory::OFF_HAND_SLOT)
.unwrap();
self.entity_equipment.lock().await.get(slot) self.entity_equipment.lock().await.get(slot)
} }
pub async fn swap_item(&self) -> (ItemStack, ItemStack) { pub async fn swap_item(&self) -> (ItemStack, ItemStack) {
let slot = self let slot = self.equipment_slots.get(&Self::OFF_HAND_SLOT).unwrap();
.equipment_slots
.get(&PlayerInventory::OFF_HAND_SLOT)
.unwrap();
let mut equipment = self.entity_equipment.lock().await; let mut equipment = self.entity_equipment.lock().await;
let binding = self.held_item(); let binding = self.held_item();
let mut main_hand_item = binding.lock().await; let mut main_hand_item = binding.lock().await;
@ -78,6 +72,7 @@ impl PlayerInventory {
(main_hand_item.clone(), off_hand_item) (main_hand_item.clone(), off_hand_item)
} }
#[must_use]
pub fn is_valid_hotbar_index(slot: usize) -> bool { pub fn is_valid_hotbar_index(slot: usize) -> bool {
slot < Self::HOTBAR_SIZE slot < Self::HOTBAR_SIZE
} }
@ -109,13 +104,11 @@ impl PlayerInventory {
let count_left = self_stack.get_max_stack_size() - self_stack.item_count; let count_left = self_stack.get_max_stack_size() - self_stack.item_count;
let count_min = stack_count.min(count_left); let count_min = stack_count.min(count_left);
if count_min == 0 { if count_min != 0 {
stack_count as usize
} else {
stack_count -= count_min; stack_count -= count_min;
self_stack.increment(count_min); self_stack.increment(count_min);
stack_count as usize
} }
stack_count as usize
} }
async fn get_empty_slot(&self) -> i16 { async fn get_empty_slot(&self) -> i16 {
@ -128,7 +121,7 @@ impl PlayerInventory {
-1 -1
} }
fn can_stack_add_more(&self, existing_stack: &ItemStack, stack: &ItemStack) -> bool { fn can_stack_add_more(existing_stack: &ItemStack, stack: &ItemStack) -> bool {
!existing_stack.is_empty() !existing_stack.is_empty()
&& existing_stack.are_items_and_components_equal(stack) && existing_stack.are_items_and_components_equal(stack)
&& existing_stack.is_stackable() && existing_stack.is_stackable()
@ -136,7 +129,7 @@ impl PlayerInventory {
} }
async fn get_occupied_slot_with_room_for_stack(&self, stack: &ItemStack) -> i16 { async fn get_occupied_slot_with_room_for_stack(&self, stack: &ItemStack) -> i16 {
if self.can_stack_add_more( if Self::can_stack_add_more(
&*self &*self
.get_stack(self.get_selected_slot() as usize) .get_stack(self.get_selected_slot() as usize)
.await .await
@ -144,15 +137,15 @@ impl PlayerInventory {
.await, .await,
stack, stack,
) { ) {
self.get_selected_slot() as i16 i16::from(self.get_selected_slot())
} else if self.can_stack_add_more( } else if Self::can_stack_add_more(
&*self.get_stack(Self::OFF_HAND_SLOT).await.lock().await, &*self.get_stack(Self::OFF_HAND_SLOT).await.lock().await,
stack, stack,
) { ) {
Self::OFF_HAND_SLOT as i16 Self::OFF_HAND_SLOT as i16
} else { } else {
for i in 0..Self::MAIN_SIZE { for i in 0..Self::MAIN_SIZE {
if self.can_stack_add_more(&*self.main_inventory[i].lock().await, stack) { if Self::can_stack_add_more(&*self.main_inventory[i].lock().await, stack) {
return i as i16; return i as i16;
} }
} }
@ -298,7 +291,7 @@ impl PlayerInventory {
{ {
player player
.enqueue_slot_set_packet(&CSetPlayerInventory::new( .enqueue_slot_set_packet(&CSetPlayerInventory::new(
(room_for_stack as i32).into(), i32::from(room_for_stack).into(),
&self &self
.get_stack(room_for_stack as usize) .get_stack(room_for_stack as usize)
.await .await
@ -316,7 +309,7 @@ impl PlayerInventory {
impl Clearable for PlayerInventory { impl Clearable for PlayerInventory {
fn clear(&self) -> Pin<Box<dyn Future<Output = ()> + Send + '_>> { fn clear(&self) -> Pin<Box<dyn Future<Output = ()> + Send + '_>> {
Box::pin(async move { Box::pin(async move {
for item in self.main_inventory.iter() { for item in &self.main_inventory {
*item.lock().await = ItemStack::EMPTY.clone(); *item.lock().await = ItemStack::EMPTY.clone();
} }
@ -332,7 +325,7 @@ impl Inventory for PlayerInventory {
fn is_empty(&self) -> InventoryFuture<'_, bool> { fn is_empty(&self) -> InventoryFuture<'_, bool> {
Box::pin(async move { Box::pin(async move {
for item in self.main_inventory.iter() { for item in &self.main_inventory {
if !item.lock().await.is_empty() { if !item.lock().await.is_empty() {
return false; return false;
} }

View File

@ -31,11 +31,12 @@ impl PlayerScreenHandler {
EquipmentSlot::FEET, EquipmentSlot::FEET,
]; ];
#[must_use]
pub fn is_in_hotbar(slot: u8) -> bool { pub fn is_in_hotbar(slot: u8) -> bool {
(36..=45).contains(&slot) (36..=45).contains(&slot)
} }
pub async fn get_slot(&self, slot: usize) -> Arc<dyn Slot> { pub fn get_slot(&self, slot: usize) -> Arc<dyn Slot> {
self.behaviour.slots[slot].clone() self.behaviour.slots[slot].clone()
} }
@ -47,7 +48,7 @@ impl PlayerScreenHandler {
let crafting_inventory: Arc<dyn RecipeInputInventory> = let crafting_inventory: Arc<dyn RecipeInputInventory> =
Arc::new(CraftingInventory::new(2, 2)); Arc::new(CraftingInventory::new(2, 2));
let mut player_screen_handler = PlayerScreenHandler { let mut player_screen_handler = Self {
behaviour: ScreenHandlerBehaviour::new(sync_id, window_type), behaviour: ScreenHandlerBehaviour::new(sync_id, window_type),
crafting_inventory: crafting_inventory.clone(), crafting_inventory: crafting_inventory.clone(),
}; };
@ -140,7 +141,6 @@ impl ScreenHandler for PlayerScreenHandler {
} else if equipment_slot.slot_type() == EquipmentType::HumanoidArmor } else if equipment_slot.slot_type() == EquipmentType::HumanoidArmor
&& self && self
.get_slot((8 - equipment_slot.get_entity_slot_id()) as usize) .get_slot((8 - equipment_slot.get_entity_slot_id()) as usize)
.await
.get_cloned_stack() .get_cloned_stack()
.await .await
.is_empty() .is_empty()
@ -159,7 +159,7 @@ impl ScreenHandler for PlayerScreenHandler {
result result
} else if matches!(equipment_slot, EquipmentSlot::OffHand(_)) } else if matches!(equipment_slot, EquipmentSlot::OffHand(_))
&& slot_index != 45 && slot_index != 45
&& self.get_slot(45).await.get_cloned_stack().await.is_empty() && self.get_slot(45).get_cloned_stack().await.is_empty()
{ {
// Into empty offhand slot (45) // Into empty offhand slot (45)
let index = 45; let index = 45;

View File

@ -41,18 +41,19 @@ pub struct ScreenProperty {
impl ScreenProperty { impl ScreenProperty {
pub fn new(value: Arc<dyn PropertyDelegate>, index: u8) -> Self { pub fn new(value: Arc<dyn PropertyDelegate>, index: u8) -> Self {
Self { Self {
old_value: value.get_property(index as i32), old_value: value.get_property(i32::from(index)),
index, index,
value, value,
} }
} }
#[must_use]
pub fn get(&self) -> i32 { pub fn get(&self) -> i32 {
self.value.get_property(self.index as i32) self.value.get_property(i32::from(self.index))
} }
pub fn set(&mut self, value: i32) { pub fn set(&mut self, value: i32) {
self.value.set_property(self.index as i32, value); self.value.set_property(i32::from(self.index), value);
} }
pub fn has_changed(&mut self) -> bool { pub fn has_changed(&mut self) -> bool {
@ -66,7 +67,7 @@ impl ScreenProperty {
pub type PlayerFuture<'a, T> = Pin<Box<dyn Future<Output = T> + Send + 'a>>; pub type PlayerFuture<'a, T> = Pin<Box<dyn Future<Output = T> + Send + 'a>>;
pub trait InventoryPlayer: Send + Sync { pub trait InventoryPlayer: Send + Sync {
fn drop_item<'a>(&'a self, item: ItemStack, retain_ownership: bool) -> PlayerFuture<'a, ()>; fn drop_item(&self, item: ItemStack, retain_ownership: bool) -> PlayerFuture<'_, ()>;
fn get_inventory(&self) -> Arc<PlayerInventory>; fn get_inventory(&self) -> Arc<PlayerInventory>;
fn has_infinite_materials(&self) -> bool; fn has_infinite_materials(&self) -> bool;
@ -238,10 +239,10 @@ pub trait ScreenHandler: Send + Sync {
}) })
} }
fn copy_shared_slots<'a>( fn copy_shared_slots(
&'a mut self, &mut self,
other: Arc<Mutex<dyn ScreenHandler>>, other: Arc<Mutex<dyn ScreenHandler>>,
) -> ScreenHandlerFuture<'a, ()> { ) -> ScreenHandlerFuture<'_, ()> {
Box::pin(async move { Box::pin(async move {
let mut table: HashMap<ComparableInventory, HashMap<usize, usize>> = HashMap::new(); let mut table: HashMap<ComparableInventory, HashMap<usize, usize>> = HashMap::new();
let other_binding = other.lock().await; let other_binding = other.lock().await;
@ -274,7 +275,7 @@ pub trait ScreenHandler: Send + Sync {
}) })
} }
fn sync_state<'a>(&'a mut self) -> ScreenHandlerFuture<'a, ()> { fn sync_state(&mut self) -> ScreenHandlerFuture<'_, ()> {
Box::pin(async move { Box::pin(async move {
let behaviour = self.get_behaviour_mut(); let behaviour = self.get_behaviour_mut();
let mut previous_tracked_stacks = Vec::new(); let mut previous_tracked_stacks = Vec::new();
@ -311,20 +312,20 @@ pub trait ScreenHandler: Send + Sync {
}) })
} }
fn add_listener<'a>( fn add_listener(
&'a mut self, &mut self,
listener: Arc<dyn ScreenHandlerListener>, listener: Arc<dyn ScreenHandlerListener>,
) -> ScreenHandlerFuture<'a, ()> { ) -> ScreenHandlerFuture<'_, ()> {
Box::pin(async move { Box::pin(async move {
self.get_behaviour_mut().listeners.push(listener); self.get_behaviour_mut().listeners.push(listener);
self.send_content_updates().await; self.send_content_updates().await;
}) })
} }
fn update_sync_handler<'a>( fn update_sync_handler(
&'a mut self, &mut self,
sync_handler: Arc<SyncHandler>, sync_handler: Arc<SyncHandler>,
) -> ScreenHandlerFuture<'a, ()> { ) -> ScreenHandlerFuture<'_, ()> {
Box::pin(async move { Box::pin(async move {
let behaviour = self.get_behaviour_mut(); let behaviour = self.get_behaviour_mut();
behaviour.sync_handler = Some(sync_handler.clone()); behaviour.sync_handler = Some(sync_handler.clone());
@ -332,7 +333,7 @@ pub trait ScreenHandler: Send + Sync {
}) })
} }
fn update_to_client<'a>(&'a mut self) -> ScreenHandlerFuture<'a, ()> { fn update_to_client(&mut self) -> ScreenHandlerFuture<'_, ()> {
Box::pin(async move { Box::pin(async move {
for i in 0..self.get_behaviour().slots.len() { for i in 0..self.get_behaviour().slots.len() {
let behaviour = self.get_behaviour_mut(); let behaviour = self.get_behaviour_mut();
@ -359,16 +360,12 @@ pub trait ScreenHandler: Send + Sync {
}) })
} }
fn update_tracked_properties<'a>( fn update_tracked_properties(&mut self, idx: i32, value: i32) -> ScreenHandlerFuture<'_, ()> {
&'a mut self,
idx: i32,
value: i32,
) -> ScreenHandlerFuture<'a, ()> {
Box::pin(async move { Box::pin(async move {
let behaviour = self.get_behaviour_mut(); let behaviour = self.get_behaviour_mut();
if idx <= behaviour.tracked_property_values.len() as i32 { if idx <= behaviour.tracked_property_values.len() as i32 {
behaviour.tracked_property_values[idx as usize] = value; behaviour.tracked_property_values[idx as usize] = value;
for listener in behaviour.listeners.iter() { for listener in &behaviour.listeners {
listener listener
.on_property_update(behaviour, idx as u8, value) .on_property_update(behaviour, idx as u8, value)
.await; .await;
@ -377,11 +374,7 @@ pub trait ScreenHandler: Send + Sync {
}) })
} }
fn check_property_updates<'a>( fn check_property_updates(&mut self, idx: i32, value: i32) -> ScreenHandlerFuture<'_, ()> {
&'a mut self,
idx: i32,
value: i32,
) -> ScreenHandlerFuture<'a, ()> {
Box::pin(async move { Box::pin(async move {
let behaviour = self.get_behaviour_mut(); let behaviour = self.get_behaviour_mut();
if !behaviour.disable_sync if !behaviour.disable_sync
@ -400,18 +393,18 @@ pub trait ScreenHandler: Send + Sync {
}) })
} }
fn update_tracked_slot<'a>( fn update_tracked_slot(
&'a mut self, &mut self,
slot: usize, slot: usize,
stack: ItemStack, stack: ItemStack,
) -> ScreenHandlerFuture<'a, ()> { ) -> ScreenHandlerFuture<'_, ()> {
Box::pin(async move { Box::pin(async move {
let behaviour = self.get_behaviour_mut(); let behaviour = self.get_behaviour_mut();
let other_stack = &behaviour.tracked_stacks[slot]; let other_stack = &behaviour.tracked_stacks[slot];
if !other_stack.are_equal(&stack) { if !other_stack.are_equal(&stack) {
behaviour.tracked_stacks[slot] = stack.clone(); behaviour.tracked_stacks[slot] = stack.clone();
for listener in behaviour.listeners.iter() { for listener in &behaviour.listeners {
listener listener
.on_slot_update(behaviour, slot as u8, stack.clone()) .on_slot_update(behaviour, slot as u8, stack.clone())
.await; .await;
@ -420,11 +413,7 @@ pub trait ScreenHandler: Send + Sync {
}) })
} }
fn check_slot_updates<'a>( fn check_slot_updates(&mut self, slot: usize, stack: ItemStack) -> ScreenHandlerFuture<'_, ()> {
&'a mut self,
slot: usize,
stack: ItemStack,
) -> ScreenHandlerFuture<'a, ()> {
Box::pin(async move { Box::pin(async move {
let behaviour = self.get_behaviour_mut(); let behaviour = self.get_behaviour_mut();
if !behaviour.disable_sync { if !behaviour.disable_sync {
@ -443,7 +432,7 @@ pub trait ScreenHandler: Send + Sync {
}) })
} }
fn check_cursor_stack_updates<'a>(&'a mut self) -> ScreenHandlerFuture<'a, ()> { fn check_cursor_stack_updates(&mut self) -> ScreenHandlerFuture<'_, ()> {
Box::pin(async move { Box::pin(async move {
let behaviour = self.get_behaviour_mut(); let behaviour = self.get_behaviour_mut();
if !behaviour.disable_sync { if !behaviour.disable_sync {
@ -462,7 +451,7 @@ pub trait ScreenHandler: Send + Sync {
}) })
} }
fn send_content_updates<'a>(&'a mut self) -> ScreenHandlerFuture<'a, ()> { fn send_content_updates(&mut self) -> ScreenHandlerFuture<'_, ()> {
Box::pin(async move { Box::pin(async move {
let slots_len = self.get_behaviour().slots.len(); let slots_len = self.get_behaviour().slots.len();
@ -492,7 +481,7 @@ pub trait ScreenHandler: Send + Sync {
}) })
} }
fn is_slot_valid<'a>(&'a self, slot: i32) -> ScreenHandlerFuture<'a, bool> { fn is_slot_valid(&self, slot: i32) -> ScreenHandlerFuture<'_, bool> {
Box::pin(async move { Box::pin(async move {
slot == -1 || slot == -999 || slot < self.get_behaviour().slots.len() as i32 slot == -1 || slot == -999 || slot < self.get_behaviour().slots.len() as i32
}) })
@ -645,6 +634,7 @@ pub trait ScreenHandler: Send + Sync {
}) })
} }
#[expect(clippy::too_many_lines)]
fn internal_on_slot_click<'a>( fn internal_on_slot_click<'a>(
&'a mut self, &'a mut self,
slot_index: i32, slot_index: i32,
@ -658,7 +648,7 @@ pub trait ScreenHandler: Send + Sync {
let mut cursor_stack = behavior.cursor_stack.lock().await; let mut cursor_stack = behavior.cursor_stack.lock().await;
let mut to_pick_up = cursor_stack.get_max_stack_size() - cursor_stack.item_count; let mut to_pick_up = cursor_stack.get_max_stack_size() - cursor_stack.item_count;
for slot in behavior.slots.iter() { for slot in &behavior.slots {
if to_pick_up == 0 { if to_pick_up == 0 {
break; break;
} }
@ -727,7 +717,7 @@ pub trait ScreenHandler: Send + Sync {
let mut cursor_stack = behaviour.cursor_stack.lock().await; let mut cursor_stack = behaviour.cursor_stack.lock().await;
let initial_count = cursor_stack.item_count; let initial_count = cursor_stack.item_count;
for slot_index in behaviour.drag_slots.iter() { for slot_index in &behaviour.drag_slots {
let slot = behaviour.slots[*slot_index as usize].clone(); let slot = behaviour.slots[*slot_index as usize].clone();
let stack_lock = slot.get_stack().await; let stack_lock = slot.get_stack().await;
let stack = stack_lock.lock().await; let stack = stack_lock.lock().await;
@ -1070,6 +1060,7 @@ pub struct ScreenHandlerBehaviour {
} }
impl ScreenHandlerBehaviour { impl ScreenHandlerBehaviour {
#[must_use]
pub fn new(sync_id: u8, window_type: Option<WindowType>) -> Self { pub fn new(sync_id: u8, window_type: Option<WindowType>) -> Self {
Self { Self {
slots: Vec::new(), slots: Vec::new(),

View File

@ -232,9 +232,7 @@ pub trait Slot: Send + Sync {
.min(stack.item_count) .min(stack.item_count)
.min(self.get_max_item_count_for_stack(&stack).await - stack_self.item_count); .min(self.get_max_item_count_for_stack(&stack).await - stack_self.item_count);
if min_count == 0 { if min_count != 0 {
stack
} else {
if stack_self.is_empty() { if stack_self.is_empty() {
drop(stack_self); drop(stack_self);
self.set_stack(stack.split(min_count)).await; self.set_stack(stack.split(min_count)).await;
@ -245,12 +243,9 @@ pub trait Slot: Send + Sync {
drop(stack_self); drop(stack_self);
self.set_stack(cloned_stack).await; self.set_stack(cloned_stack).await;
} }
stack
} }
} else {
stack
} }
stack
}) })
} }
} }

View File

@ -25,6 +25,7 @@ impl Default for SyncHandler {
} }
impl SyncHandler { impl SyncHandler {
#[must_use]
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
player: Mutex::new(None), player: Mutex::new(None),
@ -128,7 +129,7 @@ pub struct TrackedStack {
} }
impl TrackedStack { impl TrackedStack {
pub const EMPTY: TrackedStack = TrackedStack { pub const EMPTY: Self = Self {
received_stack: None, received_stack: None,
received_hash: None, received_hash: None,
}; };

View File

@ -36,14 +36,16 @@ pub enum EnchantmentTable {
// TODO: No more magic numbers // TODO: No more magic numbers
impl WindowPropertyTrait for EnchantmentTable { impl WindowPropertyTrait for EnchantmentTable {
fn to_id(self) -> i16 { fn to_id(self) -> i16 {
use EnchantmentTable::*; use EnchantmentTable::{
EnchantmentId, EnchantmentLevel, EnchantmentSeed, LevelRequirement,
};
(match self { i16::from(match self {
LevelRequirement { slot } => slot, LevelRequirement { slot } => slot,
EnchantmentSeed => 3, EnchantmentSeed => 3,
EnchantmentId { slot } => 4 + slot, EnchantmentId { slot } => 4 + slot,
EnchantmentLevel { slot } => 7 + slot, EnchantmentLevel { slot } => 7 + slot,
}) as i16 })
} }
} }
pub enum Beacon { pub enum Beacon {

View File

@ -15,3 +15,6 @@ pumpkin-data.workspace = true
proc-macro2.workspace = true proc-macro2.workspace = true
quote.workspace = true quote.workspace = true
syn.workspace = true syn.workspace = true
[lints]
workspace = true

View File

@ -46,7 +46,7 @@ pub fn cancellable(_args: TokenStream, input: TokenStream) -> TokenStream {
if fields if fields
.named .named
.iter() .iter()
.any(|f| f.ident.as_ref().map(|i| i == "cancelled").unwrap_or(false)) .any(|f| f.ident.as_ref().is_some_and(|i| i == "cancelled"))
{ {
abort!(fields.span(), "Struct already has a `cancelled` field"); abort!(fields.span(), "Struct already has a `cancelled` field");
} }
@ -199,13 +199,10 @@ pub fn pumpkin_block(args: TokenStream, item: TokenStream) -> TokenStream {
let arg_value = arg_lit.value(); let arg_value = arg_lit.value();
let block_name = arg_value.strip_prefix("minecraft:").unwrap_or(&arg_value); let block_name = arg_value.strip_prefix("minecraft:").unwrap_or(&arg_value);
let block = match Block::from_name(block_name) { let Some(block) = Block::from_name(block_name) else {
Some(b) => b,
None => {
return syn::Error::new(arg_lit.span(), "Invalid block name") return syn::Error::new(arg_lit.span(), "Invalid block name")
.to_compile_error() .to_compile_error()
.into(); .into();
}
}; };
let block_id = block.id; let block_id = block.id;
@ -239,16 +236,10 @@ pub fn pumpkin_block_from_tag(args: TokenStream, item: TokenStream) -> TokenStre
let full_tag = arg_lit.value(); let full_tag = arg_lit.value();
let values = match get_tag_ids(RegistryKey::Block, &full_tag) { let Some(values) = get_tag_ids(RegistryKey::Block, &full_tag) else {
Some(v) => v, return syn::Error::new(arg_lit.span(), format!("Failed to get tag IDs: {full_tag}"))
None => {
return syn::Error::new(
arg_lit.span(),
format!("Failed to get tag IDs: {}", full_tag),
)
.to_compile_error() .to_compile_error()
.into(); .into();
}
}; };
let expanded = quote! { let expanded = quote! {
@ -522,7 +513,7 @@ fn check_serial_attributes(attrs: &[Attribute]) -> (bool, bool) {
let mut is_big_endian = false; let mut is_big_endian = false;
let mut no_prefix = false; let mut no_prefix = false;
for attr in attrs.iter() { for attr in attrs {
if attr.path().is_ident("serial") { if attr.path().is_ident("serial") {
let _ = attr.parse_nested_meta(|meta| { let _ = attr.parse_nested_meta(|meta| {
if meta.path.is_ident("big_endian") { if meta.path.is_ident("big_endian") {
@ -545,8 +536,7 @@ fn is_vec(ty: &Type) -> bool {
.segments .segments
.iter() .iter()
.last() .last()
.map(|segment| segment.ident == "Vec") .is_some_and(|segment| segment.ident == "Vec")
.unwrap_or(false)
} else { } else {
false false
} }

View File

@ -14,3 +14,6 @@ flate2.workspace = true
[dev-dependencies] [dev-dependencies]
tempfile.workspace = true tempfile.workspace = true
[lints]
workspace = true

View File

@ -20,8 +20,9 @@ pub struct NbtCompound {
} }
impl NbtCompound { impl NbtCompound {
pub fn new() -> NbtCompound { #[must_use]
NbtCompound { pub fn new() -> Self {
Self {
child_tags: Vec::new(), child_tags: Vec::new(),
} }
} }
@ -39,7 +40,7 @@ impl NbtCompound {
} }
let len = reader.get_u16_be()?; let len = reader.get_u16_be()?;
reader.skip_bytes(len as i64)?; reader.skip_bytes(i64::from(len))?;
// Skip Value // Skip Value
NbtTag::skip_data(reader, tag_id)?; NbtTag::skip_data(reader, tag_id)?;
@ -50,8 +51,8 @@ impl NbtCompound {
pub fn deserialize_content<R: Read + Seek>( pub fn deserialize_content<R: Read + Seek>(
reader: &mut NbtReadHelper<R>, reader: &mut NbtReadHelper<R>,
) -> Result<NbtCompound, Error> { ) -> Result<Self, Error> {
let mut compound = NbtCompound::new(); let mut compound = Self::new();
loop { loop {
let tag_id = match reader.get_u8_be() { let tag_id = match reader.get_u8_be() {
@ -83,6 +84,7 @@ impl NbtCompound {
Ok(()) Ok(())
} }
#[must_use]
pub fn is_empty(&self) -> bool { pub fn is_empty(&self) -> bool {
self.child_tags.is_empty() self.child_tags.is_empty()
} }
@ -106,7 +108,7 @@ impl NbtCompound {
} }
pub fn put_bool(&mut self, name: &str, value: bool) { pub fn put_bool(&mut self, name: &str, value: bool) {
self.put(name, NbtTag::Byte(if value { 1 } else { 0 })); self.put(name, NbtTag::Byte(i8::from(value)));
} }
pub fn put_short(&mut self, name: &str, value: i16) { pub fn put_short(&mut self, name: &str, value: i16) {
@ -128,15 +130,17 @@ impl NbtCompound {
self.put(name, NbtTag::Double(value)); self.put(name, NbtTag::Double(value));
} }
pub fn put_component(&mut self, name: &str, value: NbtCompound) { pub fn put_component(&mut self, name: &str, value: Self) {
self.put(name, NbtTag::Compound(value)); self.put(name, NbtTag::Compound(value));
} }
#[must_use]
pub fn get_byte(&self, name: &str) -> Option<i8> { pub fn get_byte(&self, name: &str) -> Option<i8> {
self.get(name).and_then(|tag| tag.extract_byte()) self.get(name).and_then(super::tag::NbtTag::extract_byte)
} }
#[inline] #[inline]
#[must_use]
pub fn get(&self, name: &str) -> Option<&NbtTag> { pub fn get(&self, name: &str) -> Option<&NbtTag> {
self.child_tags self.child_tags
.iter() .iter()
@ -144,46 +148,57 @@ impl NbtCompound {
.map(|r| &r.1) .map(|r| &r.1)
} }
#[must_use]
pub fn get_short(&self, name: &str) -> Option<i16> { pub fn get_short(&self, name: &str) -> Option<i16> {
self.get(name).and_then(|tag| tag.extract_short()) self.get(name).and_then(super::tag::NbtTag::extract_short)
} }
#[must_use]
pub fn get_int(&self, name: &str) -> Option<i32> { pub fn get_int(&self, name: &str) -> Option<i32> {
self.get(name).and_then(|tag| tag.extract_int()) self.get(name).and_then(super::tag::NbtTag::extract_int)
} }
#[must_use]
pub fn get_long(&self, name: &str) -> Option<i64> { pub fn get_long(&self, name: &str) -> Option<i64> {
self.get(name).and_then(|tag| tag.extract_long()) self.get(name).and_then(super::tag::NbtTag::extract_long)
} }
#[must_use]
pub fn get_float(&self, name: &str) -> Option<f32> { pub fn get_float(&self, name: &str) -> Option<f32> {
self.get(name).and_then(|tag| tag.extract_float()) self.get(name).and_then(super::tag::NbtTag::extract_float)
} }
#[must_use]
pub fn get_double(&self, name: &str) -> Option<f64> { pub fn get_double(&self, name: &str) -> Option<f64> {
self.get(name).and_then(|tag| tag.extract_double()) self.get(name).and_then(super::tag::NbtTag::extract_double)
} }
#[must_use]
pub fn get_bool(&self, name: &str) -> Option<bool> { pub fn get_bool(&self, name: &str) -> Option<bool> {
self.get(name).and_then(|tag| tag.extract_bool()) self.get(name).and_then(super::tag::NbtTag::extract_bool)
} }
#[must_use]
pub fn get_string(&self, name: &str) -> Option<&str> { pub fn get_string(&self, name: &str) -> Option<&str> {
self.get(name).and_then(|tag| tag.extract_string()) self.get(name).and_then(|tag| tag.extract_string())
} }
#[must_use]
pub fn get_list(&self, name: &str) -> Option<&[NbtTag]> { pub fn get_list(&self, name: &str) -> Option<&[NbtTag]> {
self.get(name).and_then(|tag| tag.extract_list()) self.get(name).and_then(|tag| tag.extract_list())
} }
pub fn get_compound(&self, name: &str) -> Option<&NbtCompound> { #[must_use]
pub fn get_compound(&self, name: &str) -> Option<&Self> {
self.get(name).and_then(|tag| tag.extract_compound()) self.get(name).and_then(|tag| tag.extract_compound())
} }
#[must_use]
pub fn get_int_array(&self, name: &str) -> Option<&[i32]> { pub fn get_int_array(&self, name: &str) -> Option<&[i32]> {
self.get(name).and_then(|tag| tag.extract_int_array()) self.get(name).and_then(|tag| tag.extract_int_array())
} }
#[must_use]
pub fn get_long_array(&self, name: &str) -> Option<&[i64]> { pub fn get_long_array(&self, name: &str) -> Option<&[i64]> {
self.get(name).and_then(|tag| tag.extract_long_array()) self.get(name).and_then(|tag| tag.extract_long_array())
} }
@ -197,7 +212,7 @@ impl From<Nbt> for NbtCompound {
impl FromIterator<(String, NbtTag)> for NbtCompound { impl FromIterator<(String, NbtTag)> for NbtCompound {
fn from_iter<T: IntoIterator<Item = (String, NbtTag)>>(iter: T) -> Self { fn from_iter<T: IntoIterator<Item = (String, NbtTag)>>(iter: T) -> Self {
let mut compound = NbtCompound::new(); let mut compound = Self::new();
for (key, value) in iter { for (key, value) in iter {
compound.put(&key, value); compound.put(&key, value);
} }
@ -216,13 +231,13 @@ impl IntoIterator for NbtCompound {
impl Extend<(String, NbtTag)> for NbtCompound { impl Extend<(String, NbtTag)> for NbtCompound {
fn extend<T: IntoIterator<Item = (String, NbtTag)>>(&mut self, iter: T) { fn extend<T: IntoIterator<Item = (String, NbtTag)>>(&mut self, iter: T) {
self.child_tags.extend(iter) self.child_tags.extend(iter);
} }
} }
// Rust's AsRef is currently not reflexive so we need to implement it manually // Rust's AsRef is currently not reflexive so we need to implement it manually
impl AsRef<NbtCompound> for NbtCompound { impl AsRef<Self> for NbtCompound {
fn as_ref(&self) -> &NbtCompound { fn as_ref(&self) -> &Self {
self self
} }
} }
@ -267,11 +282,11 @@ impl<'de> Deserialize<'de> for NbtCompound {
impl From<NbtCompound> for NbtTag { impl From<NbtCompound> for NbtTag {
fn from(value: NbtCompound) -> Self { fn from(value: NbtCompound) -> Self {
NbtTag::Compound(value) Self::Compound(value)
} }
} }
/// SNBT display implementation for NbtCompound /// SNBT display implementation for `NbtCompound`
impl Display for NbtCompound { impl Display for NbtCompound {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.write_str("{")?; f.write_str("{")?;
@ -279,7 +294,7 @@ impl Display for NbtCompound {
if i > 0 { if i > 0 {
f.write_str(", ")?; f.write_str(", ")?;
} }
write!(f, "{}: {}", key, value)?; write!(f, "{key}: {value}")?;
} }
f.write_str("}") f.write_str("}")
} }
@ -288,52 +303,52 @@ impl Display for NbtCompound {
impl Display for NbtTag { impl Display for NbtTag {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self { match self {
NbtTag::End => Ok(()), Self::End => Ok(()),
NbtTag::Byte(v) => write!(f, "{v}b"), Self::Byte(v) => write!(f, "{v}b"),
NbtTag::Short(v) => write!(f, "{v}s"), Self::Short(v) => write!(f, "{v}s"),
NbtTag::Int(v) => write!(f, "{v}"), Self::Int(v) => write!(f, "{v}"),
NbtTag::Long(v) => write!(f, "{v}L"), Self::Long(v) => write!(f, "{v}L"),
NbtTag::Float(v) => write!(f, "{v}f"), Self::Float(v) => write!(f, "{v}f"),
NbtTag::Double(v) => write!(f, "{v}d"), Self::Double(v) => write!(f, "{v}d"),
NbtTag::String(v) => write!(f, "\"{v}\""), // TODO: Proper escaping needed for robust SNBT Self::String(v) => write!(f, "\"{v}\""), // TODO: Proper escaping needed for robust SNBT
NbtTag::Compound(v) => write!(f, "{v}"), Self::Compound(v) => write!(f, "{v}"),
NbtTag::ByteArray(v) => { Self::ByteArray(v) => {
f.write_str("[B;")?; f.write_str("[B;")?;
for (i, byte) in v.iter().enumerate() { for (i, byte) in v.iter().enumerate() {
if i > 0 { if i > 0 {
f.write_str(",")? f.write_str(",")?;
} }
write!(f, " {}b", byte)?; write!(f, " {byte}b")?;
} }
f.write_str("]") f.write_str("]")
} }
NbtTag::List(v) => { Self::List(v) => {
f.write_str("[")?; f.write_str("[")?;
for (i, tag) in v.iter().enumerate() { for (i, tag) in v.iter().enumerate() {
if i > 0 { if i > 0 {
f.write_str(", ")? f.write_str(", ")?;
} }
write!(f, "{}", tag)?; write!(f, "{tag}")?;
} }
f.write_str("]") f.write_str("]")
} }
NbtTag::IntArray(v) => { Self::IntArray(v) => {
f.write_str("[I;")?; f.write_str("[I;")?;
for (i, int) in v.iter().enumerate() { for (i, int) in v.iter().enumerate() {
if i > 0 { if i > 0 {
f.write_str(",")? f.write_str(",")?;
} }
write!(f, " {}", int)?; write!(f, " {int}")?;
} }
f.write_str("]") f.write_str("]")
} }
NbtTag::LongArray(v) => { Self::LongArray(v) => {
f.write_str("[L;")?; f.write_str("[L;")?;
for (i, long) in v.iter().enumerate() { for (i, long) in v.iter().enumerate() {
if i > 0 { if i > 0 {
f.write_str(",")? f.write_str(",")?;
} }
write!(f, " {}L", long)?; write!(f, " {long}L")?;
} }
f.write_str("]") f.write_str("]")
} }

View File

@ -1,7 +1,10 @@
use std::cell::RefCell; use std::cell::RefCell;
use std::io::{Seek, SeekFrom}; use std::io::{Seek, SeekFrom};
use crate::*; use crate::{
BYTE_ARRAY_ID, BYTE_ID, COMPOUND_ID, END_ID, Error, INT_ARRAY_ID, INT_ID, LIST_ID,
LONG_ARRAY_ID, LONG_ID, NbtTag, get_nbt_string, io,
};
use io::Read; use io::Read;
use serde::de::{self, DeserializeSeed, IntoDeserializer, MapAccess, SeqAccess, Visitor}; use serde::de::{self, DeserializeSeed, IntoDeserializer, MapAccess, SeqAccess, Visitor};
use serde::{Deserialize, forward_to_deserialize_any}; use serde::{Deserialize, forward_to_deserialize_any};
@ -13,7 +16,7 @@ thread_local! {
} }
pub(super) fn take_curr_visitor_seq_list_id() -> Option<u8> { pub(super) fn take_curr_visitor_seq_list_id() -> Option<u8> {
CURR_VISITOR_LIST_TYPE.with(|cell| cell.take()) CURR_VISITOR_LIST_TYPE.with(std::cell::RefCell::take)
} }
pub(super) fn set_curr_visitor_seq_list_id(tag: Option<u8>) { pub(super) fn set_curr_visitor_seq_list_id(tag: Option<u8>) {
@ -85,7 +88,7 @@ pub struct Deserializer<R: Read + Seek> {
impl<R: Read + Seek> Deserializer<R> { impl<R: Read + Seek> Deserializer<R> {
pub fn new(input: R, is_named: bool) -> Self { pub fn new(input: R, is_named: bool) -> Self {
Deserializer { Self {
input: NbtReadHelper { reader: input }, input: NbtReadHelper { reader: input },
tag_to_deserialize_stack: None, tag_to_deserialize_stack: None,
in_list: false, in_list: false,
@ -230,8 +233,7 @@ impl<'de, R: Read + Seek> de::Deserializer<'de> for &mut Deserializer<R> {
if let Some(tag_id) = self.tag_to_deserialize_stack { if let Some(tag_id) = self.tag_to_deserialize_stack {
if tag_id != COMPOUND_ID { if tag_id != COMPOUND_ID {
return Err(Error::SerdeError(format!( return Err(Error::SerdeError(format!(
"Trying to deserialize a map without a compound ID (id {})", "Trying to deserialize a map without a compound ID (id {tag_id})"
tag_id
))); )));
} }
} else { } else {

View File

@ -59,13 +59,13 @@ pub enum Error {
impl ser::Error for Error { impl ser::Error for Error {
fn custom<T: Display>(msg: T) -> Self { fn custom<T: Display>(msg: T) -> Self {
Error::SerdeError(msg.to_string()) Self::SerdeError(msg.to_string())
} }
} }
impl de::Error for Error { impl de::Error for Error {
fn custom<T: Display>(msg: T) -> Self { fn custom<T: Display>(msg: T) -> Self {
Error::SerdeError(msg.to_string()) Self::SerdeError(msg.to_string())
} }
} }
@ -76,40 +76,42 @@ pub struct Nbt {
} }
impl Nbt { impl Nbt {
#[must_use]
pub fn new(name: String, tag: NbtCompound) -> Self { pub fn new(name: String, tag: NbtCompound) -> Self {
Nbt { Self {
name, name,
root_tag: tag, root_tag: tag,
} }
} }
pub fn read<R: Read + Seek>(reader: &mut NbtReadHelper<R>) -> Result<Nbt, Error> { pub fn read<R: Read + Seek>(reader: &mut NbtReadHelper<R>) -> Result<Self, Error> {
let tag_type_id = reader.get_u8_be()?; let tag_type_id = reader.get_u8_be()?;
if tag_type_id != COMPOUND_ID { if tag_type_id != COMPOUND_ID {
return Err(Error::NoRootCompound(tag_type_id)); return Err(Error::NoRootCompound(tag_type_id));
} }
Ok(Nbt { Ok(Self {
name: get_nbt_string(reader)?, name: get_nbt_string(reader)?,
root_tag: NbtCompound::deserialize_content(reader)?, root_tag: NbtCompound::deserialize_content(reader)?,
}) })
} }
/// Reads an NBT tag that doesn't contain the name of the root `Compound`. /// Reads an NBT tag that doesn't contain the name of the root `Compound`.
pub fn read_unnamed<R: Read + Seek>(reader: &mut NbtReadHelper<R>) -> Result<Nbt, Error> { pub fn read_unnamed<R: Read + Seek>(reader: &mut NbtReadHelper<R>) -> Result<Self, Error> {
let tag_type_id = reader.get_u8_be()?; let tag_type_id = reader.get_u8_be()?;
if tag_type_id != COMPOUND_ID { if tag_type_id != COMPOUND_ID {
return Err(Error::NoRootCompound(tag_type_id)); return Err(Error::NoRootCompound(tag_type_id));
} }
Ok(Nbt { Ok(Self {
name: String::new(), name: String::new(),
root_tag: NbtCompound::deserialize_content(reader)?, root_tag: NbtCompound::deserialize_content(reader)?,
}) })
} }
#[must_use]
pub fn write(self) -> Bytes { pub fn write(self) -> Bytes {
let mut bytes = Vec::new(); let mut bytes = Vec::new();
let mut writer = WriteAdaptor::new(&mut bytes); let mut writer = WriteAdaptor::new(&mut bytes);
@ -128,6 +130,7 @@ impl Nbt {
} }
/// Writes an NBT tag without a root `Compound` name. /// Writes an NBT tag without a root `Compound` name.
#[must_use]
pub fn write_unnamed(self) -> Bytes { pub fn write_unnamed(self) -> Bytes {
let mut bytes = Vec::new(); let mut bytes = Vec::new();
let mut writer = WriteAdaptor::new(&mut bytes); let mut writer = WriteAdaptor::new(&mut bytes);
@ -154,14 +157,14 @@ impl Deref for Nbt {
impl From<NbtCompound> for Nbt { impl From<NbtCompound> for Nbt {
fn from(value: NbtCompound) -> Self { fn from(value: NbtCompound) -> Self {
Nbt::new(String::new(), value) Self::new(String::new(), value)
} }
} }
impl<T> AsRef<T> for Nbt impl<T> AsRef<T> for Nbt
where where
T: ?Sized, T: ?Sized,
<Nbt as Deref>::Target: AsRef<T>, <Self as Deref>::Target: AsRef<T>,
{ {
fn as_ref(&self) -> &T { fn as_ref(&self) -> &T {
self.deref().as_ref() self.deref().as_ref()
@ -246,6 +249,7 @@ mod test {
} }
#[derive(Serialize, Deserialize, PartialEq, Debug)] #[derive(Serialize, Deserialize, PartialEq, Debug)]
#[expect(clippy::struct_field_names)]
struct TestArray { struct TestArray {
#[serde(serialize_with = "nbt_byte_array")] #[serde(serialize_with = "nbt_byte_array")]
byte_array: Vec<u8>, byte_array: Vec<u8>,
@ -354,7 +358,7 @@ mod test {
}, },
}, },
compounds: vec![test1, test2], compounds: vec![test1, test2],
list_string: vec!["".to_string(), "abcbcbcbbc".to_string()], list_string: vec![String::new(), "abcbcbcbbc".to_string()],
empty: vec![], empty: vec![],
}; };
@ -392,7 +396,7 @@ mod test {
}, },
}, },
compounds: vec![test1, test2], compounds: vec![test1, test2],
list_string: vec!["".to_string(), "abcbcbcbbc".to_string()], list_string: vec![String::new(), "abcbcbcbbc".to_string()],
empty: vec![], empty: vec![],
}; };
@ -413,6 +417,12 @@ mod test {
#[serde(serialize_with = "nbt_byte_array")] #[serde(serialize_with = "nbt_byte_array")]
b: [u8; 1], b: [u8; 1],
} }
#[derive(Serialize)]
struct NotTagged {
l: [i64; 1],
i: [i32; 1],
b: [u8; 1],
}
let value = Tagged { let value = Tagged {
l: [0], l: [0],
@ -444,13 +454,6 @@ mod test {
to_bytes(&value, &mut bytes).unwrap(); to_bytes(&value, &mut bytes).unwrap();
assert_eq!(bytes, expected_bytes); assert_eq!(bytes, expected_bytes);
#[derive(Serialize)]
struct NotTagged {
l: [i64; 1],
i: [i32; 1],
b: [u8; 1],
}
let value = NotTagged { let value = NotTagged {
l: [0], l: [0],
i: [0], i: [0],
@ -499,7 +502,7 @@ mod test {
match err { match err {
Err(Error::SerdeError(_)) => (), Err(Error::SerdeError(_)) => (),
_ => panic!("Expected to fail serialization!"), _ => panic!("Expected to fail serialization!"),
}; }
} }
#[test] #[test]

View File

@ -3,15 +3,15 @@ use crate::{Error, Nbt, NbtCompound, deserializer, serializer};
use flate2::{Compression, read::GzDecoder, write::GzEncoder}; use flate2::{Compression, read::GzDecoder, write::GzEncoder};
use std::io::{Cursor, Read, Seek, Write}; use std::io::{Cursor, Read, Seek, Write};
/// Reads a GZipped NBT compound tag from any reader. /// Reads a `GZipped` NBT compound tag from any reader.
/// ///
/// # Arguments /// # Arguments
/// ///
/// * `input` - Any type implementing the Read trait containing GZipped NBT data /// * `input` - Any type implementing the Read trait containing `GZipped` NBT data
/// ///
/// # Returns /// # Returns
/// ///
/// A Result containing either the parsed NbtCompound or an Error /// A Result containing either the parsed `NbtCompound` or an Error
pub fn read_gzip_compound_tag(input: impl Read + Seek) -> Result<NbtCompound, Error> { pub fn read_gzip_compound_tag(input: impl Read + Seek) -> Result<NbtCompound, Error> {
// Create a GZip decoder and directly chain it to the NBT reader // Create a GZip decoder and directly chain it to the NBT reader
let mut decoder = GzDecoder::new(input); let mut decoder = GzDecoder::new(input);
@ -24,13 +24,13 @@ pub fn read_gzip_compound_tag(input: impl Read + Seek) -> Result<NbtCompound, Er
Ok(nbt.root_tag) Ok(nbt.root_tag)
} }
/// Writes an NBT compound tag with GZip compression. /// Writes an NBT compound tag with `GZip` compression.
/// ///
/// This function takes an NbtCompound and writes it as a GZipped byte vector. /// This function takes an `NbtCompound` and writes it as a `GZipped` byte vector.
/// ///
/// # Arguments /// # Arguments
/// ///
/// * `compound` - The NbtCompound to serialize and compress /// * `compound` - The `NbtCompound` to serialize and compress
/// * `output` - Any type implementing the Write trait where the compressed data will be written /// * `output` - Any type implementing the Write trait where the compressed data will be written
/// ///
/// # Returns /// # Returns
@ -58,11 +58,11 @@ pub fn write_gzip_compound_tag_to_bytes(compound: NbtCompound) -> Result<Vec<u8>
Ok(buffer) Ok(buffer)
} }
/// Reads a GZipped NBT structure into a Rust type. /// Reads a `GZipped` NBT structure into a Rust type.
/// ///
/// # Arguments /// # Arguments
/// ///
/// * `input` - Any type implementing the Read trait containing GZipped NBT data /// * `input` - Any type implementing the Read trait containing `GZipped` NBT data
/// ///
/// # Returns /// # Returns
/// ///
@ -75,7 +75,7 @@ pub fn from_gzip_bytes<'a, T: serde::Deserialize<'a>, R: Read>(input: R) -> Resu
deserializer::from_bytes(Cursor::new(buf)) deserializer::from_bytes(Cursor::new(buf))
} }
/// Writes a Rust type as GZipped NBT to any writer. /// Writes a Rust type as `GZipped` NBT to any writer.
/// ///
/// # Arguments /// # Arguments
/// ///
@ -262,6 +262,7 @@ mod tests {
} }
#[test] #[test]
#[expect(clippy::print_stdout)]
fn test_gzip_compression_ratio() { fn test_gzip_compression_ratio() {
let mut compound = NbtCompound::new(); let mut compound = NbtCompound::new();
@ -294,6 +295,7 @@ mod tests {
} }
#[test] #[test]
#[expect(clippy::struct_field_names)]
fn test_roundtrip_with_arrays() { fn test_roundtrip_with_arrays() {
#[derive(Serialize, Deserialize, Debug, PartialEq)] #[derive(Serialize, Deserialize, Debug, PartialEq)]
struct ArrayTest { struct ArrayTest {

View File

@ -122,7 +122,7 @@ impl<W: Write> Serializer<W> {
return Err(Error::SerdeError( return Err(Error::SerdeError(
"Invalid state: already handled root component!".to_string(), "Invalid state: already handled root component!".to_string(),
)); ));
} else { }
if tag != COMPOUND_ID { if tag != COMPOUND_ID {
return Err(Error::SerdeError(format!( return Err(Error::SerdeError(format!(
"Invalid state: root is not a `Compound`! ({tag})" "Invalid state: root is not a `Compound`! ({tag})"
@ -135,7 +135,6 @@ impl<W: Write> Serializer<W> {
} }
} }
} }
};
Ok(()) Ok(())
} }
} }
@ -171,7 +170,7 @@ impl<W: Write> ser::Serializer for &mut Serializer<W> {
type SerializeStructVariant = Impossible<(), Error>; type SerializeStructVariant = Impossible<(), Error>;
fn serialize_bool(self, v: bool) -> Result<()> { fn serialize_bool(self, v: bool) -> Result<()> {
self.serialize_i8(v as i8)?; self.serialize_i8(i8::from(v))?;
Ok(()) Ok(())
} }
@ -200,17 +199,16 @@ impl<W: Write> ser::Serializer for &mut Serializer<W> {
} }
fn serialize_u8(self, v: u8) -> Result<()> { fn serialize_u8(self, v: u8) -> Result<()> {
match self.state { if let State::Named(_) = self.state {
State::Named(_) => Err(Error::UnsupportedType( Err(Error::UnsupportedType(
"u8; NBT only supports signed values".to_string(), "u8; NBT only supports signed values".to_string(),
)), ))
_ => { } else {
self.parse_state(BYTE_ID)?; self.parse_state(BYTE_ID)?;
self.output.write_u8_be(v)?; self.output.write_u8_be(v)?;
Ok(()) Ok(())
} }
} }
}
fn serialize_u16(self, v: u16) -> Result<()> { fn serialize_u16(self, v: u16) -> Result<()> {
self.serialize_i16(v as i16) self.serialize_i16(v as i16)
@ -336,8 +334,7 @@ impl<W: Write> ser::Serializer for &mut Serializer<W> {
return Err(Error::LargeLength(len)); return Err(Error::LargeLength(len));
} }
match &mut self.state { if let State::Array { array_type, .. } = &mut self.state {
State::Array { array_type, .. } => {
let (id, expected_tag) = match *array_type { let (id, expected_tag) = match *array_type {
NBT_BYTE_ARRAY_TAG => (BYTE_ARRAY_ID, BYTE_ID), NBT_BYTE_ARRAY_TAG => (BYTE_ARRAY_ID, BYTE_ID),
NBT_INT_ARRAY_TAG => (INT_ARRAY_ID, INT_ID), NBT_INT_ARRAY_TAG => (INT_ARRAY_ID, INT_ID),
@ -355,8 +352,7 @@ impl<W: Write> ser::Serializer for &mut Serializer<W> {
// We can mark anything as an NBT array list, so mark as needed to be checked. // We can mark anything as an NBT array list, so mark as needed to be checked.
self.expected_list_tag = expected_tag; self.expected_list_tag = expected_tag;
self.state = State::CheckedListElement; self.state = State::CheckedListElement;
} } else {
_ => {
self.parse_state(LIST_ID)?; self.parse_state(LIST_ID)?;
self.state = State::FirstListElement { len: len as i32 }; self.state = State::FirstListElement { len: len as i32 };
if len == 0 { if len == 0 {
@ -366,7 +362,6 @@ impl<W: Write> ser::Serializer for &mut Serializer<W> {
self.output.write_i32_be(0)?; self.output.write_i32_be(0)?;
} }
} }
}
Ok(self) Ok(self)
} }

View File

@ -4,7 +4,11 @@ use io::Read;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use serializer::WriteAdaptor; use serializer::WriteAdaptor;
use crate::*; use crate::{
BYTE_ARRAY_ID, BYTE_ID, COMPOUND_ID, DOUBLE_ID, END_ID, Error, FLOAT_ID, INT_ARRAY_ID, INT_ID,
LIST_ID, LONG_ARRAY_ID, LONG_ID, SHORT_ID, STRING_ID, Seek, Write, compound, deserializer,
get_nbt_string, io, nbt_byte_array, nbt_int_array, nbt_long_array, serializer,
};
#[derive(Clone, Debug, PartialEq, PartialOrd)] #[derive(Clone, Debug, PartialEq, PartialOrd)]
#[repr(u8)] #[repr(u8)]
@ -18,7 +22,7 @@ pub enum NbtTag {
Double(f64) = DOUBLE_ID, Double(f64) = DOUBLE_ID,
ByteArray(Box<[u8]>) = BYTE_ARRAY_ID, ByteArray(Box<[u8]>) = BYTE_ARRAY_ID,
String(String) = STRING_ID, String(String) = STRING_ID,
List(Vec<NbtTag>) = LIST_ID, List(Vec<Self>) = LIST_ID,
Compound(NbtCompound) = COMPOUND_ID, Compound(NbtCompound) = COMPOUND_ID,
IntArray(Vec<i32>) = INT_ARRAY_ID, IntArray(Vec<i32>) = INT_ARRAY_ID,
LongArray(Vec<i64>) = LONG_ARRAY_ID, LongArray(Vec<i64>) = LONG_ARRAY_ID,
@ -26,10 +30,11 @@ pub enum NbtTag {
impl NbtTag { impl NbtTag {
/// Returns the numeric id associated with the data type. /// Returns the numeric id associated with the data type.
#[must_use]
pub const fn get_type_id(&self) -> u8 { pub const fn get_type_id(&self) -> u8 {
// Safety: Since Self is repr(u8), it is guaranteed to hold the discriminant in the first byte // Safety: Since Self is repr(u8), it is guaranteed to hold the discriminant in the first byte
// See https://doc.rust-lang.org/reference/items/enumerations.html#pointer-casting // See https://doc.rust-lang.org/reference/items/enumerations.html#pointer-casting
unsafe { *(self as *const Self as *const u8) } unsafe { *std::ptr::from_ref::<Self>(self).cast::<u8>() }
} }
pub fn serialize<W: Write>(self, w: &mut WriteAdaptor<W>) -> serializer::Result<()> { pub fn serialize<W: Write>(self, w: &mut WriteAdaptor<W>) -> serializer::Result<()> {
@ -52,14 +57,14 @@ impl NbtTag {
pub fn serialize_data<W: Write>(self, w: &mut WriteAdaptor<W>) -> serializer::Result<()> { pub fn serialize_data<W: Write>(self, w: &mut WriteAdaptor<W>) -> serializer::Result<()> {
match self { match self {
NbtTag::End => {} Self::End => {}
NbtTag::Byte(byte) => w.write_i8_be(byte)?, Self::Byte(byte) => w.write_i8_be(byte)?,
NbtTag::Short(short) => w.write_i16_be(short)?, Self::Short(short) => w.write_i16_be(short)?,
NbtTag::Int(int) => w.write_i32_be(int)?, Self::Int(int) => w.write_i32_be(int)?,
NbtTag::Long(long) => w.write_i64_be(long)?, Self::Long(long) => w.write_i64_be(long)?,
NbtTag::Float(float) => w.write_f32_be(float)?, Self::Float(float) => w.write_f32_be(float)?,
NbtTag::Double(double) => w.write_f64_be(double)?, Self::Double(double) => w.write_f64_be(double)?,
NbtTag::ByteArray(byte_array) => { Self::ByteArray(byte_array) => {
let len = byte_array.len(); let len = byte_array.len();
if len > i32::MAX as usize { if len > i32::MAX as usize {
return Err(Error::LargeLength(len)); return Err(Error::LargeLength(len));
@ -68,25 +73,25 @@ impl NbtTag {
w.write_i32_be(len as i32)?; w.write_i32_be(len as i32)?;
w.write_slice(&byte_array)?; w.write_slice(&byte_array)?;
} }
NbtTag::String(string) => { Self::String(string) => {
Self::write_string(&string, w)?; Self::write_string(&string, w)?;
} }
NbtTag::List(list) => { Self::List(list) => {
let len = list.len(); let len = list.len();
if len > i32::MAX as usize { if len > i32::MAX as usize {
return Err(Error::LargeLength(len)); return Err(Error::LargeLength(len));
} }
w.write_u8_be(list.first().unwrap_or(&NbtTag::End).get_type_id())?; w.write_u8_be(list.first().unwrap_or(&Self::End).get_type_id())?;
w.write_i32_be(len as i32)?; w.write_i32_be(len as i32)?;
for nbt_tag in list { for nbt_tag in list {
nbt_tag.serialize_data(w)?; nbt_tag.serialize_data(w)?;
} }
} }
NbtTag::Compound(compound) => { Self::Compound(compound) => {
compound.serialize_content(w)?; compound.serialize_content(w)?;
} }
NbtTag::IntArray(int_array) => { Self::IntArray(int_array) => {
let len = int_array.len(); let len = int_array.len();
if len > i32::MAX as usize { if len > i32::MAX as usize {
return Err(Error::LargeLength(len)); return Err(Error::LargeLength(len));
@ -97,7 +102,7 @@ impl NbtTag {
w.write_i32_be(int)?; w.write_i32_be(int)?;
} }
} }
NbtTag::LongArray(long_array) => { Self::LongArray(long_array) => {
let len = long_array.len(); let len = long_array.len();
if len > i32::MAX as usize { if len > i32::MAX as usize {
return Err(Error::LargeLength(len)); return Err(Error::LargeLength(len));
@ -109,11 +114,11 @@ impl NbtTag {
w.write_i64_be(long)?; w.write_i64_be(long)?;
} }
} }
}; }
Ok(()) Ok(())
} }
pub fn deserialize<R: Read + Seek>(reader: &mut NbtReadHelper<R>) -> Result<NbtTag, Error> { pub fn deserialize<R: Read + Seek>(reader: &mut NbtReadHelper<R>) -> Result<Self, Error> {
let tag_id = reader.get_u8_be()?; let tag_id = reader.get_u8_be()?;
Self::deserialize_data(reader, tag_id) Self::deserialize_data(reader, tag_id)
} }
@ -126,20 +131,18 @@ impl NbtTag {
END_ID => Ok(()), END_ID => Ok(()),
BYTE_ID => reader.skip_bytes(1), BYTE_ID => reader.skip_bytes(1),
SHORT_ID => reader.skip_bytes(2), SHORT_ID => reader.skip_bytes(2),
INT_ID => reader.skip_bytes(4), INT_ID | FLOAT_ID => reader.skip_bytes(4),
LONG_ID => reader.skip_bytes(8), LONG_ID | DOUBLE_ID => reader.skip_bytes(8),
FLOAT_ID => reader.skip_bytes(4),
DOUBLE_ID => reader.skip_bytes(8),
BYTE_ARRAY_ID => { BYTE_ARRAY_ID => {
let len = reader.get_i32_be()?; let len = reader.get_i32_be()?;
if len < 0 { if len < 0 {
return Err(Error::NegativeLength(len)); return Err(Error::NegativeLength(len));
} }
reader.skip_bytes(len as i64) reader.skip_bytes(i64::from(len))
} }
STRING_ID => { STRING_ID => {
let len = reader.get_u16_be()?; let len = reader.get_u16_be()?;
reader.skip_bytes(len as i64) reader.skip_bytes(i64::from(len))
} }
LIST_ID => { LIST_ID => {
let tag_type_id = reader.get_u8_be()?; let tag_type_id = reader.get_u8_be()?;
@ -161,7 +164,7 @@ impl NbtTag {
return Err(Error::NegativeLength(len)); return Err(Error::NegativeLength(len));
} }
reader.skip_bytes(len as i64 * 4) reader.skip_bytes(i64::from(len) * 4)
} }
LONG_ARRAY_ID => { LONG_ARRAY_ID => {
let len = reader.get_i32_be()?; let len = reader.get_i32_be()?;
@ -169,7 +172,7 @@ impl NbtTag {
return Err(Error::NegativeLength(len)); return Err(Error::NegativeLength(len));
} }
reader.skip_bytes(len as i64 * 8) reader.skip_bytes(i64::from(len) * 8)
} }
_ => Err(Error::UnknownTagId(tag_id)), _ => Err(Error::UnknownTagId(tag_id)),
} }
@ -178,32 +181,32 @@ impl NbtTag {
pub fn deserialize_data<R: Read + Seek>( pub fn deserialize_data<R: Read + Seek>(
reader: &mut NbtReadHelper<R>, reader: &mut NbtReadHelper<R>,
tag_id: u8, tag_id: u8,
) -> Result<NbtTag, Error> { ) -> Result<Self, Error> {
match tag_id { match tag_id {
END_ID => Ok(NbtTag::End), END_ID => Ok(Self::End),
BYTE_ID => { BYTE_ID => {
let byte = reader.get_i8_be()?; let byte = reader.get_i8_be()?;
Ok(NbtTag::Byte(byte)) Ok(Self::Byte(byte))
} }
SHORT_ID => { SHORT_ID => {
let short = reader.get_i16_be()?; let short = reader.get_i16_be()?;
Ok(NbtTag::Short(short)) Ok(Self::Short(short))
} }
INT_ID => { INT_ID => {
let int = reader.get_i32_be()?; let int = reader.get_i32_be()?;
Ok(NbtTag::Int(int)) Ok(Self::Int(int))
} }
LONG_ID => { LONG_ID => {
let long = reader.get_i64_be()?; let long = reader.get_i64_be()?;
Ok(NbtTag::Long(long)) Ok(Self::Long(long))
} }
FLOAT_ID => { FLOAT_ID => {
let float = reader.get_f32_be()?; let float = reader.get_f32_be()?;
Ok(NbtTag::Float(float)) Ok(Self::Float(float))
} }
DOUBLE_ID => { DOUBLE_ID => {
let double = reader.get_f64_be()?; let double = reader.get_f64_be()?;
Ok(NbtTag::Double(double)) Ok(Self::Double(double))
} }
BYTE_ARRAY_ID => { BYTE_ARRAY_ID => {
let len = reader.get_i32_be()?; let len = reader.get_i32_be()?;
@ -212,9 +215,9 @@ impl NbtTag {
} }
let byte_array = reader.read_boxed_slice(len as usize)?; let byte_array = reader.read_boxed_slice(len as usize)?;
Ok(NbtTag::ByteArray(byte_array)) Ok(Self::ByteArray(byte_array))
} }
STRING_ID => Ok(NbtTag::String(get_nbt_string(reader)?)), STRING_ID => Ok(Self::String(get_nbt_string(reader)?)),
LIST_ID => { LIST_ID => {
let tag_type_id = reader.get_u8_be()?; let tag_type_id = reader.get_u8_be()?;
let len = reader.get_i32_be()?; let len = reader.get_i32_be()?;
@ -224,13 +227,13 @@ impl NbtTag {
let mut list = Vec::with_capacity(len as usize); let mut list = Vec::with_capacity(len as usize);
for _ in 0..len { for _ in 0..len {
let tag = NbtTag::deserialize_data(reader, tag_type_id)?; let tag = Self::deserialize_data(reader, tag_type_id)?;
assert_eq!(tag.get_type_id(), tag_type_id); assert_eq!(tag.get_type_id(), tag_type_id);
list.push(tag); list.push(tag);
} }
Ok(NbtTag::List(list)) Ok(Self::List(list))
} }
COMPOUND_ID => Ok(NbtTag::Compound(NbtCompound::deserialize_content(reader)?)), COMPOUND_ID => Ok(Self::Compound(NbtCompound::deserialize_content(reader)?)),
INT_ARRAY_ID => { INT_ARRAY_ID => {
let len = reader.get_i32_be()?; let len = reader.get_i32_be()?;
if len < 0 { if len < 0 {
@ -243,7 +246,7 @@ impl NbtTag {
let int = reader.get_i32_be()?; let int = reader.get_i32_be()?;
int_array.push(int); int_array.push(int);
} }
Ok(NbtTag::IntArray(int_array)) Ok(Self::IntArray(int_array))
} }
LONG_ARRAY_ID => { LONG_ARRAY_ID => {
let len = reader.get_i32_be()?; let len = reader.get_i32_be()?;
@ -257,99 +260,112 @@ impl NbtTag {
let long = reader.get_i64_be()?; let long = reader.get_i64_be()?;
long_array.push(long); long_array.push(long);
} }
Ok(NbtTag::LongArray(long_array)) Ok(Self::LongArray(long_array))
} }
_ => Err(Error::UnknownTagId(tag_id)), _ => Err(Error::UnknownTagId(tag_id)),
} }
} }
#[must_use]
pub fn extract_byte(&self) -> Option<i8> { pub fn extract_byte(&self) -> Option<i8> {
match self { match self {
NbtTag::Byte(byte) => Some(*byte), Self::Byte(byte) => Some(*byte),
_ => None, _ => None,
} }
} }
#[must_use]
pub fn extract_short(&self) -> Option<i16> { pub fn extract_short(&self) -> Option<i16> {
match self { match self {
NbtTag::Short(short) => Some(*short), Self::Short(short) => Some(*short),
_ => None, _ => None,
} }
} }
#[must_use]
pub fn extract_int(&self) -> Option<i32> { pub fn extract_int(&self) -> Option<i32> {
match self { match self {
NbtTag::Int(int) => Some(*int), Self::Int(int) => Some(*int),
_ => None, _ => None,
} }
} }
#[must_use]
pub fn extract_long(&self) -> Option<i64> { pub fn extract_long(&self) -> Option<i64> {
match self { match self {
NbtTag::Long(long) => Some(*long), Self::Long(long) => Some(*long),
_ => None, _ => None,
} }
} }
#[must_use]
pub fn extract_float(&self) -> Option<f32> { pub fn extract_float(&self) -> Option<f32> {
match self { match self {
NbtTag::Float(float) => Some(*float), Self::Float(float) => Some(*float),
_ => None, _ => None,
} }
} }
#[must_use]
pub fn extract_double(&self) -> Option<f64> { pub fn extract_double(&self) -> Option<f64> {
match self { match self {
NbtTag::Double(double) => Some(*double), Self::Double(double) => Some(*double),
_ => None, _ => None,
} }
} }
#[must_use]
pub fn extract_bool(&self) -> Option<bool> { pub fn extract_bool(&self) -> Option<bool> {
match self { match self {
NbtTag::Byte(byte) => Some(byte != &0), Self::Byte(byte) => Some(byte != &0),
_ => None, _ => None,
} }
} }
#[must_use]
pub fn extract_byte_array(&self) -> Option<&[u8]> { pub fn extract_byte_array(&self) -> Option<&[u8]> {
match self { match self {
NbtTag::ByteArray(byte_array) => Some(byte_array), Self::ByteArray(byte_array) => Some(byte_array),
_ => None, _ => None,
} }
} }
#[must_use]
pub fn extract_string(&self) -> Option<&str> { pub fn extract_string(&self) -> Option<&str> {
match self { match self {
NbtTag::String(string) => Some(string), Self::String(string) => Some(string),
_ => None, _ => None,
} }
} }
pub fn extract_list(&self) -> Option<&[NbtTag]> { #[must_use]
pub fn extract_list(&self) -> Option<&[Self]> {
match self { match self {
NbtTag::List(list) => Some(list), Self::List(list) => Some(list),
_ => None, _ => None,
} }
} }
#[must_use]
pub fn extract_compound(&self) -> Option<&NbtCompound> { pub fn extract_compound(&self) -> Option<&NbtCompound> {
match self { match self {
NbtTag::Compound(compound) => Some(compound), Self::Compound(compound) => Some(compound),
_ => None, _ => None,
} }
} }
#[must_use]
pub fn extract_int_array(&self) -> Option<&[i32]> { pub fn extract_int_array(&self) -> Option<&[i32]> {
match self { match self {
NbtTag::IntArray(int_array) => Some(int_array), Self::IntArray(int_array) => Some(int_array),
_ => None, _ => None,
} }
} }
#[must_use]
pub fn extract_long_array(&self) -> Option<&[i64]> { pub fn extract_long_array(&self) -> Option<&[i64]> {
match self { match self {
NbtTag::LongArray(long_array) => Some(long_array), Self::LongArray(long_array) => Some(long_array),
_ => None, _ => None,
} }
} }
@ -357,7 +373,7 @@ impl NbtTag {
impl From<&str> for NbtTag { impl From<&str> for NbtTag {
fn from(value: &str) -> Self { fn from(value: &str) -> Self {
NbtTag::String(value.to_string()) Self::String(value.to_string())
} }
} }
@ -365,51 +381,51 @@ impl From<&[u8]> for NbtTag {
fn from(value: &[u8]) -> Self { fn from(value: &[u8]) -> Self {
let mut cloned = Vec::with_capacity(value.len()); let mut cloned = Vec::with_capacity(value.len());
cloned.copy_from_slice(value); cloned.copy_from_slice(value);
NbtTag::ByteArray(cloned.into_boxed_slice()) Self::ByteArray(cloned.into_boxed_slice())
} }
} }
impl From<f32> for NbtTag { impl From<f32> for NbtTag {
fn from(value: f32) -> Self { fn from(value: f32) -> Self {
NbtTag::Float(value) Self::Float(value)
} }
} }
impl From<f64> for NbtTag { impl From<f64> for NbtTag {
fn from(value: f64) -> Self { fn from(value: f64) -> Self {
NbtTag::Double(value) Self::Double(value)
} }
} }
impl From<bool> for NbtTag { impl From<bool> for NbtTag {
fn from(value: bool) -> Self { fn from(value: bool) -> Self {
NbtTag::Byte(value as i8) Self::Byte(i8::from(value))
} }
} }
impl Serialize for NbtTag { impl Serialize for NbtTag {
fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> { fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
match self { match self {
NbtTag::End => serializer.serialize_unit(), Self::End => serializer.serialize_unit(),
NbtTag::Byte(v) => serializer.serialize_i8(*v), Self::Byte(v) => serializer.serialize_i8(*v),
NbtTag::Short(v) => serializer.serialize_i16(*v), Self::Short(v) => serializer.serialize_i16(*v),
NbtTag::Int(v) => serializer.serialize_i32(*v), Self::Int(v) => serializer.serialize_i32(*v),
NbtTag::Long(v) => serializer.serialize_i64(*v), Self::Long(v) => serializer.serialize_i64(*v),
NbtTag::Float(v) => serializer.serialize_f32(*v), Self::Float(v) => serializer.serialize_f32(*v),
NbtTag::Double(v) => serializer.serialize_f64(*v), Self::Double(v) => serializer.serialize_f64(*v),
NbtTag::ByteArray(v) => nbt_byte_array(v, serializer), Self::ByteArray(v) => nbt_byte_array(v, serializer),
NbtTag::String(v) => serializer.serialize_str(v), Self::String(v) => serializer.serialize_str(v),
NbtTag::List(v) => { Self::List(v) => {
use serde::ser::SerializeSeq; use serde::ser::SerializeSeq;
let mut seq = serializer.serialize_seq(Some(v.len()))?; let mut seq = serializer.serialize_seq(Some(v.len()))?;
for item in v.iter() { for item in v {
seq.serialize_element(item)?; seq.serialize_element(item)?;
} }
seq.end() seq.end()
} }
NbtTag::Compound(v) => v.serialize(serializer), Self::Compound(v) => v.serialize(serializer),
NbtTag::IntArray(v) => nbt_int_array(v, serializer), Self::IntArray(v) => nbt_int_array(v, serializer),
NbtTag::LongArray(v) => nbt_long_array(v, serializer), Self::LongArray(v) => nbt_long_array(v, serializer),
} }
} }
} }
@ -426,7 +442,7 @@ impl<'de> Deserialize<'de> for NbtTag {
} }
fn visit_bool<E>(self, v: bool) -> Result<Self::Value, E> { fn visit_bool<E>(self, v: bool) -> Result<Self::Value, E> {
Ok(NbtTag::Byte(v as i8)) Ok(NbtTag::Byte(i8::from(v)))
} }
fn visit_i8<E>(self, v: i8) -> Result<Self::Value, E> { fn visit_i8<E>(self, v: i8) -> Result<Self::Value, E> {
@ -493,8 +509,7 @@ impl<'de> Deserialize<'de> for NbtTag {
Ok(NbtTag::List(vec)) Ok(NbtTag::List(vec))
} }
_ => Err(serde::de::Error::custom(format!( _ => Err(serde::de::Error::custom(format!(
"Invalid list type id: {}", "Invalid list type id: {curr}"
curr
))), ))),
} }
} }

View File

@ -36,3 +36,6 @@ bitflags.workspace = true
[dev-dependencies] [dev-dependencies]
# Validate correctness # Validate correctness
flate2.workspace = true flate2.workspace = true
[lints]
workspace = true

View File

@ -15,6 +15,7 @@ pub struct Ack {
} }
impl Ack { impl Ack {
#[must_use]
pub fn new(sequences: Vec<u32>) -> Self { pub fn new(sequences: Vec<u32>) -> Self {
Self { sequences } Self { sequences }
} }
@ -65,14 +66,12 @@ impl Ack {
let mut start = self.sequences[0]; let mut start = self.sequences[0];
let mut end = start; let mut end = start;
for seq in self.sequences.iter().copied() { for seq in self.sequences.iter().copied() {
if seq == end + 1 { if seq != end + 1 {
end = seq
} else {
Self::write_range(start, end, &mut buf)?; Self::write_range(start, end, &mut buf)?;
count += 1; count += 1;
start = seq; start = seq;
end = seq;
} }
end = seq;
} }
Self::write_range(start, end, &mut buf)?; Self::write_range(start, end, &mut buf)?;
count += 1; count += 1;

View File

@ -13,6 +13,7 @@ pub struct CDisconnectPlayer {
} }
impl CDisconnectPlayer { impl CDisconnectPlayer {
#[must_use]
pub fn new(reason: i32, message: String) -> Self { pub fn new(reason: i32, message: String) -> Self {
Self { Self {
reason: VarInt(reason), reason: VarInt(reason),

View File

@ -8,6 +8,7 @@ pub struct CHandshake {
} }
impl CHandshake { impl CHandshake {
#[must_use]
pub fn new(jwt_data: String) -> Self { pub fn new(jwt_data: String) -> Self {
Self { jwt_data } Self { jwt_data }
} }

View File

@ -13,6 +13,6 @@ pub struct CInventoryContent {
pub slots: Vec<NetworkItemStackDescriptor>, pub slots: Vec<NetworkItemStackDescriptor>,
pub container_name: u8, pub container_name: u8,
pub dynamic_id: Option<u32>, pub dynamic_id: Option<u32>,
/// Use NetworkItemDescriptor if none /// Use `NetworkItemDescriptor` if none
pub storage_item: NetworkItemStackDescriptor, pub storage_item: NetworkItemStackDescriptor,
} }

View File

@ -20,7 +20,7 @@ pub struct CLevelChunk<'a> {
pub chunk: &'a ChunkData, pub chunk: &'a ChunkData,
} }
impl<'a> PacketWrite for CLevelChunk<'a> { impl PacketWrite for CLevelChunk<'_> {
fn write<W: Write>(&self, writer: &mut W) -> Result<(), Error> { fn write<W: Write>(&self, writer: &mut W) -> Result<(), Error> {
VarInt(self.chunk.x).write(writer)?; VarInt(self.chunk.x).write(writer)?;
VarInt(self.chunk.z).write(writer)?; VarInt(self.chunk.z).write(writer)?;
@ -52,12 +52,12 @@ impl<'a> PacketWrite for CLevelChunk<'a> {
match network_repr.palette { match network_repr.palette {
NetworkPalette::Single(id) => { NetworkPalette::Single(id) => {
VarInt(id as i32).write(data_write)?; VarInt(i32::from(id)).write(data_write)?;
} }
NetworkPalette::Indirect(palette) => { NetworkPalette::Indirect(palette) => {
VarInt(palette.len() as i32).write(data_write)?; VarInt(palette.len() as i32).write(data_write)?;
for id in palette { for id in palette {
VarInt(id as i32).write(data_write)?; VarInt(i32::from(id)).write(data_write)?;
} }
} }
NetworkPalette::Direct => (), NetworkPalette::Direct => (),

View File

@ -19,6 +19,7 @@ pub struct CNetworkChunkPublisherUpdate {
} }
impl CNetworkChunkPublisherUpdate { impl CNetworkChunkPublisherUpdate {
#[must_use]
pub fn new(pos_for_view: BlockPos, new_radius: u32) -> Self { pub fn new(pos_for_view: BlockPos, new_radius: u32) -> Self {
Self { Self {
pos_for_view: NetworkPos(pos_for_view), pos_for_view: NetworkPos(pos_for_view),

View File

@ -13,6 +13,7 @@ pub struct CNetworkSettings {
} }
impl CNetworkSettings { impl CNetworkSettings {
#[must_use]
pub fn new( pub fn new(
compression_threshold: u16, compression_threshold: u16,
compression_method: u16, compression_method: u16,

View File

@ -6,16 +6,15 @@ use crate::serial::PacketWrite;
#[derive(PacketWrite)] #[derive(PacketWrite)]
#[packet(0x03)] #[packet(0x03)]
pub struct CConnectedPong { pub struct CConnectedPong {
ping_time: u64, ping: u64,
pong_time: u64, pong: u64,
} }
impl CConnectedPong { impl CConnectedPong {
pub fn new(ping_time: u64, pong_time: u64) -> Self { #[must_use]
Self { #[expect(clippy::similar_names)]
ping_time, pub fn new(ping: u64, pong: u64) -> Self {
pong_time, Self { ping, pong }
}
} }
} }
@ -30,6 +29,7 @@ pub struct CConnectionRequestAccepted {
} }
impl CConnectionRequestAccepted { impl CConnectionRequestAccepted {
#[must_use]
pub fn new( pub fn new(
client_address: SocketAddr, client_address: SocketAddr,
system_index: u16, system_index: u16,

View File

@ -16,6 +16,7 @@ pub struct COpenConnectionReply1 {
} }
impl COpenConnectionReply1 { impl COpenConnectionReply1 {
#[must_use]
pub fn new(server_guid: u64, has_server_security: bool, mtu: u16) -> Self { pub fn new(server_guid: u64, has_server_security: bool, mtu: u16) -> Self {
Self { Self {
magic: RAKNET_MAGIC, magic: RAKNET_MAGIC,
@ -38,6 +39,7 @@ pub struct COpenConnectionReply2 {
} }
impl COpenConnectionReply2 { impl COpenConnectionReply2 {
#[must_use]
pub fn new(server_guid: u64, client_address: SocketAddr, mtu: u16, security: bool) -> Self { pub fn new(server_guid: u64, client_address: SocketAddr, mtu: u16, security: bool) -> Self {
Self { Self {
magic: RAKNET_MAGIC, magic: RAKNET_MAGIC,

View File

@ -61,6 +61,7 @@ impl fmt::Display for ServerInfo {
} }
impl CUnconnectedPong { impl CUnconnectedPong {
#[must_use]
pub fn new(time: u64, server_guid: u64, magic: [u8; 16], server_id: String) -> Self { pub fn new(time: u64, server_guid: u64, magic: [u8; 16], server_id: String) -> Self {
Self { Self {
time, time,

View File

@ -17,6 +17,7 @@ pub struct CResourcePackStackPacket {
} }
impl CResourcePackStackPacket { impl CResourcePackStackPacket {
#[must_use]
pub fn new( pub fn new(
resource_pack_required: bool, resource_pack_required: bool,
texture_pack_list_size: VarUInt, texture_pack_list_size: VarUInt,

View File

@ -15,6 +15,8 @@ pub struct CResourcePacksInfo {
} }
impl CResourcePacksInfo { impl CResourcePacksInfo {
#[must_use]
#[expect(clippy::fn_params_excessive_bools)]
pub fn new( pub fn new(
resource_pack_required: bool, resource_pack_required: bool,
has_addon_packs: bool, has_addon_packs: bool,

View File

@ -71,6 +71,7 @@ pub enum MetadataValue {
} }
impl MetadataValue { impl MetadataValue {
#[must_use]
pub fn type_id(&self) -> u32 { pub fn type_id(&self) -> u32 {
match self { match self {
Self::Byte(_) => 0, Self::Byte(_) => 0,

View File

@ -9,6 +9,7 @@ pub struct CSetTime {
} }
impl CSetTime { impl CSetTime {
#[must_use]
pub const fn new(time: i32) -> Self { pub const fn new(time: i32) -> Self {
Self { time: VarInt(time) } Self { time: VarInt(time) }
} }

View File

@ -51,6 +51,7 @@ pub struct Frame {
} }
impl Frame { impl Frame {
#[must_use]
pub fn new_unreliable(payload: Vec<u8>) -> Self { pub fn new_unreliable(payload: Vec<u8>) -> Self {
Self { Self {
reliability: RakReliability::Unreliable, reliability: RakReliability::Unreliable,
@ -71,19 +72,18 @@ impl Frame {
while let Ok(header) = u8::read(reader) { while let Ok(header) = u8::read(reader) {
let mut frame = Self::default(); let mut frame = Self::default();
let reliability_id = (header & 0xE0) >> 5; let reliability_id = (header & 0xE0) >> 5;
let reliability = match RakReliability::from_id(reliability_id) { let Some(reliability) = RakReliability::from_id(reliability_id) else {
Some(reliability) => reliability, return Err(Error::other("Invalid reliability"));
None => return Err(Error::other("Invalid reliability")),
}; };
let split = (header & RAKNET_SPLIT) != 0; let split = (header & RAKNET_SPLIT) != 0;
let length = u16::read_be(reader)? >> 3; let length = u16::read_be(reader)? >> 3;
if reliability.is_reliable() { if reliability.is_reliable() {
frame.reliable_number = u24::read(reader)?.0 frame.reliable_number = u24::read(reader)?.0;
} }
if reliability.is_sequenced() { if reliability.is_sequenced() {
frame.sequence_index = u24::read(reader)?.0 frame.sequence_index = u24::read(reader)?.0;
} }
if reliability.is_ordered() { if reliability.is_ordered() {

View File

@ -35,65 +35,68 @@ pub enum RakReliability {
} }
impl RakReliability { impl RakReliability {
#[must_use]
pub fn is_reliable(&self) -> bool { pub fn is_reliable(&self) -> bool {
matches!( matches!(
self, self,
RakReliability::Reliable Self::Reliable
| RakReliability::ReliableOrdered | Self::ReliableOrdered
| RakReliability::ReliableSequenced | Self::ReliableSequenced
| RakReliability::ReliableWithAckReceipt | Self::ReliableWithAckReceipt
| RakReliability::ReliableOrderedWithAckReceipt | Self::ReliableOrderedWithAckReceipt
) )
} }
#[must_use]
pub fn is_sequenced(&self) -> bool { pub fn is_sequenced(&self) -> bool {
matches!( matches!(self, Self::ReliableSequenced | Self::UnreliableSequenced)
self,
RakReliability::ReliableSequenced | RakReliability::UnreliableSequenced
)
} }
#[must_use]
pub fn is_ordered(&self) -> bool { pub fn is_ordered(&self) -> bool {
matches!( matches!(
self, self,
RakReliability::UnreliableSequenced Self::UnreliableSequenced
| RakReliability::ReliableOrdered | Self::ReliableOrdered
| RakReliability::ReliableSequenced | Self::ReliableSequenced
| RakReliability::ReliableOrderedWithAckReceipt | Self::ReliableOrderedWithAckReceipt
) )
} }
#[must_use]
pub fn is_order_exclusive(&self) -> bool { pub fn is_order_exclusive(&self) -> bool {
matches!( matches!(
self, self,
RakReliability::ReliableOrdered | RakReliability::ReliableOrderedWithAckReceipt Self::ReliableOrdered | Self::ReliableOrderedWithAckReceipt
) )
} }
#[must_use]
pub fn from_id(id: u8) -> Option<Self> { pub fn from_id(id: u8) -> Option<Self> {
match id { match id {
0 => Some(RakReliability::Unreliable), 0 => Some(Self::Unreliable),
1 => Some(RakReliability::UnreliableSequenced), 1 => Some(Self::UnreliableSequenced),
2 => Some(RakReliability::Reliable), 2 => Some(Self::Reliable),
3 => Some(RakReliability::ReliableOrdered), 3 => Some(Self::ReliableOrdered),
4 => Some(RakReliability::ReliableSequenced), 4 => Some(Self::ReliableSequenced),
5 => Some(RakReliability::UnreliableWithAckReceipt), 5 => Some(Self::UnreliableWithAckReceipt),
6 => Some(RakReliability::ReliableWithAckReceipt), 6 => Some(Self::ReliableWithAckReceipt),
7 => Some(RakReliability::ReliableOrderedWithAckReceipt), 7 => Some(Self::ReliableOrderedWithAckReceipt),
_ => None, _ => None,
} }
} }
#[must_use]
pub fn to_id(&self) -> u8 { pub fn to_id(&self) -> u8 {
match self { match self {
RakReliability::Unreliable => 0, Self::Unreliable => 0,
RakReliability::UnreliableSequenced => 1, Self::UnreliableSequenced => 1,
RakReliability::Reliable => 2, Self::Reliable => 2,
RakReliability::ReliableOrdered => 3, Self::ReliableOrdered => 3,
RakReliability::ReliableSequenced => 4, Self::ReliableSequenced => 4,
RakReliability::UnreliableWithAckReceipt => 5, Self::UnreliableWithAckReceipt => 5,
RakReliability::ReliableWithAckReceipt => 6, Self::ReliableWithAckReceipt => 6,
RakReliability::ReliableOrderedWithAckReceipt => 7, Self::ReliableOrderedWithAckReceipt => 7,
} }
} }
} }

View File

@ -46,10 +46,11 @@ pub enum DecryptionReader<R: AsyncRead + Unpin> {
} }
impl<R: AsyncRead + Unpin> DecryptionReader<R> { impl<R: AsyncRead + Unpin> DecryptionReader<R> {
#[must_use]
pub fn upgrade(self, cipher: Aes128Cfb8Dec) -> Self { pub fn upgrade(self, cipher: Aes128Cfb8Dec) -> Self {
match self { match self {
Self::None(stream) => Self::Decrypt(Box::new(StreamDecryptor::new(cipher, stream))), Self::None(stream) => Self::Decrypt(Box::new(StreamDecryptor::new(cipher, stream))),
_ => panic!("Cannot upgrade a stream that already has a cipher!"), Self::Decrypt(_) => panic!("Cannot upgrade a stream that already has a cipher!"),
} }
} }
} }
@ -75,7 +76,7 @@ impl<R: AsyncRead + Unpin> AsyncRead for DecryptionReader<R> {
} }
/// Decoder: Client -> Server /// Decoder: Client -> Server
/// Supports ZLib decoding/decompression /// Supports `ZLib` decoding/decompression
/// Supports Aes128 Encryption /// Supports Aes128 Encryption
pub struct UDPNetworkDecoder { pub struct UDPNetworkDecoder {
compression: Option<CompressionThreshold>, compression: Option<CompressionThreshold>,
@ -88,6 +89,7 @@ impl Default for UDPNetworkDecoder {
} }
impl UDPNetworkDecoder { impl UDPNetworkDecoder {
#[must_use]
pub fn new() -> Self { pub fn new() -> Self {
Self { compression: None } Self { compression: None }
} }
@ -105,6 +107,7 @@ impl UDPNetworkDecoder {
// take_mut::take(&mut self.reader, |decoder| decoder.upgrade(cipher)); // take_mut::take(&mut self.reader, |decoder| decoder.upgrade(cipher));
} }
#[expect(clippy::unused_async)]
pub async fn get_packet_payload( pub async fn get_packet_payload(
&mut self, &mut self,
reader: Cursor<Vec<u8>>, reader: Cursor<Vec<u8>>,
@ -118,7 +121,7 @@ impl UDPNetworkDecoder {
Ok(reader.into_inner().into()) Ok(reader.into_inner().into())
} }
pub async fn get_game_packet( pub fn get_game_packet(
&mut self, &mut self,
mut reader: Cursor<Vec<u8>>, mut reader: Cursor<Vec<u8>>,
) -> Result<RawPacket, PacketDecodeError> { ) -> Result<RawPacket, PacketDecodeError> {
@ -134,7 +137,7 @@ impl UDPNetworkDecoder {
err => PacketDecodeError::MalformedLength(err.to_string()), err => PacketDecodeError::MalformedLength(err.to_string()),
})?; })?;
let packet_len = packet_len.0 as u64; let packet_len = u64::from(packet_len.0);
let var_header = VarUInt::decode(&mut reader)?; let var_header = VarUInt::decode(&mut reader)?;
@ -148,10 +151,10 @@ impl UDPNetworkDecoder {
// SubClient Target ID (2 bits) // SubClient Target ID (2 bits)
// SubClient Target ID: Lowest 2 bits // SubClient Target ID: Lowest 2 bits
let _sub_client_target = (header >> 10 & 0b11) as u8; // let _sub_client_target = (header >> 10 & 0b11) as u8;
// SubClient Sender ID: Next 2 bits (bits 2 and 3) // SubClient Sender ID: Next 2 bits (bits 2 and 3)
let _sub_client_sender = (header >> 12 & 0b11) as u8; // let _sub_client_sender = (header >> 12 & 0b11) as u8;
// Gamepacket ID: Remaining 10 bits (bits 4 to 13) // Gamepacket ID: Remaining 10 bits (bits 4 to 13)
let gamepacket_id = (header & 0x3FF) as u16; // 0x3FF is 10 bits set to 1 let gamepacket_id = (header & 0x3FF) as u16; // 0x3FF is 10 bits set to 1
@ -161,7 +164,7 @@ impl UDPNetworkDecoder {
.map_err(|err| PacketDecodeError::FailedDecompression(err.to_string()))?; .map_err(|err| PacketDecodeError::FailedDecompression(err.to_string()))?;
Ok(RawPacket { Ok(RawPacket {
id: gamepacket_id as i32, id: i32::from(gamepacket_id),
payload: payload.into(), payload: payload.into(),
}) })
} }

View File

@ -5,7 +5,6 @@ use std::{
task::{Context, Poll}, task::{Context, Poll},
}; };
use bytes::Bytes;
use thiserror::Error; use thiserror::Error;
use tokio::{io::AsyncWrite, net::UdpSocket}; use tokio::{io::AsyncWrite, net::UdpSocket};
@ -22,10 +21,11 @@ pub enum EncryptionWriter<W: AsyncWrite + Unpin> {
} }
impl<W: AsyncWrite + Unpin> EncryptionWriter<W> { impl<W: AsyncWrite + Unpin> EncryptionWriter<W> {
#[must_use]
pub fn upgrade(self, cipher: Aes128Cfb8Enc) -> Self { pub fn upgrade(self, cipher: Aes128Cfb8Enc) -> Self {
match self { match self {
Self::None(stream) => Self::Encrypt(Box::new(StreamEncryptor::new(cipher, stream))), Self::None(stream) => Self::Encrypt(Box::new(StreamEncryptor::new(cipher, stream))),
_ => panic!("Cannot upgrade a stream that already has a cipher!"), Self::Encrypt(_) => panic!("Cannot upgrade a stream that already has a cipher!"),
} }
} }
} }
@ -76,7 +76,7 @@ impl<W: AsyncWrite + Unpin> AsyncWrite for EncryptionWriter<W> {
} }
/// Encoder: Server -> Client /// Encoder: Server -> Client
/// Supports ZLib endecoding/compression /// Supports `ZLib` endecoding/compression
/// Supports Aes128 Encryption /// Supports Aes128 Encryption
pub struct UDPNetworkEncoder { pub struct UDPNetworkEncoder {
// compression and compression threshold // compression and compression threshold
@ -90,6 +90,7 @@ impl Default for UDPNetworkEncoder {
} }
impl UDPNetworkEncoder { impl UDPNetworkEncoder {
#[must_use]
pub fn new() -> Self { pub fn new() -> Self {
Self { compression: None } Self { compression: None }
} }
@ -107,12 +108,12 @@ impl UDPNetworkEncoder {
// take_mut::take(&mut self.writer, |encoder| encoder.upgrade(cipher)); // take_mut::take(&mut self.writer, |encoder| encoder.upgrade(cipher));
} }
pub async fn write_game_packet( pub fn write_game_packet(
&mut self, &mut self,
packet_id: u16, packet_id: u16,
sub_client_sender: SubClient, sub_client_sender: SubClient,
sub_client_target: SubClient, sub_client_target: SubClient,
packet_payload: Bytes, packet_payload: &[u8],
mut writer: impl Write, mut writer: impl Write,
) -> Result<(), Error> { ) -> Result<(), Error> {
// Game Packet ID // Game Packet ID
@ -128,7 +129,7 @@ impl UDPNetworkEncoder {
// Gamepacket ID (10 bits) << 4 (offset by 2 bits for target + 2 bits for sender) // Gamepacket ID (10 bits) << 4 (offset by 2 bits for target + 2 bits for sender)
// SubClient Sender ID (2 bits) << 2 (offset by 2 bits for target) // SubClient Sender ID (2 bits) << 2 (offset by 2 bits for target)
// SubClient Target ID (2 bits) // SubClient Target ID (2 bits)
let header_value: u32 = packet_id as u32 let header_value: u32 = u32::from(packet_id)
| ((sub_client_sender as u32) << 10) | ((sub_client_sender as u32) << 10)
| ((sub_client_target as u32) << 12); | ((sub_client_target as u32) << 12);
@ -158,7 +159,7 @@ impl UDPNetworkEncoder {
.unwrap(); .unwrap();
// 5. Write the payload // 5. Write the payload
writer.write_all(&packet_payload) writer.write_all(packet_payload)
} }
pub async fn write_packet( pub async fn write_packet(

View File

@ -13,6 +13,7 @@ pub struct SLoadingScreen {
} }
impl SLoadingScreen { impl SLoadingScreen {
#[must_use]
pub fn is_loading_done(&self) -> bool { pub fn is_loading_done(&self) -> bool {
self.status.0 == 2 self.status.0 == 2
} }

View File

@ -19,6 +19,7 @@ pub struct SText {
} }
impl SText { impl SText {
#[must_use]
pub fn new(message: String, source_name: String) -> Self { pub fn new(message: String, source_name: String) -> Self {
Self { Self {
needs_translation: false, needs_translation: false,
@ -36,6 +37,7 @@ impl SText {
} }
} }
#[must_use]
pub fn system_message(message: String) -> Self { pub fn system_message(message: String) -> Self {
Self { Self {
needs_translation: false, needs_translation: false,
@ -97,10 +99,7 @@ impl PacketRead for SText {
if actual != expected { if actual != expected {
return Err(Error::new( return Err(Error::new(
ErrorKind::InvalidData, ErrorKind::InvalidData,
format!( format!("Dummy string mismatch: expected {expected}, got {actual}"),
"Dummy string mismatch: expected {}, got {}",
expected, actual
),
)); ));
} }
} }

View File

@ -10,7 +10,7 @@ use crate::{
/// A wrapper for `BlockPos` that handles Bedrock-specific network serialization. /// A wrapper for `BlockPos` that handles Bedrock-specific network serialization.
/// ///
/// Bedrock Edition encodes coordinates differently than Java Edition, using /// Bedrock Edition encodes coordinates differently than Java Edition, using
/// VarInt's to save bandwidth. /// `VarInt`'s to save bandwidth.
pub struct NetworkPos(pub BlockPos); pub struct NetworkPos(pub BlockPos);
impl NetworkPos { impl NetworkPos {

View File

@ -31,7 +31,7 @@ impl BitSet {
let long = read.get_i64_be()?; let long = read.get_i64_be()?;
array.push(long); array.push(long);
} }
Ok(BitSet(array.into_boxed_slice())) Ok(Self(array.into_boxed_slice()))
} }
} }

View File

@ -10,17 +10,13 @@ pub struct Bitset<const N: usize> {
impl<const N: usize> Bitset<N> { impl<const N: usize> Bitset<N> {
pub fn get<T: Into<usize>>(&self, index: T) -> bool { pub fn get<T: Into<usize>>(&self, index: T) -> bool {
let index: usize = index.into(); let index: usize = index.into();
if index > N { assert!(index <= N, "");
panic!("")
}
(self.bits & (1 << index)) != 0 (self.bits & (1 << index)) != 0
} }
pub fn set<T: Into<usize>>(&mut self, index: T, value: bool) { pub fn set<T: Into<usize>>(&mut self, index: T, value: bool) {
let index: usize = index.into(); let index: usize = index.into();
if index > N { assert!(index <= N, "");
panic!("")
}
if value { if value {
self.bits |= 1 << index; self.bits |= 1 << index;
} else { } else {
@ -31,16 +27,14 @@ impl<const N: usize> Bitset<N> {
impl<const N: usize> Default for Bitset<N> { impl<const N: usize> Default for Bitset<N> {
fn default() -> Self { fn default() -> Self {
if N > 80 { assert!(N <= 80,);
panic!()
}
Self { bits: 0 } Self { bits: 0 }
} }
} }
impl<const N: usize> PacketRead for Bitset<N> { impl<const N: usize> PacketRead for Bitset<N> {
fn read<R: Read>(reader: &mut R) -> Result<Self, Error> { fn read<R: Read>(reader: &mut R) -> Result<Self, Error> {
let mut bitset = Bitset::<N>::default(); let mut bitset = Self::default();
for i in 0..N.div_ceil(8) { for i in 0..N.div_ceil(8) {
let byte = u8::read(reader)?; let byte = u8::read(reader)?;

View File

@ -71,7 +71,7 @@ impl DataComponentCodec<Self> for EnchantmentsImpl {
"EnchantmentsImpl Enchantment VarInt Incorrect!", "EnchantmentsImpl Enchantment VarInt Incorrect!",
))?, ))?,
level, level,
)) ));
} }
Ok(Self { Ok(Self {
enchantment: Cow::from(enc), enchantment: Cow::from(enc),

View File

@ -57,7 +57,7 @@ impl<'de> Deserialize<'de> for ItemStackSerializer<'static> {
let _byte_len = seq let _byte_len = seq
.next_element::<VarInt>()? .next_element::<VarInt>()?
.ok_or(de::Error::custom("No data len VarInt!"))?; .ok_or(de::Error::custom("No data len VarInt!"))?;
patch.push((id, Some(deserialize(id, &mut seq)?))) patch.push((id, Some(deserialize(id, &mut seq)?)));
} }
for _ in 0..num_components_to_remove { for _ in 0..num_components_to_remove {
let id = seq let id = seq
@ -68,7 +68,7 @@ impl<'de> Deserialize<'de> for ItemStackSerializer<'static> {
.map_err(|_| de::Error::custom("Unknown component id VarInt!"))?; .map_err(|_| de::Error::custom("Unknown component id VarInt!"))?;
let id = DataComponent::try_from_id(id) let id = DataComponent::try_from_id(id)
.ok_or(de::Error::custom("Unknown component id VarInt!"))?; .ok_or(de::Error::custom("Unknown component id VarInt!"))?;
patch.push((id, None)) patch.push((id, None));
} }
let item_id: u16 = item_id let item_id: u16 = item_id
@ -131,6 +131,7 @@ impl Serialize for ItemStackSerializer<'_> {
} }
impl ItemStackSerializer<'_> { impl ItemStackSerializer<'_> {
#[must_use]
pub fn to_stack(self) -> ItemStack { pub fn to_stack(self) -> ItemStack {
self.0.into_owned() self.0.into_owned()
} }
@ -144,10 +145,10 @@ impl From<ItemStack> for ItemStackSerializer<'_> {
impl From<Option<ItemStack>> for ItemStackSerializer<'_> { impl From<Option<ItemStack>> for ItemStackSerializer<'_> {
fn from(item: Option<ItemStack>) -> Self { fn from(item: Option<ItemStack>) -> Self {
match item { item.map_or_else(
Some(item) => ItemStackSerializer::from(item), || ItemStackSerializer(Cow::Borrowed(ItemStack::EMPTY)),
None => ItemStackSerializer(Cow::Borrowed(ItemStack::EMPTY)), ItemStackSerializer::from,
} )
} }
} }
@ -165,6 +166,7 @@ pub struct ItemStackHash {
} }
impl OptionalItemStackHash { impl OptionalItemStackHash {
#[must_use]
pub fn hash_equals(&self, other: &ItemStack) -> bool { pub fn hash_equals(&self, other: &ItemStack) -> bool {
if let Some(hash) = &self.0 { if let Some(hash) = &self.0 {
if hash.item_id != other.item.id.into() || hash.count != other.item_count.into() { if hash.item_id != other.item.id.into() || hash.count != other.item_count.into() {
@ -193,11 +195,10 @@ impl OptionalItemStackHash {
let checksum = data.get_hash(); let checksum = data.get_hash();
for (id, hash) in &hash.components.added { for (id, hash) in &hash.components.added {
if id == &VarInt::from(other_id.to_id()) { if id == &VarInt::from(other_id.to_id()) {
if hash != &checksum { if hash == &checksum {
return false;
} else {
break; break;
} }
return false;
} }
} }
} else if !hash } else if !hash

View File

@ -8,10 +8,7 @@ pub struct OptionalInt(pub Option<i32>);
impl Serialize for OptionalInt { impl Serialize for OptionalInt {
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> { fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
// Vanilla logic: empty is 0, otherwise value + 1 // Vanilla logic: empty is 0, otherwise value + 1
let val = match self.0 { let val = self.0.map_or(0, |id| id + 1);
None => 0,
Some(id) => id + 1,
};
VarInt(val).serialize(serializer) VarInt(val).serialize(serializer)
} }
} }

View File

@ -17,6 +17,6 @@ impl PacketRead for u24 {
fn read<R: Read>(reader: &mut R) -> Result<Self, Error> { fn read<R: Read>(reader: &mut R) -> Result<Self, Error> {
let mut buf = [0; 3]; let mut buf = [0; 3];
reader.read_exact(&mut buf)?; reader.read_exact(&mut buf)?;
Ok(u24(u32::from_le_bytes([buf[0], buf[1], buf[2], 0]))) Ok(Self(u32::from_le_bytes([buf[0], buf[1], buf[2], 0])))
} }
} }

View File

@ -28,8 +28,9 @@ impl VarInt {
/// The maximum number of bytes a `VarInt` can occupy. /// The maximum number of bytes a `VarInt` can occupy.
const MAX_SIZE: NonZeroUsize = NonZeroUsize::new(5).unwrap(); const MAX_SIZE: NonZeroUsize = NonZeroUsize::new(5).unwrap();
/// Returns the exact number of bytes this VarInt will write when /// Returns the exact number of bytes this `VarInt` will write when
/// [`Encode::encode`] is called, assuming no error occurs. /// [`Encode::encode`] is called, assuming no error occurs.
#[must_use]
pub fn written_size(&self) -> usize { pub fn written_size(&self) -> usize {
match self.0 { match self.0 {
0 => 1, 0 => 1,
@ -57,7 +58,7 @@ impl VarInt {
let byte = read.get_u8()?; let byte = read.get_u8()?;
val |= (i32::from(byte) & 0x7F) << (i * 7); val |= (i32::from(byte) & 0x7F) << (i * 7);
if byte & 0x80 == 0 { if byte & 0x80 == 0 {
return Ok(VarInt(val)); return Ok(Self(val));
} }
} }
Err(ReadingError::TooLarge("VarInt".to_string())) Err(ReadingError::TooLarge("VarInt".to_string()))
@ -77,7 +78,7 @@ impl VarInt {
})?; })?;
val |= (i32::from(byte) & 0x7F) << (i * 7); val |= (i32::from(byte) & 0x7F) << (i * 7);
if byte & 0x80 == 0 { if byte & 0x80 == 0 {
return Ok(VarInt(val)); return Ok(Self(val));
} }
} }
Err(ReadingError::TooLarge("VarInt".to_string())) Err(ReadingError::TooLarge("VarInt".to_string()))
@ -89,10 +90,10 @@ impl VarInt {
) -> Result<(), WritingError> { ) -> Result<(), WritingError> {
let mut val = self.0; let mut val = self.0;
for _ in 0..Self::MAX_SIZE.get() { for _ in 0..Self::MAX_SIZE.get() {
let b: u8 = val as u8 & 0b01111111; let b: u8 = val as u8 & 0b0111_1111;
val >>= 7; val >>= 7;
write write
.write_u8(if val == 0 { b } else { b | 0b10000000 }) .write_u8(if val == 0 { b } else { b | 0b1000_0000 })
.await .await
.map_err(WritingError::IoError)?; .map_err(WritingError::IoError)?;
if val == 0 { if val == 0 {
@ -183,8 +184,8 @@ impl<'de> Deserialize<'de> for VarInt {
let mut val = 0; let mut val = 0;
for i in 0..VarInt::MAX_SIZE.get() { for i in 0..VarInt::MAX_SIZE.get() {
if let Some(byte) = seq.next_element::<u8>()? { if let Some(byte) = seq.next_element::<u8>()? {
val |= (i32::from(byte) & 0b01111111) << (i * 7); val |= (i32::from(byte) & 0b0111_1111) << (i * 7);
if byte & 0b10000000 == 0 { if byte & 0b1000_0000 == 0 {
return Ok(VarInt(val)); return Ok(VarInt(val));
} }
} else { } else {
@ -220,7 +221,7 @@ impl PacketRead for VarInt {
let byte = u8::read(read)?; let byte = u8::read(read)?;
val |= (i32::from(byte) & 0x7F) << (i * 7); val |= (i32::from(byte) & 0x7F) << (i * 7);
if byte & 0x80 == 0 { if byte & 0x80 == 0 {
return Ok(VarInt((val >> 1) ^ (val << 31))); return Ok(Self((val >> 1) ^ (val << 31)));
} }
} }
Err(Error::new(ErrorKind::InvalidData, "")) Err(Error::new(ErrorKind::InvalidData, ""))

View File

@ -46,7 +46,7 @@ impl VarLong {
let byte = read.get_u8()?; let byte = read.get_u8()?;
val |= (i64::from(byte) & 0x7F) << (i * 7); val |= (i64::from(byte) & 0x7F) << (i * 7);
if byte & 0x80 == 0 { if byte & 0x80 == 0 {
return Ok(VarLong(val)); return Ok(Self(val));
} }
} }
Err(ReadingError::TooLarge("VarLong".to_string())) Err(ReadingError::TooLarge("VarLong".to_string()))
@ -55,25 +55,25 @@ impl VarLong {
impl From<i64> for VarLong { impl From<i64> for VarLong {
fn from(value: i64) -> Self { fn from(value: i64) -> Self {
VarLong(value) Self(value)
} }
} }
impl From<u32> for VarLong { impl From<u32> for VarLong {
fn from(value: u32) -> Self { fn from(value: u32) -> Self {
VarLong(value as i64) Self(i64::from(value))
} }
} }
impl From<u8> for VarLong { impl From<u8> for VarLong {
fn from(value: u8) -> Self { fn from(value: u8) -> Self {
VarLong(value as i64) Self(i64::from(value))
} }
} }
impl From<usize> for VarLong { impl From<usize> for VarLong {
fn from(value: usize) -> Self { fn from(value: usize) -> Self {
VarLong(value as i64) Self(value as i64)
} }
} }
@ -128,8 +128,8 @@ impl<'de> Deserialize<'de> for VarLong {
let mut val = 0; let mut val = 0;
for i in 0..VarLong::MAX_SIZE.get() { for i in 0..VarLong::MAX_SIZE.get() {
if let Some(byte) = seq.next_element::<u8>()? { if let Some(byte) = seq.next_element::<u8>()? {
val |= (i64::from(byte) & 0b01111111) << (i * 7); val |= (i64::from(byte) & 0b0111_1111) << (i * 7);
if byte & 0b10000000 == 0 { if byte & 0b1000_0000 == 0 {
return Ok(VarLong(val)); return Ok(VarLong(val));
} }
} else { } else {

View File

@ -27,8 +27,9 @@ impl VarUInt {
/// The maximum number of bytes a `VarUInt` can occupy. /// The maximum number of bytes a `VarUInt` can occupy.
const MAX_SIZE: NonZeroUsize = NonZeroUsize::new(5).unwrap(); const MAX_SIZE: NonZeroUsize = NonZeroUsize::new(5).unwrap();
/// Returns the exact number of bytes this VarUInt will write when /// Returns the exact number of bytes this `VarUInt` will write when
/// [`Encode::encode`] is called, assuming no error occurs. /// [`Encode::encode`] is called, assuming no error occurs.
#[must_use]
pub fn written_size(&self) -> usize { pub fn written_size(&self) -> usize {
(32 - self.0.leading_zeros() as usize).max(1).div_ceil(7) (32 - self.0.leading_zeros() as usize).max(1).div_ceil(7)
} }
@ -56,7 +57,7 @@ impl VarUInt {
let byte = read.get_u8()?; let byte = read.get_u8()?;
val |= (u32::from(byte) & 0x7F) << (i * 7); val |= (u32::from(byte) & 0x7F) << (i * 7);
if byte & 0x80 == 0 { if byte & 0x80 == 0 {
return Ok(VarUInt(val)); return Ok(Self(val));
} }
} }
Err(ReadingError::TooLarge("VarUInt".to_string())) Err(ReadingError::TooLarge("VarUInt".to_string()))
@ -76,7 +77,7 @@ impl VarUInt {
})?; })?;
val |= (u32::from(byte) & 0x7F) << (i * 7); val |= (u32::from(byte) & 0x7F) << (i * 7);
if byte & 0x80 == 0 { if byte & 0x80 == 0 {
return Ok(VarUInt(val)); return Ok(Self(val));
} }
} }
Err(ReadingError::TooLarge("VarUInt".to_string())) Err(ReadingError::TooLarge("VarUInt".to_string()))
@ -88,10 +89,10 @@ impl VarUInt {
) -> Result<(), WritingError> { ) -> Result<(), WritingError> {
let mut val = self.0; let mut val = self.0;
for _ in 0..Self::MAX_SIZE.get() { for _ in 0..Self::MAX_SIZE.get() {
let b: u8 = val as u8 & 0b01111111; let b: u8 = val as u8 & 0b0111_1111;
val >>= 7; val >>= 7;
write write
.write_u8(if val == 0 { b } else { b | 0b10000000 }) .write_u8(if val == 0 { b } else { b | 0b1000_0000 })
.await .await
.map_err(WritingError::IoError)?; .map_err(WritingError::IoError)?;
if val == 0 { if val == 0 {
@ -166,8 +167,8 @@ impl<'de> Deserialize<'de> for VarUInt {
let mut val = 0; let mut val = 0;
for i in 0..VarUInt::MAX_SIZE.get() { for i in 0..VarUInt::MAX_SIZE.get() {
if let Some(byte) = seq.next_element::<u8>()? { if let Some(byte) = seq.next_element::<u8>()? {
val |= (u32::from(byte) & 0b01111111) << (i * 7); val |= (u32::from(byte) & 0b0111_1111) << (i * 7);
if byte & 0b10000000 == 0 { if byte & 0b1000_0000 == 0 {
return Ok(VarUInt(val)); return Ok(VarUInt(val));
} }
} else { } else {
@ -207,7 +208,7 @@ impl PacketRead for VarUInt {
let byte = u8::read(reader)?; let byte = u8::read(reader)?;
val |= (u32::from(byte) & 0x7F) << (i * 7); val |= (u32::from(byte) & 0x7F) << (i * 7);
if byte & 0x80 == 0 { if byte & 0x80 == 0 {
return Ok(VarUInt(val)); return Ok(Self(val));
} }
} }
Err(Error::new(ErrorKind::InvalidData, "")) Err(Error::new(ErrorKind::InvalidData, ""))

View File

@ -27,8 +27,9 @@ impl VarULong {
/// The maximum number of bytes a `VarULong` can occupy. /// The maximum number of bytes a `VarULong` can occupy.
const MAX_SIZE: NonZeroUsize = NonZeroUsize::new(10).unwrap(); const MAX_SIZE: NonZeroUsize = NonZeroUsize::new(10).unwrap();
/// Returns the exact number of bytes this VarLong will write when /// Returns the exact number of bytes this `VarLong` will write when
/// [`Encode::encode`] is called, assuming no error occurs. /// [`Encode::encode`] is called, assuming no error occurs.
#[must_use]
pub fn written_size(&self) -> usize { pub fn written_size(&self) -> usize {
match self.0 { match self.0 {
0 => 1, 0 => 1,
@ -56,9 +57,9 @@ impl VarULong {
let mut val = 0; let mut val = 0;
for i in 0..Self::MAX_SIZE.get() { for i in 0..Self::MAX_SIZE.get() {
let byte = read.get_u8()?; let byte = read.get_u8()?;
val |= (u64::from(byte) & 0b01111111) << (i * 7); val |= (u64::from(byte) & 0b0111_1111) << (i * 7);
if byte & 0b10000000 == 0 { if byte & 0b1000_0000 == 0 {
return Ok(VarULong(val)); return Ok(Self(val));
} }
} }
Err(ReadingError::TooLarge("VarLong".to_string())) Err(ReadingError::TooLarge("VarLong".to_string()))
@ -67,25 +68,25 @@ impl VarULong {
impl From<u64> for VarULong { impl From<u64> for VarULong {
fn from(value: u64) -> Self { fn from(value: u64) -> Self {
VarULong(value) Self(value)
} }
} }
impl From<u32> for VarULong { impl From<u32> for VarULong {
fn from(value: u32) -> Self { fn from(value: u32) -> Self {
VarULong(value as u64) Self(u64::from(value))
} }
} }
impl From<u8> for VarULong { impl From<u8> for VarULong {
fn from(value: u8) -> Self { fn from(value: u8) -> Self {
VarULong(value as u64) Self(u64::from(value))
} }
} }
impl From<usize> for VarULong { impl From<usize> for VarULong {
fn from(value: usize) -> Self { fn from(value: usize) -> Self {
VarULong(value as u64) Self(value as u64)
} }
} }
@ -140,8 +141,8 @@ impl<'de> Deserialize<'de> for VarULong {
let mut val = 0; let mut val = 0;
for i in 0..VarULong::MAX_SIZE.get() { for i in 0..VarULong::MAX_SIZE.get() {
if let Some(byte) = seq.next_element::<u8>()? { if let Some(byte) = seq.next_element::<u8>()? {
val |= (u64::from(byte) & 0b01111111) << (i * 7); val |= (u64::from(byte) & 0b0111_1111) << (i * 7);
if byte & 0b10000000 == 0 { if byte & 0b1000_0000 == 0 {
return Ok(VarULong(val)); return Ok(VarULong(val));
} }
} else { } else {
@ -178,9 +179,9 @@ impl PacketRead for VarULong {
let mut val = 0; let mut val = 0;
for i in 0..Self::MAX_SIZE.get() { for i in 0..Self::MAX_SIZE.get() {
let byte = u8::read(reader)?; let byte = u8::read(reader)?;
val |= (u64::from(byte) & 0b01111111) << (i * 7); val |= (u64::from(byte) & 0b0111_1111) << (i * 7);
if byte & 0b10000000 == 0 { if byte & 0b1000_0000 == 0 {
return Ok(VarULong(val)); return Ok(Self(val));
} }
} }
Err(Error::other("Invalid VarUInt")) Err(Error::other("Invalid VarUInt"))

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