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:
parent
3776b225e4
commit
fb13004b47
46
Cargo.toml
46
Cargo.toml
@ -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"
|
||||
|
||||
@ -12,3 +12,6 @@ syn .workspace = true
|
||||
quote.workspace = true
|
||||
proc-macro2.workspace = true
|
||||
proc-macro-error2.workspace = true
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
@ -15,3 +15,6 @@ toml.workspace = true
|
||||
[features]
|
||||
# Adds helper to change the config at runtime
|
||||
test_helper = []
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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"
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -14,7 +14,7 @@ impl Default for CompressionConfig {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
enabled: true,
|
||||
info: Default::default(),
|
||||
info: CompressionInfo::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -11,6 +11,7 @@ pub struct Op {
|
||||
}
|
||||
|
||||
impl Op {
|
||||
#[must_use]
|
||||
pub fn new(
|
||||
uuid: Uuid,
|
||||
name: String,
|
||||
|
||||
@ -30,6 +30,6 @@ impl ResourcePackConfig {
|
||||
assert!(
|
||||
hash_len == 40,
|
||||
"Resource pack SHA1 hash is the wrong length (should be 40, is {hash_len})"
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@ -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(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -36,3 +36,7 @@ criterion.workspace = true
|
||||
[[bench]]
|
||||
name = "has_random_ticks"
|
||||
harness = false
|
||||
|
||||
# Generated files generate a lot of warns
|
||||
# [lints]
|
||||
# workspace = true
|
||||
@ -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! {
|
||||
|
||||
@ -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();
|
||||
|
||||
@ -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 = if let Some(opacity) = self.opacity {
|
||||
let opacity = LitInt::new(&opacity.to_string(), Span::call_site());
|
||||
quote! { #opacity }
|
||||
}
|
||||
None => quote! { 0 },
|
||||
} 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());
|
||||
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 }
|
||||
}
|
||||
None => quote! { u16::MAX },
|
||||
} 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 experience = if let Some(exp) = &self.experience {
|
||||
let exp_tokens = exp.to_token_stream();
|
||||
quote! { Some(#exp_tokens) }
|
||||
}
|
||||
None => quote! { None },
|
||||
} 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 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) }
|
||||
}
|
||||
None => quote! { None },
|
||||
} 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 = if let Some(flammable) = &self.flammable {
|
||||
let flammable_tokens = flammable.to_token_stream();
|
||||
quote! { Some(#flammable_tokens) }
|
||||
}
|
||||
None => quote! { None },
|
||||
} 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}"),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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());
|
||||
|
||||
@ -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! {
|
||||
|
||||
@ -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 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 }
|
||||
}
|
||||
None => quote! { DeathMessageType::Default },
|
||||
} else {
|
||||
quote! { DeathMessageType::Default }
|
||||
};
|
||||
|
||||
let effects = match &data.effects {
|
||||
Some(msg) => {
|
||||
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) }
|
||||
}
|
||||
None => quote! { None },
|
||||
} else {
|
||||
quote! { None }
|
||||
};
|
||||
|
||||
let exhaustion = data.exhaustion;
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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! {
|
||||
|
||||
@ -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! {
|
||||
|
||||
@ -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! {
|
||||
|
||||
@ -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 loot_table = if let Some(table) = &entity.loot_table {
|
||||
let table_tokens = table.to_token_stream();
|
||||
quote! { Some(#table_tokens) }
|
||||
}
|
||||
None => quote! { None },
|
||||
} 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());
|
||||
|
||||
@ -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!(
|
||||
assert!(
|
||||
expected_values == &property.values,
|
||||
"Enum overlap for '{}' ({:?} vs {:?})",
|
||||
property.name, &property.values, expected_values
|
||||
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};
|
||||
|
||||
@ -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) => {
|
||||
let speed = if let Some(speed) = rule.speed {
|
||||
quote! { Some(#speed) }
|
||||
}
|
||||
None => quote! { None },
|
||||
} else {
|
||||
quote! { None }
|
||||
};
|
||||
let correct_for_drops = match rule.correct_for_drops {
|
||||
Some(correct_for_drops) => {
|
||||
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) }
|
||||
}
|
||||
None => quote! { None },
|
||||
} 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
|
||||
}), });
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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();
|
||||
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),*]) }
|
||||
}
|
||||
None => quote! { None },
|
||||
} 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();
|
||||
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),*]) }
|
||||
}
|
||||
None => quote! { None },
|
||||
} else {
|
||||
quote! { None }
|
||||
};
|
||||
let functions_tokens = match &self.functions {
|
||||
Some(fns) => {
|
||||
let cond_tokens: Vec<_> = fns.iter().map(|c| c.to_token_stream()).collect();
|
||||
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),*]) }
|
||||
}
|
||||
None => quote! { None },
|
||||
} 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();
|
||||
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),*]) }
|
||||
}
|
||||
None => quote! { None },
|
||||
} 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 parameters = if let Some(params) = parameters {
|
||||
let params = params.to_token_stream();
|
||||
quote! { Some(#params) }
|
||||
}
|
||||
None => quote! { None },
|
||||
} 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();
|
||||
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),*]) }
|
||||
}
|
||||
None => quote! { None },
|
||||
} else {
|
||||
quote! { None }
|
||||
};
|
||||
let functions_tokens = match &self.functions {
|
||||
Some(fns) => {
|
||||
let cond_tokens: Vec<_> = fns.iter().map(|c| c.to_token_stream()).collect();
|
||||
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),*]) }
|
||||
}
|
||||
None => quote! { None },
|
||||
} 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);
|
||||
|
||||
@ -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! {
|
||||
|
||||
@ -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());
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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();
|
||||
|
||||
|
||||
@ -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 }
|
||||
}
|
||||
};
|
||||
|
||||
@ -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");
|
||||
|
||||
|
||||
@ -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,
|
||||
})
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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)
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -15,3 +15,6 @@ log.workspace = true
|
||||
tokio.workspace = true
|
||||
thiserror.workspace = true
|
||||
crossbeam-utils.workspace = true
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
@ -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 = 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 = 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),
|
||||
|
||||
@ -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();
|
||||
}
|
||||
})
|
||||
|
||||
@ -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(),
|
||||
};
|
||||
|
||||
@ -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 {}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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(
|
||||
|
||||
@ -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(
|
||||
|
||||
@ -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();
|
||||
}
|
||||
})
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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(),
|
||||
|
||||
@ -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
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@ -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,
|
||||
};
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -15,3 +15,6 @@ pumpkin-data.workspace = true
|
||||
proc-macro2.workspace = true
|
||||
quote.workspace = true
|
||||
syn.workspace = true
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
@ -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 => {
|
||||
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
|
||||
}
|
||||
|
||||
@ -14,3 +14,6 @@ flate2.workspace = true
|
||||
|
||||
[dev-dependencies]
|
||||
tempfile.workspace = true
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
@ -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("]")
|
||||
}
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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]
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -122,7 +122,7 @@ 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})"
|
||||
@ -135,7 +135,6 @@ impl<W: Write> Serializer<W> {
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
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,17 +199,16 @@ 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(),
|
||||
)),
|
||||
_ => {
|
||||
))
|
||||
} else {
|
||||
self.parse_state(BYTE_ID)?;
|
||||
self.output.write_u8_be(v)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn serialize_u16(self, v: u16) -> Result<()> {
|
||||
self.serialize_i16(v as i16)
|
||||
@ -336,8 +334,7 @@ impl<W: Write> ser::Serializer for &mut Serializer<W> {
|
||||
return Err(Error::LargeLength(len));
|
||||
}
|
||||
|
||||
match &mut self.state {
|
||||
State::Array { array_type, .. } => {
|
||||
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),
|
||||
@ -355,8 +352,7 @@ impl<W: Write> ser::Serializer for &mut Serializer<W> {
|
||||
// We can mark anything as an NBT array list, so mark as needed to be checked.
|
||||
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 {
|
||||
@ -366,7 +362,6 @@ impl<W: Write> ser::Serializer for &mut Serializer<W> {
|
||||
self.output.write_i32_be(0)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(self)
|
||||
}
|
||||
|
||||
@ -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}"
|
||||
))),
|
||||
}
|
||||
}
|
||||
|
||||
@ -36,3 +36,6 @@ bitflags.workspace = true
|
||||
[dev-dependencies]
|
||||
# Validate correctness
|
||||
flate2.workspace = true
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -13,6 +13,7 @@ pub struct CDisconnectPlayer {
|
||||
}
|
||||
|
||||
impl CDisconnectPlayer {
|
||||
#[must_use]
|
||||
pub fn new(reason: i32, message: String) -> Self {
|
||||
Self {
|
||||
reason: VarInt(reason),
|
||||
|
||||
@ -8,6 +8,7 @@ pub struct CHandshake {
|
||||
}
|
||||
|
||||
impl CHandshake {
|
||||
#[must_use]
|
||||
pub fn new(jwt_data: String) -> Self {
|
||||
Self { jwt_data }
|
||||
}
|
||||
|
||||
@ -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,
|
||||
}
|
||||
|
||||
@ -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 => (),
|
||||
|
||||
@ -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),
|
||||
|
||||
@ -13,6 +13,7 @@ pub struct CNetworkSettings {
|
||||
}
|
||||
|
||||
impl CNetworkSettings {
|
||||
#[must_use]
|
||||
pub fn new(
|
||||
compression_threshold: u16,
|
||||
compression_method: u16,
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -17,6 +17,7 @@ pub struct CResourcePackStackPacket {
|
||||
}
|
||||
|
||||
impl CResourcePackStackPacket {
|
||||
#[must_use]
|
||||
pub fn new(
|
||||
resource_pack_required: bool,
|
||||
texture_pack_list_size: VarUInt,
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -71,6 +71,7 @@ pub enum MetadataValue {
|
||||
}
|
||||
|
||||
impl MetadataValue {
|
||||
#[must_use]
|
||||
pub fn type_id(&self) -> u32 {
|
||||
match self {
|
||||
Self::Byte(_) => 0,
|
||||
|
||||
@ -9,6 +9,7 @@ pub struct CSetTime {
|
||||
}
|
||||
|
||||
impl CSetTime {
|
||||
#[must_use]
|
||||
pub const fn new(time: i32) -> Self {
|
||||
Self { time: VarInt(time) }
|
||||
}
|
||||
|
||||
@ -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() {
|
||||
|
||||
@ -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,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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(),
|
||||
})
|
||||
}
|
||||
|
||||
@ -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(
|
||||
|
||||
@ -13,6 +13,7 @@ pub struct SLoadingScreen {
|
||||
}
|
||||
|
||||
impl SLoadingScreen {
|
||||
#[must_use]
|
||||
pub fn is_loading_done(&self) -> bool {
|
||||
self.status.0 == 2
|
||||
}
|
||||
|
||||
@ -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}"),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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()))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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)?;
|
||||
|
||||
@ -71,7 +71,7 @@ impl DataComponentCodec<Self> for EnchantmentsImpl {
|
||||
"EnchantmentsImpl Enchantment VarInt Incorrect!",
|
||||
))?,
|
||||
level,
|
||||
))
|
||||
));
|
||||
}
|
||||
Ok(Self {
|
||||
enchantment: Cow::from(enc),
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@ -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])))
|
||||
}
|
||||
}
|
||||
|
||||
@ -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, ""))
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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, ""))
|
||||
|
||||
@ -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
Loading…
Reference in New Issue
Block a user