Improve chunk generation speed by 5x (#988)

* Fewer locks and limit chunk gen to 2x per core

* remove logs

* Fix server shutdown

* Always use static blockstate

* Remove clone from block

* Fix clippy

* Imporve perf

* Implement FyorDev & MartV0 lookup tables

* Add chunk benchmark (FyorDev)

* fix c

* Fix CI

* fix clippy

* Format

* fix CI fr

* format

* Update benchmark to 1000 chunks
This commit is contained in:
4lve
2025-07-02 09:48:36 +02:00
committed by GitHub
parent 5dac015dd9
commit 622e2a13d2
123 changed files with 886 additions and 728 deletions

67
Cargo.lock generated
View File

@@ -1041,6 +1041,12 @@ version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
[[package]]
name = "hermit-abi"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c"
[[package]]
name = "hmac"
version = "0.13.0-rc.0"
@@ -1600,6 +1606,16 @@ dependencies = [
"autocfg",
]
[[package]]
name = "num_cpus"
version = "1.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "91df4bbde75afed763b708b7eee1e8e7651e02d97f6d5dd763e89367e957b23b"
dependencies = [
"hermit-abi",
"libc",
]
[[package]]
name = "num_threads"
version = "0.1.7"
@@ -1718,6 +1734,49 @@ dependencies = [
"sha2 0.10.9",
]
[[package]]
name = "phf"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "913273894cec178f401a31ec4b656318d95473527be05c0752cc41cdc32be8b7"
dependencies = [
"phf_macros",
"phf_shared",
"serde",
]
[[package]]
name = "phf_generator"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2cbb1126afed61dd6368748dae63b1ee7dc480191c6262a3b4ff1e29d86a6c5b"
dependencies = [
"fastrand",
"phf_shared",
]
[[package]]
name = "phf_macros"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d713258393a82f091ead52047ca779d37e5766226d009de21696c4e667044368"
dependencies = [
"phf_generator",
"phf_shared",
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "phf_shared"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "06005508882fb681fd97892ecff4b7fd0fee13ef1aa569f8695dae7ab9099981"
dependencies = [
"siphasher",
]
[[package]]
name = "pin-project"
version = "1.1.10"
@@ -1962,6 +2021,7 @@ name = "pumpkin-data"
version = "0.1.0-dev+1.21.7"
dependencies = [
"heck",
"phf",
"proc-macro2",
"pumpkin-util",
"quote",
@@ -2090,6 +2150,7 @@ dependencies = [
"lz4-java-wrc",
"num-derive",
"num-traits",
"num_cpus",
"pumpkin-config",
"pumpkin-data",
"pumpkin-nbt",
@@ -2653,6 +2714,12 @@ dependencies = [
"time",
]
[[package]]
name = "siphasher"
version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d"
[[package]]
name = "slab"
version = "0.4.10"

View File

@@ -19,7 +19,7 @@ edition = "2024"
[profile.dev]
opt-level = 0
#opt-level = 0
[profile.release]
lto = true

View File

@@ -5,6 +5,7 @@ edition.workspace = true
build = "build/build.rs"
[dependencies]
phf = { version = "0.12.1", features = ["macros"] }
pumpkin-util = { path = "../pumpkin-util" }
serde.workspace = true

View File

@@ -11,6 +11,19 @@ use syn::{Ident, LitInt, LitStr};
use crate::loot::LootTableStruct;
// Takes an array of tuples containing indices paired with values,Add commentMore actions
// Outputs an array with the values in the appropriate index, gaps filled with None
fn fill_array<T: Clone + quote::ToTokens>(array: Vec<(u16, T)>) -> Vec<TokenStream> {
let max_index = array.iter().map(|(index, _)| index).max().unwrap();
let mut raw_id_from_state_id_ordered = vec![quote! { None }; (max_index + 1) as usize];
for (state_id, id_lit) in array {
raw_id_from_state_id_ordered[state_id as usize] = quote! { Some(#id_lit) };
}
raw_id_from_state_id_ordered
}
fn const_block_name_from_block_name(block: &str) -> String {
block.to_shouty_snake_case()
}
@@ -413,12 +426,6 @@ impl PistonBehavior {
}
}
#[derive(Deserialize, Clone, Debug)]
pub struct BlockStateRef {
pub id: u16,
pub state_idx: u16,
}
impl BlockState {
fn to_tokens(&self) -> TokenStream {
let mut tokens = TokenStream::new();
@@ -473,20 +480,6 @@ impl BlockState {
}
}
impl ToTokens for BlockStateRef {
fn to_tokens(&self, tokens: &mut TokenStream) {
let id = LitInt::new(&self.id.to_string(), Span::call_site());
let state_idx = LitInt::new(&self.state_idx.to_string(), Span::call_site());
tokens.extend(quote! {
BlockStateRef {
id: #id,
state_idx: #state_idx,
}
});
}
}
#[derive(Deserialize, Clone, Debug)]
pub struct Block {
pub id: u16,
@@ -506,26 +499,8 @@ pub struct Block {
pub experience: Option<Experience>,
}
#[derive(Deserialize, Clone, Debug)]
pub struct OptimizedBlock {
pub id: u16,
pub name: String,
pub translation_key: String,
pub hardness: f32,
pub blast_resistance: f32,
pub item_id: u16,
pub flammable: Option<FlammableStruct>,
pub loot_table: Option<LootTableStruct>,
pub slipperiness: f32,
pub velocity_multiplier: f32,
pub jump_velocity_multiplier: f32,
pub default_state_id: u16,
pub states: Vec<BlockStateRef>,
pub experience: Option<Experience>,
}
impl OptimizedBlock {
fn to_tokens(&self, tokens: &mut TokenStream, all_states: &[BlockState]) {
impl Block {
fn to_tokens(&self, tokens: &mut TokenStream) {
let id = LitInt::new(&self.id.to_string(), Span::call_site());
let name = LitStr::new(&self.name, Span::call_site());
let translation_key = LitStr::new(&self.translation_key, Span::call_site());
@@ -543,7 +518,7 @@ impl OptimizedBlock {
None => quote! { None },
};
// Generate state tokens
let states = self.states.iter().map(|state| state.to_token_stream());
let states = self.states.iter().map(|state| state.to_tokens());
let loot_table = match &self.loot_table {
Some(table) => {
let table_tokens = table.to_token_stream();
@@ -552,12 +527,12 @@ impl OptimizedBlock {
None => quote! { None },
};
let default_state_ref: &BlockStateRef = self
let default_state_ref: &BlockState = self
.states
.iter()
.find(|state| state.id == self.default_state_id)
.unwrap();
let mut default_state = all_states[default_state_ref.state_idx as usize].clone();
let mut default_state = default_state_ref.clone();
default_state.id = default_state_ref.id;
let default_state = default_state.to_tokens();
let flammable = match &self.flammable {
@@ -578,7 +553,7 @@ impl OptimizedBlock {
velocity_multiplier: #velocity_multiplier,
jump_velocity_multiplier: #jump_velocity_multiplier,
item_id: #item_id,
default_state: #default_state,
default_state: &#default_state,
states: &[#(#states),*],
flammable: #flammable,
loot_table: #loot_table,
@@ -665,9 +640,9 @@ pub(crate) fn build() -> TokenStream {
serde_json::from_str(&fs::read_to_string("../assets/properties.json").unwrap())
.expect("Failed to parse properties.json");
let mut type_from_raw_id_arms = TokenStream::new();
let mut type_from_name = TokenStream::new();
let mut block_from_state_id = TokenStream::new();
let mut type_from_raw_id_items = TokenStream::new();
let mut block_from_name = TokenStream::new();
let mut raw_id_from_state_id = TokenStream::new();
let mut block_from_item_id = TokenStream::new();
let mut block_properties_from_state_and_block_id = TokenStream::new();
let mut block_properties_from_props_and_name = TokenStream::new();
@@ -699,46 +674,9 @@ pub(crate) fn build() -> TokenStream {
// Mapping of a collection of property hashes -> blocks that have these properties.
let mut property_collection_map: HashMap<Vec<i32>, PropertyCollectionData> = HashMap::new();
// Validator that we have no `enum` collisions.
let mut optimized_blocks: Vec<(String, OptimizedBlock)> = Vec::new();
let mut optimized_blocks: Vec<(String, Block)> = Vec::new();
for block in blocks_assets.blocks.clone() {
let optimized_block = OptimizedBlock {
id: block.id,
name: block.name.clone(),
translation_key: block.translation_key.clone(),
hardness: block.hardness,
blast_resistance: block.blast_resistance,
item_id: block.item_id,
default_state_id: block.default_state_id,
slipperiness: block.slipperiness,
velocity_multiplier: block.velocity_multiplier,
jump_velocity_multiplier: block.jump_velocity_multiplier,
flammable: block.flammable,
loot_table: block.loot_table,
experience: block.experience,
states: block
.states
.iter()
.map(|state| {
// Find the index in `unique_states` by comparing all fields except `id`.
let state_idx = unique_states
.iter()
.position(|s| {
s.state_flags == state.state_flags
&& s.luminance == state.luminance
&& s.hardness == state.hardness
&& s.collision_shapes == state.collision_shapes
})
.unwrap() as u16;
BlockStateRef {
id: state.id,
state_idx,
}
})
.collect(),
};
optimized_blocks.push((block.name.clone(), optimized_block));
optimized_blocks.push((block.name.clone(), block.clone()));
let mut property_collection = HashSet::new();
let mut property_mapping = Vec::new();
@@ -785,7 +723,7 @@ pub(crate) fn build() -> TokenStream {
property_collection_map
.entry(property_collection)
.or_insert_with(|| PropertyCollectionData::from_mappings(property_mapping))
.add_block(block.name, block.id);
.add_block(block.name.clone(), block.id);
}
}
@@ -821,7 +759,7 @@ pub(crate) fn build() -> TokenStream {
.iter()
.map(|shape| shape.to_token_stream());
let unique_states_tokens = unique_states.iter().map(|state| state.to_tokens());
//let unique_states_tokens = unique_states.iter().map(|state| state.to_tokens());
let block_props = block_properties.iter().map(|prop| prop.to_token_stream());
let properties = property_enums.values().map(|prop| prop.to_token_stream());
@@ -832,14 +770,16 @@ pub(crate) fn build() -> TokenStream {
.iter()
.map(|entity_type| LitStr::new(entity_type, Span::call_site()));
let mut raw_id_from_state_id_array = vec![];
let mut type_from_raw_id_array = vec![];
// Generate constants and `match` arms for each block.
for (name, block) in optimized_blocks {
let const_ident = format_ident!("{}", const_block_name_from_block_name(&name));
let mut block_tokens = TokenStream::new();
block.to_tokens(&mut block_tokens, &unique_states);
block.to_tokens(&mut block_tokens);
let id_lit = LitInt::new(&block.id.to_string(), Span::call_site());
let state_start = block.states.iter().map(|state| state.id).min().unwrap();
let state_end = block.states.iter().map(|state| state.id).max().unwrap();
let item_id = block.item_id;
constants.extend(quote! {
@@ -847,34 +787,48 @@ pub(crate) fn build() -> TokenStream {
});
type_from_raw_id_arms.extend(quote! {
#id_lit => Some(Self::#const_ident),
type_from_raw_id_array.push((block.id, quote! { &Self::#const_ident }));
block_from_name.extend(quote! {
#name => Self::#const_ident,
});
type_from_name.extend(quote! {
#name => Some(Self::#const_ident),
});
block_from_state_id.extend(quote! {
#state_start..=#state_end => Some(Self::#const_ident),
});
for state in &block.states {
raw_id_from_state_id_array.push((state.id, id_lit.clone()));
}
if !existing_item_ids.contains(&item_id) {
block_from_item_id.extend(quote! {
#item_id => Some(Self::#const_ident),
#item_id => Some(&Self::#const_ident),
});
existing_item_ids.push(item_id);
}
}
let raw_id_from_state_id_ordered = fill_array(raw_id_from_state_id_array);
let max_state_id = raw_id_from_state_id_ordered.len();
for id_lit in raw_id_from_state_id_ordered {
raw_id_from_state_id.extend(quote! {
#id_lit,
});
}
let type_from_raw_id_array = fill_array(type_from_raw_id_array);
let max_type_id = type_from_raw_id_array.len();
for type_lit in type_from_raw_id_array {
type_from_raw_id_items.extend(quote! {
#type_lit,
});
}
quote! {
use crate::{BlockState, BlockStateRef, Block, CollisionShape, blocks::Flammable};
use crate::{BlockState, Block, CollisionShape, blocks::Flammable};
use crate::block_state::PistonBehavior;
use pumpkin_util::math::int_provider::{UniformIntProvider, IntProvider, NormalIntProvider};
use pumpkin_util::loot_table::*;
use pumpkin_util::math::experience::Experience;
use pumpkin_util::math::vector3::Vector3;
use std::collections::HashMap;
use phf;
#[derive(Clone, Copy, Debug)]
@@ -918,53 +872,53 @@ pub(crate) fn build() -> TokenStream {
#(#shapes),*
];
pub static BLOCK_STATES: &[BlockState] = &[
#(#unique_states_tokens),*
];
//pub static BLOCK_STATES: &[BlockState] = &[
// #(#unique_states_tokens),*
//];
pub static BLOCK_ENTITY_TYPES: &[&str] = &[
#(#block_entity_types),*
];
pub fn get_block(registry_id: &str) -> Option<Block> {
pub fn get_block(registry_id: &str) -> Option<&'static Block> {
let key = registry_id.strip_prefix("minecraft:").unwrap_or(registry_id);
Block::from_registry_key(key)
}
pub fn get_block_by_id(id: u16) -> Option<Block> {
pub fn get_block_by_id(id: u16) -> Option<&'static Block> {
Block::from_id(id)
}
pub fn get_state_by_state_id(id: u16) -> Option<BlockState> {
pub fn get_state_by_state_id(id: u16) -> Option<&'static BlockState> {
if let Some(block) = Block::from_state_id(id) {
let state: &BlockStateRef = block.states.iter().find(|state| state.id == id)?;
Some(state.get_state())
let state: &BlockState = block.states.iter().find(|state| state.id == id)?;
Some(state)
} else {
None
}
}
pub fn get_block_by_state_id(id: u16) -> Option<Block> {
pub fn get_block_by_state_id(id: u16) -> Option<&'static Block> {
Block::from_state_id(id)
}
pub fn get_block_and_state_by_state_id(id: u16) -> Option<(Block, BlockState)> {
pub fn get_block_and_state_by_state_id(id: u16) -> Option<(&'static Block, &'static BlockState)> {
if let Some(block) = Block::from_state_id(id) {
let state: &BlockStateRef = block.states.iter().find(|state| state.id == id)?;
Some((block, state.get_state()))
let state: &BlockState = block.states.iter().find(|state| state.id == id)?;
Some((block, state))
} else {
None
}
}
pub fn get_block_by_item(item_id: u16) -> Option<Block> {
pub fn get_block_by_item(item_id: u16) -> Option<&'static Block> {
Block::from_item_id(item_id)
}
pub fn blocks_movement(block_state: &BlockState) -> bool {
if block_state.is_solid() {
if let Some(block) = get_block_by_state_id(block_state.id) {
return block != Block::COBWEB && block != Block::BAMBOO_SAPLING;
return block != &Block::COBWEB && block != &Block::BAMBOO_SAPLING;
}
}
false
@@ -973,32 +927,47 @@ pub(crate) fn build() -> TokenStream {
impl Block {
#constants
// String name to block struct
const BLOCK_FROM_NAME_MAP: phf::Map<&'static str, Block> = phf::phf_map!{
#block_from_name
};
// Many state ids map to single raw block id
const RAW_ID_FROM_STATE_ID: [Option<u16>; #max_state_id] = [
#raw_id_from_state_id
];
const TYPE_FROM_RAW_ID: [Option<&Block>; #max_type_id] = [
#type_from_raw_id_items
];
#[doc = r" Try to parse a block from a resource location string."]
pub fn from_registry_key(name: &str) -> Option<Self> {
match name {
#type_from_name
_ => None
}
pub fn from_registry_key(name: &str) -> Option<&'static Self> {
Self::BLOCK_FROM_NAME_MAP.get(name)
}
#[doc = r" Try to parse a block from a raw id."]
pub const fn from_id(id: u16) -> Option<Self> {
match id {
#type_from_raw_id_arms
_ => None
pub const fn from_id(id: u16) -> Option<&'static Self> {
if id as usize >= Self::RAW_ID_FROM_STATE_ID.len() {
None
} else {
Self::TYPE_FROM_RAW_ID[id as usize]
}
}
#[doc = r" Try to parse a block from a state id."]
pub const fn from_state_id(id: u16) -> Option<Self> {
match id {
#block_from_state_id
_ => None
pub const fn from_state_id(id: u16) -> Option<&'static Self> {
if id as usize >= Self::RAW_ID_FROM_STATE_ID.len() {
return None;
}
match Self::RAW_ID_FROM_STATE_ID[id as usize] {
Some(id) => Self::from_id(id),
None => None,
}
}
#[doc = r" Try to parse a block from an item id."]
pub const fn from_item_id(id: u16) -> Option<Self> {
pub const fn from_item_id(id: u16) -> Option<&'static Self> {
#[allow(unreachable_patterns)]
match id {
#block_from_item_id
@@ -1027,14 +996,6 @@ pub(crate) fn build() -> TokenStream {
#(#block_props)*
impl BlockStateRef {
pub fn get_state(&self) -> BlockState {
let mut state = BLOCK_STATES[self.state_idx as usize].clone();
state.id = self.id;
state
}
}
impl Facing {
pub fn opposite(&self) -> Self {
match self {

View File

@@ -40,22 +40,20 @@ pub(crate) fn build() -> TokenStream {
.to_token_stream();
// Generate tag arrays for each registry key
let mut tag_arrays = Vec::new();
let mut tag_dicts = Vec::new();
let mut match_arms = Vec::new();
let mut match_arms_tags_all = Vec::new();
let mut tag_identifiers = Vec::new();
for (key, tag_map) in &tags {
let key_pascal = format_ident!("{}", key.to_pascal_case());
let array_name = format_ident!("{}_TAGS", key.to_pascal_case().to_uppercase());
let dict_name = format_ident!("{}_TAGS", key.to_pascal_case().to_uppercase());
// Create a HashMap to store tag name -> index mapping
let mut tag_indices = HashMap::new();
let mut tag_values = Vec::new();
// Collect all unique tags
for (tag_name, values) in tag_map {
tag_indices.insert(tag_name.clone(), tag_values.len());
tag_values.push((tag_name.clone(), values.clone()));
}
@@ -65,35 +63,27 @@ pub(crate) fn build() -> TokenStream {
.map(|(tag_name, values)| {
let tag_values_array = values.iter().map(|v| quote! { #v }).collect::<Vec<_>>();
quote! {
(#tag_name, &[#(#tag_values_array),*])
#tag_name => &[#(#tag_values_array),*]
}
})
.collect::<Vec<_>>();
let tag_array_len = tag_values.len();
// Add the static array declaration
tag_arrays.push(quote! {
static #array_name: [(&str, &[&str]); #tag_array_len] = [
tag_dicts.push(quote! {
static #dict_name: phf::Map<&str, &[&str]> = phf::phf_map! {
#(#tag_array_entries),*
];
};
});
// Add match arm for this registry key
match_arms.push(quote! {
RegistryKey::#key_pascal => {
for (tag_name, values) in &#array_name {
if *tag_name == tag {
return Some(*values);
}
}
None
#dict_name.get(tag).copied()
}
});
match_arms_tags_all.push(quote! {
RegistryKey::#key_pascal => {
&#array_name
&#dict_name
}
});
@@ -103,48 +93,49 @@ pub(crate) fn build() -> TokenStream {
}
quote! {
#[derive(Eq, PartialEq, Hash, Debug)]
#registry_key_enum
#[derive(Eq, PartialEq, Hash, Debug)]
#registry_key_enum
impl RegistryKey {
// IDK why the linter is saying this isn't used
#[allow(dead_code)]
pub fn identifier_string(&self) -> &str {
match self {
#(#tag_identifiers),*
}
}
}
impl RegistryKey {
// IDK why the linter is saying this isn't used
#[allow(dead_code)]
pub fn identifier_string(&self) -> &str {
match self {
#(#tag_identifiers),*
}
}
}
#(#tag_arrays)*
#(#tag_dicts)*
pub fn get_tag_values(tag_category: RegistryKey, tag: &str) -> Option<&'static [&'static str]> {
match tag_category {
#(#match_arms),*
}
}
pub fn get_tag_values(tag_category: RegistryKey, tag: &str) -> Option<&'static [&'static str]> {
match tag_category {
#(#match_arms),*
}
}
pub fn get_registry_key_tags(tag_category: &RegistryKey) -> &'static [(&'static str, &'static [&'static str])] {
match tag_category {
#(#match_arms_tags_all),*
}
}
pub fn get_registry_key_tags(tag_category: &RegistryKey) -> &phf::Map<&'static str, &'static [&'static str]> {
match tag_category {
#(#match_arms_tags_all),*
}
}
pub trait Tagable {
fn tag_key() -> RegistryKey;
fn registry_key(&self) -> &str;
pub trait Tagable {
fn tag_key() -> RegistryKey;
fn registry_key(&self) -> &str;
/// Returns `None` if the tag does not exist.
fn is_tagged_with(&self, tag: &str) -> Option<bool> {
let tag = tag.strip_prefix("#").unwrap_or(tag);
let items = get_tag_values(Self::tag_key(), tag)?;
Some(items.iter().any(|elem| *elem == self.registry_key()))
}
/// Returns `None` if the tag does not exist.
fn is_tagged_with(&self, tag: &str) -> Option<bool> {
let tag = tag.strip_prefix("#").unwrap_or(tag);
let items = get_tag_values(Self::tag_key(), tag)?;
Some(items.iter().any(|elem| *elem == self.registry_key()))
}
fn get_tag_values(tag: &str) -> Option<&'static [&'static str]> {
let tag = tag.strip_prefix("#").unwrap_or(tag);
get_tag_values(Self::tag_key(), tag)
}
}
}
fn get_tag_values(tag: &str) -> Option<&'static [&'static str]> {
let tag = tag.strip_prefix("#").unwrap_or(tag);
get_tag_values(Self::tag_key(), tag)
}
}
}
}

View File

@@ -3,7 +3,7 @@ use pumpkin_util::math::vector3::Vector3;
use crate::block_properties::{COLLISION_SHAPES, Instrument, get_block_by_state_id};
use crate::{Block, BlockDirection, CollisionShape};
#[derive(Clone, Debug)]
#[derive(Debug)]
pub struct BlockState {
pub id: u16,
pub state_flags: u8,
@@ -92,7 +92,7 @@ impl BlockState {
}
}
pub fn block(&self) -> Block {
pub fn block(&self) -> &'static Block {
get_block_by_state_id(self.id).unwrap()
}

View File

@@ -5,7 +5,7 @@ use crate::{
};
use pumpkin_util::{loot_table::LootTable, math::experience::Experience};
#[derive(Clone, Debug)]
#[derive(Debug)]
pub struct Block {
pub id: u16,
pub name: &'static str,
@@ -16,8 +16,8 @@ pub struct Block {
pub velocity_multiplier: f32,
pub jump_velocity_multiplier: f32,
pub item_id: u16,
pub default_state: BlockState,
pub states: &'static [BlockStateRef],
pub default_state: &'static BlockState,
pub states: &'static [BlockState],
pub flammable: Option<Flammable>,
pub loot_table: Option<LootTable>,
pub experience: Option<Experience>,

View File

@@ -35,7 +35,7 @@ impl ClientPacket for CUpdateTags<'_> {
WritingError::Message(format!("{} isn't representable as a VarInt", values.len()))
})?)?;
for (key, values) in values.iter() {
for (key, values) in values.entries() {
// This is technically a `ResourceLocation` but same thing
p.write_string_bounded(key, u16::MAX as usize)?;
p.write_list(values, |p, string_id| {

View File

@@ -46,6 +46,7 @@ thread_local = "1.1.9"
lru = "0.15.0"
tokio-util = { version = "0.7.15", features = ["rt"] }
num_cpus = "1.17.0"
[dev-dependencies]
criterion = { version = "0.6", features = ["html_reports", "async_tokio"] }
@@ -64,3 +65,7 @@ harness = false
[[bench]]
name = "chunk_io"
harness = false
[[bench]]
name = "chunk_gen"
harness = false

View File

@@ -0,0 +1,83 @@
use criterion::{Criterion, criterion_group, criterion_main};
use async_trait::async_trait;
use pumpkin_data::BlockDirection;
use pumpkin_util::math::position::BlockPos;
use pumpkin_util::math::vector2::Vector2;
use pumpkin_world::generation::implementation::WorldGenerator;
use std::sync::Arc;
use temp_dir::TempDir;
use tokio_util::task::TaskTracker;
use pumpkin_world::dimension::Dimension;
use pumpkin_world::generation::{Seed, get_world_gen};
use pumpkin_world::level::Level;
use pumpkin_world::world::{BlockAccessor, BlockRegistryExt};
use tokio::runtime::Runtime;
struct BlockRegistry;
#[async_trait]
impl BlockRegistryExt for BlockRegistry {
async fn can_place_at(
&self,
_block: &pumpkin_data::Block,
_block_accessor: &dyn BlockAccessor,
_block_pos: &BlockPos,
_face: BlockDirection,
) -> bool {
true
}
}
async fn chunk_generation_seed(seed: i64) {
let generator: Arc<dyn WorldGenerator> =
get_world_gen(Seed(seed as u64), Dimension::Overworld).into();
let temp_dir = TempDir::new().unwrap();
let block_registry = Arc::new(BlockRegistry);
let level = Arc::new(Level::from_root_folder(
temp_dir.path().to_path_buf(),
block_registry.clone(),
seed,
Dimension::Overworld,
));
let tasks = TaskTracker::new();
for x in 0..100 {
for y in 0..10 {
let position = Vector2::new(x, y);
let generator_clone = generator.clone();
let level_clone = level.clone();
let block_registry_clone = block_registry.clone();
tasks.spawn(async move {
generator_clone
.generate_chunk(&level_clone, block_registry_clone.as_ref(), &position)
.await;
});
}
}
tasks.close();
tasks.wait().await;
}
fn bench_chunk_generation(c: &mut Criterion) {
let seeds = [0];
let runtime = Runtime::new().unwrap();
for seed in seeds {
let name = format!("chunk generation seed {seed}");
c.bench_function(&name, |b| {
b.to_async(&runtime).iter(|| chunk_generation_seed(seed))
});
}
}
criterion_group! {
name = benches;
config = Criterion::default().sample_size(10).measurement_time(std::time::Duration::from_secs(180));
targets = bench_chunk_generation
}
criterion_main!(benches);

View File

@@ -12,7 +12,7 @@ use super::BlockEntity;
pub struct PistonBlockEntity {
pub position: BlockPos,
pub pushed_block_state: BlockState,
pub pushed_block_state: &'static BlockState,
pub facing: BlockDirection,
pub current_progress: AtomicCell<f32>,
pub last_progress: AtomicCell<f32>,
@@ -27,7 +27,7 @@ impl PistonBlockEntity {
if self.last_progress.load() < 1.0 {
let pos = self.position;
world.remove_block_entity(&pos).await;
if world.get_block(&pos).await == Block::MOVING_PISTON {
if world.get_block(&pos).await == &Block::MOVING_PISTON {
let state = if self.source {
Block::AIR.default_state.id
} else {
@@ -38,7 +38,7 @@ impl PistonBlockEntity {
.set_block_state(&pos, state, BlockFlags::NOTIFY_ALL)
.await;
world
.update_neighbor(&pos, &get_block_by_state_id(state).unwrap())
.update_neighbor(&pos, get_block_by_state_id(state).unwrap())
.await;
}
}
@@ -66,7 +66,7 @@ impl BlockEntity for PistonBlockEntity {
if current_progress >= 1.0 {
let pos = self.position;
world.remove_block_entity(&pos).await;
if world.get_block(&pos).await == Block::MOVING_PISTON {
if world.get_block(&pos).await == &Block::MOVING_PISTON {
if self.pushed_block_state.is_air() {
world
.clone()
@@ -89,7 +89,7 @@ impl BlockEntity for PistonBlockEntity {
.clone()
.update_neighbor(
&pos,
&get_block_by_state_id(self.pushed_block_state.id).unwrap(),
get_block_by_state_id(self.pushed_block_state.id).unwrap(),
)
.await;
}

View File

@@ -4,25 +4,45 @@ pub mod state;
use std::collections::HashMap;
use pumpkin_data::{
BlockState,
Block, BlockState,
block_properties::{get_block, get_state_by_state_id},
};
use serde::{Deserialize, Serialize};
use serde::{Deserialize, Deserializer, Serialize, Serializer};
pub use state::RawBlockState;
#[derive(Serialize, Deserialize, Debug, Clone)]
#[serde(rename_all = "PascalCase")]
pub struct BlockStateCodec {
/// Block name
pub name: String,
#[serde(
deserialize_with = "parse_block_name",
serialize_with = "block_to_string"
)]
pub name: &'static Block,
/// Key-value pairs of properties
#[serde(skip_serializing_if = "Option::is_none")]
pub properties: Option<HashMap<String, String>>,
}
fn parse_block_name<'de, D>(deserializer: D) -> Result<&'static Block, D::Error>
where
D: Deserializer<'de>,
{
let s = String::deserialize(deserializer)?;
let block = get_block(s.as_str()).ok_or(serde::de::Error::custom("Invalid block name"))?;
Ok(block)
}
fn block_to_string<S>(block: &'static Block, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
serializer.serialize_str(block.name)
}
impl BlockStateCodec {
pub fn get_state(&self) -> Option<BlockState> {
let block = get_block(self.name.as_str())?;
pub fn get_state(&self) -> Option<&'static BlockState> {
let block = self.name;
let mut state_id = block.default_state.id;
@@ -32,7 +52,7 @@ impl BlockStateCodec {
.map(|(k, v)| (k.as_str(), v.as_str()))
.collect();
let block_properties = block.from_properties(props).unwrap();
state_id = block_properties.to_state_id(&block);
state_id = block_properties.to_state_id(block);
}
get_state_by_state_id(state_id)

View File

@@ -16,12 +16,12 @@ impl RawBlockState {
}
#[inline]
pub fn to_state(&self) -> pumpkin_data::BlockState {
pub fn to_state(&self) -> &'static pumpkin_data::BlockState {
get_state_by_state_id(self.0).unwrap()
}
#[inline]
pub fn to_block(&self) -> pumpkin_data::Block {
pub fn to_block(&self) -> &'static pumpkin_data::Block {
get_block_by_state_id(self.0).unwrap()
}
}

View File

@@ -198,7 +198,7 @@ impl ChunkData {
.strip_prefix("minecraft:")
.unwrap_or(&tick.target_block),
)
.unwrap_or(Block::AIR)
.unwrap_or(&Block::AIR)
.id,
})
.collect(),
@@ -214,7 +214,7 @@ impl ChunkData {
.strip_prefix("minecraft:")
.unwrap_or(&tick.target_block),
)
.unwrap_or(Block::AIR)
.unwrap_or(&Block::AIR)
.id,
})
.collect(),

View File

@@ -293,7 +293,6 @@ where
}
}?;
let mut serializer = chunk_serializer.write().await;
for chunk_lock in chunk_locks {
let mut chunk = chunk_lock.write().await;
let chunk_is_dirty = chunk.is_dirty();
@@ -306,7 +305,7 @@ where
// We only need to update the chunk if it is dirty
if chunk_is_dirty {
serializer.update_chunk(&*chunk).await?;
chunk_serializer.write().await.update_chunk(&*chunk).await?;
}
}
log::trace!("Updated data for file {path:?}");
@@ -318,10 +317,10 @@ where
.get(&path)
.is_some_and(|count| !count.is_zero());
if serializer.should_write(is_watched) {
if !is_watched {
// With the modification done, we can drop the write lock but keep the read lock
// to avoid other threads to write/modify the data, but allow other threads to read it
let serializer = serializer.downgrade();
let serializer = chunk_serializer.read().await;
log::debug!("Writing file for {path:?}");
serializer

View File

@@ -404,7 +404,7 @@ impl BlockPalette {
} else {
log::warn!(
"Could not find valid block state for {}. Defaulting...",
entry.name
entry.name.name
);
0
}
@@ -438,7 +438,7 @@ impl BlockPalette {
let block = Block::from_state_id(registry_id).unwrap();
BlockStateCodec {
name: block.name.into(),
name: block,
properties: block.properties(registry_id).map(|p| p.to_props()),
}
}

View File

@@ -21,11 +21,11 @@ use super::{
#[derive(Clone)]
pub struct FluidLevel {
max_y: i32,
block: Block,
block: &'static Block,
}
impl FluidLevel {
pub fn new(max_y: i32, block: Block) -> Self {
pub fn new(max_y: i32, block: &'static Block) -> Self {
Self { max_y, block }
}
@@ -33,11 +33,11 @@ impl FluidLevel {
self.max_y
}
fn get_block(&self, y: i32) -> Block {
fn get_block(&self, y: i32) -> &'static Block {
if y < self.max_y {
self.block.clone()
self.block
} else {
Block::AIR
&Block::AIR
}
}
}
@@ -59,18 +59,18 @@ impl FluidLevelSamplerImpl for FluidLevelSampler {
pub struct StaticFluidLevelSampler {
y: i32,
block: Block,
block: &'static Block,
}
impl StaticFluidLevelSampler {
pub fn new(y: i32, block: Block) -> Self {
pub fn new(y: i32, block: &'static Block) -> Self {
Self { y, block }
}
}
impl FluidLevelSamplerImpl for StaticFluidLevelSampler {
fn get_fluid_level(&self, _x: i32, _y: i32, _z: i32) -> FluidLevel {
FluidLevel::new(self.y, self.block.clone())
FluidLevel::new(self.y, self.block)
}
}
@@ -206,8 +206,8 @@ impl WorldAquiferSampler {
let block_state1 = level_1.get_block(y);
let block_state2 = level_2.get_block(y);
if (block_state1 != LAVA_BLOCK || block_state2 != WATER_BLOCK)
&& (block_state1 != WATER_BLOCK || block_state2 != LAVA_BLOCK)
if (block_state1 != &LAVA_BLOCK || block_state2 != &WATER_BLOCK)
&& (block_state1 != &WATER_BLOCK || block_state2 != &LAVA_BLOCK)
{
let level_diff = (level_1.max_y - level_2.max_y).abs();
if level_diff == 0 {
@@ -418,8 +418,8 @@ impl WorldAquiferSampler {
level: i32,
router: &mut ChunkNoiseRouter,
sample_options: &ChunkNoiseFunctionSampleOptions,
) -> Block {
if level <= -10 && level != MIN_HEIGHT_CELL && default_level.block != LAVA_BLOCK {
) -> &'static Block {
if level <= -10 && level != MIN_HEIGHT_CELL && default_level.block != &LAVA_BLOCK {
let x = floor_div(block_x, 64);
let y = floor_div(block_y, 40);
let z = floor_div(block_z, 64);
@@ -427,7 +427,7 @@ impl WorldAquiferSampler {
let sample = router.lava_noise(&UnblendedNoisePos::new(x, y, z), sample_options);
if sample.abs() > 0.3f64 {
return LAVA_BLOCK;
return &LAVA_BLOCK;
}
}
@@ -441,7 +441,7 @@ impl WorldAquiferSampler {
sample_options: &ChunkNoiseFunctionSampleOptions,
height_estimator: &mut SurfaceHeightEstimateSampler,
density: f64,
) -> Option<BlockState> {
) -> Option<&'static BlockState> {
if density > 0f64 {
None
} else {
@@ -450,7 +450,7 @@ impl WorldAquiferSampler {
let k = pos.z();
let fluid_level = self.fluid_level.get_fluid_level(i, j, k);
if fluid_level.get_block(j) == LAVA_BLOCK {
if fluid_level.get_block(j) == &LAVA_BLOCK {
Some(LAVA_BLOCK.default_state)
} else {
let scaled_x = floor_div(i - 5, 16);
@@ -511,12 +511,12 @@ impl WorldAquiferSampler {
// TODO: Handle fluid tick
Some(block_state.default_state)
} else if block_state == WATER_BLOCK
} else if block_state == &WATER_BLOCK
&& self
.fluid_level
.get_fluid_level(i, j - 1, k)
.get_block(j - 1)
== LAVA_BLOCK
== &LAVA_BLOCK
{
Some(block_state.default_state)
} else {
@@ -597,7 +597,7 @@ impl AquiferSamplerImpl for WorldAquiferSampler {
pos: &impl NoisePos,
sample_options: &ChunkNoiseFunctionSampleOptions,
height_estimator: &mut SurfaceHeightEstimateSampler,
) -> Option<BlockState> {
) -> Option<&'static BlockState> {
let density = router.final_density(pos, sample_options);
self.apply_internal(router, pos, sample_options, height_estimator, density)
}
@@ -620,7 +620,7 @@ impl AquiferSamplerImpl for SeaLevelAquiferSampler {
pos: &impl NoisePos,
sample_options: &ChunkNoiseFunctionSampleOptions,
_height_estimator: &mut SurfaceHeightEstimateSampler,
) -> Option<BlockState> {
) -> Option<&'static BlockState> {
let sample = router.final_density(pos, sample_options);
//log::debug!("Aquifer sample {:?}: {}", &pos, sample);
if sample > 0f64 {
@@ -644,7 +644,7 @@ pub trait AquiferSamplerImpl {
pos: &impl NoisePos,
sample_options: &ChunkNoiseFunctionSampleOptions,
height_estimator: &mut SurfaceHeightEstimateSampler,
) -> Option<BlockState>;
) -> Option<&'static BlockState>;
}
#[cfg(test)]
@@ -701,8 +701,8 @@ mod test {
let shape = &surface_config.shape;
let chunk_pos = Vector2::new(7, 4);
let sampler = FluidLevelSampler::Chunk(Box::new(StandardChunkFluidLevelSampler::new(
FluidLevel::new(63, WATER_BLOCK),
FluidLevel::new(-54, LAVA_BLOCK),
FluidLevel::new(63, &WATER_BLOCK),
FluidLevel::new(-54, &LAVA_BLOCK),
)));
const CHUNK_WIDTH: usize = 16;
let noise = ChunkNoiseGenerator::new(
@@ -762,7 +762,7 @@ mod test {
#[test]
fn test_get_fluid_block_state() {
let (mut aquifer, mut router, _, options) = create_aquifer(&PROTO_ROUTER);
let level = FluidLevel::new(0, WATER_BLOCK);
let level = FluidLevel::new(0, &WATER_BLOCK);
let values = [
((-100, -100, -100), WATER_BLOCK),
@@ -895,7 +895,7 @@ mod test {
for ((x, y, z), result) in values {
assert_eq!(
aquifer.get_fluid_block_state(x, y, z, level.clone(), -10, &mut router, &options),
result
&result
);
}
}
@@ -1043,7 +1043,7 @@ mod test {
#[test]
fn test_get_fluid_block_y() {
let (mut aquifer, mut router, _, env) = create_aquifer(&PROTO_ROUTER);
let level = FluidLevel::new(0, WATER_BLOCK);
let level = FluidLevel::new(0, &WATER_BLOCK);
let values = [
((-100, -100, -100), -32512),
((-100, -100, -50), -32512),
@@ -1449,7 +1449,7 @@ mod test {
for ((x, y, z), (y1, state)) in values {
let level = aquifer.get_fluid_level(x, y, z, &mut router, &mut height_estimator, &env);
assert_eq!(level.max_y, y1);
assert_eq!(level.block, state);
assert_eq!(level.block, &state);
}
}
@@ -1586,8 +1586,8 @@ mod test {
];
for ((x, y, z, h1, h2), result) in values {
let level1 = FluidLevel::new(h1, WATER_BLOCK);
let level2 = FluidLevel::new(h2, WATER_BLOCK);
let level1 = FluidLevel::new(h1, &WATER_BLOCK);
let level2 = FluidLevel::new(h2, &WATER_BLOCK);
let pos = UnblendedNoisePos::new(x, y, z);
let sample = router.barrier_noise(&pos, &env);
assert_eq!(

View File

@@ -225,7 +225,7 @@ impl WouldSurviveBlockPredicate {
let pos = self.offset.get(pos);
return block_registry
.can_place_at(
&get_block_by_state_id(state.id).unwrap(),
get_block_by_state_id(state.id).unwrap(),
chunk,
&pos,
BlockDirection::Up,
@@ -259,11 +259,11 @@ impl OffsetBlocksBlockPredicate {
}
*pos
}
pub fn get_block(&self, chunk: &ProtoChunk, pos: &BlockPos) -> Block {
pub fn get_block(&self, chunk: &ProtoChunk, pos: &BlockPos) -> &'static Block {
let pos = self.get(pos);
chunk.get_block_state(&pos.0).to_block()
}
pub fn get_state(&self, chunk: &ProtoChunk, pos: &BlockPos) -> BlockState {
pub fn get_state(&self, chunk: &ProtoChunk, pos: &BlockPos) -> &'static BlockState {
let pos = self.get(pos);
chunk.get_block_state(&pos.0).to_state()
}

View File

@@ -36,7 +36,7 @@ pub enum BlockStateProvider {
}
impl BlockStateProvider {
pub fn get(&self, random: &mut RandomGenerator, pos: BlockPos) -> BlockState {
pub fn get(&self, random: &mut RandomGenerator, pos: BlockPos) -> &'static BlockState {
match self {
BlockStateProvider::NoiseThreshold(provider) => provider.get(random, pos),
BlockStateProvider::NoiseProvider(provider) => provider.get(pos),
@@ -57,7 +57,7 @@ pub struct RandomizedIntBlockStateProvider {
}
impl RandomizedIntBlockStateProvider {
pub fn get(&self, random: &mut RandomGenerator, pos: BlockPos) -> BlockState {
pub fn get(&self, random: &mut RandomGenerator, pos: BlockPos) -> &'static BlockState {
// TODO
self.source.get(random, pos)
}
@@ -69,7 +69,7 @@ pub struct PillarBlockStateProvider {
}
impl PillarBlockStateProvider {
pub fn get(&self, _pos: BlockPos) -> BlockState {
pub fn get(&self, _pos: BlockPos) -> &'static BlockState {
// TODO: random axis
self.state.get_state().unwrap()
}
@@ -85,7 +85,7 @@ pub struct DualNoiseBlockStateProvider {
}
impl DualNoiseBlockStateProvider {
pub fn get(&self, pos: BlockPos) -> BlockState {
pub fn get(&self, pos: BlockPos) -> &'static BlockState {
let noise = perlin_codec_to_static(self.slow_noise.clone());
let sampler = DoublePerlinNoiseSampler::new(
&mut RandomGenerator::Legacy(LegacyRand::from_seed(self.base.base.seed as u64)),
@@ -130,7 +130,7 @@ pub struct WeightedBlockStateProvider {
}
impl WeightedBlockStateProvider {
pub fn get(&self, random: &mut RandomGenerator) -> BlockState {
pub fn get(&self, random: &mut RandomGenerator) -> &'static BlockState {
Pool::get(&self.entries, random)
.unwrap()
.get_state()
@@ -144,7 +144,7 @@ pub struct SimpleStateProvider {
}
impl SimpleStateProvider {
pub fn get(&self, _pos: BlockPos) -> BlockState {
pub fn get(&self, _pos: BlockPos) -> &'static BlockState {
self.state.get_state().unwrap()
}
}
@@ -185,7 +185,7 @@ pub struct NoiseBlockStateProvider {
}
impl NoiseBlockStateProvider {
pub fn get(&self, pos: BlockPos) -> BlockState {
pub fn get(&self, pos: BlockPos) -> &'static BlockState {
let value = self.base.get_noise(pos);
self.get_state_by_value(&self.states, value)
.get_state()
@@ -210,7 +210,7 @@ pub struct NoiseThresholdBlockStateProvider {
}
impl NoiseThresholdBlockStateProvider {
pub fn get(&self, random: &mut RandomGenerator, pos: BlockPos) -> BlockState {
pub fn get(&self, random: &mut RandomGenerator, pos: BlockPos) -> &'static BlockState {
let value = self.base.get_noise(pos);
if value < self.threshold as f64 {
return self.low_states[random.next_bounded_i32(self.low_states.len() as i32) as usize]

View File

@@ -42,7 +42,7 @@ impl BlockStateSampler {
pos: &impl NoisePos,
sample_options: &ChunkNoiseFunctionSampleOptions,
height_estimator: &mut SurfaceHeightEstimateSampler,
) -> Option<BlockState> {
) -> Option<&'static BlockState> {
match self {
Self::Aquifer(aquifer) => aquifer.apply(router, pos, sample_options, height_estimator),
Self::Ore(ore) => ore.sample(router, pos, sample_options),
@@ -66,7 +66,7 @@ impl ChainedBlockStateSampler {
pos: &impl NoisePos,
sample_options: &ChunkNoiseFunctionSampleOptions,
height_estimator: &mut SurfaceHeightEstimateSampler,
) -> Option<BlockState> {
) -> Option<&'static BlockState> {
self.samplers
.iter_mut()
.map(|sampler| sampler.sample(router, pos, sample_options, height_estimator))
@@ -370,7 +370,7 @@ impl<'a> ChunkNoiseGenerator<'a> {
start_pos: Vector3<i32>,
cell_pos: Vector3<i32>,
height_estimator: &mut SurfaceHeightEstimateSampler,
) -> Option<BlockState> {
) -> Option<&'static BlockState> {
//TODO: Fix this when Blender is added
let pos = UnblendedNoisePos::new(
start_pos.x + cell_pos.x,

View File

@@ -50,7 +50,7 @@ impl BambooFeature {
if !block.to_block().is_tagged_with("minecraft:dirt").unwrap() {
continue;
}
chunk.set_block_state(&block_below.0, &Block::PODZOL.default_state);
chunk.set_block_state(&block_below.0, Block::PODZOL.default_state);
}
}
}
@@ -58,7 +58,7 @@ impl BambooFeature {
let bamboo = Block::BAMBOO.default_state;
for _ in 0..height {
if chunk.is_air(&bpos.0) {
chunk.set_block_state(&bpos.0, &bamboo);
chunk.set_block_state(&bpos.0, bamboo);
bpos = bpos.up();
} else {
break;
@@ -72,19 +72,19 @@ impl BambooFeature {
chunk.set_block_state(
&bpos.0,
&get_state_by_state_id(props.to_state_id(&Block::BAMBOO)).unwrap(),
get_state_by_state_id(props.to_state_id(&Block::BAMBOO)).unwrap(),
);
props.stage = Integer0To1::L0;
chunk.set_block_state(
&bpos.down().0,
&get_state_by_state_id(props.to_state_id(&Block::BAMBOO)).unwrap(),
get_state_by_state_id(props.to_state_id(&Block::BAMBOO)).unwrap(),
);
props.leaves = BambooLeaves::Small;
chunk.set_block_state(
&bpos.down().down().0,
&get_state_by_state_id(props.to_state_id(&Block::BAMBOO)).unwrap(),
get_state_by_state_id(props.to_state_id(&Block::BAMBOO)).unwrap(),
);
}
}

View File

@@ -75,7 +75,7 @@ impl BlockColumnFeature {
let layer = &self.layers[l];
for _n in 0..*m {
let state = layer.provider.get(random, mutable);
chunk.set_block_state(&mutable.0, &state);
chunk.set_block_state(&mutable.0, state);
mutable = mutable.offset(self.direction.to_offset());
}
}

View File

@@ -24,7 +24,7 @@ impl CoralClawFeature {
) -> bool {
// First lets get a random coral
let block = CoralFeature::get_random_tag_entry("minecraft:coral_blocks", random);
if !CoralFeature::generate_coral_piece(chunk, random, &block, pos) {
if !CoralFeature::generate_coral_piece(chunk, random, block, pos) {
return false;
}
let i = random.next_bounded_i32(2) + 2;
@@ -54,7 +54,7 @@ impl CoralClawFeature {
}
for _ in 0..j {
if !CoralFeature::generate_coral_piece(chunk, random, &block, pos) {
if !CoralFeature::generate_coral_piece(chunk, random, block, pos) {
break;
}
pos = pos.offset(direction3.to_offset());
@@ -65,7 +65,7 @@ impl CoralClawFeature {
for _l in 0..k {
pos = pos.offset(direction.opposite().to_offset());
if !CoralFeature::generate_coral_piece(chunk, random, &block, pos) {
if !CoralFeature::generate_coral_piece(chunk, random, block, pos) {
continue 'block0;
}
if random.next_f32() < 0.25 {

View File

@@ -44,7 +44,7 @@ impl CoralMushroomFeature {
if !((condition_a && condition_b && condition_c && condition_d)
&& !random_check
&& CoralFeature::generate_coral_piece(chunk, random, &block, pos))
&& CoralFeature::generate_coral_piece(chunk, random, block, pos))
{
continue;
}

View File

@@ -27,7 +27,7 @@ impl CoralTreeFeature {
let mut pos = pos;
let i = random.next_bounded_i32(3) + 1;
for _ in 0..i {
if !CoralFeature::generate_coral_piece(chunk, random, &block, pos) {
if !CoralFeature::generate_coral_piece(chunk, random, block, pos) {
return true;
}
pos = pos.up();
@@ -44,7 +44,7 @@ impl CoralTreeFeature {
let times = random.next_bounded_i32(5) + 2;
let mut m = 0;
for n in 0..times {
if !CoralFeature::generate_coral_piece(chunk, random, &block, pos) {
if !CoralFeature::generate_coral_piece(chunk, random, block, pos) {
break;
}
pos = pos.up();

View File

@@ -29,8 +29,8 @@ impl CoralFeature {
let block = chunk.get_block_state(&pos.0).to_block();
let above_block = chunk.get_block_state(&pos.up().0).to_block();
if block != Block::WATER && !block.is_tagged_with("minecraft:corals").unwrap()
|| above_block != Block::WATER
if block != &Block::WATER && !block.is_tagged_with("minecraft:corals").unwrap()
|| above_block != &Block::WATER
{
return false;
}
@@ -38,20 +38,20 @@ impl CoralFeature {
if random.next_f32() < 0.25 {
chunk.set_block_state(
&pos.0,
&Self::get_random_tag_entry("minecraft:corals", random),
Self::get_random_tag_entry("minecraft:corals", random),
);
} else if random.next_f32() < 0.05 {
let mut props = SeaPickleLikeProperties::default(&Block::SEA_PICKLE);
props.pickles = Integer1To4::from_index(random.next_bounded_i32(4) as u16); // TODO: vanilla adds + 1, but this can crash
chunk.set_block_state(
&pos.0,
&get_state_by_state_id(props.to_state_id(&Block::SEA_PICKLE)).unwrap(),
get_state_by_state_id(props.to_state_id(&Block::SEA_PICKLE)).unwrap(),
);
}
for dir in BlockDirection::horizontal() {
let dir_pos = pos.offset(dir.to_offset());
if random.next_f32() >= 0.2
|| chunk.get_block_state(&dir_pos.0).to_block() != Block::WATER
|| chunk.get_block_state(&dir_pos.0).to_block() != &Block::WATER
{
continue;
}
@@ -74,11 +74,11 @@ impl CoralFeature {
.collect();
chunk.set_block_state(
&dir_pos.0,
&get_state_by_state_id(
get_state_by_state_id(
wall_coral
.from_properties(props)
.unwrap()
.to_state_id(&wall_coral),
.to_state_id(wall_coral),
)
.unwrap(),
);
@@ -87,12 +87,12 @@ impl CoralFeature {
true
}
pub fn get_random_tag_entry(tag: &str, random: &mut RandomGenerator) -> BlockState {
pub fn get_random_tag_entry(tag: &str, random: &mut RandomGenerator) -> &'static BlockState {
let block = Self::get_random_tag_entry_block(tag, random);
block.default_state
}
pub fn get_random_tag_entry_block(tag: &str, random: &mut RandomGenerator) -> Block {
pub fn get_random_tag_entry_block(tag: &str, random: &mut RandomGenerator) -> &'static Block {
let values = get_tag_values(RegistryKey::Block, tag).unwrap();
let value = values[random.next_bounded_i32(values.len() as i32) as usize];
get_block(value).unwrap()

View File

@@ -56,28 +56,28 @@ impl DesertWellFeature {
for k in -2..=2 {
chunk.set_block_state(
&block_pos.0.add(&Vector3::new(j2, i, k)),
&Self::WALL.default_state,
Self::WALL.default_state,
);
}
}
}
chunk.set_block_state(&block_pos.0, &WATER_BLOCK.default_state);
chunk.set_block_state(&block_pos.0, WATER_BLOCK.default_state);
for direction in BlockDirection::horizontal().iter() {
chunk.set_block_state(
&block_pos.0.add(&direction.to_offset()),
&WATER_BLOCK.default_state,
WATER_BLOCK.default_state,
);
}
let block_pos2 = &block_pos.0.add(&Vector3::new(0, -1, 0));
chunk.set_block_state(block_pos2, &Self::SAND.default_state);
chunk.set_block_state(block_pos2, Self::SAND.default_state);
for direction2 in BlockDirection::horizontal().iter() {
chunk.set_block_state(
&block_pos2.add(&direction2.to_offset()),
&Self::SAND.default_state,
Self::SAND.default_state,
);
}
@@ -88,26 +88,26 @@ impl DesertWellFeature {
}
chunk.set_block_state(
&block_pos.0.add(&Vector3::new(j, 1, k)),
&Self::WALL.default_state,
Self::WALL.default_state,
);
}
}
chunk.set_block_state(
&block_pos.0.add(&Vector3::new(2, 1, 0)),
&Self::SLAB.default_state,
Self::SLAB.default_state,
);
chunk.set_block_state(
&block_pos.0.add(&Vector3::new(-2, 1, 0)),
&Self::SLAB.default_state,
Self::SLAB.default_state,
);
chunk.set_block_state(
&block_pos.0.add(&Vector3::new(0, 1, 2)),
&Self::SLAB.default_state,
Self::SLAB.default_state,
);
chunk.set_block_state(
&block_pos.0.add(&Vector3::new(0, 1, -2)),
&Self::SLAB.default_state,
Self::SLAB.default_state,
);
for j in -1..=1 {
@@ -115,13 +115,13 @@ impl DesertWellFeature {
if j == 0 && k == 0 {
chunk.set_block_state(
&block_pos.0.add(&Vector3::new(j, 4, k)),
&Self::WALL.default_state,
Self::WALL.default_state,
);
continue;
}
chunk.set_block_state(
&block_pos.0.add(&Vector3::new(j, 4, k)),
&Self::SLAB.default_state,
Self::SLAB.default_state,
);
}
}
@@ -129,19 +129,19 @@ impl DesertWellFeature {
for j in 1..=3 {
chunk.set_block_state(
&block_pos.0.add(&Vector3::new(-1, j, -1)),
&Self::WALL.default_state,
Self::WALL.default_state,
);
chunk.set_block_state(
&block_pos.0.add(&Vector3::new(-1, j, 1)),
&Self::WALL.default_state,
Self::WALL.default_state,
);
chunk.set_block_state(
&block_pos.0.add(&Vector3::new(1, j, -1)),
&Self::WALL.default_state,
Self::WALL.default_state,
);
chunk.set_block_state(
&block_pos.0.add(&Vector3::new(1, j, 1)),
&Self::WALL.default_state,
Self::WALL.default_state,
);
}

View File

@@ -20,7 +20,7 @@ pub(super) fn gen_dripstone(chunk: &mut ProtoChunk, pos: BlockPos) -> bool {
.is_tagged_with("minecraft:dripstone_replaceable_blocks")
.unwrap()
{
chunk.set_block_state(&pos.0, &Block::DRIPSTONE_BLOCK.default_state);
chunk.set_block_state(&pos.0, Block::DRIPSTONE_BLOCK.default_state);
return true;
}
false

View File

@@ -36,8 +36,8 @@ impl SmallDripstoneFeature {
pos: BlockPos,
random: &mut RandomGenerator,
) -> Option<BlockDirection> {
let up = super::can_replace(&chunk.get_block_state(&pos.up().0).to_block());
let down: bool = super::can_replace(&chunk.get_block_state(&pos.down().0).to_block());
let up = super::can_replace(chunk.get_block_state(&pos.up().0).to_block());
let down: bool = super::can_replace(chunk.get_block_state(&pos.down().0).to_block());
if up && down {
return if random.next_bool() {
Some(BlockDirection::Down)

View File

@@ -30,7 +30,7 @@ impl EndPlatformFeature {
if chunk.get_block_state(&pos.0).0 == state.id {
continue;
}
chunk.set_block_state(&pos.0, &state);
chunk.set_block_state(&pos.0, state);
}
}
}

View File

@@ -98,13 +98,13 @@ impl EndSpikeFeature {
<= (radius * radius + 1)
&& pos.0.y < spike.height
{
chunk.set_block_state(&pos.0, &Block::OBSIDIAN.default_state);
chunk.set_block_state(&pos.0, Block::OBSIDIAN.default_state);
continue;
}
if pos.0.y <= 65 {
continue;
}
chunk.set_block_state(&pos.0, &Block::AIR.default_state);
chunk.set_block_state(&pos.0, Block::AIR.default_state);
}
// TODO
}

View File

@@ -22,6 +22,6 @@ impl FallenTreeFeature {
}
fn gen_stump(&self, chunk: &mut ProtoChunk, random: &mut RandomGenerator, pos: BlockPos) {
chunk.set_block_state(&pos.0, &self.trunk_provider.get(random, pos));
chunk.set_block_state(&pos.0, self.trunk_provider.get(random, pos));
}
}

View File

@@ -51,12 +51,12 @@ impl NetherForestVegetationFeature {
if !chunk.is_air(&pos.0)
|| pos.0.y <= chunk.bottom_y() as i32
|| block_registry
.can_place_at(&nether_block, chunk, &pos, BlockDirection::Up)
.can_place_at(nether_block, chunk, &pos, BlockDirection::Up)
.await
{
continue;
}
chunk.set_block_state(&pos.0, &nether_state);
chunk.set_block_state(&pos.0, nether_state);
result = true;
}

View File

@@ -32,7 +32,7 @@ impl ReplaceBlobsFeature {
let target = self.target.get_state().unwrap();
let target = get_block_by_state_id(target.id).unwrap();
let state = self.state.get_state().unwrap();
let Some(pos) = Self::move_down_to_target(pos, chunk, &target) else {
let Some(pos) = Self::move_down_to_target(pos, chunk, target) else {
return false;
};
let x = self.radius.get(random);
@@ -50,7 +50,7 @@ impl ReplaceBlobsFeature {
if current_state.to_block() != target {
continue;
}
chunk.set_block_state(&iter_pos.0, &state);
chunk.set_block_state(&iter_pos.0, state);
result = true;
}
@@ -60,11 +60,11 @@ impl ReplaceBlobsFeature {
fn move_down_to_target(
mut pos: BlockPos,
chunk: &mut ProtoChunk,
target: &Block,
target: &'static Block,
) -> Option<BlockPos> {
while pos.0.y > chunk.bottom_y() as i32 + 1 {
let state = chunk.get_block_state(&pos.0);
if &state.to_block() == target {
if state.to_block() == target {
return Some(pos);
}

View File

@@ -197,7 +197,7 @@ impl OreFeature {
) {
chunk.set_block_state(
&Vector3::new(ad, ae, af),
&target.state.get_state().unwrap(),
target.state.get_state().unwrap(),
);
placed_blocks_count += 1;
break; // Equivalent to 'continue block11;'
@@ -213,12 +213,12 @@ impl OreFeature {
fn should_place(
&self,
chunk: &mut ProtoChunk,
state: BlockState,
state: &'static BlockState,
random: &mut RandomGenerator,
target: &OreTarget,
pos: &mut BlockPos,
) -> bool {
if !target.target.test(&state, random) {
if !target.target.test(state, random) {
return false;
}
if Self::should_not_discard(random, self.discard_chance_on_air_exposure) {

View File

@@ -34,7 +34,7 @@ impl SeaPickleFeature {
let z = random.next_bounded_i32(8) - random.next_bounded_i32(8);
let y =
chunk.ocean_floor_height_exclusive(&Vector2::new(pos.0.x + x, pos.0.z + z)) as i32;
if chunk.get_block_state(&pos.0).to_block() != Block::WATER {
if chunk.get_block_state(&pos.0).to_block() != &Block::WATER {
continue;
}
let mut props = SeaPickleLikeProperties::default(&Block::SEA_PICKLE);
@@ -42,7 +42,7 @@ impl SeaPickleFeature {
let pos = BlockPos::new(pos.0.x + x, y, pos.0.z + z);
chunk.set_block_state(
&pos.0,
&get_state_by_state_id(props.to_state_id(&Block::SEA_PICKLE)).unwrap(),
get_state_by_state_id(props.to_state_id(&Block::SEA_PICKLE)).unwrap(),
);
times += 1;
}

View File

@@ -31,21 +31,21 @@ impl SeagrassFeature {
let z = random.next_bounded_i32(8) - random.next_bounded_i32(8);
let y = chunk.ocean_floor_height_exclusive(&Vector2::new(pos.0.x + x, pos.0.z + z)) as i32;
let top_pos = BlockPos::new(pos.0.x + x, y, pos.0.z + z);
if chunk.get_block_state(&top_pos.0).to_block() == Block::WATER {
if chunk.get_block_state(&top_pos.0).to_block() == &Block::WATER {
let tall = random.next_f64() < self.probability as f64;
if tall {
let tall_pos = top_pos.up();
if chunk.get_block_state(&tall_pos.0).to_block() == Block::WATER {
if chunk.get_block_state(&tall_pos.0).to_block() == &Block::WATER {
let mut props = TallSeagrassLikeProperties::default(&Block::TALL_SEAGRASS);
props.half = DoubleBlockHalf::Upper;
chunk.set_block_state(&top_pos.0, &Block::TALL_SEAGRASS.default_state);
chunk.set_block_state(&top_pos.0, Block::TALL_SEAGRASS.default_state);
chunk.set_block_state(
&tall_pos.0,
&get_state_by_state_id(props.to_state_id(&Block::TALL_SEAGRASS)).unwrap(),
get_state_by_state_id(props.to_state_id(&Block::TALL_SEAGRASS)).unwrap(),
);
}
} else {
chunk.set_block_state(&top_pos.0, &Block::SEAGRASS.default_state);
chunk.set_block_state(&top_pos.0, Block::SEAGRASS.default_state);
}
return true;
}

View File

@@ -27,14 +27,14 @@ impl SimpleBlockFeature {
let block_accessor: &dyn BlockAccessor = chunk;
if !futures::executor::block_on(async move {
block_registry
.can_place_at(&block, block_accessor, &pos, BlockDirection::Up)
.can_place_at(block, block_accessor, &pos, BlockDirection::Up)
.await
}) {
return false;
}
// TODO: check things..
chunk.set_block_state(&pos.0, &state);
chunk.set_block_state(&pos.0, state);
// TODO: schedule tick when needed
true
}

View File

@@ -122,7 +122,7 @@ impl SpringFeatureFeature {
air += 1;
}
if valid == self.rock_count && air == self.hole_count {
chunk.set_block_state(&pos.0, &self.state.get_state().unwrap());
chunk.set_block_state(&pos.0, self.state.get_state().unwrap());
return true;
}
false

View File

@@ -31,7 +31,7 @@ impl AttachedToLogsTreeDecorator {
{
continue;
}
chunk.set_block_state(&pos.0, &self.block_provider.get(random, pos));
chunk.set_block_state(&pos.0, self.block_provider.get(random, pos));
}
}
}

View File

@@ -74,10 +74,10 @@ impl PlaceOnGroundTreeDecorator {
let up_state = chunk.get_block_state(&pos.0);
// TODO
if (up_state.to_state().is_air() || up_state.to_block() == Block::VINE)
if (up_state.to_state().is_air() || up_state.to_block() == &Block::VINE)
&& state.to_state().is_full_cube()
{
chunk.set_block_state(&pos.0, &self.block_state_provider.get(random, pos));
chunk.set_block_state(&pos.0, self.block_state_provider.get(random, pos));
}
}
}

View File

@@ -28,7 +28,7 @@ impl TrunkVineTreeDecorator {
vine.east = true;
chunk.set_block_state(
&pos.offset(BlockDirection::West.to_offset()).0,
&get_state_by_state_id(vine.to_state_id(&Block::VINE)).unwrap(),
get_state_by_state_id(vine.to_state_id(&Block::VINE)).unwrap(),
);
}
@@ -39,7 +39,7 @@ impl TrunkVineTreeDecorator {
vine.west = true;
chunk.set_block_state(
&pos.offset(BlockDirection::West.to_offset()).0,
&get_state_by_state_id(vine.to_state_id(&Block::VINE)).unwrap(),
get_state_by_state_id(vine.to_state_id(&Block::VINE)).unwrap(),
);
}
@@ -50,7 +50,7 @@ impl TrunkVineTreeDecorator {
vine.south = true;
chunk.set_block_state(
&pos.offset(BlockDirection::West.to_offset()).0,
&get_state_by_state_id(vine.to_state_id(&Block::VINE)).unwrap(),
get_state_by_state_id(vine.to_state_id(&Block::VINE)).unwrap(),
);
}
@@ -61,7 +61,7 @@ impl TrunkVineTreeDecorator {
vine.north = true;
chunk.set_block_state(
&pos.offset(BlockDirection::West.to_offset()).0,
&get_state_by_state_id(vine.to_state_id(&Block::VINE)).unwrap(),
get_state_by_state_id(vine.to_state_id(&Block::VINE)).unwrap(),
);
}
}

View File

@@ -142,7 +142,7 @@ impl FoliagePlacer {
block_state: &BlockState,
) {
let block = chunk.get_block_state(&pos.0);
if !TreeFeature::can_replace(&block.to_state(), &block.to_block()) {
if !TreeFeature::can_replace(block.to_state(), block.to_block()) {
return;
}
if chunk.chunk_pos == pos.chunk_and_chunk_relative_position().0 {

View File

@@ -104,8 +104,8 @@ impl TreeFeature {
level,
random,
self.force_dirt,
&dirt_state,
&trunk_state,
dirt_state,
trunk_state,
)
.await;
@@ -125,7 +125,7 @@ impl TreeFeature {
&node,
foliage_height,
foliage_radius,
&foliage_state,
foliage_state,
)
.await;
}
@@ -140,8 +140,8 @@ impl TreeFeature {
let pos = BlockPos(init_pos.0.add_raw(x, y as i32, z));
let rstate = chunk.get_block_state(&pos.0);
let block = rstate.to_block();
if Self::can_replace_or_log(&rstate.to_state(), &block)
&& (self.ignore_vines || block != Block::VINE)
if Self::can_replace_or_log(rstate.to_state(), block)
&& (self.ignore_vines || block != &Block::VINE)
{
continue;
}

View File

@@ -71,7 +71,7 @@ impl DarkOakTrunkPlacer {
let pos = BlockPos::new(x, y_height, z);
// TODO: support multiple chunks
let state = chunk.get_block_state(&pos.0);
if !TreeFeature::is_air_or_leaves(&state.to_state(), &state.to_block()) {
if !TreeFeature::is_air_or_leaves(state.to_state(), state.to_block()) {
continue;
}
if placer.try_place(chunk, &pos, trunk_block) {

View File

@@ -158,7 +158,7 @@ impl FancyTrunkPlacer {
if make {
let axis = Self::get_log_axis(start_pos, block_pos_2.0);
if TreeFeature::can_replace(&block.to_state(), &block.to_block()) {
if TreeFeature::can_replace(block.to_state(), block.to_block()) {
let block = get_block_by_state_id(trunk_provider.id).unwrap();
let original_props = &block.properties(trunk_provider.id).unwrap().to_props();
let axis = axis.to_value();
@@ -173,12 +173,10 @@ impl FancyTrunkPlacer {
}
})
.collect();
let state = block.from_properties(props).unwrap().to_state_id(&block);
let state = block.from_properties(props).unwrap().to_state_id(block);
if chunk.chunk_pos == block_pos_2.chunk_and_chunk_relative_position().0 {
chunk.set_block_state(
&block_pos_2.0,
&get_state_by_state_id(state).unwrap(),
);
chunk
.set_block_state(&block_pos_2.0, get_state_by_state_id(state).unwrap());
} else {
// level.set_block_state(&block_pos_2, state).await;
}
@@ -187,7 +185,7 @@ impl FancyTrunkPlacer {
}
}
if TreeFeature::can_replace_or_log(&block.to_state(), &block.to_block()) {
if TreeFeature::can_replace_or_log(block.to_state(), block.to_block()) {
continue;
}
return (false, logs);

View File

@@ -57,8 +57,8 @@ impl TrunkPlacer {
let block = chunk.get_block_state(&pos.0).to_block();
if force_dirt
|| !(block.is_tagged_with("minecraft:dirt").unwrap()
&& block != Block::GRASS_BLOCK
&& block != Block::MYCELIUM)
&& block != &Block::GRASS_BLOCK
&& block != &Block::MYCELIUM)
{
chunk.set_block_state(&pos.0, dirt_state);
}
@@ -71,7 +71,7 @@ impl TrunkPlacer {
trunk_block: &BlockState,
) -> bool {
let block = chunk.get_block_state(&pos.0);
if TreeFeature::can_replace(&block.to_state(), &block.to_block()) {
if TreeFeature::can_replace(block.to_state(), block.to_block()) {
chunk.set_block_state(&pos.0, trunk_block);
return true;
}
@@ -85,7 +85,7 @@ impl TrunkPlacer {
trunk_block: &BlockState,
) -> bool {
let block = chunk.get_block_state(&pos.0);
if TreeFeature::can_replace_or_log(&block.to_state(), &block.to_block()) {
if TreeFeature::can_replace_or_log(block.to_state(), block.to_block()) {
return self.place(chunk, pos, trunk_block);
}
false

View File

@@ -44,7 +44,7 @@ impl VinesFeature {
vine.up = dir == BlockDirection::Up;
chunk.set_block_state(
&pos.0,
&get_state_by_state_id(vine.to_state_id(&Block::VINE)).unwrap(),
get_state_by_state_id(vine.to_state_id(&Block::VINE)).unwrap(),
);
return true;
}

View File

@@ -389,7 +389,7 @@ impl CountOnEveryLayerPlacementModifier {
if !Self::blocks_spawn(&next_block_state)
&& Self::blocks_spawn(&current_block_state)
&& next_block_state.to_block() != Block::BEDROCK
&& next_block_state.to_block() != &Block::BEDROCK
{
if found_count == target_y {
return mutable_pos.0.y + 1;
@@ -403,7 +403,7 @@ impl CountOnEveryLayerPlacementModifier {
fn blocks_spawn(state: &RawBlockState) -> bool {
let block = state.to_block();
state.to_state().is_air() || block == Block::WATER || block == Block::LAVA
state.to_state().is_air() || block == &Block::WATER || block == &Block::LAVA
}
}

View File

@@ -24,7 +24,7 @@ impl OreVeinSampler {
router: &mut ChunkNoiseRouter,
pos: &impl NoisePos,
sample_options: &ChunkNoiseFunctionSampleOptions,
) -> Option<BlockState> {
) -> Option<&'static BlockState> {
let vein_toggle = router.vein_toggle(pos, sample_options);
let vein_type: &VeinType = if vein_toggle > 0f64 {
&vein_type::COPPER
@@ -57,12 +57,12 @@ impl OreVeinSampler {
&& vein_gap > (-0.3f32 as f64)
{
Some(if random.next_f32() < 0.02f32 {
vein_type.raw_ore.default_state.clone()
vein_type.raw_ore.default_state
} else {
vein_type.ore.default_state.clone()
vein_type.ore.default_state
})
} else {
Some(vein_type.stone.default_state.clone())
Some(vein_type.stone.default_state)
};
}
}

View File

@@ -107,7 +107,7 @@ pub struct ProtoChunk<'a> {
// TODO: These can technically go to an even higher level and we can reuse them across chunks
pub multi_noise_sampler: MultiNoiseSampler<'a>,
pub surface_height_estimate_sampler: SurfaceHeightEstimateSampler<'a>,
pub default_block: BlockState,
pub default_block: &'static BlockState,
random_config: &'a GlobalRandomConfig,
settings: &'a GenerationSettings,
biome_mixer_seed: i64,
@@ -140,7 +140,7 @@ impl<'a> ProtoChunk<'a> {
settings.sea_level,
settings.default_fluid.get_state().unwrap().block(),
),
FluidLevel::new(-54, LAVA_BLOCK), // this is always the same for every dimension
FluidLevel::new(-54, &LAVA_BLOCK), // this is always the same for every dimension
)));
let height = generation_shape.height;
@@ -531,10 +531,10 @@ impl<'a> ProtoChunk<'a> {
Vector3::new(cell_offset_x, cell_offset_y, cell_offset_z),
&mut self.surface_height_estimate_sampler,
)
.unwrap_or(self.default_block.clone());
.unwrap_or(self.default_block);
self.set_block_state(
&Vector3::new(block_x, block_y, block_z),
&block_state,
block_state,
);
}
}
@@ -649,7 +649,9 @@ impl<'a> ProtoChunk<'a> {
.to_block();
// TODO: Is there a better way to check that its not a fluid?
if !(state != AIR_BLOCK && state != WATER_BLOCK && state != LAVA_BLOCK)
if !(state != &AIR_BLOCK
&& state != &WATER_BLOCK
&& state != &LAVA_BLOCK)
{
min = search_y + 1;
break;
@@ -668,7 +670,7 @@ impl<'a> ProtoChunk<'a> {
let new_state = self.settings.surface_rule.try_apply(self, &mut context);
if let Some(state) = new_state {
self.set_block_state(&pos, &state);
self.set_block_state(&pos, state);
}
}
}
@@ -761,20 +763,23 @@ impl<'a> ProtoChunk<'a> {
#[async_trait]
impl BlockAccessor for ProtoChunk<'_> {
async fn get_block(&self, position: &BlockPos) -> pumpkin_data::Block {
async fn get_block(&self, position: &BlockPos) -> &'static pumpkin_data::Block {
self.get_block_state(&position.0).to_block()
}
async fn get_block_state(&self, position: &BlockPos) -> pumpkin_data::BlockState {
async fn get_block_state(&self, position: &BlockPos) -> &'static pumpkin_data::BlockState {
self.get_block_state(&position.0).to_state()
}
async fn get_block_and_block_state(
&self,
position: &BlockPos,
) -> (pumpkin_data::Block, pumpkin_data::BlockState) {
) -> (
&'static pumpkin_data::Block,
&'static pumpkin_data::BlockState,
) {
let id = self.get_block_state(&position.0);
get_block_and_state_by_state_id(id.0).unwrap_or((Block::AIR, Block::AIR.default_state))
get_block_and_state_by_state_id(id.0).unwrap_or((&Block::AIR, Block::AIR.default_state))
}
}

View File

@@ -12,7 +12,7 @@ pub enum RuleTest {
pub struct AlwaysTrueRuleTest;
impl AlwaysTrueRuleTest {
pub fn test(&self, _block: Block) -> bool {
pub fn test(&self, _block: &'static Block) -> bool {
true
}
}
@@ -23,7 +23,7 @@ pub struct BlockMatchRuleTest {
}
impl BlockMatchRuleTest {
pub fn test(&self, block: Block) -> bool {
pub fn test(&self, block: &'static Block) -> bool {
let test_block = Block::from_registry_key(&self.block).expect("Failed to find block");
test_block == block
}
@@ -35,7 +35,7 @@ pub struct TagMatchTest {
}
impl TagMatchTest {
pub fn test(&self, block: Block) -> bool {
pub fn test(&self, block: &'static Block) -> bool {
block.is_tagged_with(&self.tag).unwrap()
}
}

View File

@@ -22,7 +22,7 @@ impl MaterialRule {
&self,
chunk: &mut ProtoChunk,
context: &mut MaterialRuleContext,
) -> Option<BlockState> {
) -> Option<&'static BlockState> {
match self {
MaterialRule::Badlands(badlands) => badlands.try_apply(context),
MaterialRule::Block(block) => block.try_apply(),
@@ -36,7 +36,7 @@ impl MaterialRule {
pub struct BadLandsMaterialRule;
impl BadLandsMaterialRule {
pub fn try_apply(&self, context: &mut MaterialRuleContext) -> Option<BlockState> {
pub fn try_apply(&self, context: &mut MaterialRuleContext) -> Option<&'static BlockState> {
Some(
context
.terrain_builder
@@ -51,7 +51,7 @@ pub struct BlockMaterialRule {
}
impl BlockMaterialRule {
pub fn try_apply(&self) -> Option<BlockState> {
pub fn try_apply(&self) -> Option<&'static BlockState> {
self.result_state.get_state()
}
}
@@ -66,7 +66,7 @@ impl SequenceMaterialRule {
&self,
chunk: &mut ProtoChunk,
context: &mut MaterialRuleContext,
) -> Option<BlockState> {
) -> Option<&'static BlockState> {
for seq in &self.sequence {
if let Some(state) = seq.try_apply(chunk, context) {
return Some(state);
@@ -87,7 +87,7 @@ impl ConditionMaterialRule {
&self,
chunk: &mut ProtoChunk,
context: &mut MaterialRuleContext,
) -> Option<BlockState> {
) -> Option<&'static BlockState> {
if self.if_true.test(chunk, context) {
return self.then_run.try_apply(chunk, context);
}

View File

@@ -161,7 +161,7 @@ impl SurfaceTerrainBuilder {
break;
}
if block_state == WATER_BLOCK {
if block_state == &WATER_BLOCK {
return;
}
}
@@ -174,7 +174,7 @@ impl SurfaceTerrainBuilder {
}
let default_block = &chunk.default_block;
chunk.set_block_state(&pos, &default_block.clone());
chunk.set_block_state(&pos, default_block);
}
}
}
@@ -242,24 +242,24 @@ impl SurfaceTerrainBuilder {
let pos = Vector3::new(x, y, z);
let block_state = chunk.get_block_state(&pos);
if (block_state.to_state().is_air() && y < top_block && rand.next_f64() > 0.01)
|| (block_state.to_block() == WATER_BLOCK
|| (block_state.to_block() == &WATER_BLOCK
&& y > bottom_block
&& y < sea_level
&& bottom_block != 0
&& rand.next_f64() > 0.15)
{
if snow_blocks <= snow_block_count && y > snow_bottom {
chunk.set_block_state(&pos, &Self::SNOW_BLOCK.default_state);
chunk.set_block_state(&pos, Self::SNOW_BLOCK.default_state);
snow_blocks += 1;
} else {
chunk.set_block_state(&pos, &Self::PACKED_ICE.default_state);
chunk.set_block_state(&pos, Self::PACKED_ICE.default_state);
}
}
}
}
}
pub fn get_terracotta_block(&self, pos: &Vector3<i32>) -> BlockState {
pub fn get_terracotta_block(&self, pos: &Vector3<i32>) -> &'static BlockState {
let offset = (self
.terracotta_bands_offset_noise
.sample(pos.x as f64, 0.0, pos.z as f64)

View File

@@ -1,5 +1,6 @@
use dashmap::{DashMap, Entry};
use log::trace;
use num_cpus;
use num_traits::Zero;
use pumpkin_config::{advanced_config, chunk::ChunkFormat};
use pumpkin_data::Block;
@@ -15,7 +16,7 @@ use std::{
use tokio::{
select,
sync::{
Mutex, Notify, RwLock,
Mutex, Notify, RwLock, Semaphore,
mpsc::{self, UnboundedReceiver},
},
task::JoinHandle,
@@ -71,6 +72,8 @@ pub struct Level {
block_ticks: Arc<Mutex<Vec<ScheduledTick>>>,
remaining_block_ticks_this_tick: Arc<Mutex<VecDeque<ScheduledTick>>>,
fluid_ticks: Arc<Mutex<Vec<ScheduledTick>>>,
/// Semaphore to limit concurrent chunk generation tasks
chunk_generation_semaphore: Arc<Semaphore>,
/// Tracks tasks associated with this world instance
tasks: TaskTracker,
/// Notification that interrupts tasks for shutdown
@@ -143,6 +146,8 @@ impl Level {
block_ticks: Arc::new(Mutex::new(Vec::new())),
remaining_block_ticks_this_tick: Arc::new(Mutex::new(VecDeque::new())),
fluid_ticks: Arc::new(Mutex::new(Vec::new())),
// Limits concurrent chunk generation tasks to 2x the number of CPUs
chunk_generation_semaphore: Arc::new(Semaphore::new(num_cpus::get() * 2)),
}
}
@@ -750,6 +755,7 @@ impl Level {
let world_gen = self.world_gen.clone();
let block_registry = self.block_registry.clone();
let self_clone = self.clone();
let chunk_generation_semaphore = self.chunk_generation_semaphore.clone();
let handle_generate = async move {
let continue_to_generate = Arc::new(AtomicBool::new(true));
while let Some(pos) = generate_bridge_recv.recv().await {
@@ -763,8 +769,12 @@ impl Level {
let cloned_continue_to_generate = continue_to_generate.clone();
let block_registry = block_registry.clone();
let self_clone = self_clone.clone();
let semaphore = chunk_generation_semaphore.clone();
tokio::spawn(async move {
// Acquire a permit from the semaphore to limit concurrent generation
let _permit = semaphore.acquire().await.expect("Semaphore closed");
// Rayon tasks are queued, so also check it here
if !cloned_continue_to_generate.load(Ordering::Relaxed) {
return;
@@ -894,6 +904,7 @@ impl Level {
};
let loaded_chunks = self.loaded_entity_chunks.clone();
let chunk_generation_semaphore = self.chunk_generation_semaphore.clone();
let handle_generate = async move {
let continue_to_generate = Arc::new(AtomicBool::new(true));
while let Some(pos) = generate_bridge_recv.recv().await {
@@ -904,8 +915,12 @@ impl Level {
let loaded_chunks = loaded_chunks.clone();
let channel = channel.clone();
let cloned_continue_to_generate = continue_to_generate.clone();
let semaphore = chunk_generation_semaphore.clone();
tokio::spawn(async move {
// Acquire a permit from the semaphore to limit concurrent generation
let _permit = semaphore.acquire().await.expect("Semaphore closed");
// Rayon tasks are queued, so also check it here
if !cloned_continue_to_generate.load(Ordering::Relaxed) {
return;

View File

@@ -72,12 +72,15 @@ pub trait BlockRegistryExt: Send + Sync {
#[async_trait]
pub trait BlockAccessor: Send + Sync {
async fn get_block(&self, position: &BlockPos) -> pumpkin_data::Block;
async fn get_block(&self, position: &BlockPos) -> &'static pumpkin_data::Block;
async fn get_block_state(&self, position: &BlockPos) -> pumpkin_data::BlockState;
async fn get_block_state(&self, position: &BlockPos) -> &'static pumpkin_data::BlockState;
async fn get_block_and_block_state(
&self,
position: &BlockPos,
) -> (pumpkin_data::Block, pumpkin_data::BlockState);
) -> (
&'static pumpkin_data::Block,
&'static pumpkin_data::BlockState,
);
}

View File

@@ -116,7 +116,7 @@ impl PumpkinBlock for BedBlock {
block_pos: BlockPos,
_server: &Server,
world: Arc<World>,
state: BlockState,
state: &'static BlockState,
) {
let bed_props = BedProperties::from_state_id(state.id, block);
let other_half_pos = if bed_props.part == BedPart::Head {

View File

@@ -61,8 +61,8 @@ impl PumpkinBlock for CactusBlock {
_world: &Arc<World>,
entity: &dyn EntityBase,
_pos: BlockPos,
_block: Block,
_state: BlockState,
_block: &'static Block,
_state: &'static BlockState,
_server: &Server,
) {
entity.damage(1.0, DamageType::CACTUS).await;
@@ -109,12 +109,12 @@ async fn can_place_at(world: &dyn BlockAccessor, block_pos: &BlockPos) -> bool {
let (block, state) = world
.get_block_and_block_state(&block_pos.offset(direction.to_offset()))
.await;
if state.is_solid() || block == Block::LAVA {
if state.is_solid() || block == &Block::LAVA {
return false;
}
}
let block = world.get_block(&block_pos.down()).await;
// TODO: use tags
(block == Block::CACTUS || block.is_tagged_with("minecraft:sand").unwrap())
(block == &Block::CACTUS || block.is_tagged_with("minecraft:sand").unwrap())
&& !world.get_block_state(&block_pos.up()).await.is_liquid()
}

View File

@@ -41,11 +41,11 @@ impl PumpkinBlock for CampfireBlock {
_world: &Arc<World>,
entity: &dyn EntityBase,
_pos: BlockPos,
block: Block,
state: BlockState,
block: &'static Block,
state: &'static BlockState,
_server: &Server,
) {
if CampfireLikeProperties::from_state_id(state.id, &block).lit
if CampfireLikeProperties::from_state_id(state.id, block).lit
&& entity.get_living_entity().is_some()
{
entity.damage(1.0, DamageType::CAMPFIRE).await;
@@ -66,7 +66,7 @@ impl PumpkinBlock for CampfireBlock {
let is_replacing_water = matches!(replacing, BlockIsReplacing::Water(_));
let mut props = CampfireLikeProperties::from_state_id(block.default_state.id, block);
props.waterlogged = is_replacing_water;
props.signal_fire = is_signal_fire_base_block(&world.get_block(&block_pos.down()).await);
props.signal_fire = is_signal_fire_base_block(world.get_block(&block_pos.down()).await);
props.lit = !is_replacing_water;
props.facing = player.get_entity().get_horizontal_facing();
props.to_state_id(block)
@@ -92,7 +92,7 @@ impl PumpkinBlock for CampfireBlock {
}
if direction == BlockDirection::Down {
props.signal_fire = is_signal_fire_base_block(&world.get_block(neighbor_pos).await);
props.signal_fire = is_signal_fire_base_block(world.get_block(neighbor_pos).await);
}
props.to_state_id(block)

View File

@@ -121,7 +121,7 @@ impl PumpkinBlock for ChestBlock {
block_pos: BlockPos,
_server: &Server,
world: Arc<World>,
state: BlockState,
state: &'static BlockState,
) {
let chest_props = ChestLikeProperties::from_state_id(state.id, block);
let connected_towards = match chest_props.r#type {
@@ -171,9 +171,9 @@ async fn compute_chest_props(
.get_block_and_block_state(&block_pos.offset(face.to_offset()))
.await;
if clicked_block == *block {
if clicked_block == block {
let clicked_props =
ChestLikeProperties::from_state_id(clicked_block_state.id, &clicked_block);
ChestLikeProperties::from_state_id(clicked_block_state.id, clicked_block);
if clicked_props.r#type != ChestType::Single {
return (ChestType::Single, chest_facing);
@@ -230,12 +230,12 @@ async fn get_chest_properties_if_can_connect(
.get_block_and_block_state(&block_pos.offset(direction.to_offset()))
.await;
if neighbor_block != *block {
if neighbor_block != block {
return None;
}
let neighbor_props =
ChestLikeProperties::from_state_id(neighbor_block_state.id, &neighbor_block);
ChestLikeProperties::from_state_id(neighbor_block_state.id, neighbor_block);
if neighbor_props.facing == facing && neighbor_props.r#type == wanted_type {
return Some(neighbor_props);
}

View File

@@ -33,7 +33,7 @@ type DoorProperties = pumpkin_data::block_properties::OakDoorLikeProperties;
async fn toggle_door(player: &Player, world: &Arc<World>, block_pos: &BlockPos) {
let (block, block_state) = world.get_block_and_block_state(block_pos).await;
let mut door_props = DoorProperties::from_state_id(block_state.id, &block);
let mut door_props = DoorProperties::from_state_id(block_state.id, block);
door_props.open = !door_props.open;
let other_half = match door_props.half {
@@ -43,13 +43,13 @@ async fn toggle_door(player: &Player, world: &Arc<World>, block_pos: &BlockPos)
let other_pos = block_pos.offset(other_half.to_offset());
let (other_block, other_state_id) = world.get_block_and_block_state(&other_pos).await;
let mut other_door_props = DoorProperties::from_state_id(other_state_id.id, &other_block);
let mut other_door_props = DoorProperties::from_state_id(other_state_id.id, other_block);
other_door_props.open = door_props.open;
world
.play_block_sound_expect(
player,
get_sound(&block, door_props.open),
get_sound(block, door_props.open),
SoundCategory::Blocks,
*block_pos,
)
@@ -58,14 +58,14 @@ async fn toggle_door(player: &Player, world: &Arc<World>, block_pos: &BlockPos)
world
.set_block_state(
block_pos,
door_props.to_state_id(&block),
door_props.to_state_id(block),
BlockFlags::NOTIFY_LISTENERS,
)
.await;
world
.set_block_state(
&other_pos,
other_door_props.to_state_id(&other_block),
other_door_props.to_state_id(other_block),
BlockFlags::NOTIFY_LISTENERS,
)
.await;
@@ -123,14 +123,14 @@ async fn get_hinge(
.await
.is_tagged_with("minecraft:doors")
.unwrap()
&& DoorProperties::from_state_id(left_state.id, &left_block).half == DoubleBlockHalf::Lower;
&& DoorProperties::from_state_id(left_state.id, left_block).half == DoubleBlockHalf::Lower;
let has_right_door = world
.get_block(&right_pos)
.await
.is_tagged_with("minecraft:doors")
.unwrap()
&& DoorProperties::from_state_id(right_state.id, &right_block).half
&& DoorProperties::from_state_id(right_state.id, right_block).half
== DoubleBlockHalf::Lower;
let score = -(left_state.is_full_cube() as i32) - (top_state.is_full_cube() as i32)
@@ -287,7 +287,7 @@ impl PumpkinBlock for DoorBlock {
if block.id == other_block.id && powered != door_props.powered {
let mut other_door_props =
DoorProperties::from_state_id(other_state_id.id, &other_block);
DoorProperties::from_state_id(other_state_id.id, other_block);
door_props.powered = !door_props.powered;
other_door_props.powered = door_props.powered;
@@ -310,7 +310,7 @@ impl PumpkinBlock for DoorBlock {
world
.set_block_state(
&other_pos,
other_door_props.to_state_id(&other_block),
other_door_props.to_state_id(other_block),
BlockFlags::NOTIFY_LISTENERS,
)
.await;

View File

@@ -21,8 +21,8 @@ impl PumpkinBlock for EndPortalBlock {
world: &Arc<World>,
entity: &dyn EntityBase,
pos: BlockPos,
_block: Block,
_state: BlockState,
_block: &'static Block,
_state: &'static BlockState,
server: &Server,
) {
let world = if world.dimension_type == VanillaDimensionType::TheEnd {

View File

@@ -28,7 +28,7 @@ pub async fn toggle_fence_gate(
) -> BlockStateId {
let (block, state) = world.get_block_and_block_state(block_pos).await;
let mut fence_gate_props = FenceGateProperties::from_state_id(state.id, &block);
let mut fence_gate_props = FenceGateProperties::from_state_id(state.id, block);
if fence_gate_props.open {
fence_gate_props.open = false;
} else {
@@ -46,12 +46,12 @@ pub async fn toggle_fence_gate(
world
.set_block_state(
block_pos,
fence_gate_props.to_state_id(&block),
fence_gate_props.to_state_id(block),
BlockFlags::NOTIFY_LISTENERS,
)
.await;
// TODO playSound depend on WoodType
fence_gate_props.to_state_id(&block)
fence_gate_props.to_state_id(block)
}
pub struct FenceGateBlock;

View File

@@ -75,7 +75,7 @@ pub async fn compute_fence_state(
let (other_block, other_block_state) =
world.get_block_and_block_state(&other_block_pos).await;
let connected = connects_to(block, &other_block, &other_block_state, direction);
let connected = connects_to(block, other_block, other_block_state, direction);
match direction {
BlockDirection::North => fence_props.north = connected,
BlockDirection::South => fence_props.south = connected,

View File

@@ -55,6 +55,7 @@ impl FireBlock {
block_state
.block()
.flammable
.as_ref()
.is_some_and(|f| f.burn_chance > 0)
}
@@ -66,7 +67,7 @@ impl FireBlock {
for direction in BlockDirection::all() {
let neighbor_pos = pos.offset(direction.to_offset());
let block_state = block_accessor.get_block_state(&neighbor_pos).await;
if Self::is_flammable(&block_state) {
if Self::is_flammable(block_state) {
return true;
}
}
@@ -81,7 +82,7 @@ impl FireBlock {
) -> BlockStateId {
let down_pos = pos.down();
let down_state = world.get_block_state(&down_pos).await;
if Self::is_flammable(&down_state) || down_state.is_side_solid(BlockDirection::Up) {
if Self::is_flammable(down_state) || down_state.is_side_solid(BlockDirection::Up) {
return Block::FIRE.default_state.id;
}
let mut fire_props =
@@ -89,7 +90,7 @@ impl FireBlock {
for direction in BlockDirection::all() {
let neighbor_pos = pos.offset(direction.to_offset());
let neighbor_state = world.get_block_state(&neighbor_pos).await;
if Self::is_flammable(&neighbor_state) {
if Self::is_flammable(neighbor_state) {
match direction {
BlockDirection::North => fire_props.north = true,
BlockDirection::South => fire_props.south = true,
@@ -117,6 +118,7 @@ impl FireBlock {
.get_block(pos)
.await
.flammable
.clone()
.map_or(0, |f| f.spread_chance)
.into();
if rand::rng().random_range(0..spread_factor) < spread_chance {
@@ -140,7 +142,7 @@ impl FireBlock {
.await;
}
if block == Block::TNT {
if block == &Block::TNT {
TNTBlock::prime(world, pos).await;
}
}
@@ -158,7 +160,7 @@ impl FireBlock {
if world.get_fluid(&pos.offset(dir.to_offset())).await.name != Fluid::EMPTY.name {
continue; // Skip if there is a fluid
}
if let Some(flammable) = neighbor_block.flammable {
if let Some(flammable) = neighbor_block.flammable.clone() {
total_burn_chance += i32::from(flammable.burn_chance);
}
}
@@ -210,8 +212,8 @@ impl PumpkinBlock for FireBlock {
_world: &Arc<World>,
entity: &dyn EntityBase,
_pos: BlockPos,
_block: Block,
_state: BlockState,
_block: &'static Block,
_state: &'static BlockState,
_server: &Server,
) {
let base_entity = entity.get_entity();
@@ -347,7 +349,7 @@ impl PumpkinBlock for FireBlock {
if age == 15
&& rand::rng().random_range(0..4) == 0
&& !Self::is_flammable(&world.get_block_state(&pos.down()).await)
&& !Self::is_flammable(world.get_block_state(&pos.down()).await)
{
world
.set_block_state(
@@ -441,7 +443,7 @@ impl PumpkinBlock for FireBlock {
block_pos: BlockPos,
_server: &Server,
world: Arc<World>,
_state: BlockState,
_state: &'static BlockState,
) {
FireBlockBase::broken(world, block_pos).await;
}

View File

@@ -24,7 +24,7 @@ pub struct FireBlockBase;
impl FireBlockBase {
pub async fn get_fire_type(world: &World, pos: &BlockPos) -> Block {
let (block, _block_state) = world.get_block_and_block_state(&pos.down()).await;
if SoulFireBlock::is_soul_base(&block) {
if SoulFireBlock::is_soul_base(block) {
return Block::SOUL_FIRE;
}
Block::FIRE
@@ -32,13 +32,11 @@ impl FireBlockBase {
#[must_use]
pub fn can_place_on(block: &Block) -> bool {
let block = block.clone();
// Make sure the block below is not a fire block or fluid block
block != Block::SOUL_FIRE
&& block != Block::FIRE
&& block != Block::WATER
&& block != Block::LAVA
block != &Block::SOUL_FIRE
&& block != &Block::FIRE
&& block != &Block::WATER
&& block != &Block::LAVA
}
pub async fn is_soul_fire(world: &Arc<World>, block_pos: &BlockPos) -> bool {
@@ -95,7 +93,7 @@ impl FireBlockBase {
let mut found = false;
for dir in BlockDirection::all() {
if world.get_block(&block_pos.offset(dir.to_offset())).await == Block::OBSIDIAN {
if world.get_block(&block_pos.offset(dir.to_offset())).await == &Block::OBSIDIAN {
found = true;
break;
}

View File

@@ -21,7 +21,7 @@ pub struct SoulFireBlock;
impl SoulFireBlock {
#[must_use]
pub fn is_soul_base(block: &Block) -> bool {
pub fn is_soul_base(block: &'static Block) -> bool {
block
.is_tagged_with("minecraft:soul_fire_base_blocks")
.unwrap()
@@ -40,7 +40,7 @@ impl PumpkinBlock for SoulFireBlock {
_neighbor_pos: &BlockPos,
_neighbor_state: BlockStateId,
) -> BlockStateId {
if !Self::is_soul_base(&world.get_block(&block_pos.down()).await) {
if !Self::is_soul_base(world.get_block(&block_pos.down()).await) {
return Block::AIR.default_state.id;
}
@@ -58,7 +58,7 @@ impl PumpkinBlock for SoulFireBlock {
_face: BlockDirection,
_use_item_on: Option<&SUseItemOn>,
) -> bool {
Self::is_soul_base(&block_accessor.get_block(&block_pos.down()).await)
Self::is_soul_base(block_accessor.get_block(&block_pos.down()).await)
}
async fn broken(
@@ -68,7 +68,7 @@ impl PumpkinBlock for SoulFireBlock {
block_pos: BlockPos,
_server: &Server,
world: Arc<World>,
_state: BlockState,
_state: &'static BlockState,
) {
FireBlockBase::broken(world, block_pos).await;
}

View File

@@ -73,10 +73,10 @@ pub async fn compute_pane_state(
let (other_block, other_block_state) =
world.get_block_and_block_state(&other_block_pos).await;
let connected = other_block == *block
let connected = other_block == block
|| other_block_state.is_side_solid(direction.opposite())
|| other_block.is_tagged_with("c:glass_panes").unwrap()
|| other_block == Block::IRON_BARS
|| other_block == &Block::IRON_BARS
|| other_block.is_tagged_with("minecraft:walls").unwrap();
match direction {

View File

@@ -64,7 +64,7 @@ pub async fn compute_bars_state(
let (other_block, other_block_state) =
world.get_block_and_block_state(&other_block_pos).await;
let connected = other_block == *block
let connected = other_block == block
|| other_block_state.is_side_solid(direction.opposite())
|| other_block.is_tagged_with("c:glass_panes").unwrap()
|| other_block.is_tagged_with("minecraft:walls").unwrap();

View File

@@ -113,7 +113,7 @@ impl PumpkinBlock for JukeboxBlock {
position: BlockPos,
_server: &Server,
world: Arc<World>,
_state: BlockState,
_state: &'static BlockState,
) {
// For now just stop the music at this position
world

View File

@@ -66,8 +66,8 @@ impl PumpkinBlock for NetherPortalBlock {
world: &Arc<World>,
entity: &dyn EntityBase,
pos: BlockPos,
_block: Block,
_state: BlockState,
_block: &'static Block,
_state: &'static BlockState,
server: &Server,
) {
let target_world = if world.dimension_type == VanillaDimensionType::TheNether {

View File

@@ -52,8 +52,8 @@ impl<'a> PistonHandler<'a> {
let (block, block_state) = self.world.get_block_and_block_state(&self.pos_to).await;
if !PistonBlock::is_movable(
&block,
&block_state,
block,
block_state,
self.motion_direction,
false,
self.piston_direction,
@@ -69,8 +69,7 @@ impl<'a> PistonHandler<'a> {
}
for block_pos in self.moved_blocks.clone() {
let block = self.world.get_block(&block_pos).await;
if Self::is_block_sticky(&block)
&& !self.try_move_adjacent_block(&block, block_pos).await
if Self::is_block_sticky(block) && !self.try_move_adjacent_block(block, block_pos).await
{
return false;
}
@@ -97,7 +96,7 @@ impl<'a> PistonHandler<'a> {
if block_state.is_air() {
return true;
}
if !PistonBlock::is_movable(&block, &block_state, self.motion_direction, false, dir) {
if !PistonBlock::is_movable(block, block_state, self.motion_direction, false, dir) {
return true;
}
if pos == self.pos_from {
@@ -110,15 +109,15 @@ impl<'a> PistonHandler<'a> {
if i + self.moved_blocks.len() > MAX_MOVABLE_BLOCKS {
return false;
}
while Self::is_block_sticky(&block) {
while Self::is_block_sticky(block) {
let block_pos = pos.offset_dir(self.motion_direction.opposite().to_offset(), i as i32);
let block2 = block;
(block, block_state) = self.world.get_block_and_block_state(&block_pos).await;
if block_state.is_air()
|| !Self::is_adjacent_block_stuck(&block2, &block)
|| !Self::is_adjacent_block_stuck(block2, block)
|| !PistonBlock::is_movable(
&block,
&block_state,
block,
block_state,
self.motion_direction,
false,
self.motion_direction.opposite(),
@@ -146,8 +145,8 @@ impl<'a> PistonHandler<'a> {
for m in 0..=(l + j) {
let block_pos3 = self.moved_blocks[m];
let block = self.world.get_block(&block_pos3).await;
if Self::is_block_sticky(&block)
&& !Box::pin(self.try_move_adjacent_block(&block, block_pos3)).await
if Self::is_block_sticky(block)
&& !Box::pin(self.try_move_adjacent_block(block, block_pos3)).await
{
return false;
}
@@ -159,8 +158,8 @@ impl<'a> PistonHandler<'a> {
return true;
}
if !PistonBlock::is_movable(
&block,
&block_state,
block,
block_state,
self.motion_direction,
true,
self.motion_direction,
@@ -201,7 +200,7 @@ impl<'a> PistonHandler<'a> {
}
let block_pos = pos.offset(direction.to_offset());
let block_state2 = self.world.get_block(&block_pos).await;
if Self::is_adjacent_block_stuck(&block_state2, block)
if Self::is_adjacent_block_stuck(block_state2, block)
&& !self.try_move(block_pos, direction).await
{
return false;

View File

@@ -225,7 +225,7 @@ impl PumpkinBlock for PistonBlock {
let pos = pos.offset_dir(dir.to_offset(), 2);
let (block, state) = world.get_block_and_block_state(&pos).await;
let mut bl2 = false;
if block == Block::MOVING_PISTON {
if block == &Block::MOVING_PISTON {
if let Some(entity) = world.get_block_entity(&pos).await {
let piston = PistonBlockEntity::from_nbt(&entity.0, pos);
if piston.facing == dir && piston.extending {
@@ -237,10 +237,10 @@ impl PumpkinBlock for PistonBlock {
if !bl2 {
if r#type == 1
&& !state.is_air()
&& Self::is_movable(&block, &state, dir, false, dir)
&& Self::is_movable(block, state, dir, false, dir)
&& (state.piston_behavior == PistonBehavior::Normal
|| block == Block::PISTON
|| block == Block::STICKY_PISTON)
|| block == &Block::PISTON
|| block == &Block::STICKY_PISTON)
{
move_piston(world, dir, &pos, false, sticky).await;
} else {
@@ -274,7 +274,7 @@ async fn should_extend(world: &World, block_pos: &BlockPos, piston_dir: BlockDir
let (block, state) = world.get_block_and_block_state(&neighbor_pos).await;
// Pistons can't be powered from the same direction as they are facing
if dir == piston_dir
|| !is_emitting_redstone_power(&block, &state, world, &neighbor_pos, dir).await
|| !is_emitting_redstone_power(block, state, world, &neighbor_pos, dir).await
{
continue;
}
@@ -282,14 +282,14 @@ async fn should_extend(world: &World, block_pos: &BlockPos, piston_dir: BlockDir
}
let neighbor_pos = block_pos.offset(BlockDirection::Down.to_offset());
let (block, state) = world.get_block_and_block_state(&neighbor_pos).await;
if is_emitting_redstone_power(&block, &state, world, block_pos, BlockDirection::Down).await {
if is_emitting_redstone_power(block, state, world, block_pos, BlockDirection::Down).await {
return true;
}
for dir in BlockDirection::all() {
let neighbor_pos = block_pos.up().offset(dir.to_offset());
let (block, state) = world.get_block_and_block_state(&neighbor_pos).await;
if dir == BlockDirection::Down
|| !is_emitting_redstone_power(&block, &state, world, &neighbor_pos, dir).await
|| !is_emitting_redstone_power(block, state, world, &neighbor_pos, dir).await
{
continue;
}
@@ -318,8 +318,8 @@ async fn try_move(world: &Arc<World>, block: &Block, block_pos: &BlockPos) {
let (new_block, new_state) = world.get_block_and_block_state(&new_pos).await;
let mut r#type = 1;
if new_block == Block::MOVING_PISTON {
let new_props = MovingPistonLikeProperties::from_state_id(new_state.id, &new_block);
if new_block == &Block::MOVING_PISTON {
let new_props = MovingPistonLikeProperties::from_state_id(new_state.id, new_block);
if new_props.facing == props.facing {
if let Some(entity) = world.get_block_entity(&new_pos).await {
let piston = PistonBlockEntity::from_nbt(&entity.0, new_pos);
@@ -347,7 +347,7 @@ async fn move_piston(
sticky: bool,
) -> bool {
let extended_pos = block_pos.offset(dir.to_offset());
if !extend && world.get_block(&extended_pos).await == Block::PISTON_HEAD {
if !extend && world.get_block(&extended_pos).await == &Block::PISTON_HEAD {
world
.set_block_state(
&extended_pos,
@@ -361,19 +361,19 @@ async fn move_piston(
return false;
}
let mut moved_blocks_map: HashMap<BlockPos, BlockState> = HashMap::new();
let mut moved_blocks_map: HashMap<BlockPos, &'static BlockState> = HashMap::new();
let moved_blocks: Vec<BlockPos> = handler.moved_blocks;
let mut moved_block_states: Vec<BlockState> = Vec::new();
let mut moved_block_states: Vec<&'static BlockState> = Vec::new();
for &block_pos in &moved_blocks {
let block_state = world.get_block_state(&block_pos).await;
moved_block_states.push(block_state.clone());
moved_block_states.push(block_state);
moved_blocks_map.insert(block_pos, block_state);
}
let broken_blocks: Vec<BlockPos> = handler.broken_blocks;
let mut affected_block_states: Vec<BlockState> =
let mut affected_block_states: Vec<&'static BlockState> =
Vec::with_capacity(moved_blocks.len() + broken_blocks.len());
let move_direction = if extend { dir } else { dir.opposite() };
@@ -407,7 +407,7 @@ async fn move_piston(
.add_block_entity(Arc::new(PistonBlockEntity {
position: extended_pos,
facing: dir.to_facing().to_block_direction(),
pushed_block_state: moved_state.clone(),
pushed_block_state: moved_state,
current_progress: 0.0.into(),
last_progress: 0.0.into(),
extending: extend,
@@ -469,7 +469,7 @@ async fn move_piston(
.prepare(
world,
pos,
&get_block_by_state_id(state.id).unwrap(),
get_block_by_state_id(state.id).unwrap(),
state.id,
BlockFlags::NOTIFY_LISTENERS,
)
@@ -488,12 +488,12 @@ async fn move_piston(
}
for (i, &broken_block_pos) in broken_blocks.iter().rev().enumerate() {
if let Some(block_state) = affected_block_states.get(i).cloned() {
if let Some(block_state) = affected_block_states.get(i) {
world
.block_registry
.on_state_replaced(
world,
&get_block_by_state_id(block_state.id).unwrap(),
get_block_by_state_id(block_state.id).unwrap(),
broken_block_pos,
block_state.id, // ?
false,
@@ -504,7 +504,7 @@ async fn move_piston(
.prepare(
world,
&broken_block_pos,
&get_block_by_state_id(block_state.id).unwrap(),
get_block_by_state_id(block_state.id).unwrap(),
block_state.id,
BlockFlags::NOTIFY_LISTENERS,
)

View File

@@ -30,13 +30,13 @@ impl PumpkinBlock for PistonExtensionBlock {
location: BlockPos,
_server: &Server,
world: Arc<World>,
state: BlockState,
state: &'static BlockState,
) {
let props = MovingPistonProps::from_state_id(state.id, &Block::MOVING_PISTON);
let pos = location.offset(props.facing.opposite().to_block_direction().to_offset());
let (new_block, new_state) = world.get_block_and_block_state(&pos).await;
if PistonBlock::ids(&PistonBlock).contains(&new_block.name) {
let props = PistonProps::from_state_id(new_state.id, &new_block);
let props = PistonProps::from_state_id(new_state.id, new_block);
if props.extended {
// TODO: use player
world.break_block(&pos, None, BlockFlags::SKIP_DROPS).await;

View File

@@ -30,13 +30,13 @@ impl PumpkinBlock for PistonHeadBlock {
location: BlockPos,
_server: &Server,
world: Arc<World>,
state: BlockState,
state: &'static BlockState,
) {
let props = PistonHeadProperties::from_state_id(state.id, &Block::PISTON_HEAD);
let pos = location.offset(props.facing.opposite().to_block_direction().to_offset());
let (new_block, new_state) = world.get_block_and_block_state(&pos).await;
if PistonBlock::ids(&PistonBlock).contains(&new_block.name) {
let props = PistonProps::from_state_id(new_state.id, &new_block);
let props = PistonProps::from_state_id(new_state.id, new_block);
if props.extended {
// TODO: use player
world.break_block(&pos, None, BlockFlags::SKIP_DROPS).await;

View File

@@ -36,6 +36,6 @@ impl PumpkinBlock for BushBlock {
_use_item_on: Option<&SUseItemOn>,
) -> bool {
let block_below = block_accessor.get_block(&block_pos.down()).await;
block_below.is_tagged_with("minecraft:dirt").unwrap() || block_below == Block::FARMLAND
block_below.is_tagged_with("minecraft:dirt").unwrap() || block_below == &Block::FARMLAND
}
}

View File

@@ -38,7 +38,7 @@ impl PumpkinBlock for FlowerBlock {
_use_item_on: Option<&SUseItemOn>,
) -> bool {
let block_below = block_accessor.get_block(&block_pos.down()).await;
block_below.is_tagged_with("minecraft:dirt").unwrap() || block_below == Block::FARMLAND
block_below.is_tagged_with("minecraft:dirt").unwrap() || block_below == &Block::FARMLAND
}
async fn random_tick(&self, block: &Block, world: &Arc<World>, pos: &BlockPos) {

View File

@@ -41,7 +41,7 @@ impl PumpkinBlock for FlowerbedBlock {
_use_item_on: Option<&SUseItemOn>,
) -> bool {
let block_below = block_accessor.get_block(&block_pos.down()).await;
block_below.is_tagged_with("minecraft:dirt").unwrap() || block_below == Block::FARMLAND
block_below.is_tagged_with("minecraft:dirt").unwrap() || block_below == &Block::FARMLAND
}
async fn can_update_at(
@@ -103,7 +103,7 @@ impl PumpkinBlock for FlowerbedBlock {
if direction == BlockDirection::Down {
let block_below = world.get_block(&pos.down()).await;
if !(block_below.is_tagged_with("minecraft:dirt").unwrap()
|| block_below == Block::FARMLAND)
|| block_below == &Block::FARMLAND)
{
return Block::AIR.default_state.id;
}

View File

@@ -24,8 +24,8 @@ impl PumpkinBlock for LilyPadBlock {
world: &Arc<World>,
entity: &dyn EntityBase,
pos: BlockPos,
_block: Block,
_state: BlockState,
_block: &'static Block,
_state: &'static BlockState,
_server: &Server,
) {
// Proberbly not the best solution, but works
@@ -51,6 +51,6 @@ impl PumpkinBlock for LilyPadBlock {
_use_item_on: Option<&SUseItemOn>,
) -> bool {
let block_below = block_accessor.get_block(&block_pos.down()).await;
block_below == Block::WATER || block_below == Block::ICE
block_below == &Block::WATER || block_below == &Block::ICE
}
}

View File

@@ -37,8 +37,8 @@ impl PumpkinBlock for RootsBlock {
) -> bool {
let block_below = block_accessor.get_block(&block_pos.down()).await;
block_below.is_tagged_with("minecraft:nylium").unwrap()
|| block_below == Block::SOUL_SOIL
|| block_below == &Block::SOUL_SOIL
|| block_below.is_tagged_with("minecraft:dirt").unwrap()
|| block_below == Block::FARMLAND
|| block_below == &Block::FARMLAND
}
}

View File

@@ -36,6 +36,6 @@ impl PumpkinBlock for SaplingBlock {
_use_item_on: Option<&SUseItemOn>,
) -> bool {
let block_below = block_accessor.get_block(&block_pos.down()).await;
block_below.is_tagged_with("minecraft:dirt").unwrap() || block_below == Block::FARMLAND
block_below.is_tagged_with("minecraft:dirt").unwrap() || block_below == &Block::FARMLAND
}
}

View File

@@ -36,6 +36,6 @@ impl PumpkinBlock for ShortPlantBlock {
_use_item_on: Option<&SUseItemOn>,
) -> bool {
let block_below = block_accessor.get_block(&block_pos.down()).await;
block_below.is_tagged_with("minecraft:dirt").unwrap() || block_below == Block::FARMLAND
block_below.is_tagged_with("minecraft:dirt").unwrap() || block_below == &Block::FARMLAND
}
}

View File

@@ -62,6 +62,6 @@ impl PumpkinBlock for TallPlantBlock {
}
}
let block_below = block_accessor.get_block(&block_pos.down()).await;
block_below.is_tagged_with("minecraft:dirt").unwrap() || block_below == Block::FARMLAND
block_below.is_tagged_with("minecraft:dirt").unwrap() || block_below == &Block::FARMLAND
}
}

View File

@@ -30,7 +30,7 @@ pub trait RedstoneGateBlock<T: Send + BlockProperties + RedstoneGateBlockPropert
async fn can_place_at(&self, world: &dyn BlockAccessor, pos: BlockPos) -> bool {
let under_pos = pos.down();
let under_state = world.get_block_state(&under_pos).await;
self.can_place_above(world, under_pos, &under_state).await
self.can_place_above(world, under_pos, under_state).await
}
async fn can_place_above(
@@ -81,7 +81,7 @@ pub trait RedstoneGateBlock<T: Send + BlockProperties + RedstoneGateBlockPropert
) {
let state = world.get_block_state(pos).await;
if RedstoneGateBlock::can_place_at(self, &**world, *pos).await {
self.update_powered(world, *pos, &state, block).await;
self.update_powered(world, *pos, state, block).await;
return;
}
world
@@ -170,7 +170,7 @@ pub trait RedstoneGateBlock<T: Send + BlockProperties + RedstoneGateBlockPropert
pos: &BlockPos,
) {
if let Some(state) = get_state_by_state_id(state_id) {
if RedstoneGateBlock::has_power(self, world, *pos, &state, block).await {
if RedstoneGateBlock::has_power(self, world, *pos, state, block).await {
world
.schedule_block_tick(block, *pos, 1, TickPriority::Normal)
.await;
@@ -186,8 +186,7 @@ pub trait RedstoneGateBlock<T: Send + BlockProperties + RedstoneGateBlockPropert
old_state_id: BlockStateId,
moved: bool,
) {
if moved || Block::from_state_id(old_state_id).is_some_and(|old_block| old_block == *block)
{
if moved || Block::from_state_id(old_state_id).is_some_and(|old_block| old_block == block) {
return;
}
if let Some(old_state) = get_state_by_state_id(old_state_id) {
@@ -207,11 +206,11 @@ pub trait RedstoneGateBlock<T: Send + BlockProperties + RedstoneGateBlockPropert
let (target_block, target_state) = world
.get_block_and_block_state(&pos.offset(facing.to_offset()))
.await;
if target_block == Block::COMPARATOR {
let props = ComparatorLikeProperties::from_state_id(target_state.id, &target_block);
if target_block == &Block::COMPARATOR {
let props = ComparatorLikeProperties::from_state_id(target_state.id, target_block);
props.facing != facing
} else if target_block == Block::REPEATER {
let props = RepeaterLikeProperties::from_state_id(target_state.id, &target_block);
} else if target_block == &Block::REPEATER {
let props = RepeaterLikeProperties::from_state_id(target_state.id, target_block);
props.facing != facing
} else {
false
@@ -232,8 +231,8 @@ pub async fn get_power<T: BlockProperties + RedstoneGateBlockProperties + Send>(
let source_pos = pos.offset(facing.to_offset());
let (source_block, source_state) = world.get_block_and_block_state(&source_pos).await;
let source_level = get_redstone_power(
&source_block,
&source_state,
source_block,
source_state,
world,
&source_pos,
facing.to_block_direction(),
@@ -242,8 +241,8 @@ pub async fn get_power<T: BlockProperties + RedstoneGateBlockProperties + Send>(
if source_level >= 15 {
source_level
} else {
source_level.max(if source_block == Block::REDSTONE_WIRE {
let props = RedstoneWireLikeProperties::from_state_id(source_state.id, &source_block);
source_level.max(if source_block == &Block::REDSTONE_WIRE {
let props = RedstoneWireLikeProperties::from_state_id(source_state.id, source_block);
props.power.to_index() as u8
} else {
0
@@ -259,14 +258,14 @@ async fn get_power_on_side(
) -> u8 {
let side_pos = pos.offset(side.to_block_direction().to_offset());
let (side_block, side_state) = world.get_block_and_block_state(&side_pos).await;
if !only_gate || is_diode(&side_block) {
if !only_gate || is_diode(side_block) {
world
.block_registry
.get_weak_redstone_power(
&side_block,
side_block,
world,
&side_pos,
&side_state,
side_state,
side.to_block_direction(),
)
.await

View File

@@ -31,19 +31,23 @@ use crate::world::World;
async fn click_button(world: &Arc<World>, block_pos: &BlockPos) {
let (block, state) = world.get_block_and_block_state(block_pos).await;
let mut button_props = ButtonLikeProperties::from_state_id(state.id, &block);
let mut button_props = ButtonLikeProperties::from_state_id(state.id, block);
if !button_props.powered {
button_props.powered = true;
world
.set_block_state(
block_pos,
button_props.to_state_id(&block),
button_props.to_state_id(block),
BlockFlags::NOTIFY_ALL,
)
.await;
let delay = if block == Block::STONE_BUTTON { 20 } else { 30 };
let delay = if block == &Block::STONE_BUTTON {
20
} else {
30
};
world
.schedule_block_tick(&block, *block_pos, delay, TickPriority::Normal)
.schedule_block_tick(block, *block_pos, delay, TickPriority::Normal)
.await;
ButtonBlock::update_neighbors(world, block_pos, &button_props).await;
}

View File

@@ -134,7 +134,7 @@ impl PumpkinBlock for ComparatorBlock {
block_pos: BlockPos,
_server: &Server,
world: Arc<World>,
_state: BlockState,
_state: &'static BlockState,
) {
world.remove_block_entity(&block_pos).await;
}
@@ -151,7 +151,7 @@ impl PumpkinBlock for ComparatorBlock {
) -> BlockStateId {
if direction == BlockDirection::Down {
if let Some(neighbor_state) = get_state_by_state_id(neighbor_state_id) {
if !RedstoneGateBlock::can_place_above(self, world, *neighbor_pos, &neighbor_state)
if !RedstoneGateBlock::can_place_above(self, world, *neighbor_pos, neighbor_state)
.await
{
return Block::AIR.default_state.id;
@@ -200,7 +200,7 @@ impl PumpkinBlock for ComparatorBlock {
async fn on_scheduled_tick(&self, world: &Arc<World>, block: &Block, pos: &BlockPos) {
let state = world.get_block_state(pos).await;
self.update(world, *pos, &state, block).await;
self.update(world, *pos, state, block).await;
}
async fn on_state_replaced(
@@ -313,9 +313,9 @@ impl RedstoneGateBlock<ComparatorLikeProperties> for ComparatorBlock {
let source_pos = pos.offset(facing.to_offset());
let (source_block, source_state) = world.get_block_and_block_state(&source_pos).await;
if let Some(pumpkin_block) = world.block_registry.get_pumpkin_block(&source_block) {
if let Some(pumpkin_block) = world.block_registry.get_pumpkin_block(source_block) {
if let Some(level) = pumpkin_block
.get_comparator_output(&source_block, world, &source_pos, &source_state)
.get_comparator_output(source_block, world, &source_pos, source_state)
.await
{
return level;
@@ -329,15 +329,14 @@ impl RedstoneGateBlock<ComparatorLikeProperties> for ComparatorBlock {
let itemframe_level = self
.get_attached_itemframe_level(world, facing, source_pos)
.await;
let block_level = if let Some(pumpkin_block) =
world.block_registry.get_pumpkin_block(&source_block)
{
pumpkin_block
.get_comparator_output(&source_block, world, &source_pos, &source_state)
.await
} else {
None
};
let block_level =
if let Some(pumpkin_block) = world.block_registry.get_pumpkin_block(source_block) {
pumpkin_block
.get_comparator_output(source_block, world, &source_pos, source_state)
.await
} else {
None
};
if let Some(level) = itemframe_level.max(block_level) {
return level;
}
@@ -367,7 +366,7 @@ impl ComparatorBlock {
.set_block_state(&block_pos, state_id, BlockFlags::empty())
.await;
if let Some(state) = get_state_by_state_id(state_id) {
self.update(world, block_pos, &state, block).await;
self.update(world, block_pos, state, block).await;
}
}

View File

@@ -27,12 +27,12 @@ use crate::{
async fn toggle_lever(world: &Arc<World>, block_pos: &BlockPos) {
let (block, state) = world.get_block_and_block_state(block_pos).await;
let mut lever_props = LeverLikeProperties::from_state_id(state.id, &block);
let mut lever_props = LeverLikeProperties::from_state_id(state.id, block);
lever_props.powered = !lever_props.powered;
world
.set_block_state(
block_pos,
lever_props.to_state_id(&block),
lever_props.to_state_id(block),
BlockFlags::NOTIFY_ALL,
)
.await;

View File

@@ -35,7 +35,7 @@ pub async fn update_wire_neighbors(world: &Arc<World>, pos: &BlockPos) {
let block = world.get_block(&neighbor_pos).await;
world
.block_registry
.on_neighbor_update(world, &block, &neighbor_pos, &block, true)
.on_neighbor_update(world, block, &neighbor_pos, block, true)
.await;
for n_direction in BlockDirection::all() {
@@ -43,7 +43,7 @@ pub async fn update_wire_neighbors(world: &Arc<World>, pos: &BlockPos) {
let block = world.get_block(&n_neighbor_pos).await;
world
.block_registry
.on_neighbor_update(world, &block, &n_neighbor_pos, &block, true)
.on_neighbor_update(world, block, &n_neighbor_pos, block, true)
.await;
}
}
@@ -99,8 +99,8 @@ async fn get_max_strong_power(world: &World, pos: &BlockPos, dust_power: bool) -
.await;
max_power = max_power.max(
get_strong_power(
&block,
&state,
block,
state,
world,
&pos.offset(side.to_offset()),
side,
@@ -120,8 +120,8 @@ async fn get_max_weak_power(world: &World, pos: &BlockPos, dust_power: bool) ->
.await;
max_power = max_power.max(
get_weak_power(
&block,
&state,
block,
state,
world,
&pos.offset(side.to_offset()),
side,
@@ -171,7 +171,7 @@ pub async fn block_receives_redstone_power(world: &World, pos: &BlockPos) -> boo
for face in BlockDirection::all() {
let neighbor_pos = pos.offset(face.to_offset());
let (block, state) = world.get_block_and_block_state(&neighbor_pos).await;
if is_emitting_redstone_power(&block, &state, world, pos, face).await {
if is_emitting_redstone_power(block, state, world, pos, face).await {
return true;
}
}
@@ -186,7 +186,7 @@ pub fn is_diode(block: &Block) -> bool {
pub async fn diode_get_input_strength(world: &World, pos: &BlockPos, facing: BlockDirection) -> u8 {
let input_pos = pos.offset(facing.to_offset());
let (input_block, input_state) = world.get_block_and_block_state(&input_pos).await;
let power: u8 = get_redstone_power(&input_block, &input_state, world, &input_pos, facing).await;
let power: u8 = get_redstone_power(input_block, input_state, world, &input_pos, facing).await;
if power == 0 && input_state.is_solid() {
return get_max_weak_power(world, &input_pos, true).await;
}

View File

@@ -14,12 +14,12 @@ pub(crate) trait PressurePlate {
&self,
world: &Arc<World>,
pos: BlockPos,
block: Block,
state: BlockState,
block: &'static Block,
state: &'static BlockState,
) {
let output = self.get_redstone_output(&block, state.id);
let output = self.get_redstone_output(block, state.id);
if output == 0 {
self.update_plate_state(world, pos, &block, state, output)
self.update_plate_state(world, pos, block, state, output)
.await;
}
}
@@ -52,13 +52,13 @@ pub(crate) trait PressurePlate {
world: &Arc<World>,
pos: BlockPos,
block: &Block,
state: BlockState,
state: &'static BlockState,
output: u8,
) {
let calc_output = self.calculate_redstone_output(world, block, &pos).await;
let has_output = calc_output > 0;
if calc_output != output {
let state = self.set_redstone_output(block, &state, calc_output);
let state = self.set_redstone_output(block, state, calc_output);
world
.set_block_state(&pos, state, BlockFlags::NOTIFY_LISTENERS)
.await;

View File

@@ -47,8 +47,8 @@ impl PumpkinBlock for PressurePlateBlock {
world: &Arc<World>,
_entity: &dyn EntityBase,
pos: BlockPos,
block: Block,
state: BlockState,
block: &'static Block,
state: &'static BlockState,
_server: &Server,
) {
self.on_entity_collision_pp(world, pos, block, state).await;

View File

@@ -44,8 +44,8 @@ impl PumpkinBlock for WeightedPressurePlateBlock {
world: &Arc<World>,
_entity: &dyn EntityBase,
pos: BlockPos,
block: Block,
state: BlockState,
block: &'static Block,
state: &'static BlockState,
_server: &Server,
) {
self.on_entity_collision_pp(world, pos, block, state).await;

View File

@@ -95,7 +95,7 @@ pub(super) async fn update_flanking_rails_shape(
world
.set_block_state(
&flanking_rail.position,
flanking_rail.properties.to_state_id(&flanking_rail.block),
flanking_rail.properties.to_state_id(flanking_rail.block),
BlockFlags::NOTIFY_ALL,
)
.await;

View File

@@ -19,7 +19,7 @@ pub mod powered_rail;
pub mod rail;
struct Rail {
block: Block,
block: &'static Block,
position: BlockPos,
properties: RailProperties,
elevation: RailElevation,
@@ -29,7 +29,7 @@ impl Rail {
async fn find_with_elevation(world: &World, position: BlockPos) -> Option<Self> {
let (block, block_state) = world.get_block_and_block_state(&position).await;
if block.is_tagged_with("#minecraft:rails").unwrap() {
let properties = RailProperties::new(block_state.id, &block);
let properties = RailProperties::new(block_state.id, block);
return Some(Self {
block,
position,
@@ -41,7 +41,7 @@ impl Rail {
let pos = position.up();
let (block, block_state) = world.get_block_and_block_state(&pos).await;
if block.is_tagged_with("#minecraft:rails").unwrap() {
let properties = RailProperties::new(block_state.id, &block);
let properties = RailProperties::new(block_state.id, block);
return Some(Self {
block,
position: pos,
@@ -53,7 +53,7 @@ impl Rail {
let pos = position.down();
let (block, block_state) = world.get_block_and_block_state(&pos).await;
if block.is_tagged_with("#minecraft:rails").unwrap() {
let properties = RailProperties::new(block_state.id, &block);
let properties = RailProperties::new(block_state.id, block);
return Some(Self {
block,
position: pos,

View File

@@ -301,7 +301,7 @@ impl PumpkinBlock for RedstoneTorchBlock {
pub async fn should_be_lit(world: &World, pos: &BlockPos, face: BlockDirection) -> bool {
let other_pos = pos.offset(face.to_offset());
let (block, state) = world.get_block_and_block_state(&other_pos).await;
get_redstone_power(&block, &state, world, &other_pos, face).await == 0
get_redstone_power(block, state, world, &other_pos, face).await == 0
}
pub async fn update_neighbors(world: &Arc<World>, pos: &BlockPos) {

View File

@@ -134,10 +134,10 @@ impl PumpkinBlock for RedstoneWireBlock {
let other_block_pos = block_pos.offset(direction.to_offset());
let other_block = world.get_block(&other_block_pos).await;
if wire_props.is_side_connected(direction) && other_block != Block::REDSTONE_WIRE {
if wire_props.is_side_connected(direction) && other_block != &Block::REDSTONE_WIRE {
let up_block_pos = other_block_pos.up();
let up_block = world.get_block(&up_block_pos).await;
if up_block == Block::REDSTONE_WIRE {
if up_block == &Block::REDSTONE_WIRE {
world
.replace_with_state_for_neighbor_update(
&up_block_pos,
@@ -149,7 +149,7 @@ impl PumpkinBlock for RedstoneWireBlock {
let down_block_pos = other_block_pos.down();
let down_block = world.get_block(&down_block_pos).await;
if down_block == Block::REDSTONE_WIRE {
if down_block == &Block::REDSTONE_WIRE {
world
.replace_with_state_for_neighbor_update(
&down_block_pos,
@@ -272,7 +272,7 @@ impl PumpkinBlock for RedstoneWireBlock {
location: BlockPos,
_server: &Server,
world: Arc<World>,
_state: BlockState,
_state: &'static BlockState,
) {
update_wire_neighbors(&world, &location).await;
}
@@ -353,7 +353,7 @@ pub async fn get_side(world: &World, pos: &BlockPos, side: BlockDirection) -> Wi
let neighbor_pos: BlockPos = pos.offset(side.to_offset());
let (neighbor, state) = world.get_block_and_block_state(&neighbor_pos).await;
if can_connect_to(world, &neighbor, side, &state).await {
if can_connect_to(world, neighbor, side, state).await {
return WireConnection::Side;
}
@@ -362,7 +362,7 @@ pub async fn get_side(world: &World, pos: &BlockPos, side: BlockDirection) -> Wi
if !up_state.is_solid()
&& can_connect_diagonal_to(
&world
world
.get_block(&neighbor_pos.offset(BlockDirection::Up.to_offset()))
.await,
)
@@ -370,7 +370,7 @@ pub async fn get_side(world: &World, pos: &BlockPos, side: BlockDirection) -> Wi
WireConnection::Up
} else if !state.is_solid()
&& can_connect_diagonal_to(
&world
world
.get_block(&neighbor_pos.offset(BlockDirection::Down.to_offset()))
.await,
)
@@ -579,8 +579,8 @@ impl CardinalWireConnectionExt for WestWireConnection {
async fn max_wire_power(wire_power: u8, world: &World, pos: BlockPos) -> u8 {
let (block, block_state) = world.get_block_and_block_state(&pos).await;
if block == Block::REDSTONE_WIRE {
let wire = RedstoneWireProperties::from_state_id(block_state.id, &block);
if block == &Block::REDSTONE_WIRE {
let wire = RedstoneWireProperties::from_state_id(block_state.id, block);
wire_power.max(wire.power.to_index() as u8)
} else {
wire_power
@@ -599,7 +599,7 @@ async fn calculate_power(world: &World, pos: &BlockPos) -> u8 {
wire_power = max_wire_power(wire_power, world, neighbor_pos).await;
let (neighbor, neighbor_state) = world.get_block_and_block_state(&neighbor_pos).await;
block_power = block_power.max(
get_redstone_power_no_dust(&neighbor, &neighbor_state, world, neighbor_pos, side).await,
get_redstone_power_no_dust(neighbor, neighbor_state, world, neighbor_pos, side).await,
);
if side.is_horizontal() {
if !up_state.is_solid()

View File

@@ -68,7 +68,7 @@ impl PumpkinBlock for RepeaterBlock {
let mut props = RepeaterProperties::from_state_id(state.id, block);
let now_powered = props.powered;
let should_be_powered = self.has_power(world, *block_pos, &state, block).await;
let should_be_powered = self.has_power(world, *block_pos, state, block).await;
if now_powered && !should_be_powered {
props.powered = false;
@@ -226,7 +226,7 @@ impl PumpkinBlock for RepeaterBlock {
) -> BlockStateId {
if direction == BlockDirection::Down {
if let Some(neighbor_state) = get_state_by_state_id(neighbor_state_id) {
if !RedstoneGateBlock::can_place_above(self, world, *neighbor_pos, &neighbor_state)
if !RedstoneGateBlock::can_place_above(self, world, *neighbor_pos, neighbor_state)
.await
{
return Block::AIR.default_state.id;

View File

@@ -33,17 +33,17 @@ impl PumpkinBlock for TripwireBlock {
world: &Arc<World>,
_entity: &dyn EntityBase,
pos: BlockPos,
block: Block,
state: BlockState,
block: &'static Block,
state: &'static BlockState,
_server: &Server,
) {
let mut props = TripwireProperties::from_state_id(state.id, &block);
let mut props = TripwireProperties::from_state_id(state.id, block);
if props.powered {
return;
}
props.powered = true;
let state_id = props.to_state_id(&block);
let state_id = props.to_state_id(block);
world
.set_block_state(&pos, state_id, BlockFlags::NOTIFY_ALL)
.await;
@@ -51,7 +51,7 @@ impl PumpkinBlock for TripwireBlock {
Self::update(world, &pos, state_id).await;
world
.schedule_block_tick(&block, pos, 10, TickPriority::Normal)
.schedule_block_tick(block, pos, 10, TickPriority::Normal)
.await;
}
@@ -115,7 +115,7 @@ impl PumpkinBlock for TripwireBlock {
location: BlockPos,
_server: &Server,
world: Arc<World>,
state: BlockState,
state: &'static BlockState,
) {
let has_shears = {
let main_hand_item_stack = player.inventory().held_item();
@@ -191,8 +191,7 @@ impl PumpkinBlock for TripwireBlock {
old_state_id: BlockStateId,
moved: bool,
) {
if moved || Block::from_state_id(old_state_id).is_some_and(|old_block| old_block == *block)
{
if moved || Block::from_state_id(old_state_id).is_some_and(|old_block| old_block == block) {
return;
}
let state_id = world.get_block_state_id(&location).await;
@@ -207,7 +206,7 @@ impl TripwireBlock {
let current_pos = pos.offset_dir(dir.to_offset(), i);
let (current_block, current_state) =
world.get_block_and_block_state(&current_pos).await;
if current_block == Block::TRIPWIRE_HOOK {
if current_block == &Block::TRIPWIRE_HOOK {
let current_props = TripwireHookProperties::from_state_id(
current_state.id,
&Block::TRIPWIRE_HOOK,
@@ -226,7 +225,7 @@ impl TripwireBlock {
}
break;
}
if current_block != Block::TRIPWIRE {
if current_block != &Block::TRIPWIRE {
break;
}
}
@@ -236,11 +235,11 @@ impl TripwireBlock {
#[must_use]
pub fn should_connect_to(state_id: BlockStateId, facing: BlockDirection) -> bool {
Block::from_state_id(state_id).is_some_and(|block| {
if block == Block::TRIPWIRE_HOOK {
let props = TripwireHookProperties::from_state_id(state_id, &block);
if block == &Block::TRIPWIRE_HOOK {
let props = TripwireHookProperties::from_state_id(state_id, block);
Some(props.facing) == facing.opposite().to_horizontal_facing()
} else {
block == Block::TRIPWIRE
block == &Block::TRIPWIRE
}
})
}

View File

@@ -116,8 +116,7 @@ impl PumpkinBlock for TripwireHookBlock {
old_state_id: BlockStateId,
moved: bool,
) {
if moved || Block::from_state_id(old_state_id).is_some_and(|old_block| old_block == *block)
{
if moved || Block::from_state_id(old_state_id).is_some_and(|old_block| old_block == block) {
return;
}
let props = TripwireHookProperties::from_state_id(old_state_id, block);
@@ -205,7 +204,7 @@ impl TripwireHookBlock {
for k in 1..42 {
let current_pos = start_hook_pos.offset_dir(start_hook_props.facing.to_offset(), k);
let current_block = world.get_block(&current_pos).await;
if current_block == Block::TRIPWIRE_HOOK {
if current_block == &Block::TRIPWIRE_HOOK {
let current_hook_props = {
let state_id = world.get_block_state_id(&current_pos).await;
TripwireHookProperties::from_state_id(state_id, &Block::TRIPWIRE_HOOK)
@@ -215,7 +214,7 @@ impl TripwireHookBlock {
}
break;
}
if current_block == Block::TRIPWIRE || k == raw_wire_index {
if current_block == &Block::TRIPWIRE || k == raw_wire_index {
let current_wire_props = {
let ro_state_id = world.get_block_state_id(&current_pos).await;
let state_id = if k == raw_wire_index {

View File

@@ -32,7 +32,7 @@ struct NodeId {
struct UpdateNode {
pos: BlockPos,
/// The cached state of the block
state: BlockState,
state: &'static BlockState,
/// This will only be `Some` when all the neighbors are identified.
neighbors: Option<Vec<NodeId>>,
visited: bool,
@@ -293,7 +293,7 @@ impl RedstoneWireTurbo {
while !self.update_queue[0].is_empty() || !self.update_queue[1].is_empty() {
for node_id in self.update_queue[0].clone() {
let block = &Block::from_state_id(self.nodes[node_id.index].state.id).unwrap();
let block = Block::from_state_id(self.nodes[node_id.index].state.id).unwrap();
if block == &Block::REDSTONE_WIRE {
self.update_node(world, node_id, self.current_walk_layer)
.await;
@@ -324,13 +324,13 @@ impl RedstoneWireTurbo {
let old_wire = {
let node = &mut self.nodes[upd1.index];
node.visited = true;
unwrap_wire(&node.state)
unwrap_wire(node.state)
};
let new_wire = self.calculate_current_changes(world, upd1).await;
if old_wire.power != new_wire.power {
let node = &mut self.nodes[upd1.index];
let mut wire = unwrap_wire(&node.state);
let mut wire = unwrap_wire(node.state);
wire.power = new_wire.power;
node.state = get_state_by_state_id(wire.to_state_id(&Block::REDSTONE_WIRE)).unwrap();
@@ -347,7 +347,7 @@ impl RedstoneWireTurbo {
world: &Arc<World>,
upd: NodeId,
) -> RedstoneWireProps {
let mut wire = unwrap_wire(&self.nodes[upd.index].state);
let mut wire = unwrap_wire(self.nodes[upd.index].state);
let i = wire.power;
let mut block_power = 0;
@@ -363,7 +363,7 @@ impl RedstoneWireTurbo {
let neighbor = &self.nodes[self.node_cache[&neighbor_pos].index].state;
wire_power = wire_power.max(
get_redstone_power_no_dust(
&Block::from_state_id(neighbor.id).unwrap(),
Block::from_state_id(neighbor.id).unwrap(),
neighbor,
world,
neighbor_pos,
@@ -416,9 +416,9 @@ impl RedstoneWireTurbo {
fn get_max_current_strength(&self, upd: NodeId, strength: u8) -> u8 {
let node = &self.nodes[upd.index];
let block = &Block::from_state_id(node.state.id).unwrap();
let block = Block::from_state_id(node.state.id).unwrap();
if block == &Block::REDSTONE_WIRE {
(unwrap_wire(&node.state).power.to_index() as u8).max(strength)
(unwrap_wire(node.state).power.to_index() as u8).max(strength)
} else {
strength
}

View File

@@ -162,5 +162,5 @@ async fn get_stair_properties_if_exists(
block
.is_tagged_with("#minecraft:stairs")
.unwrap()
.then(|| StairsProperties::from_state_id(block_state.id, &block))
.then(|| StairsProperties::from_state_id(block_state.id, block))
}

Some files were not shown because too many files have changed in this diff Show More