add gourds (#1090)

* add gourds

* fix

* Update stem.rs
This commit is contained in:
teknostom
2025-07-30 14:10:15 +02:00
committed by GitHub
parent 6e7b56abc5
commit d8d6676008
6 changed files with 227 additions and 0 deletions

View File

@@ -0,0 +1,85 @@
use async_trait::async_trait;
use pumpkin_data::{
Block,
block_properties::{
BlockProperties, EnumVariants, Integer0To7, WallTorchLikeProperties, WheatLikeProperties,
},
};
use pumpkin_util::math::position::BlockPos;
use pumpkin_world::{BlockStateId, world::BlockAccessor};
use crate::block::{
BlockBehaviour, BlockMetadata, CanPlaceAtArgs, GetStateForNeighborUpdateArgs,
blocks::plant::PlantBlockBase,
};
type AttachedStemProperties = WallTorchLikeProperties;
type StemProperties = WheatLikeProperties;
pub struct AttachedStemBlock;
impl BlockMetadata for AttachedStemBlock {
fn namespace(&self) -> &'static str {
"minecraft"
}
fn ids(&self) -> &'static [&'static str] {
&[
Block::ATTACHED_PUMPKIN_STEM.name,
Block::ATTACHED_MELON_STEM.name,
]
}
}
impl AttachedStemBlock {
fn get_stem(block: &Block) -> &Block {
match block.id {
id if id == Block::ATTACHED_PUMPKIN_STEM.id => &Block::PUMPKIN_STEM,
id if id == Block::ATTACHED_MELON_STEM.id => &Block::MELON_STEM,
_ => &Block::MELON_STEM, // Should never happen
}
}
fn get_gourd(block: &Block) -> &Block {
match block.id {
id if id == Block::ATTACHED_PUMPKIN_STEM.id => &Block::PUMPKIN,
id if id == Block::ATTACHED_MELON_STEM.id => &Block::MELON,
_ => &Block::MELON, // Should never happen
}
}
}
#[async_trait]
impl BlockBehaviour for AttachedStemBlock {
async fn can_place_at(&self, args: CanPlaceAtArgs<'_>) -> bool {
<Self as PlantBlockBase>::can_place_at(self, args.block_accessor, args.position).await
}
async fn get_state_for_neighbor_update(
&self,
args: GetStateForNeighborUpdateArgs<'_>,
) -> BlockStateId {
let props = AttachedStemProperties::from_state_id(args.state_id, args.block);
if args.direction.to_horizontal_facing() == Some(props.facing)
&& args.neighbor_state_id != Self::get_gourd(args.block).default_state.id
{
let mut props = StemProperties::default(Self::get_stem(args.block));
props.age = Integer0To7::from_index(7);
return props.to_state_id(Self::get_stem(args.block));
}
<Self as PlantBlockBase>::get_state_for_neighbor_update(
self,
args.world,
args.position,
args.state_id,
)
.await
}
}
impl PlantBlockBase for AttachedStemBlock {
async fn can_plant_on_top(&self, block_accessor: &dyn BlockAccessor, pos: &BlockPos) -> bool {
let block = block_accessor.get_block(pos).await;
block == &Block::FARMLAND
}
}

View File

@@ -0,0 +1,2 @@
pub mod attached_stem;
pub mod stem;

View File

