diff --git a/Cargo.lock b/Cargo.lock index a77bdbfe0..36bdaba22 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -876,9 +876,9 @@ checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" [[package]] name = "crossfire" -version = "3.1.15" +version = "3.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7985ad34fb5a761ce21154d0e5a8c37ec6b50af61c90d594eb5cdeb934f91f7c" +checksum = "4d8c4de3db833e7ef74050bae09d5f3fa8f9d1507d3c2689c6e8c50b71208b18" dependencies = [ "crossbeam-utils", "embed-collections", @@ -2155,7 +2155,7 @@ version = "0.50.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 40d9532fa..0b0432bac 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -127,7 +127,7 @@ console-subscriber = { version = "0.5.0", default-features = false } crc-fast = { version = "1.10.0", default-features = false, features = ["std"] } criterion = { version = "0.8", default-features = false } crossbeam-utils = { version = "0.8.21", default-features = false, features = ["std"] } -crossfire = { version = "3.1.15", default-features = false, features = ["compat"] } +crossfire = { version = "3.1.16", default-features = false, features = ["compat"] } crypto-bigint = { version = "0.7.3", default-features = false } dashmap = { version = "6.2", default-features = false } ecdsa = { version = "0.16.9", default-features = false, features = ["std"] } diff --git a/pumpkin-codegen/src/block.rs b/pumpkin-codegen/src/block.rs index 54e880afb..6db07d711 100644 --- a/pumpkin-codegen/src/block.rs +++ b/pumpkin-codegen/src/block.rs @@ -1435,7 +1435,7 @@ fn get_be_data_from_nbt( let raw_name = nbt.get_string("name").unwrap(); raw_name .strip_prefix("minecraft:") - .unwrap_or(&raw_name) + .unwrap_or(raw_name) .to_string() }; diff --git a/pumpkin-codegen/src/loot.rs b/pumpkin-codegen/src/loot.rs index 074e7c908..20ef963ac 100644 --- a/pumpkin-codegen/src/loot.rs +++ b/pumpkin-codegen/src/loot.rs @@ -91,7 +91,6 @@ impl ToTokens for LootPoolStruct { } } - /// Deserialized single-item loot entry holding the item's registry key. #[derive(Deserialize, Clone, Debug)] pub struct ItemEntryStruct { @@ -428,9 +427,7 @@ pub enum LootConditionStruct { }, /// References an external predicate by ID. #[serde(rename = "minecraft:reference")] - Reference { - name: String, - }, + Reference { name: String }, /// Passes based on the current in-game time. #[serde(rename = "minecraft:time_check")] TimeCheck { @@ -446,9 +443,7 @@ pub enum LootConditionStruct { }, /// Passes if an enchantment is currently active. #[serde(rename = "minecraft:enchantment_active_check")] - EnchantmentActiveCheck { - active: bool, - }, + EnchantmentActiveCheck { active: bool }, } impl ToTokens for LootConditionStruct { @@ -461,7 +456,10 @@ impl ToTokens for LootConditionStruct { Self::RandomChance { chance } => { quote! { LootCondition::RandomChance { chance: #chance } } } - Self::RandomChanceWithEnchantedBonus { enchantment, chances } => { + Self::RandomChanceWithEnchantedBonus { + enchantment, + chances, + } => { let e = LitStr::new(enchantment, Span::call_site()); if let Some(chances) = chances { quote! { LootCondition::RandomChanceWithEnchantedBonus { enchantment: #e, chances: Some(&[#(#chances),*]) } } @@ -472,15 +470,17 @@ impl ToTokens for LootConditionStruct { Self::EntityProperties { entity, predicate } => { let entity = entity.as_deref().unwrap_or("this"); let e = LitStr::new(entity, Span::call_site()); - let expected_type = predicate.as_ref().and_then(|p| p.entity_type.as_ref()).map(|t| { - match t { + let expected_type = predicate + .as_ref() + .and_then(|p| p.entity_type.as_ref()) + .map(|t| match t { StringOrVec::String(s) => quote! { Some(#s) }, StringOrVec::Vec(v) => { let s = &v[0]; quote! { Some(#s) } } - } - }).unwrap_or(quote! { None }); + }) + .unwrap_or(quote! { None }); quote! { LootCondition::EntityProperties { entity: #e, expected_type: #expected_type } } } Self::KilledByPlayer => quote! { LootCondition::KilledByPlayer }, @@ -516,7 +516,10 @@ impl ToTokens for LootConditionStruct { quote! { LootCondition::MatchTool { items: None } } } } - Self::TableBonus { enchantment, chances } => { + Self::TableBonus { + enchantment, + chances, + } => { let e = LitStr::new(enchantment, Span::call_site()); quote! { LootCondition::TableBonus { enchantment: #e, chances: &[#(#chances),*] } } } @@ -559,20 +562,29 @@ impl ToTokens for LootConditionStruct { let ox = offset_x.unwrap_or(0); let oy = offset_y.unwrap_or(0); let oz = offset_z.unwrap_or(0); - let expected_biome = predicate.as_ref().and_then(|p| p.biome.as_ref()).map(|b| { - match b { + let expected_biome = predicate + .as_ref() + .and_then(|p| p.biome.as_ref()) + .map(|b| match b { StringOrVec::String(s) => quote! { Some(#s) }, StringOrVec::Vec(v) => { let s = &v[0]; quote! { Some(#s) } } - } - }).unwrap_or(quote! { None }); + }) + .unwrap_or(quote! { None }); quote! { LootCondition::LocationCheck { offset_x: #ox, offset_y: #oy, offset_z: #oz, expected_biome: #expected_biome } } } - Self::WeatherCheck { raining, thundering } => { - let r = raining.map(|b| quote! { Some(#b) }).unwrap_or(quote! { None }); - let t = thundering.map(|b| quote! { Some(#b) }).unwrap_or(quote! { None }); + Self::WeatherCheck { + raining, + thundering, + } => { + let r = raining + .map(|b| quote! { Some(#b) }) + .unwrap_or(quote! { None }); + let t = thundering + .map(|b| quote! { Some(#b) }) + .unwrap_or(quote! { None }); quote! { LootCondition::WeatherCheck { raining: #r, thundering: #t } } } Self::Reference { name } => { @@ -581,7 +593,9 @@ impl ToTokens for LootConditionStruct { } Self::TimeCheck { range, period } => { let r = range.to_token_stream(); - let p = period.map(|val| quote! { Some(#val) }).unwrap_or(quote! { None }); + let p = period + .map(|val| quote! { Some(#val) }) + .unwrap_or(quote! { None }); quote! { LootCondition::TimeCheck { range: #r, period: #p } } } Self::ValueCheck { value, range } => { @@ -824,8 +838,14 @@ pub struct LootFunctionLimitCountStruct { impl ToTokens for LootFunctionLimitCountStruct { fn to_tokens(&self, tokens: &mut TokenStream) { - let min = self.min.map(|val| quote! { Some(#val) }).unwrap_or(quote! { None }); - let max = self.max.map(|val| quote! { Some(#val) }).unwrap_or(quote! { None }); + let min = self + .min + .map(|val| quote! { Some(#val) }) + .unwrap_or(quote! { None }); + let max = self + .max + .map(|val| quote! { Some(#val) }) + .unwrap_or(quote! { None }); tokens.extend(quote! { (#min, #max) }); } } @@ -918,7 +938,6 @@ impl ToTokens for LootPoolEntryStruct { } } - /// Deserialized loot table category, tagged by its `"type"` field. #[derive(Deserialize, Clone, Debug)] #[serde(rename = "snake_case")] diff --git a/pumpkin-codegen/src/meta_data_type.rs b/pumpkin-codegen/src/meta_data_type.rs index f3f40eeb5..be4fb2dbb 100644 --- a/pumpkin-codegen/src/meta_data_type.rs +++ b/pumpkin-codegen/src/meta_data_type.rs @@ -15,7 +15,10 @@ pub fn build() -> TokenStream { (JavaMinecraftVersion::V_1_21_6, "1_21_6_meta_data_type.json"), (JavaMinecraftVersion::V_1_21_7, "1_21_7_meta_data_type.json"), (JavaMinecraftVersion::V_1_21_9, "1_21_9_meta_data_type.json"), - (JavaMinecraftVersion::V_1_21_11, "1_21_11_meta_data_type.json"), + ( + JavaMinecraftVersion::V_1_21_11, + "1_21_11_meta_data_type.json", + ), (JavaMinecraftVersion::V_26_1, "26_1_meta_data_type.json"), ]; diff --git a/pumpkin-codegen/src/registry.rs b/pumpkin-codegen/src/registry.rs index f259bda01..2bdb1a4ba 100644 --- a/pumpkin-codegen/src/registry.rs +++ b/pumpkin-codegen/src/registry.rs @@ -13,14 +13,35 @@ const LATEST_VERSION: JavaMinecraftVersion = JavaMinecraftVersion::V_26_1; /// static registry data, and the `Registry::get_synced` method. pub(crate) fn build() -> TokenStream { let assets = [ - (JavaMinecraftVersion::V_1_20_5, "1_21_synced_registries.json"), + ( + JavaMinecraftVersion::V_1_20_5, + "1_21_synced_registries.json", + ), (JavaMinecraftVersion::V_1_21, "1_21_synced_registries.json"), - (JavaMinecraftVersion::V_1_21_2, "1_21_2_synced_registries.json"), - (JavaMinecraftVersion::V_1_21_4, "1_21_4_synced_registries.json"), - (JavaMinecraftVersion::V_1_21_5, "1_21_5_synced_registries.json"), - (JavaMinecraftVersion::V_1_21_6, "1_21_6_synced_registries.json"), - (JavaMinecraftVersion::V_1_21_7, "1_21_7_synced_registries.json"), - (JavaMinecraftVersion::V_1_21_9, "1_21_9_synced_registries.json"), + ( + JavaMinecraftVersion::V_1_21_2, + "1_21_2_synced_registries.json", + ), + ( + JavaMinecraftVersion::V_1_21_4, + "1_21_4_synced_registries.json", + ), + ( + JavaMinecraftVersion::V_1_21_5, + "1_21_5_synced_registries.json", + ), + ( + JavaMinecraftVersion::V_1_21_6, + "1_21_6_synced_registries.json", + ), + ( + JavaMinecraftVersion::V_1_21_7, + "1_21_7_synced_registries.json", + ), + ( + JavaMinecraftVersion::V_1_21_9, + "1_21_9_synced_registries.json", + ), ( JavaMinecraftVersion::V_1_21_11, "1_21_11_synced_registries.json", diff --git a/pumpkin-codegen/src/wit/biome.rs b/pumpkin-codegen/src/wit/biome.rs index 77ec2e96b..684b85ad5 100644 --- a/pumpkin-codegen/src/wit/biome.rs +++ b/pumpkin-codegen/src/wit/biome.rs @@ -27,10 +27,7 @@ pub fn build() -> String { biome_enum.case(name); } - interface.type_def(TypeDef::new( - "biome", - TypeDefKind::Enum(biome_enum), - )); + interface.type_def(TypeDef::new("biome", TypeDefKind::Enum(biome_enum))); package.interface(interface); package.to_string() diff --git a/pumpkin-codegen/src/wit/data_component.rs b/pumpkin-codegen/src/wit/data_component.rs index b7ad3e59a..69a684156 100644 --- a/pumpkin-codegen/src/wit/data_component.rs +++ b/pumpkin-codegen/src/wit/data_component.rs @@ -23,8 +23,7 @@ pub fn build() -> String { let name = raw_name .strip_prefix("minecraft:") .unwrap_or(raw_name) - .replace('_', "-") - .replace('/', "-"); + .replace(['_', '/'], "-"); component_enum.case(name); } diff --git a/pumpkin-codegen/src/wit/java_packet.rs b/pumpkin-codegen/src/wit/java_packet.rs index dc4dba89d..13812ac9c 100644 --- a/pumpkin-codegen/src/wit/java_packet.rs +++ b/pumpkin-codegen/src/wit/java_packet.rs @@ -88,7 +88,9 @@ fn parse_packet_file(path: &Path, interface: &mut Interface, variant: &mut Varia syn::Type::Path(p) => p.path.segments.last().unwrap().ident.to_string(), syn::Type::Reference(r) => match &*r.elem { syn::Type::Slice(s) => match &*s.elem { - syn::Type::Path(p) => p.path.segments.last().unwrap().ident.to_string(), + syn::Type::Path(p) => { + p.path.segments.last().unwrap().ident.to_string() + } _ => String::new(), }, syn::Type::Path(p) => p.path.segments.last().unwrap().ident.to_string(), diff --git a/pumpkin-codegen/src/wit/packet_mapping.rs b/pumpkin-codegen/src/wit/packet_mapping.rs index 61e542ba6..aa339f8f5 100644 --- a/pumpkin-codegen/src/wit/packet_mapping.rs +++ b/pumpkin-codegen/src/wit/packet_mapping.rs @@ -235,7 +235,11 @@ fn parse_packet_file( fn get_type_info(ty: &syn::Type) -> (String, bool, bool) { match ty { - syn::Type::Path(tp) => (tp.path.segments.last().unwrap().ident.to_string(), false, false), + syn::Type::Path(tp) => ( + tp.path.segments.last().unwrap().ident.to_string(), + false, + false, + ), syn::Type::Reference(tr) => { let (name, _, is_slice) = get_type_info(&tr.elem); (name, true, is_slice) diff --git a/pumpkin-codegen/src/wit/utils.rs b/pumpkin-codegen/src/wit/utils.rs index 0ab128638..408093809 100644 --- a/pumpkin-codegen/src/wit/utils.rs +++ b/pumpkin-codegen/src/wit/utils.rs @@ -17,16 +17,15 @@ pub fn map_type(ty: &Type) -> WitType { "u8" | "i8" => WitType::U8, "u16" | "i16" => WitType::S32, "Option" => { - if let syn::PathArguments::AngleBracketed(args) = &last_segment.arguments { - if let Some(syn::GenericArgument::Type(inner_ty)) = args.args.first() { + if let syn::PathArguments::AngleBracketed(args) = &last_segment.arguments + && let Some(syn::GenericArgument::Type(inner_ty)) = args.args.first() { return WitType::option(map_type(inner_ty)); } - } WitType::String } "Vec" | "Box" => { - if let syn::PathArguments::AngleBracketed(args) = &last_segment.arguments { - if let Some(syn::GenericArgument::Type(inner_ty)) = args.args.first() { + if let syn::PathArguments::AngleBracketed(args) = &last_segment.arguments + && let Some(syn::GenericArgument::Type(inner_ty)) = args.args.first() { // Check if the inner type is u8 if let Type::Path(tp) = inner_ty && tp.path.segments.last().unwrap().ident == "u8" @@ -35,7 +34,6 @@ pub fn map_type(ty: &Type) -> WitType { } return WitType::list(map_type(inner_ty)); } - } WitType::String } "Vector3" | "BlockPos" => { diff --git a/pumpkin-nbt/benches/nbt.rs b/pumpkin-nbt/benches/nbt.rs index 73e71b3e3..301498f24 100644 --- a/pumpkin-nbt/benches/nbt.rs +++ b/pumpkin-nbt/benches/nbt.rs @@ -47,7 +47,7 @@ fn create_large_compound(depth: usize) -> NbtCompound { compound.put_string("string", "Hello test benchmark data".to_string()); compound.put( "byte_array", - NbtTag::ByteArray(vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9]), + NbtTag::ByteArray(vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9].into()), ); compound.put( "int_array", diff --git a/pumpkin-nbt/src/nbt_ops.rs b/pumpkin-nbt/src/nbt_ops.rs index 2acadd039..fe25e2196 100644 --- a/pumpkin-nbt/src/nbt_ops.rs +++ b/pumpkin-nbt/src/nbt_ops.rs @@ -166,14 +166,14 @@ impl DynamicOps for NbtOps { fn get_byte_list(&self, input: Self::Value) -> DataResult> { if let NbtTag::ByteArray(b) = input { - DataResult::new_success(b) + DataResult::new_success(b.into()) } else { impl_get_list!(self, input, "bytes") } } fn create_byte_list(&self, buffer: Vec) -> Self::Value { - NbtTag::ByteArray(buffer) + NbtTag::ByteArray(buffer.into()) } fn get_int_list(&self, input: Self::Value) -> DataResult> { @@ -301,7 +301,7 @@ impl DynamicOps for NbtOps { NbtTag::Long(l) => out_ops.create_long(l), NbtTag::Float(f) => out_ops.create_float(f), NbtTag::Double(d) => out_ops.create_double(d), - NbtTag::ByteArray(b) => out_ops.create_byte_list(b), + NbtTag::ByteArray(b) => out_ops.create_byte_list(b.to_vec()), NbtTag::String(s) => out_ops.create_string(&s), NbtTag::List(_) => self.convert_list(out_ops, input), NbtTag::Compound(_) => self.convert_map(out_ops, input), @@ -477,7 +477,9 @@ impl ListCollector { // From this point onwards, we know that the list is not empty. match tag { NbtTag::List(list) => Some(Self::Generic(InnerGenericListCollector::new(list))), - NbtTag::ByteArray(list) => Some(Self::Byte(InnerByteListCollector::new(list))), + NbtTag::ByteArray(list) => { + Some(Self::Byte(InnerByteListCollector::new(list.into()))) + } NbtTag::IntArray(list) => Some(Self::Int(InnerIntListCollector::new(list))), NbtTag::LongArray(list) => Some(Self::Long(InnerLongListCollector::new(list))), @@ -592,7 +594,7 @@ impl InnerListCollector for InnerByteListCollector { } fn result(self) -> NbtTag { - NbtTag::ByteArray(self.list) + NbtTag::ByteArray(self.list.into()) } } @@ -669,13 +671,13 @@ mod test { ); // Byte list collector - let tag = NbtTag::ByteArray(vec![-1, 45, 100]); + let tag = NbtTag::ByteArray(vec![-1, 45, 100].into()); assert_eq!( ListCollector::new(tag) .expect("List collector should exist") .result(), - NbtTag::ByteArray(vec![-1, 45, 100]) + NbtTag::ByteArray(vec![-1, 45, 100].into()) ); // Long list diff --git a/pumpkin-nbt/src/tag.rs b/pumpkin-nbt/src/tag.rs index cd937efae..cf34900ac 100644 --- a/pumpkin-nbt/src/tag.rs +++ b/pumpkin-nbt/src/tag.rs @@ -19,7 +19,7 @@ pub enum NbtTag { Long(i64) = LONG_ID, Float(f32) = FLOAT_ID, Double(f64) = DOUBLE_ID, - ByteArray(Vec) = BYTE_ARRAY_ID, + ByteArray(Box<[i8]>) = BYTE_ARRAY_ID, String(Box) = STRING_ID, List(Vec) = LIST_ID, Compound(NbtCompound) = COMPOUND_ID, @@ -281,7 +281,7 @@ impl NbtTag { let byte = reader.get_i8()?; byte_array.push(byte); } - Ok(Self::ByteArray(byte_array)) + Ok(Self::ByteArray(byte_array.into())) } STRING_ID => Ok(Self::String(reader.get_string()?.into())), LIST_ID => { @@ -457,7 +457,7 @@ impl From<&str> for NbtTag { impl From<&[i8]> for NbtTag { fn from(value: &[i8]) -> Self { - Self::ByteArray(value.to_vec()) + Self::ByteArray(value.into()) } } @@ -575,7 +575,7 @@ impl<'de> Deserialize<'de> for NbtTag { while let Some(value) = seq.next_element()? { vec.push(value); } - Ok(NbtTag::ByteArray(vec)) + Ok(NbtTag::ByteArray(vec.into())) } _ => { let mut vec = Vec::new(); diff --git a/pumpkin-protocol/src/bedrock/packet_decoder.rs b/pumpkin-protocol/src/bedrock/packet_decoder.rs index 495623e47..c217f6967 100644 --- a/pumpkin-protocol/src/bedrock/packet_decoder.rs +++ b/pumpkin-protocol/src/bedrock/packet_decoder.rs @@ -87,7 +87,7 @@ impl UDPNetworkDecoder { pub async fn get_packet_payload( &mut self, - mut full_packet: Vec, + full_packet: Vec, ) -> Result, PacketDecodeError> { if full_packet.is_empty() { return Err(PacketDecodeError::MalformedLength("Empty packet".into())); @@ -104,7 +104,7 @@ impl UDPNetworkDecoder { // If compression is NOT enabled yet, the payload starts at index 1. if self.compression.is_none() { - return Ok(full_packet.split_off(1)); + return Ok(full_packet[1..].to_vec()); } // If compression IS enabled, Bedrock expects a compression method byte at index 1. @@ -125,7 +125,7 @@ impl UDPNetworkDecoder { } 0xff => { // None (Compression enabled but this specific packet is raw) - Ok(full_packet.split_off(2)) + Ok(full_packet[data_start..].to_vec()) } _ => Err(PacketDecodeError::FailedDecompression(format!( "Unsupported compression method: 0x{compression_method:02x}" diff --git a/pumpkin-protocol/src/java/client/play/set_player_team.rs b/pumpkin-protocol/src/java/client/play/set_player_team.rs index c8e742a08..44f0ac41a 100644 --- a/pumpkin-protocol/src/java/client/play/set_player_team.rs +++ b/pumpkin-protocol/src/java/client/play/set_player_team.rs @@ -35,7 +35,7 @@ pub struct CSetPlayerTeam<'a> { pub team_name: String, pub method: TeamMethod, pub parameters: Option>, - pub players: Vec, + pub players: Box<[String]>, } impl ClientPacket for CSetPlayerTeam<'_> { diff --git a/pumpkin-world/src/generation/carver/cave.rs b/pumpkin-world/src/generation/carver/cave.rs index 542040499..a0dd873e4 100644 --- a/pumpkin-world/src/generation/carver/cave.rs +++ b/pumpkin-world/src/generation/carver/cave.rs @@ -1,8 +1,8 @@ use super::Carver; use crate::ProtoChunk; -use pumpkin_data::block_state::BlockState; use pumpkin_data::carver::{CarverAdditionalConfig, CarverConfig, HeightProvider}; use pumpkin_util::math::vector2::Vector2; +use pumpkin_util::math::vector3::Vector3; use pumpkin_util::random::{RandomGenerator, RandomImpl}; use std::f32::consts::PI; @@ -352,8 +352,8 @@ impl CaveCarver { has_grass: &mut bool, ) -> bool { let local_y = y - chunk.bottom_y() as i32; - let state_id = chunk.get_block_state_raw(x & 15, local_y, z & 15); - let block = pumpkin_data::Block::from_state_id(state_id); + let state = chunk.get_block_state(&Vector3::new(x, y, z)); + let block = state.to_block(); if block.id == pumpkin_data::Block::GRASS_BLOCK.id || block.id == pumpkin_data::Block::MYCELIUM.id @@ -361,12 +361,11 @@ impl CaveCarver { *has_grass = true; } - // Only carve if it's replaceable - if config.replaceable.1.contains(&block.id) { - // Replace with air or lava - let air = BlockState::from_id(pumpkin_data::Block::AIR.default_state.id); - let lava = BlockState::from_id(pumpkin_data::Block::LAVA.default_state.id); + if !config.replaceable.1.contains(&block.id) { + return false; + } + let carve_state = { let lava_y = if is_nether { chunk.bottom_y() as i32 + 31 } else { @@ -376,26 +375,44 @@ impl CaveCarver { }; if y <= lava_y { - chunk.set_block_state(x & 15, local_y, z & 15, lava); + Some(pumpkin_data::Block::LAVA.default_state) } else { - chunk.set_block_state(x & 15, local_y, z & 15, air); + // TODO: Aquifer logic goes here. + // BlockState state = aquifer.computeSubstance(...) + // return state (or debug barrier if null) + if block.id == pumpkin_data::Block::WATER.id + || block.id == pumpkin_data::Block::LAVA.id + { + None + } else { + Some(pumpkin_data::Block::AIR.default_state) + } } + }; - // TODO: fix this + if let Some(state) = carve_state { + chunk.set_block_state(x, local_y, z, state); + + // TODO: Fluid scheduling + // if aquifer.should_schedule_fluid_update() && !state.fluid_state().is_empty() { + // chunk.mark_pos_for_postprocessing(x, y, z); + // } + + // TODO: fix this (grass block survival logic) // if *has_grass { - // let below_state_id = chunk.get_block_state_raw(x & 15, local_y - 1, z & 15); + // let below_state_id = chunk.get_block_state_raw(x, local_y - 1, z); // let below_block = pumpkin_data::Block::from_state_id(below_state_id); // if below_block.id == pumpkin_data::Block::DIRT.id { - // // TODO: Java uses Biome top material here, defaulting to Grass for now // let top_material = - // BlockState::from_id(pumpkin_data::Block::GRASS_BLOCK.default_state.id); - // chunk.set_block_state(x & 15, local_y - 1, z & 15, top_material); + // pumpkin_data::Block::GRASS_BLOCK.default_state; + // chunk.set_block_state(x, local_y - 1, z, top_material); // } // } return true; } + false } } diff --git a/pumpkin-world/src/generation/carver/mod.rs b/pumpkin-world/src/generation/carver/mod.rs index fd1773278..3e93012ea 100644 --- a/pumpkin-world/src/generation/carver/mod.rs +++ b/pumpkin-world/src/generation/carver/mod.rs @@ -39,7 +39,7 @@ pub fn carve(chunk: &mut ProtoChunk, generator: &VanillaGenerator) { &[] }; - let cave_carver = cave::CaveCarver; + let _cave_carver = cave::CaveCarver; let canyon_carver = canyon::CanyonCarver; for dx in -radius..=radius { @@ -69,14 +69,14 @@ pub fn carve(chunk: &mut ProtoChunk, generator: &VanillaGenerator) { if should_carve(config, &mut carver_random) { match config.additional { CarverAdditionalConfig::Cave(_) | CarverAdditionalConfig::NetherCave(_) => { - cave_carver.carve( - config, - chunk, - &mut carver_random, - &chunk_pos, - &carver_chunk_pos, - generator.settings.legacy_random_source, - ); + // cave_carver.carve( + // config, + // chunk, + // &mut carver_random, + // &chunk_pos, + // &carver_chunk_pos, + // generator.settings.legacy_random_source, + // ); } CarverAdditionalConfig::Canyon(_) => { canyon_carver.carve( diff --git a/pumpkin/src/block/blocks/command.rs b/pumpkin/src/block/blocks/command.rs index ac7a8d89d..8ec08038e 100644 --- a/pumpkin/src/block/blocks/command.rs +++ b/pumpkin/src/block/blocks/command.rs @@ -61,7 +61,11 @@ impl CommandBlock { warn!("Command block has no matching entity"); return false; }; - let command_entity: &CommandBlockEntity = before_entity.as_any().downcast_ref().unwrap(); + let Some(command_entity) = before_entity.as_any().downcast_ref::() + else { + warn!("Block entity at {} is not a command block", before.0); + return false; + }; command_entity.success_count.load(Ordering::Relaxed) > 0 } @@ -122,7 +126,10 @@ impl CommandBlock { return; } - let command_entity: Arc = Arc::downcast(block_entity).unwrap(); + let Ok(command_entity) = Arc::downcast::(block_entity) else { + warn!("Failed to downcast block entity to CommandBlockEntity"); + return; + }; if command.is_empty() { command_entity.success_count.store(0, Ordering::Release); @@ -164,7 +171,11 @@ impl CommandBlock { break; }; - let command_entity: &CommandBlockEntity = block_entity.as_any().downcast_ref().unwrap(); + let Some(command_entity) = block_entity.as_any().downcast_ref::() + else { + warn!("Block entity at {} is not a command block", pos); + break; + }; let powered = command_entity.powered.load(Ordering::Relaxed); let auto = command_entity.auto.load(Ordering::Relaxed); let state_id = world.get_block_state_id(&pos); @@ -174,7 +185,10 @@ impl CommandBlock { let conditions_met = Self::conditions_met(&world, &pos, direction); if conditions_met { let command = command_entity.command.lock().await; - let entity = world.get_block_entity(&pos).unwrap(); + let Some(entity) = world.get_block_entity(&pos) else { + warn!("Command block entity disappeared during execution"); + break; + }; Self::execute(server, world.clone(), entity, &command).await; } else if props.conditional { command_entity.success_count.store(0, Ordering::Release); @@ -238,10 +252,12 @@ impl BlockBehaviour for CommandBlock { if block_entity.resource_location() != CommandBlockEntity::ID { return; } - let command_entity = block_entity - .as_any() - .downcast_ref::() - .unwrap(); + let Some(command_entity) = + block_entity.as_any().downcast_ref::() + else { + warn!("Block entity at {} is not a command block", args.position); + return; + }; Self::update( args.world, @@ -268,7 +284,11 @@ impl BlockBehaviour for CommandBlock { return; } - let command_entity: &CommandBlockEntity = block_entity.as_any().downcast_ref().unwrap(); + let Some(command_entity) = block_entity.as_any().downcast_ref::() + else { + warn!("Block entity at {} is not a command block", args.position); + return; + }; let Some(server) = args.world.server.upgrade() else { return; }; diff --git a/pumpkin/src/block/blocks/fire/mod.rs b/pumpkin/src/block/blocks/fire/mod.rs index 14860fc22..cf5399b56 100644 --- a/pumpkin/src/block/blocks/fire/mod.rs +++ b/pumpkin/src/block/blocks/fire/mod.rs @@ -109,7 +109,13 @@ impl FireBlockBase { Xoroshiro::from_seed(rand::rng().random()), )) }; - NetherPortal::get_new_portal(world, block_pos, dir.to_horizontal_axis().unwrap()).is_some() + NetherPortal::get_new_portal( + world, + block_pos, + dir.to_horizontal_axis() + .expect("Direction should be horizontal"), + ) + .is_some() } /// Shared fire collision behavior used by `fire` and `soul_fire`. diff --git a/pumpkin/src/block/blocks/ladder.rs b/pumpkin/src/block/blocks/ladder.rs index 0a390bbfa..0c68ab6e3 100644 --- a/pumpkin/src/block/blocks/ladder.rs +++ b/pumpkin/src/block/blocks/ladder.rs @@ -26,8 +26,10 @@ impl BlockBehaviour for LadderBlock { let props = LadderLikeProperties::from_state_id(clicked_block_state_id, clicked_block); let sub = args.position.0.sub(&clicked_pos.0); - let dir = horizontal_facing_from_offset(sub).unwrap(); - if props.facing == dir.to_horizontal_facing().unwrap() { + if let Some(dir) = horizontal_facing_from_offset(sub) + && let Some(horizontal_facing) = dir.to_horizontal_facing() + && props.facing == horizontal_facing + { return Block::AIR.default_state.id; } } @@ -45,7 +47,7 @@ impl BlockBehaviour for LadderBlock { .opposite() .to_block_direction() .to_horizontal_facing() - .unwrap(); + .expect("Opposite of horizontal direction should be horizontal"); return props.to_state_id(args.block); } Block::AIR.default_state.id diff --git a/pumpkin/src/block/blocks/lanterns.rs b/pumpkin/src/block/blocks/lanterns.rs index 81e7b3739..7f1b21938 100644 --- a/pumpkin/src/block/blocks/lanterns.rs +++ b/pumpkin/src/block/blocks/lanterns.rs @@ -48,7 +48,8 @@ impl BlockBehaviour for LanternBlock { } fn can_place_at(&self, args: CanPlaceAtArgs<'_>) -> bool { - can_place_at(args.world.unwrap(), args.position) + args.world + .is_some_and(|world| can_place_at(world, args.position)) } fn get_state_for_neighbor_update<'a>( diff --git a/pumpkin/src/block/blocks/piston/piston.rs b/pumpkin/src/block/blocks/piston/piston.rs index 1605d82a2..f06e5b21a 100644 --- a/pumpkin/src/block/blocks/piston/piston.rs +++ b/pumpkin/src/block/blocks/piston/piston.rs @@ -216,7 +216,7 @@ impl BlockBehaviour for PistonBlock { let mut props = PistonProps::default(block); props.facing = BlockDirection::by_index((data & 7) as usize) - .unwrap() + .expect("Invalid block direction index") .to_facing(); world.add_block_entity(Arc::new(PistonBlockEntity { @@ -343,7 +343,10 @@ pub async fn try_move(world: &Arc, block: &Block, block_pos: &BlockPos) { if new_props.facing == props.facing && let Some(entity) = world.get_block_entity(&new_pos) { - let piston = entity.as_any().downcast_ref::().unwrap(); + let piston = entity + .as_any() + .downcast_ref::() + .expect("Block entity at MOVING_PISTON should be PistonBlockEntity"); if piston.extending && piston.current_progress.load() < 0.5 // TODO: more stuff... { diff --git a/pumpkin/src/block/blocks/redstone/pressure_plate/plate.rs b/pumpkin/src/block/blocks/redstone/pressure_plate/plate.rs index ee2490659..2c13979b2 100644 --- a/pumpkin/src/block/blocks/redstone/pressure_plate/plate.rs +++ b/pumpkin/src/block/blocks/redstone/pressure_plate/plate.rs @@ -87,7 +87,8 @@ impl BlockBehaviour for PressurePlateBlock { } fn can_place_at(&self, args: CanPlaceAtArgs<'_>) -> bool { - Self::can_pressure_plate_place_at(args.world.unwrap(), args.position) + args.world + .is_some_and(|world| Self::can_pressure_plate_place_at(world, args.position)) } } diff --git a/pumpkin/src/block/blocks/redstone/pressure_plate/weighted.rs b/pumpkin/src/block/blocks/redstone/pressure_plate/weighted.rs index 8074af326..54ecf24ff 100644 --- a/pumpkin/src/block/blocks/redstone/pressure_plate/weighted.rs +++ b/pumpkin/src/block/blocks/redstone/pressure_plate/weighted.rs @@ -86,7 +86,8 @@ impl BlockBehaviour for WeightedPressurePlateBlock { } fn can_place_at(&self, args: CanPlaceAtArgs<'_>) -> bool { - Self::can_pressure_plate_place_at(args.world.unwrap(), args.position) + args.world + .is_some_and(|world| Self::can_pressure_plate_place_at(world, args.position)) } } diff --git a/pumpkin/src/block/entities/brewing_stand.rs b/pumpkin/src/block/entities/brewing_stand.rs index 8d8d4dc70..e59d836d0 100644 --- a/pumpkin/src/block/entities/brewing_stand.rs +++ b/pumpkin/src/block/entities/brewing_stand.rs @@ -53,7 +53,7 @@ impl BrewingStandBlockEntity { fn ingredient_matches(&self, ingredient: &ItemStack) -> bool { self.ingredient_item .lock() - .unwrap() + .expect("Ingredient item mutex should not be poisoned") .is_some_and(|stored| !ingredient.is_empty() && ingredient.get_item().id == stored.id) } @@ -350,7 +350,10 @@ impl crate::block::entities::BlockEntity for BrewingStandBlockEntity { if let Ok(guard) = entity.items[3].try_lock() && !guard.is_empty() { - *entity.ingredient_item.lock().unwrap() = Some(guard.get_item()); + *entity + .ingredient_item + .lock() + .expect("Ingredient item mutex should not be poisoned") = Some(guard.get_item()); } // Recompute last_potion_count so visuals are correct after load @@ -362,7 +365,10 @@ impl crate::block::entities::BlockEntity for BrewingStandBlockEntity { || slot.get_item().id == pumpkin_data::item::Item::GLASS_BOTTLE.id); } } - *entity.last_potion_count.lock().unwrap() = Some(current); + *entity + .last_potion_count + .lock() + .expect("Last potion count mutex should not be poisoned") = Some(current); entity } @@ -455,7 +461,11 @@ impl crate::block::entities::BlockEntity for BrewingStandBlockEntity { // Start new brewing cycle self.fuel.fetch_sub(1, Ordering::Relaxed); self.brew_time.store(400, Ordering::Relaxed); - *self.ingredient_item.lock().unwrap() = Some(ingredient.get_item()); + *self + .ingredient_item + .lock() + .expect("Ingredient item mutex should not be poisoned") = + Some(ingredient.get_item()); self.mark_dirty(); } else if fuel_refilled { // Mark dirty if fuel was refilled to update fuel indicator @@ -474,8 +484,11 @@ impl crate::block::entities::BlockEntity for BrewingStandBlockEntity { // If potion presence changed, update last_potion_count and update block state so clients let mut needs_update = false; { - let mut last_guard = self.last_potion_count.lock().unwrap(); - if last_guard.is_none() || last_guard.as_ref().unwrap() != ¤t { + let mut last_guard = self + .last_potion_count + .lock() + .expect("Last potion count mutex should not be poisoned"); + if last_guard.as_ref() != Some(¤t) { *last_guard = Some(current); needs_update = true; } diff --git a/pumpkin/src/block/entities/chest_like_block_entity.rs b/pumpkin/src/block/entities/chest_like_block_entity.rs index 0cbd2b0f6..ece7161bf 100644 --- a/pumpkin/src/block/entities/chest_like_block_entity.rs +++ b/pumpkin/src/block/entities/chest_like_block_entity.rs @@ -34,7 +34,7 @@ macro_rules! impl_block_entity_for_chest { }; // Only read saved items when there is no pending loot table. - if chest.loot_table.lock().unwrap().is_none() { + if chest.loot_table.lock().expect("Loot table mutex should not be poisoned").is_none() { chest.read_data(nbt, &chest.items); } @@ -50,7 +50,7 @@ macro_rules! impl_block_entity_for_chest { Box::pin(async move { // Clone the loot table key without holding the lock across an await. let loot_table_key = { - let guard = self.loot_table.lock().unwrap(); + let guard = self.loot_table.lock().expect("Loot table mutex should not be poisoned"); guard.clone() }; @@ -100,12 +100,12 @@ macro_rules! impl_block_entity_for_chest { } fn take_loot_table(&self) -> Option<(String, i64)> { - let mut guard = self.loot_table.lock().unwrap(); + let mut guard = self.loot_table.lock().expect("Loot table mutex should not be poisoned"); guard.take().map(|key| (key, self.loot_table_seed)) } fn has_loot_table(&self) -> bool { - self.loot_table.lock().unwrap().is_some() + self.loot_table.lock().expect("Loot table mutex should not be poisoned").is_some() } } }; diff --git a/pumpkin/src/block/entities/furnace_like_block_entity.rs b/pumpkin/src/block/entities/furnace_like_block_entity.rs index c7b0eaf5d..f55f5a52a 100644 --- a/pumpkin/src/block/entities/furnace_like_block_entity.rs +++ b/pumpkin/src/block/entities/furnace_like_block_entity.rs @@ -135,7 +135,11 @@ macro_rules! impl_cooking_block_entity_base { } if let Some(recipe_output_item) = pumpkin_data::item::Item::from_registry_key( - recipe.result.id.strip_prefix("minecraft:").unwrap(), + recipe + .result + .id + .strip_prefix("minecraft:") + .expect("Recipe ID should have minecraft: prefix"), ) && !is_top_items_empty && recipe_output_item.id == side_item_stack.item.id && side_item_stack.item_count < max_count @@ -156,7 +160,11 @@ macro_rules! impl_cooking_block_entity_base { if can_accept_output { let mut side_items = self.items[2].lock().await; let Some(output_item) = pumpkin_data::item::Item::from_registry_key( - recipe.result.id.strip_prefix("minecraft:").unwrap(), + recipe + .result + .id + .strip_prefix("minecraft:") + .expect("Recipe ID should have minecraft: prefix"), ) else { return false; }; diff --git a/pumpkin/src/block/entities/mod.rs b/pumpkin/src/block/entities/mod.rs index 1df541cfb..f78c50282 100644 --- a/pumpkin/src/block/entities/mod.rs +++ b/pumpkin/src/block/entities/mod.rs @@ -86,9 +86,14 @@ pub trait BlockEntity: Any + Send + Sync { pumpkin_data::block_properties::BLOCK_ENTITY_TYPES .iter() .position(|block_entity_name| { - *block_entity_name == self.resource_location().split(':').next_back().unwrap() + *block_entity_name + == self + .resource_location() + .split(':') + .next_back() + .expect("Resource location should have a name") }) - .unwrap() as u32 + .expect("Block entity type should be registered") as u32 } /// Obtain NBT data for sending to the client in [`ChunkData`](crate::chunk::ChunkData) @@ -135,9 +140,9 @@ pub trait BlockEntity: Any + Send + Sync { #[must_use] pub fn block_entity_from_generic(nbt: &NbtCompound) -> T { - let x = nbt.get_int("x").unwrap(); - let y = nbt.get_int("y").unwrap(); - let z = nbt.get_int("z").unwrap(); + let x = nbt.get_int("x").expect("NBT should have x coordinate"); + let y = nbt.get_int("y").expect("NBT should have y coordinate"); + let z = nbt.get_int("z").expect("NBT should have z coordinate"); T::from_nbt(nbt, BlockPos::new(x, y, z)) } diff --git a/pumpkin/src/block/entities/sign.rs b/pumpkin/src/block/entities/sign.rs index c9a6a3569..f4c3c2722 100644 --- a/pumpkin/src/block/entities/sign.rs +++ b/pumpkin/src/block/entities/sign.rs @@ -158,7 +158,7 @@ impl From for NbtTag { value .messages .lock() - .unwrap() + .expect("Text messages mutex should not be poisoned") .iter() .map(|s| Self::String(s.clone())) .collect(), @@ -172,7 +172,7 @@ impl From for Text { fn from(tag: NbtTag) -> Self { let nbt = tag.extract_compound().unwrap(); let has_glowing_text = nbt.get_bool("has_glowing_text").unwrap_or(false); - let color = nbt.get_string("color").unwrap(); + let color = nbt.get_string("color").unwrap_or("black"); let messages: Vec> = nbt .get_list("messages") .unwrap() @@ -226,8 +226,16 @@ impl BlockEntity for SignBlockEntity { where Self: Sized, { - let front_text = Text::from(nbt.get("front_text").unwrap().clone()); - let back_text = Text::from(nbt.get("back_text").unwrap().clone()); + let front_text = nbt + .get("front_text") + .cloned() + .map(Text::from) + .unwrap_or_default(); + let back_text = nbt + .get("back_text") + .cloned() + .map(Text::from) + .unwrap_or_default(); let is_waxed = nbt.get_bool("is_waxed").unwrap_or(false); Self { position, diff --git a/pumpkin/src/command/args/entities.rs b/pumpkin/src/command/args/entities.rs index f41c06d40..1e59235a4 100644 --- a/pumpkin/src/command/args/entities.rs +++ b/pumpkin/src/command/args/entities.rs @@ -471,7 +471,7 @@ mod test { let Err(error) = parse_target_selector_with_context(raw_arg) else { panic!("expected selector parsing to fail"); }; - let cursor = error.context.unwrap().cursor; + let cursor = error.context.expect("Error should have context").cursor; assert_eq!(cursor, 7); } @@ -484,7 +484,9 @@ mod test { end: input.len(), input, }; - let selector = "@e".parse::().unwrap(); + let selector = "@e" + .parse::() + .expect("Selector should be valid"); let error = ensure_player_only_selector(&selector, raw_arg).unwrap_err(); let translate_key = match error.message.0.content.as_ref() { @@ -492,6 +494,6 @@ mod test { _ => "", }; assert_eq!(translate_key, translation::java::ARGUMENT_PLAYER_ENTITIES); - assert_eq!(error.context.unwrap().cursor, 4); + assert_eq!(error.context.expect("Error should have context").cursor, 4); } } diff --git a/pumpkin/src/command/args/gameprofile.rs b/pumpkin/src/command/args/gameprofile.rs index f17391a4e..02649027a 100644 --- a/pumpkin/src/command/args/gameprofile.rs +++ b/pumpkin/src/command/args/gameprofile.rs @@ -423,6 +423,6 @@ mod test { _ => "", }; assert_eq!(translate_key, translation::java::ARGUMENT_PLAYER_UNKNOWN); - assert_eq!(error.context.unwrap().cursor, 4); + assert_eq!(error.context.expect("Error should have context").cursor, 4); } } diff --git a/pumpkin/src/command/argument_types/entity_selector/mod.rs b/pumpkin/src/command/argument_types/entity_selector/mod.rs index f1abb69b7..d7fe7c159 100644 --- a/pumpkin/src/command/argument_types/entity_selector/mod.rs +++ b/pumpkin/src/command/argument_types/entity_selector/mod.rs @@ -162,7 +162,10 @@ impl EntitySelector { ) -> Result, CommandSyntaxError> { let list = self.find_players(source).await?; if list.len() == 1 { - Ok(list.first().unwrap().clone()) + Ok(list + .first() + .expect("List length is 1, so first should exist") + .clone()) } else { Err(entity::NO_PLAYERS_ERROR_TYPE.create_without_context()) } diff --git a/pumpkin/src/command/argument_types/entity_selector/parser.rs b/pumpkin/src/command/argument_types/entity_selector/parser.rs index 63af81527..ece32d89d 100644 --- a/pumpkin/src/command/argument_types/entity_selector/parser.rs +++ b/pumpkin/src/command/argument_types/entity_selector/parser.rs @@ -250,7 +250,7 @@ impl<'b, 'a> EntitySelectorParser<'b, 'a> { return Err(MISSING_SELECTOR_TYPE_ERROR_TYPE.create(self.reader)); } let i = self.reader.cursor(); - let char = self.reader.read().unwrap(); + let char = self.reader.read().expect("can_read_char is true"); let mut add_alive_predicate = false; match char { 'a' => { diff --git a/pumpkin/src/command/commands/effect.rs b/pumpkin/src/command/commands/effect.rs index efb69141f..d94fd0197 100644 --- a/pumpkin/src/command/commands/effect.rs +++ b/pumpkin/src/command/commands/effect.rs @@ -93,7 +93,7 @@ impl CommandExecutor for GiveExecutor { .living_entity .get_effect(effect) .await - .unwrap() + .expect("Effect should exist because has_effect returned true") .amplifier >= amplifier { diff --git a/pumpkin/src/command/commands/give.rs b/pumpkin/src/command/commands/give.rs index e5c5e46a4..976f64a74 100644 --- a/pumpkin/src/command/commands/give.rs +++ b/pumpkin/src/command/commands/give.rs @@ -65,7 +65,7 @@ impl CommandExecutor for Executor { .find_map(|(id, component)| { (id == &MaxStackSize).then(|| get::(*component).size) }) - .unwrap(), + .expect("Item should have MaxStackSize component"), ); let mut remaining = item_count; diff --git a/pumpkin/src/command/commands/mod.rs b/pumpkin/src/command/commands/mod.rs index 8a5d2e7a7..0bb4f643a 100644 --- a/pumpkin/src/command/commands/mod.rs +++ b/pumpkin/src/command/commands/mod.rs @@ -176,7 +176,7 @@ fn register_permissions(registry: &mut PermissionRegistry) { "Allows a player to use selector variables", PermissionDefault::Allow, )) - .unwrap(); + .expect("Permission already registered"); } fn register_level_0_permissions(registry: &mut PermissionRegistry) { @@ -187,21 +187,21 @@ fn register_level_0_permissions(registry: &mut PermissionRegistry) { "Shows information about the Pumpkin server", PermissionDefault::Allow, )) - .unwrap(); + .expect("Permission already registered"); registry .register_permission(Permission::new( "minecraft:command.me", "Broadcasts a narrative message about the player", PermissionDefault::Allow, )) - .unwrap(); + .expect("Permission already registered"); registry .register_permission(Permission::new( "minecraft:command.msg", "Sends a private message to another player", PermissionDefault::Allow, )) - .unwrap(); + .expect("Permission already registered"); } #[expect(clippy::too_many_lines)] @@ -213,189 +213,189 @@ fn register_level_2_permissions(registry: &mut PermissionRegistry) { "Manages the world border", PermissionDefault::Op(PermissionLvl::Two), )) - .unwrap(); + .expect("Permission already registered"); registry .register_permission(Permission::new( "minecraft:command.effect", "Adds or removes status effects", PermissionDefault::Op(PermissionLvl::Two), )) - .unwrap(); + .expect("Permission already registered"); registry .register_permission(Permission::new( "minecraft:command.teleport", "Teleports entities to other locations", PermissionDefault::Op(PermissionLvl::Two), )) - .unwrap(); + .expect("Permission already registered"); registry .register_permission(Permission::new( "minecraft:command.time", "Changes or queries the world's game time", PermissionDefault::Op(PermissionLvl::Two), )) - .unwrap(); + .expect("Permission already registered"); registry .register_permission(Permission::new( "minecraft:command.give", "Gives an item to a player", PermissionDefault::Op(PermissionLvl::Two), )) - .unwrap(); + .expect("Permission already registered"); registry .register_permission(Permission::new( "minecraft:command.clear", "Clears items from player inventory", PermissionDefault::Op(PermissionLvl::Two), )) - .unwrap(); + .expect("Permission already registered"); registry .register_permission(Permission::new( "minecraft:command.setblock", "Changes a block to another block", PermissionDefault::Op(PermissionLvl::Two), )) - .unwrap(); + .expect("Permission already registered"); registry .register_permission(Permission::new( "minecraft:command.fill", "Fills a region with a specific block", PermissionDefault::Op(PermissionLvl::Two), )) - .unwrap(); + .expect("Permission already registered"); registry .register_permission(Permission::new( "minecraft:command.playsound", "Plays a sound to players", PermissionDefault::Op(PermissionLvl::Two), )) - .unwrap(); + .expect("Permission already registered"); registry .register_permission(Permission::new( "minecraft:command.tellraw", "Displays a JSON message to players", PermissionDefault::Op(PermissionLvl::Two), )) - .unwrap(); + .expect("Permission already registered"); registry .register_permission(Permission::new( "minecraft:command.title", "Controls screen titles displayed to players", PermissionDefault::Op(PermissionLvl::Two), )) - .unwrap(); + .expect("Permission already registered"); registry .register_permission(Permission::new( "minecraft:command.summon", "Summons an entity", PermissionDefault::Op(PermissionLvl::Two), )) - .unwrap(); + .expect("Permission already registered"); registry .register_permission(Permission::new( "minecraft:command.experience", "Adds, removes or queries player experience", PermissionDefault::Op(PermissionLvl::Two), )) - .unwrap(); + .expect("Permission already registered"); registry .register_permission(Permission::new( "minecraft:command.weather", "Sets the weather in the server", PermissionDefault::Op(PermissionLvl::Two), )) - .unwrap(); + .expect("Permission already registered"); registry .register_permission(Permission::new( "minecraft:command.particle", "Creates particles in the world", PermissionDefault::Op(PermissionLvl::Two), )) - .unwrap(); + .expect("Permission already registered"); registry .register_permission(Permission::new( "minecraft:command.rotate", "Changes the rotation of an entity", PermissionDefault::Op(PermissionLvl::Two), )) - .unwrap(); + .expect("Permission already registered"); registry .register_permission(Permission::new( "minecraft:command.damage", "Damages entities", PermissionDefault::Op(PermissionLvl::Two), )) - .unwrap(); + .expect("Permission already registered"); registry .register_permission(Permission::new( "minecraft:command.bossbar", "Creates and manages boss bars", PermissionDefault::Op(PermissionLvl::Two), )) - .unwrap(); + .expect("Permission already registered"); registry .register_permission(Permission::new( "minecraft:command.say", "Broadcasts a message to multiple players", PermissionDefault::Op(PermissionLvl::Two), )) - .unwrap(); + .expect("Permission already registered"); registry .register_permission(Permission::new( "minecraft:command.gamemode", "Sets a player's game mode", PermissionDefault::Op(PermissionLvl::Two), )) - .unwrap(); + .expect("Permission already registered"); registry .register_permission(Permission::new( "minecraft:command.gamerule", "Sets a player's game mode", PermissionDefault::Op(PermissionLvl::Two), )) - .unwrap(); + .expect("Permission already registered"); registry .register_permission(Permission::new( "minecraft:command.stopsound", "Stops sounds from playing", PermissionDefault::Op(PermissionLvl::Two), )) - .unwrap(); + .expect("Permission already registered"); registry .register_permission(Permission::new( "minecraft:command.defaultgamemode", "Sets the default game mode for new players", PermissionDefault::Op(PermissionLvl::Two), )) - .unwrap(); + .expect("Permission already registered"); registry .register_permission(Permission::new( "minecraft:command.data", "Query and modify data of entities and blocks", PermissionDefault::Op(PermissionLvl::Two), )) - .unwrap(); + .expect("Permission already registered"); registry .register_permission(Permission::new( "minecraft:command.enchant", "Adds an enchantment to a player's selected item, subject to the same restrictions as an anvil. Also works on any mob or entity holding a weapon/tool/armor in its main hand.", PermissionDefault::Op(PermissionLvl::Two), )) - .unwrap(); + .expect("Permission already registered"); registry .register_permission(Permission::new( "minecraft:command.spawnpoint", "Sets the spawn point for a player", PermissionDefault::Op(PermissionLvl::Two), )) - .unwrap(); + .expect("Permission already registered"); registry .register_permission(Permission::new( "pumpkin:command.tps", "Displays the server TPS and MSPT", PermissionDefault::Op(PermissionLvl::Two), )) - .unwrap(); + .expect("Permission already registered"); } fn register_level_3_permissions(registry: &mut PermissionRegistry) { @@ -406,75 +406,75 @@ fn register_level_3_permissions(registry: &mut PermissionRegistry) { "Sets the world spawn point", PermissionDefault::Op(PermissionLvl::Three), )) - .unwrap(); + .expect("Permission already registered"); registry .register_permission(Permission::new( "minecraft:command.deop", "Revokes operator status from a player", PermissionDefault::Op(PermissionLvl::Three), )) - .unwrap(); + .expect("Permission already registered"); registry .register_permission(Permission::new( "minecraft:command.kick", "Removes players from the server", PermissionDefault::Op(PermissionLvl::Three), )) - .unwrap(); + .expect("Permission already registered"); registry .register_permission(Permission::new( "pumpkin:command.plugin", "Manages server plugins", PermissionDefault::Op(PermissionLvl::Three), )) - .unwrap(); + .expect("Permission already registered"); registry .register_permission(Permission::new( "pumpkin:command.plugins", "Lists all plugins loaded on the server", PermissionDefault::Op(PermissionLvl::Three), )) - .unwrap(); + .expect("Permission already registered"); registry .register_permission(Permission::new( "minecraft:command.ban", "Adds players to banlist", PermissionDefault::Op(PermissionLvl::Three), )) - .unwrap(); + .expect("Permission already registered"); registry .register_permission(Permission::new( "minecraft:command.banip", "Adds IP addresses to banlist", PermissionDefault::Op(PermissionLvl::Three), )) - .unwrap(); + .expect("Permission already registered"); registry .register_permission(Permission::new( "minecraft:command.pardon", "Removes entries from the player banlist", PermissionDefault::Op(PermissionLvl::Three), )) - .unwrap(); + .expect("Permission already registered"); registry .register_permission(Permission::new( "minecraft:command.pardonip", "Removes entries from the IP banlist", PermissionDefault::Op(PermissionLvl::Three), )) - .unwrap(); + .expect("Permission already registered"); registry .register_permission(Permission::new( "minecraft:command.whitelist", "Manages server whitelist", PermissionDefault::Op(PermissionLvl::Three), )) - .unwrap(); + .expect("Permission already registered"); registry .register_permission(Permission::new( "minecraft:command.transfer", "Transfers the player to another server", PermissionDefault::Op(PermissionLvl::Three), )) - .unwrap(); + .expect("Permission already registered"); } diff --git a/pumpkin/src/command/commands/teleport.rs b/pumpkin/src/command/commands/teleport.rs index 62e410a15..a29a96311 100644 --- a/pumpkin/src/command/commands/teleport.rs +++ b/pumpkin/src/command/commands/teleport.rs @@ -57,9 +57,14 @@ fn resolve_sender_world( sender: &CommandSender, server: &crate::server::Server, ) -> std::sync::Arc { - sender - .world() - .unwrap_or_else(|| server.worlds.load().first().unwrap().clone()) + sender.world().unwrap_or_else(|| { + server + .worlds + .load() + .first() + .expect("Server should have at least one world") + .clone() + }) } struct EntitiesToEntityExecutor; diff --git a/pumpkin/src/command/mod.rs b/pumpkin/src/command/mod.rs index 0476cfd4e..bb080aaf2 100644 --- a/pumpkin/src/command/mod.rs +++ b/pumpkin/src/command/mod.rs @@ -99,7 +99,9 @@ impl CommandSender { let now = time::OffsetDateTime::now_utc(); let format = time::macros::format_description!("[hour]:[minute]:[second]"); - let timestamp = now.format(&format).unwrap(); + let timestamp = now + .format(&format) + .expect("Failed to format timestamp for command block output"); *last_output = format!("[{}] {}", timestamp, text.get_text()); } diff --git a/pumpkin/src/command/node/dispatcher.rs b/pumpkin/src/command/node/dispatcher.rs index 3389a364f..dda8d6504 100644 --- a/pumpkin/src/command/node/dispatcher.rs +++ b/pumpkin/src/command/node/dispatcher.rs @@ -224,7 +224,12 @@ impl CommandDispatcher { pub async fn execute(&self, parsed: ParsingResult<'_>) -> Result { if parsed.reader.peek().is_some() { return if parsed.errors.len() == 1 { - Err(parsed.errors.values().next().unwrap().clone()) + Err(parsed + .errors + .values() + .next() + .expect("Errors length is 1, so next should exist") + .clone()) } else if parsed.context.range.is_empty() { Err(DISPATCHER_UNKNOWN_COMMAND.create(&parsed.reader)) } else { @@ -358,7 +363,7 @@ impl CommandDispatcher { (a_reader_remaining, a_has_errors).cmp(&(b_reader_remaining, b_has_errors)) }) - .unwrap() + .expect("Potentials list is not empty") } } @@ -897,7 +902,10 @@ impl CommandDispatcher { } } if child_usages.len() == 1 { - let mut child_usage = child_usages.into_iter().next().unwrap(); + let mut child_usage = child_usages + .into_iter() + .next() + .expect("Child usages length is 1, so next should exist"); if is_optional { child_usage = format!( "{USAGE_OPTIONAL_OPEN}{child_usage}{USAGE_OPTIONAL_CLOSE}" diff --git a/pumpkin/src/command/node/tree.rs b/pumpkin/src/command/node/tree.rs index 2bd8785aa..83d1c94ee 100644 --- a/pumpkin/src/command/node/tree.rs +++ b/pumpkin/src/command/node/tree.rs @@ -17,7 +17,7 @@ use std::ops::{Index, IndexMut}; use std::sync::Arc; /// The constant local ID occupied by the root node. -pub const ROOT_NODE_ID: NodeId = NodeId(NonZero::new(1).unwrap()); +pub const ROOT_NODE_ID: NodeId = NodeId(NonZero::new(1).expect("1 is non-zero")); /// A consumer which takes ambiguity of input (when two or more nodes are satisfied) pub trait AmbiguityConsumer { diff --git a/pumpkin/src/command/snbt/mod.rs b/pumpkin/src/command/snbt/mod.rs index 8164af0b3..e5bafd1e2 100644 --- a/pumpkin/src/command/snbt/mod.rs +++ b/pumpkin/src/command/snbt/mod.rs @@ -439,7 +439,7 @@ impl SnbtParser<'_, '_> { } bytes.push(self.parse_integer_literal(value, TypeSuffix::Byte)?.into()); } - Some(NbtTag::ByteArray(bytes)) + Some(NbtTag::ByteArray(bytes.into())) } fn create_int_array(&mut self, values: &[IntegerLiteral]) -> Option { diff --git a/pumpkin/src/command/snbt/tests.rs b/pumpkin/src/command/snbt/tests.rs index 47e2c465a..02faef4e9 100644 --- a/pumpkin/src/command/snbt/tests.rs +++ b/pumpkin/src/command/snbt/tests.rs @@ -76,7 +76,10 @@ macro_rules! assert_parse_err { ); // There should always be a context in SNBT parsing. assert_eq!( - error.context.unwrap().cursor, + error + .context + .expect("There should always be a context in SNBT parsing") + .cursor, $cursor, "Cursor positions for error don't match" ); @@ -453,7 +456,7 @@ fn lists() { #[test] fn arrays() { - assert_parse_ok!("[B;]", NbtTag::ByteArray(vec![])); + assert_parse_ok!("[B;]", NbtTag::ByteArray(vec![].into())); assert_parse_ok!("[I ;1 ,2 , 3,]", NbtTag::IntArray(vec![1, 2, 3])); assert_parse_ok!("[L;1 ,2 , 3, 4]", NbtTag::LongArray(vec![1, 2, 3, 4])); @@ -481,7 +484,7 @@ fn arrays() { assert_parse_err!("[I;{}]", "Expected literal +", 3, []); assert_parse_err!("[i;4]", "Expected literal (", 2, []); - assert_parse_ok!("[B; 0b11111111]", NbtTag::ByteArray(vec![-1])); + assert_parse_ok!("[B; 0b11111111]", NbtTag::ByteArray(vec![-1].into())); assert_parse_ok!("[L; 0xFFFFFFFFFFFFFFFF]", NbtTag::LongArray(vec![-1])); assert_parse_err!( "[L; 0xFFFFFFFFFFFFFFFFF]", diff --git a/pumpkin/src/command/string_reader.rs b/pumpkin/src/command/string_reader.rs index b77655670..6a9a8eb28 100644 --- a/pumpkin/src/command/string_reader.rs +++ b/pumpkin/src/command/string_reader.rs @@ -381,9 +381,9 @@ mod test { assert!(reader.can_read_chars(7)); assert!(!reader.can_read_chars(8)); - reader.expect('l').unwrap(); + reader.expect('l').expect("Expected 'l'"); reader.skip(); - reader.expect('o').unwrap(); + reader.expect('o').expect("Expected 'o'"); // Note: 🎃 carries 4 bytes in UTF-8 assert!(reader.can_read_bytes(6)); @@ -422,10 +422,10 @@ mod test { assert_eq!(reader.read_long(), Ok(7890123456)); reader.skip_whitespace(); - assert!((reader.read_float().unwrap() - 1.233f32).abs() < 1e-07); + assert!((reader.read_float().expect("Expected float") - 1.233f32).abs() < 1e-07); reader.skip_whitespace(); - assert!((reader.read_double().unwrap() - 1.592394582f64).abs() < 1e-15); + assert!((reader.read_double().expect("Expected double") - 1.592394582f64).abs() < 1e-15); reader.skip_whitespace(); assert_eq!(reader.read_bool(), Ok(false)); diff --git a/pumpkin/src/command/suggestion/suggestions.rs b/pumpkin/src/command/suggestion/suggestions.rs index ed991a4d4..e1a68e040 100644 --- a/pumpkin/src/command/suggestion/suggestions.rs +++ b/pumpkin/src/command/suggestion/suggestions.rs @@ -335,7 +335,7 @@ impl Suggestions { .iter() .map(|s| s.borrow().range) .reduce(StringRange::encompass) - .unwrap(); + .expect("Suggestions list is not empty, so range should exist"); let mut texts = Vec::new(); for suggestion in &suggestions { @@ -412,7 +412,9 @@ impl Suggestions { match side { PushSide::Text => { - let text = text_iter.next().unwrap(); + let text = text_iter.next().expect( + "text_iter should have a next value because side is PushSide::Text", + ); suggestions.push(Suggestion { text: SuggestionText::Text(text.0), tooltip: text.1, @@ -420,7 +422,9 @@ impl Suggestions { }); } PushSide::Integer => { - let text = integer_iter.next().unwrap(); + let text = integer_iter.next().expect( + "integer_iter should have a next value because side is PushSide::Integer", + ); suggestions.push(Suggestion { text: SuggestionText::Integer { cached_text: text.0, diff --git a/pumpkin/src/data/mod.rs b/pumpkin/src/data/mod.rs index 1ace7d47d..71767f354 100644 --- a/pumpkin/src/data/mod.rs +++ b/pumpkin/src/data/mod.rs @@ -42,7 +42,7 @@ pub trait LoadJSONConfiguration { where Self: Sized + Default + Serialize + for<'de> Deserialize<'de>, { - let exe_dir = env::current_dir().unwrap(); + let exe_dir = env::current_dir().expect("Failed to get current directory"); let data_dir = exe_dir.join(DATA_FOLDER); if !data_dir.exists() { debug!("creating new data root folder"); @@ -63,7 +63,11 @@ pub trait LoadJSONConfiguration { } else { let content = Self::default(); - if let Err(err) = fs::write(&path, serde_json::to_string_pretty(&content).unwrap()) { + if let Err(err) = fs::write( + &path, + serde_json::to_string_pretty(&content) + .expect("Failed to serialize default data config"), + ) { error!( "Couldn't write default data config to {}. Reason: {err}. This is probably caused by a config update. Just delete the old data config and restart.", path.display(), @@ -87,7 +91,7 @@ pub trait SaveJSONConfiguration: LoadJSONConfiguration { where Self: Sized + Default + Serialize + for<'de> Deserialize<'de>, { - let exe_dir = env::current_dir().unwrap(); + let exe_dir = env::current_dir().expect("Failed to get current directory"); let data_dir = exe_dir.join(DATA_FOLDER); if !data_dir.exists() { debug!("creating new data root folder"); diff --git a/pumpkin/src/item/items/axe.rs b/pumpkin/src/item/items/axe.rs index 220650ea5..68f0fb786 100644 --- a/pumpkin/src/item/items/axe.rs +++ b/pumpkin/src/item/items/axe.rs @@ -18,7 +18,7 @@ pub struct AxeItem; impl ItemMetadata for AxeItem { fn ids() -> Box<[u16]> { - tag::Item::MINECRAFT_AXES.1.to_vec().into_boxed_slice() + tag::Item::MINECRAFT_AXES.1.into() } } diff --git a/pumpkin/src/item/items/dye.rs b/pumpkin/src/item/items/dye.rs index 8aeef768e..07b719b43 100644 --- a/pumpkin/src/item/items/dye.rs +++ b/pumpkin/src/item/items/dye.rs @@ -17,7 +17,7 @@ pub struct DyeItem; impl ItemMetadata for DyeItem { fn ids() -> Box<[u16]> { - tag::Item::C_DYES.1.to_vec().into_boxed_slice() + tag::Item::C_DYES.1.into() } } diff --git a/pumpkin/src/item/items/hoe.rs b/pumpkin/src/item/items/hoe.rs index 4253dd11f..a4de5d118 100644 --- a/pumpkin/src/item/items/hoe.rs +++ b/pumpkin/src/item/items/hoe.rs @@ -19,7 +19,7 @@ pub struct HoeItem; impl ItemMetadata for HoeItem { fn ids() -> Box<[u16]> { - tag::Item::MINECRAFT_HOES.1.to_vec().into_boxed_slice() + tag::Item::MINECRAFT_HOES.1.into() } } diff --git a/pumpkin/src/item/items/shovel.rs b/pumpkin/src/item/items/shovel.rs index 13a995d91..316d11c28 100644 --- a/pumpkin/src/item/items/shovel.rs +++ b/pumpkin/src/item/items/shovel.rs @@ -19,7 +19,7 @@ pub struct ShovelItem; impl ItemMetadata for ShovelItem { fn ids() -> Box<[u16]> { - tag::Item::MINECRAFT_SHOVELS.1.to_vec().into_boxed_slice() + tag::Item::MINECRAFT_SHOVELS.1.into() } } diff --git a/pumpkin/src/item/items/swords.rs b/pumpkin/src/item/items/swords.rs index 07c56dcdf..c1dbabd67 100644 --- a/pumpkin/src/item/items/swords.rs +++ b/pumpkin/src/item/items/swords.rs @@ -7,7 +7,7 @@ pub struct SwordItem; impl ItemMetadata for SwordItem { fn ids() -> Box<[u16]> { - tag::Item::MINECRAFT_SWORDS.1.to_vec().into_boxed_slice() + tag::Item::MINECRAFT_SWORDS.1.into() } } diff --git a/pumpkin/src/plugin/loader/wasm/wasm_host/wit/v0_1/generated_packets.rs b/pumpkin/src/plugin/loader/wasm/wasm_host/wit/v0_1/generated_packets.rs index fcabeb638..24d92ce8d 100644 --- a/pumpkin/src/plugin/loader/wasm/wasm_host/wit/v0_1/generated_packets.rs +++ b/pumpkin/src/plugin/loader/wasm/wasm_host/wit/v0_1/generated_packets.rs @@ -697,6 +697,26 @@ pub fn serialize_bedrock_packet(packet: &BClientboundPacket) -> Option { crate::net::bedrock::BedrockClient::write_raw_packet(&p, &mut buf).unwrap(); Some(buf.into()) } + BClientboundPacket::CSetDisplayObjective(data) => { + let p = pumpkin_protocol::bedrock::client::CSetDisplayObjective { + display_slot: data.display_slot.clone(), + objective_name: data.objective_name.clone(), + display_name: data.display_name.clone(), + criteria_name: data.criteria_name.clone(), + sort_order: VarInt(data.sort_order), + }; + let mut buf = Vec::new(); + crate::net::bedrock::BedrockClient::write_raw_packet(&p, &mut buf).unwrap(); + Some(buf.into()) + } + BClientboundPacket::CRemoveObjective(data) => { + let p = pumpkin_protocol::bedrock::client::CRemoveObjective { + objective_name: data.objective_name.clone(), + }; + let mut buf = Vec::new(); + crate::net::bedrock::BedrockClient::write_raw_packet(&p, &mut buf).unwrap(); + Some(buf.into()) + } BClientboundPacket::CSetHealth(data) => { let p = pumpkin_protocol::bedrock::client::CSetHealth { health: VarInt(data.health), @@ -728,6 +748,16 @@ pub fn serialize_bedrock_packet(packet: &BClientboundPacket) -> Option { crate::net::bedrock::BedrockClient::write_raw_packet(&p, &mut buf).unwrap(); Some(buf.into()) } + BClientboundPacket::CTransfer(data) => { + let p = pumpkin_protocol::bedrock::client::CTransfer { + address: data.address.clone(), + port: data.port.try_into().unwrap(), + reload_world: data.reload_world.try_into().unwrap(), + }; + let mut buf = Vec::new(); + crate::net::bedrock::BedrockClient::write_raw_packet(&p, &mut buf).unwrap(); + Some(buf.into()) + } _ => None, } } diff --git a/pumpkin/src/world/scoreboard.rs b/pumpkin/src/world/scoreboard.rs index 8287b924f..5ecf2cee5 100644 --- a/pumpkin/src/world/scoreboard.rs +++ b/pumpkin/src/world/scoreboard.rs @@ -181,7 +181,7 @@ impl Scoreboard { team_name: team.name.clone(), method: TeamMethod::Create, parameters: Some(parameters), - players: team.players.clone(), + players: team.players.clone().into(), }); self.teams.insert(team.name.clone(), team); @@ -207,7 +207,7 @@ impl Scoreboard { team_name: team.name.clone(), method: TeamMethod::Update, parameters: Some(parameters), - players: Vec::new(), + players: Box::new([]), }); self.teams.insert(team.name.clone(), team); @@ -223,7 +223,7 @@ impl Scoreboard { team_name: name.to_string(), method: TeamMethod::Remove, parameters: None, - players: Vec::new(), + players: Box::new([]), }); self.teams.remove(name); @@ -246,7 +246,7 @@ impl Scoreboard { team_name: team_name.to_string(), method: TeamMethod::AddPlayers, parameters: None, - players: vec![player.clone()], + players: vec![player.clone()].into(), }); team.players.push(player); @@ -269,7 +269,7 @@ impl Scoreboard { team_name: team_name.to_string(), method: TeamMethod::RemovePlayers, parameters: None, - players: vec![player.to_string()], + players: vec![player.to_string()].into(), }); team.players.retain(|p| p != player);