chunk-gen: add MatchingFluids BlockPredicate

this lets some more things generate, like sugar cane
This commit is contained in:
Alexander Medvedev 2025-12-06 14:31:12 +01:00
parent dbdbc04eb4
commit f734230cd6
6 changed files with 75 additions and 13 deletions

View File

@ -7,10 +7,6 @@ pub struct CollisionShape {
} }
impl CollisionShape { impl CollisionShape {
pub fn is_empty() -> bool {
unimplemented!()
}
pub fn to_bounding_box(&self) -> BoundingBox { pub fn to_bounding_box(&self) -> BoundingBox {
BoundingBox { BoundingBox {
min: self.min, min: self.min,

View File

@ -27,6 +27,7 @@ use log::{debug, error};
use num_traits::abs; use num_traits::abs;
use pumpkin_data::biome::Biome; use pumpkin_data::biome::Biome;
use pumpkin_data::fluid::{Fluid, FluidState};
use pumpkin_data::{Block, BlockState}; use pumpkin_data::{Block, BlockState};
use pumpkin_util::HeightMap; use pumpkin_util::HeightMap;
use pumpkin_util::math::position::BlockPos; use pumpkin_util::math::position::BlockPos;
@ -880,6 +881,37 @@ impl GenerationCache for Cache {
self.chunks[mid].get_proto_chunk_mut() self.chunks[mid].get_proto_chunk_mut()
} }
fn get_fluid_and_fluid_state(&self, pos: &Vector3<i32>) -> (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<i32>) -> RawBlockState { fn get_block_state(&self, pos: &Vector3<i32>) -> RawBlockState {
let dx = (pos.x >> 4) - self.x; let dx = (pos.x >> 4) - self.x;
let dz = (pos.z >> 4) - self.y; let dz = (pos.z >> 4) - self.y;

View File

@ -1,4 +1,5 @@
use itertools::Itertools; use itertools::Itertools;
use pumpkin_data::fluid::{Fluid, FluidState};
use pumpkin_data::{Block, BlockDirection, BlockState, tag::Taggable}; use pumpkin_data::{Block, BlockDirection, BlockState, tag::Taggable};
use pumpkin_util::math::{position::BlockPos, vector3::Vector3}; use pumpkin_util::math::{position::BlockPos, vector3::Vector3};
use serde::Deserialize; use serde::Deserialize;
@ -17,7 +18,7 @@ pub enum BlockPredicate {
#[serde(rename = "minecraft:matching_block_tag")] #[serde(rename = "minecraft:matching_block_tag")]
MatchingBlockTag(MatchingBlockTagPredicate), MatchingBlockTag(MatchingBlockTagPredicate),
#[serde(rename = "minecraft:matching_fluids")] #[serde(rename = "minecraft:matching_fluids")]
MatchingFluids(EmptyTODOStruct), MatchingFluids(MatchingFluidsBlockPredicate),
#[serde(rename = "minecraft:has_sturdy_face")] #[serde(rename = "minecraft:has_sturdy_face")]
HasSturdyFace(HasSturdyFacePredicate), HasSturdyFace(HasSturdyFacePredicate),
#[serde(rename = "minecraft:solid")] #[serde(rename = "minecraft:solid")]
@ -51,7 +52,7 @@ impl BlockPredicate {
match self { match self {
BlockPredicate::MatchingBlocks(predicate) => predicate.test(chunk, pos), BlockPredicate::MatchingBlocks(predicate) => predicate.test(chunk, pos),
BlockPredicate::MatchingBlockTag(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::HasSturdyFace(predicate) => predicate.test(chunk, pos),
BlockPredicate::Solid(predicate) => predicate.test(chunk, pos), BlockPredicate::Solid(predicate) => predicate.test(chunk, pos),
BlockPredicate::Replaceable(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<T: GenerationCache>(&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)] #[derive(Deserialize)]
pub struct MatchingBlockTagPredicate { pub struct MatchingBlockTagPredicate {
#[serde(flatten)] #[serde(flatten)]
@ -250,6 +273,16 @@ impl OffsetBlocksBlockPredicate {
let pos = self.get(pos); let pos = self.get(pos);
GenerationCache::get_block_state(chunk, &pos.0).to_block() GenerationCache::get_block_state(chunk, &pos.0).to_block()
} }
pub fn get_fluid_and_fluid_state<T: GenerationCache>(
&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<T: GenerationCache>(&self, chunk: &T, pos: &BlockPos) -> &'static BlockState { pub fn get_state<T: GenerationCache>(&self, chunk: &T, pos: &BlockPos) -> &'static BlockState {
let pos = self.get(pos); let pos = self.get(pos);
GenerationCache::get_block_state(chunk, &pos.0).to_state() GenerationCache::get_block_state(chunk, &pos.0).to_state()

View File

@ -1,6 +1,7 @@
use std::collections::HashMap; use std::collections::HashMap;
use std::pin::Pin; use std::pin::Pin;
use pumpkin_data::fluid::{Fluid, FluidState};
use pumpkin_data::tag; use pumpkin_data::tag;
use pumpkin_data::{ use pumpkin_data::{
Block, BlockState, block_properties::blocks_movement, chunk::Biome, tag::Taggable, Block, BlockState, block_properties::blocks_movement, chunk::Biome, tag::Taggable,
@ -48,6 +49,7 @@ use crate::{
pub trait GenerationCache: HeightLimitView + BlockAccessor { pub trait GenerationCache: HeightLimitView + BlockAccessor {
fn get_center_chunk_mut(&mut self) -> &mut ProtoChunk; fn get_center_chunk_mut(&mut self) -> &mut ProtoChunk;
fn get_block_state(&self, pos: &Vector3<i32>) -> RawBlockState; fn get_block_state(&self, pos: &Vector3<i32>) -> RawBlockState;
fn get_fluid_and_fluid_state(&self, position: &Vector3<i32>) -> (Fluid, FluidState);
fn set_block_state(&mut self, pos: &Vector3<i32>, block_state: &BlockState); fn set_block_state(&mut self, pos: &Vector3<i32>, block_state: &BlockState);
fn top_motion_blocking_block_height_exclusive(&self, pos: &Vector2<i32>) -> i32; fn top_motion_blocking_block_height_exclusive(&self, pos: &Vector2<i32>) -> i32;
fn top_motion_blocking_block_no_leaves_height_exclusive(&self, pos: &Vector2<i32>) -> i32; fn top_motion_blocking_block_no_leaves_height_exclusive(&self, pos: &Vector2<i32>) -> i32;

View File

@ -73,7 +73,7 @@ fn waterlogged_check(block: &Block, state: u16) -> Option<bool> {
.to_props() .to_props()
.into_iter() .into_iter()
.find(|p| p.0 == "waterlogged") .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() .to_props()
.into_iter() .into_iter()
.find(|p| p.0 == "waterlogged") .find(|p| p.0 == "waterlogged")
.map(|(_, value)| value == true.to_string()) .map(|(_, value)| value == "true")
}) })
.unwrap_or(false) .unwrap_or(false)
{ {

View File

@ -2722,7 +2722,7 @@ impl World {
.to_props() .to_props()
.into_iter() .into_iter()
.find(|p| p.0 == "waterlogged") .find(|p| p.0 == "waterlogged")
.map(|(_, value)| value == true.to_string()) .map(|(_, value)| value == "true")
}) })
.unwrap_or(false) .unwrap_or(false)
{ {
@ -2867,7 +2867,7 @@ impl World {
.into_iter() .into_iter()
.find(|p| p.0 == "waterlogged") .find(|p| p.0 == "waterlogged")
.map(|(_, value)| { .map(|(_, value)| {
if value == true.to_string() { if value == "true" {
&Fluid::FLOWING_WATER &Fluid::FLOWING_WATER
} else { } else {
&Fluid::EMPTY &Fluid::EMPTY
@ -2898,7 +2898,7 @@ impl World {
.into_iter() .into_iter()
.find(|p| p.0 == "waterlogged") .find(|p| p.0 == "waterlogged")
.map(|(_, value)| { .map(|(_, value)| {
if value == true.to_string() { if value == "true" {
&Fluid::FLOWING_WATER &Fluid::FLOWING_WATER
} else { } else {
&Fluid::EMPTY &Fluid::EMPTY
@ -2918,7 +2918,7 @@ impl World {
if let Some(properties) = block.properties(id) { if let Some(properties) = block.properties(id) {
for (name, value) in properties.to_props() { for (name, value) in properties.to_props() {
if name == "waterlogged" { if name == "waterlogged" {
if value == true.to_string() { if value == "true" {
let fluid = Fluid::FLOWING_WATER; let fluid = Fluid::FLOWING_WATER;
let state = fluid.states[0].clone(); let state = fluid.states[0].clone();
return (fluid, state); return (fluid, state);
@ -2930,7 +2930,6 @@ impl World {
} }
let fluid = Fluid::EMPTY; let fluid = Fluid::EMPTY;
let state = fluid.states[0].clone(); let state = fluid.states[0].clone();
return (fluid, state); return (fluid, state);