From f734230cd66c651fe33383a4e96b489eaa4f764d Mon Sep 17 00:00:00 2001 From: Alexander Medvedev Date: Sat, 6 Dec 2025 14:31:12 +0100 Subject: [PATCH] chunk-gen: add MatchingFluids BlockPredicate this lets some more things generate, like sugar cane --- pumpkin-data/src/collision_shape.rs | 4 -- pumpkin-world/src/chunk_system.rs | 32 ++++++++++++++++ .../src/generation/block_predicate.rs | 37 ++++++++++++++++++- pumpkin-world/src/generation/proto_chunk.rs | 2 + pumpkin/src/item/items/bucket.rs | 4 +- pumpkin/src/world/mod.rs | 9 ++--- 6 files changed, 75 insertions(+), 13 deletions(-) diff --git a/pumpkin-data/src/collision_shape.rs b/pumpkin-data/src/collision_shape.rs index 66c7403c2..2421283a4 100644 --- a/pumpkin-data/src/collision_shape.rs +++ b/pumpkin-data/src/collision_shape.rs @@ -7,10 +7,6 @@ pub struct CollisionShape { } impl CollisionShape { - pub fn is_empty() -> bool { - unimplemented!() - } - pub fn to_bounding_box(&self) -> BoundingBox { BoundingBox { min: self.min, diff --git a/pumpkin-world/src/chunk_system.rs b/pumpkin-world/src/chunk_system.rs index b523f3987..baa5068ab 100644 --- a/pumpkin-world/src/chunk_system.rs +++ b/pumpkin-world/src/chunk_system.rs @@ -27,6 +27,7 @@ use log::{debug, error}; use num_traits::abs; use pumpkin_data::biome::Biome; +use pumpkin_data::fluid::{Fluid, FluidState}; use pumpkin_data::{Block, BlockState}; use pumpkin_util::HeightMap; use pumpkin_util::math::position::BlockPos; @@ -880,6 +881,37 @@ impl GenerationCache for Cache { self.chunks[mid].get_proto_chunk_mut() } + fn get_fluid_and_fluid_state(&self, pos: &Vector3) -> (Fluid, FluidState) { + let id = GenerationCache::get_block_state(self, pos).0; + + let Some(fluid) = Fluid::from_state_id(id) else { + let block = Block::from_state_id(id); + if let Some(properties) = block.properties(id) { + for (name, value) in properties.to_props() { + if name == "waterlogged" { + if value == "true" { + let fluid = Fluid::FLOWING_WATER; + let state = fluid.states[0].clone(); + return (fluid, state); + } + + break; + } + } + } + + let fluid = Fluid::EMPTY; + let state = fluid.states[0].clone(); + + return (fluid, state); + }; + + //let state = fluid.get_state(id); + let state = fluid.states[0].clone(); + + (fluid.clone(), state) + } + fn get_block_state(&self, pos: &Vector3) -> RawBlockState { let dx = (pos.x >> 4) - self.x; let dz = (pos.z >> 4) - self.y; diff --git a/pumpkin-world/src/generation/block_predicate.rs b/pumpkin-world/src/generation/block_predicate.rs index d04693d78..ac22c9ab8 100644 --- a/pumpkin-world/src/generation/block_predicate.rs +++ b/pumpkin-world/src/generation/block_predicate.rs @@ -1,4 +1,5 @@ use itertools::Itertools; +use pumpkin_data::fluid::{Fluid, FluidState}; use pumpkin_data::{Block, BlockDirection, BlockState, tag::Taggable}; use pumpkin_util::math::{position::BlockPos, vector3::Vector3}; use serde::Deserialize; @@ -17,7 +18,7 @@ pub enum BlockPredicate { #[serde(rename = "minecraft:matching_block_tag")] MatchingBlockTag(MatchingBlockTagPredicate), #[serde(rename = "minecraft:matching_fluids")] - MatchingFluids(EmptyTODOStruct), + MatchingFluids(MatchingFluidsBlockPredicate), #[serde(rename = "minecraft:has_sturdy_face")] HasSturdyFace(HasSturdyFacePredicate), #[serde(rename = "minecraft:solid")] @@ -51,7 +52,7 @@ impl BlockPredicate { match self { BlockPredicate::MatchingBlocks(predicate) => predicate.test(chunk, pos), BlockPredicate::MatchingBlockTag(predicate) => predicate.test(chunk, pos), - BlockPredicate::MatchingFluids(_predicate) => false, + BlockPredicate::MatchingFluids(predicate) => predicate.test(chunk, pos), BlockPredicate::HasSturdyFace(predicate) => predicate.test(chunk, pos), BlockPredicate::Solid(predicate) => predicate.test(chunk, pos), BlockPredicate::Replaceable(predicate) => predicate.test(chunk, pos), @@ -100,6 +101,28 @@ impl InsideWorldBoundsBlockPredicate { } } +#[derive(Deserialize)] +pub struct MatchingFluidsBlockPredicate { + #[serde(flatten)] + offset: OffsetBlocksBlockPredicate, + fluids: MatchingBlocksWrapper, +} + +impl MatchingFluidsBlockPredicate { + pub fn test(&self, chunk: &T, pos: &BlockPos) -> bool { + let (fluid, _) = self.offset.get_fluid_and_fluid_state(chunk, pos); + match &self.fluids { + MatchingBlocksWrapper::Single(single_block) => { + single_block.strip_prefix("minecraft:").unwrap() == fluid.name + } + MatchingBlocksWrapper::Multiple(blocks) => blocks + .iter() + .map(|s| s.strip_prefix("minecraft:").unwrap()) + .contains(fluid.name), + } + } +} + #[derive(Deserialize)] pub struct MatchingBlockTagPredicate { #[serde(flatten)] @@ -250,6 +273,16 @@ impl OffsetBlocksBlockPredicate { let pos = self.get(pos); GenerationCache::get_block_state(chunk, &pos.0).to_block() } + + pub fn get_fluid_and_fluid_state( + &self, + chunk: &T, + pos: &BlockPos, + ) -> (Fluid, FluidState) { + let pos = self.get(pos); + GenerationCache::get_fluid_and_fluid_state(chunk, &pos.0) + } + pub fn get_state(&self, chunk: &T, pos: &BlockPos) -> &'static BlockState { let pos = self.get(pos); GenerationCache::get_block_state(chunk, &pos.0).to_state() diff --git a/pumpkin-world/src/generation/proto_chunk.rs b/pumpkin-world/src/generation/proto_chunk.rs index 501046a66..ea2875278 100644 --- a/pumpkin-world/src/generation/proto_chunk.rs +++ b/pumpkin-world/src/generation/proto_chunk.rs @@ -1,6 +1,7 @@ use std::collections::HashMap; use std::pin::Pin; +use pumpkin_data::fluid::{Fluid, FluidState}; use pumpkin_data::tag; use pumpkin_data::{ Block, BlockState, block_properties::blocks_movement, chunk::Biome, tag::Taggable, @@ -48,6 +49,7 @@ use crate::{ pub trait GenerationCache: HeightLimitView + BlockAccessor { fn get_center_chunk_mut(&mut self) -> &mut ProtoChunk; fn get_block_state(&self, pos: &Vector3) -> RawBlockState; + fn get_fluid_and_fluid_state(&self, position: &Vector3) -> (Fluid, FluidState); fn set_block_state(&mut self, pos: &Vector3, block_state: &BlockState); fn top_motion_blocking_block_height_exclusive(&self, pos: &Vector2) -> i32; fn top_motion_blocking_block_no_leaves_height_exclusive(&self, pos: &Vector2) -> i32; diff --git a/pumpkin/src/item/items/bucket.rs b/pumpkin/src/item/items/bucket.rs index afc75c79c..c39a77500 100644 --- a/pumpkin/src/item/items/bucket.rs +++ b/pumpkin/src/item/items/bucket.rs @@ -73,7 +73,7 @@ fn waterlogged_check(block: &Block, state: u16) -> Option { .to_props() .into_iter() .find(|p| p.0 == "waterlogged") - .map(|(_, value)| value == true.to_string()) + .map(|(_, value)| value == "true") }) } @@ -131,7 +131,7 @@ impl ItemBehaviour for EmptyBucketItem { .to_props() .into_iter() .find(|p| p.0 == "waterlogged") - .map(|(_, value)| value == true.to_string()) + .map(|(_, value)| value == "true") }) .unwrap_or(false) { diff --git a/pumpkin/src/world/mod.rs b/pumpkin/src/world/mod.rs index d165612d2..8001c0d30 100644 --- a/pumpkin/src/world/mod.rs +++ b/pumpkin/src/world/mod.rs @@ -2722,7 +2722,7 @@ impl World { .to_props() .into_iter() .find(|p| p.0 == "waterlogged") - .map(|(_, value)| value == true.to_string()) + .map(|(_, value)| value == "true") }) .unwrap_or(false) { @@ -2867,7 +2867,7 @@ impl World { .into_iter() .find(|p| p.0 == "waterlogged") .map(|(_, value)| { - if value == true.to_string() { + if value == "true" { &Fluid::FLOWING_WATER } else { &Fluid::EMPTY @@ -2898,7 +2898,7 @@ impl World { .into_iter() .find(|p| p.0 == "waterlogged") .map(|(_, value)| { - if value == true.to_string() { + if value == "true" { &Fluid::FLOWING_WATER } else { &Fluid::EMPTY @@ -2918,7 +2918,7 @@ impl World { if let Some(properties) = block.properties(id) { for (name, value) in properties.to_props() { if name == "waterlogged" { - if value == true.to_string() { + if value == "true" { let fluid = Fluid::FLOWING_WATER; let state = fluid.states[0].clone(); return (fluid, state); @@ -2930,7 +2930,6 @@ impl World { } let fluid = Fluid::EMPTY; - let state = fluid.states[0].clone(); return (fluid, state);