mirror of
https://github.com/Pumpkin-MC/Pumpkin.git
synced 2026-08-30 20:14:23 +00:00
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:
67
Cargo.lock
generated
67
Cargo.lock
generated
@@ -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"
|
||||
|
||||
@@ -19,7 +19,7 @@ edition = "2024"
|
||||
|
||||
|
||||
[profile.dev]
|
||||
opt-level = 0
|
||||
#opt-level = 0
|
||||
|
||||
[profile.release]
|
||||
lto = true
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
|
||||
@@ -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>,
|
||||
|
||||
@@ -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| {
|
||||
|
||||
@@ -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
|
||||
83
pumpkin-world/benches/chunk_gen.rs
Normal file
83
pumpkin-world/benches/chunk_gen.rs
Normal 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);
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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(),
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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!(
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -389,7 +389,7 @@ impl CountOnEveryLayerPlacementModifier {
|
||||
|
||||
if !Self::blocks_spawn(&next_block_state)
|
||||
&& Self::blocks_spawn(¤t_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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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(¤t_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
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@@ -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(¤t_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(¤t_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(¤t_pos).await;
|
||||
let state_id = if k == raw_wire_index {
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user