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",
|
"pumpkin-data",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
[workspace.lints.clippy]
|
||||||
|
# Groups
|
||||||
|
all = { level = "deny", priority = -1 }
|
||||||
|
# nursery = { level = "deny", priority = -1 }
|
||||||
|
pedantic = { level = "deny", priority = -1 }
|
||||||
|
cargo = { level = "deny", priority = -1 }
|
||||||
|
|
||||||
|
if_then_some_else_none = "deny"
|
||||||
|
empty_enum_variants_with_brackets = "deny"
|
||||||
|
empty_structs_with_brackets = "deny"
|
||||||
|
separated_literal_suffix = "deny"
|
||||||
|
semicolon_outside_block = "deny"
|
||||||
|
non_zero_suggestions = "deny"
|
||||||
|
string_lit_chars_any = "deny"
|
||||||
|
use_self = "deny"
|
||||||
|
useless_let_if_seq = "deny"
|
||||||
|
branches_sharing_code = "deny"
|
||||||
|
equatable_if_let = "deny"
|
||||||
|
option_if_let_else = "deny"
|
||||||
|
needless_pass_by_ref_mut = "deny"
|
||||||
|
needless_collect = "deny"
|
||||||
|
redundant_clone = "deny"
|
||||||
|
set_contains_or_insert = "deny"
|
||||||
|
significant_drop_in_scrutinee = "deny"
|
||||||
|
print_stdout = "deny"
|
||||||
|
print_stderr = "deny"
|
||||||
|
|
||||||
|
# Expected/Allowed
|
||||||
|
cargo_common_metadata = "allow"
|
||||||
|
cast_precision_loss = "allow"
|
||||||
|
multiple_crate_versions = "allow"
|
||||||
|
single_call_fn = "allow"
|
||||||
|
unreadable_literal = "allow"
|
||||||
|
cast_lossless = "allow"
|
||||||
|
cast_sign_loss = "allow"
|
||||||
|
float_cmp = "allow"
|
||||||
|
cast_possible_truncation = "allow"
|
||||||
|
cast_possible_wrap = "allow"
|
||||||
|
missing_panics_doc = "allow"
|
||||||
|
missing_errors_doc = "allow"
|
||||||
|
module_name_repetitions = "allow"
|
||||||
|
struct_excessive_bools = "allow"
|
||||||
|
|
||||||
[workspace.package]
|
[workspace.package]
|
||||||
version = "0.1.0-dev+1.21.11"
|
version = "0.1.0-dev+1.21.11"
|
||||||
edition = "2024"
|
edition = "2024"
|
||||||
@ -108,7 +152,7 @@ take_mut = "0.2.2"
|
|||||||
temp-dir = "0.1.16"
|
temp-dir = "0.1.16"
|
||||||
thread_local = "1.1.9"
|
thread_local = "1.1.9"
|
||||||
time = "0.3"
|
time = "0.3"
|
||||||
arc-swap = "1.7"
|
arc-swap = "1.8"
|
||||||
tokio-util = "0.7.18"
|
tokio-util = "0.7.18"
|
||||||
toml = "0.9"
|
toml = "0.9"
|
||||||
ureq = "3.1.4"
|
ureq = "3.1.4"
|
||||||
|
|||||||
@ -12,3 +12,6 @@ syn .workspace = true
|
|||||||
quote.workspace = true
|
quote.workspace = true
|
||||||
proc-macro2.workspace = true
|
proc-macro2.workspace = true
|
||||||
proc-macro-error2.workspace = true
|
proc-macro-error2.workspace = true
|
||||||
|
|
||||||
|
[lints]
|
||||||
|
workspace = true
|
||||||
|
|||||||
@ -15,3 +15,6 @@ toml.workspace = true
|
|||||||
[features]
|
[features]
|
||||||
# Adds helper to change the config at runtime
|
# Adds helper to change the config at runtime
|
||||||
test_helper = []
|
test_helper = []
|
||||||
|
|
||||||
|
[lints]
|
||||||
|
workspace = true
|
||||||
|
|||||||
@ -13,7 +13,7 @@ pub enum ChunkConfig {
|
|||||||
|
|
||||||
impl Default for ChunkConfig {
|
impl Default for ChunkConfig {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self::Anvil(Default::default())
|
Self::Anvil(AnvilChunkConfig::default())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -41,9 +41,9 @@ impl Default for ChunkCompression {
|
|||||||
|
|
||||||
#[derive(Deserialize, Serialize, Clone, Copy)]
|
#[derive(Deserialize, Serialize, Clone, Copy)]
|
||||||
pub enum Compression {
|
pub enum Compression {
|
||||||
/// GZip Compression
|
/// `GZip` Compression
|
||||||
GZip,
|
GZip,
|
||||||
/// ZLib Compression
|
/// `ZLib` Compression
|
||||||
ZLib,
|
ZLib,
|
||||||
/// LZ4 Compression (since 24w04a)
|
/// LZ4 Compression (since 24w04a)
|
||||||
LZ4,
|
LZ4,
|
||||||
|
|||||||
@ -149,12 +149,16 @@ impl Default for BasicConfiguration {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl BasicConfiguration {
|
impl BasicConfiguration {
|
||||||
|
#[must_use]
|
||||||
pub fn get_world_path(&self) -> PathBuf {
|
pub fn get_world_path(&self) -> PathBuf {
|
||||||
PathBuf::from(&self.default_level_name)
|
PathBuf::from(&self.default_level_name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait LoadConfiguration {
|
pub trait LoadConfiguration {
|
||||||
|
#[must_use]
|
||||||
|
// Logger is may not ready
|
||||||
|
#[expect(clippy::print_stdout)]
|
||||||
fn load(config_dir: &Path) -> Self
|
fn load(config_dir: &Path) -> Self
|
||||||
where
|
where
|
||||||
Self: Sized + Default + Serialize + DeserializeOwned,
|
Self: Sized + Default + Serialize + DeserializeOwned,
|
||||||
@ -166,14 +170,15 @@ pub trait LoadConfiguration {
|
|||||||
let path = config_dir.join(Self::get_path());
|
let path = config_dir.join(Self::get_path());
|
||||||
|
|
||||||
let config = if path.exists() {
|
let config = if path.exists() {
|
||||||
let file_content = fs::read_to_string(&path)
|
let file_content = fs::read_to_string(&path).unwrap_or_else(|_| {
|
||||||
.unwrap_or_else(|_| panic!("Couldn't read configuration file at {:?}", &path));
|
panic!("Couldn't read configuration file at {}", path.display())
|
||||||
|
});
|
||||||
|
|
||||||
let parsed_toml_value: toml::Value = toml::from_str(&file_content)
|
let parsed_toml_value: toml::Value = toml::from_str(&file_content)
|
||||||
.unwrap_or_else(|err| {
|
.unwrap_or_else(|err| {
|
||||||
panic!(
|
panic!(
|
||||||
"Couldn't parse TOML at {:?}. Reason: {}. This is probably caused by invalid TOML syntax",
|
"Couldn't parse TOML at {}. Reason: {}. This is probably caused by invalid TOML syntax",
|
||||||
&path, err
|
path.display(), err
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -186,8 +191,8 @@ pub trait LoadConfiguration {
|
|||||||
);
|
);
|
||||||
if let Err(err) = fs::write(&path, toml::to_string(&merged_config).unwrap()) {
|
if let Err(err) = fs::write(&path, toml::to_string(&merged_config).unwrap()) {
|
||||||
log::warn!(
|
log::warn!(
|
||||||
"Couldn't write merged config to {:?}. Reason: {}",
|
"Couldn't write merged config to {}. Reason: {}",
|
||||||
&path,
|
path.display(),
|
||||||
err
|
err
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -200,7 +205,7 @@ pub trait LoadConfiguration {
|
|||||||
if let Err(err) = fs::write(&path, toml::to_string(&content).unwrap()) {
|
if let Err(err) = fs::write(&path, toml::to_string(&content).unwrap()) {
|
||||||
log::warn!(
|
log::warn!(
|
||||||
"Couldn't write default config to {:?}. Reason: {}",
|
"Couldn't write default config to {:?}. Reason: {}",
|
||||||
&path,
|
path.display(),
|
||||||
err
|
err
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -212,6 +217,7 @@ pub trait LoadConfiguration {
|
|||||||
config
|
config
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
fn merge_with_default_toml(parsed_toml: toml::Value) -> (Self, bool)
|
fn merge_with_default_toml(parsed_toml: toml::Value) -> (Self, bool)
|
||||||
where
|
where
|
||||||
Self: Sized + Default + Serialize + DeserializeOwned,
|
Self: Sized + Default + Serialize + DeserializeOwned,
|
||||||
@ -221,8 +227,7 @@ pub trait LoadConfiguration {
|
|||||||
let default_toml_value =
|
let default_toml_value =
|
||||||
toml::Value::try_from(default_config).expect("Failed to parse default config");
|
toml::Value::try_from(default_config).expect("Failed to parse default config");
|
||||||
|
|
||||||
let (merged_value, changed) =
|
let (merged_value, changed) = Self::merge_toml_values(default_toml_value, parsed_toml);
|
||||||
Self::merge_toml_values(default_toml_value, parsed_toml.clone());
|
|
||||||
|
|
||||||
let config = merged_value
|
let config = merged_value
|
||||||
.try_into()
|
.try_into()
|
||||||
@ -231,6 +236,7 @@ pub trait LoadConfiguration {
|
|||||||
(config, changed)
|
(config, changed)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
fn merge_toml_values(base: toml::Value, overlay: toml::Value) -> (toml::Value, bool) {
|
fn merge_toml_values(base: toml::Value, overlay: toml::Value) -> (toml::Value, bool) {
|
||||||
match (base, overlay) {
|
match (base, overlay) {
|
||||||
(toml::Value::Table(mut base_table), toml::Value::Table(overlay_table)) => {
|
(toml::Value::Table(mut base_table), toml::Value::Table(overlay_table)) => {
|
||||||
@ -272,7 +278,7 @@ impl LoadConfiguration for AdvancedConfiguration {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn validate(&self) {
|
fn validate(&self) {
|
||||||
self.resource_pack.validate()
|
self.resource_pack.validate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -297,13 +303,13 @@ impl LoadConfiguration for BasicConfiguration {
|
|||||||
assert!(
|
assert!(
|
||||||
self.encryption,
|
self.encryption,
|
||||||
"When online mode is enabled, encryption must be enabled"
|
"When online mode is enabled, encryption must be enabled"
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
if self.allow_chat_reports {
|
if self.allow_chat_reports {
|
||||||
assert!(
|
assert!(
|
||||||
self.online_mode,
|
self.online_mode,
|
||||||
"When allow_chat_reports is enabled, online_mode must be enabled"
|
"When allow_chat_reports is enabled, online_mode must be enabled"
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -24,8 +24,8 @@ impl Default for AuthenticationConfig {
|
|||||||
Self {
|
Self {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
prevent_proxy_connections: false,
|
prevent_proxy_connections: false,
|
||||||
player_profile: Default::default(),
|
player_profile: PlayerProfileConfig::default(),
|
||||||
textures: Default::default(),
|
textures: TextureConfig::default(),
|
||||||
url: None,
|
url: None,
|
||||||
prevent_proxy_connection_auth_url: None,
|
prevent_proxy_connection_auth_url: None,
|
||||||
services_url: None,
|
services_url: None,
|
||||||
@ -75,7 +75,7 @@ impl Default for TextureConfig {
|
|||||||
enabled: true,
|
enabled: true,
|
||||||
allowed_url_schemes: vec!["http".into(), "https".into()],
|
allowed_url_schemes: vec!["http".into(), "https".into()],
|
||||||
allowed_url_domains: vec![".minecraft.net".into(), ".mojang.com".into()],
|
allowed_url_domains: vec![".minecraft.net".into(), ".mojang.com".into()],
|
||||||
types: Default::default(),
|
types: TextureTypes::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -14,7 +14,7 @@ impl Default for CompressionConfig {
|
|||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
info: Default::default(),
|
info: CompressionInfo::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -13,7 +13,7 @@ impl Default for QueryConfig {
|
|||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
address: SocketAddr::new(Ipv4Addr::new(0, 0, 0, 0).into(), 25565),
|
address: SocketAddr::new(Ipv4Addr::UNSPECIFIED.into(), 25565),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -21,10 +21,10 @@ impl Default for RCONConfig {
|
|||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self {
|
Self {
|
||||||
enabled: false,
|
enabled: false,
|
||||||
address: SocketAddr::new(Ipv4Addr::new(0, 0, 0, 0).into(), 25575),
|
address: SocketAddr::new(Ipv4Addr::UNSPECIFIED.into(), 25575),
|
||||||
password: "".to_string(),
|
password: String::new(),
|
||||||
max_connections: 0,
|
max_connections: 0,
|
||||||
logging: Default::default(),
|
logging: RCONLogging::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -11,6 +11,7 @@ pub struct Op {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Op {
|
impl Op {
|
||||||
|
#[must_use]
|
||||||
pub fn new(
|
pub fn new(
|
||||||
uuid: Uuid,
|
uuid: Uuid,
|
||||||
name: String,
|
name: String,
|
||||||
|
|||||||
@ -30,6 +30,6 @@ impl ResourcePackConfig {
|
|||||||
assert!(
|
assert!(
|
||||||
hash_len == 40,
|
hash_len == 40,
|
||||||
"Resource pack SHA1 hash is the wrong length (should be 40, is {hash_len})"
|
"Resource pack SHA1 hash is the wrong length (should be 40, is {hash_len})"
|
||||||
)
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -22,15 +22,15 @@ impl Default for ServerLinksConfig {
|
|||||||
Self {
|
Self {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
bug_report: "https://github.com/Pumpkin-MC/Pumpkin/issues".to_string(),
|
bug_report: "https://github.com/Pumpkin-MC/Pumpkin/issues".to_string(),
|
||||||
support: "".to_string(),
|
support: String::new(),
|
||||||
status: "".to_string(),
|
status: String::new(),
|
||||||
feedback: "".to_string(),
|
feedback: String::new(),
|
||||||
community: "".to_string(),
|
community: String::new(),
|
||||||
website: "".to_string(),
|
website: String::new(),
|
||||||
forums: "".to_string(),
|
forums: String::new(),
|
||||||
news: "".to_string(),
|
news: String::new(),
|
||||||
announcements: "".to_string(),
|
announcements: String::new(),
|
||||||
custom: Default::default(),
|
custom: HashMap::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -36,3 +36,7 @@ criterion.workspace = true
|
|||||||
[[bench]]
|
[[bench]]
|
||||||
name = "has_random_ticks"
|
name = "has_random_ticks"
|
||||||
harness = false
|
harness = false
|
||||||
|
|
||||||
|
# Generated files generate a lot of warns
|
||||||
|
# [lints]
|
||||||
|
# workspace = true
|
||||||
@ -111,7 +111,7 @@ enum BiomeTree {
|
|||||||
Branch {
|
Branch {
|
||||||
parameters: [ParameterRange; 7],
|
parameters: [ParameterRange; 7],
|
||||||
#[serde(rename = "subTree")]
|
#[serde(rename = "subTree")]
|
||||||
nodes: Box<[BiomeTree]>,
|
nodes: Box<[Self]>,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -126,7 +126,7 @@ impl BiomeTree {
|
|||||||
.unwrap()
|
.unwrap()
|
||||||
.to_shouty_snake_case()
|
.to_shouty_snake_case()
|
||||||
);
|
);
|
||||||
let parameters = parameters.map(|range| range.into_token_stream());
|
let parameters = parameters.map(ParameterRange::into_token_stream);
|
||||||
quote! {
|
quote! {
|
||||||
BiomeTree::Leaf {
|
BiomeTree::Leaf {
|
||||||
parameters: [#(#parameters),*],
|
parameters: [#(#parameters),*],
|
||||||
@ -137,9 +137,9 @@ impl BiomeTree {
|
|||||||
Self::Branch { parameters, nodes } => {
|
Self::Branch { parameters, nodes } => {
|
||||||
let nodes = nodes
|
let nodes = nodes
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|node| node.into_token_stream())
|
.map(Self::into_token_stream)
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
let parameters = parameters.map(|range| range.into_token_stream());
|
let parameters = parameters.map(ParameterRange::into_token_stream);
|
||||||
quote! {
|
quote! {
|
||||||
BiomeTree::Branch {
|
BiomeTree::Branch {
|
||||||
parameters: [#(#parameters),*],
|
parameters: [#(#parameters),*],
|
||||||
@ -172,7 +172,7 @@ pub(crate) fn build() -> TokenStream {
|
|||||||
let mut name_to_type = TokenStream::new();
|
let mut name_to_type = TokenStream::new();
|
||||||
let mut id_to_type = TokenStream::new();
|
let mut id_to_type = TokenStream::new();
|
||||||
|
|
||||||
for (name, biome) in biomes.into_iter() {
|
for (name, biome) in biomes {
|
||||||
// let full_name = format!("minecraft:{name}");
|
// let full_name = format!("minecraft:{name}");
|
||||||
let format_name = format_ident!("{}", name.to_shouty_snake_case());
|
let format_name = format_ident!("{}", name.to_shouty_snake_case());
|
||||||
let has_precipitation = biome.has_precipitation;
|
let has_precipitation = biome.has_precipitation;
|
||||||
@ -190,44 +190,44 @@ pub(crate) fn build() -> TokenStream {
|
|||||||
.spawners
|
.spawners
|
||||||
.monster
|
.monster
|
||||||
.iter()
|
.iter()
|
||||||
.map(|s| s.to_tokens())
|
.map(Spawner::to_tokens)
|
||||||
.collect();
|
.collect();
|
||||||
let ambient: Vec<_> = biome
|
let ambient: Vec<_> = biome
|
||||||
.spawners
|
.spawners
|
||||||
.ambient
|
.ambient
|
||||||
.iter()
|
.iter()
|
||||||
.map(|s| s.to_tokens())
|
.map(Spawner::to_tokens)
|
||||||
.collect();
|
.collect();
|
||||||
let axolotls: Vec<_> = biome
|
let axolotls: Vec<_> = biome
|
||||||
.spawners
|
.spawners
|
||||||
.axolotls
|
.axolotls
|
||||||
.iter()
|
.iter()
|
||||||
.map(|s| s.to_tokens())
|
.map(Spawner::to_tokens)
|
||||||
.collect();
|
.collect();
|
||||||
let creature: Vec<_> = biome
|
let creature: Vec<_> = biome
|
||||||
.spawners
|
.spawners
|
||||||
.creature
|
.creature
|
||||||
.iter()
|
.iter()
|
||||||
.map(|s| s.to_tokens())
|
.map(Spawner::to_tokens)
|
||||||
.collect();
|
.collect();
|
||||||
let misc: Vec<_> = biome.spawners.misc.iter().map(|s| s.to_tokens()).collect();
|
let misc: Vec<_> = biome.spawners.misc.iter().map(Spawner::to_tokens).collect();
|
||||||
let underground_water_creature: Vec<_> = biome
|
let underground_water_creature: Vec<_> = biome
|
||||||
.spawners
|
.spawners
|
||||||
.underground_water_creature
|
.underground_water_creature
|
||||||
.iter()
|
.iter()
|
||||||
.map(|s| s.to_tokens())
|
.map(Spawner::to_tokens)
|
||||||
.collect();
|
.collect();
|
||||||
let water_ambient: Vec<_> = biome
|
let water_ambient: Vec<_> = biome
|
||||||
.spawners
|
.spawners
|
||||||
.water_ambient
|
.water_ambient
|
||||||
.iter()
|
.iter()
|
||||||
.map(|s| s.to_tokens())
|
.map(Spawner::to_tokens)
|
||||||
.collect();
|
.collect();
|
||||||
let water_creature: Vec<_> = biome
|
let water_creature: Vec<_> = biome
|
||||||
.spawners
|
.spawners
|
||||||
.water_creature
|
.water_creature
|
||||||
.iter()
|
.iter()
|
||||||
.map(|s| s.to_tokens())
|
.map(Spawner::to_tokens)
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
let spawners = quote! {
|
let spawners = quote! {
|
||||||
|
|||||||
@ -17,7 +17,7 @@ pub fn gen_u16_bitset(name: &str, ids: &[u16]) -> Bitset {
|
|||||||
let mut bitset = vec![0u64; words];
|
let mut bitset = vec![0u64; words];
|
||||||
for &id in ids {
|
for &id in ids {
|
||||||
let index = (id as usize) >> 6;
|
let index = (id as usize) >> 6;
|
||||||
let bit = (id as u32) & 63;
|
let bit = u32::from(id) & 63;
|
||||||
bitset[index] |= 1u64 << bit;
|
bitset[index] |= 1u64 << bit;
|
||||||
}
|
}
|
||||||
let name_uppercase = name.to_uppercase();
|
let name_uppercase = name.to_uppercase();
|
||||||
|
|||||||
@ -418,11 +418,11 @@ pub enum PistonBehavior {
|
|||||||
impl PistonBehavior {
|
impl PistonBehavior {
|
||||||
fn to_tokens(&self) -> TokenStream {
|
fn to_tokens(&self) -> TokenStream {
|
||||||
match self {
|
match self {
|
||||||
PistonBehavior::Normal => quote! { PistonBehavior::Normal },
|
Self::Normal => quote! { PistonBehavior::Normal },
|
||||||
PistonBehavior::Destroy => quote! { PistonBehavior::Destroy },
|
Self::Destroy => quote! { PistonBehavior::Destroy },
|
||||||
PistonBehavior::Block => quote! { PistonBehavior::Block },
|
Self::Block => quote! { PistonBehavior::Block },
|
||||||
PistonBehavior::Ignore => quote! { PistonBehavior::Ignore },
|
Self::Ignore => quote! { PistonBehavior::Ignore },
|
||||||
PistonBehavior::PushOnly => quote! { PistonBehavior::PushOnly },
|
Self::PushOnly => quote! { PistonBehavior::PushOnly },
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -447,20 +447,17 @@ impl BlockState {
|
|||||||
let instrument = format_ident!("{}", self.instrument.to_upper_camel_case());
|
let instrument = format_ident!("{}", self.instrument.to_upper_camel_case());
|
||||||
let luminance = LitInt::new(&self.luminance.to_string(), Span::call_site());
|
let luminance = LitInt::new(&self.luminance.to_string(), Span::call_site());
|
||||||
let hardness = self.hardness;
|
let hardness = self.hardness;
|
||||||
let opacity = match self.opacity {
|
let opacity = if let Some(opacity) = self.opacity {
|
||||||
Some(opacity) => {
|
let opacity = LitInt::new(&opacity.to_string(), Span::call_site());
|
||||||
let opacity = LitInt::new(&opacity.to_string(), Span::call_site());
|
quote! { #opacity }
|
||||||
quote! { #opacity }
|
} else {
|
||||||
}
|
quote! { 0 }
|
||||||
None => quote! { 0 },
|
|
||||||
};
|
};
|
||||||
let block_entity_type = match self.block_entity_type {
|
let block_entity_type = if let Some(block_entity_type) = self.block_entity_type {
|
||||||
Some(block_entity_type) => {
|
let block_entity_type = LitInt::new(&block_entity_type.to_string(), Span::call_site());
|
||||||
let block_entity_type =
|
quote! { #block_entity_type }
|
||||||
LitInt::new(&block_entity_type.to_string(), Span::call_site());
|
} else {
|
||||||
quote! { #block_entity_type }
|
quote! { u16::MAX }
|
||||||
}
|
|
||||||
None => quote! { u16::MAX },
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let collision_shapes = self
|
let collision_shapes = self
|
||||||
@ -522,21 +519,19 @@ impl ToTokens for Block {
|
|||||||
let slipperiness = &self.slipperiness;
|
let slipperiness = &self.slipperiness;
|
||||||
let velocity_multiplier = &self.velocity_multiplier;
|
let velocity_multiplier = &self.velocity_multiplier;
|
||||||
let jump_velocity_multiplier = &self.jump_velocity_multiplier;
|
let jump_velocity_multiplier = &self.jump_velocity_multiplier;
|
||||||
let experience = match &self.experience {
|
let experience = if let Some(exp) = &self.experience {
|
||||||
Some(exp) => {
|
let exp_tokens = exp.to_token_stream();
|
||||||
let exp_tokens = exp.to_token_stream();
|
quote! { Some(#exp_tokens) }
|
||||||
quote! { Some(#exp_tokens) }
|
} else {
|
||||||
}
|
quote! { None }
|
||||||
None => quote! { None },
|
|
||||||
};
|
};
|
||||||
// Generate state tokens
|
// Generate state tokens
|
||||||
let states = self.states.iter().map(|state| state.to_tokens());
|
let states = self.states.iter().map(BlockState::to_tokens);
|
||||||
let loot_table = match &self.loot_table {
|
let loot_table = if let Some(table) = &self.loot_table {
|
||||||
Some(table) => {
|
let table_tokens = table.to_token_stream();
|
||||||
let table_tokens = table.to_token_stream();
|
quote! { Some(#table_tokens) }
|
||||||
quote! { Some(#table_tokens) }
|
} else {
|
||||||
}
|
quote! { None }
|
||||||
None => quote! { None },
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let default_state_ref: &BlockState = self
|
let default_state_ref: &BlockState = self
|
||||||
@ -547,12 +542,11 @@ impl ToTokens for Block {
|
|||||||
let mut default_state = default_state_ref.clone();
|
let mut default_state = default_state_ref.clone();
|
||||||
default_state.id = default_state_ref.id;
|
default_state.id = default_state_ref.id;
|
||||||
let default_state = default_state.to_tokens();
|
let default_state = default_state.to_tokens();
|
||||||
let flammable = match &self.flammable {
|
let flammable = if let Some(flammable) = &self.flammable {
|
||||||
Some(flammable) => {
|
let flammable_tokens = flammable.to_token_stream();
|
||||||
let flammable_tokens = flammable.to_token_stream();
|
quote! { Some(#flammable_tokens) }
|
||||||
quote! { Some(#flammable_tokens) }
|
} else {
|
||||||
}
|
quote! { None }
|
||||||
None => quote! { None },
|
|
||||||
};
|
};
|
||||||
tokens.extend(quote! {
|
tokens.extend(quote! {
|
||||||
Block {
|
Block {
|
||||||
@ -800,10 +794,12 @@ pub(crate) fn build() -> TokenStream {
|
|||||||
.find(|(_, be_props)| {
|
.find(|(_, be_props)| {
|
||||||
java_props_for_this_state
|
java_props_for_this_state
|
||||||
.iter()
|
.iter()
|
||||||
.all(|(k, v)| be_props.get(k).map(|be_v| be_v == v).unwrap_or(false))
|
.all(|(k, v)| be_props.get(k).is_some_and(|be_v| be_v == v))
|
||||||
})
|
})
|
||||||
.map(|(id, _)| *id)
|
.map_or_else(
|
||||||
.unwrap_or_else(|| be_variants.first().map(|(id, _)| *id).unwrap_or(1));
|
|| be_variants.first().map_or(1, |(id, _)| *id),
|
||||||
|
|(id, _)| *id,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
block_state_to_bedrock.push((state.id, matched_be_id));
|
block_state_to_bedrock.push((state.id, matched_be_id));
|
||||||
@ -861,12 +857,16 @@ pub(crate) fn build() -> TokenStream {
|
|||||||
let shapes = blocks_assets
|
let shapes = blocks_assets
|
||||||
.shapes
|
.shapes
|
||||||
.iter()
|
.iter()
|
||||||
.map(|shape| shape.to_token_stream());
|
.map(quote::ToTokens::to_token_stream);
|
||||||
|
|
||||||
let air_state_ids = quote! { #(#air_states)|* };
|
let air_state_ids = quote! { #(#air_states)|* };
|
||||||
|
|
||||||
let block_props = block_properties.iter().map(|prop| prop.to_token_stream());
|
let block_props = block_properties
|
||||||
let properties = property_enums.values().map(|prop| prop.to_token_stream());
|
.iter()
|
||||||
|
.map(quote::ToTokens::to_token_stream);
|
||||||
|
let properties = property_enums
|
||||||
|
.values()
|
||||||
|
.map(quote::ToTokens::to_token_stream);
|
||||||
|
|
||||||
let block_entity_types = blocks_assets
|
let block_entity_types = blocks_assets
|
||||||
.block_entity_types
|
.block_entity_types
|
||||||
@ -1181,11 +1181,7 @@ fn get_be_data_from_nbt<R: Read>(
|
|||||||
|
|
||||||
let read_byte_safe = |reader: &mut R| -> Option<u8> {
|
let read_byte_safe = |reader: &mut R| -> Option<u8> {
|
||||||
let mut buf = [0; 1];
|
let mut buf = [0; 1];
|
||||||
if reader.read_exact(&mut buf).is_ok() {
|
reader.read_exact(&mut buf).is_ok().then(|| buf[0])
|
||||||
Some(buf[0])
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
while let Some(tag_id) = read_byte_safe(reader) {
|
while let Some(tag_id) = read_byte_safe(reader) {
|
||||||
@ -1234,7 +1230,7 @@ fn get_be_data_from_nbt<R: Read>(
|
|||||||
}
|
}
|
||||||
3 => read_varint(reader).to_string(),
|
3 => read_varint(reader).to_string(),
|
||||||
8 => read_nbt_string(reader),
|
8 => read_nbt_string(reader),
|
||||||
_ => panic!("Unknown property type {} for key {}", prop_type, prop_key),
|
_ => panic!("Unknown property type {prop_type} for key {prop_key}"),
|
||||||
};
|
};
|
||||||
|
|
||||||
properties.insert(prop_key, prop_val);
|
properties.insert(prop_key, prop_val);
|
||||||
@ -1242,7 +1238,7 @@ fn get_be_data_from_nbt<R: Read>(
|
|||||||
"version" => {
|
"version" => {
|
||||||
read_varint(reader);
|
read_varint(reader);
|
||||||
}
|
}
|
||||||
_ => panic!("Unexpected root field: {}", field_name),
|
_ => panic!("Unexpected root field: {field_name}"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -55,7 +55,7 @@ pub const OUT_DIR: &str = "src/generated";
|
|||||||
|
|
||||||
pub fn main() {
|
pub fn main() {
|
||||||
if let Err(e) = fs::create_dir_all(OUT_DIR) {
|
if let Err(e) = fs::create_dir_all(OUT_DIR) {
|
||||||
eprintln!("Failed to create output directory {}: {}", OUT_DIR, e);
|
eprintln!("Failed to create output directory {OUT_DIR}: {e}");
|
||||||
}
|
}
|
||||||
|
|
||||||
type BuilderFn = fn() -> TokenStream;
|
type BuilderFn = fn() -> TokenStream;
|
||||||
@ -115,6 +115,7 @@ pub fn main() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub fn array_to_tokenstream(array: &[String]) -> TokenStream {
|
pub fn array_to_tokenstream(array: &[String]) -> TokenStream {
|
||||||
let variants = array.iter().map(|item| {
|
let variants = array.iter().map(|item| {
|
||||||
let name = format_ident!("{}", item.to_pascal_case());
|
let name = format_ident!("{}", item.to_pascal_case());
|
||||||
|
|||||||
@ -13,7 +13,7 @@ pub(crate) fn build() -> TokenStream {
|
|||||||
let variants: Vec<TokenStream> = chunk_status
|
let variants: Vec<TokenStream> = chunk_status
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|status| {
|
.map(|status| {
|
||||||
let full_name = format!("minecraft:{}", status);
|
let full_name = format!("minecraft:{status}");
|
||||||
let name = format_ident!("{}", status.to_pascal_case());
|
let name = format_ident!("{}", status.to_pascal_case());
|
||||||
|
|
||||||
quote! {
|
quote! {
|
||||||
|
|||||||
@ -66,20 +66,18 @@ pub(crate) fn build() -> TokenStream {
|
|||||||
});
|
});
|
||||||
|
|
||||||
let data = &entry.components;
|
let data = &entry.components;
|
||||||
let death_message_type = match &data.death_message_type {
|
let death_message_type = if let Some(msg) = &data.death_message_type {
|
||||||
Some(msg) => {
|
let msg_ident = Ident::new(&format!("{msg:?}"), proc_macro2::Span::call_site());
|
||||||
let msg_ident = Ident::new(&format!("{msg:?}"), proc_macro2::Span::call_site());
|
quote! { DeathMessageType::#msg_ident }
|
||||||
quote! { DeathMessageType::#msg_ident }
|
} else {
|
||||||
}
|
quote! { DeathMessageType::Default }
|
||||||
None => quote! { DeathMessageType::Default },
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let effects = match &data.effects {
|
let effects = if let Some(msg) = &data.effects {
|
||||||
Some(msg) => {
|
let msg_ident = Ident::new(&format!("{msg:?}"), proc_macro2::Span::call_site());
|
||||||
let msg_ident = Ident::new(&format!("{msg:?}"), proc_macro2::Span::call_site());
|
quote! { Some(DamageEffects::#msg_ident) }
|
||||||
quote! { Some(DamageEffects::#msg_ident) }
|
} else {
|
||||||
}
|
quote! { None }
|
||||||
None => quote! { None },
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let exhaustion = data.exhaustion;
|
let exhaustion = data.exhaustion;
|
||||||
|
|||||||
@ -22,7 +22,7 @@ pub(crate) fn build() -> TokenStream {
|
|||||||
let strip_name = raw_name
|
let strip_name = raw_name
|
||||||
.strip_prefix("minecraft:")
|
.strip_prefix("minecraft:")
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.replace("/", "_");
|
.replace('/', "_");
|
||||||
let pascal_case = format_ident!("{}", strip_name.to_pascal_case());
|
let pascal_case = format_ident!("{}", strip_name.to_pascal_case());
|
||||||
|
|
||||||
// Enum variant
|
// Enum variant
|
||||||
|
|||||||
@ -60,9 +60,10 @@ pub(crate) fn build() -> TokenStream {
|
|||||||
.to_shouty_snake_case()
|
.to_shouty_snake_case()
|
||||||
);
|
);
|
||||||
|
|
||||||
let fixed_time = match dim.fixed_time {
|
let fixed_time = if let Some(t) = dim.fixed_time {
|
||||||
Some(t) => quote! { Some(#t) },
|
quote! { Some(#t) }
|
||||||
None => quote! { None },
|
} else {
|
||||||
|
quote! { None }
|
||||||
};
|
};
|
||||||
|
|
||||||
let ambient_light = dim.ambient_light;
|
let ambient_light = dim.ambient_light;
|
||||||
@ -77,7 +78,7 @@ pub(crate) fn build() -> TokenStream {
|
|||||||
let minecraft_name = if name.contains(':') {
|
let minecraft_name = if name.contains(':') {
|
||||||
name.clone()
|
name.clone()
|
||||||
} else {
|
} else {
|
||||||
format!("minecraft:{}", name)
|
format!("minecraft:{name}")
|
||||||
};
|
};
|
||||||
|
|
||||||
variants.extend(quote! {
|
variants.extend(quote! {
|
||||||
|
|||||||
@ -51,9 +51,9 @@ impl Modifiers {
|
|||||||
impl MobEffectCategory {
|
impl MobEffectCategory {
|
||||||
pub fn to_tokens(&self) -> TokenStream {
|
pub fn to_tokens(&self) -> TokenStream {
|
||||||
match self {
|
match self {
|
||||||
MobEffectCategory::BENEFICIAL => quote! { MobEffectCategory::Beneficial },
|
Self::BENEFICIAL => quote! { MobEffectCategory::Beneficial },
|
||||||
MobEffectCategory::HARMFUL => quote! { MobEffectCategory::Harmful },
|
Self::HARMFUL => quote! { MobEffectCategory::Harmful },
|
||||||
MobEffectCategory::NEUTRAL => quote! { MobEffectCategory::Neutral },
|
Self::NEUTRAL => quote! { MobEffectCategory::Neutral },
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -69,14 +69,14 @@ pub(crate) fn build() -> TokenStream {
|
|||||||
let mut name_to_type = TokenStream::new();
|
let mut name_to_type = TokenStream::new();
|
||||||
let mut minecraft_name_to_type = TokenStream::new();
|
let mut minecraft_name_to_type = TokenStream::new();
|
||||||
|
|
||||||
for (name, effect) in effects.into_iter() {
|
for (name, effect) in effects {
|
||||||
let format_name = format_ident!("{}", name.to_shouty_snake_case());
|
let format_name = format_ident!("{}", name.to_shouty_snake_case());
|
||||||
let id = effect.id;
|
let id = effect.id;
|
||||||
let color = effect.color;
|
let color = effect.color;
|
||||||
let translation_key = effect.translation_key;
|
let translation_key = effect.translation_key;
|
||||||
let category = effect.category.to_tokens();
|
let category = effect.category.to_tokens();
|
||||||
let slots = effect.attribute_modifiers;
|
let slots = effect.attribute_modifiers;
|
||||||
let slots = slots.into_iter().map(|slot| slot.get_tokens());
|
let slots = slots.into_iter().map(Modifiers::get_tokens);
|
||||||
|
|
||||||
let minecraft_name = "minecraft:".to_string() + &name;
|
let minecraft_name = "minecraft:".to_string() + &name;
|
||||||
variants.extend([quote! {
|
variants.extend([quote! {
|
||||||
|
|||||||
@ -37,17 +37,17 @@ pub enum AttributeModifierSlot {
|
|||||||
impl AttributeModifierSlot {
|
impl AttributeModifierSlot {
|
||||||
pub fn to_tokens(&self) -> TokenStream {
|
pub fn to_tokens(&self) -> TokenStream {
|
||||||
match self {
|
match self {
|
||||||
AttributeModifierSlot::Any => quote! { AttributeModifierSlot::Any },
|
Self::Any => quote! { AttributeModifierSlot::Any },
|
||||||
AttributeModifierSlot::MainHand => quote! { AttributeModifierSlot::MainHand },
|
Self::MainHand => quote! { AttributeModifierSlot::MainHand },
|
||||||
AttributeModifierSlot::OffHand => quote! { AttributeModifierSlot::OffHand },
|
Self::OffHand => quote! { AttributeModifierSlot::OffHand },
|
||||||
AttributeModifierSlot::Hand => quote! { AttributeModifierSlot::Hand },
|
Self::Hand => quote! { AttributeModifierSlot::Hand },
|
||||||
AttributeModifierSlot::Feet => quote! { AttributeModifierSlot::Feet },
|
Self::Feet => quote! { AttributeModifierSlot::Feet },
|
||||||
AttributeModifierSlot::Legs => quote! { AttributeModifierSlot::Legs },
|
Self::Legs => quote! { AttributeModifierSlot::Legs },
|
||||||
AttributeModifierSlot::Chest => quote! { AttributeModifierSlot::Chest },
|
Self::Chest => quote! { AttributeModifierSlot::Chest },
|
||||||
AttributeModifierSlot::Head => quote! { AttributeModifierSlot::Head },
|
Self::Head => quote! { AttributeModifierSlot::Head },
|
||||||
AttributeModifierSlot::Armor => quote! { AttributeModifierSlot::Armor },
|
Self::Armor => quote! { AttributeModifierSlot::Armor },
|
||||||
AttributeModifierSlot::Body => quote! { AttributeModifierSlot::Body },
|
Self::Body => quote! { AttributeModifierSlot::Body },
|
||||||
AttributeModifierSlot::Saddle => quote! { AttributeModifierSlot::Saddle },
|
Self::Saddle => quote! { AttributeModifierSlot::Saddle },
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -63,7 +63,7 @@ pub(crate) fn build() -> TokenStream {
|
|||||||
let mut name_to_type = TokenStream::new();
|
let mut name_to_type = TokenStream::new();
|
||||||
let mut id_to_type = TokenStream::new();
|
let mut id_to_type = TokenStream::new();
|
||||||
|
|
||||||
for (name, enchantment) in enchantments.into_iter() {
|
for (name, enchantment) in enchantments {
|
||||||
let id = enchantment.id;
|
let id = enchantment.id;
|
||||||
let raw_name = name.strip_prefix("minecraft:").unwrap();
|
let raw_name = name.strip_prefix("minecraft:").unwrap();
|
||||||
let format_name = format_ident!("{}", raw_name.to_shouty_snake_case());
|
let format_name = format_ident!("{}", raw_name.to_shouty_snake_case());
|
||||||
@ -74,13 +74,12 @@ pub(crate) fn build() -> TokenStream {
|
|||||||
.supported_items
|
.supported_items
|
||||||
.strip_prefix("#")
|
.strip_prefix("#")
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.replace(":", "_")
|
.replace([':', '/'], "_")
|
||||||
.replace("/", "_")
|
|
||||||
.to_uppercase()
|
.to_uppercase()
|
||||||
);
|
);
|
||||||
let max_level = enchantment.max_level;
|
let max_level = enchantment.max_level;
|
||||||
let slots = enchantment.slots;
|
let slots = enchantment.slots;
|
||||||
let slots = slots.iter().map(|slot| slot.to_tokens());
|
let slots = slots.iter().map(AttributeModifierSlot::to_tokens);
|
||||||
let Translate { translate, with: _ } = &enchantment.description.0.content else {
|
let Translate { translate, with: _ } = &enchantment.description.0.content else {
|
||||||
panic!()
|
panic!()
|
||||||
};
|
};
|
||||||
@ -92,8 +91,7 @@ pub(crate) fn build() -> TokenStream {
|
|||||||
exclusive_set
|
exclusive_set
|
||||||
.strip_prefix("#")
|
.strip_prefix("#")
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.replace(":", "_")
|
.replace([':', '/'], "_")
|
||||||
.replace("/", "_")
|
|
||||||
.to_uppercase()
|
.to_uppercase()
|
||||||
);
|
);
|
||||||
variants.extend([quote! {
|
variants.extend([quote! {
|
||||||
|
|||||||
@ -63,14 +63,16 @@ impl ToTokens for NamedEntityType<'_> {
|
|||||||
let entity = self.1;
|
let entity = self.1;
|
||||||
let id = LitInt::new(&entity.id.to_string(), proc_macro2::Span::call_site());
|
let id = LitInt::new(&entity.id.to_string(), proc_macro2::Span::call_site());
|
||||||
|
|
||||||
let max_health = match entity.max_health {
|
let max_health = if let Some(mh) = entity.max_health {
|
||||||
Some(mh) => quote! { Some(#mh) },
|
quote! { Some(#mh) }
|
||||||
None => quote! { None },
|
} else {
|
||||||
|
quote! { None }
|
||||||
};
|
};
|
||||||
|
|
||||||
let attackable = match entity.attackable {
|
let attackable = if let Some(a) = entity.attackable {
|
||||||
Some(a) => quote! { Some(#a) },
|
quote! { Some(#a) }
|
||||||
None => quote! { None },
|
} else {
|
||||||
|
quote! { None }
|
||||||
};
|
};
|
||||||
|
|
||||||
let spawn_restriction_location = match entity.spawn_restriction.location {
|
let spawn_restriction_location = match entity.spawn_restriction.location {
|
||||||
@ -111,12 +113,14 @@ impl ToTokens for NamedEntityType<'_> {
|
|||||||
let summonable = entity.summonable;
|
let summonable = entity.summonable;
|
||||||
let fire_immune = entity.fire_immune;
|
let fire_immune = entity.fire_immune;
|
||||||
let eye_height = entity.eye_height;
|
let eye_height = entity.eye_height;
|
||||||
if entity.mob.is_none() && name != "player" {
|
assert!(
|
||||||
panic!("missing field 'mob', entity name {name}");
|
!(entity.mob.is_none() && name != "player"),
|
||||||
}
|
"missing field 'mob', entity name {name}"
|
||||||
if entity.limit_per_chunk.is_none() && name != "player" {
|
);
|
||||||
panic!("missing field 'mob', entity name {name}");
|
assert!(
|
||||||
}
|
!(entity.limit_per_chunk.is_none() && name != "player"),
|
||||||
|
"missing field 'mob', entity name {name}"
|
||||||
|
);
|
||||||
let mob = entity.mob.unwrap_or(false);
|
let mob = entity.mob.unwrap_or(false);
|
||||||
let limit_per_chunk = entity.limit_per_chunk.unwrap_or(0);
|
let limit_per_chunk = entity.limit_per_chunk.unwrap_or(0);
|
||||||
let can_spawn_far_from_player = entity.can_spawn_far_from_player;
|
let can_spawn_far_from_player = entity.can_spawn_far_from_player;
|
||||||
@ -124,12 +128,11 @@ impl ToTokens for NamedEntityType<'_> {
|
|||||||
let dimension0 = entity.dimension[0];
|
let dimension0 = entity.dimension[0];
|
||||||
let dimension1 = entity.dimension[1];
|
let dimension1 = entity.dimension[1];
|
||||||
|
|
||||||
let loot_table = match &entity.loot_table {
|
let loot_table = if let Some(table) = &entity.loot_table {
|
||||||
Some(table) => {
|
let table_tokens = table.to_token_stream();
|
||||||
let table_tokens = table.to_token_stream();
|
quote! { Some(#table_tokens) }
|
||||||
quote! { Some(#table_tokens) }
|
} else {
|
||||||
}
|
quote! { None }
|
||||||
None => quote! { None },
|
|
||||||
};
|
};
|
||||||
|
|
||||||
tokens.extend(quote! {
|
tokens.extend(quote! {
|
||||||
@ -165,7 +168,7 @@ pub(crate) fn build() -> TokenStream {
|
|||||||
let mut type_from_raw_id_arms = TokenStream::new();
|
let mut type_from_raw_id_arms = TokenStream::new();
|
||||||
let mut type_from_name = TokenStream::new();
|
let mut type_from_name = TokenStream::new();
|
||||||
|
|
||||||
for (name, entity) in json.iter() {
|
for (name, entity) in &json {
|
||||||
let id = entity.id as u8;
|
let id = entity.id as u8;
|
||||||
let id_lit = LitInt::new(&id.to_string(), proc_macro2::Span::call_site());
|
let id_lit = LitInt::new(&id.to_string(), proc_macro2::Span::call_site());
|
||||||
let upper_name = format_ident!("{}", name.to_uppercase());
|
let upper_name = format_ident!("{}", name.to_uppercase());
|
||||||
|
|||||||
@ -57,7 +57,7 @@ impl ToTokens for PropertyStruct {
|
|||||||
let values_index = (0..self.values.len() as u16).collect::<Vec<_>>();
|
let values_index = (0..self.values.len() as u16).collect::<Vec<_>>();
|
||||||
|
|
||||||
let ident_values = self.values.iter().map(|value| {
|
let ident_values = self.values.iter().map(|value| {
|
||||||
let value_str = if value.chars().all(|c| c.is_numeric()) {
|
let value_str = if value.chars().all(char::is_numeric) {
|
||||||
format!("L{value}")
|
format!("L{value}")
|
||||||
} else {
|
} else {
|
||||||
value.clone()
|
value.clone()
|
||||||
@ -69,7 +69,7 @@ impl ToTokens for PropertyStruct {
|
|||||||
let values_3 = ident_values.clone();
|
let values_3 = ident_values.clone();
|
||||||
|
|
||||||
let from_values = self.values.iter().map(|value| {
|
let from_values = self.values.iter().map(|value| {
|
||||||
let value_str = if value.chars().all(|c| c.is_numeric()) {
|
let value_str = if value.chars().all(char::is_numeric) {
|
||||||
format!("L{value}")
|
format!("L{value}")
|
||||||
} else {
|
} else {
|
||||||
value.clone()
|
value.clone()
|
||||||
@ -80,7 +80,7 @@ impl ToTokens for PropertyStruct {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
let to_values = self.values.iter().map(|value| {
|
let to_values = self.values.iter().map(|value| {
|
||||||
let value_str = if value.chars().all(|c| c.is_numeric()) {
|
let value_str = if value.chars().all(char::is_numeric) {
|
||||||
format!("L{value}")
|
format!("L{value}")
|
||||||
} else {
|
} else {
|
||||||
value.clone()
|
value.clone()
|
||||||
@ -512,12 +512,13 @@ pub(crate) fn build() -> TokenStream {
|
|||||||
.entry(renamed_property.clone())
|
.entry(renamed_property.clone())
|
||||||
.or_insert_with(|| property.values.clone());
|
.or_insert_with(|| property.values.clone());
|
||||||
|
|
||||||
if expected_values != &property.values {
|
assert!(
|
||||||
panic!(
|
expected_values == &property.values,
|
||||||
"Enum overlap for '{}' ({:?} vs {:?})",
|
"Enum overlap for '{}' ({:?} vs {:?})",
|
||||||
property.name, &property.values, expected_values
|
property.name,
|
||||||
);
|
&property.values,
|
||||||
};
|
expected_values
|
||||||
|
);
|
||||||
|
|
||||||
property_mapping.push(PropertyVariantMapping {
|
property_mapping.push(PropertyVariantMapping {
|
||||||
original_name: property.name.clone(),
|
original_name: property.name.clone(),
|
||||||
@ -591,8 +592,12 @@ pub(crate) fn build() -> TokenStream {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
let fluid_props = fluid_properties.iter().map(|prop| prop.to_token_stream());
|
let fluid_props = fluid_properties
|
||||||
let properties = property_enums.values().map(|prop| prop.to_token_stream());
|
.iter()
|
||||||
|
.map(quote::ToTokens::to_token_stream);
|
||||||
|
let properties = property_enums
|
||||||
|
.values()
|
||||||
|
.map(quote::ToTokens::to_token_stream);
|
||||||
|
|
||||||
quote! {
|
quote! {
|
||||||
use std::hash::{Hash, Hasher};
|
use std::hash::{Hash, Hasher};
|
||||||
|
|||||||
@ -81,7 +81,7 @@ impl ToTokens for ItemComponents {
|
|||||||
damage: #damage_lit,
|
damage: #damage_lit,
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
};
|
}
|
||||||
|
|
||||||
if let Some(md) = self.max_damage {
|
if let Some(md) = self.max_damage {
|
||||||
let max_damage_lit = LitInt::new(&md.to_string(), Span::call_site());
|
let max_damage_lit = LitInt::new(&md.to_string(), Span::call_site());
|
||||||
@ -90,7 +90,7 @@ impl ToTokens for ItemComponents {
|
|||||||
max_damage: #max_damage_lit,
|
max_damage: #max_damage_lit,
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
};
|
}
|
||||||
|
|
||||||
if let Some(modifiers) = &self.attribute_modifiers {
|
if let Some(modifiers) = &self.attribute_modifiers {
|
||||||
let modifier_code = modifiers.iter().map(|modifier| {
|
let modifier_code = modifiers.iter().map(|modifier| {
|
||||||
@ -122,7 +122,7 @@ impl ToTokens for ItemComponents {
|
|||||||
attribute_modifiers: Cow::Borrowed(&[#(#modifier_code),*])
|
attribute_modifiers: Cow::Borrowed(&[#(#modifier_code),*])
|
||||||
}),
|
}),
|
||||||
});
|
});
|
||||||
};
|
}
|
||||||
|
|
||||||
if let Some(tool) = &self.tool {
|
if let Some(tool) = &self.tool {
|
||||||
let rules_code = tool.rules.iter().map(|rule| {
|
let rules_code = tool.rules.iter().map(|rule| {
|
||||||
@ -138,10 +138,8 @@ impl ToTokens for ItemComponents {
|
|||||||
Blocks(Cow::Borrowed(&[&Block::#ident]))
|
Blocks(Cow::Borrowed(&[&Block::#ident]))
|
||||||
}
|
}
|
||||||
} else if let TagType::Tag(str) = t {
|
} else if let TagType::Tag(str) = t {
|
||||||
let ident = format_ident!(
|
let ident =
|
||||||
"{}",
|
format_ident!("{}", str.replace([':', '/'], "_").to_uppercase());
|
||||||
str.replace(":", "_").replace("/", "_").to_uppercase()
|
|
||||||
);
|
|
||||||
block_array = quote! {
|
block_array = quote! {
|
||||||
Tag(&tag::Block::#ident)
|
Tag(&tag::Block::#ident)
|
||||||
}
|
}
|
||||||
@ -168,18 +166,16 @@ impl ToTokens for ItemComponents {
|
|||||||
} else {
|
} else {
|
||||||
unreachable!();
|
unreachable!();
|
||||||
}
|
}
|
||||||
let speed = match rule.speed {
|
let speed = if let Some(speed) = rule.speed {
|
||||||
Some(speed) => {
|
quote! { Some(#speed) }
|
||||||
quote! { Some(#speed) }
|
} else {
|
||||||
}
|
quote! { None }
|
||||||
None => quote! { None },
|
|
||||||
};
|
};
|
||||||
let correct_for_drops = match rule.correct_for_drops {
|
let correct_for_drops = if let Some(correct_for_drops) = rule.correct_for_drops {
|
||||||
Some(correct_for_drops) => {
|
let correct_for_drops = LitBool::new(correct_for_drops, Span::call_site());
|
||||||
let correct_for_drops = LitBool::new(correct_for_drops, Span::call_site());
|
quote! { Some(#correct_for_drops) }
|
||||||
quote! { Some(#correct_for_drops) }
|
} else {
|
||||||
}
|
quote! { None }
|
||||||
None => quote! { None },
|
|
||||||
};
|
};
|
||||||
quote! {
|
quote! {
|
||||||
ToolRule {
|
ToolRule {
|
||||||
@ -208,7 +204,7 @@ impl ToTokens for ItemComponents {
|
|||||||
damage_per_block: #damage_per_block,
|
damage_per_block: #damage_per_block,
|
||||||
can_destroy_blocks_in_creative: #can_destroy_blocks_in_creative
|
can_destroy_blocks_in_creative: #can_destroy_blocks_in_creative
|
||||||
}), });
|
}), });
|
||||||
};
|
}
|
||||||
|
|
||||||
if let Some(food) = &self.food {
|
if let Some(food) = &self.food {
|
||||||
let nutrition = LitInt::new(&food.nutrition.to_string(), Span::call_site());
|
let nutrition = LitInt::new(&food.nutrition.to_string(), Span::call_site());
|
||||||
@ -222,7 +218,7 @@ impl ToTokens for ItemComponents {
|
|||||||
saturation: #saturation,
|
saturation: #saturation,
|
||||||
can_always_eat: #can_always_eat,
|
can_always_eat: #can_always_eat,
|
||||||
}), });
|
}), });
|
||||||
};
|
}
|
||||||
|
|
||||||
if let Some(consumable) = &self.consumable {
|
if let Some(consumable) = &self.consumable {
|
||||||
let consume_seconds = LitFloat::new(
|
let consume_seconds = LitFloat::new(
|
||||||
@ -233,15 +229,15 @@ impl ToTokens for ItemComponents {
|
|||||||
tokens.extend(quote! { (Consumable, &ConsumableImpl {
|
tokens.extend(quote! { (Consumable, &ConsumableImpl {
|
||||||
consume_seconds: #consume_seconds,
|
consume_seconds: #consume_seconds,
|
||||||
}), });
|
}), });
|
||||||
};
|
}
|
||||||
|
|
||||||
if self.blocks_attacks.is_some() {
|
if self.blocks_attacks.is_some() {
|
||||||
tokens.extend(quote! { (BlocksAttacks, &BlocksAttacksImpl), });
|
tokens.extend(quote! { (BlocksAttacks, &BlocksAttacksImpl), });
|
||||||
};
|
}
|
||||||
|
|
||||||
if self.death_protection.is_some() {
|
if self.death_protection.is_some() {
|
||||||
tokens.extend(quote! { (DeathProtection, &DeathProtectionImpl), });
|
tokens.extend(quote! { (DeathProtection, &DeathProtectionImpl), });
|
||||||
};
|
}
|
||||||
|
|
||||||
if let Some(equippable) = &self.equippable {
|
if let Some(equippable) = &self.equippable {
|
||||||
let slot = match equippable.slot.as_str() {
|
let slot = match equippable.slot.as_str() {
|
||||||
@ -298,7 +294,7 @@ impl ToTokens for ItemComponents {
|
|||||||
TagType::Tag(tag) => {
|
TagType::Tag(tag) => {
|
||||||
let ident = format_ident!(
|
let ident = format_ident!(
|
||||||
"{}",
|
"{}",
|
||||||
tag.replace(":", "_").replace("/", "_").to_uppercase()
|
tag.replace([':', '/'], "_").to_uppercase()
|
||||||
);
|
);
|
||||||
quote! { EntityTypeOrTag::Tag(&crate::tag::EntityType::#ident) }
|
quote! { EntityTypeOrTag::Tag(&crate::tag::EntityType::#ident) }
|
||||||
}
|
}
|
||||||
@ -339,7 +335,7 @@ impl ToTokens for ItemComponents {
|
|||||||
can_be_sheared: #can_be_sheared,
|
can_be_sheared: #can_be_sheared,
|
||||||
shearing_sound: #shearing_sound
|
shearing_sound: #shearing_sound
|
||||||
}), });
|
}), });
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -17,16 +17,16 @@ pub struct LootTableStruct {
|
|||||||
impl ToTokens for LootTableStruct {
|
impl ToTokens for LootTableStruct {
|
||||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||||
let loot_table_type = self.r#type.to_token_stream();
|
let loot_table_type = self.r#type.to_token_stream();
|
||||||
let random_sequence = match &self.random_sequence {
|
let random_sequence = if let Some(seq) = &self.random_sequence {
|
||||||
Some(seq) => quote! { Some(#seq) },
|
quote! { Some(#seq) }
|
||||||
None => quote! { None },
|
} else {
|
||||||
|
quote! { None }
|
||||||
};
|
};
|
||||||
let pools = match &self.pools {
|
let pools = if let Some(pools) = &self.pools {
|
||||||
Some(pools) => {
|
let pool_tokens: Vec<_> = pools.iter().map(quote::ToTokens::to_token_stream).collect();
|
||||||
let pool_tokens: Vec<_> = pools.iter().map(|pool| pool.to_token_stream()).collect();
|
quote! { Some(&[#(#pool_tokens),*]) }
|
||||||
quote! { Some(&[#(#pool_tokens),*]) }
|
} else {
|
||||||
}
|
quote! { None }
|
||||||
None => quote! { None },
|
|
||||||
};
|
};
|
||||||
|
|
||||||
tokens.extend(quote! {
|
tokens.extend(quote! {
|
||||||
@ -53,23 +53,21 @@ impl ToTokens for LootPoolStruct {
|
|||||||
let entries_tokens: Vec<_> = self
|
let entries_tokens: Vec<_> = self
|
||||||
.entries
|
.entries
|
||||||
.iter()
|
.iter()
|
||||||
.map(|entry| entry.to_token_stream())
|
.map(quote::ToTokens::to_token_stream)
|
||||||
.collect();
|
.collect();
|
||||||
let rolls = &self.rolls;
|
let rolls = &self.rolls;
|
||||||
let bonus_rolls = &self.bonus_rolls;
|
let bonus_rolls = &self.bonus_rolls;
|
||||||
let conditions_tokens = match &self.conditions {
|
let conditions_tokens = if let Some(conds) = &self.conditions {
|
||||||
Some(conds) => {
|
let cond_tokens: Vec<_> = conds.iter().map(quote::ToTokens::to_token_stream).collect();
|
||||||
let cond_tokens: Vec<_> = conds.iter().map(|c| c.to_token_stream()).collect();
|
quote! { Some(&[#(#cond_tokens),*]) }
|
||||||
quote! { Some(&[#(#cond_tokens),*]) }
|
} else {
|
||||||
}
|
quote! { None }
|
||||||
None => quote! { None },
|
|
||||||
};
|
};
|
||||||
let functions_tokens = match &self.functions {
|
let functions_tokens = if let Some(fns) = &self.functions {
|
||||||
Some(fns) => {
|
let cond_tokens: Vec<_> = fns.iter().map(quote::ToTokens::to_token_stream).collect();
|
||||||
let cond_tokens: Vec<_> = fns.iter().map(|c| c.to_token_stream()).collect();
|
quote! { Some(&[#(#cond_tokens),*]) }
|
||||||
quote! { Some(&[#(#cond_tokens),*]) }
|
} else {
|
||||||
}
|
quote! { None }
|
||||||
None => quote! { None },
|
|
||||||
};
|
};
|
||||||
|
|
||||||
tokens.extend(quote! {
|
tokens.extend(quote! {
|
||||||
@ -108,7 +106,7 @@ pub struct AlternativeEntryStruct {
|
|||||||
|
|
||||||
impl ToTokens for AlternativeEntryStruct {
|
impl ToTokens for AlternativeEntryStruct {
|
||||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||||
let children = self.children.iter().map(|entry| entry.to_token_stream());
|
let children = self.children.iter().map(quote::ToTokens::to_token_stream);
|
||||||
|
|
||||||
tokens.extend(quote! {
|
tokens.extend(quote! {
|
||||||
AlternativeEntry {
|
AlternativeEntry {
|
||||||
@ -142,28 +140,28 @@ pub enum LootPoolEntryTypesStruct {
|
|||||||
impl ToTokens for LootPoolEntryTypesStruct {
|
impl ToTokens for LootPoolEntryTypesStruct {
|
||||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||||
match self {
|
match self {
|
||||||
LootPoolEntryTypesStruct::Empty => {
|
Self::Empty => {
|
||||||
tokens.extend(quote! { LootPoolEntryTypes::Empty });
|
tokens.extend(quote! { LootPoolEntryTypes::Empty });
|
||||||
}
|
}
|
||||||
LootPoolEntryTypesStruct::Item(item) => {
|
Self::Item(item) => {
|
||||||
tokens.extend(quote! { LootPoolEntryTypes::Item(#item) });
|
tokens.extend(quote! { LootPoolEntryTypes::Item(#item) });
|
||||||
}
|
}
|
||||||
LootPoolEntryTypesStruct::LootTable => {
|
Self::LootTable => {
|
||||||
tokens.extend(quote! { LootPoolEntryTypes::LootTable });
|
tokens.extend(quote! { LootPoolEntryTypes::LootTable });
|
||||||
}
|
}
|
||||||
LootPoolEntryTypesStruct::Dynamic => {
|
Self::Dynamic => {
|
||||||
tokens.extend(quote! { LootPoolEntryTypes::Dynamic });
|
tokens.extend(quote! { LootPoolEntryTypes::Dynamic });
|
||||||
}
|
}
|
||||||
LootPoolEntryTypesStruct::Tag => {
|
Self::Tag => {
|
||||||
tokens.extend(quote! { LootPoolEntryTypes::Tag });
|
tokens.extend(quote! { LootPoolEntryTypes::Tag });
|
||||||
}
|
}
|
||||||
LootPoolEntryTypesStruct::Alternatives(alt) => {
|
Self::Alternatives(alt) => {
|
||||||
tokens.extend(quote! { LootPoolEntryTypes::Alternatives(#alt) });
|
tokens.extend(quote! { LootPoolEntryTypes::Alternatives(#alt) });
|
||||||
}
|
}
|
||||||
LootPoolEntryTypesStruct::Sequence => {
|
Self::Sequence => {
|
||||||
tokens.extend(quote! { LootPoolEntryTypes::Sequence });
|
tokens.extend(quote! { LootPoolEntryTypes::Sequence });
|
||||||
}
|
}
|
||||||
LootPoolEntryTypesStruct::Group => {
|
Self::Group => {
|
||||||
tokens.extend(quote! { LootPoolEntryTypes::Group });
|
tokens.extend(quote! { LootPoolEntryTypes::Group });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -219,35 +217,35 @@ pub enum LootConditionStruct {
|
|||||||
impl ToTokens for LootConditionStruct {
|
impl ToTokens for LootConditionStruct {
|
||||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||||
let name = match self {
|
let name = match self {
|
||||||
LootConditionStruct::Inverted => quote! { LootCondition::Inverted },
|
Self::Inverted => quote! { LootCondition::Inverted },
|
||||||
LootConditionStruct::AnyOf => quote! { LootCondition::AnyOf },
|
Self::AnyOf => quote! { LootCondition::AnyOf },
|
||||||
LootConditionStruct::AllOf => quote! { LootCondition::AllOf },
|
Self::AllOf => quote! { LootCondition::AllOf },
|
||||||
LootConditionStruct::RandomChance => quote! { LootCondition::RandomChance },
|
Self::RandomChance => quote! { LootCondition::RandomChance },
|
||||||
LootConditionStruct::RandomChanceWithEnchantedBonus => {
|
Self::RandomChanceWithEnchantedBonus => {
|
||||||
quote! { LootCondition::RandomChanceWithEnchantedBonus }
|
quote! { LootCondition::RandomChanceWithEnchantedBonus }
|
||||||
}
|
}
|
||||||
LootConditionStruct::EntityProperties => quote! { LootCondition::EntityProperties },
|
Self::EntityProperties => quote! { LootCondition::EntityProperties },
|
||||||
LootConditionStruct::KilledByPlayer => quote! { LootCondition::KilledByPlayer },
|
Self::KilledByPlayer => quote! { LootCondition::KilledByPlayer },
|
||||||
LootConditionStruct::EntityScores => quote! { LootCondition::EntityScores },
|
Self::EntityScores => quote! { LootCondition::EntityScores },
|
||||||
LootConditionStruct::BlockStateProperty { block, properties } => {
|
Self::BlockStateProperty { block, properties } => {
|
||||||
let properties: Vec<_> = properties
|
let properties: Vec<_> = properties
|
||||||
.iter()
|
.iter()
|
||||||
.map(|(k, v)| quote! { (#k, #v) })
|
.map(|(k, v)| quote! { (#k, #v) })
|
||||||
.collect();
|
.collect();
|
||||||
quote! { LootCondition::BlockStateProperty { block: #block, properties: &[#(#properties),*] } }
|
quote! { LootCondition::BlockStateProperty { block: #block, properties: &[#(#properties),*] } }
|
||||||
}
|
}
|
||||||
LootConditionStruct::MatchTool => quote! { LootCondition::MatchTool },
|
Self::MatchTool => quote! { LootCondition::MatchTool },
|
||||||
LootConditionStruct::TableBonus => quote! { LootCondition::TableBonus },
|
Self::TableBonus => quote! { LootCondition::TableBonus },
|
||||||
LootConditionStruct::SurvivesExplosion => quote! { LootCondition::SurvivesExplosion },
|
Self::SurvivesExplosion => quote! { LootCondition::SurvivesExplosion },
|
||||||
LootConditionStruct::DamageSourceProperties => {
|
Self::DamageSourceProperties => {
|
||||||
quote! { LootCondition::DamageSourceProperties }
|
quote! { LootCondition::DamageSourceProperties }
|
||||||
}
|
}
|
||||||
LootConditionStruct::LocationCheck => quote! { LootCondition::LocationCheck },
|
Self::LocationCheck => quote! { LootCondition::LocationCheck },
|
||||||
LootConditionStruct::WeatherCheck => quote! { LootCondition::WeatherCheck },
|
Self::WeatherCheck => quote! { LootCondition::WeatherCheck },
|
||||||
LootConditionStruct::Reference => quote! { LootCondition::Reference },
|
Self::Reference => quote! { LootCondition::Reference },
|
||||||
LootConditionStruct::TimeCheck => quote! { LootCondition::TimeCheck },
|
Self::TimeCheck => quote! { LootCondition::TimeCheck },
|
||||||
LootConditionStruct::ValueCheck => quote! { LootCondition::ValueCheck },
|
Self::ValueCheck => quote! { LootCondition::ValueCheck },
|
||||||
LootConditionStruct::EnchantmentActiveCheck => {
|
Self::EnchantmentActiveCheck => {
|
||||||
quote! { LootCondition::EnchantmentActiveCheck }
|
quote! { LootCondition::EnchantmentActiveCheck }
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -267,12 +265,11 @@ impl ToTokens for LootFunctionStruct {
|
|||||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||||
let functions_tokens = &self.content.to_token_stream();
|
let functions_tokens = &self.content.to_token_stream();
|
||||||
|
|
||||||
let conditions_tokens = match &self.conditions {
|
let conditions_tokens = if let Some(conds) = &self.conditions {
|
||||||
Some(conds) => {
|
let cond_tokens: Vec<_> = conds.iter().map(quote::ToTokens::to_token_stream).collect();
|
||||||
let cond_tokens: Vec<_> = conds.iter().map(|c| c.to_token_stream()).collect();
|
quote! { Some(&[#(#cond_tokens),*]) }
|
||||||
quote! { Some(&[#(#cond_tokens),*]) }
|
} else {
|
||||||
}
|
quote! { None }
|
||||||
None => quote! { None },
|
|
||||||
};
|
};
|
||||||
|
|
||||||
tokens.extend(quote! {
|
tokens.extend(quote! {
|
||||||
@ -325,45 +322,46 @@ pub enum LootFunctionTypesStruct {
|
|||||||
impl ToTokens for LootFunctionTypesStruct {
|
impl ToTokens for LootFunctionTypesStruct {
|
||||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||||
let name = match self {
|
let name = match self {
|
||||||
LootFunctionTypesStruct::SetCount { count, add } => {
|
Self::SetCount { count, add } => {
|
||||||
let count = count.to_token_stream();
|
let count = count.to_token_stream();
|
||||||
let add = add.unwrap_or(false);
|
let add = add.unwrap_or(false);
|
||||||
quote! { LootFunctionTypes::SetCount { count: #count, add: #add } }
|
quote! { LootFunctionTypes::SetCount { count: #count, add: #add } }
|
||||||
}
|
}
|
||||||
LootFunctionTypesStruct::SetOminousBottleAmplifier => {
|
Self::SetOminousBottleAmplifier => {
|
||||||
quote! { LootFunctionTypes::SetOminousBottleAmplifier }
|
quote! { LootFunctionTypes::SetOminousBottleAmplifier }
|
||||||
}
|
}
|
||||||
LootFunctionTypesStruct::FurnaceSmelt => {
|
Self::FurnaceSmelt => {
|
||||||
quote! { LootFunctionTypes::FurnaceSmelt }
|
quote! { LootFunctionTypes::FurnaceSmelt }
|
||||||
}
|
}
|
||||||
LootFunctionTypesStruct::SetPotion => {
|
Self::SetPotion => {
|
||||||
quote! { LootFunctionTypes::SetPotion }
|
quote! { LootFunctionTypes::SetPotion }
|
||||||
}
|
}
|
||||||
LootFunctionTypesStruct::EnchantedCountIncrease => {
|
Self::EnchantedCountIncrease => {
|
||||||
quote! { LootFunctionTypes::EnchantedCountIncrease }
|
quote! { LootFunctionTypes::EnchantedCountIncrease }
|
||||||
}
|
}
|
||||||
LootFunctionTypesStruct::LimitCount { limit } => {
|
Self::LimitCount { limit } => {
|
||||||
let min = match limit.min {
|
let min = if let Some(min) = limit.min {
|
||||||
Some(min) => quote! { Some(#min) },
|
quote! { Some(#min) }
|
||||||
None => quote! { None },
|
} else {
|
||||||
|
quote! { None }
|
||||||
};
|
};
|
||||||
let max = match limit.max {
|
let max = if let Some(max) = limit.max {
|
||||||
Some(max) => quote! { Some(#max) },
|
quote! { Some(#max) }
|
||||||
None => quote! { None },
|
} else {
|
||||||
|
quote! { None }
|
||||||
};
|
};
|
||||||
quote! { LootFunctionTypes::LimitCount { min: #min, max: #max } }
|
quote! { LootFunctionTypes::LimitCount { min: #min, max: #max } }
|
||||||
}
|
}
|
||||||
LootFunctionTypesStruct::ApplyBonus {
|
Self::ApplyBonus {
|
||||||
enchantment,
|
enchantment,
|
||||||
formula,
|
formula,
|
||||||
parameters,
|
parameters,
|
||||||
} => {
|
} => {
|
||||||
let parameters = match parameters {
|
let parameters = if let Some(params) = parameters {
|
||||||
Some(params) => {
|
let params = params.to_token_stream();
|
||||||
let params = params.to_token_stream();
|
quote! { Some(#params) }
|
||||||
quote! { Some(#params) }
|
} else {
|
||||||
}
|
quote! { None }
|
||||||
None => quote! { None },
|
|
||||||
};
|
};
|
||||||
|
|
||||||
quote! {
|
quote! {
|
||||||
@ -374,7 +372,7 @@ impl ToTokens for LootFunctionTypesStruct {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
LootFunctionTypesStruct::CopyComponents { source, include } => {
|
Self::CopyComponents { source, include } => {
|
||||||
quote! {
|
quote! {
|
||||||
LootFunctionTypes::CopyComponents {
|
LootFunctionTypes::CopyComponents {
|
||||||
source: #source,
|
source: #source,
|
||||||
@ -382,7 +380,7 @@ impl ToTokens for LootFunctionTypesStruct {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
LootFunctionTypesStruct::CopyState { block, properties } => {
|
Self::CopyState { block, properties } => {
|
||||||
quote! {
|
quote! {
|
||||||
LootFunctionTypes::CopyState {
|
LootFunctionTypes::CopyState {
|
||||||
block: #block,
|
block: #block,
|
||||||
@ -390,7 +388,7 @@ impl ToTokens for LootFunctionTypesStruct {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
LootFunctionTypesStruct::ExplosionDecay => {
|
Self::ExplosionDecay => {
|
||||||
quote! { LootFunctionTypes::ExplosionDecay }
|
quote! { LootFunctionTypes::ExplosionDecay }
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@ -473,19 +471,17 @@ pub struct LootPoolEntryStruct {
|
|||||||
impl ToTokens for LootPoolEntryStruct {
|
impl ToTokens for LootPoolEntryStruct {
|
||||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||||
let content = &self.content;
|
let content = &self.content;
|
||||||
let conditions_tokens = match &self.conditions {
|
let conditions_tokens = if let Some(conds) = &self.conditions {
|
||||||
Some(conds) => {
|
let cond_tokens: Vec<_> = conds.iter().map(quote::ToTokens::to_token_stream).collect();
|
||||||
let cond_tokens: Vec<_> = conds.iter().map(|c| c.to_token_stream()).collect();
|
quote! { Some(&[#(#cond_tokens),*]) }
|
||||||
quote! { Some(&[#(#cond_tokens),*]) }
|
} else {
|
||||||
}
|
quote! { None }
|
||||||
None => quote! { None },
|
|
||||||
};
|
};
|
||||||
let functions_tokens = match &self.functions {
|
let functions_tokens = if let Some(fns) = &self.functions {
|
||||||
Some(fns) => {
|
let cond_tokens: Vec<_> = fns.iter().map(quote::ToTokens::to_token_stream).collect();
|
||||||
let cond_tokens: Vec<_> = fns.iter().map(|c| c.to_token_stream()).collect();
|
quote! { Some(&[#(#cond_tokens),*]) }
|
||||||
quote! { Some(&[#(#cond_tokens),*]) }
|
} else {
|
||||||
}
|
quote! { None }
|
||||||
None => quote! { None },
|
|
||||||
};
|
};
|
||||||
|
|
||||||
tokens.extend(quote! {
|
tokens.extend(quote! {
|
||||||
@ -518,10 +514,10 @@ pub enum LootTableTypeStruct {
|
|||||||
impl ToTokens for LootTableTypeStruct {
|
impl ToTokens for LootTableTypeStruct {
|
||||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||||
let name = match self {
|
let name = match self {
|
||||||
LootTableTypeStruct::Empty => quote! { LootTableType::Empty },
|
Self::Empty => quote! { LootTableType::Empty },
|
||||||
LootTableTypeStruct::Entity => quote! { LootTableType::Entity },
|
Self::Entity => quote! { LootTableType::Entity },
|
||||||
LootTableTypeStruct::Block => quote! { LootTableType::Block },
|
Self::Block => quote! { LootTableType::Block },
|
||||||
LootTableTypeStruct::Chest => quote! { LootTableType::Chest },
|
Self::Chest => quote! { LootTableType::Chest },
|
||||||
};
|
};
|
||||||
|
|
||||||
tokens.extend(name);
|
tokens.extend(name);
|
||||||
|
|||||||
@ -32,7 +32,7 @@ pub(crate) fn build() -> TokenStream {
|
|||||||
.expect("Failed to parse message_type.json");
|
.expect("Failed to parse message_type.json");
|
||||||
let mut variants = TokenStream::new();
|
let mut variants = TokenStream::new();
|
||||||
|
|
||||||
for (name, typee) in json.iter() {
|
for (name, typee) in &json {
|
||||||
let i = typee.id as u8;
|
let i = typee.id as u8;
|
||||||
let name = format_ident!("{}", name.to_uppercase());
|
let name = format_ident!("{}", name.to_uppercase());
|
||||||
variants.extend([quote! {
|
variants.extend([quote! {
|
||||||
|
|||||||
@ -13,7 +13,7 @@ pub(crate) fn build() -> TokenStream {
|
|||||||
let mut variants = TokenStream::new();
|
let mut variants = TokenStream::new();
|
||||||
let mut match_variants = TokenStream::new();
|
let mut match_variants = TokenStream::new();
|
||||||
|
|
||||||
for (name, parameter) in json.iter() {
|
for (name, parameter) in &json {
|
||||||
let raw_name = format!("minecraft:{name}");
|
let raw_name = format!("minecraft:{name}");
|
||||||
let simple_id = name;
|
let simple_id = name;
|
||||||
let name = format_ident!("{}", name.to_uppercase());
|
let name = format_ident!("{}", name.to_uppercase());
|
||||||
|
|||||||
@ -87,7 +87,7 @@ enum SplineRepr {
|
|||||||
#[serde(rename(deserialize = "locationFunction"))]
|
#[serde(rename(deserialize = "locationFunction"))]
|
||||||
location_function: Box<DensityFunctionRepr>,
|
location_function: Box<DensityFunctionRepr>,
|
||||||
locations: Box<[HashableF32]>,
|
locations: Box<[HashableF32]>,
|
||||||
values: Box<[SplineRepr]>,
|
values: Box<[Self]>,
|
||||||
derivatives: Box<[HashableF32]>,
|
derivatives: Box<[HashableF32]>,
|
||||||
},
|
},
|
||||||
#[serde(rename(deserialize = "fixed"))]
|
#[serde(rename(deserialize = "fixed"))]
|
||||||
@ -459,7 +459,7 @@ enum DensityFunctionRepr {
|
|||||||
BlendAlpha,
|
BlendAlpha,
|
||||||
BlendOffset,
|
BlendOffset,
|
||||||
BlendDensity {
|
BlendDensity {
|
||||||
input: Box<DensityFunctionRepr>,
|
input: Box<Self>,
|
||||||
},
|
},
|
||||||
EndIslands,
|
EndIslands,
|
||||||
Noise {
|
Noise {
|
||||||
@ -476,11 +476,11 @@ enum DensityFunctionRepr {
|
|||||||
},
|
},
|
||||||
ShiftedNoise {
|
ShiftedNoise {
|
||||||
#[serde(rename(deserialize = "shiftX"))]
|
#[serde(rename(deserialize = "shiftX"))]
|
||||||
shift_x: Box<DensityFunctionRepr>,
|
shift_x: Box<Self>,
|
||||||
#[serde(rename(deserialize = "shiftY"))]
|
#[serde(rename(deserialize = "shiftY"))]
|
||||||
shift_y: Box<DensityFunctionRepr>,
|
shift_y: Box<Self>,
|
||||||
#[serde(rename(deserialize = "shiftZ"))]
|
#[serde(rename(deserialize = "shiftZ"))]
|
||||||
shift_z: Box<DensityFunctionRepr>,
|
shift_z: Box<Self>,
|
||||||
#[serde(flatten)]
|
#[serde(flatten)]
|
||||||
data: ShiftedNoiseData,
|
data: ShiftedNoiseData,
|
||||||
},
|
},
|
||||||
@ -490,7 +490,7 @@ enum DensityFunctionRepr {
|
|||||||
},
|
},
|
||||||
#[serde(rename(deserialize = "WeirdScaledSampler"))]
|
#[serde(rename(deserialize = "WeirdScaledSampler"))]
|
||||||
WeirdScaled {
|
WeirdScaled {
|
||||||
input: Box<DensityFunctionRepr>,
|
input: Box<Self>,
|
||||||
#[serde(flatten)]
|
#[serde(flatten)]
|
||||||
data: WeirdScaledData,
|
data: WeirdScaledData,
|
||||||
},
|
},
|
||||||
@ -498,7 +498,7 @@ enum DensityFunctionRepr {
|
|||||||
#[serde(rename(deserialize = "Wrapping"))]
|
#[serde(rename(deserialize = "Wrapping"))]
|
||||||
Wrapper {
|
Wrapper {
|
||||||
#[serde(rename(deserialize = "wrapped"))]
|
#[serde(rename(deserialize = "wrapped"))]
|
||||||
input: Box<DensityFunctionRepr>,
|
input: Box<Self>,
|
||||||
#[serde(rename(deserialize = "type"))]
|
#[serde(rename(deserialize = "type"))]
|
||||||
wrapper: WrapperType,
|
wrapper: WrapperType,
|
||||||
},
|
},
|
||||||
@ -513,34 +513,34 @@ enum DensityFunctionRepr {
|
|||||||
},
|
},
|
||||||
#[serde(rename(deserialize = "BinaryOperation"))]
|
#[serde(rename(deserialize = "BinaryOperation"))]
|
||||||
Binary {
|
Binary {
|
||||||
argument1: Box<DensityFunctionRepr>,
|
argument1: Box<Self>,
|
||||||
argument2: Box<DensityFunctionRepr>,
|
argument2: Box<Self>,
|
||||||
#[serde(flatten)]
|
#[serde(flatten)]
|
||||||
data: BinaryData,
|
data: BinaryData,
|
||||||
},
|
},
|
||||||
#[serde(rename(deserialize = "LinearOperation"))]
|
#[serde(rename(deserialize = "LinearOperation"))]
|
||||||
Linear {
|
Linear {
|
||||||
input: Box<DensityFunctionRepr>,
|
input: Box<Self>,
|
||||||
#[serde(flatten)]
|
#[serde(flatten)]
|
||||||
data: LinearData,
|
data: LinearData,
|
||||||
},
|
},
|
||||||
#[serde(rename(deserialize = "UnaryOperation"))]
|
#[serde(rename(deserialize = "UnaryOperation"))]
|
||||||
Unary {
|
Unary {
|
||||||
input: Box<DensityFunctionRepr>,
|
input: Box<Self>,
|
||||||
#[serde(flatten)]
|
#[serde(flatten)]
|
||||||
data: UnaryData,
|
data: UnaryData,
|
||||||
},
|
},
|
||||||
Clamp {
|
Clamp {
|
||||||
input: Box<DensityFunctionRepr>,
|
input: Box<Self>,
|
||||||
#[serde(flatten)]
|
#[serde(flatten)]
|
||||||
data: ClampData,
|
data: ClampData,
|
||||||
},
|
},
|
||||||
RangeChoice {
|
RangeChoice {
|
||||||
input: Box<DensityFunctionRepr>,
|
input: Box<Self>,
|
||||||
#[serde(rename(deserialize = "whenInRange"))]
|
#[serde(rename(deserialize = "whenInRange"))]
|
||||||
when_in_range: Box<DensityFunctionRepr>,
|
when_in_range: Box<Self>,
|
||||||
#[serde(rename(deserialize = "whenOutOfRange"))]
|
#[serde(rename(deserialize = "whenOutOfRange"))]
|
||||||
when_out_range: Box<DensityFunctionRepr>,
|
when_out_range: Box<Self>,
|
||||||
#[serde(flatten)]
|
#[serde(flatten)]
|
||||||
data: RangeChoiceData,
|
data: RangeChoiceData,
|
||||||
},
|
},
|
||||||
@ -720,8 +720,8 @@ impl DensityFunctionRepr {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
Self::ClampedYGradient { data } => {
|
Self::ClampedYGradient { data } => {
|
||||||
let from_y = data.from_y as f64;
|
let from_y = f64::from(data.from_y);
|
||||||
let to_y = data.to_y as f64;
|
let to_y = f64::from(data.to_y);
|
||||||
let from_value = &data.from_value;
|
let from_value = &data.from_value;
|
||||||
let to_value = &data.to_value;
|
let to_value = &data.to_value;
|
||||||
|
|
||||||
|
|||||||
@ -92,14 +92,14 @@ fn generate_mapped_consts(latest: &Packets, v7: &Packets, is_serverbound: bool)
|
|||||||
|
|
||||||
for (phase, packets) in latest_phases {
|
for (phase, packets) in latest_phases {
|
||||||
for (name, id_11) in packets {
|
for (name, id_11) in packets {
|
||||||
let sanitized = name.replace("/", "_").replace("-", "_").to_uppercase();
|
let sanitized = name.replace(['/', '-'], "_").to_uppercase();
|
||||||
let const_name = format_ident!("{}_{}", phase.to_uppercase(), sanitized);
|
let const_name = format_ident!("{}_{}", phase.to_uppercase(), sanitized);
|
||||||
|
|
||||||
// Check if the packet exists in 1.21.7 to get the alternate ID
|
// Check if the packet exists in 1.21.7 to get the alternate ID
|
||||||
let id_7 = v7_phases
|
let id_7 = v7_phases
|
||||||
.get(phase)
|
.get(phase)
|
||||||
.and_then(|p| p.get(name))
|
.and_then(|p| p.get(name))
|
||||||
.cloned()
|
.copied()
|
||||||
.unwrap_or(-1);
|
.unwrap_or(-1);
|
||||||
|
|
||||||
// Since serverbound/clientbound are modules, we reference the PacketId in the parent scope
|
// Since serverbound/clientbound are modules, we reference the PacketId in the parent scope
|
||||||
|
|||||||
@ -59,11 +59,11 @@ pub(crate) fn build() -> TokenStream {
|
|||||||
let mut variants = TokenStream::new();
|
let mut variants = TokenStream::new();
|
||||||
let mut name_to_type = TokenStream::new();
|
let mut name_to_type = TokenStream::new();
|
||||||
|
|
||||||
for (name, potion) in potions.into_iter() {
|
for (name, potion) in potions {
|
||||||
let format_name = format_ident!("{}", name.to_shouty_snake_case());
|
let format_name = format_ident!("{}", name.to_shouty_snake_case());
|
||||||
let id = potion.id;
|
let id = potion.id;
|
||||||
let slots = potion.effects;
|
let slots = potion.effects;
|
||||||
let slots = slots.iter().map(|slot| slot.to_tokens());
|
let slots = slots.iter().map(Effect::to_tokens);
|
||||||
|
|
||||||
variants.extend([quote! {
|
variants.extend([quote! {
|
||||||
pub const #format_name: Self = Self {
|
pub const #format_name: Self = Self {
|
||||||
|
|||||||
@ -81,7 +81,7 @@ pub(crate) fn build() -> TokenStream {
|
|||||||
let item_recipes_tokens: Vec<TokenStream> = json
|
let item_recipes_tokens: Vec<TokenStream> = json
|
||||||
.item_recipes
|
.item_recipes
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|recipe| recipe.get_tokens_item())
|
.map(Recipes::get_tokens_item)
|
||||||
.collect();
|
.collect();
|
||||||
let item_len = item_recipes_tokens.len();
|
let item_len = item_recipes_tokens.len();
|
||||||
|
|
||||||
@ -89,7 +89,7 @@ pub(crate) fn build() -> TokenStream {
|
|||||||
let potion_recipes_tokens: Vec<TokenStream> = json
|
let potion_recipes_tokens: Vec<TokenStream> = json
|
||||||
.potion_recipes
|
.potion_recipes
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|recipe| recipe.get_tokens_potion())
|
.map(Recipes::get_tokens_potion)
|
||||||
.collect();
|
.collect();
|
||||||
let potion_len = potion_recipes_tokens.len();
|
let potion_len = potion_recipes_tokens.len();
|
||||||
|
|
||||||
|
|||||||
@ -50,9 +50,10 @@ impl ToTokens for CookingRecipeStruct {
|
|||||||
Some(category) => category.to_token_stream(),
|
Some(category) => category.to_token_stream(),
|
||||||
None => RecipeCategoryTypes::Misc.to_token_stream(),
|
None => RecipeCategoryTypes::Misc.to_token_stream(),
|
||||||
};
|
};
|
||||||
let group = match &self.group {
|
let group = if let Some(group) = &self.group {
|
||||||
Some(group) => quote! { Some(#group) },
|
quote! { Some(#group) }
|
||||||
None => quote! { None },
|
} else {
|
||||||
|
quote! { None }
|
||||||
};
|
};
|
||||||
let ingredient = self.ingredient.to_token_stream();
|
let ingredient = self.ingredient.to_token_stream();
|
||||||
let cookingtime = self.cookingtime.to_token_stream();
|
let cookingtime = self.cookingtime.to_token_stream();
|
||||||
@ -88,9 +89,10 @@ impl ToTokens for CraftingShapedRecipeStruct {
|
|||||||
Some(category) => category.to_token_stream(),
|
Some(category) => category.to_token_stream(),
|
||||||
None => RecipeCategoryTypes::Misc.to_token_stream(),
|
None => RecipeCategoryTypes::Misc.to_token_stream(),
|
||||||
};
|
};
|
||||||
let group = match &self.group {
|
let group = if let Some(group) = &self.group {
|
||||||
Some(group) => quote! { Some(#group) },
|
quote! { Some(#group) }
|
||||||
None => quote! { None },
|
} else {
|
||||||
|
quote! { None }
|
||||||
};
|
};
|
||||||
let show_notification = self.show_notification.unwrap_or(true);
|
let show_notification = self.show_notification.unwrap_or(true);
|
||||||
let key = self
|
let key = self
|
||||||
@ -104,7 +106,7 @@ impl ToTokens for CraftingShapedRecipeStruct {
|
|||||||
let pattern = self
|
let pattern = self
|
||||||
.pattern
|
.pattern
|
||||||
.iter()
|
.iter()
|
||||||
.map(|c| c.to_token_stream())
|
.map(quote::ToTokens::to_token_stream)
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
let result = self.result.to_token_stream();
|
let result = self.result.to_token_stream();
|
||||||
|
|
||||||
@ -135,14 +137,15 @@ impl ToTokens for CraftingShapelessRecipeStruct {
|
|||||||
Some(category) => category.to_token_stream(),
|
Some(category) => category.to_token_stream(),
|
||||||
None => RecipeCategoryTypes::Misc.to_token_stream(),
|
None => RecipeCategoryTypes::Misc.to_token_stream(),
|
||||||
};
|
};
|
||||||
let group = match &self.group {
|
let group = if let Some(group) = &self.group {
|
||||||
Some(group) => quote! { Some(#group) },
|
quote! { Some(#group) }
|
||||||
None => quote! { None },
|
} else {
|
||||||
|
quote! { None }
|
||||||
};
|
};
|
||||||
let ingredients = self
|
let ingredients = self
|
||||||
.ingredients
|
.ingredients
|
||||||
.iter()
|
.iter()
|
||||||
.map(|c| c.to_token_stream())
|
.map(quote::ToTokens::to_token_stream)
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
let result = self.result.to_token_stream();
|
let result = self.result.to_token_stream();
|
||||||
|
|
||||||
@ -172,9 +175,10 @@ impl ToTokens for CraftingTransmuteRecipeStruct {
|
|||||||
Some(category) => category.to_token_stream(),
|
Some(category) => category.to_token_stream(),
|
||||||
None => RecipeCategoryTypes::Misc.to_token_stream(),
|
None => RecipeCategoryTypes::Misc.to_token_stream(),
|
||||||
};
|
};
|
||||||
let group = match &self.group {
|
let group = if let Some(group) = &self.group {
|
||||||
Some(group) => quote! { Some(#group) },
|
quote! { Some(#group) }
|
||||||
None => quote! { None },
|
} else {
|
||||||
|
quote! { None }
|
||||||
};
|
};
|
||||||
let input = self.input.to_token_stream();
|
let input = self.input.to_token_stream();
|
||||||
let material = self.material.to_token_stream();
|
let material = self.material.to_token_stream();
|
||||||
@ -243,17 +247,17 @@ pub enum RecipeIngredientTypes {
|
|||||||
impl ToTokens for RecipeIngredientTypes {
|
impl ToTokens for RecipeIngredientTypes {
|
||||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||||
let name = match self {
|
let name = match self {
|
||||||
RecipeIngredientTypes::Simple(ingredient) => {
|
Self::Simple(ingredient) => {
|
||||||
if ingredient.starts_with("#") {
|
if ingredient.starts_with('#') {
|
||||||
quote! { RecipeIngredientTypes::Tagged(#ingredient) }
|
quote! { RecipeIngredientTypes::Tagged(#ingredient) }
|
||||||
} else {
|
} else {
|
||||||
quote! { RecipeIngredientTypes::Simple(#ingredient) }
|
quote! { RecipeIngredientTypes::Simple(#ingredient) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
RecipeIngredientTypes::OneOf(ingredients) => {
|
Self::OneOf(ingredients) => {
|
||||||
let ingredients = ingredients
|
let ingredients = ingredients
|
||||||
.iter()
|
.iter()
|
||||||
.map(|c| c.to_token_stream())
|
.map(quote::ToTokens::to_token_stream)
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
quote! { RecipeIngredientTypes::OneOf(&[#(#ingredients),*]) }
|
quote! { RecipeIngredientTypes::OneOf(&[#(#ingredients),*]) }
|
||||||
}
|
}
|
||||||
@ -282,22 +286,22 @@ pub enum RecipeCategoryTypes {
|
|||||||
impl ToTokens for RecipeCategoryTypes {
|
impl ToTokens for RecipeCategoryTypes {
|
||||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||||
let name = match self {
|
let name = match self {
|
||||||
RecipeCategoryTypes::Equipment => {
|
Self::Equipment => {
|
||||||
quote! { RecipeCategoryTypes::Equipment }
|
quote! { RecipeCategoryTypes::Equipment }
|
||||||
}
|
}
|
||||||
RecipeCategoryTypes::Building => {
|
Self::Building => {
|
||||||
quote! { RecipeCategoryTypes::Building }
|
quote! { RecipeCategoryTypes::Building }
|
||||||
}
|
}
|
||||||
RecipeCategoryTypes::Restone => {
|
Self::Restone => {
|
||||||
quote! { RecipeCategoryTypes::Restone }
|
quote! { RecipeCategoryTypes::Restone }
|
||||||
}
|
}
|
||||||
RecipeCategoryTypes::Misc => {
|
Self::Misc => {
|
||||||
quote! { RecipeCategoryTypes::Misc }
|
quote! { RecipeCategoryTypes::Misc }
|
||||||
}
|
}
|
||||||
RecipeCategoryTypes::Food => {
|
Self::Food => {
|
||||||
quote! { RecipeCategoryTypes::Food }
|
quote! { RecipeCategoryTypes::Food }
|
||||||
}
|
}
|
||||||
RecipeCategoryTypes::Blocks => {
|
Self::Blocks => {
|
||||||
quote! { RecipeCategoryTypes::Blocks }
|
quote! { RecipeCategoryTypes::Blocks }
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@ -9,8 +9,7 @@ pub(crate) fn build() -> TokenStream {
|
|||||||
println!("cargo:rerun-if-changed=../assets/registry/1_21_11_synced_registries.json");
|
println!("cargo:rerun-if-changed=../assets/registry/1_21_11_synced_registries.json");
|
||||||
|
|
||||||
let process_version = |path: &str| -> TokenStream {
|
let process_version = |path: &str| -> TokenStream {
|
||||||
let json_str =
|
let json_str = fs::read_to_string(path).unwrap_or_else(|_| panic!("Failed to read {path}"));
|
||||||
fs::read_to_string(path).unwrap_or_else(|_| panic!("Failed to read {}", path));
|
|
||||||
let mut data: IndexMap<String, IndexMap<String, Value>> =
|
let mut data: IndexMap<String, IndexMap<String, Value>> =
|
||||||
serde_json::from_str(&json_str).expect("Failed to parse JSON");
|
serde_json::from_str(&json_str).expect("Failed to parse JSON");
|
||||||
|
|
||||||
|
|||||||
@ -115,7 +115,7 @@ pub(crate) fn build() -> TokenStream {
|
|||||||
let versions = vec![latest_version_key, legacy_version_key];
|
let versions = vec![latest_version_key, legacy_version_key];
|
||||||
|
|
||||||
for version in versions {
|
for version in versions {
|
||||||
let file_path = format!("../assets/tags/{}_tags.json", version);
|
let file_path = format!("../assets/tags/{version}_tags.json");
|
||||||
if !Path::new(&file_path).exists() {
|
if !Path::new(&file_path).exists() {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -144,13 +144,13 @@ pub(crate) fn build() -> TokenStream {
|
|||||||
let ids: Vec<u16> = values
|
let ids: Vec<u16> = values
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|v| match key.as_str() {
|
.filter_map(|v| match key.as_str() {
|
||||||
"worldgen/biome" => biomes.get(v).map(|b| b.id as u16),
|
"worldgen/biome" => biomes.get(v).map(|b| u16::from(b.id)),
|
||||||
"fluid" => fluid_id_map.get(v).copied(),
|
"fluid" => fluid_id_map.get(v).copied(),
|
||||||
"item" => items.get(v).map(|i| i.id),
|
"item" => items.get(v).map(|i| i.id),
|
||||||
"block" => block_id_map.get(v).copied(),
|
"block" => block_id_map.get(v).copied(),
|
||||||
"enchantment" => enchantments
|
"enchantment" => enchantments
|
||||||
.get(&format!("minecraft:{}", v))
|
.get(&format!("minecraft:{v}"))
|
||||||
.map(|e| e.id as u16),
|
.map(|e| u16::from(e.id)),
|
||||||
"entity_type" => entities.get(v).map(|e| e.id),
|
"entity_type" => entities.get(v).map(|e| e.id),
|
||||||
_ => None,
|
_ => None,
|
||||||
})
|
})
|
||||||
|
|||||||
@ -24,7 +24,7 @@ pub(crate) fn build() -> TokenStream {
|
|||||||
for (name, id_11) in &data_11 {
|
for (name, id_11) in &data_11 {
|
||||||
let ident = format_ident!("DATA_{}", name.to_uppercase());
|
let ident = format_ident!("DATA_{}", name.to_uppercase());
|
||||||
|
|
||||||
let id_7 = data_7.get(name).cloned().unwrap_or(255); // 255 as an 'Invalid' marker
|
let id_7 = data_7.get(name).copied().unwrap_or(255); // 255 as an 'Invalid' marker
|
||||||
|
|
||||||
constants.extend(quote! {
|
constants.extend(quote! {
|
||||||
pub const #ident: TrackedId = TrackedId {
|
pub const #ident: TrackedId = TrackedId {
|
||||||
|
|||||||
@ -27,7 +27,7 @@ impl From<MathAxis> for Axis {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl From<Axis> for MathAxis {
|
impl From<Axis> for MathAxis {
|
||||||
fn from(a: Axis) -> MathAxis {
|
fn from(a: Axis) -> Self {
|
||||||
match a {
|
match a {
|
||||||
Axis::X => Self::X,
|
Axis::X => Self::X,
|
||||||
Axis::Y => Self::Y,
|
Axis::Y => Self::Y,
|
||||||
@ -55,17 +55,19 @@ impl TryFrom<i32> for BlockDirection {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl BlockDirection {
|
impl BlockDirection {
|
||||||
|
#[must_use]
|
||||||
pub fn to_index(&self) -> u8 {
|
pub fn to_index(&self) -> u8 {
|
||||||
match self {
|
match self {
|
||||||
BlockDirection::Down => 0,
|
Self::Down => 0,
|
||||||
BlockDirection::Up => 1,
|
Self::Up => 1,
|
||||||
BlockDirection::North => 2,
|
Self::North => 2,
|
||||||
BlockDirection::South => 3,
|
Self::South => 3,
|
||||||
BlockDirection::West => 4,
|
Self::West => 4,
|
||||||
BlockDirection::East => 5,
|
Self::East => 5,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub fn from_index(index: u8) -> Option<Self> {
|
pub fn from_index(index: u8) -> Option<Self> {
|
||||||
match index {
|
match index {
|
||||||
0 => Some(Self::Down),
|
0 => Some(Self::Down),
|
||||||
@ -86,176 +88,173 @@ impl BlockDirection {
|
|||||||
Self::horizontal()[random.next_bounded_i32(Self::horizontal().len() as i32 - 1) as usize]
|
Self::horizontal()[random.next_bounded_i32(Self::horizontal().len() as i32 - 1) as usize]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub fn by_index(index: usize) -> Option<Self> {
|
pub fn by_index(index: usize) -> Option<Self> {
|
||||||
Self::all().get(index % Self::all().len()).cloned()
|
Self::all().get(index % Self::all().len()).copied()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub fn to_offset(&self) -> Vector3<i32> {
|
pub fn to_offset(&self) -> Vector3<i32> {
|
||||||
match self {
|
match self {
|
||||||
BlockDirection::Down => (0, -1, 0),
|
Self::Down => (0, -1, 0),
|
||||||
BlockDirection::Up => (0, 1, 0),
|
Self::Up => (0, 1, 0),
|
||||||
BlockDirection::North => (0, 0, -1),
|
Self::North => (0, 0, -1),
|
||||||
BlockDirection::South => (0, 0, 1),
|
Self::South => (0, 0, 1),
|
||||||
BlockDirection::West => (-1, 0, 0),
|
Self::West => (-1, 0, 0),
|
||||||
BlockDirection::East => (1, 0, 0),
|
Self::East => (1, 0, 0),
|
||||||
}
|
}
|
||||||
.into()
|
.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn opposite(&self) -> BlockDirection {
|
#[must_use]
|
||||||
|
pub fn opposite(&self) -> Self {
|
||||||
match self {
|
match self {
|
||||||
BlockDirection::Down => BlockDirection::Up,
|
Self::Down => Self::Up,
|
||||||
BlockDirection::Up => BlockDirection::Down,
|
Self::Up => Self::Down,
|
||||||
BlockDirection::North => BlockDirection::South,
|
Self::North => Self::South,
|
||||||
BlockDirection::South => BlockDirection::North,
|
Self::South => Self::North,
|
||||||
BlockDirection::West => BlockDirection::East,
|
Self::West => Self::East,
|
||||||
BlockDirection::East => BlockDirection::West,
|
Self::East => Self::West,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub fn positive(&self) -> bool {
|
pub fn positive(&self) -> bool {
|
||||||
matches!(self, Self::South | Self::East | Self::Up)
|
matches!(self, Self::South | Self::East | Self::Up)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn all() -> [BlockDirection; 6] {
|
#[must_use]
|
||||||
|
pub fn all() -> [Self; 6] {
|
||||||
[
|
[
|
||||||
BlockDirection::Down,
|
Self::Down,
|
||||||
BlockDirection::Up,
|
Self::Up,
|
||||||
BlockDirection::North,
|
Self::North,
|
||||||
BlockDirection::South,
|
Self::South,
|
||||||
BlockDirection::West,
|
Self::West,
|
||||||
BlockDirection::East,
|
Self::East,
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
pub fn update_order() -> [BlockDirection; 6] {
|
#[must_use]
|
||||||
|
pub fn update_order() -> [Self; 6] {
|
||||||
[
|
[
|
||||||
BlockDirection::West,
|
Self::West,
|
||||||
BlockDirection::East,
|
Self::East,
|
||||||
BlockDirection::Down,
|
Self::Down,
|
||||||
BlockDirection::Up,
|
Self::Up,
|
||||||
BlockDirection::North,
|
Self::North,
|
||||||
BlockDirection::South,
|
Self::South,
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn abstract_block_update_order() -> [BlockDirection; 6] {
|
#[must_use]
|
||||||
|
pub fn abstract_block_update_order() -> [Self; 6] {
|
||||||
[
|
[
|
||||||
BlockDirection::West,
|
Self::West,
|
||||||
BlockDirection::East,
|
Self::East,
|
||||||
BlockDirection::North,
|
Self::North,
|
||||||
BlockDirection::South,
|
Self::South,
|
||||||
BlockDirection::Down,
|
Self::Down,
|
||||||
BlockDirection::Up,
|
Self::Up,
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn horizontal() -> [BlockDirection; 4] {
|
#[must_use]
|
||||||
[
|
pub fn horizontal() -> [Self; 4] {
|
||||||
BlockDirection::North,
|
[Self::North, Self::South, Self::West, Self::East]
|
||||||
BlockDirection::South,
|
|
||||||
BlockDirection::West,
|
|
||||||
BlockDirection::East,
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn flow_directions() -> [BlockDirection; 5] {
|
#[must_use]
|
||||||
[
|
pub fn flow_directions() -> [Self; 5] {
|
||||||
BlockDirection::Down,
|
[Self::Down, Self::North, Self::South, Self::West, Self::East]
|
||||||
BlockDirection::North,
|
|
||||||
BlockDirection::South,
|
|
||||||
BlockDirection::West,
|
|
||||||
BlockDirection::East,
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub fn is_horizontal(&self) -> bool {
|
pub fn is_horizontal(&self) -> bool {
|
||||||
matches!(
|
matches!(self, Self::North | Self::South | Self::West | Self::East)
|
||||||
self,
|
|
||||||
BlockDirection::North
|
|
||||||
| BlockDirection::South
|
|
||||||
| BlockDirection::West
|
|
||||||
| BlockDirection::East
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn vertical() -> [BlockDirection; 2] {
|
#[must_use]
|
||||||
[BlockDirection::Down, BlockDirection::Up]
|
pub fn vertical() -> [Self; 2] {
|
||||||
|
[Self::Down, Self::Up]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub fn to_horizontal_facing(&self) -> Option<HorizontalFacing> {
|
pub fn to_horizontal_facing(&self) -> Option<HorizontalFacing> {
|
||||||
match self {
|
match self {
|
||||||
BlockDirection::North => Some(HorizontalFacing::North),
|
Self::North => Some(HorizontalFacing::North),
|
||||||
BlockDirection::South => Some(HorizontalFacing::South),
|
Self::South => Some(HorizontalFacing::South),
|
||||||
BlockDirection::West => Some(HorizontalFacing::West),
|
Self::West => Some(HorizontalFacing::West),
|
||||||
BlockDirection::East => Some(HorizontalFacing::East),
|
Self::East => Some(HorizontalFacing::East),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub fn to_horizontal_axis(&self) -> Option<HorizontalAxis> {
|
pub fn to_horizontal_axis(&self) -> Option<HorizontalAxis> {
|
||||||
match self {
|
match self {
|
||||||
BlockDirection::North | BlockDirection::South => Some(HorizontalAxis::Z),
|
Self::North | Self::South => Some(HorizontalAxis::Z),
|
||||||
BlockDirection::West | BlockDirection::East => Some(HorizontalAxis::X),
|
Self::West | Self::East => Some(HorizontalAxis::X),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub fn to_cardinal_direction(&self) -> HorizontalFacing {
|
pub fn to_cardinal_direction(&self) -> HorizontalFacing {
|
||||||
match self {
|
match self {
|
||||||
BlockDirection::North => HorizontalFacing::North,
|
Self::South => HorizontalFacing::South,
|
||||||
BlockDirection::South => HorizontalFacing::South,
|
Self::West => HorizontalFacing::West,
|
||||||
BlockDirection::West => HorizontalFacing::West,
|
Self::East => HorizontalFacing::East,
|
||||||
BlockDirection::East => HorizontalFacing::East,
|
|
||||||
_ => HorizontalFacing::North,
|
_ => HorizontalFacing::North,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn from_cardinal_direction(direction: HorizontalFacing) -> BlockDirection {
|
#[must_use]
|
||||||
|
pub fn from_cardinal_direction(direction: HorizontalFacing) -> Self {
|
||||||
match direction {
|
match direction {
|
||||||
HorizontalFacing::North => BlockDirection::North,
|
HorizontalFacing::North => Self::North,
|
||||||
HorizontalFacing::South => BlockDirection::South,
|
HorizontalFacing::South => Self::South,
|
||||||
HorizontalFacing::West => BlockDirection::West,
|
HorizontalFacing::West => Self::West,
|
||||||
HorizontalFacing::East => BlockDirection::East,
|
HorizontalFacing::East => Self::East,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#[must_use]
|
||||||
pub fn to_axis(&self) -> Axis {
|
pub fn to_axis(&self) -> Axis {
|
||||||
match self {
|
match self {
|
||||||
BlockDirection::North | BlockDirection::South => Axis::Z,
|
Self::North | Self::South => Axis::Z,
|
||||||
BlockDirection::West | BlockDirection::East => Axis::X,
|
Self::West | Self::East => Axis::X,
|
||||||
BlockDirection::Up | BlockDirection::Down => Axis::Y,
|
Self::Up | Self::Down => Axis::Y,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub fn to_facing(&self) -> Facing {
|
pub fn to_facing(&self) -> Facing {
|
||||||
match self {
|
match self {
|
||||||
BlockDirection::North => Facing::North,
|
Self::North => Facing::North,
|
||||||
BlockDirection::South => Facing::South,
|
Self::South => Facing::South,
|
||||||
BlockDirection::West => Facing::West,
|
Self::West => Facing::West,
|
||||||
BlockDirection::East => Facing::East,
|
Self::East => Facing::East,
|
||||||
BlockDirection::Up => Facing::Up,
|
Self::Up => Facing::Up,
|
||||||
BlockDirection::Down => Facing::Down,
|
Self::Down => Facing::Down,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn rotate_clockwise(&self) -> BlockDirection {
|
#[must_use]
|
||||||
|
pub fn rotate_clockwise(&self) -> Self {
|
||||||
match self {
|
match self {
|
||||||
BlockDirection::North => BlockDirection::East,
|
Self::East => Self::South,
|
||||||
BlockDirection::East => BlockDirection::South,
|
Self::West => Self::North,
|
||||||
BlockDirection::South => BlockDirection::West,
|
Self::Up | Self::North => Self::East,
|
||||||
BlockDirection::West => BlockDirection::North,
|
Self::Down | Self::South => Self::West,
|
||||||
BlockDirection::Up => BlockDirection::East,
|
|
||||||
BlockDirection::Down => BlockDirection::West,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn rotate_counter_clockwise(&self) -> BlockDirection {
|
#[must_use]
|
||||||
|
pub fn rotate_counter_clockwise(&self) -> Self {
|
||||||
match self {
|
match self {
|
||||||
BlockDirection::North => BlockDirection::West,
|
Self::West => Self::South,
|
||||||
BlockDirection::West => BlockDirection::South,
|
Self::East => Self::North,
|
||||||
BlockDirection::South => BlockDirection::East,
|
Self::Up | Self::North => Self::West,
|
||||||
BlockDirection::East => BlockDirection::North,
|
Self::Down | Self::South => Self::East,
|
||||||
BlockDirection::Up => BlockDirection::West,
|
|
||||||
BlockDirection::Down => BlockDirection::East,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -52,35 +52,43 @@ pub enum PistonBehavior {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl BlockState {
|
impl BlockState {
|
||||||
|
#[must_use]
|
||||||
pub const fn is_air(&self) -> bool {
|
pub const fn is_air(&self) -> bool {
|
||||||
self.state_flags & IS_AIR != 0
|
self.state_flags & IS_AIR != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub const fn burnable(&self) -> bool {
|
pub const fn burnable(&self) -> bool {
|
||||||
self.state_flags & BURNABLE != 0
|
self.state_flags & BURNABLE != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub const fn tool_required(&self) -> bool {
|
pub const fn tool_required(&self) -> bool {
|
||||||
self.state_flags & TOOL_REQUIRED != 0
|
self.state_flags & TOOL_REQUIRED != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub const fn sided_transparency(&self) -> bool {
|
pub const fn sided_transparency(&self) -> bool {
|
||||||
self.state_flags & SIDED_TRANSPARENCY != 0
|
self.state_flags & SIDED_TRANSPARENCY != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub const fn replaceable(&self) -> bool {
|
pub const fn replaceable(&self) -> bool {
|
||||||
self.state_flags & REPLACEABLE != 0
|
self.state_flags & REPLACEABLE != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub const fn is_liquid(&self) -> bool {
|
pub const fn is_liquid(&self) -> bool {
|
||||||
self.state_flags & IS_LIQUID != 0
|
self.state_flags & IS_LIQUID != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the legacy value for whether a block is solid.
|
/// Returns the legacy value for whether a block is solid.
|
||||||
|
#[must_use]
|
||||||
pub const fn is_solid(&self) -> bool {
|
pub const fn is_solid(&self) -> bool {
|
||||||
self.state_flags & IS_SOLID != 0
|
self.state_flags & IS_SOLID != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub const fn is_full_cube(&self) -> bool {
|
pub const fn is_full_cube(&self) -> bool {
|
||||||
self.state_flags & IS_FULL_CUBE != 0
|
self.state_flags & IS_FULL_CUBE != 0
|
||||||
}
|
}
|
||||||
@ -88,15 +96,18 @@ impl BlockState {
|
|||||||
/// Returns whether the block is solid.
|
/// Returns whether the block is solid.
|
||||||
/// Solid blocks conduct redstone and block redstone wire.
|
/// Solid blocks conduct redstone and block redstone wire.
|
||||||
/// Non-solid blocks don't allow redstone wire on top to propagate their signal downwards in java.
|
/// Non-solid blocks don't allow redstone wire on top to propagate their signal downwards in java.
|
||||||
|
#[must_use]
|
||||||
pub const fn is_solid_block(&self) -> bool {
|
pub const fn is_solid_block(&self) -> bool {
|
||||||
self.state_flags & IS_SOLID_BLOCK != 0
|
self.state_flags & IS_SOLID_BLOCK != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub const fn has_random_ticks(&self) -> bool {
|
pub const fn has_random_ticks(&self) -> bool {
|
||||||
self.state_flags & HAS_RANDOM_TICKS != 0
|
self.state_flags & HAS_RANDOM_TICKS != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
///isSideSolidFullSquare() in Java!
|
///`isSideSolidFullSquare()` in Java!
|
||||||
|
#[must_use]
|
||||||
pub const fn is_side_solid(&self, side: BlockDirection) -> bool {
|
pub const fn is_side_solid(&self, side: BlockDirection) -> bool {
|
||||||
match side {
|
match side {
|
||||||
BlockDirection::Down => self.side_flags & DOWN_SIDE_SOLID != 0,
|
BlockDirection::Down => self.side_flags & DOWN_SIDE_SOLID != 0,
|
||||||
@ -110,6 +121,7 @@ impl BlockState {
|
|||||||
|
|
||||||
///isSideSolid(..., Direction.UP, SideShapeType.CENTER) in Java!
|
///isSideSolid(..., Direction.UP, SideShapeType.CENTER) in Java!
|
||||||
///Only valid for UP and DOWN sides
|
///Only valid for UP and DOWN sides
|
||||||
|
#[must_use]
|
||||||
pub const fn is_center_solid(&self, side: BlockDirection) -> bool {
|
pub const fn is_center_solid(&self, side: BlockDirection) -> bool {
|
||||||
match side {
|
match side {
|
||||||
BlockDirection::Down => self.side_flags & DOWN_CENTER_SOLID != 0,
|
BlockDirection::Down => self.side_flags & DOWN_CENTER_SOLID != 0,
|
||||||
@ -118,17 +130,16 @@ impl BlockState {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub fn is_waterlogged(&self) -> bool {
|
pub fn is_waterlogged(&self) -> bool {
|
||||||
let block = Block::from_state_id(self.id);
|
let block = Block::from_state_id(self.id);
|
||||||
|
|
||||||
if let Some(props) = block.properties(self.id) {
|
block.properties(self.id).is_some_and(|props| {
|
||||||
props
|
props
|
||||||
.to_props()
|
.to_props()
|
||||||
.iter()
|
.iter()
|
||||||
.any(|(k, v)| k == &"waterlogged" && v == &"true")
|
.any(|(k, v)| k == &"waterlogged" && v == &"true")
|
||||||
} else {
|
})
|
||||||
false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_block_collision_shapes(&self) -> impl Iterator<Item = CollisionShape> + '_ {
|
pub fn get_block_collision_shapes(&self) -> impl Iterator<Item = CollisionShape> + '_ {
|
||||||
@ -143,14 +154,9 @@ impl BlockState {
|
|||||||
.iter()
|
.iter()
|
||||||
.map(|&id| COLLISION_SHAPES[id as usize]);
|
.map(|&id| COLLISION_SHAPES[id as usize]);
|
||||||
|
|
||||||
let water_shape = if self.is_waterlogged() {
|
let water_shape = self.is_waterlogged().then(|| {
|
||||||
Some(CollisionShape::new(
|
CollisionShape::new(Vector3::new(0.0, 0.0, 0.0), Vector3::new(1.0, 0.875, 1.0))
|
||||||
Vector3::new(0.0, 0.0, 0.0),
|
});
|
||||||
Vector3::new(1.0, 0.875, 1.0),
|
|
||||||
))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
};
|
|
||||||
|
|
||||||
base_shapes.chain(water_shape)
|
base_shapes.chain(water_shape)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -18,9 +18,9 @@ use std::hash::{Hash, Hasher};
|
|||||||
pub struct Block {
|
pub struct Block {
|
||||||
/// The numeric ID used for internal registry mapping.
|
/// The numeric ID used for internal registry mapping.
|
||||||
pub id: u16,
|
pub id: u16,
|
||||||
/// The unique namespaced ID (e.g., "diamond_ore").
|
/// The unique namespaced ID (e.g., "`diamond_ore`").
|
||||||
pub name: &'static str,
|
pub name: &'static str,
|
||||||
/// The key used for client-side localization (e.g., "block.minecraft.diamond_ore").
|
/// The key used for client-side localization (e.g., "`block.minecraft.diamond_ore`").
|
||||||
pub translation_key: &'static str,
|
pub translation_key: &'static str,
|
||||||
/// How hard the block is to break. A value of -1.0 indicates an unbreakable block (e.g., Bedrock).
|
/// How hard the block is to break. A value of -1.0 indicates an unbreakable block (e.g., Bedrock).
|
||||||
pub hardness: f32,
|
pub hardness: f32,
|
||||||
@ -102,6 +102,7 @@ impl FromResourceLocation for &'static Block {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Block {
|
impl Block {
|
||||||
|
#[must_use]
|
||||||
pub fn is_waterlogged(&self, state_id: u16) -> bool {
|
pub fn is_waterlogged(&self, state_id: u16) -> bool {
|
||||||
self.properties(state_id).is_some_and(|properties| {
|
self.properties(state_id).is_some_and(|properties| {
|
||||||
properties
|
properties
|
||||||
|
|||||||
@ -7,6 +7,7 @@ pub struct CollisionShape {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl CollisionShape {
|
impl CollisionShape {
|
||||||
|
#[must_use]
|
||||||
pub fn to_bounding_box(&self) -> BoundingBox {
|
pub fn to_bounding_box(&self) -> BoundingBox {
|
||||||
BoundingBox {
|
BoundingBox {
|
||||||
min: self.min,
|
min: self.min,
|
||||||
@ -14,10 +15,12 @@ impl CollisionShape {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub fn new(min: Vector3<f64>, max: Vector3<f64>) -> Self {
|
pub fn new(min: Vector3<f64>, max: Vector3<f64>) -> Self {
|
||||||
Self { min, max }
|
Self { min, max }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub fn intersects(&self, other: &BoundingBox) -> bool {
|
pub fn intersects(&self, other: &BoundingBox) -> bool {
|
||||||
self.min.x < other.max.x
|
self.min.x < other.max.x
|
||||||
&& self.max.x > other.min.x
|
&& self.max.x > other.min.x
|
||||||
@ -27,11 +30,12 @@ impl CollisionShape {
|
|||||||
&& self.max.z > other.min.z
|
&& self.max.z > other.min.z
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub fn at_pos(&self, pos: BlockPos) -> Self {
|
pub fn at_pos(&self, pos: BlockPos) -> Self {
|
||||||
let vec3 = Vector3 {
|
let vec3 = Vector3 {
|
||||||
x: pos.0.x as f64,
|
x: f64::from(pos.0.x),
|
||||||
y: pos.0.y as f64,
|
y: f64::from(pos.0.y),
|
||||||
z: pos.0.z as f64,
|
z: f64::from(pos.0.z),
|
||||||
};
|
};
|
||||||
Self {
|
Self {
|
||||||
min: self.min + vec3,
|
min: self.min + vec3,
|
||||||
|
|||||||
@ -2,7 +2,11 @@
|
|||||||
|
|
||||||
use crate::attributes::Attributes;
|
use crate::attributes::Attributes;
|
||||||
use crate::data_component::DataComponent;
|
use crate::data_component::DataComponent;
|
||||||
use crate::data_component::DataComponent::*;
|
use crate::data_component::DataComponent::{
|
||||||
|
AttributeModifiers, BlocksAttacks, Consumable, CustomData, CustomName, Damage, DeathProtection,
|
||||||
|
Enchantments, Equippable, Food, ItemName, JukeboxPlayable, MaxDamage, MaxStackSize, Tool,
|
||||||
|
Unbreakable,
|
||||||
|
};
|
||||||
use crate::entity_type::EntityType;
|
use crate::entity_type::EntityType;
|
||||||
use crate::tag::{Tag, Taggable};
|
use crate::tag::{Tag, Taggable};
|
||||||
use crate::{AttributeModifierSlot, Block, Enchantment};
|
use crate::{AttributeModifierSlot, Block, Enchantment};
|
||||||
@ -38,6 +42,7 @@ pub trait DataComponentImpl: Send + Sync {
|
|||||||
fn as_any(&self) -> &dyn Any;
|
fn as_any(&self) -> &dyn Any;
|
||||||
fn as_mut_any(&mut self) -> &mut dyn Any;
|
fn as_mut_any(&mut self) -> &mut dyn Any;
|
||||||
}
|
}
|
||||||
|
#[must_use]
|
||||||
pub fn read_data(id: DataComponent, data: &NbtTag) -> Option<Box<dyn DataComponentImpl>> {
|
pub fn read_data(id: DataComponent, data: &NbtTag) -> Option<Box<dyn DataComponentImpl>> {
|
||||||
match id {
|
match id {
|
||||||
MaxStackSize => Some(MaxStackSizeImpl::read_data(data)?.to_dyn()),
|
MaxStackSize => Some(MaxStackSizeImpl::read_data(data)?.to_dyn()),
|
||||||
@ -116,10 +121,10 @@ impl MaxStackSizeImpl {
|
|||||||
}
|
}
|
||||||
impl DataComponentImpl for MaxStackSizeImpl {
|
impl DataComponentImpl for MaxStackSizeImpl {
|
||||||
fn write_data(&self) -> NbtTag {
|
fn write_data(&self) -> NbtTag {
|
||||||
NbtTag::Int(self.size as i32)
|
NbtTag::Int(i32::from(self.size))
|
||||||
}
|
}
|
||||||
fn get_hash(&self) -> i32 {
|
fn get_hash(&self) -> i32 {
|
||||||
get_i32_hash(self.size as i32) as i32
|
get_i32_hash(i32::from(self.size)) as i32
|
||||||
}
|
}
|
||||||
|
|
||||||
default_impl!(MaxStackSize);
|
default_impl!(MaxStackSize);
|
||||||
@ -196,7 +201,7 @@ impl EnchantmentsImpl {
|
|||||||
let data = &data.extract_compound()?.child_tags;
|
let data = &data.extract_compound()?.child_tags;
|
||||||
let mut enc = Vec::with_capacity(data.len());
|
let mut enc = Vec::with_capacity(data.len());
|
||||||
for (name, level) in data {
|
for (name, level) in data {
|
||||||
enc.push((Enchantment::from_name(name.as_str())?, level.extract_int()?))
|
enc.push((Enchantment::from_name(name.as_str())?, level.extract_int()?));
|
||||||
}
|
}
|
||||||
Some(Self {
|
Some(Self {
|
||||||
enchantment: Cow::from(enc),
|
enchantment: Cow::from(enc),
|
||||||
@ -279,7 +284,7 @@ impl Hash for Modifier {
|
|||||||
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
||||||
self.r#type.hash(state);
|
self.r#type.hash(state);
|
||||||
self.id.hash(state);
|
self.id.hash(state);
|
||||||
unsafe { (*(&self.amount as *const f64 as *const u64)).hash(state) };
|
unsafe { (*(&raw const self.amount).cast::<u64>()).hash(state) };
|
||||||
self.operation.hash(state);
|
self.operation.hash(state);
|
||||||
self.slot.hash(state);
|
self.slot.hash(state);
|
||||||
}
|
}
|
||||||
@ -315,7 +320,7 @@ impl DataComponentImpl for FoodImpl {
|
|||||||
impl Hash for FoodImpl {
|
impl Hash for FoodImpl {
|
||||||
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
||||||
self.nutrition.hash(state);
|
self.nutrition.hash(state);
|
||||||
unsafe { (*(&self.saturation as *const f32 as *const u32)).hash(state) };
|
unsafe { (*(&raw const self.saturation).cast::<u32>()).hash(state) };
|
||||||
self.can_always_eat.hash(state);
|
self.can_always_eat.hash(state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -326,6 +331,7 @@ pub struct ConsumableImpl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ConsumableImpl {
|
impl ConsumableImpl {
|
||||||
|
#[must_use]
|
||||||
pub fn consume_ticks(&self) -> i32 {
|
pub fn consume_ticks(&self) -> i32 {
|
||||||
(self.consume_seconds * 20.0) as i32
|
(self.consume_seconds * 20.0) as i32
|
||||||
}
|
}
|
||||||
@ -336,7 +342,7 @@ impl DataComponentImpl for ConsumableImpl {
|
|||||||
}
|
}
|
||||||
impl Hash for ConsumableImpl {
|
impl Hash for ConsumableImpl {
|
||||||
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
||||||
unsafe { (*(&self.consume_seconds as *const f32 as *const u32)).hash(state) };
|
unsafe { (*(&raw const self.consume_seconds).cast::<u32>()).hash(state) };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#[derive(Clone, Debug, Hash, PartialEq)]
|
#[derive(Clone, Debug, Hash, PartialEq)]
|
||||||
@ -363,7 +369,7 @@ impl Hash for ToolRule {
|
|||||||
self.blocks.hash(state);
|
self.blocks.hash(state);
|
||||||
if let Some(val) = self.speed {
|
if let Some(val) = self.speed {
|
||||||
true.hash(state);
|
true.hash(state);
|
||||||
unsafe { (*(&val as *const f32 as *const u32)).hash(state) };
|
unsafe { (*(&raw const val).cast::<u32>()).hash(state) };
|
||||||
} else {
|
} else {
|
||||||
false.hash(state);
|
false.hash(state);
|
||||||
}
|
}
|
||||||
@ -383,7 +389,7 @@ impl DataComponentImpl for ToolImpl {
|
|||||||
impl Hash for ToolImpl {
|
impl Hash for ToolImpl {
|
||||||
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
||||||
self.rules.hash(state);
|
self.rules.hash(state);
|
||||||
unsafe { (*(&self.default_mining_speed as *const f32 as *const u32)).hash(state) };
|
unsafe { (*(&raw const self.default_mining_speed).cast::<u32>()).hash(state) };
|
||||||
self.damage_per_block.hash(state);
|
self.damage_per_block.hash(state);
|
||||||
self.can_destroy_blocks_in_creative.hash(state);
|
self.can_destroy_blocks_in_creative.hash(state);
|
||||||
}
|
}
|
||||||
@ -479,6 +485,7 @@ impl EquipmentSlot {
|
|||||||
name: Cow::Borrowed("saddle"),
|
name: Cow::Borrowed("saddle"),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub fn get_entity_slot_id(&self) -> i32 {
|
pub fn get_entity_slot_id(&self) -> i32 {
|
||||||
match self {
|
match self {
|
||||||
Self::MainHand(data) => data.entity_id,
|
Self::MainHand(data) => data.entity_id,
|
||||||
@ -492,6 +499,7 @@ impl EquipmentSlot {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub fn get_from_name(name: &str) -> Option<Self> {
|
pub fn get_from_name(name: &str) -> Option<Self> {
|
||||||
match name {
|
match name {
|
||||||
"mainhand" => Some(Self::MAIN_HAND),
|
"mainhand" => Some(Self::MAIN_HAND),
|
||||||
@ -506,10 +514,12 @@ impl EquipmentSlot {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub fn get_offset_entity_slot_id(&self, offset: i32) -> i32 {
|
pub fn get_offset_entity_slot_id(&self, offset: i32) -> i32 {
|
||||||
self.get_entity_slot_id() + offset
|
self.get_entity_slot_id() + offset
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub fn slot_type(&self) -> EquipmentType {
|
pub fn slot_type(&self) -> EquipmentType {
|
||||||
match self {
|
match self {
|
||||||
Self::MainHand(data) => data.slot_type,
|
Self::MainHand(data) => data.slot_type,
|
||||||
@ -523,6 +533,7 @@ impl EquipmentSlot {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub fn is_armor_slot(&self) -> bool {
|
pub fn is_armor_slot(&self) -> bool {
|
||||||
matches!(
|
matches!(
|
||||||
self.slot_type(),
|
self.slot_type(),
|
||||||
@ -530,6 +541,7 @@ impl EquipmentSlot {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub const fn discriminant(&self) -> i8 {
|
pub const fn discriminant(&self) -> i8 {
|
||||||
match self {
|
match self {
|
||||||
Self::MainHand(_) => 0,
|
Self::MainHand(_) => 0,
|
||||||
@ -553,12 +565,12 @@ pub enum EntityTypeOrTag {
|
|||||||
impl Hash for EntityTypeOrTag {
|
impl Hash for EntityTypeOrTag {
|
||||||
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
||||||
match self {
|
match self {
|
||||||
EntityTypeOrTag::Tag(tag) => {
|
Self::Tag(tag) => {
|
||||||
for x in tag.0 {
|
for x in tag.0 {
|
||||||
x.hash(state);
|
x.hash(state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
EntityTypeOrTag::Single(entity_type) => {
|
Self::Single(entity_type) => {
|
||||||
entity_type.id.hash(state);
|
entity_type.id.hash(state);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -15,3 +15,6 @@ log.workspace = true
|
|||||||
tokio.workspace = true
|
tokio.workspace = true
|
||||||
thiserror.workspace = true
|
thiserror.workspace = true
|
||||||
crossbeam-utils.workspace = true
|
crossbeam-utils.workspace = true
|
||||||
|
|
||||||
|
[lints]
|
||||||
|
workspace = true
|
||||||
|
|||||||
@ -17,7 +17,7 @@ const KEY_CLICK_HOTBAR_END: i8 = 9;
|
|||||||
const SLOT_INDEX_OUTSIDE: i16 = -999;
|
const SLOT_INDEX_OUTSIDE: i16 = -999;
|
||||||
|
|
||||||
impl Click {
|
impl Click {
|
||||||
pub fn new(mode: SlotActionType, button: i8, slot: i16) -> Result<Self, InventoryError> {
|
pub fn new(mode: &SlotActionType, button: i8, slot: i16) -> Result<Self, InventoryError> {
|
||||||
match mode {
|
match mode {
|
||||||
SlotActionType::Pickup => Self::new_normal_click(button, slot),
|
SlotActionType::Pickup => Self::new_normal_click(button, slot),
|
||||||
// Both buttons do the same here, so we omit it
|
// Both buttons do the same here, so we omit it
|
||||||
@ -37,12 +37,11 @@ impl Click {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn new_normal_click(button: i8, slot: i16) -> Result<Self, InventoryError> {
|
fn new_normal_click(button: i8, slot: i16) -> Result<Self, InventoryError> {
|
||||||
let slot = match slot {
|
let slot = if slot == SLOT_INDEX_OUTSIDE {
|
||||||
SLOT_INDEX_OUTSIDE => Slot::OutsideInventory,
|
Slot::OutsideInventory
|
||||||
_ => {
|
} else {
|
||||||
let slot = slot.try_into().unwrap_or(0);
|
let slot = slot.try_into().unwrap_or(0);
|
||||||
Slot::Normal(slot)
|
Slot::Normal(slot)
|
||||||
}
|
|
||||||
};
|
};
|
||||||
let button = match button {
|
let button = match button {
|
||||||
BUTTON_CLICK_LEFT => MouseClick::Left,
|
BUTTON_CLICK_LEFT => MouseClick::Left,
|
||||||
@ -79,12 +78,11 @@ impl Click {
|
|||||||
|
|
||||||
fn new_drop_item(button: i8, slot: i16) -> Result<Self, InventoryError> {
|
fn new_drop_item(button: i8, slot: i16) -> Result<Self, InventoryError> {
|
||||||
let drop_type = DropType::from_i8(button)?;
|
let drop_type = DropType::from_i8(button)?;
|
||||||
let slot = match slot {
|
let slot = if slot == SLOT_INDEX_OUTSIDE {
|
||||||
SLOT_INDEX_OUTSIDE => Slot::OutsideInventory,
|
Slot::OutsideInventory
|
||||||
_ => {
|
} else {
|
||||||
let slot = slot.try_into().unwrap_or(0);
|
let slot = slot.try_into().unwrap_or(0);
|
||||||
Slot::Normal(slot)
|
Slot::Normal(slot)
|
||||||
}
|
|
||||||
};
|
};
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
click_type: ClickType::DropType(drop_type),
|
click_type: ClickType::DropType(drop_type),
|
||||||
|
|||||||
@ -16,6 +16,7 @@ pub struct CraftingInventory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl CraftingInventory {
|
impl CraftingInventory {
|
||||||
|
#[must_use]
|
||||||
pub fn new(width: u8, height: u8) -> Self {
|
pub fn new(width: u8, height: u8) -> Self {
|
||||||
Self {
|
Self {
|
||||||
width,
|
width,
|
||||||
@ -38,7 +39,7 @@ impl Inventory for CraftingInventory {
|
|||||||
|
|
||||||
fn is_empty(&self) -> InventoryFuture<'_, bool> {
|
fn is_empty(&self) -> InventoryFuture<'_, bool> {
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
for slot in self.items.iter() {
|
for slot in &self.items {
|
||||||
if !slot.lock().await.is_empty() {
|
if !slot.lock().await.is_empty() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -89,7 +90,7 @@ impl RecipeInputInventory for CraftingInventory {
|
|||||||
impl Clearable for CraftingInventory {
|
impl Clearable for CraftingInventory {
|
||||||
fn clear(&self) -> Pin<Box<dyn Future<Output = ()> + Send + '_>> {
|
fn clear(&self) -> Pin<Box<dyn Future<Output = ()> + Send + '_>> {
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
for item in self.items.iter() {
|
for item in &self.items {
|
||||||
*item.lock().await = ItemStack::EMPTY.clone();
|
*item.lock().await = ItemStack::EMPTY.clone();
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@ -48,6 +48,7 @@ fn is_symmetrical_horizontally(pattern: &'static [&'static str]) -> bool {
|
|||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[expect(clippy::too_many_lines)]
|
||||||
async fn recipe_matches<'a>(
|
async fn recipe_matches<'a>(
|
||||||
recipe: &'static CraftingRecipeTypes,
|
recipe: &'static CraftingRecipeTypes,
|
||||||
input_height: usize,
|
input_height: usize,
|
||||||
@ -146,7 +147,7 @@ async fn recipe_matches<'a>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Apply components
|
// TODO: Apply components
|
||||||
if matched { Some(result) } else { None }
|
matched.then_some(result)
|
||||||
}
|
}
|
||||||
CraftingRecipeTypes::CraftingShapeless {
|
CraftingRecipeTypes::CraftingShapeless {
|
||||||
ingredients,
|
ingredients,
|
||||||
@ -234,7 +235,7 @@ async fn recipe_matches<'a>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ResultSlot {
|
impl ResultSlot {
|
||||||
fn stat_crafted(&self, _crafted_amount: u8, _player: &dyn InventoryPlayer) {}
|
//fn stat_crafted(&self, _crafted_amount: u8, _player: &dyn InventoryPlayer) {}
|
||||||
|
|
||||||
pub fn new(inventory: Arc<dyn RecipeInputInventory>) -> Self {
|
pub fn new(inventory: Arc<dyn RecipeInputInventory>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
@ -315,8 +316,7 @@ impl ResultSlot {
|
|||||||
let result = self
|
let result = self
|
||||||
.match_recipe()
|
.match_recipe()
|
||||||
.await
|
.await
|
||||||
.map(|x| ItemStack::from(x.0))
|
.map_or(ItemStack::EMPTY.clone(), |x| ItemStack::from(x.0));
|
||||||
.unwrap_or(ItemStack::EMPTY.clone());
|
|
||||||
*self.result.lock().await = result.clone();
|
*self.result.lock().await = result.clone();
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
@ -348,8 +348,8 @@ impl Slot for ResultSlot {
|
|||||||
|
|
||||||
fn on_take_item<'a>(
|
fn on_take_item<'a>(
|
||||||
&'a self,
|
&'a self,
|
||||||
player: &'a dyn InventoryPlayer,
|
_player: &'a dyn InventoryPlayer,
|
||||||
stack: &'a ItemStack,
|
_stack: &'a ItemStack,
|
||||||
) -> BoxFuture<'a, ()> {
|
) -> BoxFuture<'a, ()> {
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
for i in 0..self.inventory.size() {
|
for i in 0..self.inventory.size() {
|
||||||
@ -360,7 +360,8 @@ impl Slot for ResultSlot {
|
|||||||
stack.item_count -= 1;
|
stack.item_count -= 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
self.stat_crafted(stack.item_count, player);
|
// TODO
|
||||||
|
//self.stat_crafted(stack.item_count, player);
|
||||||
self.mark_dirty().await;
|
self.mark_dirty().await;
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -489,7 +490,7 @@ impl CraftingTableScreenHandler {
|
|||||||
let crafting_inventory: Arc<dyn RecipeInputInventory> =
|
let crafting_inventory: Arc<dyn RecipeInputInventory> =
|
||||||
Arc::new(CraftingInventory::new(3, 3));
|
Arc::new(CraftingInventory::new(3, 3));
|
||||||
|
|
||||||
let mut crafting_table_handler = CraftingTableScreenHandler {
|
let mut crafting_table_handler = Self {
|
||||||
behaviour: ScreenHandlerBehaviour::new(sync_id, Some(WindowType::Crafting)),
|
behaviour: ScreenHandlerBehaviour::new(sync_id, Some(WindowType::Crafting)),
|
||||||
crafting_inventory: crafting_inventory.clone(),
|
crafting_inventory: crafting_inventory.clone(),
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,10 +1,10 @@
|
|||||||
use pumpkin_world::inventory::Inventory;
|
use pumpkin_world::inventory::Inventory;
|
||||||
|
|
||||||
// RecipeMatcher.java
|
// RecipeMatcher.java
|
||||||
pub struct RecipeMatcher {}
|
pub struct RecipeMatcher;
|
||||||
|
|
||||||
// RecipeFinder.java
|
// RecipeFinder.java
|
||||||
pub struct RecipeFinder {}
|
pub struct RecipeFinder;
|
||||||
|
|
||||||
// AbstractRecipeScreenHandle.java
|
// AbstractRecipeScreenHandle.java
|
||||||
pub trait RecipeFinderScreenHandler {}
|
pub trait RecipeFinderScreenHandler {}
|
||||||
|
|||||||
@ -65,9 +65,9 @@ impl Inventory for DoubleInventory {
|
|||||||
fn set_stack(&self, slot: usize, stack: ItemStack) -> InventoryFuture<'_, ()> {
|
fn set_stack(&self, slot: usize, stack: ItemStack) -> InventoryFuture<'_, ()> {
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
if slot >= self.first.size() {
|
if slot >= self.first.size() {
|
||||||
self.second.set_stack(slot - self.first.size(), stack).await
|
self.second.set_stack(slot - self.first.size(), stack).await;
|
||||||
} else {
|
} else {
|
||||||
self.first.set_stack(slot, stack).await
|
self.first.set_stack(slot, stack).await;
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@ -17,6 +17,7 @@ impl Default for EntityEquipment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl EntityEquipment {
|
impl EntityEquipment {
|
||||||
|
#[must_use]
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
equipment: HashMap::new(),
|
equipment: HashMap::new(),
|
||||||
@ -32,6 +33,7 @@ impl EntityEquipment {
|
|||||||
.clone()
|
.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub fn get(&self, slot: &EquipmentSlot) -> Arc<Mutex<ItemStack>> {
|
pub fn get(&self, slot: &EquipmentSlot) -> Arc<Mutex<ItemStack>> {
|
||||||
self.equipment
|
self.equipment
|
||||||
.get(slot)
|
.get(slot)
|
||||||
|
|||||||
@ -26,12 +26,6 @@ impl FurnaceLikeScreenHandler {
|
|||||||
furnace_block_entity: Arc<dyn BlockEntity>,
|
furnace_block_entity: Arc<dyn BlockEntity>,
|
||||||
window_type: WindowType,
|
window_type: WindowType,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let furnace_like_property_delegate = furnace_block_entity.to_property_delegate().unwrap();
|
|
||||||
let mut handler = Self {
|
|
||||||
inventory,
|
|
||||||
behaviour: ScreenHandlerBehaviour::new(sync_id, Some(window_type)),
|
|
||||||
};
|
|
||||||
|
|
||||||
struct FurnaceLikeScreenListener;
|
struct FurnaceLikeScreenListener;
|
||||||
impl ScreenHandlerListener for FurnaceLikeScreenListener {
|
impl ScreenHandlerListener for FurnaceLikeScreenListener {
|
||||||
fn on_property_update<'a>(
|
fn on_property_update<'a>(
|
||||||
@ -43,12 +37,17 @@ impl FurnaceLikeScreenHandler {
|
|||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
if let Some(sync_handler) = screen_handler.sync_handler.as_ref() {
|
if let Some(sync_handler) = screen_handler.sync_handler.as_ref() {
|
||||||
sync_handler
|
sync_handler
|
||||||
.update_property(screen_handler, property as i32, value)
|
.update_property(screen_handler, i32::from(property), value)
|
||||||
.await;
|
.await;
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
let furnace_like_property_delegate = furnace_block_entity.to_property_delegate().unwrap();
|
||||||
|
let mut handler = Self {
|
||||||
|
inventory,
|
||||||
|
behaviour: ScreenHandlerBehaviour::new(sync_id, Some(window_type)),
|
||||||
|
};
|
||||||
|
|
||||||
// 0: Fire icon (fuel left) counting from fuel burn time down to 0 (in-game ticks)
|
// 0: Fire icon (fuel left) counting from fuel burn time down to 0 (in-game ticks)
|
||||||
// 1: Maximum fuel burn time fuel burn time or 0 (in-game ticks)
|
// 1: Maximum fuel burn time fuel burn time or 0 (in-game ticks)
|
||||||
|
|||||||
@ -161,7 +161,7 @@ impl ScreenHandler for GenericContainerScreenHandler {
|
|||||||
// Re-acquire lock for insert_item (which expects &mut ItemStack)
|
// Re-acquire lock for insert_item (which expects &mut ItemStack)
|
||||||
let mut slot_stack_mut = slot_stack_lock.lock().await;
|
let mut slot_stack_mut = slot_stack_lock.lock().await;
|
||||||
|
|
||||||
if slot_index < (self.rows * 9) as i32 {
|
if slot_index < i32::from(self.rows * 9) {
|
||||||
// Move from inventory to player area (end)
|
// Move from inventory to player area (end)
|
||||||
if !self
|
if !self
|
||||||
.insert_item(
|
.insert_item(
|
||||||
|
|||||||
@ -19,6 +19,7 @@ use pumpkin_data::data_component_impl::EquipmentSlot;
|
|||||||
|
|
||||||
use crate::player::player_inventory::PlayerInventory;
|
use crate::player::player_inventory::PlayerInventory;
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub fn build_equipment_slots() -> HashMap<usize, EquipmentSlot> {
|
pub fn build_equipment_slots() -> HashMap<usize, EquipmentSlot> {
|
||||||
let mut equipment_slots = HashMap::new();
|
let mut equipment_slots = HashMap::new();
|
||||||
equipment_slots.insert(
|
equipment_slots.insert(
|
||||||
|
|||||||
@ -21,6 +21,7 @@ impl Default for EnderChestInventory {
|
|||||||
impl EnderChestInventory {
|
impl EnderChestInventory {
|
||||||
pub const INVENTORY_SIZE: usize = 27;
|
pub const INVENTORY_SIZE: usize = 27;
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
items: from_fn(|_| Arc::new(Mutex::new(ItemStack::EMPTY.clone()))),
|
items: from_fn(|_| Arc::new(Mutex::new(ItemStack::EMPTY.clone()))),
|
||||||
@ -51,7 +52,7 @@ impl Inventory for EnderChestInventory {
|
|||||||
|
|
||||||
fn is_empty(&self) -> InventoryFuture<'_, bool> {
|
fn is_empty(&self) -> InventoryFuture<'_, bool> {
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
for slot in self.items.iter() {
|
for slot in &self.items {
|
||||||
if !slot.lock().await.is_empty() {
|
if !slot.lock().await.is_empty() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -110,7 +111,7 @@ impl Inventory for EnderChestInventory {
|
|||||||
impl Clearable for EnderChestInventory {
|
impl Clearable for EnderChestInventory {
|
||||||
fn clear(&self) -> Pin<Box<dyn Future<Output = ()> + Send + '_>> {
|
fn clear(&self) -> Pin<Box<dyn Future<Output = ()> + Send + '_>> {
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
for item in self.items.iter() {
|
for item in &self.items {
|
||||||
*item.lock().await = ItemStack::EMPTY.clone();
|
*item.lock().await = ItemStack::EMPTY.clone();
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@ -58,18 +58,12 @@ impl PlayerInventory {
|
|||||||
|
|
||||||
/// getOffHandStack in source
|
/// getOffHandStack in source
|
||||||
pub async fn off_hand_item(&self) -> Arc<Mutex<ItemStack>> {
|
pub async fn off_hand_item(&self) -> Arc<Mutex<ItemStack>> {
|
||||||
let slot = self
|
let slot = self.equipment_slots.get(&Self::OFF_HAND_SLOT).unwrap();
|
||||||
.equipment_slots
|
|
||||||
.get(&PlayerInventory::OFF_HAND_SLOT)
|
|
||||||
.unwrap();
|
|
||||||
self.entity_equipment.lock().await.get(slot)
|
self.entity_equipment.lock().await.get(slot)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn swap_item(&self) -> (ItemStack, ItemStack) {
|
pub async fn swap_item(&self) -> (ItemStack, ItemStack) {
|
||||||
let slot = self
|
let slot = self.equipment_slots.get(&Self::OFF_HAND_SLOT).unwrap();
|
||||||
.equipment_slots
|
|
||||||
.get(&PlayerInventory::OFF_HAND_SLOT)
|
|
||||||
.unwrap();
|
|
||||||
let mut equipment = self.entity_equipment.lock().await;
|
let mut equipment = self.entity_equipment.lock().await;
|
||||||
let binding = self.held_item();
|
let binding = self.held_item();
|
||||||
let mut main_hand_item = binding.lock().await;
|
let mut main_hand_item = binding.lock().await;
|
||||||
@ -78,6 +72,7 @@ impl PlayerInventory {
|
|||||||
(main_hand_item.clone(), off_hand_item)
|
(main_hand_item.clone(), off_hand_item)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub fn is_valid_hotbar_index(slot: usize) -> bool {
|
pub fn is_valid_hotbar_index(slot: usize) -> bool {
|
||||||
slot < Self::HOTBAR_SIZE
|
slot < Self::HOTBAR_SIZE
|
||||||
}
|
}
|
||||||
@ -109,13 +104,11 @@ impl PlayerInventory {
|
|||||||
let count_left = self_stack.get_max_stack_size() - self_stack.item_count;
|
let count_left = self_stack.get_max_stack_size() - self_stack.item_count;
|
||||||
let count_min = stack_count.min(count_left);
|
let count_min = stack_count.min(count_left);
|
||||||
|
|
||||||
if count_min == 0 {
|
if count_min != 0 {
|
||||||
stack_count as usize
|
|
||||||
} else {
|
|
||||||
stack_count -= count_min;
|
stack_count -= count_min;
|
||||||
self_stack.increment(count_min);
|
self_stack.increment(count_min);
|
||||||
stack_count as usize
|
|
||||||
}
|
}
|
||||||
|
stack_count as usize
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_empty_slot(&self) -> i16 {
|
async fn get_empty_slot(&self) -> i16 {
|
||||||
@ -128,7 +121,7 @@ impl PlayerInventory {
|
|||||||
-1
|
-1
|
||||||
}
|
}
|
||||||
|
|
||||||
fn can_stack_add_more(&self, existing_stack: &ItemStack, stack: &ItemStack) -> bool {
|
fn can_stack_add_more(existing_stack: &ItemStack, stack: &ItemStack) -> bool {
|
||||||
!existing_stack.is_empty()
|
!existing_stack.is_empty()
|
||||||
&& existing_stack.are_items_and_components_equal(stack)
|
&& existing_stack.are_items_and_components_equal(stack)
|
||||||
&& existing_stack.is_stackable()
|
&& existing_stack.is_stackable()
|
||||||
@ -136,7 +129,7 @@ impl PlayerInventory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async fn get_occupied_slot_with_room_for_stack(&self, stack: &ItemStack) -> i16 {
|
async fn get_occupied_slot_with_room_for_stack(&self, stack: &ItemStack) -> i16 {
|
||||||
if self.can_stack_add_more(
|
if Self::can_stack_add_more(
|
||||||
&*self
|
&*self
|
||||||
.get_stack(self.get_selected_slot() as usize)
|
.get_stack(self.get_selected_slot() as usize)
|
||||||
.await
|
.await
|
||||||
@ -144,15 +137,15 @@ impl PlayerInventory {
|
|||||||
.await,
|
.await,
|
||||||
stack,
|
stack,
|
||||||
) {
|
) {
|
||||||
self.get_selected_slot() as i16
|
i16::from(self.get_selected_slot())
|
||||||
} else if self.can_stack_add_more(
|
} else if Self::can_stack_add_more(
|
||||||
&*self.get_stack(Self::OFF_HAND_SLOT).await.lock().await,
|
&*self.get_stack(Self::OFF_HAND_SLOT).await.lock().await,
|
||||||
stack,
|
stack,
|
||||||
) {
|
) {
|
||||||
Self::OFF_HAND_SLOT as i16
|
Self::OFF_HAND_SLOT as i16
|
||||||
} else {
|
} else {
|
||||||
for i in 0..Self::MAIN_SIZE {
|
for i in 0..Self::MAIN_SIZE {
|
||||||
if self.can_stack_add_more(&*self.main_inventory[i].lock().await, stack) {
|
if Self::can_stack_add_more(&*self.main_inventory[i].lock().await, stack) {
|
||||||
return i as i16;
|
return i as i16;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -298,7 +291,7 @@ impl PlayerInventory {
|
|||||||
{
|
{
|
||||||
player
|
player
|
||||||
.enqueue_slot_set_packet(&CSetPlayerInventory::new(
|
.enqueue_slot_set_packet(&CSetPlayerInventory::new(
|
||||||
(room_for_stack as i32).into(),
|
i32::from(room_for_stack).into(),
|
||||||
&self
|
&self
|
||||||
.get_stack(room_for_stack as usize)
|
.get_stack(room_for_stack as usize)
|
||||||
.await
|
.await
|
||||||
@ -316,7 +309,7 @@ impl PlayerInventory {
|
|||||||
impl Clearable for PlayerInventory {
|
impl Clearable for PlayerInventory {
|
||||||
fn clear(&self) -> Pin<Box<dyn Future<Output = ()> + Send + '_>> {
|
fn clear(&self) -> Pin<Box<dyn Future<Output = ()> + Send + '_>> {
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
for item in self.main_inventory.iter() {
|
for item in &self.main_inventory {
|
||||||
*item.lock().await = ItemStack::EMPTY.clone();
|
*item.lock().await = ItemStack::EMPTY.clone();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -332,7 +325,7 @@ impl Inventory for PlayerInventory {
|
|||||||
|
|
||||||
fn is_empty(&self) -> InventoryFuture<'_, bool> {
|
fn is_empty(&self) -> InventoryFuture<'_, bool> {
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
for item in self.main_inventory.iter() {
|
for item in &self.main_inventory {
|
||||||
if !item.lock().await.is_empty() {
|
if !item.lock().await.is_empty() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -31,11 +31,12 @@ impl PlayerScreenHandler {
|
|||||||
EquipmentSlot::FEET,
|
EquipmentSlot::FEET,
|
||||||
];
|
];
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub fn is_in_hotbar(slot: u8) -> bool {
|
pub fn is_in_hotbar(slot: u8) -> bool {
|
||||||
(36..=45).contains(&slot)
|
(36..=45).contains(&slot)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_slot(&self, slot: usize) -> Arc<dyn Slot> {
|
pub fn get_slot(&self, slot: usize) -> Arc<dyn Slot> {
|
||||||
self.behaviour.slots[slot].clone()
|
self.behaviour.slots[slot].clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -47,7 +48,7 @@ impl PlayerScreenHandler {
|
|||||||
let crafting_inventory: Arc<dyn RecipeInputInventory> =
|
let crafting_inventory: Arc<dyn RecipeInputInventory> =
|
||||||
Arc::new(CraftingInventory::new(2, 2));
|
Arc::new(CraftingInventory::new(2, 2));
|
||||||
|
|
||||||
let mut player_screen_handler = PlayerScreenHandler {
|
let mut player_screen_handler = Self {
|
||||||
behaviour: ScreenHandlerBehaviour::new(sync_id, window_type),
|
behaviour: ScreenHandlerBehaviour::new(sync_id, window_type),
|
||||||
crafting_inventory: crafting_inventory.clone(),
|
crafting_inventory: crafting_inventory.clone(),
|
||||||
};
|
};
|
||||||
@ -140,7 +141,6 @@ impl ScreenHandler for PlayerScreenHandler {
|
|||||||
} else if equipment_slot.slot_type() == EquipmentType::HumanoidArmor
|
} else if equipment_slot.slot_type() == EquipmentType::HumanoidArmor
|
||||||
&& self
|
&& self
|
||||||
.get_slot((8 - equipment_slot.get_entity_slot_id()) as usize)
|
.get_slot((8 - equipment_slot.get_entity_slot_id()) as usize)
|
||||||
.await
|
|
||||||
.get_cloned_stack()
|
.get_cloned_stack()
|
||||||
.await
|
.await
|
||||||
.is_empty()
|
.is_empty()
|
||||||
@ -159,7 +159,7 @@ impl ScreenHandler for PlayerScreenHandler {
|
|||||||
result
|
result
|
||||||
} else if matches!(equipment_slot, EquipmentSlot::OffHand(_))
|
} else if matches!(equipment_slot, EquipmentSlot::OffHand(_))
|
||||||
&& slot_index != 45
|
&& slot_index != 45
|
||||||
&& self.get_slot(45).await.get_cloned_stack().await.is_empty()
|
&& self.get_slot(45).get_cloned_stack().await.is_empty()
|
||||||
{
|
{
|
||||||
// Into empty offhand slot (45)
|
// Into empty offhand slot (45)
|
||||||
let index = 45;
|
let index = 45;
|
||||||
|
|||||||
@ -41,18 +41,19 @@ pub struct ScreenProperty {
|
|||||||
impl ScreenProperty {
|
impl ScreenProperty {
|
||||||
pub fn new(value: Arc<dyn PropertyDelegate>, index: u8) -> Self {
|
pub fn new(value: Arc<dyn PropertyDelegate>, index: u8) -> Self {
|
||||||
Self {
|
Self {
|
||||||
old_value: value.get_property(index as i32),
|
old_value: value.get_property(i32::from(index)),
|
||||||
index,
|
index,
|
||||||
value,
|
value,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub fn get(&self) -> i32 {
|
pub fn get(&self) -> i32 {
|
||||||
self.value.get_property(self.index as i32)
|
self.value.get_property(i32::from(self.index))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set(&mut self, value: i32) {
|
pub fn set(&mut self, value: i32) {
|
||||||
self.value.set_property(self.index as i32, value);
|
self.value.set_property(i32::from(self.index), value);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn has_changed(&mut self) -> bool {
|
pub fn has_changed(&mut self) -> bool {
|
||||||
@ -66,7 +67,7 @@ impl ScreenProperty {
|
|||||||
pub type PlayerFuture<'a, T> = Pin<Box<dyn Future<Output = T> + Send + 'a>>;
|
pub type PlayerFuture<'a, T> = Pin<Box<dyn Future<Output = T> + Send + 'a>>;
|
||||||
|
|
||||||
pub trait InventoryPlayer: Send + Sync {
|
pub trait InventoryPlayer: Send + Sync {
|
||||||
fn drop_item<'a>(&'a self, item: ItemStack, retain_ownership: bool) -> PlayerFuture<'a, ()>;
|
fn drop_item(&self, item: ItemStack, retain_ownership: bool) -> PlayerFuture<'_, ()>;
|
||||||
fn get_inventory(&self) -> Arc<PlayerInventory>;
|
fn get_inventory(&self) -> Arc<PlayerInventory>;
|
||||||
fn has_infinite_materials(&self) -> bool;
|
fn has_infinite_materials(&self) -> bool;
|
||||||
|
|
||||||
@ -238,10 +239,10 @@ pub trait ScreenHandler: Send + Sync {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn copy_shared_slots<'a>(
|
fn copy_shared_slots(
|
||||||
&'a mut self,
|
&mut self,
|
||||||
other: Arc<Mutex<dyn ScreenHandler>>,
|
other: Arc<Mutex<dyn ScreenHandler>>,
|
||||||
) -> ScreenHandlerFuture<'a, ()> {
|
) -> ScreenHandlerFuture<'_, ()> {
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
let mut table: HashMap<ComparableInventory, HashMap<usize, usize>> = HashMap::new();
|
let mut table: HashMap<ComparableInventory, HashMap<usize, usize>> = HashMap::new();
|
||||||
let other_binding = other.lock().await;
|
let other_binding = other.lock().await;
|
||||||
@ -274,7 +275,7 @@ pub trait ScreenHandler: Send + Sync {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn sync_state<'a>(&'a mut self) -> ScreenHandlerFuture<'a, ()> {
|
fn sync_state(&mut self) -> ScreenHandlerFuture<'_, ()> {
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
let behaviour = self.get_behaviour_mut();
|
let behaviour = self.get_behaviour_mut();
|
||||||
let mut previous_tracked_stacks = Vec::new();
|
let mut previous_tracked_stacks = Vec::new();
|
||||||
@ -311,20 +312,20 @@ pub trait ScreenHandler: Send + Sync {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn add_listener<'a>(
|
fn add_listener(
|
||||||
&'a mut self,
|
&mut self,
|
||||||
listener: Arc<dyn ScreenHandlerListener>,
|
listener: Arc<dyn ScreenHandlerListener>,
|
||||||
) -> ScreenHandlerFuture<'a, ()> {
|
) -> ScreenHandlerFuture<'_, ()> {
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
self.get_behaviour_mut().listeners.push(listener);
|
self.get_behaviour_mut().listeners.push(listener);
|
||||||
self.send_content_updates().await;
|
self.send_content_updates().await;
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_sync_handler<'a>(
|
fn update_sync_handler(
|
||||||
&'a mut self,
|
&mut self,
|
||||||
sync_handler: Arc<SyncHandler>,
|
sync_handler: Arc<SyncHandler>,
|
||||||
) -> ScreenHandlerFuture<'a, ()> {
|
) -> ScreenHandlerFuture<'_, ()> {
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
let behaviour = self.get_behaviour_mut();
|
let behaviour = self.get_behaviour_mut();
|
||||||
behaviour.sync_handler = Some(sync_handler.clone());
|
behaviour.sync_handler = Some(sync_handler.clone());
|
||||||
@ -332,7 +333,7 @@ pub trait ScreenHandler: Send + Sync {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_to_client<'a>(&'a mut self) -> ScreenHandlerFuture<'a, ()> {
|
fn update_to_client(&mut self) -> ScreenHandlerFuture<'_, ()> {
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
for i in 0..self.get_behaviour().slots.len() {
|
for i in 0..self.get_behaviour().slots.len() {
|
||||||
let behaviour = self.get_behaviour_mut();
|
let behaviour = self.get_behaviour_mut();
|
||||||
@ -359,16 +360,12 @@ pub trait ScreenHandler: Send + Sync {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_tracked_properties<'a>(
|
fn update_tracked_properties(&mut self, idx: i32, value: i32) -> ScreenHandlerFuture<'_, ()> {
|
||||||
&'a mut self,
|
|
||||||
idx: i32,
|
|
||||||
value: i32,
|
|
||||||
) -> ScreenHandlerFuture<'a, ()> {
|
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
let behaviour = self.get_behaviour_mut();
|
let behaviour = self.get_behaviour_mut();
|
||||||
if idx <= behaviour.tracked_property_values.len() as i32 {
|
if idx <= behaviour.tracked_property_values.len() as i32 {
|
||||||
behaviour.tracked_property_values[idx as usize] = value;
|
behaviour.tracked_property_values[idx as usize] = value;
|
||||||
for listener in behaviour.listeners.iter() {
|
for listener in &behaviour.listeners {
|
||||||
listener
|
listener
|
||||||
.on_property_update(behaviour, idx as u8, value)
|
.on_property_update(behaviour, idx as u8, value)
|
||||||
.await;
|
.await;
|
||||||
@ -377,11 +374,7 @@ pub trait ScreenHandler: Send + Sync {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_property_updates<'a>(
|
fn check_property_updates(&mut self, idx: i32, value: i32) -> ScreenHandlerFuture<'_, ()> {
|
||||||
&'a mut self,
|
|
||||||
idx: i32,
|
|
||||||
value: i32,
|
|
||||||
) -> ScreenHandlerFuture<'a, ()> {
|
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
let behaviour = self.get_behaviour_mut();
|
let behaviour = self.get_behaviour_mut();
|
||||||
if !behaviour.disable_sync
|
if !behaviour.disable_sync
|
||||||
@ -400,18 +393,18 @@ pub trait ScreenHandler: Send + Sync {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_tracked_slot<'a>(
|
fn update_tracked_slot(
|
||||||
&'a mut self,
|
&mut self,
|
||||||
slot: usize,
|
slot: usize,
|
||||||
stack: ItemStack,
|
stack: ItemStack,
|
||||||
) -> ScreenHandlerFuture<'a, ()> {
|
) -> ScreenHandlerFuture<'_, ()> {
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
let behaviour = self.get_behaviour_mut();
|
let behaviour = self.get_behaviour_mut();
|
||||||
let other_stack = &behaviour.tracked_stacks[slot];
|
let other_stack = &behaviour.tracked_stacks[slot];
|
||||||
if !other_stack.are_equal(&stack) {
|
if !other_stack.are_equal(&stack) {
|
||||||
behaviour.tracked_stacks[slot] = stack.clone();
|
behaviour.tracked_stacks[slot] = stack.clone();
|
||||||
|
|
||||||
for listener in behaviour.listeners.iter() {
|
for listener in &behaviour.listeners {
|
||||||
listener
|
listener
|
||||||
.on_slot_update(behaviour, slot as u8, stack.clone())
|
.on_slot_update(behaviour, slot as u8, stack.clone())
|
||||||
.await;
|
.await;
|
||||||
@ -420,11 +413,7 @@ pub trait ScreenHandler: Send + Sync {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_slot_updates<'a>(
|
fn check_slot_updates(&mut self, slot: usize, stack: ItemStack) -> ScreenHandlerFuture<'_, ()> {
|
||||||
&'a mut self,
|
|
||||||
slot: usize,
|
|
||||||
stack: ItemStack,
|
|
||||||
) -> ScreenHandlerFuture<'a, ()> {
|
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
let behaviour = self.get_behaviour_mut();
|
let behaviour = self.get_behaviour_mut();
|
||||||
if !behaviour.disable_sync {
|
if !behaviour.disable_sync {
|
||||||
@ -443,7 +432,7 @@ pub trait ScreenHandler: Send + Sync {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_cursor_stack_updates<'a>(&'a mut self) -> ScreenHandlerFuture<'a, ()> {
|
fn check_cursor_stack_updates(&mut self) -> ScreenHandlerFuture<'_, ()> {
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
let behaviour = self.get_behaviour_mut();
|
let behaviour = self.get_behaviour_mut();
|
||||||
if !behaviour.disable_sync {
|
if !behaviour.disable_sync {
|
||||||
@ -462,7 +451,7 @@ pub trait ScreenHandler: Send + Sync {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn send_content_updates<'a>(&'a mut self) -> ScreenHandlerFuture<'a, ()> {
|
fn send_content_updates(&mut self) -> ScreenHandlerFuture<'_, ()> {
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
let slots_len = self.get_behaviour().slots.len();
|
let slots_len = self.get_behaviour().slots.len();
|
||||||
|
|
||||||
@ -492,7 +481,7 @@ pub trait ScreenHandler: Send + Sync {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_slot_valid<'a>(&'a self, slot: i32) -> ScreenHandlerFuture<'a, bool> {
|
fn is_slot_valid(&self, slot: i32) -> ScreenHandlerFuture<'_, bool> {
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
slot == -1 || slot == -999 || slot < self.get_behaviour().slots.len() as i32
|
slot == -1 || slot == -999 || slot < self.get_behaviour().slots.len() as i32
|
||||||
})
|
})
|
||||||
@ -645,6 +634,7 @@ pub trait ScreenHandler: Send + Sync {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[expect(clippy::too_many_lines)]
|
||||||
fn internal_on_slot_click<'a>(
|
fn internal_on_slot_click<'a>(
|
||||||
&'a mut self,
|
&'a mut self,
|
||||||
slot_index: i32,
|
slot_index: i32,
|
||||||
@ -658,7 +648,7 @@ pub trait ScreenHandler: Send + Sync {
|
|||||||
let mut cursor_stack = behavior.cursor_stack.lock().await;
|
let mut cursor_stack = behavior.cursor_stack.lock().await;
|
||||||
let mut to_pick_up = cursor_stack.get_max_stack_size() - cursor_stack.item_count;
|
let mut to_pick_up = cursor_stack.get_max_stack_size() - cursor_stack.item_count;
|
||||||
|
|
||||||
for slot in behavior.slots.iter() {
|
for slot in &behavior.slots {
|
||||||
if to_pick_up == 0 {
|
if to_pick_up == 0 {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -727,7 +717,7 @@ pub trait ScreenHandler: Send + Sync {
|
|||||||
|
|
||||||
let mut cursor_stack = behaviour.cursor_stack.lock().await;
|
let mut cursor_stack = behaviour.cursor_stack.lock().await;
|
||||||
let initial_count = cursor_stack.item_count;
|
let initial_count = cursor_stack.item_count;
|
||||||
for slot_index in behaviour.drag_slots.iter() {
|
for slot_index in &behaviour.drag_slots {
|
||||||
let slot = behaviour.slots[*slot_index as usize].clone();
|
let slot = behaviour.slots[*slot_index as usize].clone();
|
||||||
let stack_lock = slot.get_stack().await;
|
let stack_lock = slot.get_stack().await;
|
||||||
let stack = stack_lock.lock().await;
|
let stack = stack_lock.lock().await;
|
||||||
@ -1070,6 +1060,7 @@ pub struct ScreenHandlerBehaviour {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ScreenHandlerBehaviour {
|
impl ScreenHandlerBehaviour {
|
||||||
|
#[must_use]
|
||||||
pub fn new(sync_id: u8, window_type: Option<WindowType>) -> Self {
|
pub fn new(sync_id: u8, window_type: Option<WindowType>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
slots: Vec::new(),
|
slots: Vec::new(),
|
||||||
|
|||||||
@ -232,9 +232,7 @@ pub trait Slot: Send + Sync {
|
|||||||
.min(stack.item_count)
|
.min(stack.item_count)
|
||||||
.min(self.get_max_item_count_for_stack(&stack).await - stack_self.item_count);
|
.min(self.get_max_item_count_for_stack(&stack).await - stack_self.item_count);
|
||||||
|
|
||||||
if min_count == 0 {
|
if min_count != 0 {
|
||||||
stack
|
|
||||||
} else {
|
|
||||||
if stack_self.is_empty() {
|
if stack_self.is_empty() {
|
||||||
drop(stack_self);
|
drop(stack_self);
|
||||||
self.set_stack(stack.split(min_count)).await;
|
self.set_stack(stack.split(min_count)).await;
|
||||||
@ -245,12 +243,9 @@ pub trait Slot: Send + Sync {
|
|||||||
drop(stack_self);
|
drop(stack_self);
|
||||||
self.set_stack(cloned_stack).await;
|
self.set_stack(cloned_stack).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
stack
|
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
stack
|
|
||||||
}
|
}
|
||||||
|
stack
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -25,6 +25,7 @@ impl Default for SyncHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl SyncHandler {
|
impl SyncHandler {
|
||||||
|
#[must_use]
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
player: Mutex::new(None),
|
player: Mutex::new(None),
|
||||||
@ -128,7 +129,7 @@ pub struct TrackedStack {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl TrackedStack {
|
impl TrackedStack {
|
||||||
pub const EMPTY: TrackedStack = TrackedStack {
|
pub const EMPTY: Self = Self {
|
||||||
received_stack: None,
|
received_stack: None,
|
||||||
received_hash: None,
|
received_hash: None,
|
||||||
};
|
};
|
||||||
|
|||||||
@ -36,14 +36,16 @@ pub enum EnchantmentTable {
|
|||||||
// TODO: No more magic numbers
|
// TODO: No more magic numbers
|
||||||
impl WindowPropertyTrait for EnchantmentTable {
|
impl WindowPropertyTrait for EnchantmentTable {
|
||||||
fn to_id(self) -> i16 {
|
fn to_id(self) -> i16 {
|
||||||
use EnchantmentTable::*;
|
use EnchantmentTable::{
|
||||||
|
EnchantmentId, EnchantmentLevel, EnchantmentSeed, LevelRequirement,
|
||||||
|
};
|
||||||
|
|
||||||
(match self {
|
i16::from(match self {
|
||||||
LevelRequirement { slot } => slot,
|
LevelRequirement { slot } => slot,
|
||||||
EnchantmentSeed => 3,
|
EnchantmentSeed => 3,
|
||||||
EnchantmentId { slot } => 4 + slot,
|
EnchantmentId { slot } => 4 + slot,
|
||||||
EnchantmentLevel { slot } => 7 + slot,
|
EnchantmentLevel { slot } => 7 + slot,
|
||||||
}) as i16
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub enum Beacon {
|
pub enum Beacon {
|
||||||
|
|||||||
@ -15,3 +15,6 @@ pumpkin-data.workspace = true
|
|||||||
proc-macro2.workspace = true
|
proc-macro2.workspace = true
|
||||||
quote.workspace = true
|
quote.workspace = true
|
||||||
syn.workspace = true
|
syn.workspace = true
|
||||||
|
|
||||||
|
[lints]
|
||||||
|
workspace = true
|
||||||
@ -46,7 +46,7 @@ pub fn cancellable(_args: TokenStream, input: TokenStream) -> TokenStream {
|
|||||||
if fields
|
if fields
|
||||||
.named
|
.named
|
||||||
.iter()
|
.iter()
|
||||||
.any(|f| f.ident.as_ref().map(|i| i == "cancelled").unwrap_or(false))
|
.any(|f| f.ident.as_ref().is_some_and(|i| i == "cancelled"))
|
||||||
{
|
{
|
||||||
abort!(fields.span(), "Struct already has a `cancelled` field");
|
abort!(fields.span(), "Struct already has a `cancelled` field");
|
||||||
}
|
}
|
||||||
@ -199,13 +199,10 @@ pub fn pumpkin_block(args: TokenStream, item: TokenStream) -> TokenStream {
|
|||||||
let arg_value = arg_lit.value();
|
let arg_value = arg_lit.value();
|
||||||
|
|
||||||
let block_name = arg_value.strip_prefix("minecraft:").unwrap_or(&arg_value);
|
let block_name = arg_value.strip_prefix("minecraft:").unwrap_or(&arg_value);
|
||||||
let block = match Block::from_name(block_name) {
|
let Some(block) = Block::from_name(block_name) else {
|
||||||
Some(b) => b,
|
return syn::Error::new(arg_lit.span(), "Invalid block name")
|
||||||
None => {
|
.to_compile_error()
|
||||||
return syn::Error::new(arg_lit.span(), "Invalid block name")
|
.into();
|
||||||
.to_compile_error()
|
|
||||||
.into();
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
let block_id = block.id;
|
let block_id = block.id;
|
||||||
|
|
||||||
@ -239,16 +236,10 @@ pub fn pumpkin_block_from_tag(args: TokenStream, item: TokenStream) -> TokenStre
|
|||||||
|
|
||||||
let full_tag = arg_lit.value();
|
let full_tag = arg_lit.value();
|
||||||
|
|
||||||
let values = match get_tag_ids(RegistryKey::Block, &full_tag) {
|
let Some(values) = get_tag_ids(RegistryKey::Block, &full_tag) else {
|
||||||
Some(v) => v,
|
return syn::Error::new(arg_lit.span(), format!("Failed to get tag IDs: {full_tag}"))
|
||||||
None => {
|
|
||||||
return syn::Error::new(
|
|
||||||
arg_lit.span(),
|
|
||||||
format!("Failed to get tag IDs: {}", full_tag),
|
|
||||||
)
|
|
||||||
.to_compile_error()
|
.to_compile_error()
|
||||||
.into();
|
.into();
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let expanded = quote! {
|
let expanded = quote! {
|
||||||
@ -522,7 +513,7 @@ fn check_serial_attributes(attrs: &[Attribute]) -> (bool, bool) {
|
|||||||
let mut is_big_endian = false;
|
let mut is_big_endian = false;
|
||||||
let mut no_prefix = false;
|
let mut no_prefix = false;
|
||||||
|
|
||||||
for attr in attrs.iter() {
|
for attr in attrs {
|
||||||
if attr.path().is_ident("serial") {
|
if attr.path().is_ident("serial") {
|
||||||
let _ = attr.parse_nested_meta(|meta| {
|
let _ = attr.parse_nested_meta(|meta| {
|
||||||
if meta.path.is_ident("big_endian") {
|
if meta.path.is_ident("big_endian") {
|
||||||
@ -545,8 +536,7 @@ fn is_vec(ty: &Type) -> bool {
|
|||||||
.segments
|
.segments
|
||||||
.iter()
|
.iter()
|
||||||
.last()
|
.last()
|
||||||
.map(|segment| segment.ident == "Vec")
|
.is_some_and(|segment| segment.ident == "Vec")
|
||||||
.unwrap_or(false)
|
|
||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|||||||
@ -14,3 +14,6 @@ flate2.workspace = true
|
|||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
tempfile.workspace = true
|
tempfile.workspace = true
|
||||||
|
|
||||||
|
[lints]
|
||||||
|
workspace = true
|
||||||
|
|||||||
@ -20,8 +20,9 @@ pub struct NbtCompound {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl NbtCompound {
|
impl NbtCompound {
|
||||||
pub fn new() -> NbtCompound {
|
#[must_use]
|
||||||
NbtCompound {
|
pub fn new() -> Self {
|
||||||
|
Self {
|
||||||
child_tags: Vec::new(),
|
child_tags: Vec::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -39,7 +40,7 @@ impl NbtCompound {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let len = reader.get_u16_be()?;
|
let len = reader.get_u16_be()?;
|
||||||
reader.skip_bytes(len as i64)?;
|
reader.skip_bytes(i64::from(len))?;
|
||||||
|
|
||||||
// Skip Value
|
// Skip Value
|
||||||
NbtTag::skip_data(reader, tag_id)?;
|
NbtTag::skip_data(reader, tag_id)?;
|
||||||
@ -50,8 +51,8 @@ impl NbtCompound {
|
|||||||
|
|
||||||
pub fn deserialize_content<R: Read + Seek>(
|
pub fn deserialize_content<R: Read + Seek>(
|
||||||
reader: &mut NbtReadHelper<R>,
|
reader: &mut NbtReadHelper<R>,
|
||||||
) -> Result<NbtCompound, Error> {
|
) -> Result<Self, Error> {
|
||||||
let mut compound = NbtCompound::new();
|
let mut compound = Self::new();
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let tag_id = match reader.get_u8_be() {
|
let tag_id = match reader.get_u8_be() {
|
||||||
@ -83,6 +84,7 @@ impl NbtCompound {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub fn is_empty(&self) -> bool {
|
pub fn is_empty(&self) -> bool {
|
||||||
self.child_tags.is_empty()
|
self.child_tags.is_empty()
|
||||||
}
|
}
|
||||||
@ -106,7 +108,7 @@ impl NbtCompound {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn put_bool(&mut self, name: &str, value: bool) {
|
pub fn put_bool(&mut self, name: &str, value: bool) {
|
||||||
self.put(name, NbtTag::Byte(if value { 1 } else { 0 }));
|
self.put(name, NbtTag::Byte(i8::from(value)));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn put_short(&mut self, name: &str, value: i16) {
|
pub fn put_short(&mut self, name: &str, value: i16) {
|
||||||
@ -128,15 +130,17 @@ impl NbtCompound {
|
|||||||
self.put(name, NbtTag::Double(value));
|
self.put(name, NbtTag::Double(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn put_component(&mut self, name: &str, value: NbtCompound) {
|
pub fn put_component(&mut self, name: &str, value: Self) {
|
||||||
self.put(name, NbtTag::Compound(value));
|
self.put(name, NbtTag::Compound(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub fn get_byte(&self, name: &str) -> Option<i8> {
|
pub fn get_byte(&self, name: &str) -> Option<i8> {
|
||||||
self.get(name).and_then(|tag| tag.extract_byte())
|
self.get(name).and_then(super::tag::NbtTag::extract_byte)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
pub fn get(&self, name: &str) -> Option<&NbtTag> {
|
pub fn get(&self, name: &str) -> Option<&NbtTag> {
|
||||||
self.child_tags
|
self.child_tags
|
||||||
.iter()
|
.iter()
|
||||||
@ -144,46 +148,57 @@ impl NbtCompound {
|
|||||||
.map(|r| &r.1)
|
.map(|r| &r.1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub fn get_short(&self, name: &str) -> Option<i16> {
|
pub fn get_short(&self, name: &str) -> Option<i16> {
|
||||||
self.get(name).and_then(|tag| tag.extract_short())
|
self.get(name).and_then(super::tag::NbtTag::extract_short)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub fn get_int(&self, name: &str) -> Option<i32> {
|
pub fn get_int(&self, name: &str) -> Option<i32> {
|
||||||
self.get(name).and_then(|tag| tag.extract_int())
|
self.get(name).and_then(super::tag::NbtTag::extract_int)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub fn get_long(&self, name: &str) -> Option<i64> {
|
pub fn get_long(&self, name: &str) -> Option<i64> {
|
||||||
self.get(name).and_then(|tag| tag.extract_long())
|
self.get(name).and_then(super::tag::NbtTag::extract_long)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub fn get_float(&self, name: &str) -> Option<f32> {
|
pub fn get_float(&self, name: &str) -> Option<f32> {
|
||||||
self.get(name).and_then(|tag| tag.extract_float())
|
self.get(name).and_then(super::tag::NbtTag::extract_float)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub fn get_double(&self, name: &str) -> Option<f64> {
|
pub fn get_double(&self, name: &str) -> Option<f64> {
|
||||||
self.get(name).and_then(|tag| tag.extract_double())
|
self.get(name).and_then(super::tag::NbtTag::extract_double)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub fn get_bool(&self, name: &str) -> Option<bool> {
|
pub fn get_bool(&self, name: &str) -> Option<bool> {
|
||||||
self.get(name).and_then(|tag| tag.extract_bool())
|
self.get(name).and_then(super::tag::NbtTag::extract_bool)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub fn get_string(&self, name: &str) -> Option<&str> {
|
pub fn get_string(&self, name: &str) -> Option<&str> {
|
||||||
self.get(name).and_then(|tag| tag.extract_string())
|
self.get(name).and_then(|tag| tag.extract_string())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub fn get_list(&self, name: &str) -> Option<&[NbtTag]> {
|
pub fn get_list(&self, name: &str) -> Option<&[NbtTag]> {
|
||||||
self.get(name).and_then(|tag| tag.extract_list())
|
self.get(name).and_then(|tag| tag.extract_list())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_compound(&self, name: &str) -> Option<&NbtCompound> {
|
#[must_use]
|
||||||
|
pub fn get_compound(&self, name: &str) -> Option<&Self> {
|
||||||
self.get(name).and_then(|tag| tag.extract_compound())
|
self.get(name).and_then(|tag| tag.extract_compound())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub fn get_int_array(&self, name: &str) -> Option<&[i32]> {
|
pub fn get_int_array(&self, name: &str) -> Option<&[i32]> {
|
||||||
self.get(name).and_then(|tag| tag.extract_int_array())
|
self.get(name).and_then(|tag| tag.extract_int_array())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub fn get_long_array(&self, name: &str) -> Option<&[i64]> {
|
pub fn get_long_array(&self, name: &str) -> Option<&[i64]> {
|
||||||
self.get(name).and_then(|tag| tag.extract_long_array())
|
self.get(name).and_then(|tag| tag.extract_long_array())
|
||||||
}
|
}
|
||||||
@ -197,7 +212,7 @@ impl From<Nbt> for NbtCompound {
|
|||||||
|
|
||||||
impl FromIterator<(String, NbtTag)> for NbtCompound {
|
impl FromIterator<(String, NbtTag)> for NbtCompound {
|
||||||
fn from_iter<T: IntoIterator<Item = (String, NbtTag)>>(iter: T) -> Self {
|
fn from_iter<T: IntoIterator<Item = (String, NbtTag)>>(iter: T) -> Self {
|
||||||
let mut compound = NbtCompound::new();
|
let mut compound = Self::new();
|
||||||
for (key, value) in iter {
|
for (key, value) in iter {
|
||||||
compound.put(&key, value);
|
compound.put(&key, value);
|
||||||
}
|
}
|
||||||
@ -216,13 +231,13 @@ impl IntoIterator for NbtCompound {
|
|||||||
|
|
||||||
impl Extend<(String, NbtTag)> for NbtCompound {
|
impl Extend<(String, NbtTag)> for NbtCompound {
|
||||||
fn extend<T: IntoIterator<Item = (String, NbtTag)>>(&mut self, iter: T) {
|
fn extend<T: IntoIterator<Item = (String, NbtTag)>>(&mut self, iter: T) {
|
||||||
self.child_tags.extend(iter)
|
self.child_tags.extend(iter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Rust's AsRef is currently not reflexive so we need to implement it manually
|
// Rust's AsRef is currently not reflexive so we need to implement it manually
|
||||||
impl AsRef<NbtCompound> for NbtCompound {
|
impl AsRef<Self> for NbtCompound {
|
||||||
fn as_ref(&self) -> &NbtCompound {
|
fn as_ref(&self) -> &Self {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -267,11 +282,11 @@ impl<'de> Deserialize<'de> for NbtCompound {
|
|||||||
|
|
||||||
impl From<NbtCompound> for NbtTag {
|
impl From<NbtCompound> for NbtTag {
|
||||||
fn from(value: NbtCompound) -> Self {
|
fn from(value: NbtCompound) -> Self {
|
||||||
NbtTag::Compound(value)
|
Self::Compound(value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// SNBT display implementation for NbtCompound
|
/// SNBT display implementation for `NbtCompound`
|
||||||
impl Display for NbtCompound {
|
impl Display for NbtCompound {
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
f.write_str("{")?;
|
f.write_str("{")?;
|
||||||
@ -279,7 +294,7 @@ impl Display for NbtCompound {
|
|||||||
if i > 0 {
|
if i > 0 {
|
||||||
f.write_str(", ")?;
|
f.write_str(", ")?;
|
||||||
}
|
}
|
||||||
write!(f, "{}: {}", key, value)?;
|
write!(f, "{key}: {value}")?;
|
||||||
}
|
}
|
||||||
f.write_str("}")
|
f.write_str("}")
|
||||||
}
|
}
|
||||||
@ -288,52 +303,52 @@ impl Display for NbtCompound {
|
|||||||
impl Display for NbtTag {
|
impl Display for NbtTag {
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
NbtTag::End => Ok(()),
|
Self::End => Ok(()),
|
||||||
NbtTag::Byte(v) => write!(f, "{v}b"),
|
Self::Byte(v) => write!(f, "{v}b"),
|
||||||
NbtTag::Short(v) => write!(f, "{v}s"),
|
Self::Short(v) => write!(f, "{v}s"),
|
||||||
NbtTag::Int(v) => write!(f, "{v}"),
|
Self::Int(v) => write!(f, "{v}"),
|
||||||
NbtTag::Long(v) => write!(f, "{v}L"),
|
Self::Long(v) => write!(f, "{v}L"),
|
||||||
NbtTag::Float(v) => write!(f, "{v}f"),
|
Self::Float(v) => write!(f, "{v}f"),
|
||||||
NbtTag::Double(v) => write!(f, "{v}d"),
|
Self::Double(v) => write!(f, "{v}d"),
|
||||||
NbtTag::String(v) => write!(f, "\"{v}\""), // TODO: Proper escaping needed for robust SNBT
|
Self::String(v) => write!(f, "\"{v}\""), // TODO: Proper escaping needed for robust SNBT
|
||||||
NbtTag::Compound(v) => write!(f, "{v}"),
|
Self::Compound(v) => write!(f, "{v}"),
|
||||||
NbtTag::ByteArray(v) => {
|
Self::ByteArray(v) => {
|
||||||
f.write_str("[B;")?;
|
f.write_str("[B;")?;
|
||||||
for (i, byte) in v.iter().enumerate() {
|
for (i, byte) in v.iter().enumerate() {
|
||||||
if i > 0 {
|
if i > 0 {
|
||||||
f.write_str(",")?
|
f.write_str(",")?;
|
||||||
}
|
}
|
||||||
write!(f, " {}b", byte)?;
|
write!(f, " {byte}b")?;
|
||||||
}
|
}
|
||||||
f.write_str("]")
|
f.write_str("]")
|
||||||
}
|
}
|
||||||
NbtTag::List(v) => {
|
Self::List(v) => {
|
||||||
f.write_str("[")?;
|
f.write_str("[")?;
|
||||||
for (i, tag) in v.iter().enumerate() {
|
for (i, tag) in v.iter().enumerate() {
|
||||||
if i > 0 {
|
if i > 0 {
|
||||||
f.write_str(", ")?
|
f.write_str(", ")?;
|
||||||
}
|
}
|
||||||
write!(f, "{}", tag)?;
|
write!(f, "{tag}")?;
|
||||||
}
|
}
|
||||||
f.write_str("]")
|
f.write_str("]")
|
||||||
}
|
}
|
||||||
NbtTag::IntArray(v) => {
|
Self::IntArray(v) => {
|
||||||
f.write_str("[I;")?;
|
f.write_str("[I;")?;
|
||||||
for (i, int) in v.iter().enumerate() {
|
for (i, int) in v.iter().enumerate() {
|
||||||
if i > 0 {
|
if i > 0 {
|
||||||
f.write_str(",")?
|
f.write_str(",")?;
|
||||||
}
|
}
|
||||||
write!(f, " {}", int)?;
|
write!(f, " {int}")?;
|
||||||
}
|
}
|
||||||
f.write_str("]")
|
f.write_str("]")
|
||||||
}
|
}
|
||||||
NbtTag::LongArray(v) => {
|
Self::LongArray(v) => {
|
||||||
f.write_str("[L;")?;
|
f.write_str("[L;")?;
|
||||||
for (i, long) in v.iter().enumerate() {
|
for (i, long) in v.iter().enumerate() {
|
||||||
if i > 0 {
|
if i > 0 {
|
||||||
f.write_str(",")?
|
f.write_str(",")?;
|
||||||
}
|
}
|
||||||
write!(f, " {}L", long)?;
|
write!(f, " {long}L")?;
|
||||||
}
|
}
|
||||||
f.write_str("]")
|
f.write_str("]")
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,7 +1,10 @@
|
|||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::io::{Seek, SeekFrom};
|
use std::io::{Seek, SeekFrom};
|
||||||
|
|
||||||
use crate::*;
|
use crate::{
|
||||||
|
BYTE_ARRAY_ID, BYTE_ID, COMPOUND_ID, END_ID, Error, INT_ARRAY_ID, INT_ID, LIST_ID,
|
||||||
|
LONG_ARRAY_ID, LONG_ID, NbtTag, get_nbt_string, io,
|
||||||
|
};
|
||||||
use io::Read;
|
use io::Read;
|
||||||
use serde::de::{self, DeserializeSeed, IntoDeserializer, MapAccess, SeqAccess, Visitor};
|
use serde::de::{self, DeserializeSeed, IntoDeserializer, MapAccess, SeqAccess, Visitor};
|
||||||
use serde::{Deserialize, forward_to_deserialize_any};
|
use serde::{Deserialize, forward_to_deserialize_any};
|
||||||
@ -13,7 +16,7 @@ thread_local! {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn take_curr_visitor_seq_list_id() -> Option<u8> {
|
pub(super) fn take_curr_visitor_seq_list_id() -> Option<u8> {
|
||||||
CURR_VISITOR_LIST_TYPE.with(|cell| cell.take())
|
CURR_VISITOR_LIST_TYPE.with(std::cell::RefCell::take)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(super) fn set_curr_visitor_seq_list_id(tag: Option<u8>) {
|
pub(super) fn set_curr_visitor_seq_list_id(tag: Option<u8>) {
|
||||||
@ -85,7 +88,7 @@ pub struct Deserializer<R: Read + Seek> {
|
|||||||
|
|
||||||
impl<R: Read + Seek> Deserializer<R> {
|
impl<R: Read + Seek> Deserializer<R> {
|
||||||
pub fn new(input: R, is_named: bool) -> Self {
|
pub fn new(input: R, is_named: bool) -> Self {
|
||||||
Deserializer {
|
Self {
|
||||||
input: NbtReadHelper { reader: input },
|
input: NbtReadHelper { reader: input },
|
||||||
tag_to_deserialize_stack: None,
|
tag_to_deserialize_stack: None,
|
||||||
in_list: false,
|
in_list: false,
|
||||||
@ -230,8 +233,7 @@ impl<'de, R: Read + Seek> de::Deserializer<'de> for &mut Deserializer<R> {
|
|||||||
if let Some(tag_id) = self.tag_to_deserialize_stack {
|
if let Some(tag_id) = self.tag_to_deserialize_stack {
|
||||||
if tag_id != COMPOUND_ID {
|
if tag_id != COMPOUND_ID {
|
||||||
return Err(Error::SerdeError(format!(
|
return Err(Error::SerdeError(format!(
|
||||||
"Trying to deserialize a map without a compound ID (id {})",
|
"Trying to deserialize a map without a compound ID (id {tag_id})"
|
||||||
tag_id
|
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@ -59,13 +59,13 @@ pub enum Error {
|
|||||||
|
|
||||||
impl ser::Error for Error {
|
impl ser::Error for Error {
|
||||||
fn custom<T: Display>(msg: T) -> Self {
|
fn custom<T: Display>(msg: T) -> Self {
|
||||||
Error::SerdeError(msg.to_string())
|
Self::SerdeError(msg.to_string())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl de::Error for Error {
|
impl de::Error for Error {
|
||||||
fn custom<T: Display>(msg: T) -> Self {
|
fn custom<T: Display>(msg: T) -> Self {
|
||||||
Error::SerdeError(msg.to_string())
|
Self::SerdeError(msg.to_string())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -76,40 +76,42 @@ pub struct Nbt {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Nbt {
|
impl Nbt {
|
||||||
|
#[must_use]
|
||||||
pub fn new(name: String, tag: NbtCompound) -> Self {
|
pub fn new(name: String, tag: NbtCompound) -> Self {
|
||||||
Nbt {
|
Self {
|
||||||
name,
|
name,
|
||||||
root_tag: tag,
|
root_tag: tag,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn read<R: Read + Seek>(reader: &mut NbtReadHelper<R>) -> Result<Nbt, Error> {
|
pub fn read<R: Read + Seek>(reader: &mut NbtReadHelper<R>) -> Result<Self, Error> {
|
||||||
let tag_type_id = reader.get_u8_be()?;
|
let tag_type_id = reader.get_u8_be()?;
|
||||||
|
|
||||||
if tag_type_id != COMPOUND_ID {
|
if tag_type_id != COMPOUND_ID {
|
||||||
return Err(Error::NoRootCompound(tag_type_id));
|
return Err(Error::NoRootCompound(tag_type_id));
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Nbt {
|
Ok(Self {
|
||||||
name: get_nbt_string(reader)?,
|
name: get_nbt_string(reader)?,
|
||||||
root_tag: NbtCompound::deserialize_content(reader)?,
|
root_tag: NbtCompound::deserialize_content(reader)?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Reads an NBT tag that doesn't contain the name of the root `Compound`.
|
/// Reads an NBT tag that doesn't contain the name of the root `Compound`.
|
||||||
pub fn read_unnamed<R: Read + Seek>(reader: &mut NbtReadHelper<R>) -> Result<Nbt, Error> {
|
pub fn read_unnamed<R: Read + Seek>(reader: &mut NbtReadHelper<R>) -> Result<Self, Error> {
|
||||||
let tag_type_id = reader.get_u8_be()?;
|
let tag_type_id = reader.get_u8_be()?;
|
||||||
|
|
||||||
if tag_type_id != COMPOUND_ID {
|
if tag_type_id != COMPOUND_ID {
|
||||||
return Err(Error::NoRootCompound(tag_type_id));
|
return Err(Error::NoRootCompound(tag_type_id));
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Nbt {
|
Ok(Self {
|
||||||
name: String::new(),
|
name: String::new(),
|
||||||
root_tag: NbtCompound::deserialize_content(reader)?,
|
root_tag: NbtCompound::deserialize_content(reader)?,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub fn write(self) -> Bytes {
|
pub fn write(self) -> Bytes {
|
||||||
let mut bytes = Vec::new();
|
let mut bytes = Vec::new();
|
||||||
let mut writer = WriteAdaptor::new(&mut bytes);
|
let mut writer = WriteAdaptor::new(&mut bytes);
|
||||||
@ -128,6 +130,7 @@ impl Nbt {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Writes an NBT tag without a root `Compound` name.
|
/// Writes an NBT tag without a root `Compound` name.
|
||||||
|
#[must_use]
|
||||||
pub fn write_unnamed(self) -> Bytes {
|
pub fn write_unnamed(self) -> Bytes {
|
||||||
let mut bytes = Vec::new();
|
let mut bytes = Vec::new();
|
||||||
let mut writer = WriteAdaptor::new(&mut bytes);
|
let mut writer = WriteAdaptor::new(&mut bytes);
|
||||||
@ -154,14 +157,14 @@ impl Deref for Nbt {
|
|||||||
|
|
||||||
impl From<NbtCompound> for Nbt {
|
impl From<NbtCompound> for Nbt {
|
||||||
fn from(value: NbtCompound) -> Self {
|
fn from(value: NbtCompound) -> Self {
|
||||||
Nbt::new(String::new(), value)
|
Self::new(String::new(), value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T> AsRef<T> for Nbt
|
impl<T> AsRef<T> for Nbt
|
||||||
where
|
where
|
||||||
T: ?Sized,
|
T: ?Sized,
|
||||||
<Nbt as Deref>::Target: AsRef<T>,
|
<Self as Deref>::Target: AsRef<T>,
|
||||||
{
|
{
|
||||||
fn as_ref(&self) -> &T {
|
fn as_ref(&self) -> &T {
|
||||||
self.deref().as_ref()
|
self.deref().as_ref()
|
||||||
@ -246,6 +249,7 @@ mod test {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, PartialEq, Debug)]
|
#[derive(Serialize, Deserialize, PartialEq, Debug)]
|
||||||
|
#[expect(clippy::struct_field_names)]
|
||||||
struct TestArray {
|
struct TestArray {
|
||||||
#[serde(serialize_with = "nbt_byte_array")]
|
#[serde(serialize_with = "nbt_byte_array")]
|
||||||
byte_array: Vec<u8>,
|
byte_array: Vec<u8>,
|
||||||
@ -354,7 +358,7 @@ mod test {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
compounds: vec![test1, test2],
|
compounds: vec![test1, test2],
|
||||||
list_string: vec!["".to_string(), "abcbcbcbbc".to_string()],
|
list_string: vec![String::new(), "abcbcbcbbc".to_string()],
|
||||||
empty: vec![],
|
empty: vec![],
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -392,7 +396,7 @@ mod test {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
compounds: vec![test1, test2],
|
compounds: vec![test1, test2],
|
||||||
list_string: vec!["".to_string(), "abcbcbcbbc".to_string()],
|
list_string: vec![String::new(), "abcbcbcbbc".to_string()],
|
||||||
empty: vec![],
|
empty: vec![],
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -413,6 +417,12 @@ mod test {
|
|||||||
#[serde(serialize_with = "nbt_byte_array")]
|
#[serde(serialize_with = "nbt_byte_array")]
|
||||||
b: [u8; 1],
|
b: [u8; 1],
|
||||||
}
|
}
|
||||||
|
#[derive(Serialize)]
|
||||||
|
struct NotTagged {
|
||||||
|
l: [i64; 1],
|
||||||
|
i: [i32; 1],
|
||||||
|
b: [u8; 1],
|
||||||
|
}
|
||||||
|
|
||||||
let value = Tagged {
|
let value = Tagged {
|
||||||
l: [0],
|
l: [0],
|
||||||
@ -444,13 +454,6 @@ mod test {
|
|||||||
to_bytes(&value, &mut bytes).unwrap();
|
to_bytes(&value, &mut bytes).unwrap();
|
||||||
assert_eq!(bytes, expected_bytes);
|
assert_eq!(bytes, expected_bytes);
|
||||||
|
|
||||||
#[derive(Serialize)]
|
|
||||||
struct NotTagged {
|
|
||||||
l: [i64; 1],
|
|
||||||
i: [i32; 1],
|
|
||||||
b: [u8; 1],
|
|
||||||
}
|
|
||||||
|
|
||||||
let value = NotTagged {
|
let value = NotTagged {
|
||||||
l: [0],
|
l: [0],
|
||||||
i: [0],
|
i: [0],
|
||||||
@ -499,7 +502,7 @@ mod test {
|
|||||||
match err {
|
match err {
|
||||||
Err(Error::SerdeError(_)) => (),
|
Err(Error::SerdeError(_)) => (),
|
||||||
_ => panic!("Expected to fail serialization!"),
|
_ => panic!("Expected to fail serialization!"),
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
@ -3,15 +3,15 @@ use crate::{Error, Nbt, NbtCompound, deserializer, serializer};
|
|||||||
use flate2::{Compression, read::GzDecoder, write::GzEncoder};
|
use flate2::{Compression, read::GzDecoder, write::GzEncoder};
|
||||||
use std::io::{Cursor, Read, Seek, Write};
|
use std::io::{Cursor, Read, Seek, Write};
|
||||||
|
|
||||||
/// Reads a GZipped NBT compound tag from any reader.
|
/// Reads a `GZipped` NBT compound tag from any reader.
|
||||||
///
|
///
|
||||||
/// # Arguments
|
/// # Arguments
|
||||||
///
|
///
|
||||||
/// * `input` - Any type implementing the Read trait containing GZipped NBT data
|
/// * `input` - Any type implementing the Read trait containing `GZipped` NBT data
|
||||||
///
|
///
|
||||||
/// # Returns
|
/// # Returns
|
||||||
///
|
///
|
||||||
/// A Result containing either the parsed NbtCompound or an Error
|
/// A Result containing either the parsed `NbtCompound` or an Error
|
||||||
pub fn read_gzip_compound_tag(input: impl Read + Seek) -> Result<NbtCompound, Error> {
|
pub fn read_gzip_compound_tag(input: impl Read + Seek) -> Result<NbtCompound, Error> {
|
||||||
// Create a GZip decoder and directly chain it to the NBT reader
|
// Create a GZip decoder and directly chain it to the NBT reader
|
||||||
let mut decoder = GzDecoder::new(input);
|
let mut decoder = GzDecoder::new(input);
|
||||||
@ -24,13 +24,13 @@ pub fn read_gzip_compound_tag(input: impl Read + Seek) -> Result<NbtCompound, Er
|
|||||||
Ok(nbt.root_tag)
|
Ok(nbt.root_tag)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Writes an NBT compound tag with GZip compression.
|
/// Writes an NBT compound tag with `GZip` compression.
|
||||||
///
|
///
|
||||||
/// This function takes an NbtCompound and writes it as a GZipped byte vector.
|
/// This function takes an `NbtCompound` and writes it as a `GZipped` byte vector.
|
||||||
///
|
///
|
||||||
/// # Arguments
|
/// # Arguments
|
||||||
///
|
///
|
||||||
/// * `compound` - The NbtCompound to serialize and compress
|
/// * `compound` - The `NbtCompound` to serialize and compress
|
||||||
/// * `output` - Any type implementing the Write trait where the compressed data will be written
|
/// * `output` - Any type implementing the Write trait where the compressed data will be written
|
||||||
///
|
///
|
||||||
/// # Returns
|
/// # Returns
|
||||||
@ -58,11 +58,11 @@ pub fn write_gzip_compound_tag_to_bytes(compound: NbtCompound) -> Result<Vec<u8>
|
|||||||
Ok(buffer)
|
Ok(buffer)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Reads a GZipped NBT structure into a Rust type.
|
/// Reads a `GZipped` NBT structure into a Rust type.
|
||||||
///
|
///
|
||||||
/// # Arguments
|
/// # Arguments
|
||||||
///
|
///
|
||||||
/// * `input` - Any type implementing the Read trait containing GZipped NBT data
|
/// * `input` - Any type implementing the Read trait containing `GZipped` NBT data
|
||||||
///
|
///
|
||||||
/// # Returns
|
/// # Returns
|
||||||
///
|
///
|
||||||
@ -75,7 +75,7 @@ pub fn from_gzip_bytes<'a, T: serde::Deserialize<'a>, R: Read>(input: R) -> Resu
|
|||||||
deserializer::from_bytes(Cursor::new(buf))
|
deserializer::from_bytes(Cursor::new(buf))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Writes a Rust type as GZipped NBT to any writer.
|
/// Writes a Rust type as `GZipped` NBT to any writer.
|
||||||
///
|
///
|
||||||
/// # Arguments
|
/// # Arguments
|
||||||
///
|
///
|
||||||
@ -262,6 +262,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
#[expect(clippy::print_stdout)]
|
||||||
fn test_gzip_compression_ratio() {
|
fn test_gzip_compression_ratio() {
|
||||||
let mut compound = NbtCompound::new();
|
let mut compound = NbtCompound::new();
|
||||||
|
|
||||||
@ -294,6 +295,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
#[expect(clippy::struct_field_names)]
|
||||||
fn test_roundtrip_with_arrays() {
|
fn test_roundtrip_with_arrays() {
|
||||||
#[derive(Serialize, Deserialize, Debug, PartialEq)]
|
#[derive(Serialize, Deserialize, Debug, PartialEq)]
|
||||||
struct ArrayTest {
|
struct ArrayTest {
|
||||||
|
|||||||
@ -122,20 +122,19 @@ impl<W: Write> Serializer<W> {
|
|||||||
return Err(Error::SerdeError(
|
return Err(Error::SerdeError(
|
||||||
"Invalid state: already handled root component!".to_string(),
|
"Invalid state: already handled root component!".to_string(),
|
||||||
));
|
));
|
||||||
} else {
|
}
|
||||||
if tag != COMPOUND_ID {
|
if tag != COMPOUND_ID {
|
||||||
return Err(Error::SerdeError(format!(
|
return Err(Error::SerdeError(format!(
|
||||||
"Invalid state: root is not a `Compound`! ({tag})"
|
"Invalid state: root is not a `Compound`! ({tag})"
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
self.handled_root = true;
|
self.handled_root = true;
|
||||||
self.output.write_u8_be(tag)?;
|
self.output.write_u8_be(tag)?;
|
||||||
if let Some(root_name) = root_name {
|
if let Some(root_name) = root_name {
|
||||||
NbtTag::write_string(root_name, &mut self.output)?;
|
NbtTag::write_string(root_name, &mut self.output)?;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -171,7 +170,7 @@ impl<W: Write> ser::Serializer for &mut Serializer<W> {
|
|||||||
type SerializeStructVariant = Impossible<(), Error>;
|
type SerializeStructVariant = Impossible<(), Error>;
|
||||||
|
|
||||||
fn serialize_bool(self, v: bool) -> Result<()> {
|
fn serialize_bool(self, v: bool) -> Result<()> {
|
||||||
self.serialize_i8(v as i8)?;
|
self.serialize_i8(i8::from(v))?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -200,15 +199,14 @@ impl<W: Write> ser::Serializer for &mut Serializer<W> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn serialize_u8(self, v: u8) -> Result<()> {
|
fn serialize_u8(self, v: u8) -> Result<()> {
|
||||||
match self.state {
|
if let State::Named(_) = self.state {
|
||||||
State::Named(_) => Err(Error::UnsupportedType(
|
Err(Error::UnsupportedType(
|
||||||
"u8; NBT only supports signed values".to_string(),
|
"u8; NBT only supports signed values".to_string(),
|
||||||
)),
|
))
|
||||||
_ => {
|
} else {
|
||||||
self.parse_state(BYTE_ID)?;
|
self.parse_state(BYTE_ID)?;
|
||||||
self.output.write_u8_be(v)?;
|
self.output.write_u8_be(v)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -336,35 +334,32 @@ impl<W: Write> ser::Serializer for &mut Serializer<W> {
|
|||||||
return Err(Error::LargeLength(len));
|
return Err(Error::LargeLength(len));
|
||||||
}
|
}
|
||||||
|
|
||||||
match &mut self.state {
|
if let State::Array { array_type, .. } = &mut self.state {
|
||||||
State::Array { array_type, .. } => {
|
let (id, expected_tag) = match *array_type {
|
||||||
let (id, expected_tag) = match *array_type {
|
NBT_BYTE_ARRAY_TAG => (BYTE_ARRAY_ID, BYTE_ID),
|
||||||
NBT_BYTE_ARRAY_TAG => (BYTE_ARRAY_ID, BYTE_ID),
|
NBT_INT_ARRAY_TAG => (INT_ARRAY_ID, INT_ID),
|
||||||
NBT_INT_ARRAY_TAG => (INT_ARRAY_ID, INT_ID),
|
NBT_LONG_ARRAY_TAG => (LONG_ARRAY_ID, LONG_ID),
|
||||||
NBT_LONG_ARRAY_TAG => (LONG_ARRAY_ID, LONG_ID),
|
_ => {
|
||||||
_ => {
|
return Err(Error::SerdeError(
|
||||||
return Err(Error::SerdeError(
|
"Array supports only `byte`, `int`, and `long`".to_string(),
|
||||||
"Array supports only `byte`, `int`, and `long`".to_string(),
|
));
|
||||||
));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
self.parse_state(id)?;
|
|
||||||
self.output.write_i32_be(len as i32)?;
|
|
||||||
|
|
||||||
// We can mark anything as an NBT array list, so mark as needed to be checked.
|
|
||||||
self.expected_list_tag = expected_tag;
|
|
||||||
self.state = State::CheckedListElement;
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
self.parse_state(LIST_ID)?;
|
|
||||||
self.state = State::FirstListElement { len: len as i32 };
|
|
||||||
if len == 0 {
|
|
||||||
// If we have no elements, the `FirstListElement` state will never be invoked, so
|
|
||||||
// write the (unknown) list type and length here.
|
|
||||||
self.output.write_u8_be(END_ID)?;
|
|
||||||
self.output.write_i32_be(0)?;
|
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
self.parse_state(id)?;
|
||||||
|
self.output.write_i32_be(len as i32)?;
|
||||||
|
|
||||||
|
// We can mark anything as an NBT array list, so mark as needed to be checked.
|
||||||
|
self.expected_list_tag = expected_tag;
|
||||||
|
self.state = State::CheckedListElement;
|
||||||
|
} else {
|
||||||
|
self.parse_state(LIST_ID)?;
|
||||||
|
self.state = State::FirstListElement { len: len as i32 };
|
||||||
|
if len == 0 {
|
||||||
|
// If we have no elements, the `FirstListElement` state will never be invoked, so
|
||||||
|
// write the (unknown) list type and length here.
|
||||||
|
self.output.write_u8_be(END_ID)?;
|
||||||
|
self.output.write_i32_be(0)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -4,7 +4,11 @@ use io::Read;
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use serializer::WriteAdaptor;
|
use serializer::WriteAdaptor;
|
||||||
|
|
||||||
use crate::*;
|
use crate::{
|
||||||
|
BYTE_ARRAY_ID, BYTE_ID, COMPOUND_ID, DOUBLE_ID, END_ID, Error, FLOAT_ID, INT_ARRAY_ID, INT_ID,
|
||||||
|
LIST_ID, LONG_ARRAY_ID, LONG_ID, SHORT_ID, STRING_ID, Seek, Write, compound, deserializer,
|
||||||
|
get_nbt_string, io, nbt_byte_array, nbt_int_array, nbt_long_array, serializer,
|
||||||
|
};
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, PartialOrd)]
|
#[derive(Clone, Debug, PartialEq, PartialOrd)]
|
||||||
#[repr(u8)]
|
#[repr(u8)]
|
||||||
@ -18,7 +22,7 @@ pub enum NbtTag {
|
|||||||
Double(f64) = DOUBLE_ID,
|
Double(f64) = DOUBLE_ID,
|
||||||
ByteArray(Box<[u8]>) = BYTE_ARRAY_ID,
|
ByteArray(Box<[u8]>) = BYTE_ARRAY_ID,
|
||||||
String(String) = STRING_ID,
|
String(String) = STRING_ID,
|
||||||
List(Vec<NbtTag>) = LIST_ID,
|
List(Vec<Self>) = LIST_ID,
|
||||||
Compound(NbtCompound) = COMPOUND_ID,
|
Compound(NbtCompound) = COMPOUND_ID,
|
||||||
IntArray(Vec<i32>) = INT_ARRAY_ID,
|
IntArray(Vec<i32>) = INT_ARRAY_ID,
|
||||||
LongArray(Vec<i64>) = LONG_ARRAY_ID,
|
LongArray(Vec<i64>) = LONG_ARRAY_ID,
|
||||||
@ -26,10 +30,11 @@ pub enum NbtTag {
|
|||||||
|
|
||||||
impl NbtTag {
|
impl NbtTag {
|
||||||
/// Returns the numeric id associated with the data type.
|
/// Returns the numeric id associated with the data type.
|
||||||
|
#[must_use]
|
||||||
pub const fn get_type_id(&self) -> u8 {
|
pub const fn get_type_id(&self) -> u8 {
|
||||||
// Safety: Since Self is repr(u8), it is guaranteed to hold the discriminant in the first byte
|
// Safety: Since Self is repr(u8), it is guaranteed to hold the discriminant in the first byte
|
||||||
// See https://doc.rust-lang.org/reference/items/enumerations.html#pointer-casting
|
// See https://doc.rust-lang.org/reference/items/enumerations.html#pointer-casting
|
||||||
unsafe { *(self as *const Self as *const u8) }
|
unsafe { *std::ptr::from_ref::<Self>(self).cast::<u8>() }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn serialize<W: Write>(self, w: &mut WriteAdaptor<W>) -> serializer::Result<()> {
|
pub fn serialize<W: Write>(self, w: &mut WriteAdaptor<W>) -> serializer::Result<()> {
|
||||||
@ -52,14 +57,14 @@ impl NbtTag {
|
|||||||
|
|
||||||
pub fn serialize_data<W: Write>(self, w: &mut WriteAdaptor<W>) -> serializer::Result<()> {
|
pub fn serialize_data<W: Write>(self, w: &mut WriteAdaptor<W>) -> serializer::Result<()> {
|
||||||
match self {
|
match self {
|
||||||
NbtTag::End => {}
|
Self::End => {}
|
||||||
NbtTag::Byte(byte) => w.write_i8_be(byte)?,
|
Self::Byte(byte) => w.write_i8_be(byte)?,
|
||||||
NbtTag::Short(short) => w.write_i16_be(short)?,
|
Self::Short(short) => w.write_i16_be(short)?,
|
||||||
NbtTag::Int(int) => w.write_i32_be(int)?,
|
Self::Int(int) => w.write_i32_be(int)?,
|
||||||
NbtTag::Long(long) => w.write_i64_be(long)?,
|
Self::Long(long) => w.write_i64_be(long)?,
|
||||||
NbtTag::Float(float) => w.write_f32_be(float)?,
|
Self::Float(float) => w.write_f32_be(float)?,
|
||||||
NbtTag::Double(double) => w.write_f64_be(double)?,
|
Self::Double(double) => w.write_f64_be(double)?,
|
||||||
NbtTag::ByteArray(byte_array) => {
|
Self::ByteArray(byte_array) => {
|
||||||
let len = byte_array.len();
|
let len = byte_array.len();
|
||||||
if len > i32::MAX as usize {
|
if len > i32::MAX as usize {
|
||||||
return Err(Error::LargeLength(len));
|
return Err(Error::LargeLength(len));
|
||||||
@ -68,25 +73,25 @@ impl NbtTag {
|
|||||||
w.write_i32_be(len as i32)?;
|
w.write_i32_be(len as i32)?;
|
||||||
w.write_slice(&byte_array)?;
|
w.write_slice(&byte_array)?;
|
||||||
}
|
}
|
||||||
NbtTag::String(string) => {
|
Self::String(string) => {
|
||||||
Self::write_string(&string, w)?;
|
Self::write_string(&string, w)?;
|
||||||
}
|
}
|
||||||
NbtTag::List(list) => {
|
Self::List(list) => {
|
||||||
let len = list.len();
|
let len = list.len();
|
||||||
if len > i32::MAX as usize {
|
if len > i32::MAX as usize {
|
||||||
return Err(Error::LargeLength(len));
|
return Err(Error::LargeLength(len));
|
||||||
}
|
}
|
||||||
|
|
||||||
w.write_u8_be(list.first().unwrap_or(&NbtTag::End).get_type_id())?;
|
w.write_u8_be(list.first().unwrap_or(&Self::End).get_type_id())?;
|
||||||
w.write_i32_be(len as i32)?;
|
w.write_i32_be(len as i32)?;
|
||||||
for nbt_tag in list {
|
for nbt_tag in list {
|
||||||
nbt_tag.serialize_data(w)?;
|
nbt_tag.serialize_data(w)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
NbtTag::Compound(compound) => {
|
Self::Compound(compound) => {
|
||||||
compound.serialize_content(w)?;
|
compound.serialize_content(w)?;
|
||||||
}
|
}
|
||||||
NbtTag::IntArray(int_array) => {
|
Self::IntArray(int_array) => {
|
||||||
let len = int_array.len();
|
let len = int_array.len();
|
||||||
if len > i32::MAX as usize {
|
if len > i32::MAX as usize {
|
||||||
return Err(Error::LargeLength(len));
|
return Err(Error::LargeLength(len));
|
||||||
@ -97,7 +102,7 @@ impl NbtTag {
|
|||||||
w.write_i32_be(int)?;
|
w.write_i32_be(int)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
NbtTag::LongArray(long_array) => {
|
Self::LongArray(long_array) => {
|
||||||
let len = long_array.len();
|
let len = long_array.len();
|
||||||
if len > i32::MAX as usize {
|
if len > i32::MAX as usize {
|
||||||
return Err(Error::LargeLength(len));
|
return Err(Error::LargeLength(len));
|
||||||
@ -109,11 +114,11 @@ impl NbtTag {
|
|||||||
w.write_i64_be(long)?;
|
w.write_i64_be(long)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deserialize<R: Read + Seek>(reader: &mut NbtReadHelper<R>) -> Result<NbtTag, Error> {
|
pub fn deserialize<R: Read + Seek>(reader: &mut NbtReadHelper<R>) -> Result<Self, Error> {
|
||||||
let tag_id = reader.get_u8_be()?;
|
let tag_id = reader.get_u8_be()?;
|
||||||
Self::deserialize_data(reader, tag_id)
|
Self::deserialize_data(reader, tag_id)
|
||||||
}
|
}
|
||||||
@ -126,20 +131,18 @@ impl NbtTag {
|
|||||||
END_ID => Ok(()),
|
END_ID => Ok(()),
|
||||||
BYTE_ID => reader.skip_bytes(1),
|
BYTE_ID => reader.skip_bytes(1),
|
||||||
SHORT_ID => reader.skip_bytes(2),
|
SHORT_ID => reader.skip_bytes(2),
|
||||||
INT_ID => reader.skip_bytes(4),
|
INT_ID | FLOAT_ID => reader.skip_bytes(4),
|
||||||
LONG_ID => reader.skip_bytes(8),
|
LONG_ID | DOUBLE_ID => reader.skip_bytes(8),
|
||||||
FLOAT_ID => reader.skip_bytes(4),
|
|
||||||
DOUBLE_ID => reader.skip_bytes(8),
|
|
||||||
BYTE_ARRAY_ID => {
|
BYTE_ARRAY_ID => {
|
||||||
let len = reader.get_i32_be()?;
|
let len = reader.get_i32_be()?;
|
||||||
if len < 0 {
|
if len < 0 {
|
||||||
return Err(Error::NegativeLength(len));
|
return Err(Error::NegativeLength(len));
|
||||||
}
|
}
|
||||||
reader.skip_bytes(len as i64)
|
reader.skip_bytes(i64::from(len))
|
||||||
}
|
}
|
||||||
STRING_ID => {
|
STRING_ID => {
|
||||||
let len = reader.get_u16_be()?;
|
let len = reader.get_u16_be()?;
|
||||||
reader.skip_bytes(len as i64)
|
reader.skip_bytes(i64::from(len))
|
||||||
}
|
}
|
||||||
LIST_ID => {
|
LIST_ID => {
|
||||||
let tag_type_id = reader.get_u8_be()?;
|
let tag_type_id = reader.get_u8_be()?;
|
||||||
@ -161,7 +164,7 @@ impl NbtTag {
|
|||||||
return Err(Error::NegativeLength(len));
|
return Err(Error::NegativeLength(len));
|
||||||
}
|
}
|
||||||
|
|
||||||
reader.skip_bytes(len as i64 * 4)
|
reader.skip_bytes(i64::from(len) * 4)
|
||||||
}
|
}
|
||||||
LONG_ARRAY_ID => {
|
LONG_ARRAY_ID => {
|
||||||
let len = reader.get_i32_be()?;
|
let len = reader.get_i32_be()?;
|
||||||
@ -169,7 +172,7 @@ impl NbtTag {
|
|||||||
return Err(Error::NegativeLength(len));
|
return Err(Error::NegativeLength(len));
|
||||||
}
|
}
|
||||||
|
|
||||||
reader.skip_bytes(len as i64 * 8)
|
reader.skip_bytes(i64::from(len) * 8)
|
||||||
}
|
}
|
||||||
_ => Err(Error::UnknownTagId(tag_id)),
|
_ => Err(Error::UnknownTagId(tag_id)),
|
||||||
}
|
}
|
||||||
@ -178,32 +181,32 @@ impl NbtTag {
|
|||||||
pub fn deserialize_data<R: Read + Seek>(
|
pub fn deserialize_data<R: Read + Seek>(
|
||||||
reader: &mut NbtReadHelper<R>,
|
reader: &mut NbtReadHelper<R>,
|
||||||
tag_id: u8,
|
tag_id: u8,
|
||||||
) -> Result<NbtTag, Error> {
|
) -> Result<Self, Error> {
|
||||||
match tag_id {
|
match tag_id {
|
||||||
END_ID => Ok(NbtTag::End),
|
END_ID => Ok(Self::End),
|
||||||
BYTE_ID => {
|
BYTE_ID => {
|
||||||
let byte = reader.get_i8_be()?;
|
let byte = reader.get_i8_be()?;
|
||||||
Ok(NbtTag::Byte(byte))
|
Ok(Self::Byte(byte))
|
||||||
}
|
}
|
||||||
SHORT_ID => {
|
SHORT_ID => {
|
||||||
let short = reader.get_i16_be()?;
|
let short = reader.get_i16_be()?;
|
||||||
Ok(NbtTag::Short(short))
|
Ok(Self::Short(short))
|
||||||
}
|
}
|
||||||
INT_ID => {
|
INT_ID => {
|
||||||
let int = reader.get_i32_be()?;
|
let int = reader.get_i32_be()?;
|
||||||
Ok(NbtTag::Int(int))
|
Ok(Self::Int(int))
|
||||||
}
|
}
|
||||||
LONG_ID => {
|
LONG_ID => {
|
||||||
let long = reader.get_i64_be()?;
|
let long = reader.get_i64_be()?;
|
||||||
Ok(NbtTag::Long(long))
|
Ok(Self::Long(long))
|
||||||
}
|
}
|
||||||
FLOAT_ID => {
|
FLOAT_ID => {
|
||||||
let float = reader.get_f32_be()?;
|
let float = reader.get_f32_be()?;
|
||||||
Ok(NbtTag::Float(float))
|
Ok(Self::Float(float))
|
||||||
}
|
}
|
||||||
DOUBLE_ID => {
|
DOUBLE_ID => {
|
||||||
let double = reader.get_f64_be()?;
|
let double = reader.get_f64_be()?;
|
||||||
Ok(NbtTag::Double(double))
|
Ok(Self::Double(double))
|
||||||
}
|
}
|
||||||
BYTE_ARRAY_ID => {
|
BYTE_ARRAY_ID => {
|
||||||
let len = reader.get_i32_be()?;
|
let len = reader.get_i32_be()?;
|
||||||
@ -212,9 +215,9 @@ impl NbtTag {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let byte_array = reader.read_boxed_slice(len as usize)?;
|
let byte_array = reader.read_boxed_slice(len as usize)?;
|
||||||
Ok(NbtTag::ByteArray(byte_array))
|
Ok(Self::ByteArray(byte_array))
|
||||||
}
|
}
|
||||||
STRING_ID => Ok(NbtTag::String(get_nbt_string(reader)?)),
|
STRING_ID => Ok(Self::String(get_nbt_string(reader)?)),
|
||||||
LIST_ID => {
|
LIST_ID => {
|
||||||
let tag_type_id = reader.get_u8_be()?;
|
let tag_type_id = reader.get_u8_be()?;
|
||||||
let len = reader.get_i32_be()?;
|
let len = reader.get_i32_be()?;
|
||||||
@ -224,13 +227,13 @@ impl NbtTag {
|
|||||||
|
|
||||||
let mut list = Vec::with_capacity(len as usize);
|
let mut list = Vec::with_capacity(len as usize);
|
||||||
for _ in 0..len {
|
for _ in 0..len {
|
||||||
let tag = NbtTag::deserialize_data(reader, tag_type_id)?;
|
let tag = Self::deserialize_data(reader, tag_type_id)?;
|
||||||
assert_eq!(tag.get_type_id(), tag_type_id);
|
assert_eq!(tag.get_type_id(), tag_type_id);
|
||||||
list.push(tag);
|
list.push(tag);
|
||||||
}
|
}
|
||||||
Ok(NbtTag::List(list))
|
Ok(Self::List(list))
|
||||||
}
|
}
|
||||||
COMPOUND_ID => Ok(NbtTag::Compound(NbtCompound::deserialize_content(reader)?)),
|
COMPOUND_ID => Ok(Self::Compound(NbtCompound::deserialize_content(reader)?)),
|
||||||
INT_ARRAY_ID => {
|
INT_ARRAY_ID => {
|
||||||
let len = reader.get_i32_be()?;
|
let len = reader.get_i32_be()?;
|
||||||
if len < 0 {
|
if len < 0 {
|
||||||
@ -243,7 +246,7 @@ impl NbtTag {
|
|||||||
let int = reader.get_i32_be()?;
|
let int = reader.get_i32_be()?;
|
||||||
int_array.push(int);
|
int_array.push(int);
|
||||||
}
|
}
|
||||||
Ok(NbtTag::IntArray(int_array))
|
Ok(Self::IntArray(int_array))
|
||||||
}
|
}
|
||||||
LONG_ARRAY_ID => {
|
LONG_ARRAY_ID => {
|
||||||
let len = reader.get_i32_be()?;
|
let len = reader.get_i32_be()?;
|
||||||
@ -257,99 +260,112 @@ impl NbtTag {
|
|||||||
let long = reader.get_i64_be()?;
|
let long = reader.get_i64_be()?;
|
||||||
long_array.push(long);
|
long_array.push(long);
|
||||||
}
|
}
|
||||||
Ok(NbtTag::LongArray(long_array))
|
Ok(Self::LongArray(long_array))
|
||||||
}
|
}
|
||||||
_ => Err(Error::UnknownTagId(tag_id)),
|
_ => Err(Error::UnknownTagId(tag_id)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub fn extract_byte(&self) -> Option<i8> {
|
pub fn extract_byte(&self) -> Option<i8> {
|
||||||
match self {
|
match self {
|
||||||
NbtTag::Byte(byte) => Some(*byte),
|
Self::Byte(byte) => Some(*byte),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub fn extract_short(&self) -> Option<i16> {
|
pub fn extract_short(&self) -> Option<i16> {
|
||||||
match self {
|
match self {
|
||||||
NbtTag::Short(short) => Some(*short),
|
Self::Short(short) => Some(*short),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub fn extract_int(&self) -> Option<i32> {
|
pub fn extract_int(&self) -> Option<i32> {
|
||||||
match self {
|
match self {
|
||||||
NbtTag::Int(int) => Some(*int),
|
Self::Int(int) => Some(*int),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub fn extract_long(&self) -> Option<i64> {
|
pub fn extract_long(&self) -> Option<i64> {
|
||||||
match self {
|
match self {
|
||||||
NbtTag::Long(long) => Some(*long),
|
Self::Long(long) => Some(*long),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub fn extract_float(&self) -> Option<f32> {
|
pub fn extract_float(&self) -> Option<f32> {
|
||||||
match self {
|
match self {
|
||||||
NbtTag::Float(float) => Some(*float),
|
Self::Float(float) => Some(*float),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub fn extract_double(&self) -> Option<f64> {
|
pub fn extract_double(&self) -> Option<f64> {
|
||||||
match self {
|
match self {
|
||||||
NbtTag::Double(double) => Some(*double),
|
Self::Double(double) => Some(*double),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub fn extract_bool(&self) -> Option<bool> {
|
pub fn extract_bool(&self) -> Option<bool> {
|
||||||
match self {
|
match self {
|
||||||
NbtTag::Byte(byte) => Some(byte != &0),
|
Self::Byte(byte) => Some(byte != &0),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub fn extract_byte_array(&self) -> Option<&[u8]> {
|
pub fn extract_byte_array(&self) -> Option<&[u8]> {
|
||||||
match self {
|
match self {
|
||||||
NbtTag::ByteArray(byte_array) => Some(byte_array),
|
Self::ByteArray(byte_array) => Some(byte_array),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub fn extract_string(&self) -> Option<&str> {
|
pub fn extract_string(&self) -> Option<&str> {
|
||||||
match self {
|
match self {
|
||||||
NbtTag::String(string) => Some(string),
|
Self::String(string) => Some(string),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn extract_list(&self) -> Option<&[NbtTag]> {
|
#[must_use]
|
||||||
|
pub fn extract_list(&self) -> Option<&[Self]> {
|
||||||
match self {
|
match self {
|
||||||
NbtTag::List(list) => Some(list),
|
Self::List(list) => Some(list),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub fn extract_compound(&self) -> Option<&NbtCompound> {
|
pub fn extract_compound(&self) -> Option<&NbtCompound> {
|
||||||
match self {
|
match self {
|
||||||
NbtTag::Compound(compound) => Some(compound),
|
Self::Compound(compound) => Some(compound),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub fn extract_int_array(&self) -> Option<&[i32]> {
|
pub fn extract_int_array(&self) -> Option<&[i32]> {
|
||||||
match self {
|
match self {
|
||||||
NbtTag::IntArray(int_array) => Some(int_array),
|
Self::IntArray(int_array) => Some(int_array),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub fn extract_long_array(&self) -> Option<&[i64]> {
|
pub fn extract_long_array(&self) -> Option<&[i64]> {
|
||||||
match self {
|
match self {
|
||||||
NbtTag::LongArray(long_array) => Some(long_array),
|
Self::LongArray(long_array) => Some(long_array),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -357,7 +373,7 @@ impl NbtTag {
|
|||||||
|
|
||||||
impl From<&str> for NbtTag {
|
impl From<&str> for NbtTag {
|
||||||
fn from(value: &str) -> Self {
|
fn from(value: &str) -> Self {
|
||||||
NbtTag::String(value.to_string())
|
Self::String(value.to_string())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -365,51 +381,51 @@ impl From<&[u8]> for NbtTag {
|
|||||||
fn from(value: &[u8]) -> Self {
|
fn from(value: &[u8]) -> Self {
|
||||||
let mut cloned = Vec::with_capacity(value.len());
|
let mut cloned = Vec::with_capacity(value.len());
|
||||||
cloned.copy_from_slice(value);
|
cloned.copy_from_slice(value);
|
||||||
NbtTag::ByteArray(cloned.into_boxed_slice())
|
Self::ByteArray(cloned.into_boxed_slice())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<f32> for NbtTag {
|
impl From<f32> for NbtTag {
|
||||||
fn from(value: f32) -> Self {
|
fn from(value: f32) -> Self {
|
||||||
NbtTag::Float(value)
|
Self::Float(value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<f64> for NbtTag {
|
impl From<f64> for NbtTag {
|
||||||
fn from(value: f64) -> Self {
|
fn from(value: f64) -> Self {
|
||||||
NbtTag::Double(value)
|
Self::Double(value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<bool> for NbtTag {
|
impl From<bool> for NbtTag {
|
||||||
fn from(value: bool) -> Self {
|
fn from(value: bool) -> Self {
|
||||||
NbtTag::Byte(value as i8)
|
Self::Byte(i8::from(value))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Serialize for NbtTag {
|
impl Serialize for NbtTag {
|
||||||
fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
|
fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
|
||||||
match self {
|
match self {
|
||||||
NbtTag::End => serializer.serialize_unit(),
|
Self::End => serializer.serialize_unit(),
|
||||||
NbtTag::Byte(v) => serializer.serialize_i8(*v),
|
Self::Byte(v) => serializer.serialize_i8(*v),
|
||||||
NbtTag::Short(v) => serializer.serialize_i16(*v),
|
Self::Short(v) => serializer.serialize_i16(*v),
|
||||||
NbtTag::Int(v) => serializer.serialize_i32(*v),
|
Self::Int(v) => serializer.serialize_i32(*v),
|
||||||
NbtTag::Long(v) => serializer.serialize_i64(*v),
|
Self::Long(v) => serializer.serialize_i64(*v),
|
||||||
NbtTag::Float(v) => serializer.serialize_f32(*v),
|
Self::Float(v) => serializer.serialize_f32(*v),
|
||||||
NbtTag::Double(v) => serializer.serialize_f64(*v),
|
Self::Double(v) => serializer.serialize_f64(*v),
|
||||||
NbtTag::ByteArray(v) => nbt_byte_array(v, serializer),
|
Self::ByteArray(v) => nbt_byte_array(v, serializer),
|
||||||
NbtTag::String(v) => serializer.serialize_str(v),
|
Self::String(v) => serializer.serialize_str(v),
|
||||||
NbtTag::List(v) => {
|
Self::List(v) => {
|
||||||
use serde::ser::SerializeSeq;
|
use serde::ser::SerializeSeq;
|
||||||
let mut seq = serializer.serialize_seq(Some(v.len()))?;
|
let mut seq = serializer.serialize_seq(Some(v.len()))?;
|
||||||
for item in v.iter() {
|
for item in v {
|
||||||
seq.serialize_element(item)?;
|
seq.serialize_element(item)?;
|
||||||
}
|
}
|
||||||
seq.end()
|
seq.end()
|
||||||
}
|
}
|
||||||
NbtTag::Compound(v) => v.serialize(serializer),
|
Self::Compound(v) => v.serialize(serializer),
|
||||||
NbtTag::IntArray(v) => nbt_int_array(v, serializer),
|
Self::IntArray(v) => nbt_int_array(v, serializer),
|
||||||
NbtTag::LongArray(v) => nbt_long_array(v, serializer),
|
Self::LongArray(v) => nbt_long_array(v, serializer),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -426,7 +442,7 @@ impl<'de> Deserialize<'de> for NbtTag {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn visit_bool<E>(self, v: bool) -> Result<Self::Value, E> {
|
fn visit_bool<E>(self, v: bool) -> Result<Self::Value, E> {
|
||||||
Ok(NbtTag::Byte(v as i8))
|
Ok(NbtTag::Byte(i8::from(v)))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_i8<E>(self, v: i8) -> Result<Self::Value, E> {
|
fn visit_i8<E>(self, v: i8) -> Result<Self::Value, E> {
|
||||||
@ -493,8 +509,7 @@ impl<'de> Deserialize<'de> for NbtTag {
|
|||||||
Ok(NbtTag::List(vec))
|
Ok(NbtTag::List(vec))
|
||||||
}
|
}
|
||||||
_ => Err(serde::de::Error::custom(format!(
|
_ => Err(serde::de::Error::custom(format!(
|
||||||
"Invalid list type id: {}",
|
"Invalid list type id: {curr}"
|
||||||
curr
|
|
||||||
))),
|
))),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -36,3 +36,6 @@ bitflags.workspace = true
|
|||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
# Validate correctness
|
# Validate correctness
|
||||||
flate2.workspace = true
|
flate2.workspace = true
|
||||||
|
|
||||||
|
[lints]
|
||||||
|
workspace = true
|
||||||
|
|||||||
@ -15,6 +15,7 @@ pub struct Ack {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Ack {
|
impl Ack {
|
||||||
|
#[must_use]
|
||||||
pub fn new(sequences: Vec<u32>) -> Self {
|
pub fn new(sequences: Vec<u32>) -> Self {
|
||||||
Self { sequences }
|
Self { sequences }
|
||||||
}
|
}
|
||||||
@ -65,14 +66,12 @@ impl Ack {
|
|||||||
let mut start = self.sequences[0];
|
let mut start = self.sequences[0];
|
||||||
let mut end = start;
|
let mut end = start;
|
||||||
for seq in self.sequences.iter().copied() {
|
for seq in self.sequences.iter().copied() {
|
||||||
if seq == end + 1 {
|
if seq != end + 1 {
|
||||||
end = seq
|
|
||||||
} else {
|
|
||||||
Self::write_range(start, end, &mut buf)?;
|
Self::write_range(start, end, &mut buf)?;
|
||||||
count += 1;
|
count += 1;
|
||||||
start = seq;
|
start = seq;
|
||||||
end = seq;
|
|
||||||
}
|
}
|
||||||
|
end = seq;
|
||||||
}
|
}
|
||||||
Self::write_range(start, end, &mut buf)?;
|
Self::write_range(start, end, &mut buf)?;
|
||||||
count += 1;
|
count += 1;
|
||||||
|
|||||||
@ -13,6 +13,7 @@ pub struct CDisconnectPlayer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl CDisconnectPlayer {
|
impl CDisconnectPlayer {
|
||||||
|
#[must_use]
|
||||||
pub fn new(reason: i32, message: String) -> Self {
|
pub fn new(reason: i32, message: String) -> Self {
|
||||||
Self {
|
Self {
|
||||||
reason: VarInt(reason),
|
reason: VarInt(reason),
|
||||||
|
|||||||
@ -8,6 +8,7 @@ pub struct CHandshake {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl CHandshake {
|
impl CHandshake {
|
||||||
|
#[must_use]
|
||||||
pub fn new(jwt_data: String) -> Self {
|
pub fn new(jwt_data: String) -> Self {
|
||||||
Self { jwt_data }
|
Self { jwt_data }
|
||||||
}
|
}
|
||||||
|
|||||||
@ -13,6 +13,6 @@ pub struct CInventoryContent {
|
|||||||
pub slots: Vec<NetworkItemStackDescriptor>,
|
pub slots: Vec<NetworkItemStackDescriptor>,
|
||||||
pub container_name: u8,
|
pub container_name: u8,
|
||||||
pub dynamic_id: Option<u32>,
|
pub dynamic_id: Option<u32>,
|
||||||
/// Use NetworkItemDescriptor if none
|
/// Use `NetworkItemDescriptor` if none
|
||||||
pub storage_item: NetworkItemStackDescriptor,
|
pub storage_item: NetworkItemStackDescriptor,
|
||||||
}
|
}
|
||||||
|
|||||||
@ -20,7 +20,7 @@ pub struct CLevelChunk<'a> {
|
|||||||
pub chunk: &'a ChunkData,
|
pub chunk: &'a ChunkData,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> PacketWrite for CLevelChunk<'a> {
|
impl PacketWrite for CLevelChunk<'_> {
|
||||||
fn write<W: Write>(&self, writer: &mut W) -> Result<(), Error> {
|
fn write<W: Write>(&self, writer: &mut W) -> Result<(), Error> {
|
||||||
VarInt(self.chunk.x).write(writer)?;
|
VarInt(self.chunk.x).write(writer)?;
|
||||||
VarInt(self.chunk.z).write(writer)?;
|
VarInt(self.chunk.z).write(writer)?;
|
||||||
@ -52,12 +52,12 @@ impl<'a> PacketWrite for CLevelChunk<'a> {
|
|||||||
|
|
||||||
match network_repr.palette {
|
match network_repr.palette {
|
||||||
NetworkPalette::Single(id) => {
|
NetworkPalette::Single(id) => {
|
||||||
VarInt(id as i32).write(data_write)?;
|
VarInt(i32::from(id)).write(data_write)?;
|
||||||
}
|
}
|
||||||
NetworkPalette::Indirect(palette) => {
|
NetworkPalette::Indirect(palette) => {
|
||||||
VarInt(palette.len() as i32).write(data_write)?;
|
VarInt(palette.len() as i32).write(data_write)?;
|
||||||
for id in palette {
|
for id in palette {
|
||||||
VarInt(id as i32).write(data_write)?;
|
VarInt(i32::from(id)).write(data_write)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
NetworkPalette::Direct => (),
|
NetworkPalette::Direct => (),
|
||||||
|
|||||||
@ -19,6 +19,7 @@ pub struct CNetworkChunkPublisherUpdate {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl CNetworkChunkPublisherUpdate {
|
impl CNetworkChunkPublisherUpdate {
|
||||||
|
#[must_use]
|
||||||
pub fn new(pos_for_view: BlockPos, new_radius: u32) -> Self {
|
pub fn new(pos_for_view: BlockPos, new_radius: u32) -> Self {
|
||||||
Self {
|
Self {
|
||||||
pos_for_view: NetworkPos(pos_for_view),
|
pos_for_view: NetworkPos(pos_for_view),
|
||||||
|
|||||||
@ -13,6 +13,7 @@ pub struct CNetworkSettings {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl CNetworkSettings {
|
impl CNetworkSettings {
|
||||||
|
#[must_use]
|
||||||
pub fn new(
|
pub fn new(
|
||||||
compression_threshold: u16,
|
compression_threshold: u16,
|
||||||
compression_method: u16,
|
compression_method: u16,
|
||||||
|
|||||||
@ -6,16 +6,15 @@ use crate::serial::PacketWrite;
|
|||||||
#[derive(PacketWrite)]
|
#[derive(PacketWrite)]
|
||||||
#[packet(0x03)]
|
#[packet(0x03)]
|
||||||
pub struct CConnectedPong {
|
pub struct CConnectedPong {
|
||||||
ping_time: u64,
|
ping: u64,
|
||||||
pong_time: u64,
|
pong: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CConnectedPong {
|
impl CConnectedPong {
|
||||||
pub fn new(ping_time: u64, pong_time: u64) -> Self {
|
#[must_use]
|
||||||
Self {
|
#[expect(clippy::similar_names)]
|
||||||
ping_time,
|
pub fn new(ping: u64, pong: u64) -> Self {
|
||||||
pong_time,
|
Self { ping, pong }
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -30,6 +29,7 @@ pub struct CConnectionRequestAccepted {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl CConnectionRequestAccepted {
|
impl CConnectionRequestAccepted {
|
||||||
|
#[must_use]
|
||||||
pub fn new(
|
pub fn new(
|
||||||
client_address: SocketAddr,
|
client_address: SocketAddr,
|
||||||
system_index: u16,
|
system_index: u16,
|
||||||
|
|||||||
@ -16,6 +16,7 @@ pub struct COpenConnectionReply1 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl COpenConnectionReply1 {
|
impl COpenConnectionReply1 {
|
||||||
|
#[must_use]
|
||||||
pub fn new(server_guid: u64, has_server_security: bool, mtu: u16) -> Self {
|
pub fn new(server_guid: u64, has_server_security: bool, mtu: u16) -> Self {
|
||||||
Self {
|
Self {
|
||||||
magic: RAKNET_MAGIC,
|
magic: RAKNET_MAGIC,
|
||||||
@ -38,6 +39,7 @@ pub struct COpenConnectionReply2 {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl COpenConnectionReply2 {
|
impl COpenConnectionReply2 {
|
||||||
|
#[must_use]
|
||||||
pub fn new(server_guid: u64, client_address: SocketAddr, mtu: u16, security: bool) -> Self {
|
pub fn new(server_guid: u64, client_address: SocketAddr, mtu: u16, security: bool) -> Self {
|
||||||
Self {
|
Self {
|
||||||
magic: RAKNET_MAGIC,
|
magic: RAKNET_MAGIC,
|
||||||
|
|||||||
@ -61,6 +61,7 @@ impl fmt::Display for ServerInfo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl CUnconnectedPong {
|
impl CUnconnectedPong {
|
||||||
|
#[must_use]
|
||||||
pub fn new(time: u64, server_guid: u64, magic: [u8; 16], server_id: String) -> Self {
|
pub fn new(time: u64, server_guid: u64, magic: [u8; 16], server_id: String) -> Self {
|
||||||
Self {
|
Self {
|
||||||
time,
|
time,
|
||||||
|
|||||||
@ -17,6 +17,7 @@ pub struct CResourcePackStackPacket {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl CResourcePackStackPacket {
|
impl CResourcePackStackPacket {
|
||||||
|
#[must_use]
|
||||||
pub fn new(
|
pub fn new(
|
||||||
resource_pack_required: bool,
|
resource_pack_required: bool,
|
||||||
texture_pack_list_size: VarUInt,
|
texture_pack_list_size: VarUInt,
|
||||||
|
|||||||
@ -15,6 +15,8 @@ pub struct CResourcePacksInfo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl CResourcePacksInfo {
|
impl CResourcePacksInfo {
|
||||||
|
#[must_use]
|
||||||
|
#[expect(clippy::fn_params_excessive_bools)]
|
||||||
pub fn new(
|
pub fn new(
|
||||||
resource_pack_required: bool,
|
resource_pack_required: bool,
|
||||||
has_addon_packs: bool,
|
has_addon_packs: bool,
|
||||||
|
|||||||
@ -71,6 +71,7 @@ pub enum MetadataValue {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl MetadataValue {
|
impl MetadataValue {
|
||||||
|
#[must_use]
|
||||||
pub fn type_id(&self) -> u32 {
|
pub fn type_id(&self) -> u32 {
|
||||||
match self {
|
match self {
|
||||||
Self::Byte(_) => 0,
|
Self::Byte(_) => 0,
|
||||||
|
|||||||
@ -9,6 +9,7 @@ pub struct CSetTime {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl CSetTime {
|
impl CSetTime {
|
||||||
|
#[must_use]
|
||||||
pub const fn new(time: i32) -> Self {
|
pub const fn new(time: i32) -> Self {
|
||||||
Self { time: VarInt(time) }
|
Self { time: VarInt(time) }
|
||||||
}
|
}
|
||||||
|
|||||||
@ -51,6 +51,7 @@ pub struct Frame {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Frame {
|
impl Frame {
|
||||||
|
#[must_use]
|
||||||
pub fn new_unreliable(payload: Vec<u8>) -> Self {
|
pub fn new_unreliable(payload: Vec<u8>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
reliability: RakReliability::Unreliable,
|
reliability: RakReliability::Unreliable,
|
||||||
@ -71,19 +72,18 @@ impl Frame {
|
|||||||
while let Ok(header) = u8::read(reader) {
|
while let Ok(header) = u8::read(reader) {
|
||||||
let mut frame = Self::default();
|
let mut frame = Self::default();
|
||||||
let reliability_id = (header & 0xE0) >> 5;
|
let reliability_id = (header & 0xE0) >> 5;
|
||||||
let reliability = match RakReliability::from_id(reliability_id) {
|
let Some(reliability) = RakReliability::from_id(reliability_id) else {
|
||||||
Some(reliability) => reliability,
|
return Err(Error::other("Invalid reliability"));
|
||||||
None => return Err(Error::other("Invalid reliability")),
|
|
||||||
};
|
};
|
||||||
let split = (header & RAKNET_SPLIT) != 0;
|
let split = (header & RAKNET_SPLIT) != 0;
|
||||||
let length = u16::read_be(reader)? >> 3;
|
let length = u16::read_be(reader)? >> 3;
|
||||||
|
|
||||||
if reliability.is_reliable() {
|
if reliability.is_reliable() {
|
||||||
frame.reliable_number = u24::read(reader)?.0
|
frame.reliable_number = u24::read(reader)?.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if reliability.is_sequenced() {
|
if reliability.is_sequenced() {
|
||||||
frame.sequence_index = u24::read(reader)?.0
|
frame.sequence_index = u24::read(reader)?.0;
|
||||||
}
|
}
|
||||||
|
|
||||||
if reliability.is_ordered() {
|
if reliability.is_ordered() {
|
||||||
|
|||||||
@ -35,65 +35,68 @@ pub enum RakReliability {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl RakReliability {
|
impl RakReliability {
|
||||||
|
#[must_use]
|
||||||
pub fn is_reliable(&self) -> bool {
|
pub fn is_reliable(&self) -> bool {
|
||||||
matches!(
|
matches!(
|
||||||
self,
|
self,
|
||||||
RakReliability::Reliable
|
Self::Reliable
|
||||||
| RakReliability::ReliableOrdered
|
| Self::ReliableOrdered
|
||||||
| RakReliability::ReliableSequenced
|
| Self::ReliableSequenced
|
||||||
| RakReliability::ReliableWithAckReceipt
|
| Self::ReliableWithAckReceipt
|
||||||
| RakReliability::ReliableOrderedWithAckReceipt
|
| Self::ReliableOrderedWithAckReceipt
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub fn is_sequenced(&self) -> bool {
|
pub fn is_sequenced(&self) -> bool {
|
||||||
matches!(
|
matches!(self, Self::ReliableSequenced | Self::UnreliableSequenced)
|
||||||
self,
|
|
||||||
RakReliability::ReliableSequenced | RakReliability::UnreliableSequenced
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub fn is_ordered(&self) -> bool {
|
pub fn is_ordered(&self) -> bool {
|
||||||
matches!(
|
matches!(
|
||||||
self,
|
self,
|
||||||
RakReliability::UnreliableSequenced
|
Self::UnreliableSequenced
|
||||||
| RakReliability::ReliableOrdered
|
| Self::ReliableOrdered
|
||||||
| RakReliability::ReliableSequenced
|
| Self::ReliableSequenced
|
||||||
| RakReliability::ReliableOrderedWithAckReceipt
|
| Self::ReliableOrderedWithAckReceipt
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub fn is_order_exclusive(&self) -> bool {
|
pub fn is_order_exclusive(&self) -> bool {
|
||||||
matches!(
|
matches!(
|
||||||
self,
|
self,
|
||||||
RakReliability::ReliableOrdered | RakReliability::ReliableOrderedWithAckReceipt
|
Self::ReliableOrdered | Self::ReliableOrderedWithAckReceipt
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub fn from_id(id: u8) -> Option<Self> {
|
pub fn from_id(id: u8) -> Option<Self> {
|
||||||
match id {
|
match id {
|
||||||
0 => Some(RakReliability::Unreliable),
|
0 => Some(Self::Unreliable),
|
||||||
1 => Some(RakReliability::UnreliableSequenced),
|
1 => Some(Self::UnreliableSequenced),
|
||||||
2 => Some(RakReliability::Reliable),
|
2 => Some(Self::Reliable),
|
||||||
3 => Some(RakReliability::ReliableOrdered),
|
3 => Some(Self::ReliableOrdered),
|
||||||
4 => Some(RakReliability::ReliableSequenced),
|
4 => Some(Self::ReliableSequenced),
|
||||||
5 => Some(RakReliability::UnreliableWithAckReceipt),
|
5 => Some(Self::UnreliableWithAckReceipt),
|
||||||
6 => Some(RakReliability::ReliableWithAckReceipt),
|
6 => Some(Self::ReliableWithAckReceipt),
|
||||||
7 => Some(RakReliability::ReliableOrderedWithAckReceipt),
|
7 => Some(Self::ReliableOrderedWithAckReceipt),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub fn to_id(&self) -> u8 {
|
pub fn to_id(&self) -> u8 {
|
||||||
match self {
|
match self {
|
||||||
RakReliability::Unreliable => 0,
|
Self::Unreliable => 0,
|
||||||
RakReliability::UnreliableSequenced => 1,
|
Self::UnreliableSequenced => 1,
|
||||||
RakReliability::Reliable => 2,
|
Self::Reliable => 2,
|
||||||
RakReliability::ReliableOrdered => 3,
|
Self::ReliableOrdered => 3,
|
||||||
RakReliability::ReliableSequenced => 4,
|
Self::ReliableSequenced => 4,
|
||||||
RakReliability::UnreliableWithAckReceipt => 5,
|
Self::UnreliableWithAckReceipt => 5,
|
||||||
RakReliability::ReliableWithAckReceipt => 6,
|
Self::ReliableWithAckReceipt => 6,
|
||||||
RakReliability::ReliableOrderedWithAckReceipt => 7,
|
Self::ReliableOrderedWithAckReceipt => 7,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -46,10 +46,11 @@ pub enum DecryptionReader<R: AsyncRead + Unpin> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<R: AsyncRead + Unpin> DecryptionReader<R> {
|
impl<R: AsyncRead + Unpin> DecryptionReader<R> {
|
||||||
|
#[must_use]
|
||||||
pub fn upgrade(self, cipher: Aes128Cfb8Dec) -> Self {
|
pub fn upgrade(self, cipher: Aes128Cfb8Dec) -> Self {
|
||||||
match self {
|
match self {
|
||||||
Self::None(stream) => Self::Decrypt(Box::new(StreamDecryptor::new(cipher, stream))),
|
Self::None(stream) => Self::Decrypt(Box::new(StreamDecryptor::new(cipher, stream))),
|
||||||
_ => panic!("Cannot upgrade a stream that already has a cipher!"),
|
Self::Decrypt(_) => panic!("Cannot upgrade a stream that already has a cipher!"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -75,7 +76,7 @@ impl<R: AsyncRead + Unpin> AsyncRead for DecryptionReader<R> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Decoder: Client -> Server
|
/// Decoder: Client -> Server
|
||||||
/// Supports ZLib decoding/decompression
|
/// Supports `ZLib` decoding/decompression
|
||||||
/// Supports Aes128 Encryption
|
/// Supports Aes128 Encryption
|
||||||
pub struct UDPNetworkDecoder {
|
pub struct UDPNetworkDecoder {
|
||||||
compression: Option<CompressionThreshold>,
|
compression: Option<CompressionThreshold>,
|
||||||
@ -88,6 +89,7 @@ impl Default for UDPNetworkDecoder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl UDPNetworkDecoder {
|
impl UDPNetworkDecoder {
|
||||||
|
#[must_use]
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self { compression: None }
|
Self { compression: None }
|
||||||
}
|
}
|
||||||
@ -105,6 +107,7 @@ impl UDPNetworkDecoder {
|
|||||||
// take_mut::take(&mut self.reader, |decoder| decoder.upgrade(cipher));
|
// take_mut::take(&mut self.reader, |decoder| decoder.upgrade(cipher));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[expect(clippy::unused_async)]
|
||||||
pub async fn get_packet_payload(
|
pub async fn get_packet_payload(
|
||||||
&mut self,
|
&mut self,
|
||||||
reader: Cursor<Vec<u8>>,
|
reader: Cursor<Vec<u8>>,
|
||||||
@ -118,7 +121,7 @@ impl UDPNetworkDecoder {
|
|||||||
Ok(reader.into_inner().into())
|
Ok(reader.into_inner().into())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_game_packet(
|
pub fn get_game_packet(
|
||||||
&mut self,
|
&mut self,
|
||||||
mut reader: Cursor<Vec<u8>>,
|
mut reader: Cursor<Vec<u8>>,
|
||||||
) -> Result<RawPacket, PacketDecodeError> {
|
) -> Result<RawPacket, PacketDecodeError> {
|
||||||
@ -134,7 +137,7 @@ impl UDPNetworkDecoder {
|
|||||||
err => PacketDecodeError::MalformedLength(err.to_string()),
|
err => PacketDecodeError::MalformedLength(err.to_string()),
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
let packet_len = packet_len.0 as u64;
|
let packet_len = u64::from(packet_len.0);
|
||||||
|
|
||||||
let var_header = VarUInt::decode(&mut reader)?;
|
let var_header = VarUInt::decode(&mut reader)?;
|
||||||
|
|
||||||
@ -148,10 +151,10 @@ impl UDPNetworkDecoder {
|
|||||||
// SubClient Target ID (2 bits)
|
// SubClient Target ID (2 bits)
|
||||||
|
|
||||||
// SubClient Target ID: Lowest 2 bits
|
// SubClient Target ID: Lowest 2 bits
|
||||||
let _sub_client_target = (header >> 10 & 0b11) as u8;
|
// let _sub_client_target = (header >> 10 & 0b11) as u8;
|
||||||
|
|
||||||
// SubClient Sender ID: Next 2 bits (bits 2 and 3)
|
// SubClient Sender ID: Next 2 bits (bits 2 and 3)
|
||||||
let _sub_client_sender = (header >> 12 & 0b11) as u8;
|
// let _sub_client_sender = (header >> 12 & 0b11) as u8;
|
||||||
|
|
||||||
// Gamepacket ID: Remaining 10 bits (bits 4 to 13)
|
// Gamepacket ID: Remaining 10 bits (bits 4 to 13)
|
||||||
let gamepacket_id = (header & 0x3FF) as u16; // 0x3FF is 10 bits set to 1
|
let gamepacket_id = (header & 0x3FF) as u16; // 0x3FF is 10 bits set to 1
|
||||||
@ -161,7 +164,7 @@ impl UDPNetworkDecoder {
|
|||||||
.map_err(|err| PacketDecodeError::FailedDecompression(err.to_string()))?;
|
.map_err(|err| PacketDecodeError::FailedDecompression(err.to_string()))?;
|
||||||
|
|
||||||
Ok(RawPacket {
|
Ok(RawPacket {
|
||||||
id: gamepacket_id as i32,
|
id: i32::from(gamepacket_id),
|
||||||
payload: payload.into(),
|
payload: payload.into(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,7 +5,6 @@ use std::{
|
|||||||
task::{Context, Poll},
|
task::{Context, Poll},
|
||||||
};
|
};
|
||||||
|
|
||||||
use bytes::Bytes;
|
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
use tokio::{io::AsyncWrite, net::UdpSocket};
|
use tokio::{io::AsyncWrite, net::UdpSocket};
|
||||||
|
|
||||||
@ -22,10 +21,11 @@ pub enum EncryptionWriter<W: AsyncWrite + Unpin> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<W: AsyncWrite + Unpin> EncryptionWriter<W> {
|
impl<W: AsyncWrite + Unpin> EncryptionWriter<W> {
|
||||||
|
#[must_use]
|
||||||
pub fn upgrade(self, cipher: Aes128Cfb8Enc) -> Self {
|
pub fn upgrade(self, cipher: Aes128Cfb8Enc) -> Self {
|
||||||
match self {
|
match self {
|
||||||
Self::None(stream) => Self::Encrypt(Box::new(StreamEncryptor::new(cipher, stream))),
|
Self::None(stream) => Self::Encrypt(Box::new(StreamEncryptor::new(cipher, stream))),
|
||||||
_ => panic!("Cannot upgrade a stream that already has a cipher!"),
|
Self::Encrypt(_) => panic!("Cannot upgrade a stream that already has a cipher!"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -76,7 +76,7 @@ impl<W: AsyncWrite + Unpin> AsyncWrite for EncryptionWriter<W> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Encoder: Server -> Client
|
/// Encoder: Server -> Client
|
||||||
/// Supports ZLib endecoding/compression
|
/// Supports `ZLib` endecoding/compression
|
||||||
/// Supports Aes128 Encryption
|
/// Supports Aes128 Encryption
|
||||||
pub struct UDPNetworkEncoder {
|
pub struct UDPNetworkEncoder {
|
||||||
// compression and compression threshold
|
// compression and compression threshold
|
||||||
@ -90,6 +90,7 @@ impl Default for UDPNetworkEncoder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl UDPNetworkEncoder {
|
impl UDPNetworkEncoder {
|
||||||
|
#[must_use]
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self { compression: None }
|
Self { compression: None }
|
||||||
}
|
}
|
||||||
@ -107,12 +108,12 @@ impl UDPNetworkEncoder {
|
|||||||
// take_mut::take(&mut self.writer, |encoder| encoder.upgrade(cipher));
|
// take_mut::take(&mut self.writer, |encoder| encoder.upgrade(cipher));
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn write_game_packet(
|
pub fn write_game_packet(
|
||||||
&mut self,
|
&mut self,
|
||||||
packet_id: u16,
|
packet_id: u16,
|
||||||
sub_client_sender: SubClient,
|
sub_client_sender: SubClient,
|
||||||
sub_client_target: SubClient,
|
sub_client_target: SubClient,
|
||||||
packet_payload: Bytes,
|
packet_payload: &[u8],
|
||||||
mut writer: impl Write,
|
mut writer: impl Write,
|
||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
// Game Packet ID
|
// Game Packet ID
|
||||||
@ -128,7 +129,7 @@ impl UDPNetworkEncoder {
|
|||||||
// Gamepacket ID (10 bits) << 4 (offset by 2 bits for target + 2 bits for sender)
|
// Gamepacket ID (10 bits) << 4 (offset by 2 bits for target + 2 bits for sender)
|
||||||
// SubClient Sender ID (2 bits) << 2 (offset by 2 bits for target)
|
// SubClient Sender ID (2 bits) << 2 (offset by 2 bits for target)
|
||||||
// SubClient Target ID (2 bits)
|
// SubClient Target ID (2 bits)
|
||||||
let header_value: u32 = packet_id as u32
|
let header_value: u32 = u32::from(packet_id)
|
||||||
| ((sub_client_sender as u32) << 10)
|
| ((sub_client_sender as u32) << 10)
|
||||||
| ((sub_client_target as u32) << 12);
|
| ((sub_client_target as u32) << 12);
|
||||||
|
|
||||||
@ -158,7 +159,7 @@ impl UDPNetworkEncoder {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
// 5. Write the payload
|
// 5. Write the payload
|
||||||
writer.write_all(&packet_payload)
|
writer.write_all(packet_payload)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn write_packet(
|
pub async fn write_packet(
|
||||||
|
|||||||
@ -13,6 +13,7 @@ pub struct SLoadingScreen {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl SLoadingScreen {
|
impl SLoadingScreen {
|
||||||
|
#[must_use]
|
||||||
pub fn is_loading_done(&self) -> bool {
|
pub fn is_loading_done(&self) -> bool {
|
||||||
self.status.0 == 2
|
self.status.0 == 2
|
||||||
}
|
}
|
||||||
|
|||||||
@ -19,6 +19,7 @@ pub struct SText {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl SText {
|
impl SText {
|
||||||
|
#[must_use]
|
||||||
pub fn new(message: String, source_name: String) -> Self {
|
pub fn new(message: String, source_name: String) -> Self {
|
||||||
Self {
|
Self {
|
||||||
needs_translation: false,
|
needs_translation: false,
|
||||||
@ -36,6 +37,7 @@ impl SText {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
pub fn system_message(message: String) -> Self {
|
pub fn system_message(message: String) -> Self {
|
||||||
Self {
|
Self {
|
||||||
needs_translation: false,
|
needs_translation: false,
|
||||||
@ -97,10 +99,7 @@ impl PacketRead for SText {
|
|||||||
if actual != expected {
|
if actual != expected {
|
||||||
return Err(Error::new(
|
return Err(Error::new(
|
||||||
ErrorKind::InvalidData,
|
ErrorKind::InvalidData,
|
||||||
format!(
|
format!("Dummy string mismatch: expected {expected}, got {actual}"),
|
||||||
"Dummy string mismatch: expected {}, got {}",
|
|
||||||
expected, actual
|
|
||||||
),
|
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -10,7 +10,7 @@ use crate::{
|
|||||||
/// A wrapper for `BlockPos` that handles Bedrock-specific network serialization.
|
/// A wrapper for `BlockPos` that handles Bedrock-specific network serialization.
|
||||||
///
|
///
|
||||||
/// Bedrock Edition encodes coordinates differently than Java Edition, using
|
/// Bedrock Edition encodes coordinates differently than Java Edition, using
|
||||||
/// VarInt's to save bandwidth.
|
/// `VarInt`'s to save bandwidth.
|
||||||
pub struct NetworkPos(pub BlockPos);
|
pub struct NetworkPos(pub BlockPos);
|
||||||
|
|
||||||
impl NetworkPos {
|
impl NetworkPos {
|
||||||
|
|||||||
@ -31,7 +31,7 @@ impl BitSet {
|
|||||||
let long = read.get_i64_be()?;
|
let long = read.get_i64_be()?;
|
||||||
array.push(long);
|
array.push(long);
|
||||||
}
|
}
|
||||||
Ok(BitSet(array.into_boxed_slice()))
|
Ok(Self(array.into_boxed_slice()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -10,17 +10,13 @@ pub struct Bitset<const N: usize> {
|
|||||||
impl<const N: usize> Bitset<N> {
|
impl<const N: usize> Bitset<N> {
|
||||||
pub fn get<T: Into<usize>>(&self, index: T) -> bool {
|
pub fn get<T: Into<usize>>(&self, index: T) -> bool {
|
||||||
let index: usize = index.into();
|
let index: usize = index.into();
|
||||||
if index > N {
|
assert!(index <= N, "");
|
||||||
panic!("")
|
|
||||||
}
|
|
||||||
(self.bits & (1 << index)) != 0
|
(self.bits & (1 << index)) != 0
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set<T: Into<usize>>(&mut self, index: T, value: bool) {
|
pub fn set<T: Into<usize>>(&mut self, index: T, value: bool) {
|
||||||
let index: usize = index.into();
|
let index: usize = index.into();
|
||||||
if index > N {
|
assert!(index <= N, "");
|
||||||
panic!("")
|
|
||||||
}
|
|
||||||
if value {
|
if value {
|
||||||
self.bits |= 1 << index;
|
self.bits |= 1 << index;
|
||||||
} else {
|
} else {
|
||||||
@ -31,16 +27,14 @@ impl<const N: usize> Bitset<N> {
|
|||||||
|
|
||||||
impl<const N: usize> Default for Bitset<N> {
|
impl<const N: usize> Default for Bitset<N> {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
if N > 80 {
|
assert!(N <= 80,);
|
||||||
panic!()
|
|
||||||
}
|
|
||||||
Self { bits: 0 }
|
Self { bits: 0 }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<const N: usize> PacketRead for Bitset<N> {
|
impl<const N: usize> PacketRead for Bitset<N> {
|
||||||
fn read<R: Read>(reader: &mut R) -> Result<Self, Error> {
|
fn read<R: Read>(reader: &mut R) -> Result<Self, Error> {
|
||||||
let mut bitset = Bitset::<N>::default();
|
let mut bitset = Self::default();
|
||||||
|
|
||||||
for i in 0..N.div_ceil(8) {
|
for i in 0..N.div_ceil(8) {
|
||||||
let byte = u8::read(reader)?;
|
let byte = u8::read(reader)?;
|
||||||
|
|||||||
@ -71,7 +71,7 @@ impl DataComponentCodec<Self> for EnchantmentsImpl {
|
|||||||
"EnchantmentsImpl Enchantment VarInt Incorrect!",
|
"EnchantmentsImpl Enchantment VarInt Incorrect!",
|
||||||
))?,
|
))?,
|
||||||
level,
|
level,
|
||||||
))
|
));
|
||||||
}
|
}
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
enchantment: Cow::from(enc),
|
enchantment: Cow::from(enc),
|
||||||
|
|||||||
@ -57,7 +57,7 @@ impl<'de> Deserialize<'de> for ItemStackSerializer<'static> {
|
|||||||
let _byte_len = seq
|
let _byte_len = seq
|
||||||
.next_element::<VarInt>()?
|
.next_element::<VarInt>()?
|
||||||
.ok_or(de::Error::custom("No data len VarInt!"))?;
|
.ok_or(de::Error::custom("No data len VarInt!"))?;
|
||||||
patch.push((id, Some(deserialize(id, &mut seq)?)))
|
patch.push((id, Some(deserialize(id, &mut seq)?)));
|
||||||
}
|
}
|
||||||
for _ in 0..num_components_to_remove {
|
for _ in 0..num_components_to_remove {
|
||||||
let id = seq
|
let id = seq
|
||||||
@ -68,7 +68,7 @@ impl<'de> Deserialize<'de> for ItemStackSerializer<'static> {
|
|||||||
.map_err(|_| de::Error::custom("Unknown component id VarInt!"))?;
|
.map_err(|_| de::Error::custom("Unknown component id VarInt!"))?;
|
||||||
let id = DataComponent::try_from_id(id)
|
let id = DataComponent::try_from_id(id)
|
||||||
.ok_or(de::Error::custom("Unknown component id VarInt!"))?;
|
.ok_or(de::Error::custom("Unknown component id VarInt!"))?;
|
||||||
patch.push((id, None))
|
patch.push((id, None));
|
||||||
}
|
}
|
||||||
|
|
||||||
let item_id: u16 = item_id
|
let item_id: u16 = item_id
|
||||||
@ -131,6 +131,7 @@ impl Serialize for ItemStackSerializer<'_> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl ItemStackSerializer<'_> {
|
impl ItemStackSerializer<'_> {
|
||||||
|
#[must_use]
|
||||||
pub fn to_stack(self) -> ItemStack {
|
pub fn to_stack(self) -> ItemStack {
|
||||||
self.0.into_owned()
|
self.0.into_owned()
|
||||||
}
|
}
|
||||||
@ -144,10 +145,10 @@ impl From<ItemStack> for ItemStackSerializer<'_> {
|
|||||||
|
|
||||||
impl From<Option<ItemStack>> for ItemStackSerializer<'_> {
|
impl From<Option<ItemStack>> for ItemStackSerializer<'_> {
|
||||||
fn from(item: Option<ItemStack>) -> Self {
|
fn from(item: Option<ItemStack>) -> Self {
|
||||||
match item {
|
item.map_or_else(
|
||||||
Some(item) => ItemStackSerializer::from(item),
|
|| ItemStackSerializer(Cow::Borrowed(ItemStack::EMPTY)),
|
||||||
None => ItemStackSerializer(Cow::Borrowed(ItemStack::EMPTY)),
|
ItemStackSerializer::from,
|
||||||
}
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -165,6 +166,7 @@ pub struct ItemStackHash {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl OptionalItemStackHash {
|
impl OptionalItemStackHash {
|
||||||
|
#[must_use]
|
||||||
pub fn hash_equals(&self, other: &ItemStack) -> bool {
|
pub fn hash_equals(&self, other: &ItemStack) -> bool {
|
||||||
if let Some(hash) = &self.0 {
|
if let Some(hash) = &self.0 {
|
||||||
if hash.item_id != other.item.id.into() || hash.count != other.item_count.into() {
|
if hash.item_id != other.item.id.into() || hash.count != other.item_count.into() {
|
||||||
@ -193,11 +195,10 @@ impl OptionalItemStackHash {
|
|||||||
let checksum = data.get_hash();
|
let checksum = data.get_hash();
|
||||||
for (id, hash) in &hash.components.added {
|
for (id, hash) in &hash.components.added {
|
||||||
if id == &VarInt::from(other_id.to_id()) {
|
if id == &VarInt::from(other_id.to_id()) {
|
||||||
if hash != &checksum {
|
if hash == &checksum {
|
||||||
return false;
|
|
||||||
} else {
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if !hash
|
} else if !hash
|
||||||
|
|||||||
@ -8,10 +8,7 @@ pub struct OptionalInt(pub Option<i32>);
|
|||||||
impl Serialize for OptionalInt {
|
impl Serialize for OptionalInt {
|
||||||
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
|
fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
|
||||||
// Vanilla logic: empty is 0, otherwise value + 1
|
// Vanilla logic: empty is 0, otherwise value + 1
|
||||||
let val = match self.0 {
|
let val = self.0.map_or(0, |id| id + 1);
|
||||||
None => 0,
|
|
||||||
Some(id) => id + 1,
|
|
||||||
};
|
|
||||||
VarInt(val).serialize(serializer)
|
VarInt(val).serialize(serializer)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -17,6 +17,6 @@ impl PacketRead for u24 {
|
|||||||
fn read<R: Read>(reader: &mut R) -> Result<Self, Error> {
|
fn read<R: Read>(reader: &mut R) -> Result<Self, Error> {
|
||||||
let mut buf = [0; 3];
|
let mut buf = [0; 3];
|
||||||
reader.read_exact(&mut buf)?;
|
reader.read_exact(&mut buf)?;
|
||||||
Ok(u24(u32::from_le_bytes([buf[0], buf[1], buf[2], 0])))
|
Ok(Self(u32::from_le_bytes([buf[0], buf[1], buf[2], 0])))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -28,8 +28,9 @@ impl VarInt {
|
|||||||
/// The maximum number of bytes a `VarInt` can occupy.
|
/// The maximum number of bytes a `VarInt` can occupy.
|
||||||
const MAX_SIZE: NonZeroUsize = NonZeroUsize::new(5).unwrap();
|
const MAX_SIZE: NonZeroUsize = NonZeroUsize::new(5).unwrap();
|
||||||
|
|
||||||
/// Returns the exact number of bytes this VarInt will write when
|
/// Returns the exact number of bytes this `VarInt` will write when
|
||||||
/// [`Encode::encode`] is called, assuming no error occurs.
|
/// [`Encode::encode`] is called, assuming no error occurs.
|
||||||
|
#[must_use]
|
||||||
pub fn written_size(&self) -> usize {
|
pub fn written_size(&self) -> usize {
|
||||||
match self.0 {
|
match self.0 {
|
||||||
0 => 1,
|
0 => 1,
|
||||||
@ -57,7 +58,7 @@ impl VarInt {
|
|||||||
let byte = read.get_u8()?;
|
let byte = read.get_u8()?;
|
||||||
val |= (i32::from(byte) & 0x7F) << (i * 7);
|
val |= (i32::from(byte) & 0x7F) << (i * 7);
|
||||||
if byte & 0x80 == 0 {
|
if byte & 0x80 == 0 {
|
||||||
return Ok(VarInt(val));
|
return Ok(Self(val));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(ReadingError::TooLarge("VarInt".to_string()))
|
Err(ReadingError::TooLarge("VarInt".to_string()))
|
||||||
@ -77,7 +78,7 @@ impl VarInt {
|
|||||||
})?;
|
})?;
|
||||||
val |= (i32::from(byte) & 0x7F) << (i * 7);
|
val |= (i32::from(byte) & 0x7F) << (i * 7);
|
||||||
if byte & 0x80 == 0 {
|
if byte & 0x80 == 0 {
|
||||||
return Ok(VarInt(val));
|
return Ok(Self(val));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(ReadingError::TooLarge("VarInt".to_string()))
|
Err(ReadingError::TooLarge("VarInt".to_string()))
|
||||||
@ -89,10 +90,10 @@ impl VarInt {
|
|||||||
) -> Result<(), WritingError> {
|
) -> Result<(), WritingError> {
|
||||||
let mut val = self.0;
|
let mut val = self.0;
|
||||||
for _ in 0..Self::MAX_SIZE.get() {
|
for _ in 0..Self::MAX_SIZE.get() {
|
||||||
let b: u8 = val as u8 & 0b01111111;
|
let b: u8 = val as u8 & 0b0111_1111;
|
||||||
val >>= 7;
|
val >>= 7;
|
||||||
write
|
write
|
||||||
.write_u8(if val == 0 { b } else { b | 0b10000000 })
|
.write_u8(if val == 0 { b } else { b | 0b1000_0000 })
|
||||||
.await
|
.await
|
||||||
.map_err(WritingError::IoError)?;
|
.map_err(WritingError::IoError)?;
|
||||||
if val == 0 {
|
if val == 0 {
|
||||||
@ -183,8 +184,8 @@ impl<'de> Deserialize<'de> for VarInt {
|
|||||||
let mut val = 0;
|
let mut val = 0;
|
||||||
for i in 0..VarInt::MAX_SIZE.get() {
|
for i in 0..VarInt::MAX_SIZE.get() {
|
||||||
if let Some(byte) = seq.next_element::<u8>()? {
|
if let Some(byte) = seq.next_element::<u8>()? {
|
||||||
val |= (i32::from(byte) & 0b01111111) << (i * 7);
|
val |= (i32::from(byte) & 0b0111_1111) << (i * 7);
|
||||||
if byte & 0b10000000 == 0 {
|
if byte & 0b1000_0000 == 0 {
|
||||||
return Ok(VarInt(val));
|
return Ok(VarInt(val));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -220,7 +221,7 @@ impl PacketRead for VarInt {
|
|||||||
let byte = u8::read(read)?;
|
let byte = u8::read(read)?;
|
||||||
val |= (i32::from(byte) & 0x7F) << (i * 7);
|
val |= (i32::from(byte) & 0x7F) << (i * 7);
|
||||||
if byte & 0x80 == 0 {
|
if byte & 0x80 == 0 {
|
||||||
return Ok(VarInt((val >> 1) ^ (val << 31)));
|
return Ok(Self((val >> 1) ^ (val << 31)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(Error::new(ErrorKind::InvalidData, ""))
|
Err(Error::new(ErrorKind::InvalidData, ""))
|
||||||
|
|||||||
@ -46,7 +46,7 @@ impl VarLong {
|
|||||||
let byte = read.get_u8()?;
|
let byte = read.get_u8()?;
|
||||||
val |= (i64::from(byte) & 0x7F) << (i * 7);
|
val |= (i64::from(byte) & 0x7F) << (i * 7);
|
||||||
if byte & 0x80 == 0 {
|
if byte & 0x80 == 0 {
|
||||||
return Ok(VarLong(val));
|
return Ok(Self(val));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(ReadingError::TooLarge("VarLong".to_string()))
|
Err(ReadingError::TooLarge("VarLong".to_string()))
|
||||||
@ -55,25 +55,25 @@ impl VarLong {
|
|||||||
|
|
||||||
impl From<i64> for VarLong {
|
impl From<i64> for VarLong {
|
||||||
fn from(value: i64) -> Self {
|
fn from(value: i64) -> Self {
|
||||||
VarLong(value)
|
Self(value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<u32> for VarLong {
|
impl From<u32> for VarLong {
|
||||||
fn from(value: u32) -> Self {
|
fn from(value: u32) -> Self {
|
||||||
VarLong(value as i64)
|
Self(i64::from(value))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<u8> for VarLong {
|
impl From<u8> for VarLong {
|
||||||
fn from(value: u8) -> Self {
|
fn from(value: u8) -> Self {
|
||||||
VarLong(value as i64)
|
Self(i64::from(value))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<usize> for VarLong {
|
impl From<usize> for VarLong {
|
||||||
fn from(value: usize) -> Self {
|
fn from(value: usize) -> Self {
|
||||||
VarLong(value as i64)
|
Self(value as i64)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -128,8 +128,8 @@ impl<'de> Deserialize<'de> for VarLong {
|
|||||||
let mut val = 0;
|
let mut val = 0;
|
||||||
for i in 0..VarLong::MAX_SIZE.get() {
|
for i in 0..VarLong::MAX_SIZE.get() {
|
||||||
if let Some(byte) = seq.next_element::<u8>()? {
|
if let Some(byte) = seq.next_element::<u8>()? {
|
||||||
val |= (i64::from(byte) & 0b01111111) << (i * 7);
|
val |= (i64::from(byte) & 0b0111_1111) << (i * 7);
|
||||||
if byte & 0b10000000 == 0 {
|
if byte & 0b1000_0000 == 0 {
|
||||||
return Ok(VarLong(val));
|
return Ok(VarLong(val));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@ -27,8 +27,9 @@ impl VarUInt {
|
|||||||
/// The maximum number of bytes a `VarUInt` can occupy.
|
/// The maximum number of bytes a `VarUInt` can occupy.
|
||||||
const MAX_SIZE: NonZeroUsize = NonZeroUsize::new(5).unwrap();
|
const MAX_SIZE: NonZeroUsize = NonZeroUsize::new(5).unwrap();
|
||||||
|
|
||||||
/// Returns the exact number of bytes this VarUInt will write when
|
/// Returns the exact number of bytes this `VarUInt` will write when
|
||||||
/// [`Encode::encode`] is called, assuming no error occurs.
|
/// [`Encode::encode`] is called, assuming no error occurs.
|
||||||
|
#[must_use]
|
||||||
pub fn written_size(&self) -> usize {
|
pub fn written_size(&self) -> usize {
|
||||||
(32 - self.0.leading_zeros() as usize).max(1).div_ceil(7)
|
(32 - self.0.leading_zeros() as usize).max(1).div_ceil(7)
|
||||||
}
|
}
|
||||||
@ -56,7 +57,7 @@ impl VarUInt {
|
|||||||
let byte = read.get_u8()?;
|
let byte = read.get_u8()?;
|
||||||
val |= (u32::from(byte) & 0x7F) << (i * 7);
|
val |= (u32::from(byte) & 0x7F) << (i * 7);
|
||||||
if byte & 0x80 == 0 {
|
if byte & 0x80 == 0 {
|
||||||
return Ok(VarUInt(val));
|
return Ok(Self(val));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(ReadingError::TooLarge("VarUInt".to_string()))
|
Err(ReadingError::TooLarge("VarUInt".to_string()))
|
||||||
@ -76,7 +77,7 @@ impl VarUInt {
|
|||||||
})?;
|
})?;
|
||||||
val |= (u32::from(byte) & 0x7F) << (i * 7);
|
val |= (u32::from(byte) & 0x7F) << (i * 7);
|
||||||
if byte & 0x80 == 0 {
|
if byte & 0x80 == 0 {
|
||||||
return Ok(VarUInt(val));
|
return Ok(Self(val));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(ReadingError::TooLarge("VarUInt".to_string()))
|
Err(ReadingError::TooLarge("VarUInt".to_string()))
|
||||||
@ -88,10 +89,10 @@ impl VarUInt {
|
|||||||
) -> Result<(), WritingError> {
|
) -> Result<(), WritingError> {
|
||||||
let mut val = self.0;
|
let mut val = self.0;
|
||||||
for _ in 0..Self::MAX_SIZE.get() {
|
for _ in 0..Self::MAX_SIZE.get() {
|
||||||
let b: u8 = val as u8 & 0b01111111;
|
let b: u8 = val as u8 & 0b0111_1111;
|
||||||
val >>= 7;
|
val >>= 7;
|
||||||
write
|
write
|
||||||
.write_u8(if val == 0 { b } else { b | 0b10000000 })
|
.write_u8(if val == 0 { b } else { b | 0b1000_0000 })
|
||||||
.await
|
.await
|
||||||
.map_err(WritingError::IoError)?;
|
.map_err(WritingError::IoError)?;
|
||||||
if val == 0 {
|
if val == 0 {
|
||||||
@ -166,8 +167,8 @@ impl<'de> Deserialize<'de> for VarUInt {
|
|||||||
let mut val = 0;
|
let mut val = 0;
|
||||||
for i in 0..VarUInt::MAX_SIZE.get() {
|
for i in 0..VarUInt::MAX_SIZE.get() {
|
||||||
if let Some(byte) = seq.next_element::<u8>()? {
|
if let Some(byte) = seq.next_element::<u8>()? {
|
||||||
val |= (u32::from(byte) & 0b01111111) << (i * 7);
|
val |= (u32::from(byte) & 0b0111_1111) << (i * 7);
|
||||||
if byte & 0b10000000 == 0 {
|
if byte & 0b1000_0000 == 0 {
|
||||||
return Ok(VarUInt(val));
|
return Ok(VarUInt(val));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -207,7 +208,7 @@ impl PacketRead for VarUInt {
|
|||||||
let byte = u8::read(reader)?;
|
let byte = u8::read(reader)?;
|
||||||
val |= (u32::from(byte) & 0x7F) << (i * 7);
|
val |= (u32::from(byte) & 0x7F) << (i * 7);
|
||||||
if byte & 0x80 == 0 {
|
if byte & 0x80 == 0 {
|
||||||
return Ok(VarUInt(val));
|
return Ok(Self(val));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(Error::new(ErrorKind::InvalidData, ""))
|
Err(Error::new(ErrorKind::InvalidData, ""))
|
||||||
|
|||||||
@ -27,8 +27,9 @@ impl VarULong {
|
|||||||
/// The maximum number of bytes a `VarULong` can occupy.
|
/// The maximum number of bytes a `VarULong` can occupy.
|
||||||
const MAX_SIZE: NonZeroUsize = NonZeroUsize::new(10).unwrap();
|
const MAX_SIZE: NonZeroUsize = NonZeroUsize::new(10).unwrap();
|
||||||
|
|
||||||
/// Returns the exact number of bytes this VarLong will write when
|
/// Returns the exact number of bytes this `VarLong` will write when
|
||||||
/// [`Encode::encode`] is called, assuming no error occurs.
|
/// [`Encode::encode`] is called, assuming no error occurs.
|
||||||
|
#[must_use]
|
||||||
pub fn written_size(&self) -> usize {
|
pub fn written_size(&self) -> usize {
|
||||||
match self.0 {
|
match self.0 {
|
||||||
0 => 1,
|
0 => 1,
|
||||||
@ -56,9 +57,9 @@ impl VarULong {
|
|||||||
let mut val = 0;
|
let mut val = 0;
|
||||||
for i in 0..Self::MAX_SIZE.get() {
|
for i in 0..Self::MAX_SIZE.get() {
|
||||||
let byte = read.get_u8()?;
|
let byte = read.get_u8()?;
|
||||||
val |= (u64::from(byte) & 0b01111111) << (i * 7);
|
val |= (u64::from(byte) & 0b0111_1111) << (i * 7);
|
||||||
if byte & 0b10000000 == 0 {
|
if byte & 0b1000_0000 == 0 {
|
||||||
return Ok(VarULong(val));
|
return Ok(Self(val));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(ReadingError::TooLarge("VarLong".to_string()))
|
Err(ReadingError::TooLarge("VarLong".to_string()))
|
||||||
@ -67,25 +68,25 @@ impl VarULong {
|
|||||||
|
|
||||||
impl From<u64> for VarULong {
|
impl From<u64> for VarULong {
|
||||||
fn from(value: u64) -> Self {
|
fn from(value: u64) -> Self {
|
||||||
VarULong(value)
|
Self(value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<u32> for VarULong {
|
impl From<u32> for VarULong {
|
||||||
fn from(value: u32) -> Self {
|
fn from(value: u32) -> Self {
|
||||||
VarULong(value as u64)
|
Self(u64::from(value))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<u8> for VarULong {
|
impl From<u8> for VarULong {
|
||||||
fn from(value: u8) -> Self {
|
fn from(value: u8) -> Self {
|
||||||
VarULong(value as u64)
|
Self(u64::from(value))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<usize> for VarULong {
|
impl From<usize> for VarULong {
|
||||||
fn from(value: usize) -> Self {
|
fn from(value: usize) -> Self {
|
||||||
VarULong(value as u64)
|
Self(value as u64)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -140,8 +141,8 @@ impl<'de> Deserialize<'de> for VarULong {
|
|||||||
let mut val = 0;
|
let mut val = 0;
|
||||||
for i in 0..VarULong::MAX_SIZE.get() {
|
for i in 0..VarULong::MAX_SIZE.get() {
|
||||||
if let Some(byte) = seq.next_element::<u8>()? {
|
if let Some(byte) = seq.next_element::<u8>()? {
|
||||||
val |= (u64::from(byte) & 0b01111111) << (i * 7);
|
val |= (u64::from(byte) & 0b0111_1111) << (i * 7);
|
||||||
if byte & 0b10000000 == 0 {
|
if byte & 0b1000_0000 == 0 {
|
||||||
return Ok(VarULong(val));
|
return Ok(VarULong(val));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -178,9 +179,9 @@ impl PacketRead for VarULong {
|
|||||||
let mut val = 0;
|
let mut val = 0;
|
||||||
for i in 0..Self::MAX_SIZE.get() {
|
for i in 0..Self::MAX_SIZE.get() {
|
||||||
let byte = u8::read(reader)?;
|
let byte = u8::read(reader)?;
|
||||||
val |= (u64::from(byte) & 0b01111111) << (i * 7);
|
val |= (u64::from(byte) & 0b0111_1111) << (i * 7);
|
||||||
if byte & 0b10000000 == 0 {
|
if byte & 0b1000_0000 == 0 {
|
||||||
return Ok(VarULong(val));
|
return Ok(Self(val));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(Error::other("Invalid VarUInt"))
|
Err(Error::other("Invalid VarUInt"))
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user