@@ -0,0 +1,134 @@
use crate::block::{
BlockBehaviour, BlockMetadata, CanPlaceAtArgs, GetStateForNeighborUpdateArgs, RandomTickArgs,
blocks::plant::PlantBlockBase,
};
use async_trait::async_trait;
use pumpkin_data::{
Block, BlockDirection,
block_properties::{
BlockProperties, EnumVariants, Integer0To7, WallTorchLikeProperties, WheatLikeProperties,
},
tag,
tag::Taggable,
};
use pumpkin_util::{
math::position::BlockPos,
random::{RandomGenerator, xoroshiro128::Xoroshiro},
};
use pumpkin_world::{
BlockStateId,
world::{BlockAccessor, BlockFlags},
};
use rand::Rng;
type StemProperties = WheatLikeProperties;
type AttachedStemProperties = WallTorchLikeProperties;
pub struct StemBlock;
impl BlockMetadata for StemBlock {
fn namespace(&self) -> &'static str {
"minecraft"
}
fn ids(&self) -> &'static [&'static str] {
&[Block::PUMPKIN_STEM.name, Block::MELON_STEM.name]
}
}
impl StemBlock {
fn state_with_age(block: &Block, state: u16, age: i32) -> BlockStateId {
let mut props = StemProperties::from_state_id(state, block);
props.age = Integer0To7::from_index(age as u16);
props.to_state_id(block)
}
fn get_attached_stem(dir: BlockDirection, block: &Block) -> BlockStateId {
let attached_block = match block.id {
id if id == Block::PUMPKIN_STEM.id => &Block::ATTACHED_PUMPKIN_STEM,
id if id == Block::MELON_STEM.id => &Block::ATTACHED_MELON_STEM,
_ => &Block::ATTACHED_MELON_STEM, // Should never happen
};
let mut props = AttachedStemProperties::default(attached_block);
props.facing = dir.to_horizontal_facing().unwrap();
props.to_state_id(attached_block)
}
fn get_gourd(block: &Block) -> &Block {
match block.id {
id if id == Block::PUMPKIN_STEM.id => &Block::PUMPKIN,
id if id == Block::MELON_STEM.id => &Block::MELON,
_ => &Block::MELON, // Should never happen
}
}
}
#[async_trait]
impl BlockBehaviour for StemBlock {
async fn can_place_at(&self, args: CanPlaceAtArgs<'_>) -> bool {
<Self as PlantBlockBase>::can_place_at(self, args.block_accessor, args.position).await
}
async fn get_state_for_neighbor_update(
&self,
args: GetStateForNeighborUpdateArgs<'_>,
) -> BlockStateId {
<Self as PlantBlockBase>::get_state_for_neighbor_update(
self,
args.world,
args.position,
args.state_id,
)
.await
}
async fn random_tick(&self, args: RandomTickArgs<'_>) {
// TODO add light level and moisture check
let f = 5;
if rand::rng().random_range(0..=(25 / f)) == 0 {
let (block, state) = args.world.get_block_and_state_id(args.position).await;
let props = StemProperties::from_state_id(state, block);
let age = i32::from(props.age.to_index());
if age < 7 {
args.world
.set_block_state(
args.position,
Self::state_with_age(block, state, age + 1),
BlockFlags::NOTIFY_NEIGHBORS,
)
.await;
} else {
let dir = BlockDirection::random_horizontal(&mut RandomGenerator::Xoroshiro(
Xoroshiro::from_seed(rand::rng().random()),
));
let plant_block_pos = args.position.offset(dir.to_offset());
let plant_block_state = args.world.get_block_state(&plant_block_pos).await;
let under_block: &Block = args.world.get_block(&plant_block_pos.down()).await;
if plant_block_state.is_air()
&& (under_block == &Block::FARMLAND
|| under_block.is_tagged_with_by_tag(&tag::Block::MINECRAFT_DIRT))
{
let attached_stem = Self::get_attached_stem(dir, block);
let gourd = Self::get_gourd(block);
args.world
.set_block_state(
&plant_block_pos,
gourd.default_state.id,
BlockFlags::NOTIFY_NEIGHBORS,
)
.await;
args.world
.set_block_state(args.position, attached_stem, BlockFlags::NOTIFY_NEIGHBORS)
.await;
}
}
}
}
}
impl PlantBlockBase for StemBlock {
async fn can_plant_on_top(&self, block_accessor: &dyn BlockAccessor, pos: &BlockPos) -> bool {
let block = block_accessor.get_block(pos).await;
block == &Block::FARMLAND
}
}

View File

@@ -7,6 +7,7 @@ pub mod crop;
pub mod dry_vegetation;
pub mod flower;
pub mod flowerbed;
pub mod gourds;
pub mod leaf_litter;
pub mod lily_pad;
pub mod mushroom_plant;

View File

@@ -267,6 +267,7 @@ pub trait FlowingFluid {
return true;
}
//TODO check if source
if self.is_same_fluid(fluid, state_id) {
let props = FlowingFluidProperties::from_state_id(state_id, fluid);
return props.level == Level::L8 && props.falling != Falling::True;

View File

@@ -107,6 +107,8 @@ use crate::block::blocks::redstone::dispenser::DispenserBlock;
use crate::block::blocks::redstone::dropper::DropperBlock;
use super::BlockIsReplacing;
use super::blocks::plant::gourds::attached_stem::AttachedStemBlock;
use super::blocks::plant::gourds::stem::StemBlock;
use super::fluid::FluidBehaviour;
use super::{
BrokenArgs, CanPlaceAtArgs, CanUpdateAtArgs, EmitsRedstonePowerArgs, ExplodeArgs,
@@ -201,6 +203,8 @@ pub fn default_registry() -> Arc<BlockRegistry> {
manager.register(SkullBlock);
manager.register(ChiseledBookshelfBlock);
manager.register(LecternBlock);
manager.register(StemBlock);
manager.register(AttachedStemBlock);
// Fire
manager.register(SoulFireBlock);