fix: disable cave carver for now
fixes some issues
This commit is contained in:
parent
f19d84efef
commit
3629f43dcc
6
Cargo.lock
generated
6
Cargo.lock
generated
@ -876,9 +876,9 @@ checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28"
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "crossfire"
|
name = "crossfire"
|
||||||
version = "3.1.15"
|
version = "3.1.16"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7985ad34fb5a761ce21154d0e5a8c37ec6b50af61c90d594eb5cdeb934f91f7c"
|
checksum = "4d8c4de3db833e7ef74050bae09d5f3fa8f9d1507d3c2689c6e8c50b71208b18"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"crossbeam-utils",
|
"crossbeam-utils",
|
||||||
"embed-collections",
|
"embed-collections",
|
||||||
@ -2155,7 +2155,7 @@ version = "0.50.3"
|
|||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5"
|
checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"windows-sys 0.59.0",
|
"windows-sys 0.61.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|||||||
@ -127,7 +127,7 @@ console-subscriber = { version = "0.5.0", default-features = false }
|
|||||||
crc-fast = { version = "1.10.0", default-features = false, features = ["std"] }
|
crc-fast = { version = "1.10.0", default-features = false, features = ["std"] }
|
||||||
criterion = { version = "0.8", default-features = false }
|
criterion = { version = "0.8", default-features = false }
|
||||||
crossbeam-utils = { version = "0.8.21", default-features = false, features = ["std"] }
|
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 }
|
crypto-bigint = { version = "0.7.3", default-features = false }
|
||||||
dashmap = { version = "6.2", default-features = false }
|
dashmap = { version = "6.2", default-features = false }
|
||||||
ecdsa = { version = "0.16.9", default-features = false, features = ["std"] }
|
ecdsa = { version = "0.16.9", default-features = false, features = ["std"] }
|
||||||
|
|||||||
@ -1435,7 +1435,7 @@ fn get_be_data_from_nbt<R: Read + Seek>(
|
|||||||
let raw_name = nbt.get_string("name").unwrap();
|
let raw_name = nbt.get_string("name").unwrap();
|
||||||
raw_name
|
raw_name
|
||||||
.strip_prefix("minecraft:")
|
.strip_prefix("minecraft:")
|
||||||
.unwrap_or(&raw_name)
|
.unwrap_or(raw_name)
|
||||||
.to_string()
|
.to_string()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -91,7 +91,6 @@ impl ToTokens for LootPoolStruct {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Deserialized single-item loot entry holding the item's registry key.
|
/// Deserialized single-item loot entry holding the item's registry key.
|
||||||
#[derive(Deserialize, Clone, Debug)]
|
#[derive(Deserialize, Clone, Debug)]
|
||||||
pub struct ItemEntryStruct {
|
pub struct ItemEntryStruct {
|
||||||
@ -428,9 +427,7 @@ pub enum LootConditionStruct {
|
|||||||
},
|
},
|
||||||
/// References an external predicate by ID.
|
/// References an external predicate by ID.
|
||||||
#[serde(rename = "minecraft:reference")]
|
#[serde(rename = "minecraft:reference")]
|
||||||
Reference {
|
Reference { name: String },
|
||||||
name: String,
|
|
||||||
},
|
|
||||||
/// Passes based on the current in-game time.
|
/// Passes based on the current in-game time.
|
||||||
#[serde(rename = "minecraft:time_check")]
|
#[serde(rename = "minecraft:time_check")]
|
||||||
TimeCheck {
|
TimeCheck {
|
||||||
@ -446,9 +443,7 @@ pub enum LootConditionStruct {
|
|||||||
},
|
},
|
||||||
/// Passes if an enchantment is currently active.
|
/// Passes if an enchantment is currently active.
|
||||||
#[serde(rename = "minecraft:enchantment_active_check")]
|
#[serde(rename = "minecraft:enchantment_active_check")]
|
||||||
EnchantmentActiveCheck {
|
EnchantmentActiveCheck { active: bool },
|
||||||
active: bool,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToTokens for LootConditionStruct {
|
impl ToTokens for LootConditionStruct {
|
||||||
@ -461,7 +456,10 @@ impl ToTokens for LootConditionStruct {
|
|||||||
Self::RandomChance { chance } => {
|
Self::RandomChance { chance } => {
|
||||||
quote! { LootCondition::RandomChance { chance: #chance } }
|
quote! { LootCondition::RandomChance { chance: #chance } }
|
||||||
}
|
}
|
||||||
Self::RandomChanceWithEnchantedBonus { enchantment, chances } => {
|
Self::RandomChanceWithEnchantedBonus {
|
||||||
|
enchantment,
|
||||||
|
chances,
|
||||||
|
} => {
|
||||||
let e = LitStr::new(enchantment, Span::call_site());
|
let e = LitStr::new(enchantment, Span::call_site());
|
||||||
if let Some(chances) = chances {
|
if let Some(chances) = chances {
|
||||||
quote! { LootCondition::RandomChanceWithEnchantedBonus { enchantment: #e, chances: Some(&[#(#chances),*]) } }
|
quote! { LootCondition::RandomChanceWithEnchantedBonus { enchantment: #e, chances: Some(&[#(#chances),*]) } }
|
||||||
@ -472,15 +470,17 @@ impl ToTokens for LootConditionStruct {
|
|||||||
Self::EntityProperties { entity, predicate } => {
|
Self::EntityProperties { entity, predicate } => {
|
||||||
let entity = entity.as_deref().unwrap_or("this");
|
let entity = entity.as_deref().unwrap_or("this");
|
||||||
let e = LitStr::new(entity, Span::call_site());
|
let e = LitStr::new(entity, Span::call_site());
|
||||||
let expected_type = predicate.as_ref().and_then(|p| p.entity_type.as_ref()).map(|t| {
|
let expected_type = predicate
|
||||||
match t {
|
.as_ref()
|
||||||
|
.and_then(|p| p.entity_type.as_ref())
|
||||||
|
.map(|t| match t {
|
||||||
StringOrVec::String(s) => quote! { Some(#s) },
|
StringOrVec::String(s) => quote! { Some(#s) },
|
||||||
StringOrVec::Vec(v) => {
|
StringOrVec::Vec(v) => {
|
||||||
let s = &v[0];
|
let s = &v[0];
|
||||||
quote! { Some(#s) }
|
quote! { Some(#s) }
|
||||||
}
|
}
|
||||||
}
|
})
|
||||||
}).unwrap_or(quote! { None });
|
.unwrap_or(quote! { None });
|
||||||
quote! { LootCondition::EntityProperties { entity: #e, expected_type: #expected_type } }
|
quote! { LootCondition::EntityProperties { entity: #e, expected_type: #expected_type } }
|
||||||
}
|
}
|
||||||
Self::KilledByPlayer => quote! { LootCondition::KilledByPlayer },
|
Self::KilledByPlayer => quote! { LootCondition::KilledByPlayer },
|
||||||
@ -516,7 +516,10 @@ impl ToTokens for LootConditionStruct {
|
|||||||
quote! { LootCondition::MatchTool { items: None } }
|
quote! { LootCondition::MatchTool { items: None } }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Self::TableBonus { enchantment, chances } => {
|
Self::TableBonus {
|
||||||
|
enchantment,
|
||||||
|
chances,
|
||||||
|
} => {
|
||||||
let e = LitStr::new(enchantment, Span::call_site());
|
let e = LitStr::new(enchantment, Span::call_site());
|
||||||
quote! { LootCondition::TableBonus { enchantment: #e, chances: &[#(#chances),*] } }
|
quote! { LootCondition::TableBonus { enchantment: #e, chances: &[#(#chances),*] } }
|
||||||
}
|
}
|
||||||
@ -559,20 +562,29 @@ impl ToTokens for LootConditionStruct {
|
|||||||
let ox = offset_x.unwrap_or(0);
|
let ox = offset_x.unwrap_or(0);
|
||||||
let oy = offset_y.unwrap_or(0);
|
let oy = offset_y.unwrap_or(0);
|
||||||
let oz = offset_z.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| {
|
let expected_biome = predicate
|
||||||
match b {
|
.as_ref()
|
||||||
|
.and_then(|p| p.biome.as_ref())
|
||||||
|
.map(|b| match b {
|
||||||
StringOrVec::String(s) => quote! { Some(#s) },
|
StringOrVec::String(s) => quote! { Some(#s) },
|
||||||
StringOrVec::Vec(v) => {
|
StringOrVec::Vec(v) => {
|
||||||
let s = &v[0];
|
let s = &v[0];
|
||||||
quote! { Some(#s) }
|
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 } }
|
quote! { LootCondition::LocationCheck { offset_x: #ox, offset_y: #oy, offset_z: #oz, expected_biome: #expected_biome } }
|
||||||
}
|
}
|
||||||
Self::WeatherCheck { raining, thundering } => {
|
Self::WeatherCheck {
|
||||||
let r = raining.map(|b| quote! { Some(#b) }).unwrap_or(quote! { None });
|
raining,
|
||||||
let t = thundering.map(|b| quote! { Some(#b) }).unwrap_or(quote! { None });
|
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 } }
|
quote! { LootCondition::WeatherCheck { raining: #r, thundering: #t } }
|
||||||
}
|
}
|
||||||
Self::Reference { name } => {
|
Self::Reference { name } => {
|
||||||
@ -581,7 +593,9 @@ impl ToTokens for LootConditionStruct {
|
|||||||
}
|
}
|
||||||
Self::TimeCheck { range, period } => {
|
Self::TimeCheck { range, period } => {
|
||||||
let r = range.to_token_stream();
|
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 } }
|
quote! { LootCondition::TimeCheck { range: #r, period: #p } }
|
||||||
}
|
}
|
||||||
Self::ValueCheck { value, range } => {
|
Self::ValueCheck { value, range } => {
|
||||||
@ -824,8 +838,14 @@ pub struct LootFunctionLimitCountStruct {
|
|||||||
|
|
||||||
impl ToTokens for LootFunctionLimitCountStruct {
|
impl ToTokens for LootFunctionLimitCountStruct {
|
||||||
fn to_tokens(&self, tokens: &mut TokenStream) {
|
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||||
let min = self.min.map(|val| quote! { Some(#val) }).unwrap_or(quote! { None });
|
let min = self
|
||||||
let max = self.max.map(|val| quote! { Some(#val) }).unwrap_or(quote! { None });
|
.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) });
|
tokens.extend(quote! { (#min, #max) });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -918,7 +938,6 @@ impl ToTokens for LootPoolEntryStruct {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Deserialized loot table category, tagged by its `"type"` field.
|
/// Deserialized loot table category, tagged by its `"type"` field.
|
||||||
#[derive(Deserialize, Clone, Debug)]
|
#[derive(Deserialize, Clone, Debug)]
|
||||||
#[serde(rename = "snake_case")]
|
#[serde(rename = "snake_case")]
|
||||||
|
|||||||
@ -15,7 +15,10 @@ pub fn build() -> TokenStream {
|
|||||||
(JavaMinecraftVersion::V_1_21_6, "1_21_6_meta_data_type.json"),
|
(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_7, "1_21_7_meta_data_type.json"),
|
||||||
(JavaMinecraftVersion::V_1_21_9, "1_21_9_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"),
|
(JavaMinecraftVersion::V_26_1, "26_1_meta_data_type.json"),
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|||||||
@ -13,14 +13,35 @@ const LATEST_VERSION: JavaMinecraftVersion = JavaMinecraftVersion::V_26_1;
|
|||||||
/// static registry data, and the `Registry::get_synced` method.
|
/// static registry data, and the `Registry::get_synced` method.
|
||||||
pub(crate) fn build() -> TokenStream {
|
pub(crate) fn build() -> TokenStream {
|
||||||
let assets = [
|
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, "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_2,
|
||||||
(JavaMinecraftVersion::V_1_21_5, "1_21_5_synced_registries.json"),
|
"1_21_2_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_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,
|
JavaMinecraftVersion::V_1_21_11,
|
||||||
"1_21_11_synced_registries.json",
|
"1_21_11_synced_registries.json",
|
||||||
|
|||||||
@ -27,10 +27,7 @@ pub fn build() -> String {
|
|||||||
biome_enum.case(name);
|
biome_enum.case(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
interface.type_def(TypeDef::new(
|
interface.type_def(TypeDef::new("biome", TypeDefKind::Enum(biome_enum)));
|
||||||
"biome",
|
|
||||||
TypeDefKind::Enum(biome_enum),
|
|
||||||
));
|
|
||||||
package.interface(interface);
|
package.interface(interface);
|
||||||
|
|
||||||
package.to_string()
|
package.to_string()
|
||||||
|
|||||||
@ -23,8 +23,7 @@ pub fn build() -> String {
|
|||||||
let name = raw_name
|
let name = raw_name
|
||||||
.strip_prefix("minecraft:")
|
.strip_prefix("minecraft:")
|
||||||
.unwrap_or(raw_name)
|
.unwrap_or(raw_name)
|
||||||
.replace('_', "-")
|
.replace(['_', '/'], "-");
|
||||||
.replace('/', "-");
|
|
||||||
component_enum.case(name);
|
component_enum.case(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -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::Path(p) => p.path.segments.last().unwrap().ident.to_string(),
|
||||||
syn::Type::Reference(r) => match &*r.elem {
|
syn::Type::Reference(r) => match &*r.elem {
|
||||||
syn::Type::Slice(s) => match &*s.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(),
|
_ => String::new(),
|
||||||
},
|
},
|
||||||
syn::Type::Path(p) => p.path.segments.last().unwrap().ident.to_string(),
|
syn::Type::Path(p) => p.path.segments.last().unwrap().ident.to_string(),
|
||||||
|
|||||||
@ -235,7 +235,11 @@ fn parse_packet_file(
|
|||||||
|
|
||||||
fn get_type_info(ty: &syn::Type) -> (String, bool, bool) {
|
fn get_type_info(ty: &syn::Type) -> (String, bool, bool) {
|
||||||
match ty {
|
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) => {
|
syn::Type::Reference(tr) => {
|
||||||
let (name, _, is_slice) = get_type_info(&tr.elem);
|
let (name, _, is_slice) = get_type_info(&tr.elem);
|
||||||
(name, true, is_slice)
|
(name, true, is_slice)
|
||||||
|
|||||||
@ -17,16 +17,15 @@ pub fn map_type(ty: &Type) -> WitType {
|
|||||||
"u8" | "i8" => WitType::U8,
|
"u8" | "i8" => WitType::U8,
|
||||||
"u16" | "i16" => WitType::S32,
|
"u16" | "i16" => WitType::S32,
|
||||||
"Option" => {
|
"Option" => {
|
||||||
if let syn::PathArguments::AngleBracketed(args) = &last_segment.arguments {
|
if let syn::PathArguments::AngleBracketed(args) = &last_segment.arguments
|
||||||
if let Some(syn::GenericArgument::Type(inner_ty)) = args.args.first() {
|
&& let Some(syn::GenericArgument::Type(inner_ty)) = args.args.first() {
|
||||||
return WitType::option(map_type(inner_ty));
|
return WitType::option(map_type(inner_ty));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
WitType::String
|
WitType::String
|
||||||
}
|
}
|
||||||
"Vec" | "Box" => {
|
"Vec" | "Box" => {
|
||||||
if let syn::PathArguments::AngleBracketed(args) = &last_segment.arguments {
|
if let syn::PathArguments::AngleBracketed(args) = &last_segment.arguments
|
||||||
if let Some(syn::GenericArgument::Type(inner_ty)) = args.args.first() {
|
&& let Some(syn::GenericArgument::Type(inner_ty)) = args.args.first() {
|
||||||
// Check if the inner type is u8
|
// Check if the inner type is u8
|
||||||
if let Type::Path(tp) = inner_ty
|
if let Type::Path(tp) = inner_ty
|
||||||
&& tp.path.segments.last().unwrap().ident == "u8"
|
&& 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));
|
return WitType::list(map_type(inner_ty));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
WitType::String
|
WitType::String
|
||||||
}
|
}
|
||||||
"Vector3" | "BlockPos" => {
|
"Vector3" | "BlockPos" => {
|
||||||
|
|||||||
@ -47,7 +47,7 @@ fn create_large_compound(depth: usize) -> NbtCompound {
|
|||||||
compound.put_string("string", "Hello test benchmark data".to_string());
|
compound.put_string("string", "Hello test benchmark data".to_string());
|
||||||
compound.put(
|
compound.put(
|
||||||
"byte_array",
|
"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(
|
compound.put(
|
||||||
"int_array",
|
"int_array",
|
||||||
|
|||||||
@ -166,14 +166,14 @@ impl DynamicOps for NbtOps {
|
|||||||
|
|
||||||
fn get_byte_list(&self, input: Self::Value) -> DataResult<Vec<i8>> {
|
fn get_byte_list(&self, input: Self::Value) -> DataResult<Vec<i8>> {
|
||||||
if let NbtTag::ByteArray(b) = input {
|
if let NbtTag::ByteArray(b) = input {
|
||||||
DataResult::new_success(b)
|
DataResult::new_success(b.into())
|
||||||
} else {
|
} else {
|
||||||
impl_get_list!(self, input, "bytes")
|
impl_get_list!(self, input, "bytes")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn create_byte_list(&self, buffer: Vec<i8>) -> Self::Value {
|
fn create_byte_list(&self, buffer: Vec<i8>) -> Self::Value {
|
||||||
NbtTag::ByteArray(buffer)
|
NbtTag::ByteArray(buffer.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_int_list(&self, input: Self::Value) -> DataResult<Vec<i32>> {
|
fn get_int_list(&self, input: Self::Value) -> DataResult<Vec<i32>> {
|
||||||
@ -301,7 +301,7 @@ impl DynamicOps for NbtOps {
|
|||||||
NbtTag::Long(l) => out_ops.create_long(l),
|
NbtTag::Long(l) => out_ops.create_long(l),
|
||||||
NbtTag::Float(f) => out_ops.create_float(f),
|
NbtTag::Float(f) => out_ops.create_float(f),
|
||||||
NbtTag::Double(d) => out_ops.create_double(d),
|
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::String(s) => out_ops.create_string(&s),
|
||||||
NbtTag::List(_) => self.convert_list(out_ops, input),
|
NbtTag::List(_) => self.convert_list(out_ops, input),
|
||||||
NbtTag::Compound(_) => self.convert_map(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.
|
// From this point onwards, we know that the list is not empty.
|
||||||
match tag {
|
match tag {
|
||||||
NbtTag::List(list) => Some(Self::Generic(InnerGenericListCollector::new(list))),
|
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::IntArray(list) => Some(Self::Int(InnerIntListCollector::new(list))),
|
||||||
NbtTag::LongArray(list) => Some(Self::Long(InnerLongListCollector::new(list))),
|
NbtTag::LongArray(list) => Some(Self::Long(InnerLongListCollector::new(list))),
|
||||||
|
|
||||||
@ -592,7 +594,7 @@ impl InnerListCollector for InnerByteListCollector {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn result(self) -> NbtTag {
|
fn result(self) -> NbtTag {
|
||||||
NbtTag::ByteArray(self.list)
|
NbtTag::ByteArray(self.list.into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -669,13 +671,13 @@ mod test {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Byte list collector
|
// Byte list collector
|
||||||
let tag = NbtTag::ByteArray(vec![-1, 45, 100]);
|
let tag = NbtTag::ByteArray(vec![-1, 45, 100].into());
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
ListCollector::new(tag)
|
ListCollector::new(tag)
|
||||||
.expect("List collector should exist")
|
.expect("List collector should exist")
|
||||||
.result(),
|
.result(),
|
||||||
NbtTag::ByteArray(vec![-1, 45, 100])
|
NbtTag::ByteArray(vec![-1, 45, 100].into())
|
||||||
);
|
);
|
||||||
|
|
||||||
// Long list
|
// Long list
|
||||||
|
|||||||
@ -19,7 +19,7 @@ pub enum NbtTag {
|
|||||||
Long(i64) = LONG_ID,
|
Long(i64) = LONG_ID,
|
||||||
Float(f32) = FLOAT_ID,
|
Float(f32) = FLOAT_ID,
|
||||||
Double(f64) = DOUBLE_ID,
|
Double(f64) = DOUBLE_ID,
|
||||||
ByteArray(Vec<i8>) = BYTE_ARRAY_ID,
|
ByteArray(Box<[i8]>) = BYTE_ARRAY_ID,
|
||||||
String(Box<str>) = STRING_ID,
|
String(Box<str>) = STRING_ID,
|
||||||
List(Vec<Self>) = LIST_ID,
|
List(Vec<Self>) = LIST_ID,
|
||||||
Compound(NbtCompound) = COMPOUND_ID,
|
Compound(NbtCompound) = COMPOUND_ID,
|
||||||
@ -281,7 +281,7 @@ impl NbtTag {
|
|||||||
let byte = reader.get_i8()?;
|
let byte = reader.get_i8()?;
|
||||||
byte_array.push(byte);
|
byte_array.push(byte);
|
||||||
}
|
}
|
||||||
Ok(Self::ByteArray(byte_array))
|
Ok(Self::ByteArray(byte_array.into()))
|
||||||
}
|
}
|
||||||
STRING_ID => Ok(Self::String(reader.get_string()?.into())),
|
STRING_ID => Ok(Self::String(reader.get_string()?.into())),
|
||||||
LIST_ID => {
|
LIST_ID => {
|
||||||
@ -457,7 +457,7 @@ impl From<&str> for NbtTag {
|
|||||||
|
|
||||||
impl From<&[i8]> for NbtTag {
|
impl From<&[i8]> for NbtTag {
|
||||||
fn from(value: &[i8]) -> Self {
|
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()? {
|
while let Some(value) = seq.next_element()? {
|
||||||
vec.push(value);
|
vec.push(value);
|
||||||
}
|
}
|
||||||
Ok(NbtTag::ByteArray(vec))
|
Ok(NbtTag::ByteArray(vec.into()))
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
let mut vec = Vec::new();
|
let mut vec = Vec::new();
|
||||||
|
|||||||
@ -87,7 +87,7 @@ impl UDPNetworkDecoder {
|
|||||||
|
|
||||||
pub async fn get_packet_payload(
|
pub async fn get_packet_payload(
|
||||||
&mut self,
|
&mut self,
|
||||||
mut full_packet: Vec<u8>,
|
full_packet: Vec<u8>,
|
||||||
) -> Result<Vec<u8>, PacketDecodeError> {
|
) -> Result<Vec<u8>, PacketDecodeError> {
|
||||||
if full_packet.is_empty() {
|
if full_packet.is_empty() {
|
||||||
return Err(PacketDecodeError::MalformedLength("Empty packet".into()));
|
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 compression is NOT enabled yet, the payload starts at index 1.
|
||||||
if self.compression.is_none() {
|
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.
|
// If compression IS enabled, Bedrock expects a compression method byte at index 1.
|
||||||
@ -125,7 +125,7 @@ impl UDPNetworkDecoder {
|
|||||||
}
|
}
|
||||||
0xff => {
|
0xff => {
|
||||||
// None (Compression enabled but this specific packet is raw)
|
// 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!(
|
_ => Err(PacketDecodeError::FailedDecompression(format!(
|
||||||
"Unsupported compression method: 0x{compression_method:02x}"
|
"Unsupported compression method: 0x{compression_method:02x}"
|
||||||
|
|||||||
@ -35,7 +35,7 @@ pub struct CSetPlayerTeam<'a> {
|
|||||||
pub team_name: String,
|
pub team_name: String,
|
||||||
pub method: TeamMethod,
|
pub method: TeamMethod,
|
||||||
pub parameters: Option<TeamParameters<'a>>,
|
pub parameters: Option<TeamParameters<'a>>,
|
||||||
pub players: Vec<String>,
|
pub players: Box<[String]>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ClientPacket for CSetPlayerTeam<'_> {
|
impl ClientPacket for CSetPlayerTeam<'_> {
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
use super::Carver;
|
use super::Carver;
|
||||||
use crate::ProtoChunk;
|
use crate::ProtoChunk;
|
||||||
use pumpkin_data::block_state::BlockState;
|
|
||||||
use pumpkin_data::carver::{CarverAdditionalConfig, CarverConfig, HeightProvider};
|
use pumpkin_data::carver::{CarverAdditionalConfig, CarverConfig, HeightProvider};
|
||||||
use pumpkin_util::math::vector2::Vector2;
|
use pumpkin_util::math::vector2::Vector2;
|
||||||
|
use pumpkin_util::math::vector3::Vector3;
|
||||||
use pumpkin_util::random::{RandomGenerator, RandomImpl};
|
use pumpkin_util::random::{RandomGenerator, RandomImpl};
|
||||||
use std::f32::consts::PI;
|
use std::f32::consts::PI;
|
||||||
|
|
||||||
@ -352,8 +352,8 @@ impl CaveCarver {
|
|||||||
has_grass: &mut bool,
|
has_grass: &mut bool,
|
||||||
) -> bool {
|
) -> bool {
|
||||||
let local_y = y - chunk.bottom_y() as i32;
|
let local_y = y - chunk.bottom_y() as i32;
|
||||||
let state_id = chunk.get_block_state_raw(x & 15, local_y, z & 15);
|
let state = chunk.get_block_state(&Vector3::new(x, y, z));
|
||||||
let block = pumpkin_data::Block::from_state_id(state_id);
|
let block = state.to_block();
|
||||||
|
|
||||||
if block.id == pumpkin_data::Block::GRASS_BLOCK.id
|
if block.id == pumpkin_data::Block::GRASS_BLOCK.id
|
||||||
|| block.id == pumpkin_data::Block::MYCELIUM.id
|
|| block.id == pumpkin_data::Block::MYCELIUM.id
|
||||||
@ -361,12 +361,11 @@ impl CaveCarver {
|
|||||||
*has_grass = true;
|
*has_grass = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only carve if it's replaceable
|
if !config.replaceable.1.contains(&block.id) {
|
||||||
if config.replaceable.1.contains(&block.id) {
|
return false;
|
||||||
// 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);
|
|
||||||
|
|
||||||
|
let carve_state = {
|
||||||
let lava_y = if is_nether {
|
let lava_y = if is_nether {
|
||||||
chunk.bottom_y() as i32 + 31
|
chunk.bottom_y() as i32 + 31
|
||||||
} else {
|
} else {
|
||||||
@ -376,26 +375,44 @@ impl CaveCarver {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if y <= lava_y {
|
if y <= lava_y {
|
||||||
chunk.set_block_state(x & 15, local_y, z & 15, lava);
|
Some(pumpkin_data::Block::LAVA.default_state)
|
||||||
} else {
|
} 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 {
|
// 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);
|
// let below_block = pumpkin_data::Block::from_state_id(below_state_id);
|
||||||
|
|
||||||
// if below_block.id == pumpkin_data::Block::DIRT.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 =
|
// let top_material =
|
||||||
// BlockState::from_id(pumpkin_data::Block::GRASS_BLOCK.default_state.id);
|
// pumpkin_data::Block::GRASS_BLOCK.default_state;
|
||||||
// chunk.set_block_state(x & 15, local_y - 1, z & 15, top_material);
|
// chunk.set_block_state(x, local_y - 1, z, top_material);
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -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;
|
let canyon_carver = canyon::CanyonCarver;
|
||||||
|
|
||||||
for dx in -radius..=radius {
|
for dx in -radius..=radius {
|
||||||
@ -69,14 +69,14 @@ pub fn carve(chunk: &mut ProtoChunk, generator: &VanillaGenerator) {
|
|||||||
if should_carve(config, &mut carver_random) {
|
if should_carve(config, &mut carver_random) {
|
||||||
match config.additional {
|
match config.additional {
|
||||||
CarverAdditionalConfig::Cave(_) | CarverAdditionalConfig::NetherCave(_) => {
|
CarverAdditionalConfig::Cave(_) | CarverAdditionalConfig::NetherCave(_) => {
|
||||||
cave_carver.carve(
|
// cave_carver.carve(
|
||||||
config,
|
// config,
|
||||||
chunk,
|
// chunk,
|
||||||
&mut carver_random,
|
// &mut carver_random,
|
||||||
&chunk_pos,
|
// &chunk_pos,
|
||||||
&carver_chunk_pos,
|
// &carver_chunk_pos,
|
||||||
generator.settings.legacy_random_source,
|
// generator.settings.legacy_random_source,
|
||||||
);
|
// );
|
||||||
}
|
}
|
||||||
CarverAdditionalConfig::Canyon(_) => {
|
CarverAdditionalConfig::Canyon(_) => {
|
||||||
canyon_carver.carve(
|
canyon_carver.carve(
|
||||||
|
|||||||
@ -61,7 +61,11 @@ impl CommandBlock {
|
|||||||
warn!("Command block has no matching entity");
|
warn!("Command block has no matching entity");
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
let command_entity: &CommandBlockEntity = before_entity.as_any().downcast_ref().unwrap();
|
let Some(command_entity) = before_entity.as_any().downcast_ref::<CommandBlockEntity>()
|
||||||
|
else {
|
||||||
|
warn!("Block entity at {} is not a command block", before.0);
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
command_entity.success_count.load(Ordering::Relaxed) > 0
|
command_entity.success_count.load(Ordering::Relaxed) > 0
|
||||||
}
|
}
|
||||||
@ -122,7 +126,10 @@ impl CommandBlock {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let command_entity: Arc<CommandBlockEntity> = Arc::downcast(block_entity).unwrap();
|
let Ok(command_entity) = Arc::downcast::<CommandBlockEntity>(block_entity) else {
|
||||||
|
warn!("Failed to downcast block entity to CommandBlockEntity");
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
if command.is_empty() {
|
if command.is_empty() {
|
||||||
command_entity.success_count.store(0, Ordering::Release);
|
command_entity.success_count.store(0, Ordering::Release);
|
||||||
@ -164,7 +171,11 @@ impl CommandBlock {
|
|||||||
break;
|
break;
|
||||||
};
|
};
|
||||||
|
|
||||||
let command_entity: &CommandBlockEntity = block_entity.as_any().downcast_ref().unwrap();
|
let Some(command_entity) = block_entity.as_any().downcast_ref::<CommandBlockEntity>()
|
||||||
|
else {
|
||||||
|
warn!("Block entity at {} is not a command block", pos);
|
||||||
|
break;
|
||||||
|
};
|
||||||
let powered = command_entity.powered.load(Ordering::Relaxed);
|
let powered = command_entity.powered.load(Ordering::Relaxed);
|
||||||
let auto = command_entity.auto.load(Ordering::Relaxed);
|
let auto = command_entity.auto.load(Ordering::Relaxed);
|
||||||
let state_id = world.get_block_state_id(&pos);
|
let state_id = world.get_block_state_id(&pos);
|
||||||
@ -174,7 +185,10 @@ impl CommandBlock {
|
|||||||
let conditions_met = Self::conditions_met(&world, &pos, direction);
|
let conditions_met = Self::conditions_met(&world, &pos, direction);
|
||||||
if conditions_met {
|
if conditions_met {
|
||||||
let command = command_entity.command.lock().await;
|
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;
|
Self::execute(server, world.clone(), entity, &command).await;
|
||||||
} else if props.conditional {
|
} else if props.conditional {
|
||||||
command_entity.success_count.store(0, Ordering::Release);
|
command_entity.success_count.store(0, Ordering::Release);
|
||||||
@ -238,10 +252,12 @@ impl BlockBehaviour for CommandBlock {
|
|||||||
if block_entity.resource_location() != CommandBlockEntity::ID {
|
if block_entity.resource_location() != CommandBlockEntity::ID {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
let command_entity = block_entity
|
let Some(command_entity) =
|
||||||
.as_any()
|
block_entity.as_any().downcast_ref::<CommandBlockEntity>()
|
||||||
.downcast_ref::<CommandBlockEntity>()
|
else {
|
||||||
.unwrap();
|
warn!("Block entity at {} is not a command block", args.position);
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
Self::update(
|
Self::update(
|
||||||
args.world,
|
args.world,
|
||||||
@ -268,7 +284,11 @@ impl BlockBehaviour for CommandBlock {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let command_entity: &CommandBlockEntity = block_entity.as_any().downcast_ref().unwrap();
|
let Some(command_entity) = block_entity.as_any().downcast_ref::<CommandBlockEntity>()
|
||||||
|
else {
|
||||||
|
warn!("Block entity at {} is not a command block", args.position);
|
||||||
|
return;
|
||||||
|
};
|
||||||
let Some(server) = args.world.server.upgrade() else {
|
let Some(server) = args.world.server.upgrade() else {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -109,7 +109,13 @@ impl FireBlockBase {
|
|||||||
Xoroshiro::from_seed(rand::rng().random()),
|
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`.
|
/// Shared fire collision behavior used by `fire` and `soul_fire`.
|
||||||
|
|||||||
@ -26,8 +26,10 @@ impl BlockBehaviour for LadderBlock {
|
|||||||
let props =
|
let props =
|
||||||
LadderLikeProperties::from_state_id(clicked_block_state_id, clicked_block);
|
LadderLikeProperties::from_state_id(clicked_block_state_id, clicked_block);
|
||||||
let sub = args.position.0.sub(&clicked_pos.0);
|
let sub = args.position.0.sub(&clicked_pos.0);
|
||||||
let dir = horizontal_facing_from_offset(sub).unwrap();
|
if let Some(dir) = horizontal_facing_from_offset(sub)
|
||||||
if props.facing == dir.to_horizontal_facing().unwrap() {
|
&& let Some(horizontal_facing) = dir.to_horizontal_facing()
|
||||||
|
&& props.facing == horizontal_facing
|
||||||
|
{
|
||||||
return Block::AIR.default_state.id;
|
return Block::AIR.default_state.id;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -45,7 +47,7 @@ impl BlockBehaviour for LadderBlock {
|
|||||||
.opposite()
|
.opposite()
|
||||||
.to_block_direction()
|
.to_block_direction()
|
||||||
.to_horizontal_facing()
|
.to_horizontal_facing()
|
||||||
.unwrap();
|
.expect("Opposite of horizontal direction should be horizontal");
|
||||||
return props.to_state_id(args.block);
|
return props.to_state_id(args.block);
|
||||||
}
|
}
|
||||||
Block::AIR.default_state.id
|
Block::AIR.default_state.id
|
||||||
|
|||||||
@ -48,7 +48,8 @@ impl BlockBehaviour for LanternBlock {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn can_place_at(&self, args: CanPlaceAtArgs<'_>) -> bool {
|
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>(
|
fn get_state_for_neighbor_update<'a>(
|
||||||
|
|||||||
@ -216,7 +216,7 @@ impl BlockBehaviour for PistonBlock {
|
|||||||
|
|
||||||
let mut props = PistonProps::default(block);
|
let mut props = PistonProps::default(block);
|
||||||
props.facing = BlockDirection::by_index((data & 7) as usize)
|
props.facing = BlockDirection::by_index((data & 7) as usize)
|
||||||
.unwrap()
|
.expect("Invalid block direction index")
|
||||||
.to_facing();
|
.to_facing();
|
||||||
|
|
||||||
world.add_block_entity(Arc::new(PistonBlockEntity {
|
world.add_block_entity(Arc::new(PistonBlockEntity {
|
||||||
@ -343,7 +343,10 @@ pub async fn try_move(world: &Arc<World>, block: &Block, block_pos: &BlockPos) {
|
|||||||
if new_props.facing == props.facing
|
if new_props.facing == props.facing
|
||||||
&& let Some(entity) = world.get_block_entity(&new_pos)
|
&& let Some(entity) = world.get_block_entity(&new_pos)
|
||||||
{
|
{
|
||||||
let piston = entity.as_any().downcast_ref::<PistonBlockEntity>().unwrap();
|
let piston = entity
|
||||||
|
.as_any()
|
||||||
|
.downcast_ref::<PistonBlockEntity>()
|
||||||
|
.expect("Block entity at MOVING_PISTON should be PistonBlockEntity");
|
||||||
if piston.extending && piston.current_progress.load() < 0.5
|
if piston.extending && piston.current_progress.load() < 0.5
|
||||||
// TODO: more stuff...
|
// TODO: more stuff...
|
||||||
{
|
{
|
||||||
|
|||||||
@ -87,7 +87,8 @@ impl BlockBehaviour for PressurePlateBlock {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn can_place_at(&self, args: CanPlaceAtArgs<'_>) -> bool {
|
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))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -86,7 +86,8 @@ impl BlockBehaviour for WeightedPressurePlateBlock {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn can_place_at(&self, args: CanPlaceAtArgs<'_>) -> bool {
|
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))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -53,7 +53,7 @@ impl BrewingStandBlockEntity {
|
|||||||
fn ingredient_matches(&self, ingredient: &ItemStack) -> bool {
|
fn ingredient_matches(&self, ingredient: &ItemStack) -> bool {
|
||||||
self.ingredient_item
|
self.ingredient_item
|
||||||
.lock()
|
.lock()
|
||||||
.unwrap()
|
.expect("Ingredient item mutex should not be poisoned")
|
||||||
.is_some_and(|stored| !ingredient.is_empty() && ingredient.get_item().id == stored.id)
|
.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()
|
if let Ok(guard) = entity.items[3].try_lock()
|
||||||
&& !guard.is_empty()
|
&& !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
|
// 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);
|
|| 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
|
entity
|
||||||
}
|
}
|
||||||
@ -455,7 +461,11 @@ impl crate::block::entities::BlockEntity for BrewingStandBlockEntity {
|
|||||||
// Start new brewing cycle
|
// Start new brewing cycle
|
||||||
self.fuel.fetch_sub(1, Ordering::Relaxed);
|
self.fuel.fetch_sub(1, Ordering::Relaxed);
|
||||||
self.brew_time.store(400, 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();
|
self.mark_dirty();
|
||||||
} else if fuel_refilled {
|
} else if fuel_refilled {
|
||||||
// Mark dirty if fuel was refilled to update fuel indicator
|
// 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
|
// If potion presence changed, update last_potion_count and update block state so clients
|
||||||
let mut needs_update = false;
|
let mut needs_update = false;
|
||||||
{
|
{
|
||||||
let mut last_guard = self.last_potion_count.lock().unwrap();
|
let mut last_guard = self
|
||||||
if last_guard.is_none() || last_guard.as_ref().unwrap() != ¤t {
|
.last_potion_count
|
||||||
|
.lock()
|
||||||
|
.expect("Last potion count mutex should not be poisoned");
|
||||||
|
if last_guard.as_ref() != Some(¤t) {
|
||||||
*last_guard = Some(current);
|
*last_guard = Some(current);
|
||||||
needs_update = true;
|
needs_update = true;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -34,7 +34,7 @@ macro_rules! impl_block_entity_for_chest {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// Only read saved items when there is no pending loot table.
|
// 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);
|
chest.read_data(nbt, &chest.items);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -50,7 +50,7 @@ macro_rules! impl_block_entity_for_chest {
|
|||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
// Clone the loot table key without holding the lock across an await.
|
// Clone the loot table key without holding the lock across an await.
|
||||||
let loot_table_key = {
|
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()
|
guard.clone()
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -100,12 +100,12 @@ macro_rules! impl_block_entity_for_chest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn take_loot_table(&self) -> Option<(String, i64)> {
|
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))
|
guard.take().map(|key| (key, self.loot_table_seed))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn has_loot_table(&self) -> bool {
|
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()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@ -135,7 +135,11 @@ macro_rules! impl_cooking_block_entity_base {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if let Some(recipe_output_item) = pumpkin_data::item::Item::from_registry_key(
|
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
|
) && !is_top_items_empty
|
||||||
&& recipe_output_item.id == side_item_stack.item.id
|
&& recipe_output_item.id == side_item_stack.item.id
|
||||||
&& side_item_stack.item_count < max_count
|
&& side_item_stack.item_count < max_count
|
||||||
@ -156,7 +160,11 @@ macro_rules! impl_cooking_block_entity_base {
|
|||||||
if can_accept_output {
|
if can_accept_output {
|
||||||
let mut side_items = self.items[2].lock().await;
|
let mut side_items = self.items[2].lock().await;
|
||||||
let Some(output_item) = pumpkin_data::item::Item::from_registry_key(
|
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 {
|
) else {
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
|
|||||||
@ -86,9 +86,14 @@ pub trait BlockEntity: Any + Send + Sync {
|
|||||||
pumpkin_data::block_properties::BLOCK_ENTITY_TYPES
|
pumpkin_data::block_properties::BLOCK_ENTITY_TYPES
|
||||||
.iter()
|
.iter()
|
||||||
.position(|block_entity_name| {
|
.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)
|
/// 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]
|
#[must_use]
|
||||||
pub fn block_entity_from_generic<T: BlockEntity>(nbt: &NbtCompound) -> T {
|
pub fn block_entity_from_generic<T: BlockEntity>(nbt: &NbtCompound) -> T {
|
||||||
let x = nbt.get_int("x").unwrap();
|
let x = nbt.get_int("x").expect("NBT should have x coordinate");
|
||||||
let y = nbt.get_int("y").unwrap();
|
let y = nbt.get_int("y").expect("NBT should have y coordinate");
|
||||||
let z = nbt.get_int("z").unwrap();
|
let z = nbt.get_int("z").expect("NBT should have z coordinate");
|
||||||
T::from_nbt(nbt, BlockPos::new(x, y, z))
|
T::from_nbt(nbt, BlockPos::new(x, y, z))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -158,7 +158,7 @@ impl From<Text> for NbtTag {
|
|||||||
value
|
value
|
||||||
.messages
|
.messages
|
||||||
.lock()
|
.lock()
|
||||||
.unwrap()
|
.expect("Text messages mutex should not be poisoned")
|
||||||
.iter()
|
.iter()
|
||||||
.map(|s| Self::String(s.clone()))
|
.map(|s| Self::String(s.clone()))
|
||||||
.collect(),
|
.collect(),
|
||||||
@ -172,7 +172,7 @@ impl From<NbtTag> for Text {
|
|||||||
fn from(tag: NbtTag) -> Self {
|
fn from(tag: NbtTag) -> Self {
|
||||||
let nbt = tag.extract_compound().unwrap();
|
let nbt = tag.extract_compound().unwrap();
|
||||||
let has_glowing_text = nbt.get_bool("has_glowing_text").unwrap_or(false);
|
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<Box<str>> = nbt
|
let messages: Vec<Box<str>> = nbt
|
||||||
.get_list("messages")
|
.get_list("messages")
|
||||||
.unwrap()
|
.unwrap()
|
||||||
@ -226,8 +226,16 @@ impl BlockEntity for SignBlockEntity {
|
|||||||
where
|
where
|
||||||
Self: Sized,
|
Self: Sized,
|
||||||
{
|
{
|
||||||
let front_text = Text::from(nbt.get("front_text").unwrap().clone());
|
let front_text = nbt
|
||||||
let back_text = Text::from(nbt.get("back_text").unwrap().clone());
|
.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);
|
let is_waxed = nbt.get_bool("is_waxed").unwrap_or(false);
|
||||||
Self {
|
Self {
|
||||||
position,
|
position,
|
||||||
|
|||||||
@ -471,7 +471,7 @@ mod test {
|
|||||||
let Err(error) = parse_target_selector_with_context(raw_arg) else {
|
let Err(error) = parse_target_selector_with_context(raw_arg) else {
|
||||||
panic!("expected selector parsing to fail");
|
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);
|
assert_eq!(cursor, 7);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -484,7 +484,9 @@ mod test {
|
|||||||
end: input.len(),
|
end: input.len(),
|
||||||
input,
|
input,
|
||||||
};
|
};
|
||||||
let selector = "@e".parse::<TargetSelector>().unwrap();
|
let selector = "@e"
|
||||||
|
.parse::<TargetSelector>()
|
||||||
|
.expect("Selector should be valid");
|
||||||
|
|
||||||
let error = ensure_player_only_selector(&selector, raw_arg).unwrap_err();
|
let error = ensure_player_only_selector(&selector, raw_arg).unwrap_err();
|
||||||
let translate_key = match error.message.0.content.as_ref() {
|
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!(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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -423,6 +423,6 @@ mod test {
|
|||||||
_ => "",
|
_ => "",
|
||||||
};
|
};
|
||||||
assert_eq!(translate_key, translation::java::ARGUMENT_PLAYER_UNKNOWN);
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -162,7 +162,10 @@ impl EntitySelector {
|
|||||||
) -> Result<Arc<Player>, CommandSyntaxError> {
|
) -> Result<Arc<Player>, CommandSyntaxError> {
|
||||||
let list = self.find_players(source).await?;
|
let list = self.find_players(source).await?;
|
||||||
if list.len() == 1 {
|
if list.len() == 1 {
|
||||||
Ok(list.first().unwrap().clone())
|
Ok(list
|
||||||
|
.first()
|
||||||
|
.expect("List length is 1, so first should exist")
|
||||||
|
.clone())
|
||||||
} else {
|
} else {
|
||||||
Err(entity::NO_PLAYERS_ERROR_TYPE.create_without_context())
|
Err(entity::NO_PLAYERS_ERROR_TYPE.create_without_context())
|
||||||
}
|
}
|
||||||
|
|||||||
@ -250,7 +250,7 @@ impl<'b, 'a> EntitySelectorParser<'b, 'a> {
|
|||||||
return Err(MISSING_SELECTOR_TYPE_ERROR_TYPE.create(self.reader));
|
return Err(MISSING_SELECTOR_TYPE_ERROR_TYPE.create(self.reader));
|
||||||
}
|
}
|
||||||
let i = self.reader.cursor();
|
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;
|
let mut add_alive_predicate = false;
|
||||||
match char {
|
match char {
|
||||||
'a' => {
|
'a' => {
|
||||||
|
|||||||
@ -93,7 +93,7 @@ impl CommandExecutor for GiveExecutor {
|
|||||||
.living_entity
|
.living_entity
|
||||||
.get_effect(effect)
|
.get_effect(effect)
|
||||||
.await
|
.await
|
||||||
.unwrap()
|
.expect("Effect should exist because has_effect returned true")
|
||||||
.amplifier
|
.amplifier
|
||||||
>= amplifier
|
>= amplifier
|
||||||
{
|
{
|
||||||
|
|||||||
@ -65,7 +65,7 @@ impl CommandExecutor for Executor {
|
|||||||
.find_map(|(id, component)| {
|
.find_map(|(id, component)| {
|
||||||
(id == &MaxStackSize).then(|| get::<MaxStackSizeImpl>(*component).size)
|
(id == &MaxStackSize).then(|| get::<MaxStackSizeImpl>(*component).size)
|
||||||
})
|
})
|
||||||
.unwrap(),
|
.expect("Item should have MaxStackSize component"),
|
||||||
);
|
);
|
||||||
let mut remaining = item_count;
|
let mut remaining = item_count;
|
||||||
|
|
||||||
|
|||||||
@ -176,7 +176,7 @@ fn register_permissions(registry: &mut PermissionRegistry) {
|
|||||||
"Allows a player to use selector variables",
|
"Allows a player to use selector variables",
|
||||||
PermissionDefault::Allow,
|
PermissionDefault::Allow,
|
||||||
))
|
))
|
||||||
.unwrap();
|
.expect("Permission already registered");
|
||||||
}
|
}
|
||||||
|
|
||||||
fn register_level_0_permissions(registry: &mut PermissionRegistry) {
|
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",
|
"Shows information about the Pumpkin server",
|
||||||
PermissionDefault::Allow,
|
PermissionDefault::Allow,
|
||||||
))
|
))
|
||||||
.unwrap();
|
.expect("Permission already registered");
|
||||||
registry
|
registry
|
||||||
.register_permission(Permission::new(
|
.register_permission(Permission::new(
|
||||||
"minecraft:command.me",
|
"minecraft:command.me",
|
||||||
"Broadcasts a narrative message about the player",
|
"Broadcasts a narrative message about the player",
|
||||||
PermissionDefault::Allow,
|
PermissionDefault::Allow,
|
||||||
))
|
))
|
||||||
.unwrap();
|
.expect("Permission already registered");
|
||||||
registry
|
registry
|
||||||
.register_permission(Permission::new(
|
.register_permission(Permission::new(
|
||||||
"minecraft:command.msg",
|
"minecraft:command.msg",
|
||||||
"Sends a private message to another player",
|
"Sends a private message to another player",
|
||||||
PermissionDefault::Allow,
|
PermissionDefault::Allow,
|
||||||
))
|
))
|
||||||
.unwrap();
|
.expect("Permission already registered");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[expect(clippy::too_many_lines)]
|
#[expect(clippy::too_many_lines)]
|
||||||
@ -213,189 +213,189 @@ fn register_level_2_permissions(registry: &mut PermissionRegistry) {
|
|||||||
"Manages the world border",
|
"Manages the world border",
|
||||||
PermissionDefault::Op(PermissionLvl::Two),
|
PermissionDefault::Op(PermissionLvl::Two),
|
||||||
))
|
))
|
||||||
.unwrap();
|
.expect("Permission already registered");
|
||||||
registry
|
registry
|
||||||
.register_permission(Permission::new(
|
.register_permission(Permission::new(
|
||||||
"minecraft:command.effect",
|
"minecraft:command.effect",
|
||||||
"Adds or removes status effects",
|
"Adds or removes status effects",
|
||||||
PermissionDefault::Op(PermissionLvl::Two),
|
PermissionDefault::Op(PermissionLvl::Two),
|
||||||
))
|
))
|
||||||
.unwrap();
|
.expect("Permission already registered");
|
||||||
registry
|
registry
|
||||||
.register_permission(Permission::new(
|
.register_permission(Permission::new(
|
||||||
"minecraft:command.teleport",
|
"minecraft:command.teleport",
|
||||||
"Teleports entities to other locations",
|
"Teleports entities to other locations",
|
||||||
PermissionDefault::Op(PermissionLvl::Two),
|
PermissionDefault::Op(PermissionLvl::Two),
|
||||||
))
|
))
|
||||||
.unwrap();
|
.expect("Permission already registered");
|
||||||
registry
|
registry
|
||||||
.register_permission(Permission::new(
|
.register_permission(Permission::new(
|
||||||
"minecraft:command.time",
|
"minecraft:command.time",
|
||||||
"Changes or queries the world's game time",
|
"Changes or queries the world's game time",
|
||||||
PermissionDefault::Op(PermissionLvl::Two),
|
PermissionDefault::Op(PermissionLvl::Two),
|
||||||
))
|
))
|
||||||
.unwrap();
|
.expect("Permission already registered");
|
||||||
registry
|
registry
|
||||||
.register_permission(Permission::new(
|
.register_permission(Permission::new(
|
||||||
"minecraft:command.give",
|
"minecraft:command.give",
|
||||||
"Gives an item to a player",
|
"Gives an item to a player",
|
||||||
PermissionDefault::Op(PermissionLvl::Two),
|
PermissionDefault::Op(PermissionLvl::Two),
|
||||||
))
|
))
|
||||||
.unwrap();
|
.expect("Permission already registered");
|
||||||
registry
|
registry
|
||||||
.register_permission(Permission::new(
|
.register_permission(Permission::new(
|
||||||
"minecraft:command.clear",
|
"minecraft:command.clear",
|
||||||
"Clears items from player inventory",
|
"Clears items from player inventory",
|
||||||
PermissionDefault::Op(PermissionLvl::Two),
|
PermissionDefault::Op(PermissionLvl::Two),
|
||||||
))
|
))
|
||||||
.unwrap();
|
.expect("Permission already registered");
|
||||||
registry
|
registry
|
||||||
.register_permission(Permission::new(
|
.register_permission(Permission::new(
|
||||||
"minecraft:command.setblock",
|
"minecraft:command.setblock",
|
||||||
"Changes a block to another block",
|
"Changes a block to another block",
|
||||||
PermissionDefault::Op(PermissionLvl::Two),
|
PermissionDefault::Op(PermissionLvl::Two),
|
||||||
))
|
))
|
||||||
.unwrap();
|
.expect("Permission already registered");
|
||||||
registry
|
registry
|
||||||
.register_permission(Permission::new(
|
.register_permission(Permission::new(
|
||||||
"minecraft:command.fill",
|
"minecraft:command.fill",
|
||||||
"Fills a region with a specific block",
|
"Fills a region with a specific block",
|
||||||
PermissionDefault::Op(PermissionLvl::Two),
|
PermissionDefault::Op(PermissionLvl::Two),
|
||||||
))
|
))
|
||||||
.unwrap();
|
.expect("Permission already registered");
|
||||||
registry
|
registry
|
||||||
.register_permission(Permission::new(
|
.register_permission(Permission::new(
|
||||||
"minecraft:command.playsound",
|
"minecraft:command.playsound",
|
||||||
"Plays a sound to players",
|
"Plays a sound to players",
|
||||||
PermissionDefault::Op(PermissionLvl::Two),
|
PermissionDefault::Op(PermissionLvl::Two),
|
||||||
))
|
))
|
||||||
.unwrap();
|
.expect("Permission already registered");
|
||||||
registry
|
registry
|
||||||
.register_permission(Permission::new(
|
.register_permission(Permission::new(
|
||||||
"minecraft:command.tellraw",
|
"minecraft:command.tellraw",
|
||||||
"Displays a JSON message to players",
|
"Displays a JSON message to players",
|
||||||
PermissionDefault::Op(PermissionLvl::Two),
|
PermissionDefault::Op(PermissionLvl::Two),
|
||||||
))
|
))
|
||||||
.unwrap();
|
.expect("Permission already registered");
|
||||||
registry
|
registry
|
||||||
.register_permission(Permission::new(
|
.register_permission(Permission::new(
|
||||||
"minecraft:command.title",
|
"minecraft:command.title",
|
||||||
"Controls screen titles displayed to players",
|
"Controls screen titles displayed to players",
|
||||||
PermissionDefault::Op(PermissionLvl::Two),
|
PermissionDefault::Op(PermissionLvl::Two),
|
||||||
))
|
))
|
||||||
.unwrap();
|
.expect("Permission already registered");
|
||||||
registry
|
registry
|
||||||
.register_permission(Permission::new(
|
.register_permission(Permission::new(
|
||||||
"minecraft:command.summon",
|
"minecraft:command.summon",
|
||||||
"Summons an entity",
|
"Summons an entity",
|
||||||
PermissionDefault::Op(PermissionLvl::Two),
|
PermissionDefault::Op(PermissionLvl::Two),
|
||||||
))
|
))
|
||||||
.unwrap();
|
.expect("Permission already registered");
|
||||||
registry
|
registry
|
||||||
.register_permission(Permission::new(
|
.register_permission(Permission::new(
|
||||||
"minecraft:command.experience",
|
"minecraft:command.experience",
|
||||||
"Adds, removes or queries player experience",
|
"Adds, removes or queries player experience",
|
||||||
PermissionDefault::Op(PermissionLvl::Two),
|
PermissionDefault::Op(PermissionLvl::Two),
|
||||||
))
|
))
|
||||||
.unwrap();
|
.expect("Permission already registered");
|
||||||
registry
|
registry
|
||||||
.register_permission(Permission::new(
|
.register_permission(Permission::new(
|
||||||
"minecraft:command.weather",
|
"minecraft:command.weather",
|
||||||
"Sets the weather in the server",
|
"Sets the weather in the server",
|
||||||
PermissionDefault::Op(PermissionLvl::Two),
|
PermissionDefault::Op(PermissionLvl::Two),
|
||||||
))
|
))
|
||||||
.unwrap();
|
.expect("Permission already registered");
|
||||||
registry
|
registry
|
||||||
.register_permission(Permission::new(
|
.register_permission(Permission::new(
|
||||||
"minecraft:command.particle",
|
"minecraft:command.particle",
|
||||||
"Creates particles in the world",
|
"Creates particles in the world",
|
||||||
PermissionDefault::Op(PermissionLvl::Two),
|
PermissionDefault::Op(PermissionLvl::Two),
|
||||||
))
|
))
|
||||||
.unwrap();
|
.expect("Permission already registered");
|
||||||
registry
|
registry
|
||||||
.register_permission(Permission::new(
|
.register_permission(Permission::new(
|
||||||
"minecraft:command.rotate",
|
"minecraft:command.rotate",
|
||||||
"Changes the rotation of an entity",
|
"Changes the rotation of an entity",
|
||||||
PermissionDefault::Op(PermissionLvl::Two),
|
PermissionDefault::Op(PermissionLvl::Two),
|
||||||
))
|
))
|
||||||
.unwrap();
|
.expect("Permission already registered");
|
||||||
registry
|
registry
|
||||||
.register_permission(Permission::new(
|
.register_permission(Permission::new(
|
||||||
"minecraft:command.damage",
|
"minecraft:command.damage",
|
||||||
"Damages entities",
|
"Damages entities",
|
||||||
PermissionDefault::Op(PermissionLvl::Two),
|
PermissionDefault::Op(PermissionLvl::Two),
|
||||||
))
|
))
|
||||||
.unwrap();
|
.expect("Permission already registered");
|
||||||
registry
|
registry
|
||||||
.register_permission(Permission::new(
|
.register_permission(Permission::new(
|
||||||
"minecraft:command.bossbar",
|
"minecraft:command.bossbar",
|
||||||
"Creates and manages boss bars",
|
"Creates and manages boss bars",
|
||||||
PermissionDefault::Op(PermissionLvl::Two),
|
PermissionDefault::Op(PermissionLvl::Two),
|
||||||
))
|
))
|
||||||
.unwrap();
|
.expect("Permission already registered");
|
||||||
registry
|
registry
|
||||||
.register_permission(Permission::new(
|
.register_permission(Permission::new(
|
||||||
"minecraft:command.say",
|
"minecraft:command.say",
|
||||||
"Broadcasts a message to multiple players",
|
"Broadcasts a message to multiple players",
|
||||||
PermissionDefault::Op(PermissionLvl::Two),
|
PermissionDefault::Op(PermissionLvl::Two),
|
||||||
))
|
))
|
||||||
.unwrap();
|
.expect("Permission already registered");
|
||||||
registry
|
registry
|
||||||
.register_permission(Permission::new(
|
.register_permission(Permission::new(
|
||||||
"minecraft:command.gamemode",
|
"minecraft:command.gamemode",
|
||||||
"Sets a player's game mode",
|
"Sets a player's game mode",
|
||||||
PermissionDefault::Op(PermissionLvl::Two),
|
PermissionDefault::Op(PermissionLvl::Two),
|
||||||
))
|
))
|
||||||
.unwrap();
|
.expect("Permission already registered");
|
||||||
registry
|
registry
|
||||||
.register_permission(Permission::new(
|
.register_permission(Permission::new(
|
||||||
"minecraft:command.gamerule",
|
"minecraft:command.gamerule",
|
||||||
"Sets a player's game mode",
|
"Sets a player's game mode",
|
||||||
PermissionDefault::Op(PermissionLvl::Two),
|
PermissionDefault::Op(PermissionLvl::Two),
|
||||||
))
|
))
|
||||||
.unwrap();
|
.expect("Permission already registered");
|
||||||
registry
|
registry
|
||||||
.register_permission(Permission::new(
|
.register_permission(Permission::new(
|
||||||
"minecraft:command.stopsound",
|
"minecraft:command.stopsound",
|
||||||
"Stops sounds from playing",
|
"Stops sounds from playing",
|
||||||
PermissionDefault::Op(PermissionLvl::Two),
|
PermissionDefault::Op(PermissionLvl::Two),
|
||||||
))
|
))
|
||||||
.unwrap();
|
.expect("Permission already registered");
|
||||||
registry
|
registry
|
||||||
.register_permission(Permission::new(
|
.register_permission(Permission::new(
|
||||||
"minecraft:command.defaultgamemode",
|
"minecraft:command.defaultgamemode",
|
||||||
"Sets the default game mode for new players",
|
"Sets the default game mode for new players",
|
||||||
PermissionDefault::Op(PermissionLvl::Two),
|
PermissionDefault::Op(PermissionLvl::Two),
|
||||||
))
|
))
|
||||||
.unwrap();
|
.expect("Permission already registered");
|
||||||
registry
|
registry
|
||||||
.register_permission(Permission::new(
|
.register_permission(Permission::new(
|
||||||
"minecraft:command.data",
|
"minecraft:command.data",
|
||||||
"Query and modify data of entities and blocks",
|
"Query and modify data of entities and blocks",
|
||||||
PermissionDefault::Op(PermissionLvl::Two),
|
PermissionDefault::Op(PermissionLvl::Two),
|
||||||
))
|
))
|
||||||
.unwrap();
|
.expect("Permission already registered");
|
||||||
registry
|
registry
|
||||||
.register_permission(Permission::new(
|
.register_permission(Permission::new(
|
||||||
"minecraft:command.enchant",
|
"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.",
|
"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),
|
PermissionDefault::Op(PermissionLvl::Two),
|
||||||
))
|
))
|
||||||
.unwrap();
|
.expect("Permission already registered");
|
||||||
registry
|
registry
|
||||||
.register_permission(Permission::new(
|
.register_permission(Permission::new(
|
||||||
"minecraft:command.spawnpoint",
|
"minecraft:command.spawnpoint",
|
||||||
"Sets the spawn point for a player",
|
"Sets the spawn point for a player",
|
||||||
PermissionDefault::Op(PermissionLvl::Two),
|
PermissionDefault::Op(PermissionLvl::Two),
|
||||||
))
|
))
|
||||||
.unwrap();
|
.expect("Permission already registered");
|
||||||
registry
|
registry
|
||||||
.register_permission(Permission::new(
|
.register_permission(Permission::new(
|
||||||
"pumpkin:command.tps",
|
"pumpkin:command.tps",
|
||||||
"Displays the server TPS and MSPT",
|
"Displays the server TPS and MSPT",
|
||||||
PermissionDefault::Op(PermissionLvl::Two),
|
PermissionDefault::Op(PermissionLvl::Two),
|
||||||
))
|
))
|
||||||
.unwrap();
|
.expect("Permission already registered");
|
||||||
}
|
}
|
||||||
|
|
||||||
fn register_level_3_permissions(registry: &mut PermissionRegistry) {
|
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",
|
"Sets the world spawn point",
|
||||||
PermissionDefault::Op(PermissionLvl::Three),
|
PermissionDefault::Op(PermissionLvl::Three),
|
||||||
))
|
))
|
||||||
.unwrap();
|
.expect("Permission already registered");
|
||||||
registry
|
registry
|
||||||
.register_permission(Permission::new(
|
.register_permission(Permission::new(
|
||||||
"minecraft:command.deop",
|
"minecraft:command.deop",
|
||||||
"Revokes operator status from a player",
|
"Revokes operator status from a player",
|
||||||
PermissionDefault::Op(PermissionLvl::Three),
|
PermissionDefault::Op(PermissionLvl::Three),
|
||||||
))
|
))
|
||||||
.unwrap();
|
.expect("Permission already registered");
|
||||||
registry
|
registry
|
||||||
.register_permission(Permission::new(
|
.register_permission(Permission::new(
|
||||||
"minecraft:command.kick",
|
"minecraft:command.kick",
|
||||||
"Removes players from the server",
|
"Removes players from the server",
|
||||||
PermissionDefault::Op(PermissionLvl::Three),
|
PermissionDefault::Op(PermissionLvl::Three),
|
||||||
))
|
))
|
||||||
.unwrap();
|
.expect("Permission already registered");
|
||||||
registry
|
registry
|
||||||
.register_permission(Permission::new(
|
.register_permission(Permission::new(
|
||||||
"pumpkin:command.plugin",
|
"pumpkin:command.plugin",
|
||||||
"Manages server plugins",
|
"Manages server plugins",
|
||||||
PermissionDefault::Op(PermissionLvl::Three),
|
PermissionDefault::Op(PermissionLvl::Three),
|
||||||
))
|
))
|
||||||
.unwrap();
|
.expect("Permission already registered");
|
||||||
registry
|
registry
|
||||||
.register_permission(Permission::new(
|
.register_permission(Permission::new(
|
||||||
"pumpkin:command.plugins",
|
"pumpkin:command.plugins",
|
||||||
"Lists all plugins loaded on the server",
|
"Lists all plugins loaded on the server",
|
||||||
PermissionDefault::Op(PermissionLvl::Three),
|
PermissionDefault::Op(PermissionLvl::Three),
|
||||||
))
|
))
|
||||||
.unwrap();
|
.expect("Permission already registered");
|
||||||
registry
|
registry
|
||||||
.register_permission(Permission::new(
|
.register_permission(Permission::new(
|
||||||
"minecraft:command.ban",
|
"minecraft:command.ban",
|
||||||
"Adds players to banlist",
|
"Adds players to banlist",
|
||||||
PermissionDefault::Op(PermissionLvl::Three),
|
PermissionDefault::Op(PermissionLvl::Three),
|
||||||
))
|
))
|
||||||
.unwrap();
|
.expect("Permission already registered");
|
||||||
registry
|
registry
|
||||||
.register_permission(Permission::new(
|
.register_permission(Permission::new(
|
||||||
"minecraft:command.banip",
|
"minecraft:command.banip",
|
||||||
"Adds IP addresses to banlist",
|
"Adds IP addresses to banlist",
|
||||||
PermissionDefault::Op(PermissionLvl::Three),
|
PermissionDefault::Op(PermissionLvl::Three),
|
||||||
))
|
))
|
||||||
.unwrap();
|
.expect("Permission already registered");
|
||||||
registry
|
registry
|
||||||
.register_permission(Permission::new(
|
.register_permission(Permission::new(
|
||||||
"minecraft:command.pardon",
|
"minecraft:command.pardon",
|
||||||
"Removes entries from the player banlist",
|
"Removes entries from the player banlist",
|
||||||
PermissionDefault::Op(PermissionLvl::Three),
|
PermissionDefault::Op(PermissionLvl::Three),
|
||||||
))
|
))
|
||||||
.unwrap();
|
.expect("Permission already registered");
|
||||||
registry
|
registry
|
||||||
.register_permission(Permission::new(
|
.register_permission(Permission::new(
|
||||||
"minecraft:command.pardonip",
|
"minecraft:command.pardonip",
|
||||||
"Removes entries from the IP banlist",
|
"Removes entries from the IP banlist",
|
||||||
PermissionDefault::Op(PermissionLvl::Three),
|
PermissionDefault::Op(PermissionLvl::Three),
|
||||||
))
|
))
|
||||||
.unwrap();
|
.expect("Permission already registered");
|
||||||
registry
|
registry
|
||||||
.register_permission(Permission::new(
|
.register_permission(Permission::new(
|
||||||
"minecraft:command.whitelist",
|
"minecraft:command.whitelist",
|
||||||
"Manages server whitelist",
|
"Manages server whitelist",
|
||||||
PermissionDefault::Op(PermissionLvl::Three),
|
PermissionDefault::Op(PermissionLvl::Three),
|
||||||
))
|
))
|
||||||
.unwrap();
|
.expect("Permission already registered");
|
||||||
registry
|
registry
|
||||||
.register_permission(Permission::new(
|
.register_permission(Permission::new(
|
||||||
"minecraft:command.transfer",
|
"minecraft:command.transfer",
|
||||||
"Transfers the player to another server",
|
"Transfers the player to another server",
|
||||||
PermissionDefault::Op(PermissionLvl::Three),
|
PermissionDefault::Op(PermissionLvl::Three),
|
||||||
))
|
))
|
||||||
.unwrap();
|
.expect("Permission already registered");
|
||||||
}
|
}
|
||||||
|
|||||||
@ -57,9 +57,14 @@ fn resolve_sender_world(
|
|||||||
sender: &CommandSender,
|
sender: &CommandSender,
|
||||||
server: &crate::server::Server,
|
server: &crate::server::Server,
|
||||||
) -> std::sync::Arc<World> {
|
) -> std::sync::Arc<World> {
|
||||||
sender
|
sender.world().unwrap_or_else(|| {
|
||||||
.world()
|
server
|
||||||
.unwrap_or_else(|| server.worlds.load().first().unwrap().clone())
|
.worlds
|
||||||
|
.load()
|
||||||
|
.first()
|
||||||
|
.expect("Server should have at least one world")
|
||||||
|
.clone()
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
struct EntitiesToEntityExecutor;
|
struct EntitiesToEntityExecutor;
|
||||||
|
|||||||
@ -99,7 +99,9 @@ impl CommandSender {
|
|||||||
|
|
||||||
let now = time::OffsetDateTime::now_utc();
|
let now = time::OffsetDateTime::now_utc();
|
||||||
let format = time::macros::format_description!("[hour]:[minute]:[second]");
|
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());
|
*last_output = format!("[{}] {}", timestamp, text.get_text());
|
||||||
}
|
}
|
||||||
|
|||||||
@ -224,7 +224,12 @@ impl CommandDispatcher {
|
|||||||
pub async fn execute(&self, parsed: ParsingResult<'_>) -> Result<i32, CommandSyntaxError> {
|
pub async fn execute(&self, parsed: ParsingResult<'_>) -> Result<i32, CommandSyntaxError> {
|
||||||
if parsed.reader.peek().is_some() {
|
if parsed.reader.peek().is_some() {
|
||||||
return if parsed.errors.len() == 1 {
|
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() {
|
} else if parsed.context.range.is_empty() {
|
||||||
Err(DISPATCHER_UNKNOWN_COMMAND.create(&parsed.reader))
|
Err(DISPATCHER_UNKNOWN_COMMAND.create(&parsed.reader))
|
||||||
} else {
|
} else {
|
||||||
@ -358,7 +363,7 @@ impl CommandDispatcher {
|
|||||||
|
|
||||||
(a_reader_remaining, a_has_errors).cmp(&(b_reader_remaining, b_has_errors))
|
(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 {
|
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 {
|
if is_optional {
|
||||||
child_usage = format!(
|
child_usage = format!(
|
||||||
"{USAGE_OPTIONAL_OPEN}{child_usage}{USAGE_OPTIONAL_CLOSE}"
|
"{USAGE_OPTIONAL_OPEN}{child_usage}{USAGE_OPTIONAL_CLOSE}"
|
||||||
|
|||||||
@ -17,7 +17,7 @@ use std::ops::{Index, IndexMut};
|
|||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
/// The constant local ID occupied by the root node.
|
/// 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)
|
/// A consumer which takes ambiguity of input (when two or more nodes are satisfied)
|
||||||
pub trait AmbiguityConsumer {
|
pub trait AmbiguityConsumer {
|
||||||
|
|||||||
@ -439,7 +439,7 @@ impl SnbtParser<'_, '_> {
|
|||||||
}
|
}
|
||||||
bytes.push(self.parse_integer_literal(value, TypeSuffix::Byte)?.into());
|
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<NbtTag> {
|
fn create_int_array(&mut self, values: &[IntegerLiteral]) -> Option<NbtTag> {
|
||||||
|
|||||||
@ -76,7 +76,10 @@ macro_rules! assert_parse_err {
|
|||||||
);
|
);
|
||||||
// There should always be a context in SNBT parsing.
|
// There should always be a context in SNBT parsing.
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
error.context.unwrap().cursor,
|
error
|
||||||
|
.context
|
||||||
|
.expect("There should always be a context in SNBT parsing")
|
||||||
|
.cursor,
|
||||||
$cursor,
|
$cursor,
|
||||||
"Cursor positions for error don't match"
|
"Cursor positions for error don't match"
|
||||||
);
|
);
|
||||||
@ -453,7 +456,7 @@ fn lists() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn arrays() {
|
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!("[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]));
|
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;{}]", "Expected literal +", 3, []);
|
||||||
assert_parse_err!("[i;4]", "Expected literal (", 2, []);
|
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_ok!("[L; 0xFFFFFFFFFFFFFFFF]", NbtTag::LongArray(vec![-1]));
|
||||||
assert_parse_err!(
|
assert_parse_err!(
|
||||||
"[L; 0xFFFFFFFFFFFFFFFFF]",
|
"[L; 0xFFFFFFFFFFFFFFFFF]",
|
||||||
|
|||||||
@ -381,9 +381,9 @@ mod test {
|
|||||||
assert!(reader.can_read_chars(7));
|
assert!(reader.can_read_chars(7));
|
||||||
assert!(!reader.can_read_chars(8));
|
assert!(!reader.can_read_chars(8));
|
||||||
|
|
||||||
reader.expect('l').unwrap();
|
reader.expect('l').expect("Expected 'l'");
|
||||||
reader.skip();
|
reader.skip();
|
||||||
reader.expect('o').unwrap();
|
reader.expect('o').expect("Expected 'o'");
|
||||||
|
|
||||||
// Note: 🎃 carries 4 bytes in UTF-8
|
// Note: 🎃 carries 4 bytes in UTF-8
|
||||||
assert!(reader.can_read_bytes(6));
|
assert!(reader.can_read_bytes(6));
|
||||||
@ -422,10 +422,10 @@ mod test {
|
|||||||
assert_eq!(reader.read_long(), Ok(7890123456));
|
assert_eq!(reader.read_long(), Ok(7890123456));
|
||||||
reader.skip_whitespace();
|
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();
|
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();
|
reader.skip_whitespace();
|
||||||
|
|
||||||
assert_eq!(reader.read_bool(), Ok(false));
|
assert_eq!(reader.read_bool(), Ok(false));
|
||||||
|
|||||||
@ -335,7 +335,7 @@ impl Suggestions {
|
|||||||
.iter()
|
.iter()
|
||||||
.map(|s| s.borrow().range)
|
.map(|s| s.borrow().range)
|
||||||
.reduce(StringRange::encompass)
|
.reduce(StringRange::encompass)
|
||||||
.unwrap();
|
.expect("Suggestions list is not empty, so range should exist");
|
||||||
|
|
||||||
let mut texts = Vec::new();
|
let mut texts = Vec::new();
|
||||||
for suggestion in &suggestions {
|
for suggestion in &suggestions {
|
||||||
@ -412,7 +412,9 @@ impl Suggestions {
|
|||||||
|
|
||||||
match side {
|
match side {
|
||||||
PushSide::Text => {
|
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 {
|
suggestions.push(Suggestion {
|
||||||
text: SuggestionText::Text(text.0),
|
text: SuggestionText::Text(text.0),
|
||||||
tooltip: text.1,
|
tooltip: text.1,
|
||||||
@ -420,7 +422,9 @@ impl Suggestions {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
PushSide::Integer => {
|
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 {
|
suggestions.push(Suggestion {
|
||||||
text: SuggestionText::Integer {
|
text: SuggestionText::Integer {
|
||||||
cached_text: text.0,
|
cached_text: text.0,
|
||||||
|
|||||||
@ -42,7 +42,7 @@ pub trait LoadJSONConfiguration {
|
|||||||
where
|
where
|
||||||
Self: Sized + Default + Serialize + for<'de> Deserialize<'de>,
|
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);
|
let data_dir = exe_dir.join(DATA_FOLDER);
|
||||||
if !data_dir.exists() {
|
if !data_dir.exists() {
|
||||||
debug!("creating new data root folder");
|
debug!("creating new data root folder");
|
||||||
@ -63,7 +63,11 @@ pub trait LoadJSONConfiguration {
|
|||||||
} else {
|
} else {
|
||||||
let content = Self::default();
|
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!(
|
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.",
|
"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(),
|
path.display(),
|
||||||
@ -87,7 +91,7 @@ pub trait SaveJSONConfiguration: LoadJSONConfiguration {
|
|||||||
where
|
where
|
||||||
Self: Sized + Default + Serialize + for<'de> Deserialize<'de>,
|
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);
|
let data_dir = exe_dir.join(DATA_FOLDER);
|
||||||
if !data_dir.exists() {
|
if !data_dir.exists() {
|
||||||
debug!("creating new data root folder");
|
debug!("creating new data root folder");
|
||||||
|
|||||||
@ -18,7 +18,7 @@ pub struct AxeItem;
|
|||||||
|
|
||||||
impl ItemMetadata for AxeItem {
|
impl ItemMetadata for AxeItem {
|
||||||
fn ids() -> Box<[u16]> {
|
fn ids() -> Box<[u16]> {
|
||||||
tag::Item::MINECRAFT_AXES.1.to_vec().into_boxed_slice()
|
tag::Item::MINECRAFT_AXES.1.into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -17,7 +17,7 @@ pub struct DyeItem;
|
|||||||
|
|
||||||
impl ItemMetadata for DyeItem {
|
impl ItemMetadata for DyeItem {
|
||||||
fn ids() -> Box<[u16]> {
|
fn ids() -> Box<[u16]> {
|
||||||
tag::Item::C_DYES.1.to_vec().into_boxed_slice()
|
tag::Item::C_DYES.1.into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -19,7 +19,7 @@ pub struct HoeItem;
|
|||||||
|
|
||||||
impl ItemMetadata for HoeItem {
|
impl ItemMetadata for HoeItem {
|
||||||
fn ids() -> Box<[u16]> {
|
fn ids() -> Box<[u16]> {
|
||||||
tag::Item::MINECRAFT_HOES.1.to_vec().into_boxed_slice()
|
tag::Item::MINECRAFT_HOES.1.into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -19,7 +19,7 @@ pub struct ShovelItem;
|
|||||||
|
|
||||||
impl ItemMetadata for ShovelItem {
|
impl ItemMetadata for ShovelItem {
|
||||||
fn ids() -> Box<[u16]> {
|
fn ids() -> Box<[u16]> {
|
||||||
tag::Item::MINECRAFT_SHOVELS.1.to_vec().into_boxed_slice()
|
tag::Item::MINECRAFT_SHOVELS.1.into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -7,7 +7,7 @@ pub struct SwordItem;
|
|||||||
|
|
||||||
impl ItemMetadata for SwordItem {
|
impl ItemMetadata for SwordItem {
|
||||||
fn ids() -> Box<[u16]> {
|
fn ids() -> Box<[u16]> {
|
||||||
tag::Item::MINECRAFT_SWORDS.1.to_vec().into_boxed_slice()
|
tag::Item::MINECRAFT_SWORDS.1.into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -697,6 +697,26 @@ pub fn serialize_bedrock_packet(packet: &BClientboundPacket) -> Option<Bytes> {
|
|||||||
crate::net::bedrock::BedrockClient::write_raw_packet(&p, &mut buf).unwrap();
|
crate::net::bedrock::BedrockClient::write_raw_packet(&p, &mut buf).unwrap();
|
||||||
Some(buf.into())
|
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) => {
|
BClientboundPacket::CSetHealth(data) => {
|
||||||
let p = pumpkin_protocol::bedrock::client::CSetHealth {
|
let p = pumpkin_protocol::bedrock::client::CSetHealth {
|
||||||
health: VarInt(data.health),
|
health: VarInt(data.health),
|
||||||
@ -728,6 +748,16 @@ pub fn serialize_bedrock_packet(packet: &BClientboundPacket) -> Option<Bytes> {
|
|||||||
crate::net::bedrock::BedrockClient::write_raw_packet(&p, &mut buf).unwrap();
|
crate::net::bedrock::BedrockClient::write_raw_packet(&p, &mut buf).unwrap();
|
||||||
Some(buf.into())
|
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,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -181,7 +181,7 @@ impl Scoreboard {
|
|||||||
team_name: team.name.clone(),
|
team_name: team.name.clone(),
|
||||||
method: TeamMethod::Create,
|
method: TeamMethod::Create,
|
||||||
parameters: Some(parameters),
|
parameters: Some(parameters),
|
||||||
players: team.players.clone(),
|
players: team.players.clone().into(),
|
||||||
});
|
});
|
||||||
|
|
||||||
self.teams.insert(team.name.clone(), team);
|
self.teams.insert(team.name.clone(), team);
|
||||||
@ -207,7 +207,7 @@ impl Scoreboard {
|
|||||||
team_name: team.name.clone(),
|
team_name: team.name.clone(),
|
||||||
method: TeamMethod::Update,
|
method: TeamMethod::Update,
|
||||||
parameters: Some(parameters),
|
parameters: Some(parameters),
|
||||||
players: Vec::new(),
|
players: Box::new([]),
|
||||||
});
|
});
|
||||||
|
|
||||||
self.teams.insert(team.name.clone(), team);
|
self.teams.insert(team.name.clone(), team);
|
||||||
@ -223,7 +223,7 @@ impl Scoreboard {
|
|||||||
team_name: name.to_string(),
|
team_name: name.to_string(),
|
||||||
method: TeamMethod::Remove,
|
method: TeamMethod::Remove,
|
||||||
parameters: None,
|
parameters: None,
|
||||||
players: Vec::new(),
|
players: Box::new([]),
|
||||||
});
|
});
|
||||||
|
|
||||||
self.teams.remove(name);
|
self.teams.remove(name);
|
||||||
@ -246,7 +246,7 @@ impl Scoreboard {
|
|||||||
team_name: team_name.to_string(),
|
team_name: team_name.to_string(),
|
||||||
method: TeamMethod::AddPlayers,
|
method: TeamMethod::AddPlayers,
|
||||||
parameters: None,
|
parameters: None,
|
||||||
players: vec![player.clone()],
|
players: vec![player.clone()].into(),
|
||||||
});
|
});
|
||||||
|
|
||||||
team.players.push(player);
|
team.players.push(player);
|
||||||
@ -269,7 +269,7 @@ impl Scoreboard {
|
|||||||
team_name: team_name.to_string(),
|
team_name: team_name.to_string(),
|
||||||
method: TeamMethod::RemovePlayers,
|
method: TeamMethod::RemovePlayers,
|
||||||
parameters: None,
|
parameters: None,
|
||||||
players: vec![player.to_string()],
|
players: vec![player.to_string()].into(),
|
||||||
});
|
});
|
||||||
|
|
||||||
team.players.retain(|p| p != player);
|
team.players.retain(|p| p != player);
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user