removed some clones

fix: https://github.com/Pumpkin-MC/Pumpkin/issues/1226
This commit is contained in:
Alexander Medvedev
2025-12-07 22:43:26 +01:00
parent f734230cd6
commit 3829850607
39 changed files with 576 additions and 711 deletions

155
Cargo.lock generated
View File

@@ -2,15 +2,6 @@
# It is not intended for manual editing.
version = 4
[[package]]
name = "addr2line"
version = "0.25.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b5d307320b3181d6d7954e663bd7c774a838b8220fe0593c86d9fb09f498b4b"
dependencies = [
"gimli",
]
[[package]]
name = "adler2"
version = "2.0.1"
@@ -134,9 +125,9 @@ checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61"
[[package]]
name = "async-compression"
version = "0.4.34"
version = "0.4.35"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0e86f6d3dc9dc4352edeea6b8e499e13e3f5dc3b964d7ca5fd411415a3498473"
checksum = "07a926debf178f2d355197f9caddb08e54a9329d44748034bba349c5848cb519"
dependencies = [
"compression-codecs",
"compression-core",
@@ -211,21 +202,6 @@ dependencies = [
"tower-service",
]
[[package]]
name = "backtrace"
version = "0.3.76"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bb531853791a215d7c62a30daf0dde835f381ab5de4589cfe7c649d2cbe92bd6"
dependencies = [
"addr2line",
"cfg-if",
"libc",
"miniz_oxide",
"object",
"rustc-demangle",
"windows-link",
]
[[package]]
name = "base16ct"
version = "0.2.0"
@@ -252,9 +228,9 @@ checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
[[package]]
name = "base64ct"
version = "1.8.0"
version = "1.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "55248b47b0caf0546f7988906588779981c43bb1bc9d0c44087278f80cdb44ba"
checksum = "0e050f626429857a27ddccb31e0aca21356bfa709c04041aefddac081a8f068a"
[[package]]
name = "bitflags"
@@ -306,9 +282,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5"
[[package]]
name = "cc"
version = "1.2.48"
version = "1.2.49"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c481bdbf0ed3b892f6f806287d72acd515b352a4ec27a208489b8c1bc839633a"
checksum = "90583009037521a116abf44494efecd645ba48b6622457080f080b85544e2215"
dependencies = [
"find-msvc-tools",
"shlex",
@@ -425,9 +401,9 @@ dependencies = [
[[package]]
name = "compression-codecs"
version = "0.4.33"
version = "0.4.34"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "302266479cb963552d11bd042013a58ef1adc56768016c8b82b4199488f2d4ad"
checksum = "34a3cbbb8b6eca96f3a5c4bf6938d5b27ced3675d69f95bb51948722870bc323"
dependencies = [
"compression-core",
"flate2",
@@ -576,9 +552,9 @@ dependencies = [
[[package]]
name = "criterion"
version = "0.8.0"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a0dfe5e9e71bdcf4e4954f7d14da74d1cdb92a3a07686452d1509652684b1aab"
checksum = "4d883447757bb0ee46f233e9dc22eb84d93a9508c9b868687b274fc431d886bf"
dependencies = [
"alloca",
"anes",
@@ -600,9 +576,9 @@ dependencies = [
[[package]]
name = "criterion-plot"
version = "0.8.0"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5de36c2bee19fba779808f92bf5d9b0fa5a40095c277aba10c458a12b35d21d6"
checksum = "ed943f81ea2faa8dcecbbfa50164acf95d555afec96a27871663b300e387b2e4"
dependencies = [
"cast",
"itertools 0.13.0",
@@ -832,22 +808,6 @@ dependencies = [
"syn",
]
[[package]]
name = "dhat"
version = "0.3.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "98cd11d84628e233de0ce467de10b8633f4ddaecafadefc86e13b84b8739b827"
dependencies = [
"backtrace",
"lazy_static",
"mintex",
"parking_lot",
"rustc-hash 1.1.0",
"serde",
"serde_json",
"thousands",
]
[[package]]
name = "digest"
version = "0.10.7"
@@ -1008,9 +968,9 @@ checksum = "3a3076410a55c90011c298b04d0cfa770b00fa04e1e3c97d3f6c9de105a03844"
[[package]]
name = "flate2"
version = "1.1.7"
version = "1.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2152dbcb980c05735e2a651d96011320a949eb31a0c8b38b72645ce97dec676"
checksum = "bfe33edd8e85a12a67454e37f8c75e730830d83e313556ab9ebf9ee7fbeb3bfb"
dependencies = [
"crc32fast",
"miniz_oxide",
@@ -1160,12 +1120,6 @@ dependencies = [
"wasip2",
]
[[package]]
name = "gimli"
version = "0.32.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e629b9b98ef3dd8afe6ca2bd0f89306cec16d43d907889945bc5d6687f2f13c7"
[[package]]
name = "group"
version = "0.13.0"
@@ -1666,15 +1620,6 @@ version = "0.11.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08ab2867e3eeeca90e844d1940eab391c9dc5228783db2ed999acbc0a9ed375a"
[[package]]
name = "matchers"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d1525a2a28c7f4fa0fc98bb91ae755d1e2d1505079e05539e35bc876b5d65ae9"
dependencies = [
"regex-automata",
]
[[package]]
name = "matchit"
version = "0.8.4"
@@ -1725,12 +1670,6 @@ dependencies = [
"simd-adler32",
]
[[package]]
name = "mintex"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c505b3e17ed6b70a7ed2e67fbb2c560ee327353556120d6e72f5232b6880d536"
[[package]]
name = "mio"
version = "1.1.1"
@@ -1817,15 +1756,6 @@ dependencies = [
"libc",
]
[[package]]
name = "object"
version = "0.37.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ff76201f031d8863c38aa7f905eca4f53abbfa15f609db4277d44cd8938f33fe"
dependencies = [
"memchr",
]
[[package]]
name = "once_cell"
version = "1.21.3"
@@ -2171,13 +2101,13 @@ dependencies = [
"bytes",
"console-subscriber",
"crossbeam",
"dhat",
"flate2",
"futures",
"hmac 0.13.0-rc.3",
"libloading",
"log",
"num-bigint",
"pkcs8 0.11.0-rc.8",
"pumpkin-config",
"pumpkin-data",
"pumpkin-inventory",
@@ -2188,10 +2118,8 @@ dependencies = [
"pumpkin-util",
"pumpkin-world",
"rand",
"rayon",
"rsa",
"rsa-der",
"rustc-hash 2.1.1",
"rustc-hash",
"rustyline-async",
"serde",
"serde_json",
@@ -2265,7 +2193,6 @@ dependencies = [
name = "pumpkin-macros"
version = "0.1.0-dev+1.21.10"
dependencies = [
"heck",
"proc-macro-error2",
"proc-macro2",
"quote",
@@ -2367,8 +2294,7 @@ dependencies = [
"pumpkin-nbt",
"pumpkin-util",
"rand",
"rayon",
"rustc-hash 2.1.1",
"rustc-hash",
"ruzstd",
"serde",
"serde_json",
@@ -2526,27 +2452,6 @@ dependencies = [
"zeroize",
]
[[package]]
name = "rsa-der"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a19473b2de3164677ff38e4309c42448ba8d0fe5ad5fa722e7d278f991859aa6"
dependencies = [
"simple_asn1",
]
[[package]]
name = "rustc-demangle"
version = "0.1.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace"
[[package]]
name = "rustc-hash"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
[[package]]
name = "rustc-hash"
version = "2.1.1"
@@ -2858,18 +2763,6 @@ version = "0.3.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe"
[[package]]
name = "simple_asn1"
version = "0.6.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "297f631f50729c8c99b84667867963997ec0b50f32b2a7dbcab828ef0541e8bb"
dependencies = [
"num-bigint",
"num-traits",
"thiserror",
"time",
]
[[package]]
name = "simplelog"
version = "0.12.2"
@@ -2896,9 +2789,9 @@ checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589"
[[package]]
name = "slotmap"
version = "1.1.0"
version = "1.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "811fec94324ff439b2d5e4a1cf88cc5b6c09d92358715d600b2fe91c0489b5cb"
checksum = "bdd58c3c93c3d278ca835519292445cb4b0d4dc59ccfdf7ceadaab3f8aeb4038"
dependencies = [
"version_check",
]
@@ -3054,12 +2947,6 @@ dependencies = [
"syn",
]
[[package]]
name = "thousands"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3bf63baf9f5039dadc247375c29eb13706706cfde997d0330d05aa63a77d8820"
[[package]]
name = "thread_local"
version = "1.1.9"
@@ -3323,12 +3210,8 @@ version = "0.3.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2f30143827ddab0d256fd843b7a66d164e9f271cfa0dde49142c5ca0ca291f1e"
dependencies = [
"matchers",
"once_cell",
"regex-automata",
"sharded-slab",
"thread_local",
"tracing",
"tracing-core",
]

View File

@@ -284,7 +284,7 @@ impl ToTokens for ItemComponents {
.clone()
.map(|list| {
let vec: Vec<_> = list
.get_values()
.into_vec()
.iter()
.map(|reg| {
match reg {

View File

@@ -1025,7 +1025,7 @@ pub trait ScreenHandlerListener: Send + Sync {
_slot: u8,
_stack: ItemStack,
) -> Pin<Box<dyn Future<Output = ()> + Send + 'a>> {
Box::pin(async move {})
Box::pin(async {})
}
fn on_property_update<'a>(
&'a self,
@@ -1033,7 +1033,7 @@ pub trait ScreenHandlerListener: Send + Sync {
_property: u8,
_value: i32,
) -> Pin<Box<dyn Future<Output = ()> + Send + 'a>> {
Box::pin(async move {})
Box::pin(async {})
}
}

View File

@@ -38,7 +38,7 @@ pub trait Slot: Send + Sync + Debug {
_stack: ItemStack,
_stack_prev: ItemStack,
) -> BoxFuture<'_, ()> {
Box::pin(async move {}) // Default implementation
Box::pin(async {}) // Default implementation
}
/// Callback for when an item is taken from the slot.
@@ -57,7 +57,7 @@ pub trait Slot: Send + Sync + Debug {
// Used for plugins
fn on_click(&self, _player: &dyn InventoryPlayer) -> BoxFuture<'_, ()> {
Box::pin(async move {}) // Default implementation
Box::pin(async {}) // Default implementation
}
fn can_insert<'a>(&'a self, _stack: &'a ItemStack) -> BoxFuture<'a, bool> {

View File

@@ -9,7 +9,6 @@ proc-macro = true
[dependencies]
proc-macro-error2.workspace = true
heck = "0.5"
proc-macro2 = "1.0"
quote = "1.0"
syn.workspace = true

View File

@@ -1,22 +1,18 @@
use heck::{ToPascalCase, ToSnakeCase};
use proc_macro::TokenStream;
use proc_macro_error2::{abort, abort_call_site, proc_macro_error};
use quote::quote;
use syn::spanned::Spanned;
use syn::{self, Attribute, Type};
use syn::{
Block, Expr, Field, Fields, ItemStruct, Stmt,
parse::{Nothing, Parser},
parse_macro_input,
};
use syn::{self, Attribute, DeriveInput, LitStr, Type, parse_quote};
use syn::{Block, Expr, Field, Fields, ItemStruct, Stmt, parse_macro_input};
#[proc_macro_derive(Event)]
pub fn event(item: TokenStream) -> TokenStream {
let input = parse_macro_input!(item as ItemStruct);
let name = &input.ident;
let ast = parse_macro_input!(item as DeriveInput);
let name = &ast.ident;
let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl();
quote! {
impl crate::plugin::Payload for #name {
impl #impl_generics crate::plugin::Payload for #name #ty_generics #where_clause {
fn get_name_static() -> &'static str {
stringify!(#name)
}
@@ -38,26 +34,36 @@ pub fn event(item: TokenStream) -> TokenStream {
}
#[proc_macro_attribute]
pub fn cancellable(args: TokenStream, input: TokenStream) -> TokenStream {
pub fn cancellable(_args: TokenStream, input: TokenStream) -> TokenStream {
let mut item_struct = parse_macro_input!(input as ItemStruct);
let name = item_struct.ident.clone();
let _ = parse_macro_input!(args as Nothing);
let name = &item_struct.ident;
let (impl_generics, ty_generics, where_clause) = item_struct.generics.split_for_impl();
if let Fields::Named(ref mut fields) = item_struct.fields {
fields.named.push(
Field::parse_named
.parse2(quote! {
/// A boolean indicating cancel state of the event.
pub cancelled: bool
})
.unwrap(),
);
match &mut item_struct.fields {
Fields::Named(fields) => {
if fields
.named
.iter()
.any(|f| f.ident.as_ref().map(|i| i == "cancelled").unwrap_or(false))
{
abort!(fields.span(), "Struct already has a `cancelled` field");
}
let field: Field = parse_quote! {
pub cancelled: bool
};
fields.named.push(field);
}
_ => abort!(
item_struct.span(),
"#[cancellable] can only be used on structs with named fields"
),
}
quote! {
#item_struct
impl crate::plugin::Cancellable for #name {
impl #impl_generics crate::plugin::Cancellable for #name #ty_generics #where_clause {
fn cancelled(&self) -> bool {
self.cancelled
}
@@ -73,115 +79,116 @@ pub fn cancellable(args: TokenStream, input: TokenStream) -> TokenStream {
#[proc_macro_error]
#[proc_macro]
pub fn send_cancellable(input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as Block);
let block = parse_macro_input!(input as Block);
let mut event = None;
let mut event_expr = None;
let mut after_block = None;
let mut cancelled_block = None;
for stmt in input.stmts {
if let Stmt::Expr(expr, _) = stmt {
if event.is_none() {
event = Some(expr);
} else if let Expr::Block(b) = expr
&& let Some(ref label) = b.label
{
if label.name.ident == "after" {
after_block = Some(b);
} else if label.name.ident == "cancelled" {
cancelled_block = Some(b);
for stmt in block.stmts {
match stmt {
Stmt::Expr(expr, _) => {
// Check if it is a labeled block first
let mut is_special_block = false;
if let Expr::Block(ref b) = expr
&& let Some(ref label) = b.label
{
let label_name = label.name.ident.to_string();
if label_name == "after" {
after_block = Some(b.clone()); // Clone strictly necessary here as we split AST
is_special_block = true;
} else if label_name == "cancelled" {
cancelled_block = Some(b.clone());
is_special_block = true;
}
}
// If it wasn't a special block, it must be the event expression
if !is_special_block {
if event_expr.is_some() {
abort!(
expr.span(),
"Multiple event expressions found. Only one event expression allowed."
);
}
event_expr = Some(expr);
}
}
// Abort on other statements (like `let x = ...`) if strictness is desired
_ => abort!(
stmt.span(),
"Only event expressions and labeled blocks allowed in `send_cancellable!`"
),
}
}
if let Some(event) = event {
if let Some(after_block) = after_block {
if let Some(cancelled_block) = cancelled_block {
quote! {
let event = crate::PLUGIN_MANAGER
.fire(#event)
.await;
let event = match event_expr {
Some(e) => e,
None => abort_call_site!("Event expression must be specified"),
};
if !event.cancelled {
#after_block
} else {
#cancelled_block
}
}
.into()
} else {
quote! {
let event = crate::PLUGIN_MANAGER
.fire(#event)
.await;
// Construct the if/else logic
let logic = match (after_block, cancelled_block) {
(Some(after), Some(cancelled)) => quote! {
if !event.cancelled { #after } else { #cancelled }
},
(Some(after), None) => quote! {
if !event.cancelled { #after }
},
(None, Some(cancelled)) => quote! {
if event.cancelled { #cancelled }
},
(None, None) => quote! {},
};
if !event.cancelled {
#after_block
}
}
.into()
}
} else if let Some(cancelled_block) = cancelled_block {
quote! {
let event = crate::PLUGIN_MANAGER
.fire(#event)
.await;
if event.cancelled {
#cancelled_block
}
}
.into()
} else {
quote! {
let event = crate::PLUGIN_MANAGER
.fire(#event)
.await;
}
.into()
}
} else {
abort_call_site!("Event must be specified");
quote! {
let event = crate::PLUGIN_MANAGER.fire(#event).await;
#logic
}
.into()
}
#[proc_macro_attribute]
pub fn packet(input: TokenStream, item: TokenStream) -> TokenStream {
let ast: syn::DeriveInput = syn::parse(item.clone()).unwrap();
pub fn packet(args: TokenStream, item: TokenStream) -> TokenStream {
let packet_id_expr = parse_macro_input!(args as Expr);
let ast = parse_macro_input!(item as DeriveInput);
let name = &ast.ident;
let (impl_generics, ty_generics, _) = ast.generics.split_for_impl();
let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl();
let input: proc_macro2::TokenStream = input.into();
let item: proc_macro2::TokenStream = item.into();
quote! {
#ast
impl #impl_generics crate::packet::Packet for #name #ty_generics #where_clause {
const PACKET_ID: i32 = #packet_id_expr;
}
}
.into()
}
let code = quote! {
#item
impl #impl_generics crate::packet::Packet for #name #ty_generics {
const PACKET_ID: i32 = #input;
#[proc_macro_attribute]
pub fn pumpkin_block(args: TokenStream, item: TokenStream) -> TokenStream {
let arg_lit = parse_macro_input!(args as LitStr);
let arg_value = arg_lit.value();
let (namespace, id) = match arg_value.split_once(':') {
Some(pair) => pair,
None => {
return syn::Error::new(
arg_lit.span(),
"Expected format \"namespace:id\" (e.g. \"minecraft:stone\")",
)
.to_compile_error()
.into();
}
};
code.into()
}
#[proc_macro_attribute]
pub fn pumpkin_block(input: TokenStream, item: TokenStream) -> TokenStream {
let ast: syn::DeriveInput = syn::parse(item.clone()).unwrap();
let ast = parse_macro_input!(item as DeriveInput);
let name = &ast.ident;
let (impl_generics, ty_generics, _) = ast.generics.split_for_impl();
let input_string = input.to_string();
let packet_name = input_string.trim_matches('"');
let (namespace, id) = packet_name
.split_once(":")
.unwrap_or_else(|| abort!(packet_name, "A namespace is required!"));
let item: proc_macro2::TokenStream = item.into();
let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl();
let code = quote! {
#item
impl #impl_generics crate::block::BlockMetadata for #name #ty_generics {
#ast
impl #impl_generics crate::block::BlockMetadata for #name #ty_generics #where_clause {
fn namespace(&self) -> &'static str {
#namespace
}
@@ -195,182 +202,183 @@ pub fn pumpkin_block(input: TokenStream, item: TokenStream) -> TokenStream {
}
#[proc_macro_attribute]
pub fn pumpkin_block_from_tag(input: TokenStream, item: TokenStream) -> TokenStream {
let ast: syn::DeriveInput = syn::parse(item.clone()).unwrap();
pub fn pumpkin_block_from_tag(args: TokenStream, item: TokenStream) -> TokenStream {
let arg_lit = parse_macro_input!(args as LitStr);
let ast = parse_macro_input!(item as DeriveInput);
let name = &ast.ident;
let (impl_generics, ty_generics, _) = ast.generics.split_for_impl();
let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl();
let input_string = input.to_string();
let packet_name = input_string.trim_matches('"');
let packet_name_split: Vec<&str> = packet_name.split(":").collect();
let full_tag = arg_lit.value();
let namespace = packet_name_split[0];
// Efficient splitting
let namespace = match full_tag.split_once(':') {
Some((ns, _)) => ns,
None => abort!(arg_lit.span(), "Expected format 'namespace:path'"),
};
let item: proc_macro2::TokenStream = item.into();
let code = quote! {
#item
impl #impl_generics crate::block::BlockMetadata for #name #ty_generics {
quote! {
#ast
impl #impl_generics crate::block::BlockMetadata for #name #ty_generics #where_clause {
fn namespace(&self) -> &'static str {
#namespace
}
fn ids(&self) -> &'static [&'static str] {
get_tag_values(RegistryKey::Block, #packet_name).unwrap()
get_tag_values(RegistryKey::Block, #arg_lit).unwrap()
}
}
};
code.into()
}
#[proc_macro_error]
#[proc_macro_attribute]
pub fn block_property(input: TokenStream, item: TokenStream) -> TokenStream {
let ast: syn::DeriveInput = syn::parse(item.clone()).unwrap();
let name = &ast.ident;
let (impl_generics, ty_generics, _) = ast.generics.split_for_impl();
let input_string = input.to_string();
let input_parts: Vec<&str> = input_string.split("[").collect();
let property_name = input_parts[0].trim_ascii().trim_matches(&['"', ','][..]);
let mut property_values: Vec<&str> = Vec::new();
if input_parts.len() > 1 {
property_values = input_parts[1]
.trim_matches(']')
.split(", ")
.map(|p| p.trim_ascii().trim_matches(&['"', ','][..]))
.collect::<Vec<&str>>();
}
let item: proc_macro2::TokenStream = item.into();
let (variants, is_enum): (Vec<proc_macro2::Ident>, bool) = match ast.data {
syn::Data::Enum(enum_item) => (
enum_item.variants.into_iter().map(|v| v.ident).collect(),
true,
),
syn::Data::Struct(s) => {
let fields = match s.fields {
Fields::Named(f) => abort!(f.span(), "Block properties can't have named fields"),
Fields::Unnamed(fields) => fields.unnamed,
Fields::Unit => abort!(s.fields.span(), "Block properties must have fields"),
};
if fields.len() != 1 {
abort!(
fields.span(),
"Block properties `struct`s must have exactly one field"
);
}
let field = fields.first().unwrap();
let ty = &field.ty;
let struct_type = match field.ty {
syn::Type::Path(ref type_path) => {
type_path.path.segments.first().unwrap().ident.to_string()
}
ref other => abort!(
other.span(),
"Block properties can only have primitive types"
),
};
match struct_type.as_str() {
"bool" => (
vec![
proc_macro2::Ident::new("true", proc_macro2::Span::call_site()),
proc_macro2::Ident::new("false", proc_macro2::Span::call_site()),
],
false,
),
other => abort!(
ty.span(),
format!("`{other}` is not supported (why not implement it yourself?)")
),
}
}
_ => abort_call_site!("Block properties can only be `enum`s or `struct`s"),
};
let values = variants.iter().enumerate().map(|(i, v)| match is_enum {
true => {
let mut value = v.to_string().to_snake_case();
if !property_values.is_empty() && i < property_values.len() {
value = property_values[i].to_string();
}
quote! {
Self::#v => #value.to_string(),
}
}
false => {
let value = v.to_string();
quote! {
Self(#v) => #value.to_string(),
}
}
});
let from_values = variants.iter().enumerate().map(|(i, v)| match is_enum {
true => {
let mut value = v.to_string().to_snake_case();
if !property_values.is_empty() && i < property_values.len() {
value = property_values[i].to_string();
}
quote! {
#value => Self::#v,
}
}
false => {
let value = v.to_string();
quote! {
#value => Self(#v),
}
}
});
let extra_fns = variants.iter().map(|v| {
let title = proc_macro2::Ident::new(
&v.to_string().to_pascal_case(),
proc_macro2::Span::call_site(),
);
quote! {
pub fn #title() -> Self {
Self(#v)
}
}
});
let extra = if is_enum {
quote! {}
} else {
quote! {
impl #name {
#(#extra_fns)*
}
}
};
let code = quote! {
#item
impl #impl_generics pumpkin_world::block::properties::BlockPropertyMetadata for #name #ty_generics {
fn name(&self) -> &'static str {
#property_name
}
fn value(&self) -> String {
match self {
#(#values)*
}
}
fn from_value(value: String) -> Self {
match value.as_str() {
#(#from_values)*
_ => panic!("Invalid value for block property"),
}
}
}
#extra
};
code.into()
.into()
}
// #[proc_macro_error]
// #[proc_macro_attribute]
// pub fn block_property(input: TokenStream, item: TokenStream) -> TokenStream {
// let ast: syn::DeriveInput = syn::parse(item.clone()).unwrap();
// let name = &ast.ident;
// let (impl_generics, ty_generics, _) = ast.generics.split_for_impl();
// let input_string = input.to_string();
// let input_parts: Vec<&str> = input_string.split("[").collect();
// let property_name = input_parts[0].trim_ascii().trim_matches(&['"', ','][..]);
// let mut property_values: Vec<&str> = Vec::new();
// if input_parts.len() > 1 {
// property_values = input_parts[1]
// .trim_matches(']')
// .split(", ")
// .map(|p| p.trim_ascii().trim_matches(&['"', ','][..]))
// .collect::<Vec<&str>>();
// }
// let item: proc_macro2::TokenStream = item.into();
// let (variants, is_enum): (Vec<proc_macro2::Ident>, bool) = match ast.data {
// syn::Data::Enum(enum_item) => (
// enum_item.variants.into_iter().map(|v| v.ident).collect(),
// true,
// ),
// syn::Data::Struct(s) => {
// let fields = match s.fields {
// Fields::Named(f) => abort!(f.span(), "Block properties can't have named fields"),
// Fields::Unnamed(fields) => fields.unnamed,
// Fields::Unit => abort!(s.fields.span(), "Block properties must have fields"),
// };
// if fields.len() != 1 {
// abort!(
// fields.span(),
// "Block properties `struct`s must have exactly one field"
// );
// }
// let field = fields.first().unwrap();
// let ty = &field.ty;
// let struct_type = match field.ty {
// syn::Type::Path(ref type_path) => {
// type_path.path.segments.first().unwrap().ident.to_string()
// }
// ref other => abort!(
// other.span(),
// "Block properties can only have primitive types"
// ),
// };
// match struct_type.as_str() {
// "bool" => (
// vec![
// proc_macro2::Ident::new("true", proc_macro2::Span::call_site()),
// proc_macro2::Ident::new("false", proc_macro2::Span::call_site()),
// ],
// false,
// ),
// other => abort!(
// ty.span(),
// format!("`{other}` is not supported (why not implement it yourself?)")
// ),
// }
// }
// _ => abort_call_site!("Block properties can only be `enum`s or `struct`s"),
// };
// let values = variants.iter().enumerate().map(|(i, v)| match is_enum {
// true => {
// let mut value = v.to_string().to_snake_case();
// if !property_values.is_empty() && i < property_values.len() {
// value = property_values[i].to_string();
// }
// quote! {
// Self::#v => #value.to_string(),
// }
// }
// false => {
// let value = v.to_string();
// quote! {
// Self(#v) => #value.to_string(),
// }
// }
// });
// let from_values = variants.iter().enumerate().map(|(i, v)| match is_enum {
// true => {
// let mut value = v.to_string().to_snake_case();
// if !property_values.is_empty() && i < property_values.len() {
// value = property_values[i].to_string();
// }
// quote! {
// #value => Self::#v,
// }
// }
// false => {
// let value = v.to_string();
// quote! {
// #value => Self(#v),
// }
// }
// });
// let extra_fns = variants.iter().map(|v| {
// let title = proc_macro2::Ident::new(
// &v.to_string().to_pascal_case(),
// proc_macro2::Span::call_site(),
// );
// quote! {
// pub fn #title() -> Self {
// Self(#v)
// }
// }
// });
// let extra = if is_enum {
// quote! {}
// } else {
// quote! {
// impl #name {
// #(#extra_fns)*
// }
// }
// };
// let code = quote! {
// #item
// impl #impl_generics pumpkin_world::block::properties::BlockPropertyMetadata for #name #ty_generics {
// fn name(&self) -> &'static str {
// #property_name
// }
// fn value(&self) -> String {
// match self {
// #(#values)*
// }
// }
// fn from_value(value: String) -> Self {
// match value.as_str() {
// #(#from_values)*
// _ => panic!("Invalid value for block property"),
// }
// }
// }
// #extra
// };
// code.into()
// }
#[rustfmt::skip]
#[proc_macro_derive(PacketWrite, attributes(serial))]
pub fn derive_serialize(input: TokenStream) -> TokenStream {

View File

@@ -27,11 +27,11 @@ aes = "0.8"
cfb8 = "0.8"
# compression
async-compression = { version = "0.4.34", features = ["tokio", "zlib"] }
async-compression = { version = "0.4.35", features = ["tokio", "zlib"] }
take_mut = "0.2.2"
bitflags = "2.10.0"
[dev-dependencies]
# Validate correctness
flate2 = "1.1.7"
flate2 = "1.1.5"

View File

@@ -45,11 +45,10 @@ pub enum RegistryEntryList {
}
impl RegistryEntryList {
#[allow(dead_code)]
pub fn get_values(&self) -> Vec<TagType> {
pub fn into_vec(self) -> Vec<TagType> {
match self {
RegistryEntryList::Single(s) => vec![s.clone()],
RegistryEntryList::Many(s) => s.clone(),
RegistryEntryList::Single(s) => vec![s],
RegistryEntryList::Many(s) => s,
}
}
}

View File

@@ -24,7 +24,6 @@ tokio = { workspace = true, features = [
"io-util",
"time",
] }
rayon.workspace = true
uuid.workspace = true
thiserror.workspace = true
serde.workspace = true

View File

@@ -29,7 +29,7 @@ impl BlockEntity for BedBlockEntity {
&'a self,
_nbt: &'a mut NbtCompound,
) -> Pin<Box<dyn Future<Output = ()> + Send + 'a>> {
Box::pin(async move {})
Box::pin(async {})
}
fn as_any(&self) -> &dyn std::any::Any {

View File

@@ -48,7 +48,7 @@ impl BlockEntity for CommandBlockEntity {
&'a self,
_nbt: &'a mut NbtCompound,
) -> Pin<Box<dyn Future<Output = ()> + Send + 'a>> {
Box::pin(async move {})
Box::pin(async {})
}
fn is_dirty(&self) -> bool {

View File

@@ -36,7 +36,7 @@ impl BlockEntity for EndPortalBlockEntity {
&'a self,
_nbt: &'a mut NbtCompound,
) -> Pin<Box<dyn Future<Output = ()> + Send + 'a>> {
Box::pin(async move {})
Box::pin(async {})
}
fn as_any(&self) -> &dyn std::any::Any {

View File

@@ -43,7 +43,7 @@ impl BlockEntity for EnderChestBlockEntity {
&'a self,
_nbt: &'a mut NbtCompound,
) -> Pin<Box<dyn Future<Output = ()> + Send + 'a>> {
Box::pin(async move {})
Box::pin(async {})
}
fn tick<'a>(

View File

@@ -51,7 +51,7 @@ pub trait BlockEntity: Send + Sync {
&'a self,
_world: Arc<dyn SimpleWorld>,
) -> Pin<Box<dyn Future<Output = ()> + Send + 'a>> {
Box::pin(async move {})
Box::pin(async {})
}
fn resource_location(&self) -> &'static str;
fn get_position(&self) -> BlockPos;

View File

@@ -271,7 +271,7 @@ impl SignBlockEntity {
Text::default()
},
back_text: if !is_front {
Text::new(messages.clone())
Text::new(messages)
} else {
Text::default()
},

View File

@@ -307,9 +307,9 @@ impl AnvilChunkData {
.decompress_data(&self.compressed_data)
.map_err(ChunkReadingError::Compression)?;
S::from_bytes(decompress_bytes.into(), pos)
S::from_bytes(&decompress_bytes.into(), pos)
} else {
S::from_bytes(self.compressed_data.clone(), pos)
S::from_bytes(&self.compressed_data, pos)
}
}
@@ -521,7 +521,7 @@ pub trait SingleChunkDataSerializer: Send + Sync + Sized + Dirtiable {
fn to_bytes(
&self,
) -> Pin<Box<dyn Future<Output = Result<Bytes, ChunkSerializingError>> + Send + '_>>;
fn from_bytes(bytes: Bytes, pos: Vector2<i32>) -> Result<Self, ChunkReadingError>;
fn from_bytes(bytes: &Bytes, pos: Vector2<i32>) -> Result<Self, ChunkReadingError>;
fn position(&self) -> &Vector2<i32>;
}
@@ -540,7 +540,7 @@ impl<S: SingleChunkDataSerializer> ChunkSerializer for AnvilChunkFile<S> {
format!("./r.{region_x}.{region_z}.mca")
}
async fn write(&self, path: PathBuf) -> Result<(), std::io::Error> {
async fn write(&self, path: &PathBuf) -> Result<(), std::io::Error> {
let mut write_action = self.write_action.lock().await;
match &*write_action {
WriteAction::Pass => {
@@ -550,9 +550,9 @@ impl<S: SingleChunkDataSerializer> ChunkSerializer for AnvilChunkFile<S> {
);
Ok(())
}
WriteAction::All => self.write_all(&path).await,
WriteAction::All => self.write_all(path).await,
WriteAction::Parts(parts) => {
self.write_indices(&path, Vec::from_iter(parts.iter().cloned()).as_slice())
self.write_indices(path, Vec::from_iter(parts.iter().cloned()).as_slice())
.await
}
}?;

View File

@@ -178,7 +178,7 @@ impl<S: SingleChunkDataSerializer> ChunkSerializer for LinearFile<S> {
format!("./r.{region_x}.{region_z}.linear")
}
async fn write(&self, path: PathBuf) -> Result<(), std::io::Error> {
async fn write(&self, path: &PathBuf) -> Result<(), std::io::Error> {
let temp_path = path.with_extension("tmp");
log::trace!("Writing tmp file to disk: {}", temp_path.display());
@@ -358,7 +358,7 @@ impl<S: SingleChunkDataSerializer> ChunkSerializer for LinearFile<S> {
let linear_chunk_data = &self.chunks_data[index];
let result = if let Some(data) = linear_chunk_data {
match S::from_bytes(data.clone(), chunk) {
match S::from_bytes(data, chunk) {
Ok(chunk) => LoadedData::Loaded(chunk),
Err(err) => LoadedData::Error((chunk, err)),
}

View File

@@ -31,8 +31,8 @@ pub mod linear;
impl SingleChunkDataSerializer for ChunkData {
#[inline]
fn from_bytes(bytes: Bytes, pos: Vector2<i32>) -> Result<Self, ChunkReadingError> {
Self::internal_from_bytes(&bytes, pos).map_err(ChunkReadingError::ParsingError)
fn from_bytes(bytes: &Bytes, pos: Vector2<i32>) -> Result<Self, ChunkReadingError> {
Self::internal_from_bytes(bytes, pos).map_err(ChunkReadingError::ParsingError)
}
#[inline]
@@ -116,46 +116,49 @@ impl ChunkData {
position.x, position.y, chunk_data.x_pos, chunk_data.z_pos,
)));
}
let light_engine = ChunkLight {
block_light: chunk_data
.sections
.iter()
.map(|x| {
x.block_light
.clone()
.map(LightContainer::new)
.unwrap_or_default()
})
.collect(),
sky_light: chunk_data
.sections
.iter()
.map(|x| {
x.sky_light
.clone()
.map(LightContainer::new)
.unwrap_or_default()
})
.collect(),
};
let sub_chunks = chunk_data
let (block_lights, sky_lights, sub_chunks) = chunk_data
.sections
.into_iter()
.map(|section| SubChunk {
block_states: section
.block_states
.map(BlockPalette::from_disk_nbt)
.unwrap_or_default(),
biomes: section
.biomes
.map(BiomePalette::from_disk_nbt)
.unwrap_or_default(),
.map(|section| {
let block_light = section
.block_light
.map(LightContainer::new)
.unwrap_or_default();
let sky_light = section
.sky_light
.map(LightContainer::new)
.unwrap_or_default();
let sub_chunk = SubChunk {
block_states: section
.block_states
.map(BlockPalette::from_disk_nbt)
.unwrap_or_default(),
biomes: section
.biomes
.map(BiomePalette::from_disk_nbt)
.unwrap_or_default(),
};
(block_light, sky_light, sub_chunk)
})
.collect();
.fold(
(Vec::new(), Vec::new(), Vec::new()),
|(mut bl, mut sl, mut sc), (block_l, sky_l, sub_c)| {
bl.push(block_l);
sl.push(sky_l);
sc.push(sub_c);
(bl, sl, sc)
},
);
// 2. Assemble the final structs using the collected vectors.
let light_engine = ChunkLight {
block_light: block_lights.into_boxed_slice(),
sky_light: sky_lights.into_boxed_slice(),
};
let min_y = section_coords::section_to_block(chunk_data.min_y_section);
let section = ChunkSections::new(sub_chunks, min_y);
let section = ChunkSections::new(sub_chunks.into_boxed_slice(), min_y);
Ok(ChunkData {
section,
@@ -249,8 +252,8 @@ impl Dirtiable for ChunkEntityData {
impl SingleChunkDataSerializer for ChunkEntityData {
#[inline]
fn from_bytes(bytes: Bytes, pos: Vector2<i32>) -> Result<Self, ChunkReadingError> {
Self::internal_from_bytes(&bytes, pos).map_err(ChunkReadingError::ParsingError)
fn from_bytes(bytes: &Bytes, pos: Vector2<i32>) -> Result<Self, ChunkReadingError> {
Self::internal_from_bytes(bytes, pos).map_err(ChunkReadingError::ParsingError)
}
#[inline]

View File

@@ -365,7 +365,7 @@ where
log::debug!("Writing file for {}", path.display());
serializer
.write(path.clone())
.write(&path)
.await
.map_err(|err| ChunkWritingError::IoError(err.kind()))?;

View File

@@ -109,7 +109,7 @@ pub trait ChunkSerializer: Send + Sync + Default {
/// Serialize the data to bytes.
fn write(
&self,
backend: Self::WriteBackend,
backend: &Self::WriteBackend,
) -> impl Future<Output = Result<(), std::io::Error>> + Send;
/// Create a new instance from bytes

View File

@@ -49,7 +49,7 @@ pub enum FluidLevelSampler {
}
impl FluidLevelSamplerImpl for FluidLevelSampler {
fn get_fluid_level(&self, x: i32, y: i32, z: i32) -> FluidLevel {
fn get_fluid_level(&self, x: i32, y: i32, z: i32) -> &FluidLevel {
match self {
FluidLevelSampler::Static(sampler) => sampler.get_fluid_level(x, y, z),
FluidLevelSampler::Chunk(sampler) => sampler.get_fluid_level(x, y, z),
@@ -58,24 +58,25 @@ impl FluidLevelSamplerImpl for FluidLevelSampler {
}
pub struct StaticFluidLevelSampler {
y: i32,
block: &'static Block,
fluid_level: FluidLevel,
}
impl StaticFluidLevelSampler {
pub fn new(y: i32, block: &'static Block) -> Self {
Self { y, block }
Self {
fluid_level: FluidLevel::new(y, block),
}
}
}
impl FluidLevelSamplerImpl for StaticFluidLevelSampler {
fn get_fluid_level(&self, _x: i32, _y: i32, _z: i32) -> FluidLevel {
FluidLevel::new(self.y, self.block)
fn get_fluid_level(&self, _x: i32, _y: i32, _z: i32) -> &FluidLevel {
&self.fluid_level
}
}
pub trait FluidLevelSamplerImpl {
fn get_fluid_level(&self, x: i32, y: i32, z: i32) -> FluidLevel;
fn get_fluid_level(&self, x: i32, y: i32, z: i32) -> &FluidLevel;
}
#[enum_dispatch(AquiferSamplerImpl)]
@@ -103,8 +104,7 @@ macro_rules! local_y {
}
pub struct WorldAquiferSampler {
random_deriver: RandomDeriver,
fluid_level: FluidLevelSampler,
fluid_level_sampler: FluidLevelSampler,
start_x: i32,
start_y: i8,
start_z: i32,
@@ -134,7 +134,7 @@ impl WorldAquiferSampler {
#[allow(clippy::too_many_arguments)]
pub fn new(
chunk_pos: Vector2<i32>,
random_deriver: RandomDeriver,
random_deriver: &RandomDeriver,
minimum_y: i8,
height: u16,
fluid_level: FluidLevelSampler,
@@ -176,8 +176,7 @@ impl WorldAquiferSampler {
}
Self {
random_deriver,
fluid_level,
fluid_level_sampler: fluid_level,
start_x,
start_y,
start_z,
@@ -230,13 +229,12 @@ impl WorldAquiferSampler {
}
fn calculate_density(
&mut self,
barrier_sample: &mut Option<f64>,
pos: &impl NoisePos,
router: &mut ChunkNoiseRouter,
sample_options: &ChunkNoiseFunctionSampleOptions,
level_1: FluidLevel,
level_2: FluidLevel,
level_1: &FluidLevel,
level_2: &FluidLevel,
) -> f64 {
let y = pos.y();
let block_state1 = level_1.get_block(y);
@@ -280,7 +278,7 @@ impl WorldAquiferSampler {
router: &mut ChunkNoiseRouter,
height_estimator: &mut SurfaceHeightEstimateSampler,
sample_options: &ChunkNoiseFunctionSampleOptions,
) -> FluidLevel {
) -> &FluidLevel {
let x = block_pos::unpack_x(packed_pos);
let y = block_pos::unpack_y(packed_pos);
let z = block_pos::unpack_z(packed_pos);
@@ -290,18 +288,26 @@ impl WorldAquiferSampler {
let local_z = local_xz!(z);
let index = self.packed_position_index(local_x, local_y, local_z);
if let Some(level) = &self.levels[index] {
level.clone()
} else {
let fluid_level =
self.get_fluid_level(x, y, z, router, height_estimator, sample_options);
self.levels[index] = Some(fluid_level.clone());
fluid_level
}
let entry = self
.levels
.get_mut(index)
.expect("Index calculated by packed_position_index is out of bounds for self.levels");
let fluid_level = &self.fluid_level_sampler;
entry.get_or_insert_with(|| {
Self::get_fluid_level(
fluid_level,
x,
y,
z,
router,
height_estimator,
sample_options,
)
})
}
fn get_fluid_level(
&mut self,
fluid_level_sampler: &FluidLevelSampler,
block_x: i32,
block_y: i32,
block_z: i32,
@@ -309,7 +315,7 @@ impl WorldAquiferSampler {
height_estimator: &mut SurfaceHeightEstimateSampler,
sample_options: &ChunkNoiseFunctionSampleOptions,
) -> FluidLevel {
let fluid_level = self.fluid_level.get_fluid_level(block_x, block_y, block_z);
let fluid_level = fluid_level_sampler.get_fluid_level(block_x, block_y, block_z);
let j = block_y + 12;
let k = block_y - 12;
let mut bl = false;
@@ -324,19 +330,19 @@ impl WorldAquiferSampler {
let bl2 = offset.x == 0 && offset.y == 0;
if bl2 && k > o {
return fluid_level;
return fluid_level.clone();
}
let bl3 = j > o;
if bl3 || bl2 {
let fluid_level = self.fluid_level.get_fluid_level(x, o, z);
let fluid_level = fluid_level_sampler.get_fluid_level(x, o, z);
if !fluid_level.get_block(o).default_state.is_air() {
if bl2 {
bl = true;
}
if bl3 {
return fluid_level;
return fluid_level.clone();
}
}
}
@@ -344,11 +350,11 @@ impl WorldAquiferSampler {
min_surface_estimate = min_surface_estimate.min(n);
}
let p = self.get_fluid_block_y(
let p = Self::get_fluid_block_y(
block_x,
block_y,
block_z,
fluid_level.clone(),
fluid_level,
min_surface_estimate,
bl,
router,
@@ -356,7 +362,7 @@ impl WorldAquiferSampler {
);
FluidLevel::new(
p,
self.get_fluid_block_state(
WorldAquiferSampler::get_fluid_block_state(
block_x,
block_y,
block_z,
@@ -370,11 +376,10 @@ impl WorldAquiferSampler {
#[allow(clippy::too_many_arguments)]
fn get_fluid_block_y(
&mut self,
block_x: i32,
block_y: i32,
block_z: i32,
default_level: FluidLevel,
default_level: &FluidLevel,
surface_height_estimate: i32,
map_y: bool,
router: &mut ChunkNoiseRouter,
@@ -407,7 +412,7 @@ impl WorldAquiferSampler {
if e > 0f64 {
default_level.max_y
} else if d > 0f64 {
self.get_noise_based_fluid_level(
Self::get_noise_based_fluid_level(
block_x,
block_y,
block_z,
@@ -421,7 +426,6 @@ impl WorldAquiferSampler {
}
fn get_noise_based_fluid_level(
&mut self,
block_x: i32,
block_y: i32,
block_z: i32,
@@ -446,11 +450,10 @@ impl WorldAquiferSampler {
#[allow(clippy::too_many_arguments)]
fn get_fluid_block_state(
&mut self,
block_x: i32,
block_y: i32,
block_z: i32,
default_level: FluidLevel,
default_level: &FluidLevel,
level: i32,
router: &mut ChunkNoiseRouter,
sample_options: &ChunkNoiseFunctionSampleOptions,
@@ -486,7 +489,7 @@ impl WorldAquiferSampler {
let sample_z = pos.z();
let fluid_level = self
.fluid_level
.fluid_level_sampler
.get_fluid_level(sample_x, sample_y, sample_z);
if fluid_level.get_block(sample_y) == &LAVA_BLOCK {
Some(LAVA_BLOCK.default_state)
@@ -521,13 +524,14 @@ impl WorldAquiferSampler {
random_positions_and_hypot[0] = (packed_random, hypot_squared);
}
}
let fluid_level2 = self.get_water_level(
random_positions_and_hypot[0].0,
router,
height_estimator,
sample_options,
);
let fluid_level2 = self
.get_water_level(
random_positions_and_hypot[0].0,
router,
height_estimator,
sample_options,
)
.clone();
let d = Self::max_distance(
random_positions_and_hypot[0].1,
random_positions_and_hypot[1].1,
@@ -540,7 +544,7 @@ impl WorldAquiferSampler {
Some(block_state.default_state)
} else if block_state == &WATER_BLOCK
&& self
.fluid_level
.fluid_level_sampler
.get_fluid_level(sample_x, sample_y - 1, sample_z)
.get_block(sample_y - 1)
== &LAVA_BLOCK
@@ -548,19 +552,21 @@ impl WorldAquiferSampler {
Some(block_state.default_state)
} else {
let mut barrier_sample = None;
let fluid_level3 = self.get_water_level(
random_positions_and_hypot[1].0,
router,
height_estimator,
sample_options,
);
let e = d * self.calculate_density(
let fluid_level3 = self
.get_water_level(
random_positions_and_hypot[1].0,
router,
height_estimator,
sample_options,
)
.clone();
let e = d * Self::calculate_density(
&mut barrier_sample,
pos,
router,
sample_options,
fluid_level2.clone(),
fluid_level3.clone(),
&fluid_level2,
&fluid_level3,
);
if density + e > 0f64 {
@@ -579,13 +585,13 @@ impl WorldAquiferSampler {
if f > 0f64 {
let g = d
* f
* self.calculate_density(
* Self::calculate_density(
&mut barrier_sample,
pos,
router,
sample_options,
fluid_level2,
fluid_level4.clone(),
&fluid_level2,
fluid_level4,
);
if density + g > 0f64 {
return None;
@@ -599,12 +605,12 @@ impl WorldAquiferSampler {
if g > 0f64 {
let h = d
* g
* self.calculate_density(
* Self::calculate_density(
&mut barrier_sample,
pos,
router,
sample_options,
fluid_level3,
&fluid_level3,
fluid_level4,
);
if density + h > 0f64 {
@@ -794,7 +800,7 @@ mod random_positions_and_hypot {
#[test]
fn test_get_fluid_block_state() {
let (mut aquifer, mut router, _, options) = create_aquifer(&PROTO_ROUTER);
let (_, mut router, _, options) = create_aquifer(&PROTO_ROUTER);
let level = FluidLevel::new(0, &WATER_BLOCK);
let values = [
@@ -927,7 +933,15 @@ mod random_positions_and_hypot {
for ((x, y, z), result) in values {
assert_eq!(
aquifer.get_fluid_block_state(x, y, z, level.clone(), -10, &mut router, &options),
WorldAquiferSampler::get_fluid_block_state(
x,
y,
z,
&level,
-10,
&mut router,
&options
),
&result
);
}
@@ -935,7 +949,7 @@ mod random_positions_and_hypot {
#[test]
fn test_get_noise_based_fluid_level() {
let (mut aquifer, mut router, _, options) = create_aquifer(&PROTO_ROUTER);
let (_, mut router, _, options) = create_aquifer(&PROTO_ROUTER);
let values = [
((-100, -100, -100), -103),
@@ -1067,7 +1081,14 @@ mod random_positions_and_hypot {
for ((x, y, z), result) in values {
assert_eq!(
aquifer.get_noise_based_fluid_level(x, y, z, 200, &mut router, &options),
WorldAquiferSampler::get_noise_based_fluid_level(
x,
y,
z,
200,
&mut router,
&options
),
result
);
}
@@ -1075,7 +1096,7 @@ mod random_positions_and_hypot {
#[test]
fn test_get_fluid_block_y() {
let (mut aquifer, mut router, _, env) = create_aquifer(&PROTO_ROUTER);
let (_, mut router, _, env) = create_aquifer(&PROTO_ROUTER);
let level = FluidLevel::new(0, &WATER_BLOCK);
let values = [
((-100, -100, -100), -32512),
@@ -1207,7 +1228,16 @@ mod random_positions_and_hypot {
for ((x, y, z), result) in values {
assert_eq!(
aquifer.get_fluid_block_y(x, y, z, level.clone(), 80, true, &mut router, &env),
WorldAquiferSampler::get_fluid_block_y(
x,
y,
z,
&level,
80,
true,
&mut router,
&env
),
result
);
}
@@ -1342,7 +1372,16 @@ mod random_positions_and_hypot {
for ((x, y, z), result) in values {
assert_eq!(
aquifer.get_fluid_block_y(x, y, z, level.clone(), 80, false, &mut router, &env),
WorldAquiferSampler::get_fluid_block_y(
x,
y,
z,
&level,
80,
false,
&mut router,
&env
),
result
);
}
@@ -1350,7 +1389,7 @@ mod random_positions_and_hypot {
#[test]
fn test_get_fluid_level() {
let (mut aquifer, mut router, mut height_estimator, env) = create_aquifer(&PROTO_ROUTER);
let (aquifer, mut router, mut height_estimator, env) = create_aquifer(&PROTO_ROUTER);
let values = [
((-100, -100, -100), (-32512, LAVA_BLOCK)),
((-100, -100, -50), (-32512, LAVA_BLOCK)),
@@ -1479,8 +1518,17 @@ mod random_positions_and_hypot {
((100, 100, 100), (63, WATER_BLOCK)),
];
let fluid_level_sampler = &aquifer.fluid_level_sampler;
for ((x, y, z), (y1, state)) in values {
let level = aquifer.get_fluid_level(x, y, z, &mut router, &mut height_estimator, &env);
let level = WorldAquiferSampler::get_fluid_level(
fluid_level_sampler,
x,
y,
z,
&mut router,
&mut height_estimator,
&env,
);
assert_eq!(level.max_y, y1);
assert_eq!(level.block, &state);
}
@@ -1488,7 +1536,7 @@ mod random_positions_and_hypot {
#[test]
fn test_calculate_density() {
let (mut aquifer, mut router, _, env) = create_aquifer(&PROTO_ROUTER);
let (_, mut router, _, env) = create_aquifer(&PROTO_ROUTER);
let values = [
((-100, -100, -100, 0, 0), 0.0),
@@ -1625,7 +1673,14 @@ mod random_positions_and_hypot {
let mut sample = None;
assert_eq!(
aquifer.calculate_density(&mut sample, &pos, &mut router, &env, level1, level2),
WorldAquiferSampler::calculate_density(
&mut sample,
&pos,
&mut router,
&env,
&level1,
&level2
),
result
);
}

View File

@@ -106,7 +106,11 @@ impl DualNoiseBlockStateProvider {
&BlockPos(pos.0.add(&Vector3::new(i * 54545, 0, i * 34234))),
&sampler,
);
list.push(self.base.get_state_by_value(&self.base.states, value));
list.push(
self.base
.get_state_by_value(&self.base.states, value)
.clone(),
);
}
let value = self.base.base.get_noise(pos);
self.base.get_state_by_value(&list, value).get_state()
@@ -184,9 +188,13 @@ impl NoiseBlockStateProvider {
self.get_state_by_value(&self.states, value).get_state()
}
fn get_state_by_value(&self, states: &[BlockStateCodec], value: f64) -> BlockStateCodec {
fn get_state_by_value<'a>(
&self,
states: &'a [BlockStateCodec],
value: f64,
) -> &'a BlockStateCodec {
let val = ((1.0 + value) / 2.0).clamp(0.0, 0.9999);
states[(val * states.len() as f64) as usize].clone()
&states[(val * states.len() as f64) as usize]
}
}

View File

@@ -210,7 +210,7 @@ impl<'a> ChunkNoiseGenerator<'a> {
let section_z = section_coords::block_to_section(start_block_z);
AquiferSampler::Aquifer(WorldAquiferSampler::new(
Vector2::new(section_x, section_z),
random_config.aquifer_random_deriver.clone(),
&random_config.aquifer_random_deriver,
generation_shape.min_y,
generation_shape.height,
level_sampler,

View File

@@ -21,6 +21,15 @@ enum BlockWrapper {
Multi(Vec<String>),
}
impl BlockWrapper {
fn contains(&self, name: &str) -> bool {
match self {
Self::Single(s) => s == name,
Self::Multi(h) => h.contains(&name.to_string()),
}
}
}
impl SpringFeatureFeature {
pub fn generate<T: GenerationCache>(
&self,
@@ -29,91 +38,80 @@ impl SpringFeatureFeature {
_random: &mut RandomGenerator,
pos: BlockPos,
) -> bool {
// i don't think this is the most efficient way, but it works
let valid_blocks = match self.valid_blocks.clone() {
BlockWrapper::Single(item) => vec![item],
BlockWrapper::Multi(items) => items,
};
let valid_blocks = &self.valid_blocks;
if !valid_blocks.contains(
&GenerationCache::get_block_state(chunk, &pos.up().0)
GenerationCache::get_block_state(chunk, &pos.up().0)
.to_block()
.name
.to_string(),
.name,
) {
return false;
}
if self.requires_block_below
&& !valid_blocks.contains(
&GenerationCache::get_block_state(
GenerationCache::get_block_state(
chunk,
&pos.offset(BlockDirection::Down.to_offset()).0,
)
.to_block()
.name
.to_string(),
.name,
)
{
return false;
}
let state = GenerationCache::get_block_state(chunk, &pos.0);
if !state.to_state().is_air() && !valid_blocks.contains(&state.to_block().name.to_string())
{
if !state.to_state().is_air() && !valid_blocks.contains(state.to_block().name) {
return false;
}
let mut valid = 0;
if valid_blocks.contains(
&GenerationCache::get_block_state(
GenerationCache::get_block_state(
chunk,
&pos.offset(BlockDirection::West.to_offset()).0,
)
.to_block()
.name
.to_string(),
.name,
) {
valid += 1;
}
if valid_blocks.contains(
&GenerationCache::get_block_state(
GenerationCache::get_block_state(
chunk,
&pos.offset(BlockDirection::East.to_offset()).0,
)
.to_block()
.name
.to_string(),
.name,
) {
valid += 1;
}
if valid_blocks.contains(
&GenerationCache::get_block_state(
GenerationCache::get_block_state(
chunk,
&pos.offset(BlockDirection::North.to_offset()).0,
)
.to_block()
.name
.to_string(),
.name,
) {
valid += 1;
}
if valid_blocks.contains(
&GenerationCache::get_block_state(
GenerationCache::get_block_state(
chunk,
&pos.offset(BlockDirection::South.to_offset()).0,
)
.to_block()
.name
.to_string(),
.name,
) {
valid += 1;
}
if valid_blocks.contains(
&GenerationCache::get_block_state(
GenerationCache::get_block_state(
chunk,
&pos.offset(BlockDirection::Down.to_offset()).0,
)
.to_block()
.name
.to_string(),
.name,
) {
valid += 1;
}

View File

@@ -82,11 +82,11 @@ impl StandardChunkFluidLevelSampler {
}
impl FluidLevelSamplerImpl for StandardChunkFluidLevelSampler {
fn get_fluid_level(&self, _x: i32, y: i32, _z: i32) -> FluidLevel {
fn get_fluid_level(&self, _x: i32, y: i32, _z: i32) -> &FluidLevel {
if y < self.bottom_y {
self.bottom_fluid.clone()
&self.bottom_fluid
} else {
self.top_fluid.clone()
&self.top_fluid
}
}
}

View File

@@ -842,7 +842,7 @@ impl Level {
.await;
let mut chunk = chunk.write().await;
chunk.block_ticks.schedule_tick(
ScheduledTick {
&ScheduledTick {
delay,
position: block_pos,
priority,
@@ -865,7 +865,7 @@ impl Level {
.await;
let mut chunk = chunk.write().await;
chunk.fluid_ticks.schedule_tick(
ScheduledTick {
&ScheduledTick {
delay,
position: block_pos,
priority,

View File

@@ -24,7 +24,7 @@ impl<'a, T: std::hash::Hash + Eq> ChunkTickScheduler<&'a T> {
res
}
pub fn schedule_tick(&mut self, tick: ScheduledTick<&'a T>, sub_tick_order: u64) {
pub fn schedule_tick(&mut self, tick: &ScheduledTick<&'a T>, sub_tick_order: u64) {
if self.queued_ticks.insert((tick.position, tick.value)) {
let index = (self.offset + tick.delay as usize) % MAX_TICK_DELAY;
self.tick_queue[index].push(OrderedTick {
@@ -57,7 +57,7 @@ impl<'a, T: std::hash::Hash + Eq> ChunkTickScheduler<&'a T> {
pub fn from_vec(ticks: &[ScheduledTick<&'a T>]) -> Self {
let mut scheduler = Self::default();
for tick in ticks {
scheduler.schedule_tick(tick.clone(), 0);
scheduler.schedule_tick(tick, 0);
}
scheduler
}

View File

@@ -112,9 +112,7 @@ impl WorldInfoWriter for AnvilLevelInfo {
.expect("Time went backwards");
let mut level_data = info.clone();
level_data.last_played = since_the_epoch.as_millis() as i64;
let level = LevelDat {
data: level_data.clone(),
};
let level = LevelDat { data: level_data };
// open file
let path = level_folder.join(LEVEL_DAT_FILE_NAME);

View File

@@ -41,7 +41,6 @@ tokio = { workspace = true, features = [
"io-util",
"time",
] }
rayon.workspace = true
thiserror.workspace = true
futures.workspace = true
@@ -60,13 +59,14 @@ rustyline-async = "0.4.7"
# encryption
rsa = { version = "=0.10.0-rc.10", features = ["sha1"] }
rsa-der = "0.3"
pkcs8 = "=0.11.0-rc.8"
# authentication
ureq = { version = "3.1.4", features = [
"json",
] }
sha1 = "=0.11.0-rc.3"
# velocity en
@@ -79,7 +79,7 @@ base64 = "0.22.1"
simplelog = { version = "0.12.2", features = ["ansi_term"] }
# Remove time in favor of chrono?
time = "0.3"
time = { version = "0.3", features = ["parsing", "macros"] }
# plugins
libloading = "0.9"
@@ -88,18 +88,12 @@ rustc-hash = "2.1.1"
# Task handling
tokio-util = { version = "0.7.17", features = ["rt"] }
# Memory profiling
dhat = { version = "0.3.3", optional = true }
flate2 = "1.1.7"
console-subscriber = { version = "0.5.0", optional = true }
flate2 = "1.1.5"
console-subscriber = { version = "0.5.0", default-features= false, optional = true }
signature = "2.2.0"
[dev-dependencies]
tempfile.workspace = true
[features]
#https://nnethercote.github.io/dh_view/dh_view.html
#https://valgrind.org/docs/manual/dh-manual.html
dhat-heap = ["dep:dhat"]
console-subscriber = ["dep:console-subscriber"]
tokio_taskdump = ["pumpkin-world/tokio_taskdump"]

View File

@@ -52,7 +52,7 @@ pub trait BlockBehaviour: Send + Sync {
}
fn on_entity_collision<'a>(&'a self, _args: OnEntityCollisionArgs<'a>) -> BlockFuture<'a, ()> {
Box::pin(async move {})
Box::pin(async {})
}
fn should_drop_items_on_explosion(&self) -> bool {
@@ -60,7 +60,7 @@ pub trait BlockBehaviour: Send + Sync {
}
fn explode<'a>(&'a self, _args: ExplodeArgs<'a>) -> BlockFuture<'a, ()> {
Box::pin(async move {})
Box::pin(async {})
}
/// Handles the block event, which is an event specific to a block with an integer ID and data.
@@ -79,7 +79,7 @@ pub trait BlockBehaviour: Send + Sync {
}
fn random_tick<'a>(&'a self, _args: RandomTickArgs<'a>) -> BlockFuture<'a, ()> {
Box::pin(async move {})
Box::pin(async {})
}
fn can_place_at<'a>(&'a self, _args: CanPlaceAtArgs<'a>) -> BlockFuture<'a, bool> {
@@ -92,24 +92,24 @@ pub trait BlockBehaviour: Send + Sync {
/// onBlockAdded in source code
fn placed<'a>(&'a self, _args: PlacedArgs<'a>) -> BlockFuture<'a, ()> {
Box::pin(async move {})
Box::pin(async {})
}
fn player_placed<'a>(&'a self, _args: PlayerPlacedArgs<'a>) -> BlockFuture<'a, ()> {
Box::pin(async move {})
Box::pin(async {})
}
fn broken<'a>(&'a self, _args: BrokenArgs<'a>) -> BlockFuture<'a, ()> {
Box::pin(async move {})
Box::pin(async {})
}
fn on_neighbor_update<'a>(&'a self, _args: OnNeighborUpdateArgs<'a>) -> BlockFuture<'a, ()> {
Box::pin(async move {})
Box::pin(async {})
}
/// Called if a block state is replaced or it replaces another state
fn prepare<'a>(&'a self, _args: PrepareArgs<'a>) -> BlockFuture<'a, ()> {
Box::pin(async move {})
Box::pin(async {})
}
fn get_state_for_neighbor_update<'a>(
@@ -120,11 +120,11 @@ pub trait BlockBehaviour: Send + Sync {
}
fn on_scheduled_tick<'a>(&'a self, _args: OnScheduledTickArgs<'a>) -> BlockFuture<'a, ()> {
Box::pin(async move {})
Box::pin(async {})
}
fn on_state_replaced<'a>(&'a self, _args: OnStateReplacedArgs<'a>) -> BlockFuture<'a, ()> {
Box::pin(async move {})
Box::pin(async {})
}
// --- Redstone/Comparator Methods ---

View File

@@ -56,9 +56,6 @@ mod weather;
mod whitelist;
mod worldborder;
#[cfg(feature = "dhat-heap")]
mod profile;
#[must_use]
pub async fn default_dispatcher(basic_config: &BasicConfiguration) -> CommandDispatcher {
let mut dispatcher = CommandDispatcher::default();
@@ -144,9 +141,6 @@ pub async fn default_dispatcher(basic_config: &BasicConfiguration) -> CommandDis
// Four
dispatcher.register(stop::init_command_tree(), "minecraft:command.stop");
#[cfg(feature = "dhat-heap")]
dispatcher.register(profile::init_command_tree(), "pumpkin:command.profile");
dispatcher
}
@@ -510,13 +504,4 @@ fn register_level_4_permissions(registry: &mut PermissionRegistry) {
PermissionDefault::Op(PermissionLvl::Four),
))
.unwrap();
#[cfg(feature = "dhat-heap")]
registry
.register_permission(Permission::new(
"pumpkin:command.profile",
"Controls heap profiling",
PermissionDefault::Op(PermissionLvl::Four),
))
.unwrap();
}

View File

@@ -1,45 +0,0 @@
use pumpkin_util::text::TextComponent;
use pumpkin_util::text::color::NamedColor;
use crate::command::CommandResult;
use crate::command::args::ConsumedArgs;
use crate::command::tree::CommandTree;
use crate::command::{CommandExecutor, CommandSender};
use crate::{HEAP_PROFILER, stop_server};
const NAMES: [&str; 1] = ["mem_profile"];
const DESCRIPTION: &str = "Stop the server and dump a memory profile.";
struct Executor;
impl CommandExecutor for Executor {
fn execute<'a>(
&'a self,
sender: &'a CommandSender,
_server: &'a crate::server::Server,
_args: &'a ConsumedArgs<'a>,
) -> CommandResult<'a> {
Box::pin(async move {
sender
.send_message(
TextComponent::translate("commands.stop.stopping", [])
.color_named(NamedColor::Red),
)
.await;
let mut profiler = HEAP_PROFILER.lock().await;
let p = profiler.take().unwrap();
drop(p);
stop_server();
Ok(())
})
}
}
pub fn init_command_tree() -> CommandTree {
CommandTree::new(NAMES, DESCRIPTION).execute(Executor)
}

View File

@@ -67,9 +67,8 @@ impl BannedIpEntry {
}
mod format {
use simplelog::FormatItem;
const DATE_FORMAT: &[FormatItem<'static>] = time::macros::format_description!(
const DATE_FORMAT: &[time::format_description::FormatItem<'static>] = time::macros::format_description!(
"[year]-[month]-[day] [hour]:[minute]:[second][offset_hour sign:mandatory]:[offset_minute]"
);

View File

@@ -25,7 +25,7 @@ pub trait ItemBehaviour: Send + Sync {
_item: &'a Item,
_player: &'a Player,
) -> Pin<Box<dyn Future<Output = ()> + Send + 'a>> {
Box::pin(async move {})
Box::pin(async {})
}
fn use_on_block<'a>(
@@ -37,7 +37,7 @@ pub trait ItemBehaviour: Send + Sync {
_block: &'a Block,
_server: &'a Server,
) -> Pin<Box<dyn Future<Output = ()> + Send + 'a>> {
Box::pin(async move {})
Box::pin(async {})
}
fn use_on_entity<'a>(
@@ -46,7 +46,7 @@ pub trait ItemBehaviour: Send + Sync {
_player: &'a Player,
_entity: Arc<dyn EntityBase>,
) -> Pin<Box<dyn Future<Output = ()> + Send + 'a>> {
Box::pin(async move {})
Box::pin(async {})
}
fn can_mine(&self, _player: &Player) -> bool {

View File

@@ -42,10 +42,6 @@ pub mod plugin;
pub mod server;
pub mod world;
#[cfg(feature = "dhat-heap")]
pub static HEAP_PROFILER: LazyLock<Mutex<Option<dhat::Profiler>>> =
LazyLock::new(|| Mutex::new(None));
pub static PLUGIN_MANAGER: LazyLock<Arc<PluginManager>> =
LazyLock::new(|| Arc::new(PluginManager::new()));

View File

@@ -53,7 +53,7 @@ use tokio::signal::ctrl_c;
use tokio::signal::unix::{SignalKind, signal};
use tokio::sync::RwLock;
use pumpkin::{LOGGER_IMPL, PumpkinServer, SHOULD_STOP, STOP_INTERRUPT, init_log, stop_server};
use pumpkin::{PumpkinServer, SHOULD_STOP, STOP_INTERRUPT, init_log, stop_server};
use pumpkin_config::{AdvancedConfiguration, BasicConfiguration, LoadConfiguration};
use pumpkin_util::{
@@ -74,13 +74,6 @@ pub mod plugin;
pub mod server;
pub mod world;
#[cfg(feature = "dhat-heap")]
#[global_allocator]
static ALLOC: dhat::Alloc = dhat::Alloc;
#[cfg(feature = "dhat-heap")]
use pumpkin::HEAP_PROFILER;
pub static PLUGIN_MANAGER: LazyLock<Arc<PluginManager>> =
LazyLock::new(|| Arc::new(PluginManager::new()));
@@ -102,13 +95,6 @@ const CARGO_PKG_VERSION: &str = env!("CARGO_PKG_VERSION");
async fn main() {
#[cfg(feature = "console-subscriber")]
console_subscriber::init();
#[cfg(feature = "dhat-heap")]
{
let profiler = dhat::Profiler::new_heap();
let mut static_loc = HEAP_PROFILER.lock().await;
*static_loc = Some(profiler);
};
let time = Instant::now();
let exec_dir = std::env::current_dir().unwrap();
@@ -123,10 +109,6 @@ async fn main() {
let default_panic = std::panic::take_hook();
std::panic::set_hook(Box::new(move |info| {
if let Some((wrapper, _)) = LOGGER_IMPL.wait() {
// Drop readline to reset terminal state
let _ = wrapper.take_readline();
}
default_panic(info);
// TODO: Gracefully exit?
// We need to abide by the panic rules here.

View File

@@ -19,7 +19,6 @@ use pumpkin_util::{Hand, ProfileAction, text::TextComponent};
use serde::Deserialize;
use sha1::Digest;
use sha2::Sha256;
use simplelog::FormatItem;
use tokio::task::JoinHandle;
use thiserror::Error;
@@ -180,7 +179,7 @@ pub async fn can_not_join(
address: &SocketAddr,
server: &Server,
) -> Option<TextComponent> {
const FORMAT_DESCRIPTION: &[FormatItem<'_>] = time::macros::format_description!(
const FORMAT_DESCRIPTION: &[time::format_description::FormatItem<'static>] = time::macros::format_description!(
"[year]-[month]-[day] at [hour]:[minute]:[second] [offset_hour sign:mandatory]:[offset_minute]"
);

View File

@@ -52,7 +52,7 @@ pub trait DynEventHandler: Send + Sync {
///
/// # Returns
/// The priority of the event handler.
fn get_priority(&self) -> EventPriority;
fn get_priority(&self) -> &EventPriority;
}
/// A trait for handling specific events.
@@ -72,7 +72,7 @@ pub trait EventHandler<E: Payload>: Send + Sync {
/// # Arguments
/// - `event`: A mutable reference to the event to handle.
fn handle_blocking(&self, _server: &Arc<Server>, _event: &mut E) -> BoxFuture<'_, ()> {
Box::pin(async move {})
Box::pin(async {})
}
}
@@ -129,8 +129,8 @@ where
}
/// Retrieves the priority of the handler.
fn get_priority(&self) -> EventPriority {
self.priority.clone()
fn get_priority(&self) -> &EventPriority {
&self.priority
}
}

View File

@@ -1,6 +1,7 @@
use num_bigint::BigInt;
use pkcs8::EncodePublicKey;
use pumpkin_protocol::java::client::login::CEncryptionRequest;
use rsa::{Pkcs1v15Encrypt, RsaPrivateKey, traits::PublicKeyParts as _};
use rsa::{Pkcs1v15Encrypt, RsaPrivateKey};
use sha1::Sha1;
use sha2::Digest;
@@ -17,11 +18,15 @@ impl KeyStore {
log::debug!("Creating encryption keys...");
let private_key = Self::generate_private_key();
let public_key_der = rsa_der::public_key_to_der(
&private_key.n().to_be_bytes(),
&private_key.e().to_be_bytes(),
)
.into_boxed_slice();
let public_key = private_key.to_public_key();
let public_key_der = public_key
.to_public_key_der()
.expect("Failed to encode public key to SPKI DER")
.as_bytes()
.to_vec()
.into_boxed_slice();
Self {
private_key,
public_key_der,