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

View File

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

View File

@ -1025,7 +1025,7 @@ pub trait ScreenHandlerListener: Send + Sync {
_slot: u8, _slot: u8,
_stack: ItemStack, _stack: ItemStack,
) -> Pin<Box<dyn Future<Output = ()> + Send + 'a>> { ) -> Pin<Box<dyn Future<Output = ()> + Send + 'a>> {
Box::pin(async move {}) Box::pin(async {})
} }
fn on_property_update<'a>( fn on_property_update<'a>(
&'a self, &'a self,
@ -1033,7 +1033,7 @@ pub trait ScreenHandlerListener: Send + Sync {
_property: u8, _property: u8,
_value: i32, _value: i32,
) -> Pin<Box<dyn Future<Output = ()> + Send + 'a>> { ) -> 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: ItemStack,
_stack_prev: ItemStack, _stack_prev: ItemStack,
) -> BoxFuture<'_, ()> { ) -> BoxFuture<'_, ()> {
Box::pin(async move {}) // Default implementation Box::pin(async {}) // Default implementation
} }
/// Callback for when an item is taken from the slot. /// Callback for when an item is taken from the slot.
@ -57,7 +57,7 @@ pub trait Slot: Send + Sync + Debug {
// Used for plugins // Used for plugins
fn on_click(&self, _player: &dyn InventoryPlayer) -> BoxFuture<'_, ()> { 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> { fn can_insert<'a>(&'a self, _stack: &'a ItemStack) -> BoxFuture<'a, bool> {

View File

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

View File

@ -1,22 +1,18 @@
use heck::{ToPascalCase, ToSnakeCase};
use proc_macro::TokenStream; use proc_macro::TokenStream;
use proc_macro_error2::{abort, abort_call_site, proc_macro_error}; use proc_macro_error2::{abort, abort_call_site, proc_macro_error};
use quote::quote; use quote::quote;
use syn::spanned::Spanned; use syn::spanned::Spanned;
use syn::{self, Attribute, Type}; use syn::{self, Attribute, DeriveInput, LitStr, Type, parse_quote};
use syn::{ use syn::{Block, Expr, Field, Fields, ItemStruct, Stmt, parse_macro_input};
Block, Expr, Field, Fields, ItemStruct, Stmt,
parse::{Nothing, Parser},
parse_macro_input,
};
#[proc_macro_derive(Event)] #[proc_macro_derive(Event)]
pub fn event(item: TokenStream) -> TokenStream { pub fn event(item: TokenStream) -> TokenStream {
let input = parse_macro_input!(item as ItemStruct); let ast = parse_macro_input!(item as DeriveInput);
let name = &input.ident; let name = &ast.ident;
let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl();
quote! { 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 { fn get_name_static() -> &'static str {
stringify!(#name) stringify!(#name)
} }
@ -38,26 +34,36 @@ pub fn event(item: TokenStream) -> TokenStream {
} }
#[proc_macro_attribute] #[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 mut item_struct = parse_macro_input!(input as ItemStruct);
let name = item_struct.ident.clone(); let name = &item_struct.ident;
let _ = parse_macro_input!(args as Nothing); let (impl_generics, ty_generics, where_clause) = item_struct.generics.split_for_impl();
if let Fields::Named(ref mut fields) = item_struct.fields { match &mut item_struct.fields {
fields.named.push( Fields::Named(fields) => {
Field::parse_named if fields
.parse2(quote! { .named
/// A boolean indicating cancel state of the event. .iter()
pub cancelled: bool .any(|f| f.ident.as_ref().map(|i| i == "cancelled").unwrap_or(false))
}) {
.unwrap(), 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! { quote! {
#item_struct #item_struct
impl crate::plugin::Cancellable for #name { impl #impl_generics crate::plugin::Cancellable for #name #ty_generics #where_clause {
fn cancelled(&self) -> bool { fn cancelled(&self) -> bool {
self.cancelled self.cancelled
} }
@ -73,115 +79,116 @@ pub fn cancellable(args: TokenStream, input: TokenStream) -> TokenStream {
#[proc_macro_error] #[proc_macro_error]
#[proc_macro] #[proc_macro]
pub fn send_cancellable(input: TokenStream) -> TokenStream { 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 after_block = None;
let mut cancelled_block = None; let mut cancelled_block = None;
for stmt in input.stmts { for stmt in block.stmts {
if let Stmt::Expr(expr, _) = stmt { match stmt {
if event.is_none() { Stmt::Expr(expr, _) => {
event = Some(expr); // Check if it is a labeled block first
} else if let Expr::Block(b) = expr let mut is_special_block = false;
&& let Some(ref label) = b.label if let Expr::Block(ref b) = expr
{ && let Some(ref label) = b.label
if label.name.ident == "after" { {
after_block = Some(b); let label_name = label.name.ident.to_string();
} else if label.name.ident == "cancelled" { if label_name == "after" {
cancelled_block = Some(b); 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 { let event = match event_expr {
if let Some(after_block) = after_block { Some(e) => e,
if let Some(cancelled_block) = cancelled_block { None => abort_call_site!("Event expression must be specified"),
quote! { };
let event = crate::PLUGIN_MANAGER
.fire(#event)
.await;
if !event.cancelled { // Construct the if/else logic
#after_block let logic = match (after_block, cancelled_block) {
} else { (Some(after), Some(cancelled)) => quote! {
#cancelled_block if !event.cancelled { #after } else { #cancelled }
} },
} (Some(after), None) => quote! {
.into() if !event.cancelled { #after }
} else { },
quote! { (None, Some(cancelled)) => quote! {
let event = crate::PLUGIN_MANAGER if event.cancelled { #cancelled }
.fire(#event) },
.await; (None, None) => quote! {},
};
if !event.cancelled { quote! {
#after_block let event = crate::PLUGIN_MANAGER.fire(#event).await;
} #logic
}
.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");
} }
.into()
} }
#[proc_macro_attribute] #[proc_macro_attribute]
pub fn packet(input: TokenStream, item: TokenStream) -> TokenStream { pub fn packet(args: TokenStream, item: TokenStream) -> TokenStream {
let ast: syn::DeriveInput = syn::parse(item.clone()).unwrap(); let packet_id_expr = parse_macro_input!(args as Expr);
let ast = parse_macro_input!(item as DeriveInput);
let name = &ast.ident; 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(); quote! {
let item: proc_macro2::TokenStream = item.into(); #ast
impl #impl_generics crate::packet::Packet for #name #ty_generics #where_clause {
const PACKET_ID: i32 = #packet_id_expr;
}
}
.into()
}
let code = quote! { #[proc_macro_attribute]
#item pub fn pumpkin_block(args: TokenStream, item: TokenStream) -> TokenStream {
impl #impl_generics crate::packet::Packet for #name #ty_generics { let arg_lit = parse_macro_input!(args as LitStr);
const PACKET_ID: i32 = #input; 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() let ast = parse_macro_input!(item as DeriveInput);
}
#[proc_macro_attribute]
pub fn pumpkin_block(input: TokenStream, item: TokenStream) -> TokenStream {
let ast: syn::DeriveInput = syn::parse(item.clone()).unwrap();
let name = &ast.ident; 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 (namespace, id) = packet_name
.split_once(":")
.unwrap_or_else(|| abort!(packet_name, "A namespace is required!"));
let item: proc_macro2::TokenStream = item.into();
let code = quote! { let code = quote! {
#item #ast
impl #impl_generics crate::block::BlockMetadata for #name #ty_generics { impl #impl_generics crate::block::BlockMetadata for #name #ty_generics #where_clause {
fn namespace(&self) -> &'static str { fn namespace(&self) -> &'static str {
#namespace #namespace
} }
@ -195,182 +202,183 @@ pub fn pumpkin_block(input: TokenStream, item: TokenStream) -> TokenStream {
} }
#[proc_macro_attribute] #[proc_macro_attribute]
pub fn pumpkin_block_from_tag(input: TokenStream, item: TokenStream) -> TokenStream { pub fn pumpkin_block_from_tag(args: TokenStream, item: TokenStream) -> TokenStream {
let ast: syn::DeriveInput = syn::parse(item.clone()).unwrap(); let arg_lit = parse_macro_input!(args as LitStr);
let ast = parse_macro_input!(item as DeriveInput);
let name = &ast.ident; 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 full_tag = arg_lit.value();
let packet_name = input_string.trim_matches('"');
let packet_name_split: Vec<&str> = packet_name.split(":").collect();
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(); quote! {
#ast
let code = quote! { impl #impl_generics crate::block::BlockMetadata for #name #ty_generics #where_clause {
#item
impl #impl_generics crate::block::BlockMetadata for #name #ty_generics {
fn namespace(&self) -> &'static str { fn namespace(&self) -> &'static str {
#namespace #namespace
} }
fn ids(&self) -> &'static [&'static str] { 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>>();
} }
.into()
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()
} }
// #[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] #[rustfmt::skip]
#[proc_macro_derive(PacketWrite, attributes(serial))] #[proc_macro_derive(PacketWrite, attributes(serial))]
pub fn derive_serialize(input: TokenStream) -> TokenStream { pub fn derive_serialize(input: TokenStream) -> TokenStream {

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -307,9 +307,9 @@ impl AnvilChunkData {
.decompress_data(&self.compressed_data) .decompress_data(&self.compressed_data)
.map_err(ChunkReadingError::Compression)?; .map_err(ChunkReadingError::Compression)?;
S::from_bytes(decompress_bytes.into(), pos) S::from_bytes(&decompress_bytes.into(), pos)
} else { } 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( fn to_bytes(
&self, &self,
) -> Pin<Box<dyn Future<Output = Result<Bytes, ChunkSerializingError>> + Send + '_>>; ) -> 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>; fn position(&self) -> &Vector2<i32>;
} }
@ -540,7 +540,7 @@ impl<S: SingleChunkDataSerializer> ChunkSerializer for AnvilChunkFile<S> {
format!("./r.{region_x}.{region_z}.mca") 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; let mut write_action = self.write_action.lock().await;
match &*write_action { match &*write_action {
WriteAction::Pass => { WriteAction::Pass => {
@ -550,9 +550,9 @@ impl<S: SingleChunkDataSerializer> ChunkSerializer for AnvilChunkFile<S> {
); );
Ok(()) Ok(())
} }
WriteAction::All => self.write_all(&path).await, WriteAction::All => self.write_all(path).await,
WriteAction::Parts(parts) => { 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 .await
} }
}?; }?;

View File

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

View File

@ -31,8 +31,8 @@ pub mod linear;
impl SingleChunkDataSerializer for ChunkData { impl SingleChunkDataSerializer for ChunkData {
#[inline] #[inline]
fn from_bytes(bytes: Bytes, pos: Vector2<i32>) -> Result<Self, ChunkReadingError> { fn from_bytes(bytes: &Bytes, pos: Vector2<i32>) -> Result<Self, ChunkReadingError> {
Self::internal_from_bytes(&bytes, pos).map_err(ChunkReadingError::ParsingError) Self::internal_from_bytes(bytes, pos).map_err(ChunkReadingError::ParsingError)
} }
#[inline] #[inline]
@ -116,46 +116,49 @@ impl ChunkData {
position.x, position.y, chunk_data.x_pos, chunk_data.z_pos, position.x, position.y, chunk_data.x_pos, chunk_data.z_pos,
))); )));
} }
let (block_lights, sky_lights, sub_chunks) = chunk_data
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
.sections .sections
.into_iter() .into_iter()
.map(|section| SubChunk { .map(|section| {
block_states: section let block_light = section
.block_states .block_light
.map(BlockPalette::from_disk_nbt) .map(LightContainer::new)
.unwrap_or_default(), .unwrap_or_default();
biomes: section let sky_light = section
.biomes .sky_light
.map(BiomePalette::from_disk_nbt) .map(LightContainer::new)
.unwrap_or_default(), .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 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 { Ok(ChunkData {
section, section,
@ -249,8 +252,8 @@ impl Dirtiable for ChunkEntityData {
impl SingleChunkDataSerializer for ChunkEntityData { impl SingleChunkDataSerializer for ChunkEntityData {
#[inline] #[inline]
fn from_bytes(bytes: Bytes, pos: Vector2<i32>) -> Result<Self, ChunkReadingError> { fn from_bytes(bytes: &Bytes, pos: Vector2<i32>) -> Result<Self, ChunkReadingError> {
Self::internal_from_bytes(&bytes, pos).map_err(ChunkReadingError::ParsingError) Self::internal_from_bytes(bytes, pos).map_err(ChunkReadingError::ParsingError)
} }
#[inline] #[inline]

View File

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

View File

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

View File

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

View File

@ -106,7 +106,11 @@ impl DualNoiseBlockStateProvider {
&BlockPos(pos.0.add(&Vector3::new(i * 54545, 0, i * 34234))), &BlockPos(pos.0.add(&Vector3::new(i * 54545, 0, i * 34234))),
&sampler, &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); let value = self.base.base.get_noise(pos);
self.base.get_state_by_value(&list, value).get_state() 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() 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); 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); let section_z = section_coords::block_to_section(start_block_z);
AquiferSampler::Aquifer(WorldAquiferSampler::new( AquiferSampler::Aquifer(WorldAquiferSampler::new(
Vector2::new(section_x, section_z), Vector2::new(section_x, section_z),
random_config.aquifer_random_deriver.clone(), &random_config.aquifer_random_deriver,
generation_shape.min_y, generation_shape.min_y,
generation_shape.height, generation_shape.height,
level_sampler, level_sampler,

View File

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

View File

@ -82,11 +82,11 @@ impl StandardChunkFluidLevelSampler {
} }
impl FluidLevelSamplerImpl for 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 { if y < self.bottom_y {
self.bottom_fluid.clone() &self.bottom_fluid
} else { } else {
self.top_fluid.clone() &self.top_fluid
} }
} }
} }

View File

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

View File

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

View File

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

View File

@ -41,7 +41,6 @@ tokio = { workspace = true, features = [
"io-util", "io-util",
"time", "time",
] } ] }
rayon.workspace = true
thiserror.workspace = true thiserror.workspace = true
futures.workspace = true futures.workspace = true
@ -60,13 +59,14 @@ rustyline-async = "0.4.7"
# encryption # encryption
rsa = { version = "=0.10.0-rc.10", features = ["sha1"] } rsa = { version = "=0.10.0-rc.10", features = ["sha1"] }
rsa-der = "0.3" pkcs8 = "=0.11.0-rc.8"
# authentication # authentication
ureq = { version = "3.1.4", features = [ ureq = { version = "3.1.4", features = [
"json", "json",
] } ] }
sha1 = "=0.11.0-rc.3" sha1 = "=0.11.0-rc.3"
# velocity en # velocity en
@ -79,7 +79,7 @@ base64 = "0.22.1"
simplelog = { version = "0.12.2", features = ["ansi_term"] } simplelog = { version = "0.12.2", features = ["ansi_term"] }
# Remove time in favor of chrono? # Remove time in favor of chrono?
time = "0.3" time = { version = "0.3", features = ["parsing", "macros"] }
# plugins # plugins
libloading = "0.9" libloading = "0.9"
@ -88,18 +88,12 @@ rustc-hash = "2.1.1"
# Task handling # Task handling
tokio-util = { version = "0.7.17", features = ["rt"] } tokio-util = { version = "0.7.17", features = ["rt"] }
# Memory profiling flate2 = "1.1.5"
dhat = { version = "0.3.3", optional = true } console-subscriber = { version = "0.5.0", default-features= false, optional = true }
flate2 = "1.1.7"
console-subscriber = { version = "0.5.0", optional = true }
signature = "2.2.0" signature = "2.2.0"
[dev-dependencies] [dev-dependencies]
tempfile.workspace = true tempfile.workspace = true
[features] [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"] console-subscriber = ["dep:console-subscriber"]
tokio_taskdump = ["pumpkin-world/tokio_taskdump"] 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, ()> { 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 { 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, ()> { 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. /// 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, ()> { 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> { 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 /// onBlockAdded in source code
fn placed<'a>(&'a self, _args: PlacedArgs<'a>) -> BlockFuture<'a, ()> { 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, ()> { 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, ()> { 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, ()> { 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 /// Called if a block state is replaced or it replaces another state
fn prepare<'a>(&'a self, _args: PrepareArgs<'a>) -> BlockFuture<'a, ()> { fn prepare<'a>(&'a self, _args: PrepareArgs<'a>) -> BlockFuture<'a, ()> {
Box::pin(async move {}) Box::pin(async {})
} }
fn get_state_for_neighbor_update<'a>( 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, ()> { 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, ()> { fn on_state_replaced<'a>(&'a self, _args: OnStateReplacedArgs<'a>) -> BlockFuture<'a, ()> {
Box::pin(async move {}) Box::pin(async {})
} }
// --- Redstone/Comparator Methods --- // --- Redstone/Comparator Methods ---

View File

@ -56,9 +56,6 @@ mod weather;
mod whitelist; mod whitelist;
mod worldborder; mod worldborder;
#[cfg(feature = "dhat-heap")]
mod profile;
#[must_use] #[must_use]
pub async fn default_dispatcher(basic_config: &BasicConfiguration) -> CommandDispatcher { pub async fn default_dispatcher(basic_config: &BasicConfiguration) -> CommandDispatcher {
let mut dispatcher = CommandDispatcher::default(); let mut dispatcher = CommandDispatcher::default();
@ -144,9 +141,6 @@ pub async fn default_dispatcher(basic_config: &BasicConfiguration) -> CommandDis
// Four // Four
dispatcher.register(stop::init_command_tree(), "minecraft:command.stop"); dispatcher.register(stop::init_command_tree(), "minecraft:command.stop");
#[cfg(feature = "dhat-heap")]
dispatcher.register(profile::init_command_tree(), "pumpkin:command.profile");
dispatcher dispatcher
} }
@ -510,13 +504,4 @@ fn register_level_4_permissions(registry: &mut PermissionRegistry) {
PermissionDefault::Op(PermissionLvl::Four), PermissionDefault::Op(PermissionLvl::Four),
)) ))
.unwrap(); .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 { 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]" "[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, _item: &'a Item,
_player: &'a Player, _player: &'a Player,
) -> Pin<Box<dyn Future<Output = ()> + Send + 'a>> { ) -> Pin<Box<dyn Future<Output = ()> + Send + 'a>> {
Box::pin(async move {}) Box::pin(async {})
} }
fn use_on_block<'a>( fn use_on_block<'a>(
@ -37,7 +37,7 @@ pub trait ItemBehaviour: Send + Sync {
_block: &'a Block, _block: &'a Block,
_server: &'a Server, _server: &'a Server,
) -> Pin<Box<dyn Future<Output = ()> + Send + 'a>> { ) -> Pin<Box<dyn Future<Output = ()> + Send + 'a>> {
Box::pin(async move {}) Box::pin(async {})
} }
fn use_on_entity<'a>( fn use_on_entity<'a>(
@ -46,7 +46,7 @@ pub trait ItemBehaviour: Send + Sync {
_player: &'a Player, _player: &'a Player,
_entity: Arc<dyn EntityBase>, _entity: Arc<dyn EntityBase>,
) -> Pin<Box<dyn Future<Output = ()> + Send + 'a>> { ) -> Pin<Box<dyn Future<Output = ()> + Send + 'a>> {
Box::pin(async move {}) Box::pin(async {})
} }
fn can_mine(&self, _player: &Player) -> bool { fn can_mine(&self, _player: &Player) -> bool {

View File

@ -42,10 +42,6 @@ pub mod plugin;
pub mod server; pub mod server;
pub mod world; 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>> = pub static PLUGIN_MANAGER: LazyLock<Arc<PluginManager>> =
LazyLock::new(|| Arc::new(PluginManager::new())); 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::signal::unix::{SignalKind, signal};
use tokio::sync::RwLock; 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_config::{AdvancedConfiguration, BasicConfiguration, LoadConfiguration};
use pumpkin_util::{ use pumpkin_util::{
@ -74,13 +74,6 @@ pub mod plugin;
pub mod server; pub mod server;
pub mod world; 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>> = pub static PLUGIN_MANAGER: LazyLock<Arc<PluginManager>> =
LazyLock::new(|| Arc::new(PluginManager::new())); LazyLock::new(|| Arc::new(PluginManager::new()));
@ -102,13 +95,6 @@ const CARGO_PKG_VERSION: &str = env!("CARGO_PKG_VERSION");
async fn main() { async fn main() {
#[cfg(feature = "console-subscriber")] #[cfg(feature = "console-subscriber")]
console_subscriber::init(); 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 time = Instant::now();
let exec_dir = std::env::current_dir().unwrap(); let exec_dir = std::env::current_dir().unwrap();
@ -123,10 +109,6 @@ async fn main() {
let default_panic = std::panic::take_hook(); let default_panic = std::panic::take_hook();
std::panic::set_hook(Box::new(move |info| { 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); default_panic(info);
// TODO: Gracefully exit? // TODO: Gracefully exit?
// We need to abide by the panic rules here. // 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 serde::Deserialize;
use sha1::Digest; use sha1::Digest;
use sha2::Sha256; use sha2::Sha256;
use simplelog::FormatItem;
use tokio::task::JoinHandle; use tokio::task::JoinHandle;
use thiserror::Error; use thiserror::Error;
@ -180,7 +179,7 @@ pub async fn can_not_join(
address: &SocketAddr, address: &SocketAddr,
server: &Server, server: &Server,
) -> Option<TextComponent> { ) -> 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]" "[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 /// # Returns
/// The priority of the event handler. /// The priority of the event handler.
fn get_priority(&self) -> EventPriority; fn get_priority(&self) -> &EventPriority;
} }
/// A trait for handling specific events. /// A trait for handling specific events.
@ -72,7 +72,7 @@ pub trait EventHandler<E: Payload>: Send + Sync {
/// # Arguments /// # Arguments
/// - `event`: A mutable reference to the event to handle. /// - `event`: A mutable reference to the event to handle.
fn handle_blocking(&self, _server: &Arc<Server>, _event: &mut E) -> BoxFuture<'_, ()> { 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. /// Retrieves the priority of the handler.
fn get_priority(&self) -> EventPriority { fn get_priority(&self) -> &EventPriority {
self.priority.clone() &self.priority
} }
} }

View File

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