implement sugar cane
it currently does not grow because random ticks are not implemented, but now it checks if it can be placed and is destroyed correctly when broken
This commit is contained in:
parent
2c63a5bd00
commit
9e8b76d6de
@ -47,7 +47,7 @@ pub struct Level {
|
||||
|
||||
// Chunks that are paired with chunk watchers. When a chunk is no longer watched, it is removed
|
||||
// from the loaded chunks map and sent to the underlying ChunkIO
|
||||
loaded_chunks: Arc<DashMap<Vector2<i32>, SyncChunk>>,
|
||||
pub loaded_chunks: Arc<DashMap<Vector2<i32>, SyncChunk>>,
|
||||
chunk_watchers: Arc<DashMap<Vector2<i32>, usize>>,
|
||||
|
||||
chunk_saver: Arc<dyn ChunkIO<Data = SyncChunk>>,
|
||||
@ -530,15 +530,17 @@ impl Level {
|
||||
pub async fn get_and_tick_block_ticks(&self) -> Vec<ScheduledTick> {
|
||||
let mut block_ticks = self.block_ticks.lock().await;
|
||||
let mut ticks = Vec::new();
|
||||
block_ticks.retain_mut(|tick| {
|
||||
let mut remaining_ticks = Vec::new();
|
||||
for mut tick in block_ticks.drain(..) {
|
||||
tick.delay = tick.delay.saturating_sub(1);
|
||||
if tick.delay == 0 {
|
||||
ticks.push(tick.clone());
|
||||
false
|
||||
ticks.push(tick);
|
||||
} else {
|
||||
true
|
||||
remaining_ticks.push(tick);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
*block_ticks = remaining_ticks;
|
||||
ticks.sort_by_key(|tick| tick.priority);
|
||||
ticks
|
||||
}
|
||||
@ -553,13 +555,13 @@ impl Level {
|
||||
pub async fn schedule_block_tick(
|
||||
&self,
|
||||
block_id: u16,
|
||||
block_pos: &BlockPos,
|
||||
block_pos: BlockPos,
|
||||
delay: u16,
|
||||
priority: TickPriority,
|
||||
) {
|
||||
let mut block_ticks = self.block_ticks.lock().await;
|
||||
block_ticks.push(ScheduledTick {
|
||||
block_pos: *block_pos,
|
||||
block_pos,
|
||||
delay,
|
||||
priority,
|
||||
target_block_id: block_id,
|
||||
|
||||
@ -14,6 +14,7 @@ pub(crate) mod furnace;
|
||||
pub(crate) mod jukebox;
|
||||
pub(crate) mod logs;
|
||||
pub(crate) mod redstone;
|
||||
pub(crate) mod sugar_cane;
|
||||
pub(crate) mod tnt;
|
||||
pub(crate) mod torches;
|
||||
/// The standard destroy with container removes the player forcibly from the container,
|
||||
|
||||
94
pumpkin/src/block/blocks/sugar_cane.rs
Normal file
94
pumpkin/src/block/blocks/sugar_cane.rs
Normal file
@ -0,0 +1,94 @@
|
||||
use async_trait::async_trait;
|
||||
use pumpkin_data::block::{
|
||||
Block, BlockProperties, CactusLikeProperties, EnumVariants, Integer0To15,
|
||||
};
|
||||
use pumpkin_macros::pumpkin_block;
|
||||
use pumpkin_world::block::BlockDirection;
|
||||
use pumpkin_world::chunk::TickPriority;
|
||||
|
||||
use crate::block::pumpkin_block::PumpkinBlock;
|
||||
use crate::world::BlockFlags;
|
||||
use crate::world::World;
|
||||
use pumpkin_util::math::position::BlockPos;
|
||||
|
||||
#[pumpkin_block("minecraft:sugar_cane")]
|
||||
pub struct SugarCaneBlock;
|
||||
|
||||
#[async_trait]
|
||||
impl PumpkinBlock for SugarCaneBlock {
|
||||
async fn on_scheduled_tick(&self, world: &World, _block: &Block, pos: &BlockPos) {
|
||||
if !self.can_place_at(world, pos).await {
|
||||
// TODO: break the block so it drops loot, but for this an &Arc<World> is required
|
||||
world.set_block_state(pos, 0, BlockFlags::empty()).await;
|
||||
}
|
||||
}
|
||||
|
||||
async fn random_tick(&self, block: &Block, world: &World, pos: &BlockPos) {
|
||||
if world.get_block_state(&pos.up()).await.unwrap().air {
|
||||
let state_id = world
|
||||
.get_block_state(pos)
|
||||
.await
|
||||
.expect("`location` should be a sugar cane")
|
||||
.id;
|
||||
let age = CactusLikeProperties::from_state_id(state_id, block).age;
|
||||
if age == Integer0To15::L15 {
|
||||
world
|
||||
.set_block_state(&pos.up(), state_id, BlockFlags::empty())
|
||||
.await;
|
||||
let props = CactusLikeProperties {
|
||||
age: Integer0To15::L0,
|
||||
};
|
||||
world
|
||||
.set_block_state(pos, props.to_state_id(block), BlockFlags::empty())
|
||||
.await;
|
||||
} else {
|
||||
let props = CactusLikeProperties {
|
||||
age: Integer0To15::from_index(age.to_index() + 1),
|
||||
};
|
||||
world
|
||||
.set_block_state(pos, props.to_state_id(block), BlockFlags::empty())
|
||||
.await;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async fn get_state_for_neighbor_update(
|
||||
&self,
|
||||
world: &World,
|
||||
block: &Block,
|
||||
state: u16,
|
||||
pos: &BlockPos,
|
||||
_direction: &BlockDirection,
|
||||
_neighbor_pos: &BlockPos,
|
||||
_neighbor_state: u16,
|
||||
) -> u16 {
|
||||
if !self.can_place_at(world, pos).await {
|
||||
world
|
||||
.schedule_block_tick(block, *pos, 1, TickPriority::Normal)
|
||||
.await;
|
||||
}
|
||||
state
|
||||
}
|
||||
|
||||
async fn can_place_at(&self, world: &World, pos: &BlockPos) -> bool {
|
||||
let block = world.get_block(&pos.down()).await.unwrap();
|
||||
|
||||
if block == Block::SUGAR_CANE {
|
||||
return true;
|
||||
}
|
||||
|
||||
// TODO: use tags
|
||||
if block == Block::DIRT || block == Block::SAND {
|
||||
for direction in BlockDirection::horizontal() {
|
||||
let block = world
|
||||
.get_block(&pos.down().offset(direction.to_offset()))
|
||||
.await
|
||||
.unwrap();
|
||||
if block == Block::WATER {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
}
|
||||
@ -11,6 +11,7 @@ use blocks::redstone::redstone_torch::register_redstone_torch_blocks;
|
||||
use blocks::redstone::redstone_wire::RedstoneWireBlock;
|
||||
use blocks::redstone::repeater::RepeaterBlock;
|
||||
use blocks::redstone::target_block::TargetBlock;
|
||||
use blocks::sugar_cane::SugarCaneBlock;
|
||||
use blocks::torches::register_torch_blocks;
|
||||
use blocks::{
|
||||
chest::ChestBlock, furnace::FurnaceBlock, redstone::lever::LeverBlock, tnt::TNTBlock,
|
||||
@ -42,6 +43,7 @@ pub fn default_registry() -> Arc<BlockRegistry> {
|
||||
let mut manager = BlockRegistry::default();
|
||||
|
||||
manager.register(JukeboxBlock);
|
||||
manager.register(SugarCaneBlock);
|
||||
manager.register(CraftingTableBlock);
|
||||
manager.register(FurnaceBlock);
|
||||
manager.register(ChestBlock);
|
||||
|
||||
@ -62,7 +62,9 @@ pub trait PumpkinBlock: Send + Sync {
|
||||
block.default_state_id
|
||||
}
|
||||
|
||||
async fn can_place_at(&self, _world: &World, _block_pos: &BlockPos) -> bool {
|
||||
async fn random_tick(&self, _block: &Block, _world: &World, _pos: &BlockPos) {}
|
||||
|
||||
async fn can_place_at(&self, _world: &World, _pos: &BlockPos) -> bool {
|
||||
true
|
||||
}
|
||||
|
||||
@ -72,7 +74,7 @@ pub trait PumpkinBlock: Send + Sync {
|
||||
_world: &World,
|
||||
_block: &Block,
|
||||
_state_id: u16,
|
||||
_block_pos: &BlockPos,
|
||||
_pos: &BlockPos,
|
||||
_old_state_id: u16,
|
||||
_notify: bool,
|
||||
) {
|
||||
@ -103,7 +105,7 @@ pub trait PumpkinBlock: Send + Sync {
|
||||
&self,
|
||||
_world: &World,
|
||||
_block: &Block,
|
||||
_block_pos: &BlockPos,
|
||||
_pos: &BlockPos,
|
||||
_source_block: &Block,
|
||||
_notify: bool,
|
||||
) {
|
||||
@ -113,7 +115,7 @@ pub trait PumpkinBlock: Send + Sync {
|
||||
async fn prepare(
|
||||
&self,
|
||||
_world: &World,
|
||||
_block_pos: &BlockPos,
|
||||
_pos: &BlockPos,
|
||||
_block: &Block,
|
||||
_state_id: u16,
|
||||
_flags: BlockFlags,
|
||||
@ -126,7 +128,7 @@ pub trait PumpkinBlock: Send + Sync {
|
||||
_world: &World,
|
||||
_block: &Block,
|
||||
state: u16,
|
||||
_block_pos: &BlockPos,
|
||||
_pos: &BlockPos,
|
||||
_direction: &BlockDirection,
|
||||
_neighbor_pos: &BlockPos,
|
||||
_neighbor_state: u16,
|
||||
@ -134,7 +136,7 @@ pub trait PumpkinBlock: Send + Sync {
|
||||
state
|
||||
}
|
||||
|
||||
async fn on_scheduled_tick(&self, _world: &World, _block: &Block, _block_pos: &BlockPos) {}
|
||||
async fn on_scheduled_tick(&self, _world: &World, _block: &Block, _pos: &BlockPos) {}
|
||||
|
||||
async fn on_state_replaced(
|
||||
&self,
|
||||
@ -161,7 +163,7 @@ pub trait PumpkinBlock: Send + Sync {
|
||||
&self,
|
||||
_block: &Block,
|
||||
_world: &World,
|
||||
_block_pos: &BlockPos,
|
||||
_pos: &BlockPos,
|
||||
_state: &BlockState,
|
||||
_direction: &BlockDirection,
|
||||
) -> u8 {
|
||||
@ -173,7 +175,7 @@ pub trait PumpkinBlock: Send + Sync {
|
||||
&self,
|
||||
_block: &Block,
|
||||
_world: &World,
|
||||
_block_pos: &BlockPos,
|
||||
_pos: &BlockPos,
|
||||
_state: &BlockState,
|
||||
_direction: &BlockDirection,
|
||||
) -> u8 {
|
||||
|
||||
@ -1158,15 +1158,9 @@ impl World {
|
||||
block_state_id: u16,
|
||||
flags: BlockFlags,
|
||||
) -> u16 {
|
||||
let (chunk_coordinate, relative_coordinates) = position.chunk_and_chunk_relative_position();
|
||||
|
||||
// Since we divide by 16, remnant can never exceed `u8::MAX`
|
||||
let relative = ChunkRelativeBlockCoordinates::from(relative_coordinates);
|
||||
|
||||
let chunk = match self.level.try_get_chunk(chunk_coordinate) {
|
||||
Some(chunk) => chunk.clone(),
|
||||
None => self.receive_chunk(chunk_coordinate).await.0,
|
||||
};
|
||||
let chunk = self.get_chunk(position).await;
|
||||
let (_, relative) = position.chunk_and_chunk_relative_position();
|
||||
let relative = ChunkRelativeBlockCoordinates::from(relative);
|
||||
let mut chunk = chunk.write().await;
|
||||
let replaced_block_state_id = chunk
|
||||
.blocks
|
||||
@ -1274,7 +1268,7 @@ impl World {
|
||||
priority: TickPriority,
|
||||
) {
|
||||
self.level
|
||||
.schedule_block_tick(block.id, &block_pos, delay, priority)
|
||||
.schedule_block_tick(block.id, block_pos, delay, priority)
|
||||
.await;
|
||||
}
|
||||
|
||||
@ -1356,13 +1350,20 @@ impl World {
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn get_block_state_id(&self, position: &BlockPos) -> Result<u16, GetBlockError> {
|
||||
let (chunk_coordinate, relative) = position.chunk_and_chunk_relative_position();
|
||||
let relative = ChunkRelativeBlockCoordinates::from(relative);
|
||||
pub async fn get_chunk(&self, position: &BlockPos) -> Arc<RwLock<ChunkData>> {
|
||||
let (chunk_coordinate, _) = position.chunk_and_chunk_relative_position();
|
||||
let chunk = match self.level.try_get_chunk(chunk_coordinate) {
|
||||
Some(chunk) => chunk.clone(),
|
||||
None => self.receive_chunk(chunk_coordinate).await.0,
|
||||
};
|
||||
chunk
|
||||
}
|
||||
|
||||
pub async fn get_block_state_id(&self, position: &BlockPos) -> Result<u16, GetBlockError> {
|
||||
let chunk = self.get_chunk(position).await;
|
||||
let (_, relative) = position.chunk_and_chunk_relative_position();
|
||||
let relative = ChunkRelativeBlockCoordinates::from(relative);
|
||||
|
||||
let chunk: tokio::sync::RwLockReadGuard<ChunkData> = chunk.read().await;
|
||||
|
||||
let Some(id) = chunk.blocks.get_block(relative) else {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user