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",
]
[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]
version = "0.1.0-dev+1.21.11"
edition = "2024"
@ -108,7 +152,7 @@ take_mut = "0.2.2"
temp-dir = "0.1.16"
thread_local = "1.1.9"
time = "0.3"
arc-swap = "1.7"
arc-swap = "1.8"
tokio-util = "0.7.18"
toml = "0.9"
ureq = "3.1.4"

View File

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

View File

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

View File

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

View File

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

View File

@ -24,8 +24,8 @@ impl Default for AuthenticationConfig {
Self {
enabled: true,
prevent_proxy_connections: false,
player_profile: Default::default(),
textures: Default::default(),
player_profile: PlayerProfileConfig::default(),
textures: TextureConfig::default(),
url: None,
prevent_proxy_connection_auth_url: None,
services_url: None,
@ -75,7 +75,7 @@ impl Default for TextureConfig {
enabled: true,
allowed_url_schemes: vec!["http".into(), "https".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 {
Self {
enabled: true,
info: Default::default(),
info: CompressionInfo::default(),
}
}
}

View File

@ -13,7 +13,7 @@ impl Default for QueryConfig {
fn default() -> Self {
Self {
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 {
Self {
enabled: false,
address: SocketAddr::new(Ipv4Addr::new(0, 0, 0, 0).into(), 25575),
password: "".to_string(),
address: SocketAddr::new(Ipv4Addr::UNSPECIFIED.into(), 25575),
password: String::new(),
max_connections: 0,
logging: Default::default(),
logging: RCONLogging::default(),
}
}
}

View File

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

View File

@ -30,6 +30,6 @@ impl ResourcePackConfig {
assert!(
hash_len == 40,
"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 {
enabled: true,
bug_report: "https://github.com/Pumpkin-MC/Pumpkin/issues".to_string(),
support: "".to_string(),
status: "".to_string(),
feedback: "".to_string(),
community: "".to_string(),
website: "".to_string(),
forums: "".to_string(),
news: "".to_string(),
announcements: "".to_string(),
custom: Default::default(),
support: String::new(),
status: String::new(),
feedback: String::new(),
community: String::new(),
website: String::new(),
forums: String::new(),
news: String::new(),
announcements: String::new(),
custom: HashMap::default(),
}
}
}

View File

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

View File

@ -111,7 +111,7 @@ enum BiomeTree {
Branch {
parameters: [ParameterRange; 7],
#[serde(rename = "subTree")]
nodes: Box<[BiomeTree]>,
nodes: Box<[Self]>,
},
}
@ -126,7 +126,7 @@ impl BiomeTree {
.unwrap()
.to_shouty_snake_case()
);
let parameters = parameters.map(|range| range.into_token_stream());
let parameters = parameters.map(ParameterRange::into_token_stream);
quote! {
BiomeTree::Leaf {
parameters: [#(#parameters),*],
@ -137,9 +137,9 @@ impl BiomeTree {
Self::Branch { parameters, nodes } => {
let nodes = nodes
.into_iter()
.map(|node| node.into_token_stream())
.map(Self::into_token_stream)
.collect::<Vec<_>>();
let parameters = parameters.map(|range| range.into_token_stream());
let parameters = parameters.map(ParameterRange::into_token_stream);
quote! {
BiomeTree::Branch {
parameters: [#(#parameters),*],
@ -172,7 +172,7 @@ pub(crate) fn build() -> TokenStream {
let mut name_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 format_name = format_ident!("{}", name.to_shouty_snake_case());
let has_precipitation = biome.has_precipitation;
@ -190,44 +190,44 @@ pub(crate) fn build() -> TokenStream {
.spawners
.monster
.iter()
.map(|s| s.to_tokens())
.map(Spawner::to_tokens)
.collect();
let ambient: Vec<_> = biome
.spawners
.ambient
.iter()
.map(|s| s.to_tokens())
.map(Spawner::to_tokens)
.collect();
let axolotls: Vec<_> = biome
.spawners
.axolotls
.iter()
.map(|s| s.to_tokens())
.map(Spawner::to_tokens)
.collect();
let creature: Vec<_> = biome
.spawners
.creature
.iter()
.map(|s| s.to_tokens())
.map(Spawner::to_tokens)
.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
.spawners
.underground_water_creature
.iter()
.map(|s| s.to_tokens())
.map(Spawner::to_tokens)
.collect();
let water_ambient: Vec<_> = biome
.spawners
.water_ambient
.iter()
.map(|s| s.to_tokens())
.map(Spawner::to_tokens)
.collect();
let water_creature: Vec<_> = biome
.spawners
.water_creature
.iter()
.map(|s| s.to_tokens())
.map(Spawner::to_tokens)
.collect();
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];
for &id in ids {
let index = (id as usize) >> 6;
let bit = (id as u32) & 63;
let bit = u32::from(id) & 63;
bitset[index] |= 1u64 << bit;
}
let name_uppercase = name.to_uppercase();

View File

@ -418,11 +418,11 @@ pub enum PistonBehavior {
impl PistonBehavior {
fn to_tokens(&self) -> TokenStream {
match self {
PistonBehavior::Normal => quote! { PistonBehavior::Normal },
PistonBehavior::Destroy => quote! { PistonBehavior::Destroy },
PistonBehavior::Block => quote! { PistonBehavior::Block },
PistonBehavior::Ignore => quote! { PistonBehavior::Ignore },
PistonBehavior::PushOnly => quote! { PistonBehavior::PushOnly },
Self::Normal => quote! { PistonBehavior::Normal },
Self::Destroy => quote! { PistonBehavior::Destroy },
Self::Block => quote! { PistonBehavior::Block },
Self::Ignore => quote! { PistonBehavior::Ignore },
Self::PushOnly => quote! { PistonBehavior::PushOnly },
}
}
}
@ -447,20 +447,17 @@ impl BlockState {
let instrument = format_ident!("{}", self.instrument.to_upper_camel_case());
let luminance = LitInt::new(&self.luminance.to_string(), Span::call_site());
let hardness = self.hardness;
let opacity = match self.opacity {
Some(opacity) => {
let opacity = LitInt::new(&opacity.to_string(), Span::call_site());
quote! { #opacity }
}
None => quote! { 0 },
let opacity = if let Some(opacity) = self.opacity {
let opacity = LitInt::new(&opacity.to_string(), Span::call_site());
quote! { #opacity }
} else {
quote! { 0 }
};
let block_entity_type = match self.block_entity_type {
Some(block_entity_type) => {
let block_entity_type =
LitInt::new(&block_entity_type.to_string(), Span::call_site());
quote! { #block_entity_type }
}
None => quote! { u16::MAX },
let block_entity_type = if let Some(block_entity_type) = self.block_entity_type {
let block_entity_type = LitInt::new(&block_entity_type.to_string(), Span::call_site());
quote! { #block_entity_type }
} else {
quote! { u16::MAX }
};
let collision_shapes = self
@ -522,21 +519,19 @@ impl ToTokens for Block {
let slipperiness = &self.slipperiness;
let velocity_multiplier = &self.velocity_multiplier;
let jump_velocity_multiplier = &self.jump_velocity_multiplier;
let experience = match &self.experience {
Some(exp) => {
let exp_tokens = exp.to_token_stream();
quote! { Some(#exp_tokens) }
}
None => quote! { None },
let experience = if let Some(exp) = &self.experience {
let exp_tokens = exp.to_token_stream();
quote! { Some(#exp_tokens) }
} else {
quote! { None }
};
// Generate state tokens
let states = self.states.iter().map(|state| state.to_tokens());
let loot_table = match &self.loot_table {
Some(table) => {
let table_tokens = table.to_token_stream();
quote! { Some(#table_tokens) }
}
None => quote! { None },
let states = self.states.iter().map(BlockState::to_tokens);
let loot_table = if let Some(table) = &self.loot_table {
let table_tokens = table.to_token_stream();
quote! { Some(#table_tokens) }
} else {
quote! { None }
};
let default_state_ref: &BlockState = self
@ -547,12 +542,11 @@ impl ToTokens for Block {
let mut default_state = default_state_ref.clone();
default_state.id = default_state_ref.id;
let default_state = default_state.to_tokens();
let flammable = match &self.flammable {
Some(flammable) => {
let flammable_tokens = flammable.to_token_stream();
quote! { Some(#flammable_tokens) }
}
None => quote! { None },
let flammable = if let Some(flammable) = &self.flammable {
let flammable_tokens = flammable.to_token_stream();
quote! { Some(#flammable_tokens) }
} else {
quote! { None }
};
tokens.extend(quote! {
Block {
@ -800,10 +794,12 @@ pub(crate) fn build() -> TokenStream {
.find(|(_, be_props)| {
java_props_for_this_state
.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)
.unwrap_or_else(|| be_variants.first().map(|(id, _)| *id).unwrap_or(1));
.map_or_else(
|| be_variants.first().map_or(1, |(id, _)| *id),
|(id, _)| *id,
);
}
block_state_to_bedrock.push((state.id, matched_be_id));
@ -861,12 +857,16 @@ pub(crate) fn build() -> TokenStream {
let shapes = blocks_assets
.shapes
.iter()
.map(|shape| shape.to_token_stream());
.map(quote::ToTokens::to_token_stream);
let air_state_ids = quote! { #(#air_states)|* };
let block_props = block_properties.iter().map(|prop| prop.to_token_stream());
let properties = property_enums.values().map(|prop| prop.to_token_stream());
let block_props = block_properties
.iter()
.map(quote::ToTokens::to_token_stream);
let properties = property_enums
.values()
.map(quote::ToTokens::to_token_stream);
let block_entity_types = blocks_assets
.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 mut buf = [0; 1];
if reader.read_exact(&mut buf).is_ok() {
Some(buf[0])
} else {
None
}
reader.read_exact(&mut buf).is_ok().then(|| buf[0])
};
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(),
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);
@ -1242,7 +1238,7 @@ fn get_be_data_from_nbt<R: Read>(
"version" => {
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() {
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;
@ -115,6 +115,7 @@ pub fn main() {
});
}
#[must_use]
pub fn array_to_tokenstream(array: &[String]) -> TokenStream {
let variants = array.iter().map(|item| {
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
.into_iter()
.map(|status| {
let full_name = format!("minecraft:{}", status);
let full_name = format!("minecraft:{status}");
let name = format_ident!("{}", status.to_pascal_case());
quote! {

View File

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

View File

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

View File

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

View File

@ -51,9 +51,9 @@ impl Modifiers {
impl MobEffectCategory {
pub fn to_tokens(&self) -> TokenStream {
match self {
MobEffectCategory::BENEFICIAL => quote! { MobEffectCategory::Beneficial },
MobEffectCategory::HARMFUL => quote! { MobEffectCategory::Harmful },
MobEffectCategory::NEUTRAL => quote! { MobEffectCategory::Neutral },
Self::BENEFICIAL => quote! { MobEffectCategory::Beneficial },
Self::HARMFUL => quote! { MobEffectCategory::Harmful },
Self::NEUTRAL => quote! { MobEffectCategory::Neutral },
}
}
}
@ -69,14 +69,14 @@ pub(crate) fn build() -> TokenStream {
let mut 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 id = effect.id;
let color = effect.color;
let translation_key = effect.translation_key;
let category = effect.category.to_tokens();
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;
variants.extend([quote! {

View File

@ -37,17 +37,17 @@ pub enum AttributeModifierSlot {
impl AttributeModifierSlot {
pub fn to_tokens(&self) -> TokenStream {
match self {
AttributeModifierSlot::Any => quote! { AttributeModifierSlot::Any },
AttributeModifierSlot::MainHand => quote! { AttributeModifierSlot::MainHand },
AttributeModifierSlot::OffHand => quote! { AttributeModifierSlot::OffHand },
AttributeModifierSlot::Hand => quote! { AttributeModifierSlot::Hand },
AttributeModifierSlot::Feet => quote! { AttributeModifierSlot::Feet },
AttributeModifierSlot::Legs => quote! { AttributeModifierSlot::Legs },
AttributeModifierSlot::Chest => quote! { AttributeModifierSlot::Chest },
AttributeModifierSlot::Head => quote! { AttributeModifierSlot::Head },
AttributeModifierSlot::Armor => quote! { AttributeModifierSlot::Armor },
AttributeModifierSlot::Body => quote! { AttributeModifierSlot::Body },
AttributeModifierSlot::Saddle => quote! { AttributeModifierSlot::Saddle },
Self::Any => quote! { AttributeModifierSlot::Any },
Self::MainHand => quote! { AttributeModifierSlot::MainHand },
Self::OffHand => quote! { AttributeModifierSlot::OffHand },
Self::Hand => quote! { AttributeModifierSlot::Hand },
Self::Feet => quote! { AttributeModifierSlot::Feet },
Self::Legs => quote! { AttributeModifierSlot::Legs },
Self::Chest => quote! { AttributeModifierSlot::Chest },
Self::Head => quote! { AttributeModifierSlot::Head },
Self::Armor => quote! { AttributeModifierSlot::Armor },
Self::Body => quote! { AttributeModifierSlot::Body },
Self::Saddle => quote! { AttributeModifierSlot::Saddle },
}
}
}
@ -63,7 +63,7 @@ pub(crate) fn build() -> TokenStream {
let mut name_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 raw_name = name.strip_prefix("minecraft:").unwrap();
let format_name = format_ident!("{}", raw_name.to_shouty_snake_case());
@ -74,13 +74,12 @@ pub(crate) fn build() -> TokenStream {
.supported_items
.strip_prefix("#")
.unwrap()
.replace(":", "_")
.replace("/", "_")
.replace([':', '/'], "_")
.to_uppercase()
);
let max_level = enchantment.max_level;
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 {
panic!()
};
@ -92,8 +91,7 @@ pub(crate) fn build() -> TokenStream {
exclusive_set
.strip_prefix("#")
.unwrap()
.replace(":", "_")
.replace("/", "_")
.replace([':', '/'], "_")
.to_uppercase()
);
variants.extend([quote! {

View File

@ -63,14 +63,16 @@ impl ToTokens for NamedEntityType<'_> {
let entity = self.1;
let id = LitInt::new(&entity.id.to_string(), proc_macro2::Span::call_site());
let max_health = match entity.max_health {
Some(mh) => quote! { Some(#mh) },
None => quote! { None },
let max_health = if let Some(mh) = entity.max_health {
quote! { Some(#mh) }
} else {
quote! { None }
};
let attackable = match entity.attackable {
Some(a) => quote! { Some(#a) },
None => quote! { None },
let attackable = if let Some(a) = entity.attackable {
quote! { Some(#a) }
} else {
quote! { None }
};
let spawn_restriction_location = match entity.spawn_restriction.location {
@ -111,12 +113,14 @@ impl ToTokens for NamedEntityType<'_> {
let summonable = entity.summonable;
let fire_immune = entity.fire_immune;
let eye_height = entity.eye_height;
if entity.mob.is_none() && name != "player" {
panic!("missing field 'mob', entity name {name}");
}
if entity.limit_per_chunk.is_none() && name != "player" {
panic!("missing field 'mob', entity name {name}");
}
assert!(
!(entity.mob.is_none() && name != "player"),
"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 limit_per_chunk = entity.limit_per_chunk.unwrap_or(0);
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 dimension1 = entity.dimension[1];
let loot_table = match &entity.loot_table {
Some(table) => {
let table_tokens = table.to_token_stream();
quote! { Some(#table_tokens) }
}
None => quote! { None },
let loot_table = if let Some(table) = &entity.loot_table {
let table_tokens = table.to_token_stream();
quote! { Some(#table_tokens) }
} else {
quote! { None }
};
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_name = TokenStream::new();
for (name, entity) in json.iter() {
for (name, entity) in &json {
let id = entity.id as u8;
let id_lit = LitInt::new(&id.to_string(), proc_macro2::Span::call_site());
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 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}")
} else {
value.clone()
@ -69,7 +69,7 @@ impl ToTokens for PropertyStruct {
let values_3 = ident_values.clone();
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}")
} else {
value.clone()
@ -80,7 +80,7 @@ impl ToTokens for PropertyStruct {
}
});
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}")
} else {
value.clone()
@ -512,12 +512,13 @@ pub(crate) fn build() -> TokenStream {
.entry(renamed_property.clone())
.or_insert_with(|| property.values.clone());
if expected_values != &property.values {
panic!(
"Enum overlap for '{}' ({:?} vs {:?})",
property.name, &property.values, expected_values
);
};
assert!(
expected_values == &property.values,
"Enum overlap for '{}' ({:?} vs {:?})",
property.name,
&property.values,
expected_values
);
property_mapping.push(PropertyVariantMapping {
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 properties = property_enums.values().map(|prop| prop.to_token_stream());
let fluid_props = fluid_properties
.iter()
.map(quote::ToTokens::to_token_stream);
let properties = property_enums
.values()
.map(quote::ToTokens::to_token_stream);
quote! {
use std::hash::{Hash, Hasher};

View File

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

View File

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

View File

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

View File

@ -13,7 +13,7 @@ pub(crate) fn build() -> TokenStream {
let mut 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 simple_id = name;
let name = format_ident!("{}", name.to_uppercase());

View File

@ -87,7 +87,7 @@ enum SplineRepr {
#[serde(rename(deserialize = "locationFunction"))]
location_function: Box<DensityFunctionRepr>,
locations: Box<[HashableF32]>,
values: Box<[SplineRepr]>,
values: Box<[Self]>,
derivatives: Box<[HashableF32]>,
},
#[serde(rename(deserialize = "fixed"))]
@ -459,7 +459,7 @@ enum DensityFunctionRepr {
BlendAlpha,
BlendOffset,
BlendDensity {
input: Box<DensityFunctionRepr>,
input: Box<Self>,
},
EndIslands,
Noise {
@ -476,11 +476,11 @@ enum DensityFunctionRepr {
},
ShiftedNoise {
#[serde(rename(deserialize = "shiftX"))]
shift_x: Box<DensityFunctionRepr>,
shift_x: Box<Self>,
#[serde(rename(deserialize = "shiftY"))]
shift_y: Box<DensityFunctionRepr>,
shift_y: Box<Self>,
#[serde(rename(deserialize = "shiftZ"))]
shift_z: Box<DensityFunctionRepr>,
shift_z: Box<Self>,
#[serde(flatten)]
data: ShiftedNoiseData,
},
@ -490,7 +490,7 @@ enum DensityFunctionRepr {
},
#[serde(rename(deserialize = "WeirdScaledSampler"))]
WeirdScaled {
input: Box<DensityFunctionRepr>,
input: Box<Self>,
#[serde(flatten)]
data: WeirdScaledData,
},
@ -498,7 +498,7 @@ enum DensityFunctionRepr {
#[serde(rename(deserialize = "Wrapping"))]
Wrapper {
#[serde(rename(deserialize = "wrapped"))]
input: Box<DensityFunctionRepr>,
input: Box<Self>,
#[serde(rename(deserialize = "type"))]
wrapper: WrapperType,
},
@ -513,34 +513,34 @@ enum DensityFunctionRepr {
},
#[serde(rename(deserialize = "BinaryOperation"))]
Binary {
argument1: Box<DensityFunctionRepr>,
argument2: Box<DensityFunctionRepr>,
argument1: Box<Self>,
argument2: Box<Self>,
#[serde(flatten)]
data: BinaryData,
},
#[serde(rename(deserialize = "LinearOperation"))]
Linear {
input: Box<DensityFunctionRepr>,
input: Box<Self>,
#[serde(flatten)]
data: LinearData,
},
#[serde(rename(deserialize = "UnaryOperation"))]
Unary {
input: Box<DensityFunctionRepr>,
input: Box<Self>,
#[serde(flatten)]
data: UnaryData,
},
Clamp {
input: Box<DensityFunctionRepr>,
input: Box<Self>,
#[serde(flatten)]
data: ClampData,
},
RangeChoice {
input: Box<DensityFunctionRepr>,
input: Box<Self>,
#[serde(rename(deserialize = "whenInRange"))]
when_in_range: Box<DensityFunctionRepr>,
when_in_range: Box<Self>,
#[serde(rename(deserialize = "whenOutOfRange"))]
when_out_range: Box<DensityFunctionRepr>,
when_out_range: Box<Self>,
#[serde(flatten)]
data: RangeChoiceData,
},
@ -720,8 +720,8 @@ impl DensityFunctionRepr {
}
}
Self::ClampedYGradient { data } => {
let from_y = data.from_y as f64;
let to_y = data.to_y as f64;
let from_y = f64::from(data.from_y);
let to_y = f64::from(data.to_y);
let from_value = &data.from_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 (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);
// Check if the packet exists in 1.21.7 to get the alternate ID
let id_7 = v7_phases
.get(phase)
.and_then(|p| p.get(name))
.cloned()
.copied()
.unwrap_or(-1);
// 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 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 id = potion.id;
let slots = potion.effects;
let slots = slots.iter().map(|slot| slot.to_tokens());
let slots = slots.iter().map(Effect::to_tokens);
variants.extend([quote! {
pub const #format_name: Self = Self {

View File

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

View File

@ -50,9 +50,10 @@ impl ToTokens for CookingRecipeStruct {
Some(category) => category.to_token_stream(),
None => RecipeCategoryTypes::Misc.to_token_stream(),
};
let group = match &self.group {
Some(group) => quote! { Some(#group) },
None => quote! { None },
let group = if let Some(group) = &self.group {
quote! { Some(#group) }
} else {
quote! { None }
};
let ingredient = self.ingredient.to_token_stream();
let cookingtime = self.cookingtime.to_token_stream();
@ -88,9 +89,10 @@ impl ToTokens for CraftingShapedRecipeStruct {
Some(category) => category.to_token_stream(),
None => RecipeCategoryTypes::Misc.to_token_stream(),
};
let group = match &self.group {
Some(group) => quote! { Some(#group) },
None => quote! { None },
let group = if let Some(group) = &self.group {
quote! { Some(#group) }
} else {
quote! { None }
};
let show_notification = self.show_notification.unwrap_or(true);
let key = self
@ -104,7 +106,7 @@ impl ToTokens for CraftingShapedRecipeStruct {
let pattern = self
.pattern
.iter()
.map(|c| c.to_token_stream())
.map(quote::ToTokens::to_token_stream)
.collect::<Vec<_>>();
let result = self.result.to_token_stream();
@ -135,14 +137,15 @@ impl ToTokens for CraftingShapelessRecipeStruct {
Some(category) => category.to_token_stream(),
None => RecipeCategoryTypes::Misc.to_token_stream(),
};
let group = match &self.group {
Some(group) => quote! { Some(#group) },
None => quote! { None },
let group = if let Some(group) = &self.group {
quote! { Some(#group) }
} else {
quote! { None }
};
let ingredients = self
.ingredients
.iter()
.map(|c| c.to_token_stream())
.map(quote::ToTokens::to_token_stream)
.collect::<Vec<_>>();
let result = self.result.to_token_stream();
@ -172,9 +175,10 @@ impl ToTokens for CraftingTransmuteRecipeStruct {
Some(category) => category.to_token_stream(),
None => RecipeCategoryTypes::Misc.to_token_stream(),
};
let group = match &self.group {
Some(group) => quote! { Some(#group) },
None => quote! { None },
let group = if let Some(group) = &self.group {
quote! { Some(#group) }
} else {
quote! { None }
};
let input = self.input.to_token_stream();
let material = self.material.to_token_stream();
@ -243,17 +247,17 @@ pub enum RecipeIngredientTypes {
impl ToTokens for RecipeIngredientTypes {
fn to_tokens(&self, tokens: &mut TokenStream) {
let name = match self {
RecipeIngredientTypes::Simple(ingredient) => {
if ingredient.starts_with("#") {
Self::Simple(ingredient) => {
if ingredient.starts_with('#') {
quote! { RecipeIngredientTypes::Tagged(#ingredient) }
} else {
quote! { RecipeIngredientTypes::Simple(#ingredient) }
}
}
RecipeIngredientTypes::OneOf(ingredients) => {
Self::OneOf(ingredients) => {
let ingredients = ingredients
.iter()
.map(|c| c.to_token_stream())
.map(quote::ToTokens::to_token_stream)
.collect::<Vec<_>>();
quote! { RecipeIngredientTypes::OneOf(&[#(#ingredients),*]) }
}
@ -282,22 +286,22 @@ pub enum RecipeCategoryTypes {
impl ToTokens for RecipeCategoryTypes {
fn to_tokens(&self, tokens: &mut TokenStream) {
let name = match self {
RecipeCategoryTypes::Equipment => {
Self::Equipment => {
quote! { RecipeCategoryTypes::Equipment }
}
RecipeCategoryTypes::Building => {
Self::Building => {
quote! { RecipeCategoryTypes::Building }
}
RecipeCategoryTypes::Restone => {
Self::Restone => {
quote! { RecipeCategoryTypes::Restone }
}
RecipeCategoryTypes::Misc => {
Self::Misc => {
quote! { RecipeCategoryTypes::Misc }
}
RecipeCategoryTypes::Food => {
Self::Food => {
quote! { RecipeCategoryTypes::Food }
}
RecipeCategoryTypes::Blocks => {
Self::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");
let process_version = |path: &str| -> TokenStream {
let json_str =
fs::read_to_string(path).unwrap_or_else(|_| panic!("Failed to read {}", path));
let json_str = fs::read_to_string(path).unwrap_or_else(|_| panic!("Failed to read {path}"));
let mut data: IndexMap<String, IndexMap<String, Value>> =
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];
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() {
continue;
}
@ -144,13 +144,13 @@ pub(crate) fn build() -> TokenStream {
let ids: Vec<u16> = values
.iter()
.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(),
"item" => items.get(v).map(|i| i.id),
"block" => block_id_map.get(v).copied(),
"enchantment" => enchantments
.get(&format!("minecraft:{}", v))
.map(|e| e.id as u16),
.get(&format!("minecraft:{v}"))
.map(|e| u16::from(e.id)),
"entity_type" => entities.get(v).map(|e| e.id),
_ => None,
})

View File

@ -24,7 +24,7 @@ pub(crate) fn build() -> TokenStream {
for (name, id_11) in &data_11 {
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! {
pub const #ident: TrackedId = TrackedId {

View File

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

View File

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

View File

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

View File

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

View File

@ -2,7 +2,11 @@
use crate::attributes::Attributes;
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::tag::{Tag, Taggable};
use crate::{AttributeModifierSlot, Block, Enchantment};
@ -38,6 +42,7 @@ pub trait DataComponentImpl: Send + Sync {
fn as_any(&self) -> &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>> {
match id {
MaxStackSize => Some(MaxStackSizeImpl::read_data(data)?.to_dyn()),
@ -116,10 +121,10 @@ impl MaxStackSizeImpl {
}
impl DataComponentImpl for MaxStackSizeImpl {
fn write_data(&self) -> NbtTag {
NbtTag::Int(self.size as i32)
NbtTag::Int(i32::from(self.size))
}
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);
@ -196,7 +201,7 @@ impl EnchantmentsImpl {
let data = &data.extract_compound()?.child_tags;
let mut enc = Vec::with_capacity(data.len());
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 {
enchantment: Cow::from(enc),
@ -279,7 +284,7 @@ impl Hash for Modifier {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.r#type.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.slot.hash(state);
}
@ -315,7 +320,7 @@ impl DataComponentImpl for FoodImpl {
impl Hash for FoodImpl {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
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);
}
}
@ -326,6 +331,7 @@ pub struct ConsumableImpl {
}
impl ConsumableImpl {
#[must_use]
pub fn consume_ticks(&self) -> i32 {
(self.consume_seconds * 20.0) as i32
}
@ -336,7 +342,7 @@ impl DataComponentImpl for ConsumableImpl {
}
impl Hash for ConsumableImpl {
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)]
@ -363,7 +369,7 @@ impl Hash for ToolRule {
self.blocks.hash(state);
if let Some(val) = self.speed {
true.hash(state);
unsafe { (*(&val as *const f32 as *const u32)).hash(state) };
unsafe { (*(&raw const val).cast::<u32>()).hash(state) };
} else {
false.hash(state);
}
@ -383,7 +389,7 @@ impl DataComponentImpl for ToolImpl {
impl Hash for ToolImpl {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
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.can_destroy_blocks_in_creative.hash(state);
}
@ -479,6 +485,7 @@ impl EquipmentSlot {
name: Cow::Borrowed("saddle"),
});
#[must_use]
pub fn get_entity_slot_id(&self) -> i32 {
match self {
Self::MainHand(data) => data.entity_id,
@ -492,6 +499,7 @@ impl EquipmentSlot {
}
}
#[must_use]
pub fn get_from_name(name: &str) -> Option<Self> {
match name {
"mainhand" => Some(Self::MAIN_HAND),
@ -506,10 +514,12 @@ impl EquipmentSlot {
}
}
#[must_use]
pub fn get_offset_entity_slot_id(&self, offset: i32) -> i32 {
self.get_entity_slot_id() + offset
}
#[must_use]
pub fn slot_type(&self) -> EquipmentType {
match self {
Self::MainHand(data) => data.slot_type,
@ -523,6 +533,7 @@ impl EquipmentSlot {
}
}
#[must_use]
pub fn is_armor_slot(&self) -> bool {
matches!(
self.slot_type(),
@ -530,6 +541,7 @@ impl EquipmentSlot {
)
}
#[must_use]
pub const fn discriminant(&self) -> i8 {
match self {
Self::MainHand(_) => 0,
@ -553,12 +565,12 @@ pub enum EntityTypeOrTag {
impl Hash for EntityTypeOrTag {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
match self {
EntityTypeOrTag::Tag(tag) => {
Self::Tag(tag) => {
for x in tag.0 {
x.hash(state);
}
}
EntityTypeOrTag::Single(entity_type) => {
Self::Single(entity_type) => {
entity_type.id.hash(state);
}
}

View File

@ -15,3 +15,6 @@ log.workspace = true
tokio.workspace = true
thiserror.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;
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 {
SlotActionType::Pickup => Self::new_normal_click(button, slot),
// 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> {
let slot = match slot {
SLOT_INDEX_OUTSIDE => Slot::OutsideInventory,
_ => {
let slot = slot.try_into().unwrap_or(0);
Slot::Normal(slot)
}
let slot = if slot == SLOT_INDEX_OUTSIDE {
Slot::OutsideInventory
} else {
let slot = slot.try_into().unwrap_or(0);
Slot::Normal(slot)
};
let button = match button {
BUTTON_CLICK_LEFT => MouseClick::Left,
@ -79,12 +78,11 @@ impl Click {
fn new_drop_item(button: i8, slot: i16) -> Result<Self, InventoryError> {
let drop_type = DropType::from_i8(button)?;
let slot = match slot {
SLOT_INDEX_OUTSIDE => Slot::OutsideInventory,
_ => {
let slot = slot.try_into().unwrap_or(0);
Slot::Normal(slot)
}
let slot = if slot == SLOT_INDEX_OUTSIDE {
Slot::OutsideInventory
} else {
let slot = slot.try_into().unwrap_or(0);
Slot::Normal(slot)
};
Ok(Self {
click_type: ClickType::DropType(drop_type),

View File

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

View File

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

View File

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

View File

@ -65,9 +65,9 @@ impl Inventory for DoubleInventory {
fn set_stack(&self, slot: usize, stack: ItemStack) -> InventoryFuture<'_, ()> {
Box::pin(async move {
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 {
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 {
#[must_use]
pub fn new() -> Self {
Self {
equipment: HashMap::new(),
@ -32,6 +33,7 @@ impl EntityEquipment {
.clone()
}
#[must_use]
pub fn get(&self, slot: &EquipmentSlot) -> Arc<Mutex<ItemStack>> {
self.equipment
.get(slot)

View File

@ -26,12 +26,6 @@ impl FurnaceLikeScreenHandler {
furnace_block_entity: Arc<dyn BlockEntity>,
window_type: WindowType,
) -> 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;
impl ScreenHandlerListener for FurnaceLikeScreenListener {
fn on_property_update<'a>(
@ -43,12 +37,17 @@ impl FurnaceLikeScreenHandler {
Box::pin(async move {
if let Some(sync_handler) = screen_handler.sync_handler.as_ref() {
sync_handler
.update_property(screen_handler, property as i32, value)
.update_property(screen_handler, i32::from(property), value)
.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)
// 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)
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)
if !self
.insert_item(

View File

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

View File

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

View File

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

View File

@ -31,11 +31,12 @@ impl PlayerScreenHandler {
EquipmentSlot::FEET,
];
#[must_use]
pub fn is_in_hotbar(slot: u8) -> bool {
(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()
}
@ -47,7 +48,7 @@ impl PlayerScreenHandler {
let crafting_inventory: Arc<dyn RecipeInputInventory> =
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),
crafting_inventory: crafting_inventory.clone(),
};
@ -140,7 +141,6 @@ impl ScreenHandler for PlayerScreenHandler {
} else if equipment_slot.slot_type() == EquipmentType::HumanoidArmor
&& self
.get_slot((8 - equipment_slot.get_entity_slot_id()) as usize)
.await
.get_cloned_stack()
.await
.is_empty()
@ -159,7 +159,7 @@ impl ScreenHandler for PlayerScreenHandler {
result
} else if matches!(equipment_slot, EquipmentSlot::OffHand(_))
&& 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)
let index = 45;

View File

@ -41,18 +41,19 @@ pub struct ScreenProperty {
impl ScreenProperty {
pub fn new(value: Arc<dyn PropertyDelegate>, index: u8) -> Self {
Self {
old_value: value.get_property(index as i32),
old_value: value.get_property(i32::from(index)),
index,
value,
}
}
#[must_use]
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) {
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 {
@ -66,7 +67,7 @@ impl ScreenProperty {
pub type PlayerFuture<'a, T> = Pin<Box<dyn Future<Output = T> + Send + 'a>>;
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 has_infinite_materials(&self) -> bool;
@ -238,10 +239,10 @@ pub trait ScreenHandler: Send + Sync {
})
}
fn copy_shared_slots<'a>(
&'a mut self,
fn copy_shared_slots(
&mut self,
other: Arc<Mutex<dyn ScreenHandler>>,
) -> ScreenHandlerFuture<'a, ()> {
) -> ScreenHandlerFuture<'_, ()> {
Box::pin(async move {
let mut table: HashMap<ComparableInventory, HashMap<usize, usize>> = HashMap::new();
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 {
let behaviour = self.get_behaviour_mut();
let mut previous_tracked_stacks = Vec::new();
@ -311,20 +312,20 @@ pub trait ScreenHandler: Send + Sync {
})
}
fn add_listener<'a>(
&'a mut self,
fn add_listener(
&mut self,
listener: Arc<dyn ScreenHandlerListener>,
) -> ScreenHandlerFuture<'a, ()> {
) -> ScreenHandlerFuture<'_, ()> {
Box::pin(async move {
self.get_behaviour_mut().listeners.push(listener);
self.send_content_updates().await;
})
}
fn update_sync_handler<'a>(
&'a mut self,
fn update_sync_handler(
&mut self,
sync_handler: Arc<SyncHandler>,
) -> ScreenHandlerFuture<'a, ()> {
) -> ScreenHandlerFuture<'_, ()> {
Box::pin(async move {
let behaviour = self.get_behaviour_mut();
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 {
for i in 0..self.get_behaviour().slots.len() {
let behaviour = self.get_behaviour_mut();
@ -359,16 +360,12 @@ pub trait ScreenHandler: Send + Sync {
})
}
fn update_tracked_properties<'a>(
&'a mut self,
idx: i32,
value: i32,
) -> ScreenHandlerFuture<'a, ()> {
fn update_tracked_properties(&mut self, idx: i32, value: i32) -> ScreenHandlerFuture<'_, ()> {
Box::pin(async move {
let behaviour = self.get_behaviour_mut();
if idx <= behaviour.tracked_property_values.len() as i32 {
behaviour.tracked_property_values[idx as usize] = value;
for listener in behaviour.listeners.iter() {
for listener in &behaviour.listeners {
listener
.on_property_update(behaviour, idx as u8, value)
.await;
@ -377,11 +374,7 @@ pub trait ScreenHandler: Send + Sync {
})
}
fn check_property_updates<'a>(
&'a mut self,
idx: i32,
value: i32,
) -> ScreenHandlerFuture<'a, ()> {
fn check_property_updates(&mut self, idx: i32, value: i32) -> ScreenHandlerFuture<'_, ()> {
Box::pin(async move {
let behaviour = self.get_behaviour_mut();
if !behaviour.disable_sync
@ -400,18 +393,18 @@ pub trait ScreenHandler: Send + Sync {
})
}
fn update_tracked_slot<'a>(
&'a mut self,
fn update_tracked_slot(
&mut self,
slot: usize,
stack: ItemStack,
) -> ScreenHandlerFuture<'a, ()> {
) -> ScreenHandlerFuture<'_, ()> {
Box::pin(async move {
let behaviour = self.get_behaviour_mut();
let other_stack = &behaviour.tracked_stacks[slot];
if !other_stack.are_equal(&stack) {
behaviour.tracked_stacks[slot] = stack.clone();
for listener in behaviour.listeners.iter() {
for listener in &behaviour.listeners {
listener
.on_slot_update(behaviour, slot as u8, stack.clone())
.await;
@ -420,11 +413,7 @@ pub trait ScreenHandler: Send + Sync {
})
}
fn check_slot_updates<'a>(
&'a mut self,
slot: usize,
stack: ItemStack,
) -> ScreenHandlerFuture<'a, ()> {
fn check_slot_updates(&mut self, slot: usize, stack: ItemStack) -> ScreenHandlerFuture<'_, ()> {
Box::pin(async move {
let behaviour = self.get_behaviour_mut();
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 {
let behaviour = self.get_behaviour_mut();
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 {
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 {
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>(
&'a mut self,
slot_index: i32,
@ -658,7 +648,7 @@ pub trait ScreenHandler: Send + Sync {
let mut cursor_stack = behavior.cursor_stack.lock().await;
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 {
break;
}
@ -727,7 +717,7 @@ pub trait ScreenHandler: Send + Sync {
let mut cursor_stack = behaviour.cursor_stack.lock().await;
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 stack_lock = slot.get_stack().await;
let stack = stack_lock.lock().await;
@ -1070,6 +1060,7 @@ pub struct ScreenHandlerBehaviour {
}
impl ScreenHandlerBehaviour {
#[must_use]
pub fn new(sync_id: u8, window_type: Option<WindowType>) -> Self {
Self {
slots: Vec::new(),

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -20,8 +20,9 @@ pub struct NbtCompound {
}
impl NbtCompound {
pub fn new() -> NbtCompound {
NbtCompound {
#[must_use]
pub fn new() -> Self {
Self {
child_tags: Vec::new(),
}
}
@ -39,7 +40,7 @@ impl NbtCompound {
}
let len = reader.get_u16_be()?;
reader.skip_bytes(len as i64)?;
reader.skip_bytes(i64::from(len))?;
// Skip Value
NbtTag::skip_data(reader, tag_id)?;
@ -50,8 +51,8 @@ impl NbtCompound {
pub fn deserialize_content<R: Read + Seek>(
reader: &mut NbtReadHelper<R>,
) -> Result<NbtCompound, Error> {
let mut compound = NbtCompound::new();
) -> Result<Self, Error> {
let mut compound = Self::new();
loop {
let tag_id = match reader.get_u8_be() {
@ -83,6 +84,7 @@ impl NbtCompound {
Ok(())
}
#[must_use]
pub fn is_empty(&self) -> bool {
self.child_tags.is_empty()
}
@ -106,7 +108,7 @@ impl NbtCompound {
}
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) {
@ -128,15 +130,17 @@ impl NbtCompound {
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));
}
#[must_use]
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]
#[must_use]
pub fn get(&self, name: &str) -> Option<&NbtTag> {
self.child_tags
.iter()
@ -144,46 +148,57 @@ impl NbtCompound {
.map(|r| &r.1)
}
#[must_use]
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> {
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> {
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> {
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> {
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> {
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> {
self.get(name).and_then(|tag| tag.extract_string())
}
#[must_use]
pub fn get_list(&self, name: &str) -> Option<&[NbtTag]> {
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())
}
#[must_use]
pub fn get_int_array(&self, name: &str) -> Option<&[i32]> {
self.get(name).and_then(|tag| tag.extract_int_array())
}
#[must_use]
pub fn get_long_array(&self, name: &str) -> Option<&[i64]> {
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 {
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 {
compound.put(&key, value);
}
@ -216,13 +231,13 @@ impl IntoIterator for NbtCompound {
impl Extend<(String, NbtTag)> for NbtCompound {
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
impl AsRef<NbtCompound> for NbtCompound {
fn as_ref(&self) -> &NbtCompound {
impl AsRef<Self> for NbtCompound {
fn as_ref(&self) -> &Self {
self
}
}
@ -267,11 +282,11 @@ impl<'de> Deserialize<'de> for NbtCompound {
impl From<NbtCompound> for NbtTag {
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 {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
f.write_str("{")?;
@ -279,7 +294,7 @@ impl Display for NbtCompound {
if i > 0 {
f.write_str(", ")?;
}
write!(f, "{}: {}", key, value)?;
write!(f, "{key}: {value}")?;
}
f.write_str("}")
}
@ -288,52 +303,52 @@ impl Display for NbtCompound {
impl Display for NbtTag {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
NbtTag::End => Ok(()),
NbtTag::Byte(v) => write!(f, "{v}b"),
NbtTag::Short(v) => write!(f, "{v}s"),
NbtTag::Int(v) => write!(f, "{v}"),
NbtTag::Long(v) => write!(f, "{v}L"),
NbtTag::Float(v) => write!(f, "{v}f"),
NbtTag::Double(v) => write!(f, "{v}d"),
NbtTag::String(v) => write!(f, "\"{v}\""), // TODO: Proper escaping needed for robust SNBT
NbtTag::Compound(v) => write!(f, "{v}"),
NbtTag::ByteArray(v) => {
Self::End => Ok(()),
Self::Byte(v) => write!(f, "{v}b"),
Self::Short(v) => write!(f, "{v}s"),
Self::Int(v) => write!(f, "{v}"),
Self::Long(v) => write!(f, "{v}L"),
Self::Float(v) => write!(f, "{v}f"),
Self::Double(v) => write!(f, "{v}d"),
Self::String(v) => write!(f, "\"{v}\""), // TODO: Proper escaping needed for robust SNBT
Self::Compound(v) => write!(f, "{v}"),
Self::ByteArray(v) => {
f.write_str("[B;")?;
for (i, byte) in v.iter().enumerate() {
if i > 0 {
f.write_str(",")?
f.write_str(",")?;
}
write!(f, " {}b", byte)?;
write!(f, " {byte}b")?;
}
f.write_str("]")
}
NbtTag::List(v) => {
Self::List(v) => {
f.write_str("[")?;
for (i, tag) in v.iter().enumerate() {
if i > 0 {
f.write_str(", ")?
f.write_str(", ")?;
}
write!(f, "{}", tag)?;
write!(f, "{tag}")?;
}
f.write_str("]")
}
NbtTag::IntArray(v) => {
Self::IntArray(v) => {
f.write_str("[I;")?;
for (i, int) in v.iter().enumerate() {
if i > 0 {
f.write_str(",")?
f.write_str(",")?;
}
write!(f, " {}", int)?;
write!(f, " {int}")?;
}
f.write_str("]")
}
NbtTag::LongArray(v) => {
Self::LongArray(v) => {
f.write_str("[L;")?;
for (i, long) in v.iter().enumerate() {
if i > 0 {
f.write_str(",")?
f.write_str(",")?;
}
write!(f, " {}L", long)?;
write!(f, " {long}L")?;
}
f.write_str("]")
}

View File

@ -1,7 +1,10 @@
use std::cell::RefCell;
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 serde::de::{self, DeserializeSeed, IntoDeserializer, MapAccess, SeqAccess, Visitor};
use serde::{Deserialize, forward_to_deserialize_any};
@ -13,7 +16,7 @@ thread_local! {
}
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>) {
@ -85,7 +88,7 @@ pub struct Deserializer<R: Read + Seek> {
impl<R: Read + Seek> Deserializer<R> {
pub fn new(input: R, is_named: bool) -> Self {
Deserializer {
Self {
input: NbtReadHelper { reader: input },
tag_to_deserialize_stack: None,
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 tag_id != COMPOUND_ID {
return Err(Error::SerdeError(format!(
"Trying to deserialize a map without a compound ID (id {})",
tag_id
"Trying to deserialize a map without a compound ID (id {tag_id})"
)));
}
} else {

View File

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

View File

@ -3,15 +3,15 @@ use crate::{Error, Nbt, NbtCompound, deserializer, serializer};
use flate2::{Compression, read::GzDecoder, write::GzEncoder};
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
///
/// * `input` - Any type implementing the Read trait containing GZipped NBT data
/// * `input` - Any type implementing the Read trait containing `GZipped` NBT data
///
/// # 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> {
// Create a GZip decoder and directly chain it to the NBT reader
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)
}
/// 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
///
/// * `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
///
/// # Returns
@ -58,11 +58,11 @@ pub fn write_gzip_compound_tag_to_bytes(compound: NbtCompound) -> Result<Vec<u8>
Ok(buffer)
}
/// Reads a GZipped NBT structure into a Rust type.
/// Reads a `GZipped` NBT structure into a Rust type.
///
/// # Arguments
///
/// * `input` - Any type implementing the Read trait containing GZipped NBT data
/// * `input` - Any type implementing the Read trait containing `GZipped` NBT data
///
/// # 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))
}
/// Writes a Rust type as GZipped NBT to any writer.
/// Writes a Rust type as `GZipped` NBT to any writer.
///
/// # Arguments
///
@ -262,6 +262,7 @@ mod tests {
}
#[test]
#[expect(clippy::print_stdout)]
fn test_gzip_compression_ratio() {
let mut compound = NbtCompound::new();
@ -294,6 +295,7 @@ mod tests {
}
#[test]
#[expect(clippy::struct_field_names)]
fn test_roundtrip_with_arrays() {
#[derive(Serialize, Deserialize, Debug, PartialEq)]
struct ArrayTest {

View File

@ -122,20 +122,19 @@ impl<W: Write> Serializer<W> {
return Err(Error::SerdeError(
"Invalid state: already handled root component!".to_string(),
));
} else {
if tag != COMPOUND_ID {
return Err(Error::SerdeError(format!(
"Invalid state: root is not a `Compound`! ({tag})"
)));
}
self.handled_root = true;
self.output.write_u8_be(tag)?;
if let Some(root_name) = root_name {
NbtTag::write_string(root_name, &mut self.output)?;
}
}
if tag != COMPOUND_ID {
return Err(Error::SerdeError(format!(
"Invalid state: root is not a `Compound`! ({tag})"
)));
}
self.handled_root = true;
self.output.write_u8_be(tag)?;
if let Some(root_name) = root_name {
NbtTag::write_string(root_name, &mut self.output)?;
}
}
};
}
Ok(())
}
}
@ -171,7 +170,7 @@ impl<W: Write> ser::Serializer for &mut Serializer<W> {
type SerializeStructVariant = Impossible<(), Error>;
fn serialize_bool(self, v: bool) -> Result<()> {
self.serialize_i8(v as i8)?;
self.serialize_i8(i8::from(v))?;
Ok(())
}
@ -200,15 +199,14 @@ impl<W: Write> ser::Serializer for &mut Serializer<W> {
}
fn serialize_u8(self, v: u8) -> Result<()> {
match self.state {
State::Named(_) => Err(Error::UnsupportedType(
if let State::Named(_) = self.state {
Err(Error::UnsupportedType(
"u8; NBT only supports signed values".to_string(),
)),
_ => {
self.parse_state(BYTE_ID)?;
self.output.write_u8_be(v)?;
Ok(())
}
))
} else {
self.parse_state(BYTE_ID)?;
self.output.write_u8_be(v)?;
Ok(())
}
}
@ -336,35 +334,32 @@ impl<W: Write> ser::Serializer for &mut Serializer<W> {
return Err(Error::LargeLength(len));
}
match &mut self.state {
State::Array { array_type, .. } => {
let (id, expected_tag) = match *array_type {
NBT_BYTE_ARRAY_TAG => (BYTE_ARRAY_ID, BYTE_ID),
NBT_INT_ARRAY_TAG => (INT_ARRAY_ID, INT_ID),
NBT_LONG_ARRAY_TAG => (LONG_ARRAY_ID, LONG_ID),
_ => {
return Err(Error::SerdeError(
"Array supports only `byte`, `int`, and `long`".to_string(),
));
}
};
self.parse_state(id)?;
self.output.write_i32_be(len as i32)?;
// We can mark anything as an NBT array list, so mark as needed to be checked.
self.expected_list_tag = expected_tag;
self.state = State::CheckedListElement;
}
_ => {
self.parse_state(LIST_ID)?;
self.state = State::FirstListElement { len: len as i32 };
if len == 0 {
// If we have no elements, the `FirstListElement` state will never be invoked, so
// write the (unknown) list type and length here.
self.output.write_u8_be(END_ID)?;
self.output.write_i32_be(0)?;
if let State::Array { array_type, .. } = &mut self.state {
let (id, expected_tag) = match *array_type {
NBT_BYTE_ARRAY_TAG => (BYTE_ARRAY_ID, BYTE_ID),
NBT_INT_ARRAY_TAG => (INT_ARRAY_ID, INT_ID),
NBT_LONG_ARRAY_TAG => (LONG_ARRAY_ID, LONG_ID),
_ => {
return Err(Error::SerdeError(
"Array supports only `byte`, `int`, and `long`".to_string(),
));
}
};
self.parse_state(id)?;
self.output.write_i32_be(len as i32)?;
// We can mark anything as an NBT array list, so mark as needed to be checked.
self.expected_list_tag = expected_tag;
self.state = State::CheckedListElement;
} else {
self.parse_state(LIST_ID)?;
self.state = State::FirstListElement { len: len as i32 };
if len == 0 {
// If we have no elements, the `FirstListElement` state will never be invoked, so
// write the (unknown) list type and length here.
self.output.write_u8_be(END_ID)?;
self.output.write_i32_be(0)?;
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -46,10 +46,11 @@ pub enum DecryptionReader<R: AsyncRead + Unpin> {
}
impl<R: AsyncRead + Unpin> DecryptionReader<R> {
#[must_use]
pub fn upgrade(self, cipher: Aes128Cfb8Dec) -> Self {
match self {
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
/// Supports ZLib decoding/decompression
/// Supports `ZLib` decoding/decompression
/// Supports Aes128 Encryption
pub struct UDPNetworkDecoder {
compression: Option<CompressionThreshold>,
@ -88,6 +89,7 @@ impl Default for UDPNetworkDecoder {
}
impl UDPNetworkDecoder {
#[must_use]
pub fn new() -> Self {
Self { compression: None }
}
@ -105,6 +107,7 @@ impl UDPNetworkDecoder {
// take_mut::take(&mut self.reader, |decoder| decoder.upgrade(cipher));
}
#[expect(clippy::unused_async)]
pub async fn get_packet_payload(
&mut self,
reader: Cursor<Vec<u8>>,
@ -118,7 +121,7 @@ impl UDPNetworkDecoder {
Ok(reader.into_inner().into())
}
pub async fn get_game_packet(
pub fn get_game_packet(
&mut self,
mut reader: Cursor<Vec<u8>>,
) -> Result<RawPacket, PacketDecodeError> {
@ -134,7 +137,7 @@ impl UDPNetworkDecoder {
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)?;
@ -148,10 +151,10 @@ impl UDPNetworkDecoder {
// SubClient Target ID (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)
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)
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()))?;
Ok(RawPacket {
id: gamepacket_id as i32,
id: i32::from(gamepacket_id),
payload: payload.into(),
})
}

View File

@ -5,7 +5,6 @@ use std::{
task::{Context, Poll},
};
use bytes::Bytes;
use thiserror::Error;
use tokio::{io::AsyncWrite, net::UdpSocket};
@ -22,10 +21,11 @@ pub enum EncryptionWriter<W: AsyncWrite + Unpin> {
}
impl<W: AsyncWrite + Unpin> EncryptionWriter<W> {
#[must_use]
pub fn upgrade(self, cipher: Aes128Cfb8Enc) -> Self {
match self {
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
/// Supports ZLib endecoding/compression
/// Supports `ZLib` endecoding/compression
/// Supports Aes128 Encryption
pub struct UDPNetworkEncoder {
// compression and compression threshold
@ -90,6 +90,7 @@ impl Default for UDPNetworkEncoder {
}
impl UDPNetworkEncoder {
#[must_use]
pub fn new() -> Self {
Self { compression: None }
}
@ -107,12 +108,12 @@ impl UDPNetworkEncoder {
// take_mut::take(&mut self.writer, |encoder| encoder.upgrade(cipher));
}
pub async fn write_game_packet(
pub fn write_game_packet(
&mut self,
packet_id: u16,
sub_client_sender: SubClient,
sub_client_target: SubClient,
packet_payload: Bytes,
packet_payload: &[u8],
mut writer: impl Write,
) -> Result<(), Error> {
// Game Packet ID
@ -128,7 +129,7 @@ impl UDPNetworkEncoder {
// 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 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_target as u32) << 12);
@ -158,7 +159,7 @@ impl UDPNetworkEncoder {
.unwrap();
// 5. Write the payload
writer.write_all(&packet_payload)
writer.write_all(packet_payload)
}
pub async fn write_packet(

View File

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

View File

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

View File

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

View File

@ -31,7 +31,7 @@ impl BitSet {
let long = read.get_i64_be()?;
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> {
pub fn get<T: Into<usize>>(&self, index: T) -> bool {
let index: usize = index.into();
if index > N {
panic!("")
}
assert!(index <= N, "");
(self.bits & (1 << index)) != 0
}
pub fn set<T: Into<usize>>(&mut self, index: T, value: bool) {
let index: usize = index.into();
if index > N {
panic!("")
}
assert!(index <= N, "");
if value {
self.bits |= 1 << index;
} else {
@ -31,16 +27,14 @@ impl<const N: usize> Bitset<N> {
impl<const N: usize> Default for Bitset<N> {
fn default() -> Self {
if N > 80 {
panic!()
}
assert!(N <= 80,);
Self { bits: 0 }
}
}
impl<const N: usize> PacketRead for Bitset<N> {
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) {
let byte = u8::read(reader)?;

View File

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

View File

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

View File

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

View File

@ -17,6 +17,6 @@ impl PacketRead for u24 {
fn read<R: Read>(reader: &mut R) -> Result<Self, Error> {
let mut buf = [0; 3];
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.
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.
#[must_use]
pub fn written_size(&self) -> usize {
match self.0 {
0 => 1,
@ -57,7 +58,7 @@ impl VarInt {
let byte = read.get_u8()?;
val |= (i32::from(byte) & 0x7F) << (i * 7);
if byte & 0x80 == 0 {
return Ok(VarInt(val));
return Ok(Self(val));
}
}
Err(ReadingError::TooLarge("VarInt".to_string()))
@ -77,7 +78,7 @@ impl VarInt {
})?;
val |= (i32::from(byte) & 0x7F) << (i * 7);
if byte & 0x80 == 0 {
return Ok(VarInt(val));
return Ok(Self(val));
}
}
Err(ReadingError::TooLarge("VarInt".to_string()))
@ -89,10 +90,10 @@ impl VarInt {
) -> Result<(), WritingError> {
let mut val = self.0;
for _ in 0..Self::MAX_SIZE.get() {
let b: u8 = val as u8 & 0b01111111;
let b: u8 = val as u8 & 0b0111_1111;
val >>= 7;
write
.write_u8(if val == 0 { b } else { b | 0b10000000 })
.write_u8(if val == 0 { b } else { b | 0b1000_0000 })
.await
.map_err(WritingError::IoError)?;
if val == 0 {
@ -183,8 +184,8 @@ impl<'de> Deserialize<'de> for VarInt {
let mut val = 0;
for i in 0..VarInt::MAX_SIZE.get() {
if let Some(byte) = seq.next_element::<u8>()? {
val |= (i32::from(byte) & 0b01111111) << (i * 7);
if byte & 0b10000000 == 0 {
val |= (i32::from(byte) & 0b0111_1111) << (i * 7);
if byte & 0b1000_0000 == 0 {
return Ok(VarInt(val));
}
} else {
@ -220,7 +221,7 @@ impl PacketRead for VarInt {
let byte = u8::read(read)?;
val |= (i32::from(byte) & 0x7F) << (i * 7);
if byte & 0x80 == 0 {
return Ok(VarInt((val >> 1) ^ (val << 31)));
return Ok(Self((val >> 1) ^ (val << 31)));
}
}
Err(Error::new(ErrorKind::InvalidData, ""))

View File

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

View File

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

View File

@ -27,8 +27,9 @@ impl VarULong {
/// The maximum number of bytes a `VarULong` can occupy.
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.
#[must_use]
pub fn written_size(&self) -> usize {
match self.0 {
0 => 1,
@ -56,9 +57,9 @@ impl VarULong {
let mut val = 0;
for i in 0..Self::MAX_SIZE.get() {
let byte = read.get_u8()?;
val |= (u64::from(byte) & 0b01111111) << (i * 7);
if byte & 0b10000000 == 0 {
return Ok(VarULong(val));
val |= (u64::from(byte) & 0b0111_1111) << (i * 7);
if byte & 0b1000_0000 == 0 {
return Ok(Self(val));
}
}
Err(ReadingError::TooLarge("VarLong".to_string()))
@ -67,25 +68,25 @@ impl VarULong {
impl From<u64> for VarULong {
fn from(value: u64) -> Self {
VarULong(value)
Self(value)
}
}
impl From<u32> for VarULong {
fn from(value: u32) -> Self {
VarULong(value as u64)
Self(u64::from(value))
}
}
impl From<u8> for VarULong {
fn from(value: u8) -> Self {
VarULong(value as u64)
Self(u64::from(value))
}
}
impl From<usize> for VarULong {
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;
for i in 0..VarULong::MAX_SIZE.get() {
if let Some(byte) = seq.next_element::<u8>()? {
val |= (u64::from(byte) & 0b01111111) << (i * 7);
if byte & 0b10000000 == 0 {
val |= (u64::from(byte) & 0b0111_1111) << (i * 7);
if byte & 0b1000_0000 == 0 {
return Ok(VarULong(val));
}
} else {
@ -178,9 +179,9 @@ impl PacketRead for VarULong {
let mut val = 0;
for i in 0..Self::MAX_SIZE.get() {
let byte = u8::read(reader)?;
val |= (u64::from(byte) & 0b01111111) << (i * 7);
if byte & 0b10000000 == 0 {
return Ok(VarULong(val));
val |= (u64::from(byte) & 0b0111_1111) << (i * 7);
if byte & 0b1000_0000 == 0 {
return Ok(Self(val));
}
}
Err(Error::other("Invalid VarUInt"))

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